0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/errno.h>
0012 #include <linux/fcntl.h>
0013 #include <linux/fs.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/sched.h>
0017 #include <linux/slab.h>
0018 #include <linux/types.h>
0019 #include <linux/uaccess.h>
0020
0021 #include <asm/intel_scu_ipc.h>
0022
0023 static int major;
0024
0025 struct intel_scu_ipc_dev *scu;
0026 static DEFINE_MUTEX(scu_lock);
0027
0028
0029 #define INTE_SCU_IPC_REGISTER_READ 0
0030 #define INTE_SCU_IPC_REGISTER_WRITE 1
0031 #define INTE_SCU_IPC_REGISTER_UPDATE 2
0032
0033 struct scu_ipc_data {
0034 u32 count;
0035 u16 addr[5];
0036 u8 data[5];
0037 u8 mask;
0038 };
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 static int scu_reg_access(u32 cmd, struct scu_ipc_data *data)
0050 {
0051 unsigned int count = data->count;
0052
0053 if (count == 0 || count == 3 || count > 4)
0054 return -EINVAL;
0055
0056 switch (cmd) {
0057 case INTE_SCU_IPC_REGISTER_READ:
0058 return intel_scu_ipc_dev_readv(scu, data->addr, data->data, count);
0059 case INTE_SCU_IPC_REGISTER_WRITE:
0060 return intel_scu_ipc_dev_writev(scu, data->addr, data->data, count);
0061 case INTE_SCU_IPC_REGISTER_UPDATE:
0062 return intel_scu_ipc_dev_update(scu, data->addr[0], data->data[0],
0063 data->mask);
0064 default:
0065 return -ENOTTY;
0066 }
0067 }
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
0078 unsigned long arg)
0079 {
0080 int ret;
0081 struct scu_ipc_data data;
0082 void __user *argp = (void __user *)arg;
0083
0084 if (!capable(CAP_SYS_RAWIO))
0085 return -EPERM;
0086
0087 if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
0088 return -EFAULT;
0089 ret = scu_reg_access(cmd, &data);
0090 if (ret < 0)
0091 return ret;
0092 if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
0093 return -EFAULT;
0094 return 0;
0095 }
0096
0097 static int scu_ipc_open(struct inode *inode, struct file *file)
0098 {
0099 int ret = 0;
0100
0101
0102 mutex_lock(&scu_lock);
0103 if (scu) {
0104 ret = -EBUSY;
0105 goto unlock;
0106 }
0107
0108 scu = intel_scu_ipc_dev_get();
0109 if (!scu)
0110 ret = -ENODEV;
0111
0112 unlock:
0113 mutex_unlock(&scu_lock);
0114 return ret;
0115 }
0116
0117 static int scu_ipc_release(struct inode *inode, struct file *file)
0118 {
0119 mutex_lock(&scu_lock);
0120 intel_scu_ipc_dev_put(scu);
0121 scu = NULL;
0122 mutex_unlock(&scu_lock);
0123
0124 return 0;
0125 }
0126
0127 static const struct file_operations scu_ipc_fops = {
0128 .unlocked_ioctl = scu_ipc_ioctl,
0129 .open = scu_ipc_open,
0130 .release = scu_ipc_release,
0131 };
0132
0133 static int __init ipc_module_init(void)
0134 {
0135 major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
0136 if (major < 0)
0137 return major;
0138
0139 return 0;
0140 }
0141
0142 static void __exit ipc_module_exit(void)
0143 {
0144 unregister_chrdev(major, "intel_mid_scu");
0145 }
0146
0147 module_init(ipc_module_init);
0148 module_exit(ipc_module_exit);
0149
0150 MODULE_LICENSE("GPL v2");
0151 MODULE_DESCRIPTION("Utility driver for intel scu ipc");
0152 MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");