11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1999-2001 Vojtech Pavlik 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB HIDBP Keyboard support 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 1005f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov * the Free Software Foundation; either version 2 of the License, or 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 1205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 1705f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 274291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 284291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 33ae0dadcf0f912cbab2ac84caa437454620bf71b2David Brownell#include <linux/usb/input.h> 344ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker#include <linux/hid.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "" 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB HID Boot Protocol keyboard driver" 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_LICENSE "GPL" 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(DRIVER_AUTHOR); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE(DRIVER_LICENSE); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48a44ebccea873cf7d58b63605f1cdd6da9dfec70fMing Leistatic const unsigned char usb_kbd_keycode[256] = { 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150,158,159,128,136,177,178,176,142,152,173,140 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 68c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx/** 69c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * struct usb_kbd - state of each attached keyboard 70c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @dev: input device associated with this keyboard 71c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @usbdev: usb device associated with this keyboard 72c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @old: data received in the past from the @irq URB representing which 73c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * keys were pressed. By comparing with the current list of keys 74c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * that are pressed, we are able to see key releases. 75c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @irq: URB for receiving a list of keys that are pressed when a 76c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * new key is pressed or a key that was pressed is released. 77c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @led: URB for sending LEDs (e.g. numlock, ...) 78c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @newleds: data that will be sent with the @led URB representing which LEDs 79c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx should be on 80c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @name: Name of the keyboard. @dev's name field points to this buffer 81c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @phys: Physical path of the keyboard. @dev's phys field points to this 82c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * buffer 83c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @new: Buffer for the @irq URB 84c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @cr: Control request for @led URB 85c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds: Buffer for the @led URB 86c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @new_dma: DMA address for @irq URB 87c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds_dma: DMA address for @led URB 88c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted 89c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been 90c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * submitted and its completion handler has not returned yet 91c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * without resubmitting @led 92c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct usb_kbd { 94c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *dev; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usbdev; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char old[8]; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *irq, *led; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char newleds; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[128]; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char phys[64]; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *new; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ctrlrequest *cr; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *leds; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t new_dma; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t leds_dma; 107c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 108c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spinlock_t leds_lock; 109c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx bool led_urb_submitted; 110c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1137d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void usb_kbd_irq(struct urb *urb) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_kbd *kbd = urb->context; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (urb->status) { 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* success */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: /* unlink */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* -EPIPE: should clear the halt */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* error */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 131c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 2; i < 8; i++) { 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_kbd_keycode[kbd->old[i]]) 137c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1394291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_info(urb->dev, 1404291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches "Unknown key (scancode %#x) released.\n", 1414291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches kbd->old[i]); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_kbd_keycode[kbd->new[i]]) 146c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1484291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_info(urb->dev, 1494291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches "Unknown key (scancode %#x) released.\n", 1504291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches kbd->new[i]); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_sync(kbd->dev); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(kbd->old, kbd->new, 8); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsresubmit: 15954e6ecb23951b195d02433a741c7f7cb0b796c78Christoph Lameter i = usb_submit_urb (urb, GFP_ATOMIC); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 1614291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d", 1624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches kbd->usbdev->bus->bus_name, 1634291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches kbd->usbdev->devpath, i); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 166be5e3383a95446e933be198d3025df10a072794bAdrian Bunkstatic int usb_kbd_event(struct input_dev *dev, unsigned int type, 167be5e3383a95446e933be198d3025df10a072794bAdrian Bunk unsigned int code, int value) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 169c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx unsigned long flags; 170e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type != EV_LED) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 175c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!!test_bit(LED_NUML, dev->led)); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx if (kbd->led_urb_submitted){ 181c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 183c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx if (*(kbd->leds) == kbd->newleds){ 186c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 188c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx } 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(kbd->leds) = kbd->newleds; 191c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->led->dev = kbd->usbdev; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_submit_urb(kbd->led, GFP_ATOMIC)) 1944291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches pr_err("usb_submit_urb(leds) failed\n"); 195c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx else 196c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx kbd->led_urb_submitted = true; 197c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 198c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 199c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2037d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void usb_kbd_led(struct urb *urb) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 205c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx unsigned long flags; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_kbd *kbd = urb->context; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status) 2094291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_warn(urb->dev, "led urb status %d received\n", 2107d89fe12bd21f1383a6a240114221bf31fd71904Greg Kroah-Hartman urb->status); 21105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 212c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags); 213c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 214c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx if (*(kbd->leds) == kbd->newleds){ 215c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx kbd->led_urb_submitted = false; 216c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 218c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(kbd->leds) = kbd->newleds; 221c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->led->dev = kbd->usbdev; 223c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx if (usb_submit_urb(kbd->led, GFP_ATOMIC)){ 2244291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); 225c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx kbd->led_urb_submitted = false; 226c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx } 227c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 228c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_kbd_open(struct input_dev *dev) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 233e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->irq->dev = kbd->usbdev; 23665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov if (usb_submit_urb(kbd->irq, GFP_KERNEL)) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_close(struct input_dev *dev) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 244e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov usb_kill_urb(kbd->irq); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 255997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma))) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2570ede76fcec5415ef82a423a95120286895822e2dAlan Stern if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 259997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2674ba0b2ed583b80cb26b9c8d8a8b418f677ec4a83Mariusz Kozlowski usb_free_urb(kbd->irq); 2684ba0b2ed583b80cb26b9c8d8a8b418f677ec4a83Mariusz Kozlowski usb_free_urb(kbd->led); 269997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(dev, 8, kbd->new, kbd->new_dma); 2700ede76fcec5415ef82a423a95120286895822e2dAlan Stern kfree(kbd->cr); 271997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhovstatic int usb_kbd_probe(struct usb_interface *iface, 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_device_id *id) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 277c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct usb_device *dev = interface_to_usbdev(iface); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_host_interface *interface; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_endpoint_descriptor *endpoint; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_kbd *kbd; 281c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov struct input_dev *input_dev; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, pipe, maxp; 2835d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov int error = -ENOMEM; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface = iface->cur_altsetting; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (interface->desc.bNumEndpoints != 1) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds endpoint = &interface->endpoint[0].desc; 291a20c314412b9e9e029a73dbb4dd951e36499eb58Luiz Fernando N. Capitulino if (!usb_endpoint_is_int_in(endpoint)) 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 297c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); 298c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev = input_allocate_device(); 299c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!kbd || !input_dev) 300c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail1; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (usb_kbd_alloc_mem(dev, kbd)) 303c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov goto fail2; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->usbdev = dev; 306c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kbd->dev = input_dev; 307c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx spin_lock_init(&kbd->leds_lock); 308c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 309c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (dev->manufacturer) 310c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); 311c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 312c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (dev->product) { 313c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (dev->manufacturer) 314c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcat(kbd->name, " ", sizeof(kbd->name)); 315c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov strlcat(kbd->name, dev->product, sizeof(kbd->name)); 316c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov } 317c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 318c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov if (!strlen(kbd->name)) 319c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov snprintf(kbd->name, sizeof(kbd->name), 320c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov "USB HIDBP Keyboard %04x:%04x", 321c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov le16_to_cpu(dev->descriptor.idVendor), 322c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov le16_to_cpu(dev->descriptor.idProduct)); 323c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 324c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); 3256236dfaa908d9e9c84a8c4d029f443104ed2c47fMárton Németh strlcat(kbd->phys, "/input0", sizeof(kbd->phys)); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 327c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->name = kbd->name; 328c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->phys = kbd->phys; 329c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov usb_to_input_id(dev, &input_dev->id); 330e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov input_dev->dev.parent = &iface->dev; 331e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov 332e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov input_set_drvdata(input_dev, kbd); 333c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 3347b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | 3357b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(EV_REP); 3367b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | 3377b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) | 3387b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby BIT_MASK(LED_KANA); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 255; i++) 341c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov set_bit(usb_kbd_keycode[i], input_dev->keybit); 342c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov clear_bit(0, input_dev->keybit); 34305f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 344c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->event = usb_kbd_event; 345c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->open = usb_kbd_open; 346c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_dev->close = usb_kbd_close; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_int_urb(kbd->irq, dev, pipe, 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->new, (maxp > 8 ? 8 : maxp), 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kbd_irq, kbd, endpoint->bInterval); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->irq->transfer_dma = kbd->new_dma; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->cr->bRequest = 0x09; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->cr->wValue = cpu_to_le16(0x200); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->cr->wLength = cpu_to_le16(1); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void *) kbd->cr, kbd->leds, 1, 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kbd_led, kbd); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->led->transfer_dma = kbd->leds_dma; 3640ede76fcec5415ef82a423a95120286895822e2dAlan Stern kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3665d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov error = input_register_device(kbd->dev); 3675d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov if (error) 3685d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov goto fail2; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(iface, kbd); 3713d61510f4ecacfe47c75c0eb51c0659dfa77fb1bAlan Stern device_set_wakeup_enable(&dev->dev, 1); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 373c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov 3745d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhovfail2: 3755d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov usb_kbd_free_mem(dev, kbd); 3765d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhovfail1: 3775d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov input_free_device(input_dev); 378c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov kfree(kbd); 3795d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov return error; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_disconnect(struct usb_interface *intf) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_kbd *kbd = usb_get_intfdata (intf); 38505f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, NULL); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd) { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(kbd->irq); 389c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov input_unregister_device(kbd->dev); 390a2b2c20ba2f6e22c065f401d63f7f883779cf642Willem Penninckx usb_kill_urb(kbd->led); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kbd_free_mem(interface_to_usbdev(intf), kbd); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id usb_kbd_id_table [] = { 3974ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 3984ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker USB_INTERFACE_PROTOCOL_KEYBOARD) }, 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, usb_kbd_id_table); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver usb_kbd_driver = { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "usbkbd", 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_kbd_probe, 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_kbd_disconnect, 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = usb_kbd_id_table, 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41142f06a13445bffae96c5e42fdd721ef65fed6abfGreg Kroah-Hartmanmodule_usb_driver(usb_kbd_driver); 412