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/major.h> 191da177e4SLinus Torvalds #include <linux/device.h> 201da177e4SLinus Torvalds #include <linux/miscdevice.h> 211da177e4SLinus Torvalds #include <linux/wait.h> 22c4e32e9fSArjan van de Ven #include <linux/mutex.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #define DRIVER_DESC "Raw serio driver" 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 271da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 281da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #define SERIO_RAW_QUEUE_LEN 64 311da177e4SLinus Torvalds struct serio_raw { 321da177e4SLinus Torvalds unsigned char queue[SERIO_RAW_QUEUE_LEN]; 331da177e4SLinus Torvalds unsigned int tail, head; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds char name[16]; 36ba538cd2SDmitry Torokhov struct kref kref; 371da177e4SLinus Torvalds struct serio *serio; 381da177e4SLinus Torvalds struct miscdevice dev; 391da177e4SLinus Torvalds wait_queue_head_t wait; 407c5bbb2eSDmitry Torokhov struct list_head client_list; 411da177e4SLinus Torvalds struct list_head node; 4285f5b35dSDmitry Torokhov bool dead; 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 457c5bbb2eSDmitry Torokhov struct serio_raw_client { 461da177e4SLinus Torvalds struct fasync_struct *fasync; 471da177e4SLinus Torvalds struct serio_raw *serio_raw; 481da177e4SLinus Torvalds struct list_head node; 491da177e4SLinus Torvalds }; 501da177e4SLinus Torvalds 51c4e32e9fSArjan van de Ven static DEFINE_MUTEX(serio_raw_mutex); 521da177e4SLinus Torvalds static LIST_HEAD(serio_raw_list); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /********************************************************************* 551da177e4SLinus Torvalds * Interface with userspace (file operations) * 561da177e4SLinus Torvalds *********************************************************************/ 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static int serio_raw_fasync(int fd, struct file *file, int on) 591da177e4SLinus Torvalds { 607c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 611da177e4SLinus Torvalds 627c5bbb2eSDmitry Torokhov return fasync_helper(fd, file, on, &client->fasync); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds static struct serio_raw *serio_raw_locate(int minor) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds struct serio_raw *serio_raw; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds list_for_each_entry(serio_raw, &serio_raw_list, node) { 701da177e4SLinus Torvalds if (serio_raw->dev.minor == minor) 711da177e4SLinus Torvalds return serio_raw; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds return NULL; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static int serio_raw_open(struct inode *inode, struct file *file) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds struct serio_raw *serio_raw; 807c5bbb2eSDmitry Torokhov struct serio_raw_client *client; 817c5bbb2eSDmitry Torokhov int retval; 821da177e4SLinus Torvalds 83c4e32e9fSArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 841da177e4SLinus Torvalds if (retval) 8577554b4dSThadeu Lima de Souza Cascardo return retval; 861da177e4SLinus Torvalds 8777554b4dSThadeu Lima de Souza Cascardo serio_raw = serio_raw_locate(iminor(inode)); 8877554b4dSThadeu Lima de Souza Cascardo if (!serio_raw) { 891da177e4SLinus Torvalds retval = -ENODEV; 901da177e4SLinus Torvalds goto out; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 9385f5b35dSDmitry Torokhov if (serio_raw->dead) { 941da177e4SLinus Torvalds retval = -ENODEV; 951da177e4SLinus Torvalds goto out; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 987c5bbb2eSDmitry Torokhov client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL); 997c5bbb2eSDmitry Torokhov if (!client) { 1001da177e4SLinus Torvalds retval = -ENOMEM; 1011da177e4SLinus Torvalds goto out; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1047c5bbb2eSDmitry Torokhov client->serio_raw = serio_raw; 1057c5bbb2eSDmitry Torokhov file->private_data = client; 1061da177e4SLinus Torvalds 107ba538cd2SDmitry Torokhov kref_get(&serio_raw->kref); 108843e784aSDmitry Torokhov 109843e784aSDmitry Torokhov serio_pause_rx(serio_raw->serio); 1107c5bbb2eSDmitry Torokhov list_add_tail(&client->node, &serio_raw->client_list); 111843e784aSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds out: 114c4e32e9fSArjan van de Ven mutex_unlock(&serio_raw_mutex); 1151da177e4SLinus Torvalds return retval; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 118550eca7cSDmitry Torokhov static void serio_raw_free(struct kref *kref) 1191da177e4SLinus Torvalds { 120ba538cd2SDmitry Torokhov struct serio_raw *serio_raw = 121ba538cd2SDmitry Torokhov container_of(kref, struct serio_raw, kref); 122ba538cd2SDmitry Torokhov 12385f5b35dSDmitry Torokhov put_device(&serio_raw->serio->dev); 1241da177e4SLinus Torvalds kfree(serio_raw); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static int serio_raw_release(struct inode *inode, struct file *file) 1281da177e4SLinus Torvalds { 1297c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 1307c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1311da177e4SLinus Torvalds 132550eca7cSDmitry Torokhov serio_pause_rx(serio_raw->serio); 133550eca7cSDmitry Torokhov list_del(&client->node); 134550eca7cSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1351da177e4SLinus Torvalds 136550eca7cSDmitry Torokhov kfree(client); 1371da177e4SLinus Torvalds 138550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 139550eca7cSDmitry Torokhov 1401da177e4SLinus Torvalds return 0; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1438c31eb01SDmitry Torokhov static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) 1441da177e4SLinus Torvalds { 1458c31eb01SDmitry Torokhov bool empty; 1461da177e4SLinus Torvalds 147843e784aSDmitry Torokhov serio_pause_rx(serio_raw->serio); 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds empty = serio_raw->head == serio_raw->tail; 1501da177e4SLinus Torvalds if (!empty) { 1511da177e4SLinus Torvalds *c = serio_raw->queue[serio_raw->tail]; 1521da177e4SLinus Torvalds serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 155843e784aSDmitry Torokhov serio_continue_rx(serio_raw->serio); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds return !empty; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 16015a564d8SDmitry Torokhov static ssize_t serio_raw_read(struct file *file, char __user *buffer, 16115a564d8SDmitry Torokhov size_t count, loff_t *ppos) 1621da177e4SLinus Torvalds { 1637c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 1647c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1654f179f71SAndrew Morton char uninitialized_var(c); 1667a0a27d2SChe-Liang Chiou ssize_t read = 0; 16746f49b7aSDmitry Torokhov int error; 1681da177e4SLinus Torvalds 16946f49b7aSDmitry Torokhov for (;;) { 17085f5b35dSDmitry Torokhov if (serio_raw->dead) 1711da177e4SLinus Torvalds return -ENODEV; 1721da177e4SLinus Torvalds 173486c8abaSDmitry Torokhov if (serio_raw->head == serio_raw->tail && 174486c8abaSDmitry Torokhov (file->f_flags & O_NONBLOCK)) 1751da177e4SLinus Torvalds return -EAGAIN; 1761da177e4SLinus Torvalds 177486c8abaSDmitry Torokhov if (count == 0) 178486c8abaSDmitry Torokhov break; 1791da177e4SLinus Torvalds 1807a0a27d2SChe-Liang Chiou while (read < count && serio_raw_fetch_byte(serio_raw, &c)) { 18146f49b7aSDmitry Torokhov if (put_user(c, buffer++)) 18246f49b7aSDmitry Torokhov return -EFAULT; 1837a0a27d2SChe-Liang Chiou read++; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 186486c8abaSDmitry Torokhov if (read) 187486c8abaSDmitry Torokhov break; 188486c8abaSDmitry Torokhov 18946f49b7aSDmitry Torokhov if (!(file->f_flags & O_NONBLOCK)) { 190486c8abaSDmitry Torokhov error = wait_event_interruptible(serio_raw->wait, 191486c8abaSDmitry Torokhov serio_raw->head != serio_raw->tail || 192486c8abaSDmitry Torokhov serio_raw->dead); 19346f49b7aSDmitry Torokhov if (error) 19446f49b7aSDmitry Torokhov return error; 19546f49b7aSDmitry Torokhov } 19646f49b7aSDmitry Torokhov } 197486c8abaSDmitry Torokhov 19846f49b7aSDmitry Torokhov return read; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 20115a564d8SDmitry Torokhov static ssize_t serio_raw_write(struct file *file, const char __user *buffer, 20215a564d8SDmitry Torokhov size_t count, loff_t *ppos) 2031da177e4SLinus Torvalds { 2047c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 2057c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 20646f49b7aSDmitry Torokhov int retval = 0; 2071da177e4SLinus Torvalds unsigned char c; 2081da177e4SLinus Torvalds 209c4e32e9fSArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 2101da177e4SLinus Torvalds if (retval) 2111da177e4SLinus Torvalds return retval; 2121da177e4SLinus Torvalds 21385f5b35dSDmitry Torokhov if (serio_raw->dead) { 2141da177e4SLinus Torvalds retval = -ENODEV; 2151da177e4SLinus Torvalds goto out; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if (count > 32) 2191da177e4SLinus Torvalds count = 32; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds while (count--) { 2221da177e4SLinus Torvalds if (get_user(c, buffer++)) { 2231da177e4SLinus Torvalds retval = -EFAULT; 2241da177e4SLinus Torvalds goto out; 2251da177e4SLinus Torvalds } 22646f49b7aSDmitry Torokhov 2277c5bbb2eSDmitry Torokhov if (serio_write(serio_raw->serio, c)) { 22846f49b7aSDmitry Torokhov /* Either signal error or partial write */ 22946f49b7aSDmitry Torokhov if (retval == 0) 2301da177e4SLinus Torvalds retval = -EIO; 2311da177e4SLinus Torvalds goto out; 2321da177e4SLinus Torvalds } 23346f49b7aSDmitry Torokhov 23446f49b7aSDmitry Torokhov retval++; 235d89c9bcbSChe-Liang Chiou } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds out: 238c4e32e9fSArjan van de Ven mutex_unlock(&serio_raw_mutex); 23946f49b7aSDmitry Torokhov return retval; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static unsigned int serio_raw_poll(struct file *file, poll_table *wait) 2431da177e4SLinus Torvalds { 2447c5bbb2eSDmitry Torokhov struct serio_raw_client *client = file->private_data; 2457c5bbb2eSDmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 2468c1c10d5SDmitry Torokhov unsigned int mask; 2471da177e4SLinus Torvalds 2487c5bbb2eSDmitry Torokhov poll_wait(file, &serio_raw->wait, wait); 2491da177e4SLinus Torvalds 2508c1c10d5SDmitry Torokhov mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; 2517c5bbb2eSDmitry Torokhov if (serio_raw->head != serio_raw->tail) 2520c62fbf6SDmitry Torokhov mask |= POLLIN | POLLRDNORM; 2531da177e4SLinus Torvalds 2540c62fbf6SDmitry Torokhov return mask; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2572b8693c0SArjan van de Ven static const struct file_operations serio_raw_fops = { 2581da177e4SLinus Torvalds .owner = THIS_MODULE, 2591da177e4SLinus Torvalds .open = serio_raw_open, 2601da177e4SLinus Torvalds .release = serio_raw_release, 2611da177e4SLinus Torvalds .read = serio_raw_read, 2621da177e4SLinus Torvalds .write = serio_raw_write, 2631da177e4SLinus Torvalds .poll = serio_raw_poll, 2641da177e4SLinus Torvalds .fasync = serio_raw_fasync, 2656038f373SArnd Bergmann .llseek = noop_llseek, 2661da177e4SLinus Torvalds }; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds /********************************************************************* 2701da177e4SLinus Torvalds * Interface with serio port * 2711da177e4SLinus Torvalds *********************************************************************/ 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, 2747d12e780SDavid Howells unsigned int dfl) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 2777c5bbb2eSDmitry Torokhov struct serio_raw_client *client; 2781da177e4SLinus Torvalds unsigned int head = serio_raw->head; 2791da177e4SLinus Torvalds 2807c5bbb2eSDmitry Torokhov /* we are holding serio->lock here so we are protected */ 2811da177e4SLinus Torvalds serio_raw->queue[head] = data; 2821da177e4SLinus Torvalds head = (head + 1) % SERIO_RAW_QUEUE_LEN; 2831da177e4SLinus Torvalds if (likely(head != serio_raw->tail)) { 2841da177e4SLinus Torvalds serio_raw->head = head; 2857c5bbb2eSDmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 2867c5bbb2eSDmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_IN); 2871da177e4SLinus Torvalds wake_up_interruptible(&serio_raw->wait); 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds return IRQ_HANDLED; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) 2941da177e4SLinus Torvalds { 295939ffb17SAniroop Mathur static atomic_t serio_raw_no = ATOMIC_INIT(-1); 2961da177e4SLinus Torvalds struct serio_raw *serio_raw; 2971da177e4SLinus Torvalds int err; 2981da177e4SLinus Torvalds 29915a564d8SDmitry Torokhov serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL); 30015a564d8SDmitry Torokhov if (!serio_raw) { 3018d928477SDmitry Torokhov dev_dbg(&serio->dev, "can't allocate memory for a device\n"); 3021da177e4SLinus Torvalds return -ENOMEM; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 30515a564d8SDmitry Torokhov snprintf(serio_raw->name, sizeof(serio_raw->name), 306939ffb17SAniroop Mathur "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no)); 307ba538cd2SDmitry Torokhov kref_init(&serio_raw->kref); 3087c5bbb2eSDmitry Torokhov INIT_LIST_HEAD(&serio_raw->client_list); 3091da177e4SLinus Torvalds init_waitqueue_head(&serio_raw->wait); 3101da177e4SLinus Torvalds 31185f5b35dSDmitry Torokhov serio_raw->serio = serio; 31285f5b35dSDmitry Torokhov get_device(&serio->dev); 31385f5b35dSDmitry Torokhov 3141da177e4SLinus Torvalds serio_set_drvdata(serio, serio_raw); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds err = serio_open(serio, drv); 3171da177e4SLinus Torvalds if (err) 318550eca7cSDmitry Torokhov goto err_free; 319550eca7cSDmitry Torokhov 320550eca7cSDmitry Torokhov err = mutex_lock_killable(&serio_raw_mutex); 321550eca7cSDmitry Torokhov if (err) 322550eca7cSDmitry Torokhov goto err_close; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds list_add_tail(&serio_raw->node, &serio_raw_list); 325550eca7cSDmitry Torokhov mutex_unlock(&serio_raw_mutex); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds serio_raw->dev.minor = PSMOUSE_MINOR; 3281da177e4SLinus Torvalds serio_raw->dev.name = serio_raw->name; 32994fbcdedSGreg Kroah-Hartman serio_raw->dev.parent = &serio->dev; 3301da177e4SLinus Torvalds serio_raw->dev.fops = &serio_raw_fops; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds err = misc_register(&serio_raw->dev); 3331da177e4SLinus Torvalds if (err) { 3341da177e4SLinus Torvalds serio_raw->dev.minor = MISC_DYNAMIC_MINOR; 3351da177e4SLinus Torvalds err = misc_register(&serio_raw->dev); 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if (err) { 3398d928477SDmitry Torokhov dev_err(&serio->dev, 3408d928477SDmitry Torokhov "failed to register raw access device for %s\n", 3411da177e4SLinus Torvalds serio->phys); 342550eca7cSDmitry Torokhov goto err_unlink; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3458d928477SDmitry Torokhov dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", 3461da177e4SLinus Torvalds serio->phys, serio_raw->name, serio_raw->dev.minor); 347550eca7cSDmitry Torokhov return 0; 3481da177e4SLinus Torvalds 349550eca7cSDmitry Torokhov err_unlink: 3501da177e4SLinus Torvalds list_del_init(&serio_raw->node); 351550eca7cSDmitry Torokhov err_close: 352550eca7cSDmitry Torokhov serio_close(serio); 353550eca7cSDmitry Torokhov err_free: 3541da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 355550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 3561da177e4SLinus Torvalds return err; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds static int serio_raw_reconnect(struct serio *serio) 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 3621da177e4SLinus Torvalds struct serio_driver *drv = serio->drv; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds if (!drv || !serio_raw) { 3658d928477SDmitry Torokhov dev_dbg(&serio->dev, 3668d928477SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n"); 3671da177e4SLinus Torvalds return -1; 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* 3711da177e4SLinus Torvalds * Nothing needs to be done here, we just need this method to 3721da177e4SLinus Torvalds * keep the same device. 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds return 0; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3778c1c10d5SDmitry Torokhov /* 3788c1c10d5SDmitry Torokhov * Wake up users waiting for IO so they can disconnect from 3798c1c10d5SDmitry Torokhov * dead device. 3808c1c10d5SDmitry Torokhov */ 3818c1c10d5SDmitry Torokhov static void serio_raw_hangup(struct serio_raw *serio_raw) 3828c1c10d5SDmitry Torokhov { 3838c1c10d5SDmitry Torokhov struct serio_raw_client *client; 3848c1c10d5SDmitry Torokhov 3858c1c10d5SDmitry Torokhov serio_pause_rx(serio_raw->serio); 3868c1c10d5SDmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 3878c1c10d5SDmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_HUP); 3888c1c10d5SDmitry Torokhov serio_continue_rx(serio_raw->serio); 3898c1c10d5SDmitry Torokhov 3908c1c10d5SDmitry Torokhov wake_up_interruptible(&serio_raw->wait); 3918c1c10d5SDmitry Torokhov } 3928c1c10d5SDmitry Torokhov 3938c1c10d5SDmitry Torokhov 3941da177e4SLinus Torvalds static void serio_raw_disconnect(struct serio *serio) 3951da177e4SLinus Torvalds { 3968c1c10d5SDmitry Torokhov struct serio_raw *serio_raw = serio_get_drvdata(serio); 3971da177e4SLinus Torvalds 398550eca7cSDmitry Torokhov misc_deregister(&serio_raw->dev); 399550eca7cSDmitry Torokhov 400c4e32e9fSArjan van de Ven mutex_lock(&serio_raw_mutex); 401550eca7cSDmitry Torokhov serio_raw->dead = true; 402550eca7cSDmitry Torokhov list_del_init(&serio_raw->node); 403550eca7cSDmitry Torokhov mutex_unlock(&serio_raw_mutex); 404550eca7cSDmitry Torokhov 405550eca7cSDmitry Torokhov serio_raw_hangup(serio_raw); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds serio_close(serio); 408550eca7cSDmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 4098c1c10d5SDmitry Torokhov 4108c1c10d5SDmitry Torokhov serio_set_drvdata(serio, NULL); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds static struct serio_device_id serio_raw_serio_ids[] = { 4141da177e4SLinus Torvalds { 4151da177e4SLinus Torvalds .type = SERIO_8042, 4161da177e4SLinus Torvalds .proto = SERIO_ANY, 4171da177e4SLinus Torvalds .id = SERIO_ANY, 4181da177e4SLinus Torvalds .extra = SERIO_ANY, 4191da177e4SLinus Torvalds }, 420d19497e2SNiels de Vos { 421d19497e2SNiels de Vos .type = SERIO_8042_XL, 422d19497e2SNiels de Vos .proto = SERIO_ANY, 423d19497e2SNiels de Vos .id = SERIO_ANY, 424d19497e2SNiels de Vos .extra = SERIO_ANY, 425d19497e2SNiels de Vos }, 4261da177e4SLinus Torvalds { 0 } 4271da177e4SLinus Torvalds }; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds static struct serio_driver serio_raw_drv = { 4321da177e4SLinus Torvalds .driver = { 4331da177e4SLinus Torvalds .name = "serio_raw", 4341da177e4SLinus Torvalds }, 4351da177e4SLinus Torvalds .description = DRIVER_DESC, 4361da177e4SLinus Torvalds .id_table = serio_raw_serio_ids, 4371da177e4SLinus Torvalds .interrupt = serio_raw_interrupt, 4381da177e4SLinus Torvalds .connect = serio_raw_connect, 4391da177e4SLinus Torvalds .reconnect = serio_raw_reconnect, 4401da177e4SLinus Torvalds .disconnect = serio_raw_disconnect, 4418c31eb01SDmitry Torokhov .manual_bind = true, 4421da177e4SLinus Torvalds }; 4431da177e4SLinus Torvalds 44465ac9f7aSAxel Lin module_serio_driver(serio_raw_drv); 445