11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Raw serio device providing access to a raw byte stream from underlying 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2004 Dmitry Torokhov 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov#include <linux/kref.h> 13d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serio.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h> 22c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Ven#include <linux/mutex.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Raw serio driver" 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERIO_RAW_QUEUE_LEN 64 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct serio_raw { 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char queue[SERIO_RAW_QUEUE_LEN]; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tail, head; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[16]; 36ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov struct kref kref; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio *serio; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct miscdevice dev; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t wait; 407c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct list_head client_list; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head node; 4285f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov bool dead; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 457c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhovstruct serio_raw_client { 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fasync_struct *fasync; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head node; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Venstatic DEFINE_MUTEX(serio_raw_mutex); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(serio_raw_list); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************* 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interface with userspace (file operations) * 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *********************************************************************/ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serio_raw_fasync(int fd, struct file *file, int on) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 607c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client = file->private_data; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 627c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov return fasync_helper(fd, file, on, &client->fasync); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_raw *serio_raw_locate(int minor) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(serio_raw, &serio_raw_list, node) { 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (serio_raw->dev.minor == minor) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return serio_raw; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serio_raw_open(struct inode *inode, struct file *file) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw; 807c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client; 817c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov int retval; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 8577554b4d1fac6a66d4e624a6e36c020a4f5b6b64Thadeu Lima de Souza Cascardo return retval; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8777554b4d1fac6a66d4e624a6e36c020a4f5b6b64Thadeu Lima de Souza Cascardo serio_raw = serio_raw_locate(iminor(inode)); 8877554b4d1fac6a66d4e624a6e36c020a4f5b6b64Thadeu Lima de Souza Cascardo if (!serio_raw) { 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9385f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov if (serio_raw->dead) { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 987c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL); 997c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov if (!client) { 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENOMEM; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1047c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov client->serio_raw = serio_raw; 1057c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov file->private_data = client; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov kref_get(&serio_raw->kref); 108843e784afe164ac8c75a97259d54cf489be74bb9Dmitry Torokhov 109843e784afe164ac8c75a97259d54cf489be74bb9Dmitry Torokhov serio_pause_rx(serio_raw->serio); 1107c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov list_add_tail(&client->node, &serio_raw->client_list); 111843e784afe164ac8c75a97259d54cf489be74bb9Dmitry Torokhov serio_continue_rx(serio_raw->serio); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 114c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Ven mutex_unlock(&serio_raw_mutex); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhovstatic void serio_raw_free(struct kref *kref) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 120ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov struct serio_raw *serio_raw = 121ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov container_of(kref, struct serio_raw, kref); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12385f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov put_device(&serio_raw->serio->dev); 124ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov kfree(serio_raw); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serio_raw_release(struct inode *inode, struct file *file) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1297c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client = file->private_data; 1307c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov serio_pause_rx(serio_raw->serio); 133550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov list_del(&client->node); 134550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov serio_continue_rx(serio_raw->serio); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov kfree(client); 137550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov 138550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1438c31eb01e1ab91df69c60554b9aec2d522d414e0Dmitry Torokhovstatic bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1458c31eb01e1ab91df69c60554b9aec2d522d414e0Dmitry Torokhov bool empty; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147843e784afe164ac8c75a97259d54cf489be74bb9Dmitry Torokhov serio_pause_rx(serio_raw->serio); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds empty = serio_raw->head == serio_raw->tail; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!empty) { 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *c = serio_raw->queue[serio_raw->tail]; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 155843e784afe164ac8c75a97259d54cf489be74bb9Dmitry Torokhov serio_continue_rx(serio_raw->serio); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return !empty; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16015a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhovstatic ssize_t serio_raw_read(struct file *file, char __user *buffer, 16115a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov size_t count, loff_t *ppos) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1637c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client = file->private_data; 1647c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 1654f179f71607382888c5ce5385a4ee136e1a2002aAndrew Morton char uninitialized_var(c); 1667a0a27d2ce38aee19a31fee8c12095f586eed393Che-Liang Chiou ssize_t read = 0; 16746f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov int error; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16946f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov for (;;) { 170486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov if (serio_raw->dead) 171486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov return -ENODEV; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 173486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov if (serio_raw->head == serio_raw->tail && 174486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov (file->f_flags & O_NONBLOCK)) 175486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov return -EAGAIN; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 177486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov if (count == 0) 178486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov break; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov while (read < count && serio_raw_fetch_byte(serio_raw, &c)) { 18146f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov if (put_user(c, buffer++)) 18246f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov return -EFAULT; 183486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov read++; 184486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov } 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 186486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov if (read) 1877a0a27d2ce38aee19a31fee8c12095f586eed393Che-Liang Chiou break; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18946f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov if (!(file->f_flags & O_NONBLOCK)) { 190486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov error = wait_event_interruptible(serio_raw->wait, 191486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov serio_raw->head != serio_raw->tail || 192486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov serio_raw->dead); 19346f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov if (error) 19446f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov return error; 19546f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov } 19646f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov } 197486c8aba39e5f194519cd5c0e85e5d1de8b74b03Dmitry Torokhov 19846f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov return read; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20115a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhovstatic ssize_t serio_raw_write(struct file *file, const char __user *buffer, 20215a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov size_t count, loff_t *ppos) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2047c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client = file->private_data; 2057c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 20646f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov int retval = 0; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char c; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Ven retval = mutex_lock_interruptible(&serio_raw_mutex); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21385f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov if (serio_raw->dead) { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > 32) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = 32; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (count--) { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(c, buffer++)) { 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EFAULT; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22646f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov 2277c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov if (serio_write(serio_raw->serio, c)) { 22846f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov /* Either signal error or partial write */ 22946f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov if (retval == 0) 23046f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov retval = -EIO; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23346f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov 23446f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov retval++; 235d89c9bcb33909568905ec9c4b44a18cd8bd88aaaChe-Liang Chiou } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 238c4e32e9faaaa83340dbbc00e07c48d38f032b7dcArjan van de Ven mutex_unlock(&serio_raw_mutex); 23946f49b7a223ac7493e7cf619fb583d11edefc2c2Dmitry Torokhov return retval; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int serio_raw_poll(struct file *file, poll_table *wait) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2447c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client = file->private_data; 2457c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw *serio_raw = client->serio_raw; 2468c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov unsigned int mask; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2487c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov poll_wait(file, &serio_raw->wait, wait); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2508c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; 2517c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov if (serio_raw->head != serio_raw->tail) 2520c62fbf6009fa338bd28bdcb14efbfc5fc0c579bDmitry Torokhov mask |= POLLIN | POLLRDNORM; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2540c62fbf6009fa338bd28bdcb14efbfc5fc0c579bDmitry Torokhov return mask; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2572b8693c0617e972fc0b2fd1ebf8de97e15b656c3Arjan van de Venstatic const struct file_operations serio_raw_fops = { 2587c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .owner = THIS_MODULE, 2597c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .open = serio_raw_open, 2607c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .release = serio_raw_release, 2617c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .read = serio_raw_read, 2627c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .write = serio_raw_write, 2637c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .poll = serio_raw_poll, 2647c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .fasync = serio_raw_fasync, 2657c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov .llseek = noop_llseek, 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********************************************************************* 27015a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov * Interface with serio port * 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *********************************************************************/ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, 2747d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells unsigned int dfl) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 2777c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov struct serio_raw_client *client; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int head = serio_raw->head; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2807c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov /* we are holding serio->lock here so we are protected */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->queue[head] = data; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = (head + 1) % SERIO_RAW_QUEUE_LEN; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (likely(head != serio_raw->tail)) { 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->head = head; 2857c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 2867c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_IN); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&serio_raw->wait); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serio_raw_connect(struct serio *serio, struct serio_driver *drv) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 295550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov static atomic_t serio_raw_no = ATOMIC_INIT(0); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29915a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL); 30015a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov if (!serio_raw) { 3018d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov dev_dbg(&serio->dev, "can't allocate memory for a device\n"); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30515a564d8dbfc9429540c2d9b38a64d1909de8b24Dmitry Torokhov snprintf(serio_raw->name, sizeof(serio_raw->name), 306550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1); 307ba538cd2a83f3556448759283d2330a603005afeDmitry Torokhov kref_init(&serio_raw->kref); 3087c5bbb2eb7ad047b53c205b1f500bae7b0a88c06Dmitry Torokhov INIT_LIST_HEAD(&serio_raw->client_list); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&serio_raw->wait); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31185f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov serio_raw->serio = serio; 31285f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov get_device(&serio->dev); 31385f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, serio_raw); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = serio_open(serio, drv); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 318550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov goto err_free; 319550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov 320550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov err = mutex_lock_killable(&serio_raw_mutex); 321550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov if (err) 322550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov goto err_close; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&serio_raw->node, &serio_raw_list); 325550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov mutex_unlock(&serio_raw_mutex); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->dev.minor = PSMOUSE_MINOR; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->dev.name = serio_raw->name; 32994fbcded4ea0dc14cbfb222a5c68372f150d1476Greg Kroah-Hartman serio_raw->dev.parent = &serio->dev; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->dev.fops = &serio_raw_fops; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = misc_register(&serio_raw->dev); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_raw->dev.minor = MISC_DYNAMIC_MINOR; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = misc_register(&serio_raw->dev); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 3398d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov dev_err(&serio->dev, 3408d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov "failed to register raw access device for %s\n", 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->phys); 342550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov goto err_unlink; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3458d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n", 3468d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov serio->phys, serio_raw->name, serio_raw->dev.minor); 347550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov return 0; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 349550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhoverr_unlink: 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init(&serio_raw->node); 351550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhoverr_close: 352550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov serio_close(serio); 353550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhoverr_free: 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, NULL); 355550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serio_raw_reconnect(struct serio *serio) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_raw *serio_raw = serio_get_drvdata(serio); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio_driver *drv = serio->drv; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!drv || !serio_raw) { 3658d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov dev_dbg(&serio->dev, 3668d92847700870e33cb92b43bde0a81f5a4298028Dmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n"); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nothing needs to be done here, we just need this method to 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * keep the same device. 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3778c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov/* 3788c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov * Wake up users waiting for IO so they can disconnect from 3798c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov * dead device. 3808c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov */ 3818c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhovstatic void serio_raw_hangup(struct serio_raw *serio_raw) 3828c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov{ 3838c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov struct serio_raw_client *client; 3848c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov 3858c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov serio_pause_rx(serio_raw->serio); 3868c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov list_for_each_entry(client, &serio_raw->client_list, node) 3878c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov kill_fasync(&client->fasync, SIGIO, POLL_HUP); 3888c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov serio_continue_rx(serio_raw->serio); 3898c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov 3908c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov wake_up_interruptible(&serio_raw->wait); 3918c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov} 3928c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov 3938c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serio_raw_disconnect(struct serio *serio) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3968c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov struct serio_raw *serio_raw = serio_get_drvdata(serio); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 398550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov misc_deregister(&serio_raw->dev); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 400550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov mutex_lock(&serio_raw_mutex); 40185f5b35da86bcd63dd27f0976176169727f96da4Dmitry Torokhov serio_raw->dead = true; 402550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov list_del_init(&serio_raw->node); 403550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov mutex_unlock(&serio_raw_mutex); 404550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov 4058c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov serio_raw_hangup(serio_raw); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 407550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov serio_close(serio); 408550eca7cafa1c6e2c077afb2211a364a982d8645Dmitry Torokhov kref_put(&serio_raw->kref, serio_raw_free); 4098c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov 4108c1c10d5706bbb3b41cb4a5578339d67d3eeffc2Dmitry Torokhov serio_set_drvdata(serio, NULL); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_device_id serio_raw_serio_ids[] = { 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = SERIO_8042, 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proto = SERIO_ANY, 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = SERIO_ANY, 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .extra = SERIO_ANY, 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 420d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos { 421d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos .type = SERIO_8042_XL, 422d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos .proto = SERIO_ANY, 423d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos .id = SERIO_ANY, 424d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos .extra = SERIO_ANY, 425d19497e2922cfe04bf0aa986bda6cf46c2b4705fNiels de Vos }, 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0 } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_driver serio_raw_drv = { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "serio_raw", 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = DRIVER_DESC, 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = serio_raw_serio_ids, 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .interrupt = serio_raw_interrupt, 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = serio_raw_connect, 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .reconnect = serio_raw_reconnect, 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = serio_raw_disconnect, 4418c31eb01e1ab91df69c60554b9aec2d522d414e0Dmitry Torokhov .manual_bind = true, 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44465ac9f7a23c934ee8c40dc20955e75db4924bfeaAxel Linmodule_serio_driver(serio_raw_drv); 445