16db3dfefSJiri Kosina /* 26db3dfefSJiri Kosina * Copyright (c) 1999-2001 Vojtech Pavlik 36db3dfefSJiri Kosina * 46db3dfefSJiri Kosina * USB HIDBP Keyboard support 56db3dfefSJiri Kosina */ 66db3dfefSJiri Kosina 76db3dfefSJiri Kosina /* 86db3dfefSJiri Kosina * This program is free software; you can redistribute it and/or modify 96db3dfefSJiri Kosina * it under the terms of the GNU General Public License as published by 106db3dfefSJiri Kosina * the Free Software Foundation; either version 2 of the License, or 116db3dfefSJiri Kosina * (at your option) any later version. 126db3dfefSJiri Kosina * 136db3dfefSJiri Kosina * This program is distributed in the hope that it will be useful, 146db3dfefSJiri Kosina * but WITHOUT ANY WARRANTY; without even the implied warranty of 156db3dfefSJiri Kosina * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 166db3dfefSJiri Kosina * GNU General Public License for more details. 176db3dfefSJiri Kosina * 186db3dfefSJiri Kosina * You should have received a copy of the GNU General Public License 196db3dfefSJiri Kosina * along with this program; if not, write to the Free Software 206db3dfefSJiri Kosina * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 216db3dfefSJiri Kosina * 226db3dfefSJiri Kosina * Should you need to contact me, the author, you can do so either by 236db3dfefSJiri Kosina * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 246db3dfefSJiri Kosina * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 256db3dfefSJiri Kosina */ 266db3dfefSJiri Kosina 274291ee30SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 284291ee30SJoe Perches 296db3dfefSJiri Kosina #include <linux/kernel.h> 306db3dfefSJiri Kosina #include <linux/slab.h> 316db3dfefSJiri Kosina #include <linux/module.h> 326db3dfefSJiri Kosina #include <linux/init.h> 336db3dfefSJiri Kosina #include <linux/usb/input.h> 346db3dfefSJiri Kosina #include <linux/hid.h> 356db3dfefSJiri Kosina 366db3dfefSJiri Kosina /* 376db3dfefSJiri Kosina * Version Information 386db3dfefSJiri Kosina */ 396db3dfefSJiri Kosina #define DRIVER_VERSION "" 406db3dfefSJiri Kosina #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" 416db3dfefSJiri Kosina #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" 426db3dfefSJiri Kosina #define DRIVER_LICENSE "GPL" 436db3dfefSJiri Kosina 446db3dfefSJiri Kosina MODULE_AUTHOR(DRIVER_AUTHOR); 456db3dfefSJiri Kosina MODULE_DESCRIPTION(DRIVER_DESC); 466db3dfefSJiri Kosina MODULE_LICENSE(DRIVER_LICENSE); 476db3dfefSJiri Kosina 48a44ebcceSMing Lei static const unsigned char usb_kbd_keycode[256] = { 496db3dfefSJiri Kosina 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 506db3dfefSJiri Kosina 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 516db3dfefSJiri Kosina 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 526db3dfefSJiri Kosina 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 536db3dfefSJiri Kosina 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 546db3dfefSJiri Kosina 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 556db3dfefSJiri Kosina 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 566db3dfefSJiri Kosina 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 576db3dfefSJiri Kosina 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 586db3dfefSJiri Kosina 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 596db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 606db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 626db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 636db3dfefSJiri Kosina 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 646db3dfefSJiri Kosina 150,158,159,128,136,177,178,176,142,152,173,140 656db3dfefSJiri Kosina }; 666db3dfefSJiri Kosina 676db3dfefSJiri Kosina struct usb_kbd { 686db3dfefSJiri Kosina struct input_dev *dev; 696db3dfefSJiri Kosina struct usb_device *usbdev; 706db3dfefSJiri Kosina unsigned char old[8]; 716db3dfefSJiri Kosina struct urb *irq, *led; 726db3dfefSJiri Kosina unsigned char newleds; 736db3dfefSJiri Kosina char name[128]; 746db3dfefSJiri Kosina char phys[64]; 756db3dfefSJiri Kosina 766db3dfefSJiri Kosina unsigned char *new; 776db3dfefSJiri Kosina struct usb_ctrlrequest *cr; 786db3dfefSJiri Kosina unsigned char *leds; 796db3dfefSJiri Kosina dma_addr_t new_dma; 806db3dfefSJiri Kosina dma_addr_t leds_dma; 816db3dfefSJiri Kosina }; 826db3dfefSJiri Kosina 836db3dfefSJiri Kosina static void usb_kbd_irq(struct urb *urb) 846db3dfefSJiri Kosina { 856db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context; 866db3dfefSJiri Kosina int i; 876db3dfefSJiri Kosina 886db3dfefSJiri Kosina switch (urb->status) { 896db3dfefSJiri Kosina case 0: /* success */ 906db3dfefSJiri Kosina break; 916db3dfefSJiri Kosina case -ECONNRESET: /* unlink */ 926db3dfefSJiri Kosina case -ENOENT: 936db3dfefSJiri Kosina case -ESHUTDOWN: 946db3dfefSJiri Kosina return; 956db3dfefSJiri Kosina /* -EPIPE: should clear the halt */ 966db3dfefSJiri Kosina default: /* error */ 976db3dfefSJiri Kosina goto resubmit; 986db3dfefSJiri Kosina } 996db3dfefSJiri Kosina 1006db3dfefSJiri Kosina for (i = 0; i < 8; i++) 1016db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); 1026db3dfefSJiri Kosina 1036db3dfefSJiri Kosina for (i = 2; i < 8; i++) { 1046db3dfefSJiri Kosina 1056db3dfefSJiri Kosina if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { 1066db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->old[i]]) 1076db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); 1086db3dfefSJiri Kosina else 1094291ee30SJoe Perches hid_info(urb->dev, 1104291ee30SJoe Perches "Unknown key (scancode %#x) released.\n", 1114291ee30SJoe Perches kbd->old[i]); 1126db3dfefSJiri Kosina } 1136db3dfefSJiri Kosina 1146db3dfefSJiri Kosina if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { 1156db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->new[i]]) 1166db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); 1176db3dfefSJiri Kosina else 1184291ee30SJoe Perches hid_info(urb->dev, 1194291ee30SJoe Perches "Unknown key (scancode %#x) released.\n", 1204291ee30SJoe Perches kbd->new[i]); 1216db3dfefSJiri Kosina } 1226db3dfefSJiri Kosina } 1236db3dfefSJiri Kosina 1246db3dfefSJiri Kosina input_sync(kbd->dev); 1256db3dfefSJiri Kosina 1266db3dfefSJiri Kosina memcpy(kbd->old, kbd->new, 8); 1276db3dfefSJiri Kosina 1286db3dfefSJiri Kosina resubmit: 1296db3dfefSJiri Kosina i = usb_submit_urb (urb, GFP_ATOMIC); 1306db3dfefSJiri Kosina if (i) 1314291ee30SJoe Perches hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d", 1326db3dfefSJiri Kosina kbd->usbdev->bus->bus_name, 1336db3dfefSJiri Kosina kbd->usbdev->devpath, i); 1346db3dfefSJiri Kosina } 1356db3dfefSJiri Kosina 1366db3dfefSJiri Kosina static int usb_kbd_event(struct input_dev *dev, unsigned int type, 1376db3dfefSJiri Kosina unsigned int code, int value) 1386db3dfefSJiri Kosina { 139e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 1406db3dfefSJiri Kosina 1416db3dfefSJiri Kosina if (type != EV_LED) 1426db3dfefSJiri Kosina return -1; 1436db3dfefSJiri Kosina 1446db3dfefSJiri Kosina kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | 1456db3dfefSJiri Kosina (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | 1466db3dfefSJiri Kosina (!!test_bit(LED_NUML, dev->led)); 1476db3dfefSJiri Kosina 1486db3dfefSJiri Kosina if (kbd->led->status == -EINPROGRESS) 1496db3dfefSJiri Kosina return 0; 1506db3dfefSJiri Kosina 1516db3dfefSJiri Kosina if (*(kbd->leds) == kbd->newleds) 1526db3dfefSJiri Kosina return 0; 1536db3dfefSJiri Kosina 1546db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds; 1556db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev; 1566db3dfefSJiri Kosina if (usb_submit_urb(kbd->led, GFP_ATOMIC)) 1574291ee30SJoe Perches pr_err("usb_submit_urb(leds) failed\n"); 1586db3dfefSJiri Kosina 1596db3dfefSJiri Kosina return 0; 1606db3dfefSJiri Kosina } 1616db3dfefSJiri Kosina 1626db3dfefSJiri Kosina static void usb_kbd_led(struct urb *urb) 1636db3dfefSJiri Kosina { 1646db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context; 1656db3dfefSJiri Kosina 1666db3dfefSJiri Kosina if (urb->status) 1674291ee30SJoe Perches hid_warn(urb->dev, "led urb status %d received\n", 1687d89fe12SFrom: Greg Kroah-Hartman urb->status); 1696db3dfefSJiri Kosina 1706db3dfefSJiri Kosina if (*(kbd->leds) == kbd->newleds) 1716db3dfefSJiri Kosina return; 1726db3dfefSJiri Kosina 1736db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds; 1746db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev; 1756db3dfefSJiri Kosina if (usb_submit_urb(kbd->led, GFP_ATOMIC)) 1764291ee30SJoe Perches hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); 1776db3dfefSJiri Kosina } 1786db3dfefSJiri Kosina 1796db3dfefSJiri Kosina static int usb_kbd_open(struct input_dev *dev) 1806db3dfefSJiri Kosina { 181e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 1826db3dfefSJiri Kosina 1836db3dfefSJiri Kosina kbd->irq->dev = kbd->usbdev; 1846db3dfefSJiri Kosina if (usb_submit_urb(kbd->irq, GFP_KERNEL)) 1856db3dfefSJiri Kosina return -EIO; 1866db3dfefSJiri Kosina 1876db3dfefSJiri Kosina return 0; 1886db3dfefSJiri Kosina } 1896db3dfefSJiri Kosina 1906db3dfefSJiri Kosina static void usb_kbd_close(struct input_dev *dev) 1916db3dfefSJiri Kosina { 192e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 1936db3dfefSJiri Kosina 1946db3dfefSJiri Kosina usb_kill_urb(kbd->irq); 1956db3dfefSJiri Kosina } 1966db3dfefSJiri Kosina 1976db3dfefSJiri Kosina static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) 1986db3dfefSJiri Kosina { 1996db3dfefSJiri Kosina if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) 2006db3dfefSJiri Kosina return -1; 2016db3dfefSJiri Kosina if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) 2026db3dfefSJiri Kosina return -1; 203997ea58eSDaniel Mack if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma))) 2046db3dfefSJiri Kosina return -1; 2050ede76fcSAlan Stern if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) 2066db3dfefSJiri Kosina return -1; 207997ea58eSDaniel Mack if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) 2086db3dfefSJiri Kosina return -1; 2096db3dfefSJiri Kosina 2106db3dfefSJiri Kosina return 0; 2116db3dfefSJiri Kosina } 2126db3dfefSJiri Kosina 2136db3dfefSJiri Kosina static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) 2146db3dfefSJiri Kosina { 2156db3dfefSJiri Kosina usb_free_urb(kbd->irq); 2166db3dfefSJiri Kosina usb_free_urb(kbd->led); 217997ea58eSDaniel Mack usb_free_coherent(dev, 8, kbd->new, kbd->new_dma); 2180ede76fcSAlan Stern kfree(kbd->cr); 219997ea58eSDaniel Mack usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma); 2206db3dfefSJiri Kosina } 2216db3dfefSJiri Kosina 2226db3dfefSJiri Kosina static int usb_kbd_probe(struct usb_interface *iface, 2236db3dfefSJiri Kosina const struct usb_device_id *id) 2246db3dfefSJiri Kosina { 2256db3dfefSJiri Kosina struct usb_device *dev = interface_to_usbdev(iface); 2266db3dfefSJiri Kosina struct usb_host_interface *interface; 2276db3dfefSJiri Kosina struct usb_endpoint_descriptor *endpoint; 2286db3dfefSJiri Kosina struct usb_kbd *kbd; 2296db3dfefSJiri Kosina struct input_dev *input_dev; 2306db3dfefSJiri Kosina int i, pipe, maxp; 2315d6341c6SDmitry Torokhov int error = -ENOMEM; 2326db3dfefSJiri Kosina 2336db3dfefSJiri Kosina interface = iface->cur_altsetting; 2346db3dfefSJiri Kosina 2356db3dfefSJiri Kosina if (interface->desc.bNumEndpoints != 1) 2366db3dfefSJiri Kosina return -ENODEV; 2376db3dfefSJiri Kosina 2386db3dfefSJiri Kosina endpoint = &interface->endpoint[0].desc; 2396db3dfefSJiri Kosina if (!usb_endpoint_is_int_in(endpoint)) 2406db3dfefSJiri Kosina return -ENODEV; 2416db3dfefSJiri Kosina 2426db3dfefSJiri Kosina pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 2436db3dfefSJiri Kosina maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 2446db3dfefSJiri Kosina 2456db3dfefSJiri Kosina kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); 2466db3dfefSJiri Kosina input_dev = input_allocate_device(); 2476db3dfefSJiri Kosina if (!kbd || !input_dev) 2486db3dfefSJiri Kosina goto fail1; 2496db3dfefSJiri Kosina 2506db3dfefSJiri Kosina if (usb_kbd_alloc_mem(dev, kbd)) 2516db3dfefSJiri Kosina goto fail2; 2526db3dfefSJiri Kosina 2536db3dfefSJiri Kosina kbd->usbdev = dev; 2546db3dfefSJiri Kosina kbd->dev = input_dev; 2556db3dfefSJiri Kosina 2566db3dfefSJiri Kosina if (dev->manufacturer) 2576db3dfefSJiri Kosina strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); 2586db3dfefSJiri Kosina 2596db3dfefSJiri Kosina if (dev->product) { 2606db3dfefSJiri Kosina if (dev->manufacturer) 2616db3dfefSJiri Kosina strlcat(kbd->name, " ", sizeof(kbd->name)); 2626db3dfefSJiri Kosina strlcat(kbd->name, dev->product, sizeof(kbd->name)); 2636db3dfefSJiri Kosina } 2646db3dfefSJiri Kosina 2656db3dfefSJiri Kosina if (!strlen(kbd->name)) 2666db3dfefSJiri Kosina snprintf(kbd->name, sizeof(kbd->name), 2676db3dfefSJiri Kosina "USB HIDBP Keyboard %04x:%04x", 2686db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idVendor), 2696db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idProduct)); 2706db3dfefSJiri Kosina 2716db3dfefSJiri Kosina usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); 2726236dfaaSMárton Németh strlcat(kbd->phys, "/input0", sizeof(kbd->phys)); 2736db3dfefSJiri Kosina 2746db3dfefSJiri Kosina input_dev->name = kbd->name; 2756db3dfefSJiri Kosina input_dev->phys = kbd->phys; 2766db3dfefSJiri Kosina usb_to_input_id(dev, &input_dev->id); 277e0712985SDmitry Torokhov input_dev->dev.parent = &iface->dev; 278e0712985SDmitry Torokhov 279e0712985SDmitry Torokhov input_set_drvdata(input_dev, kbd); 2806db3dfefSJiri Kosina 2817b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | 2827b19ada2SJiri Slaby BIT_MASK(EV_REP); 2837b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | 2847b19ada2SJiri Slaby BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) | 2857b19ada2SJiri Slaby BIT_MASK(LED_KANA); 2866db3dfefSJiri Kosina 2876db3dfefSJiri Kosina for (i = 0; i < 255; i++) 2886db3dfefSJiri Kosina set_bit(usb_kbd_keycode[i], input_dev->keybit); 2896db3dfefSJiri Kosina clear_bit(0, input_dev->keybit); 2906db3dfefSJiri Kosina 2916db3dfefSJiri Kosina input_dev->event = usb_kbd_event; 2926db3dfefSJiri Kosina input_dev->open = usb_kbd_open; 2936db3dfefSJiri Kosina input_dev->close = usb_kbd_close; 2946db3dfefSJiri Kosina 2956db3dfefSJiri Kosina usb_fill_int_urb(kbd->irq, dev, pipe, 2966db3dfefSJiri Kosina kbd->new, (maxp > 8 ? 8 : maxp), 2976db3dfefSJiri Kosina usb_kbd_irq, kbd, endpoint->bInterval); 2986db3dfefSJiri Kosina kbd->irq->transfer_dma = kbd->new_dma; 2996db3dfefSJiri Kosina kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3006db3dfefSJiri Kosina 3016db3dfefSJiri Kosina kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 3026db3dfefSJiri Kosina kbd->cr->bRequest = 0x09; 3036db3dfefSJiri Kosina kbd->cr->wValue = cpu_to_le16(0x200); 3046db3dfefSJiri Kosina kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); 3056db3dfefSJiri Kosina kbd->cr->wLength = cpu_to_le16(1); 3066db3dfefSJiri Kosina 3076db3dfefSJiri Kosina usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), 3086db3dfefSJiri Kosina (void *) kbd->cr, kbd->leds, 1, 3096db3dfefSJiri Kosina usb_kbd_led, kbd); 3106db3dfefSJiri Kosina kbd->led->transfer_dma = kbd->leds_dma; 3110ede76fcSAlan Stern kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3126db3dfefSJiri Kosina 3135d6341c6SDmitry Torokhov error = input_register_device(kbd->dev); 3145d6341c6SDmitry Torokhov if (error) 3155d6341c6SDmitry Torokhov goto fail2; 3166db3dfefSJiri Kosina 3176db3dfefSJiri Kosina usb_set_intfdata(iface, kbd); 3183d61510fSAlan Stern device_set_wakeup_enable(&dev->dev, 1); 3196db3dfefSJiri Kosina return 0; 3206db3dfefSJiri Kosina 3215d6341c6SDmitry Torokhov fail2: 3225d6341c6SDmitry Torokhov usb_kbd_free_mem(dev, kbd); 3235d6341c6SDmitry Torokhov fail1: 3245d6341c6SDmitry Torokhov input_free_device(input_dev); 3256db3dfefSJiri Kosina kfree(kbd); 3265d6341c6SDmitry Torokhov return error; 3276db3dfefSJiri Kosina } 3286db3dfefSJiri Kosina 3296db3dfefSJiri Kosina static void usb_kbd_disconnect(struct usb_interface *intf) 3306db3dfefSJiri Kosina { 3316db3dfefSJiri Kosina struct usb_kbd *kbd = usb_get_intfdata (intf); 3326db3dfefSJiri Kosina 3336db3dfefSJiri Kosina usb_set_intfdata(intf, NULL); 3346db3dfefSJiri Kosina if (kbd) { 3356db3dfefSJiri Kosina usb_kill_urb(kbd->irq); 3366db3dfefSJiri Kosina input_unregister_device(kbd->dev); 3376db3dfefSJiri Kosina usb_kbd_free_mem(interface_to_usbdev(intf), kbd); 3386db3dfefSJiri Kosina kfree(kbd); 3396db3dfefSJiri Kosina } 3406db3dfefSJiri Kosina } 3416db3dfefSJiri Kosina 3426db3dfefSJiri Kosina static struct usb_device_id usb_kbd_id_table [] = { 3436db3dfefSJiri Kosina { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 3446db3dfefSJiri Kosina USB_INTERFACE_PROTOCOL_KEYBOARD) }, 3456db3dfefSJiri Kosina { } /* Terminating entry */ 3466db3dfefSJiri Kosina }; 3476db3dfefSJiri Kosina 3486db3dfefSJiri Kosina MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); 3496db3dfefSJiri Kosina 3506db3dfefSJiri Kosina static struct usb_driver usb_kbd_driver = { 3516db3dfefSJiri Kosina .name = "usbkbd", 3526db3dfefSJiri Kosina .probe = usb_kbd_probe, 3536db3dfefSJiri Kosina .disconnect = usb_kbd_disconnect, 3546db3dfefSJiri Kosina .id_table = usb_kbd_id_table, 3556db3dfefSJiri Kosina }; 3566db3dfefSJiri Kosina 357*42f06a13SGreg Kroah-Hartman module_usb_driver(usb_kbd_driver); 358