11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Raw serio device providing access to a raw byte stream from underlying 31da177e4SLinus Torvalds * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 2004 Dmitry Torokhov 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 81da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 91da177e4SLinus Torvalds * the Free Software Foundation. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 12ba538cd2SDmitry Torokhov #include <linux/kref.h> 13d43c36dcSAlexey Dobriyan #include <linux/sched.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 151da177e4SLinus Torvalds #include <linux/poll.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/serio.h> 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/major.h> 201da177e4SLinus Torvalds #include <linux/device.h> 211da177e4SLinus Torvalds #include <linux/miscdevice.h> 221da177e4SLinus Torvalds #include <linux/wait.h> 23c4e32e9fSArjan van de Ven #include <linux/mutex.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define DRIVER_DESC "Raw serio driver" 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 281da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #define SERIO_RAW_QUEUE_LEN 64 321da177e4SLinus Torvalds struct serio_raw { 331da177e4SLinus Torvalds unsigned char queue[SERIO_RAW_QUEUE_LEN]; 341da177e4SLinus Torvalds unsigned int tail, head; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds char name[16]; 37ba538cd2SDmitry Torokhov struct kref kref; 381da177e4SLinus Torvalds struct serio *serio; 391da177e4SLinus Torvalds struct miscdevice dev; 401da177e4SLinus Torvalds wait_queue_head_t wait; 417c5bbb2eSDmitry Torokhov struct list_head client_list; 421da177e4SLinus Torvalds struct list_head node; 4385f5b35dSDmitry Torokhov bool dead; 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 467c5bbb2eSDmitry Torokhov struct serio_raw_client { 471da177e4SLinus Torvalds struct fasync_struct *fasync; 481da177e4SLinus Torvalds struct serio_raw *serio_raw; 491da177e4SLinus Torvalds struct list_head node; 501da177e4SLinus Torvalds }; 511da177e4SLinus Torvalds 52c4e32e9fSArjan van de Ven static DEFINE_MUTEX(serio_raw_mutex); 531da177e4SLinus Torvalds static LIST_HEAD(serio_raw_list); 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /********************************************************************* 561da177e4SLinus Torvalds * Interface with userspace (file operations) * 571da177e4SLinus Torvalds *********************************************************************/ 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds static int serio_raw_fasync(int fd, struct file *file, int on) 601da177e4SLinus Torvalds { 617c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 621da177e4SLinus Torvalds 637c5bbb2eSDmitry Torokhov return fasync_helper(fd, file, on, &client->fasync); 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds static struct serio_raw *serio_raw_locate(int minor) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds struct serio_raw *serio_raw; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds list_for_each_entry(serio_raw, &serio_raw_list, node) { 711da177e4SLinus Torvalds if (serio_raw->dev.minor == minor) 721da177e4SLinus Torvalds return serio_raw; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds return NULL; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds static int serio_raw_open(struct inode *inode, struct file *file) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds struct serio_raw *serio_raw; 817c5bbb2eSDmitry Torokhov struct serio_raw_client *client; 827c5bbb2eSDmitry Torokhov int retval; 831da177e4SLinus Torvalds 84c4e32e9fSArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 851da177e4SLinus Torvalds if (retval) 8677554b4dSThadeu Lima de Souza Cascardo return retval; 871da177e4SLinus Torvalds 8877554b4dSThadeu Lima de Souza Cascardo serio_raw = serio_raw_locate(iminor(inode)); 8977554b4dSThadeu Lima de Souza Cascardo if (!serio_raw) { 901da177e4SLinus Torvalds retval = -ENODEV; 911da177e4SLinus Torvalds goto out; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 9485f5b35dSDmitry Torokhov if (serio_raw->dead) { 951da177e4SLinus Torvalds retval = -ENODEV; 961da177e4SLinus Torvalds goto out; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 997c5bbb2eSDmitry Torokhov client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL); 1007c5bbb2eSDmitry Torokhov if (!client) { 1011da177e4SLinus Torvalds retval = -ENOMEM; 1021da177e4SLinus Torvalds goto out; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1057c5bbb2eSDmitry Torokhov client->serio_raw = serio_raw; 1067c5bbb2eSDmitry Torokhov file->private_data = client; 1071da177e4SLinus Torvalds 108ba538cd2SDmitry Torokhov kref_get(&serio_raw->kref); 109843e784aSDmitry Torokhov 110843e784aSDmitry Torokhov serio_pause_rx(serio_raw->serio); 1117c5bbb2eSDmitry Torokhov list_add_tail(&client->node, &serio_raw->client_list); 112843e784aSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds out: 115c4e32e9fSArjan van de Ven mutex_unlock(&serio_raw_mutex); 1161da177e4SLinus Torvalds return retval; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 119550eca7cSDmitry Torokhov static void serio_raw_free(struct kref *kref) 1201da177e4SLinus Torvalds { 121ba538cd2SDmitry Torokhov struct serio_raw *serio_raw = 122ba538cd2SDmitry Torokhov container_of(kref, struct serio_raw, kref); 123ba538cd2SDmitry Torokhov 12485f5b35dSDmitry Torokhov put_device(&serio_raw->serio->dev); 1251da177e4SLinus Torvalds kfree(serio_raw); 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static int serio_raw_release(struct inode *inode, struct file *file) 1291da177e4SLinus Torvalds { 1307c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 1317c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1321da177e4SLinus Torvalds 133550eca7cSDmitry Torokhov serio_pause_rx(serio_raw->serio); 134550eca7cSDmitry Torokhov list_del(&client->node); 135550eca7cSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1361da177e4SLinus Torvalds 137550eca7cSDmitry Torokhov kfree(client); 1381da177e4SLinus Torvalds 139550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 140550eca7cSDmitry Torokhov 1411da177e4SLinus Torvalds return 0; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1448c31eb01SDmitry Torokhov static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) 1451da177e4SLinus Torvalds { 1468c31eb01SDmitry Torokhov bool empty; 1471da177e4SLinus Torvalds 148843e784aSDmitry Torokhov serio_pause_rx(serio_raw->serio); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds empty = serio_raw->head == serio_raw->tail; 1511da177e4SLinus Torvalds if (!empty) { 1521da177e4SLinus Torvalds *c = serio_raw->queue[serio_raw->tail]; 1531da177e4SLinus Torvalds serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 156843e784aSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds return !empty; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 16115a564d8SDmitry Torokhov static ssize_t serio_raw_read(struct file *file, char __user *buffer, 16215a564d8SDmitry Torokhov size_t count, loff_t *ppos) 1631da177e4SLinus Torvalds { 1647c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 1657c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1664f179f71SAndrew Morton char uninitialized_var(c); 1677a0a27d2SChe-Liang Chiou ssize_t read = 0; 16846f49b7aSDmitry Torokhov int error; 1691da177e4SLinus Torvalds 17046f49b7aSDmitry Torokhov for (;;) { 17185f5b35dSDmitry Torokhov if (serio_raw->dead) 1721da177e4SLinus Torvalds return -ENODEV; 1731da177e4SLinus Torvalds 174486c8abaSDmitry Torokhov if (serio_raw->head == serio_raw->tail && 175486c8abaSDmitry Torokhov (file->f_flags & O_NONBLOCK)) 1761da177e4SLinus Torvalds return -EAGAIN; 1771da177e4SLinus Torvalds 178486c8abaSDmitry Torokhov if (count == 0) 179486c8abaSDmitry Torokhov break; 1801da177e4SLinus Torvalds 1817a0a27d2SChe-Liang Chiou while (read < count && serio_raw_fetch_byte(serio_raw, &c)) { 18246f49b7aSDmitry Torokhov if (put_user(c, buffer++)) 18346f49b7aSDmitry Torokhov return -EFAULT; 1847a0a27d2SChe-Liang Chiou read++; 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 187486c8abaSDmitry Torokhov if (read) 188486c8abaSDmitry Torokhov break; 189486c8abaSDmitry Torokhov 19046f49b7aSDmitry Torokhov if (!(file->f_flags & O_NONBLOCK)) { 191486c8abaSDmitry Torokhov error = wait_event_interruptible(serio_raw->wait, 192486c8abaSDmitry Torokhov serio_raw->head != serio_raw->tail || 193486c8abaSDmitry Torokhov serio_raw->dead); 19446f49b7aSDmitry Torokhov if (error) 19546f49b7aSDmitry Torokhov return error; 19646f49b7aSDmitry Torokhov } 19746f49b7aSDmitry Torokhov } 198486c8abaSDmitry Torokhov 19946f49b7aSDmitry Torokhov return read; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 20215a564d8SDmitry Torokhov static ssize_t serio_raw_write(struct file *file, const char __user *buffer, 20315a564d8SDmitry Torokhov size_t count, loff_t *ppos) 2041da177e4SLinus Torvalds { 2057c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 2067c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 20746f49b7aSDmitry Torokhov int retval = 0; 2081da177e4SLinus Torvalds unsigned char c; 2091da177e4SLinus Torvalds 210c4e32e9fSArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 2111da177e4SLinus Torvalds if (retval) 2121da177e4SLinus Torvalds return retval; 2131da177e4SLinus Torvalds 21485f5b35dSDmitry Torokhov if (serio_raw->dead) { 2151da177e4SLinus Torvalds retval = -ENODEV; 2161da177e4SLinus Torvalds goto out; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if (count > 32) 2201da177e4SLinus Torvalds count = 32; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds while (count--) { 2231da177e4SLinus Torvalds if (get_user(c, buffer++)) { 2241da177e4SLinus Torvalds retval = -EFAULT; 2251da177e4SLinus Torvalds goto out; 2261da177e4SLinus Torvalds } 22746f49b7aSDmitry Torokhov 2287c5bbb2eSDmitry Torokhov if (serio_write(serio_raw->serio, c)) { 22946f49b7aSDmitry Torokhov /* Either signal error or partial write */ 23046f49b7aSDmitry Torokhov if (retval == 0) 2311da177e4SLinus Torvalds retval = -EIO; 2321da177e4SLinus Torvalds goto out; 2331da177e4SLinus Torvalds } 23446f49b7aSDmitry Torokhov 23546f49b7aSDmitry Torokhov retval++; 236d89c9bcbSChe-Liang Chiou } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds out: 239c4e32e9fSArjan van de Ven mutex_unlock(&serio_raw_mutex); 24046f49b7aSDmitry Torokhov return retval; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds static unsigned int serio_raw_poll(struct file *file, poll_table *wait) 2441da177e4SLinus Torvalds { 2457c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 2467c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 2478c1c10d5SDmitry Torokhov unsigned int mask; 2481da177e4SLinus Torvalds 2497c5bbb2eSDmitry Torokhov poll_wait(file, &serio_raw->wait, wait); 2501da177e4SLinus Torvalds 2518c1c10d5SDmitry Torokhov mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; 2527c5bbb2eSDmitry Torokhov if (serio_raw->head != serio_raw->tail) 2530c62fbf6SDmitry Torokhov mask |= POLLIN | POLLRDNORM; 2541da177e4SLinus Torvalds 2550c62fbf6SDmitry Torokhov return mask; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2582b8693c0SArjan van de Ven static const struct file_operations serio_raw_fops = { 2591da177e4SLinus Torvalds .owner = THIS_MODULE, 2601da177e4SLinus Torvalds .open = serio_raw_open, 2611da177e4SLinus Torvalds .release = serio_raw_release, 2621da177e4SLinus Torvalds .read = serio_raw_read, 2631da177e4SLinus Torvalds .write = serio_raw_write, 2641da177e4SLinus Torvalds .poll = serio_raw_poll, 2651da177e4SLinus Torvalds .fasync = serio_raw_fasync, 2666038f373SArnd Bergmann .llseek = noop_llseek, 2671da177e4SLinus Torvalds }; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds /********************************************************************* 2711da177e4SLinus Torvalds * Interface with serio port * 2721da177e4SLinus Torvalds *********************************************************************/ 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, 2757d12e780SDavid Howells unsigned int dfl) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 2787c5bbb2eSDmitry Torokhov struct serio_raw_client *client; 2791da177e4SLinus Torvalds unsigned int head = serio_raw->head; 2801da177e4SLinus Torvalds 2817c5bbb2eSDmitry Torokhov /* we are holding serio->lock here so we are protected */ 2821da177e4SLinus Torvalds serio_raw->queue[head] = data; 2831da177e4SLinus Torvalds head = (head + 1) % SERIO_RAW_QUEUE_LEN; 2841da177e4SLinus Torvalds if (likely(head != serio_raw->tail)) { 2851da177e4SLinus Torvalds serio_raw->head = head; 2867c5bbb2eSDmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 2877c5bbb2eSDmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_IN); 2881da177e4SLinus Torvalds wake_up_interruptible(&serio_raw->wait); 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds return IRQ_HANDLED; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) 2951da177e4SLinus Torvalds { 296550eca7cSDmitry Torokhov static atomic_t serio_raw_no = ATOMIC_INIT(0); 2971da177e4SLinus Torvalds struct serio_raw *serio_raw; 2981da177e4SLinus Torvalds int err; 2991da177e4SLinus Torvalds 30015a564d8SDmitry Torokhov serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL); 30115a564d8SDmitry Torokhov if (!serio_raw) { 3028d928477SDmitry Torokhov dev_dbg(&serio->dev, "can't allocate memory for a device\n"); 3031da177e4SLinus Torvalds return -ENOMEM; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 30615a564d8SDmitry Torokhov snprintf(serio_raw->name, sizeof(serio_raw->name), 307550eca7cSDmitry Torokhov "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1); 308ba538cd2SDmitry Torokhov kref_init(&serio_raw->kref); 3097c5bbb2eSDmitry Torokhov INIT_LIST_HEAD(&serio_raw->client_list); 3101da177e4SLinus Torvalds init_waitqueue_head(&serio_raw->wait); 3111da177e4SLinus Torvalds 31285f5b35dSDmitry Torokhov serio_raw->serio = serio; 31385f5b35dSDmitry Torokhov get_device(&serio->dev); 31485f5b35dSDmitry Torokhov 3151da177e4SLinus Torvalds serio_set_drvdata(serio, serio_raw); 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds err = serio_open(serio, drv); 3181da177e4SLinus Torvalds if (err) 319550eca7cSDmitry Torokhov goto err_free; 320550eca7cSDmitry Torokhov 321550eca7cSDmitry Torokhov err = mutex_lock_killable(&serio_raw_mutex); 322550eca7cSDmitry Torokhov if (err) 323550eca7cSDmitry Torokhov goto err_close; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds list_add_tail(&serio_raw->node, &serio_raw_list); 326550eca7cSDmitry Torokhov mutex_unlock(&serio_raw_mutex); 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds serio_raw->dev.minor = PSMOUSE_MINOR; 3291da177e4SLinus Torvalds serio_raw->dev.name = serio_raw->name; 33094fbcdedSGreg Kroah-Hartman serio_raw->dev.parent = &serio->dev; 3311da177e4SLinus Torvalds serio_raw->dev.fops = &serio_raw_fops; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds err = misc_register(&serio_raw->dev); 3341da177e4SLinus Torvalds if (err) { 3351da177e4SLinus Torvalds serio_raw->dev.minor = MISC_DYNAMIC_MINOR; 3361da177e4SLinus Torvalds err = misc_register(&serio_raw->dev); 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (err) { 3408d928477SDmitry Torokhov dev_err(&serio->dev, 3418d928477SDmitry Torokhov "failed to register raw access device for %s\n", 3421da177e4SLinus Torvalds serio->phys); 343550eca7cSDmitry Torokhov goto err_unlink; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3468d928477SDmitry Torokhov dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", 3471da177e4SLinus Torvalds serio->phys, serio_raw->name, serio_raw->dev.minor); 348550eca7cSDmitry Torokhov return 0; 3491da177e4SLinus Torvalds 350550eca7cSDmitry Torokhov err_unlink: 3511da177e4SLinus Torvalds list_del_init(&serio_raw->node); 352550eca7cSDmitry Torokhov err_close: 353550eca7cSDmitry Torokhov serio_close(serio); 354550eca7cSDmitry Torokhov err_free: 3551da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 356550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 3571da177e4SLinus Torvalds return err; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds static int serio_raw_reconnect(struct serio *serio) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 3631da177e4SLinus Torvalds struct serio_driver *drv = serio->drv; 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds if (!drv || !serio_raw) { 3668d928477SDmitry Torokhov dev_dbg(&serio->dev, 3678d928477SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n"); 3681da177e4SLinus Torvalds return -1; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* 3721da177e4SLinus Torvalds * Nothing needs to be done here, we just need this method to 3731da177e4SLinus Torvalds * keep the same device. 3741da177e4SLinus Torvalds */ 3751da177e4SLinus Torvalds return 0; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3788c1c10d5SDmitry Torokhov /* 3798c1c10d5SDmitry Torokhov * Wake up users waiting for IO so they can disconnect from 3808c1c10d5SDmitry Torokhov * dead device. 3818c1c10d5SDmitry Torokhov */ 3828c1c10d5SDmitry Torokhov static void serio_raw_hangup(struct serio_raw *serio_raw) 3838c1c10d5SDmitry Torokhov { 3848c1c10d5SDmitry Torokhov struct serio_raw_client *client; 3858c1c10d5SDmitry Torokhov 3868c1c10d5SDmitry Torokhov serio_pause_rx(serio_raw->serio); 3878c1c10d5SDmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 3888c1c10d5SDmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_HUP); 3898c1c10d5SDmitry Torokhov serio_continue_rx(serio_raw->serio); 3908c1c10d5SDmitry Torokhov 3918c1c10d5SDmitry Torokhov wake_up_interruptible(&serio_raw->wait); 3928c1c10d5SDmitry Torokhov } 3938c1c10d5SDmitry Torokhov 3948c1c10d5SDmitry Torokhov 3951da177e4SLinus Torvalds static void serio_raw_disconnect(struct serio *serio) 3961da177e4SLinus Torvalds { 3978c1c10d5SDmitry Torokhov struct serio_raw *serio_raw = serio_get_drvdata(serio); 3981da177e4SLinus Torvalds 399550eca7cSDmitry Torokhov misc_deregister(&serio_raw->dev); 400550eca7cSDmitry Torokhov 401c4e32e9fSArjan van de Ven mutex_lock(&serio_raw_mutex); 402550eca7cSDmitry Torokhov serio_raw->dead = true; 403550eca7cSDmitry Torokhov list_del_init(&serio_raw->node); 404550eca7cSDmitry Torokhov mutex_unlock(&serio_raw_mutex); 405550eca7cSDmitry Torokhov 406550eca7cSDmitry Torokhov serio_raw_hangup(serio_raw); 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds serio_close(serio); 409550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 4108c1c10d5SDmitry Torokhov 4118c1c10d5SDmitry Torokhov serio_set_drvdata(serio, NULL); 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds static struct serio_device_id serio_raw_serio_ids[] = { 4151da177e4SLinus Torvalds { 4161da177e4SLinus Torvalds .type = SERIO_8042, 4171da177e4SLinus Torvalds .proto = SERIO_ANY, 4181da177e4SLinus Torvalds .id = SERIO_ANY, 4191da177e4SLinus Torvalds .extra = SERIO_ANY, 4201da177e4SLinus Torvalds }, 421d19497e2SNiels de Vos { 422d19497e2SNiels de Vos .type = SERIO_8042_XL, 423d19497e2SNiels de Vos .proto = SERIO_ANY, 424d19497e2SNiels de Vos .id = SERIO_ANY, 425d19497e2SNiels de Vos .extra = SERIO_ANY, 426d19497e2SNiels de Vos }, 4271da177e4SLinus Torvalds { 0 } 4281da177e4SLinus Torvalds }; 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds static struct serio_driver serio_raw_drv = { 4331da177e4SLinus Torvalds .driver = { 4341da177e4SLinus Torvalds .name = "serio_raw", 4351da177e4SLinus Torvalds }, 4361da177e4SLinus Torvalds .description = DRIVER_DESC, 4371da177e4SLinus Torvalds .id_table = serio_raw_serio_ids, 4381da177e4SLinus Torvalds .interrupt = serio_raw_interrupt, 4391da177e4SLinus Torvalds .connect = serio_raw_connect, 4401da177e4SLinus Torvalds .reconnect = serio_raw_reconnect, 4411da177e4SLinus Torvalds .disconnect = serio_raw_disconnect, 4428c31eb01SDmitry Torokhov .manual_bind = true, 4431da177e4SLinus Torvalds }; 4441da177e4SLinus Torvalds 44565ac9f7aSAxel Lin module_serio_driver(serio_raw_drv); 446