brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 69b36ce Raw
153 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for the Intel SCU IPC mechanism4 *5 * (C) Copyright 2008-2010 Intel Corporation6 * Author: Sreedhara DS (sreedhara.ds@intel.com)7 *8 * This driver provides IOCTL interfaces to call Intel SCU IPC driver API.9 */10 11#include <linux/errno.h>12#include <linux/fcntl.h>13#include <linux/fs.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/sched.h>17#include <linux/slab.h>18#include <linux/types.h>19#include <linux/uaccess.h>20 21#include <linux/platform_data/x86/intel_scu_ipc.h>22 23static int major;24 25static struct intel_scu_ipc_dev *scu;26static DEFINE_MUTEX(scu_lock);27 28/* IOCTL commands */29#define	INTE_SCU_IPC_REGISTER_READ	030#define INTE_SCU_IPC_REGISTER_WRITE	131#define INTE_SCU_IPC_REGISTER_UPDATE	232 33struct scu_ipc_data {34	u32     count;  /* No. of registers */35	u16     addr[5]; /* Register addresses */36	u8      data[5]; /* Register data */37	u8      mask; /* Valid for read-modify-write */38};39 40/**41 *	scu_reg_access		-	implement register access ioctls42 *	@cmd: command we are doing (read/write/update)43 *	@data: kernel copy of ioctl data44 *45 *	Allow the user to perform register accesses on the SCU via the46 *	kernel interface47 */48 49static int scu_reg_access(u32 cmd, struct scu_ipc_data  *data)50{51	unsigned int count = data->count;52 53	if (count == 0 || count == 3 || count > 4)54		return -EINVAL;55 56	switch (cmd) {57	case INTE_SCU_IPC_REGISTER_READ:58		return intel_scu_ipc_dev_readv(scu, data->addr, data->data, count);59	case INTE_SCU_IPC_REGISTER_WRITE:60		return intel_scu_ipc_dev_writev(scu, data->addr, data->data, count);61	case INTE_SCU_IPC_REGISTER_UPDATE:62		return intel_scu_ipc_dev_update(scu, data->addr[0], data->data[0],63						data->mask);64	default:65		return -ENOTTY;66	}67}68 69/**70 *	scu_ipc_ioctl		-	control ioctls for the SCU71 *	@fp: file handle of the SCU device72 *	@cmd: ioctl coce73 *	@arg: pointer to user passed structure74 *75 *	Support the I/O and firmware flashing interfaces of the SCU76 */77static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,78							unsigned long arg)79{80	int ret;81	struct scu_ipc_data  data;82	void __user *argp = (void __user *)arg;83 84	if (!capable(CAP_SYS_RAWIO))85		return -EPERM;86 87	if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))88		return -EFAULT;89	ret = scu_reg_access(cmd, &data);90	if (ret < 0)91		return ret;92	if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))93		return -EFAULT;94	return 0;95}96 97static int scu_ipc_open(struct inode *inode, struct file *file)98{99	int ret = 0;100 101	/* Only single open at the time */102	mutex_lock(&scu_lock);103	if (scu) {104		ret = -EBUSY;105		goto unlock;106	}107 108	scu = intel_scu_ipc_dev_get();109	if (!scu)110		ret = -ENODEV;111 112unlock:113	mutex_unlock(&scu_lock);114	return ret;115}116 117static int scu_ipc_release(struct inode *inode, struct file *file)118{119	mutex_lock(&scu_lock);120	intel_scu_ipc_dev_put(scu);121	scu = NULL;122	mutex_unlock(&scu_lock);123 124	return 0;125}126 127static const struct file_operations scu_ipc_fops = {128	.unlocked_ioctl = scu_ipc_ioctl,129	.open = scu_ipc_open,130	.release = scu_ipc_release,131};132 133static int __init ipc_module_init(void)134{135	major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);136	if (major < 0)137		return major;138 139	return 0;140}141 142static void __exit ipc_module_exit(void)143{144	unregister_chrdev(major, "intel_mid_scu");145}146 147module_init(ipc_module_init);148module_exit(ipc_module_exit);149 150MODULE_LICENSE("GPL v2");151MODULE_DESCRIPTION("Utility driver for intel scu ipc");152MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");153