0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/circ_buf.h>
0018 #include <linux/mutex.h>
0019 #include <linux/module.h>
0020 #include <linux/init.h>
0021 #include <linux/kernel.h>
0022 #include <linux/serio.h>
0023 #include <linux/slab.h>
0024 #include <linux/fs.h>
0025 #include <linux/miscdevice.h>
0026 #include <linux/sched.h>
0027 #include <linux/poll.h>
0028 #include <uapi/linux/userio.h>
0029
0030 #define USERIO_NAME "userio"
0031 #define USERIO_BUFSIZE 16
0032
0033 static struct miscdevice userio_misc;
0034
0035 struct userio_device {
0036 struct serio *serio;
0037 struct mutex mutex;
0038
0039 bool running;
0040
0041 u8 head;
0042 u8 tail;
0043
0044 spinlock_t buf_lock;
0045 unsigned char buf[USERIO_BUFSIZE];
0046
0047 wait_queue_head_t waitq;
0048 };
0049
0050
0051
0052
0053
0054
0055 static int userio_device_write(struct serio *id, unsigned char val)
0056 {
0057 struct userio_device *userio = id->port_data;
0058 unsigned long flags;
0059
0060 spin_lock_irqsave(&userio->buf_lock, flags);
0061
0062 userio->buf[userio->head] = val;
0063 userio->head = (userio->head + 1) % USERIO_BUFSIZE;
0064
0065 if (userio->head == userio->tail)
0066 dev_warn(userio_misc.this_device,
0067 "Buffer overflowed, userio client isn't keeping up");
0068
0069 spin_unlock_irqrestore(&userio->buf_lock, flags);
0070
0071 wake_up_interruptible(&userio->waitq);
0072
0073 return 0;
0074 }
0075
0076 static int userio_char_open(struct inode *inode, struct file *file)
0077 {
0078 struct userio_device *userio;
0079
0080 userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL);
0081 if (!userio)
0082 return -ENOMEM;
0083
0084 mutex_init(&userio->mutex);
0085 spin_lock_init(&userio->buf_lock);
0086 init_waitqueue_head(&userio->waitq);
0087
0088 userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
0089 if (!userio->serio) {
0090 kfree(userio);
0091 return -ENOMEM;
0092 }
0093
0094 userio->serio->write = userio_device_write;
0095 userio->serio->port_data = userio;
0096
0097 file->private_data = userio;
0098
0099 return 0;
0100 }
0101
0102 static int userio_char_release(struct inode *inode, struct file *file)
0103 {
0104 struct userio_device *userio = file->private_data;
0105
0106 if (userio->running) {
0107
0108
0109
0110
0111 serio_unregister_port(userio->serio);
0112 } else {
0113 kfree(userio->serio);
0114 }
0115
0116 kfree(userio);
0117
0118 return 0;
0119 }
0120
0121 static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
0122 size_t count, loff_t *ppos)
0123 {
0124 struct userio_device *userio = file->private_data;
0125 int error;
0126 size_t nonwrap_len, copylen;
0127 unsigned char buf[USERIO_BUFSIZE];
0128 unsigned long flags;
0129
0130
0131
0132
0133
0134
0135
0136
0137 for (;;) {
0138 spin_lock_irqsave(&userio->buf_lock, flags);
0139
0140 nonwrap_len = CIRC_CNT_TO_END(userio->head,
0141 userio->tail,
0142 USERIO_BUFSIZE);
0143 copylen = min(nonwrap_len, count);
0144 if (copylen) {
0145 memcpy(buf, &userio->buf[userio->tail], copylen);
0146 userio->tail = (userio->tail + copylen) %
0147 USERIO_BUFSIZE;
0148 }
0149
0150 spin_unlock_irqrestore(&userio->buf_lock, flags);
0151
0152 if (nonwrap_len)
0153 break;
0154
0155
0156 if (file->f_flags & O_NONBLOCK)
0157 return -EAGAIN;
0158
0159
0160
0161
0162
0163 if (count == 0)
0164 return 0;
0165
0166 error = wait_event_interruptible(userio->waitq,
0167 userio->head != userio->tail);
0168 if (error)
0169 return error;
0170 }
0171
0172 if (copylen)
0173 if (copy_to_user(user_buffer, buf, copylen))
0174 return -EFAULT;
0175
0176 return copylen;
0177 }
0178
0179 static ssize_t userio_char_write(struct file *file, const char __user *buffer,
0180 size_t count, loff_t *ppos)
0181 {
0182 struct userio_device *userio = file->private_data;
0183 struct userio_cmd cmd;
0184 int error;
0185
0186 if (count != sizeof(cmd)) {
0187 dev_warn(userio_misc.this_device, "Invalid payload size\n");
0188 return -EINVAL;
0189 }
0190
0191 if (copy_from_user(&cmd, buffer, sizeof(cmd)))
0192 return -EFAULT;
0193
0194 error = mutex_lock_interruptible(&userio->mutex);
0195 if (error)
0196 return error;
0197
0198 switch (cmd.type) {
0199 case USERIO_CMD_REGISTER:
0200 if (!userio->serio->id.type) {
0201 dev_warn(userio_misc.this_device,
0202 "No port type given on /dev/userio\n");
0203
0204 error = -EINVAL;
0205 goto out;
0206 }
0207
0208 if (userio->running) {
0209 dev_warn(userio_misc.this_device,
0210 "Begin command sent, but we're already running\n");
0211 error = -EBUSY;
0212 goto out;
0213 }
0214
0215 userio->running = true;
0216 serio_register_port(userio->serio);
0217 break;
0218
0219 case USERIO_CMD_SET_PORT_TYPE:
0220 if (userio->running) {
0221 dev_warn(userio_misc.this_device,
0222 "Can't change port type on an already running userio instance\n");
0223 error = -EBUSY;
0224 goto out;
0225 }
0226
0227 userio->serio->id.type = cmd.data;
0228 break;
0229
0230 case USERIO_CMD_SEND_INTERRUPT:
0231 if (!userio->running) {
0232 dev_warn(userio_misc.this_device,
0233 "The device must be registered before sending interrupts\n");
0234 error = -ENODEV;
0235 goto out;
0236 }
0237
0238 serio_interrupt(userio->serio, cmd.data, 0);
0239 break;
0240
0241 default:
0242 error = -EOPNOTSUPP;
0243 goto out;
0244 }
0245
0246 out:
0247 mutex_unlock(&userio->mutex);
0248 return error ?: count;
0249 }
0250
0251 static __poll_t userio_char_poll(struct file *file, poll_table *wait)
0252 {
0253 struct userio_device *userio = file->private_data;
0254
0255 poll_wait(file, &userio->waitq, wait);
0256
0257 if (userio->head != userio->tail)
0258 return EPOLLIN | EPOLLRDNORM;
0259
0260 return 0;
0261 }
0262
0263 static const struct file_operations userio_fops = {
0264 .owner = THIS_MODULE,
0265 .open = userio_char_open,
0266 .release = userio_char_release,
0267 .read = userio_char_read,
0268 .write = userio_char_write,
0269 .poll = userio_char_poll,
0270 .llseek = no_llseek,
0271 };
0272
0273 static struct miscdevice userio_misc = {
0274 .fops = &userio_fops,
0275 .minor = USERIO_MINOR,
0276 .name = USERIO_NAME,
0277 };
0278 module_driver(userio_misc, misc_register, misc_deregister);
0279
0280 MODULE_ALIAS_MISCDEV(USERIO_MINOR);
0281 MODULE_ALIAS("devname:" USERIO_NAME);
0282
0283 MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>");
0284 MODULE_DESCRIPTION("Virtual Serio Device Support");
0285 MODULE_LICENSE("GPL");