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 */ 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 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 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 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 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 2515523662eSStephen Chandler Paul static unsigned int 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) 2585523662eSStephen Chandler Paul return POLLIN | POLLRDNORM; 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