15523662eSStephen Chandler Paul /*
25523662eSStephen Chandler Paul * userio kernel serio device emulation module
35523662eSStephen Chandler Paul * Copyright (C) 2015 Red Hat
45523662eSStephen Chandler Paul * Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com>
55523662eSStephen Chandler Paul *
65523662eSStephen Chandler Paul * This program is free software; you can redistribute it and/or modify it
75523662eSStephen Chandler Paul * under the terms of the GNU Lesser General Public License as published by
85523662eSStephen Chandler Paul * the Free Software Foundation; either version 2 of the License, or (at
95523662eSStephen Chandler Paul * your option) any later version.
105523662eSStephen Chandler Paul *
115523662eSStephen Chandler Paul * This program is distributed in the hope that it will be useful, but
125523662eSStephen Chandler Paul * WITHOUT ANY WARRANTY; without even the implied warranty of
135523662eSStephen Chandler Paul * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
145523662eSStephen Chandler Paul * General Public License for more details.
155523662eSStephen Chandler Paul */
165523662eSStephen Chandler Paul
175523662eSStephen Chandler Paul #include <linux/circ_buf.h>
185523662eSStephen Chandler Paul #include <linux/mutex.h>
195523662eSStephen Chandler Paul #include <linux/module.h>
205523662eSStephen Chandler Paul #include <linux/init.h>
215523662eSStephen Chandler Paul #include <linux/kernel.h>
225523662eSStephen Chandler Paul #include <linux/serio.h>
235523662eSStephen Chandler Paul #include <linux/slab.h>
245523662eSStephen Chandler Paul #include <linux/fs.h>
255523662eSStephen Chandler Paul #include <linux/miscdevice.h>
265523662eSStephen Chandler Paul #include <linux/sched.h>
275523662eSStephen Chandler Paul #include <linux/poll.h>
285523662eSStephen Chandler Paul #include <uapi/linux/userio.h>
295523662eSStephen Chandler Paul
305523662eSStephen Chandler Paul #define USERIO_NAME "userio"
315523662eSStephen Chandler Paul #define USERIO_BUFSIZE 16
325523662eSStephen Chandler Paul
335523662eSStephen Chandler Paul static struct miscdevice userio_misc;
345523662eSStephen Chandler Paul
355523662eSStephen Chandler Paul struct userio_device {
365523662eSStephen Chandler Paul struct serio *serio;
375523662eSStephen Chandler Paul struct mutex mutex;
385523662eSStephen Chandler Paul
395523662eSStephen Chandler Paul bool running;
405523662eSStephen Chandler Paul
415523662eSStephen Chandler Paul u8 head;
425523662eSStephen Chandler Paul u8 tail;
435523662eSStephen Chandler Paul
445523662eSStephen Chandler Paul spinlock_t buf_lock;
455523662eSStephen Chandler Paul unsigned char buf[USERIO_BUFSIZE];
465523662eSStephen Chandler Paul
475523662eSStephen Chandler Paul wait_queue_head_t waitq;
485523662eSStephen Chandler Paul };
495523662eSStephen Chandler Paul
505523662eSStephen Chandler Paul /**
515523662eSStephen Chandler Paul * userio_device_write - Write data from serio to a userio device in userspace
525523662eSStephen Chandler Paul * @id: The serio port for the userio device
535523662eSStephen Chandler Paul * @val: The data to write to the device
545523662eSStephen Chandler Paul */
userio_device_write(struct serio * id,unsigned char val)555523662eSStephen Chandler Paul static int userio_device_write(struct serio *id, unsigned char val)
565523662eSStephen Chandler Paul {
575523662eSStephen Chandler Paul struct userio_device *userio = id->port_data;
585523662eSStephen Chandler Paul unsigned long flags;
595523662eSStephen Chandler Paul
605523662eSStephen Chandler Paul spin_lock_irqsave(&userio->buf_lock, flags);
615523662eSStephen Chandler Paul
625523662eSStephen Chandler Paul userio->buf[userio->head] = val;
635523662eSStephen Chandler Paul userio->head = (userio->head + 1) % USERIO_BUFSIZE;
645523662eSStephen Chandler Paul
655523662eSStephen Chandler Paul if (userio->head == userio->tail)
665523662eSStephen Chandler Paul dev_warn(userio_misc.this_device,
675523662eSStephen Chandler Paul "Buffer overflowed, userio client isn't keeping up");
685523662eSStephen Chandler Paul
695523662eSStephen Chandler Paul spin_unlock_irqrestore(&userio->buf_lock, flags);
705523662eSStephen Chandler Paul
715523662eSStephen Chandler Paul wake_up_interruptible(&userio->waitq);
725523662eSStephen Chandler Paul
735523662eSStephen Chandler Paul return 0;
745523662eSStephen Chandler Paul }
755523662eSStephen Chandler Paul
userio_char_open(struct inode * inode,struct file * file)765523662eSStephen Chandler Paul static int userio_char_open(struct inode *inode, struct file *file)
775523662eSStephen Chandler Paul {
785523662eSStephen Chandler Paul struct userio_device *userio;
795523662eSStephen Chandler Paul
805523662eSStephen Chandler Paul userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL);
815523662eSStephen Chandler Paul if (!userio)
825523662eSStephen Chandler Paul return -ENOMEM;
835523662eSStephen Chandler Paul
845523662eSStephen Chandler Paul mutex_init(&userio->mutex);
855523662eSStephen Chandler Paul spin_lock_init(&userio->buf_lock);
865523662eSStephen Chandler Paul init_waitqueue_head(&userio->waitq);
875523662eSStephen Chandler Paul
885523662eSStephen Chandler Paul userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
895523662eSStephen Chandler Paul if (!userio->serio) {
905523662eSStephen Chandler Paul kfree(userio);
915523662eSStephen Chandler Paul return -ENOMEM;
925523662eSStephen Chandler Paul }
935523662eSStephen Chandler Paul
945523662eSStephen Chandler Paul userio->serio->write = userio_device_write;
955523662eSStephen Chandler Paul userio->serio->port_data = userio;
965523662eSStephen Chandler Paul
975523662eSStephen Chandler Paul file->private_data = userio;
985523662eSStephen Chandler Paul
995523662eSStephen Chandler Paul return 0;
1005523662eSStephen Chandler Paul }
1015523662eSStephen Chandler Paul
userio_char_release(struct inode * inode,struct file * file)1025523662eSStephen Chandler Paul static int userio_char_release(struct inode *inode, struct file *file)
1035523662eSStephen Chandler Paul {
1045523662eSStephen Chandler Paul struct userio_device *userio = file->private_data;
1055523662eSStephen Chandler Paul
1065523662eSStephen Chandler Paul if (userio->running) {
1075523662eSStephen Chandler Paul /*
1085523662eSStephen Chandler Paul * Don't free the serio port here, serio_unregister_port()
1095523662eSStephen Chandler Paul * does it for us.
1105523662eSStephen Chandler Paul */
1115523662eSStephen Chandler Paul serio_unregister_port(userio->serio);
1125523662eSStephen Chandler Paul } else {
1135523662eSStephen Chandler Paul kfree(userio->serio);
1145523662eSStephen Chandler Paul }
1155523662eSStephen Chandler Paul
1165523662eSStephen Chandler Paul kfree(userio);
1175523662eSStephen Chandler Paul
1185523662eSStephen Chandler Paul return 0;
1195523662eSStephen Chandler Paul }
1205523662eSStephen Chandler Paul
userio_char_read(struct file * file,char __user * user_buffer,size_t count,loff_t * ppos)1215523662eSStephen Chandler Paul static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
1225523662eSStephen Chandler Paul size_t count, loff_t *ppos)
1235523662eSStephen Chandler Paul {
1245523662eSStephen Chandler Paul struct userio_device *userio = file->private_data;
1255523662eSStephen Chandler Paul int error;
1265523662eSStephen Chandler Paul size_t nonwrap_len, copylen;
1275523662eSStephen Chandler Paul unsigned char buf[USERIO_BUFSIZE];
1285523662eSStephen Chandler Paul unsigned long flags;
1295523662eSStephen Chandler Paul
1305523662eSStephen Chandler Paul /*
1315523662eSStephen Chandler Paul * By the time we get here, the data that was waiting might have
1325523662eSStephen Chandler Paul * been taken by another thread. Grab the buffer lock and check if
1335523662eSStephen Chandler Paul * there's still any data waiting, otherwise repeat this process
1345523662eSStephen Chandler Paul * until we have data (unless the file descriptor is non-blocking
1355523662eSStephen Chandler Paul * of course).
1365523662eSStephen Chandler Paul */
1375523662eSStephen Chandler Paul for (;;) {
1385523662eSStephen Chandler Paul spin_lock_irqsave(&userio->buf_lock, flags);
1395523662eSStephen Chandler Paul
1405523662eSStephen Chandler Paul nonwrap_len = CIRC_CNT_TO_END(userio->head,
1415523662eSStephen Chandler Paul userio->tail,
1425523662eSStephen Chandler Paul USERIO_BUFSIZE);
1435523662eSStephen Chandler Paul copylen = min(nonwrap_len, count);
1445523662eSStephen Chandler Paul if (copylen) {
1455523662eSStephen Chandler Paul memcpy(buf, &userio->buf[userio->tail], copylen);
1465523662eSStephen Chandler Paul userio->tail = (userio->tail + copylen) %
1475523662eSStephen Chandler Paul USERIO_BUFSIZE;
1485523662eSStephen Chandler Paul }
1495523662eSStephen Chandler Paul
1505523662eSStephen Chandler Paul spin_unlock_irqrestore(&userio->buf_lock, flags);
1515523662eSStephen Chandler Paul
1525523662eSStephen Chandler Paul if (nonwrap_len)
1535523662eSStephen Chandler Paul break;
1545523662eSStephen Chandler Paul
1555523662eSStephen Chandler Paul /* buffer was/is empty */
1565523662eSStephen Chandler Paul if (file->f_flags & O_NONBLOCK)
1575523662eSStephen Chandler Paul return -EAGAIN;
1585523662eSStephen Chandler Paul
1595523662eSStephen Chandler Paul /*
1605523662eSStephen Chandler Paul * count == 0 is special - no IO is done but we check
1615523662eSStephen Chandler Paul * for error conditions (see above).
1625523662eSStephen Chandler Paul */
1635523662eSStephen Chandler Paul if (count == 0)
1645523662eSStephen Chandler Paul return 0;
1655523662eSStephen Chandler Paul
1665523662eSStephen Chandler Paul error = wait_event_interruptible(userio->waitq,
1675523662eSStephen Chandler Paul userio->head != userio->tail);
1685523662eSStephen Chandler Paul if (error)
1695523662eSStephen Chandler Paul return error;
1705523662eSStephen Chandler Paul }
1715523662eSStephen Chandler Paul
1725523662eSStephen Chandler Paul if (copylen)
1735523662eSStephen Chandler Paul if (copy_to_user(user_buffer, buf, copylen))
1745523662eSStephen Chandler Paul return -EFAULT;
1755523662eSStephen Chandler Paul
1765523662eSStephen Chandler Paul return copylen;
1775523662eSStephen Chandler Paul }
1785523662eSStephen Chandler Paul
userio_char_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)1795523662eSStephen Chandler Paul static ssize_t userio_char_write(struct file *file, const char __user *buffer,
1805523662eSStephen Chandler Paul size_t count, loff_t *ppos)
1815523662eSStephen Chandler Paul {
1825523662eSStephen Chandler Paul struct userio_device *userio = file->private_data;
1835523662eSStephen Chandler Paul struct userio_cmd cmd;
1845523662eSStephen Chandler Paul int error;
1855523662eSStephen Chandler Paul
1865523662eSStephen Chandler Paul if (count != sizeof(cmd)) {
1875523662eSStephen Chandler Paul dev_warn(userio_misc.this_device, "Invalid payload size\n");
1885523662eSStephen Chandler Paul return -EINVAL;
1895523662eSStephen Chandler Paul }
1905523662eSStephen Chandler Paul
1915523662eSStephen Chandler Paul if (copy_from_user(&cmd, buffer, sizeof(cmd)))
1925523662eSStephen Chandler Paul return -EFAULT;
1935523662eSStephen Chandler Paul
1945523662eSStephen Chandler Paul error = mutex_lock_interruptible(&userio->mutex);
1955523662eSStephen Chandler Paul if (error)
1965523662eSStephen Chandler Paul return error;
1975523662eSStephen Chandler Paul
1985523662eSStephen Chandler Paul switch (cmd.type) {
1995523662eSStephen Chandler Paul case USERIO_CMD_REGISTER:
2005523662eSStephen Chandler Paul if (!userio->serio->id.type) {
2015523662eSStephen Chandler Paul dev_warn(userio_misc.this_device,
2025523662eSStephen Chandler Paul "No port type given on /dev/userio\n");
2035523662eSStephen Chandler Paul
2045523662eSStephen Chandler Paul error = -EINVAL;
2055523662eSStephen Chandler Paul goto out;
2065523662eSStephen Chandler Paul }
2075523662eSStephen Chandler Paul
2085523662eSStephen Chandler Paul if (userio->running) {
2095523662eSStephen Chandler Paul dev_warn(userio_misc.this_device,
2105523662eSStephen Chandler Paul "Begin command sent, but we're already running\n");
2115523662eSStephen Chandler Paul error = -EBUSY;
2125523662eSStephen Chandler Paul goto out;
2135523662eSStephen Chandler Paul }
2145523662eSStephen Chandler Paul
2155523662eSStephen Chandler Paul userio->running = true;
2165523662eSStephen Chandler Paul serio_register_port(userio->serio);
2175523662eSStephen Chandler Paul break;
2185523662eSStephen Chandler Paul
2195523662eSStephen Chandler Paul case USERIO_CMD_SET_PORT_TYPE:
2205523662eSStephen Chandler Paul if (userio->running) {
2215523662eSStephen Chandler Paul dev_warn(userio_misc.this_device,
2225523662eSStephen Chandler Paul "Can't change port type on an already running userio instance\n");
2235523662eSStephen Chandler Paul error = -EBUSY;
2245523662eSStephen Chandler Paul goto out;
2255523662eSStephen Chandler Paul }
2265523662eSStephen Chandler Paul
2275523662eSStephen Chandler Paul userio->serio->id.type = cmd.data;
2285523662eSStephen Chandler Paul break;
2295523662eSStephen Chandler Paul
2305523662eSStephen Chandler Paul case USERIO_CMD_SEND_INTERRUPT:
2315523662eSStephen Chandler Paul if (!userio->running) {
2325523662eSStephen Chandler Paul dev_warn(userio_misc.this_device,
2335523662eSStephen Chandler Paul "The device must be registered before sending interrupts\n");
2345523662eSStephen Chandler Paul error = -ENODEV;
2355523662eSStephen Chandler Paul goto out;
2365523662eSStephen Chandler Paul }
2375523662eSStephen Chandler Paul
2385523662eSStephen Chandler Paul serio_interrupt(userio->serio, cmd.data, 0);
2395523662eSStephen Chandler Paul break;
2405523662eSStephen Chandler Paul
2415523662eSStephen Chandler Paul default:
2425523662eSStephen Chandler Paul error = -EOPNOTSUPP;
2435523662eSStephen Chandler Paul goto out;
2445523662eSStephen Chandler Paul }
2455523662eSStephen Chandler Paul
2465523662eSStephen Chandler Paul out:
2475523662eSStephen Chandler Paul mutex_unlock(&userio->mutex);
2485523662eSStephen Chandler Paul return error ?: count;
2495523662eSStephen Chandler Paul }
2505523662eSStephen Chandler Paul
userio_char_poll(struct file * file,poll_table * wait)251afc9a42bSAl Viro static __poll_t userio_char_poll(struct file *file, poll_table *wait)
2525523662eSStephen Chandler Paul {
2535523662eSStephen Chandler Paul struct userio_device *userio = file->private_data;
2545523662eSStephen Chandler Paul
2555523662eSStephen Chandler Paul poll_wait(file, &userio->waitq, wait);
2565523662eSStephen Chandler Paul
2575523662eSStephen Chandler Paul if (userio->head != userio->tail)
258a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM;
2595523662eSStephen Chandler Paul
2605523662eSStephen Chandler Paul return 0;
2615523662eSStephen Chandler Paul }
2625523662eSStephen Chandler Paul
2635523662eSStephen Chandler Paul static const struct file_operations userio_fops = {
2645523662eSStephen Chandler Paul .owner = THIS_MODULE,
2655523662eSStephen Chandler Paul .open = userio_char_open,
2665523662eSStephen Chandler Paul .release = userio_char_release,
2675523662eSStephen Chandler Paul .read = userio_char_read,
2685523662eSStephen Chandler Paul .write = userio_char_write,
2695523662eSStephen Chandler Paul .poll = userio_char_poll,
2705523662eSStephen Chandler Paul .llseek = no_llseek,
2715523662eSStephen Chandler Paul };
2725523662eSStephen Chandler Paul
2735523662eSStephen Chandler Paul static struct miscdevice userio_misc = {
2745523662eSStephen Chandler Paul .fops = &userio_fops,
2755523662eSStephen Chandler Paul .minor = USERIO_MINOR,
2765523662eSStephen Chandler Paul .name = USERIO_NAME,
2775523662eSStephen Chandler Paul };
2785523662eSStephen Chandler Paul module_driver(userio_misc, misc_register, misc_deregister);
2795523662eSStephen Chandler Paul
2805523662eSStephen Chandler Paul MODULE_ALIAS_MISCDEV(USERIO_MINOR);
2815523662eSStephen Chandler Paul MODULE_ALIAS("devname:" USERIO_NAME);
2825523662eSStephen Chandler Paul
2835523662eSStephen Chandler Paul MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>");
2845523662eSStephen Chandler Paul MODULE_DESCRIPTION("Virtual Serio Device Support");
2855523662eSStephen Chandler Paul MODULE_LICENSE("GPL");
286