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 436db3dfefSJiri Kosina MODULE_AUTHOR(DRIVER_AUTHOR); 446db3dfefSJiri Kosina MODULE_DESCRIPTION(DRIVER_DESC); 457021b600SGrant Grundler MODULE_LICENSE("GPL"); 466db3dfefSJiri Kosina 47a44ebcceSMing Lei static const unsigned char usb_kbd_keycode[256] = { 486db3dfefSJiri Kosina 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 496db3dfefSJiri Kosina 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 506db3dfefSJiri Kosina 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 516db3dfefSJiri Kosina 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 526db3dfefSJiri Kosina 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 536db3dfefSJiri Kosina 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 546db3dfefSJiri Kosina 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 556db3dfefSJiri Kosina 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 566db3dfefSJiri Kosina 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, 576db3dfefSJiri Kosina 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 586db3dfefSJiri Kosina 0, 0, 0, 0, 0, 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 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 636db3dfefSJiri Kosina 150,158,159,128,136,177,178,176,142,152,173,140 646db3dfefSJiri Kosina }; 656db3dfefSJiri Kosina 66c196adf8SWillem Penninckx 67c196adf8SWillem Penninckx /** 68c196adf8SWillem Penninckx * struct usb_kbd - state of each attached keyboard 69c196adf8SWillem Penninckx * @dev: input device associated with this keyboard 70c196adf8SWillem Penninckx * @usbdev: usb device associated with this keyboard 71c196adf8SWillem Penninckx * @old: data received in the past from the @irq URB representing which 72c196adf8SWillem Penninckx * keys were pressed. By comparing with the current list of keys 73c196adf8SWillem Penninckx * that are pressed, we are able to see key releases. 74c196adf8SWillem Penninckx * @irq: URB for receiving a list of keys that are pressed when a 75c196adf8SWillem Penninckx * new key is pressed or a key that was pressed is released. 76c196adf8SWillem Penninckx * @led: URB for sending LEDs (e.g. numlock, ...) 77c196adf8SWillem Penninckx * @newleds: data that will be sent with the @led URB representing which LEDs 78c196adf8SWillem Penninckx should be on 79c196adf8SWillem Penninckx * @name: Name of the keyboard. @dev's name field points to this buffer 80c196adf8SWillem Penninckx * @phys: Physical path of the keyboard. @dev's phys field points to this 81c196adf8SWillem Penninckx * buffer 82c196adf8SWillem Penninckx * @new: Buffer for the @irq URB 83c196adf8SWillem Penninckx * @cr: Control request for @led URB 84c196adf8SWillem Penninckx * @leds: Buffer for the @led URB 85c196adf8SWillem Penninckx * @new_dma: DMA address for @irq URB 86c196adf8SWillem Penninckx * @leds_dma: DMA address for @led URB 87c196adf8SWillem Penninckx * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted 88c196adf8SWillem Penninckx * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been 89c196adf8SWillem Penninckx * submitted and its completion handler has not returned yet 90c196adf8SWillem Penninckx * without resubmitting @led 91c196adf8SWillem Penninckx */ 926db3dfefSJiri Kosina struct usb_kbd { 936db3dfefSJiri Kosina struct input_dev *dev; 946db3dfefSJiri Kosina struct usb_device *usbdev; 956db3dfefSJiri Kosina unsigned char old[8]; 966db3dfefSJiri Kosina struct urb *irq, *led; 976db3dfefSJiri Kosina unsigned char newleds; 986db3dfefSJiri Kosina char name[128]; 996db3dfefSJiri Kosina char phys[64]; 1006db3dfefSJiri Kosina 1016db3dfefSJiri Kosina unsigned char *new; 1026db3dfefSJiri Kosina struct usb_ctrlrequest *cr; 1036db3dfefSJiri Kosina unsigned char *leds; 1046db3dfefSJiri Kosina dma_addr_t new_dma; 1056db3dfefSJiri Kosina dma_addr_t leds_dma; 106c196adf8SWillem Penninckx 107c196adf8SWillem Penninckx spinlock_t leds_lock; 108c196adf8SWillem Penninckx bool led_urb_submitted; 109c196adf8SWillem Penninckx 1106db3dfefSJiri Kosina }; 1116db3dfefSJiri Kosina 1126db3dfefSJiri Kosina static void usb_kbd_irq(struct urb *urb) 1136db3dfefSJiri Kosina { 1146db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context; 1156db3dfefSJiri Kosina int i; 1166db3dfefSJiri Kosina 1176db3dfefSJiri Kosina switch (urb->status) { 1186db3dfefSJiri Kosina case 0: /* success */ 1196db3dfefSJiri Kosina break; 1206db3dfefSJiri Kosina case -ECONNRESET: /* unlink */ 1216db3dfefSJiri Kosina case -ENOENT: 1226db3dfefSJiri Kosina case -ESHUTDOWN: 1236db3dfefSJiri Kosina return; 1246db3dfefSJiri Kosina /* -EPIPE: should clear the halt */ 1256db3dfefSJiri Kosina default: /* error */ 1266db3dfefSJiri Kosina goto resubmit; 1276db3dfefSJiri Kosina } 1286db3dfefSJiri Kosina 1296db3dfefSJiri Kosina for (i = 0; i < 8; i++) 1306db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); 1316db3dfefSJiri Kosina 1326db3dfefSJiri Kosina for (i = 2; i < 8; i++) { 1336db3dfefSJiri Kosina 1346db3dfefSJiri Kosina if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { 1356db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->old[i]]) 1366db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); 1376db3dfefSJiri Kosina else 1384291ee30SJoe Perches hid_info(urb->dev, 1394291ee30SJoe Perches "Unknown key (scancode %#x) released.\n", 1404291ee30SJoe Perches kbd->old[i]); 1416db3dfefSJiri Kosina } 1426db3dfefSJiri Kosina 1436db3dfefSJiri Kosina if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { 1446db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->new[i]]) 1456db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); 1466db3dfefSJiri Kosina else 1474291ee30SJoe Perches hid_info(urb->dev, 1489fee8240SAdam Cozzette "Unknown key (scancode %#x) pressed.\n", 1494291ee30SJoe Perches kbd->new[i]); 1506db3dfefSJiri Kosina } 1516db3dfefSJiri Kosina } 1526db3dfefSJiri Kosina 1536db3dfefSJiri Kosina input_sync(kbd->dev); 1546db3dfefSJiri Kosina 1556db3dfefSJiri Kosina memcpy(kbd->old, kbd->new, 8); 1566db3dfefSJiri Kosina 1576db3dfefSJiri Kosina resubmit: 1586db3dfefSJiri Kosina i = usb_submit_urb (urb, GFP_ATOMIC); 1596db3dfefSJiri Kosina if (i) 1604291ee30SJoe Perches hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d", 1616db3dfefSJiri Kosina kbd->usbdev->bus->bus_name, 1626db3dfefSJiri Kosina kbd->usbdev->devpath, i); 1636db3dfefSJiri Kosina } 1646db3dfefSJiri Kosina 1656db3dfefSJiri Kosina static int usb_kbd_event(struct input_dev *dev, unsigned int type, 1666db3dfefSJiri Kosina unsigned int code, int value) 1676db3dfefSJiri Kosina { 168c196adf8SWillem Penninckx unsigned long flags; 169e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 1706db3dfefSJiri Kosina 1716db3dfefSJiri Kosina if (type != EV_LED) 1726db3dfefSJiri Kosina return -1; 1736db3dfefSJiri Kosina 174c196adf8SWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags); 1756db3dfefSJiri Kosina kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | 1766db3dfefSJiri Kosina (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | 1776db3dfefSJiri Kosina (!!test_bit(LED_NUML, dev->led)); 1786db3dfefSJiri Kosina 179c196adf8SWillem Penninckx if (kbd->led_urb_submitted){ 180c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 1816db3dfefSJiri Kosina return 0; 182c196adf8SWillem Penninckx } 1836db3dfefSJiri Kosina 184c196adf8SWillem Penninckx if (*(kbd->leds) == kbd->newleds){ 185c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 1866db3dfefSJiri Kosina return 0; 187c196adf8SWillem Penninckx } 1886db3dfefSJiri Kosina 1896db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds; 190c196adf8SWillem Penninckx 1916db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev; 1926db3dfefSJiri Kosina if (usb_submit_urb(kbd->led, GFP_ATOMIC)) 1934291ee30SJoe Perches pr_err("usb_submit_urb(leds) failed\n"); 194c196adf8SWillem Penninckx else 195c196adf8SWillem Penninckx kbd->led_urb_submitted = true; 196c196adf8SWillem Penninckx 197c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 1986db3dfefSJiri Kosina 1996db3dfefSJiri Kosina return 0; 2006db3dfefSJiri Kosina } 2016db3dfefSJiri Kosina 2026db3dfefSJiri Kosina static void usb_kbd_led(struct urb *urb) 2036db3dfefSJiri Kosina { 204c196adf8SWillem Penninckx unsigned long flags; 2056db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context; 2066db3dfefSJiri Kosina 2076db3dfefSJiri Kosina if (urb->status) 2084291ee30SJoe Perches hid_warn(urb->dev, "led urb status %d received\n", 2097d89fe12SFrom: Greg Kroah-Hartman urb->status); 2106db3dfefSJiri Kosina 211c196adf8SWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags); 212c196adf8SWillem Penninckx 213c196adf8SWillem Penninckx if (*(kbd->leds) == kbd->newleds){ 214c196adf8SWillem Penninckx kbd->led_urb_submitted = false; 215c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 2166db3dfefSJiri Kosina return; 217c196adf8SWillem Penninckx } 2186db3dfefSJiri Kosina 2196db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds; 220c196adf8SWillem Penninckx 2216db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev; 222c196adf8SWillem Penninckx if (usb_submit_urb(kbd->led, GFP_ATOMIC)){ 2234291ee30SJoe Perches hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); 224c196adf8SWillem Penninckx kbd->led_urb_submitted = false; 225c196adf8SWillem Penninckx } 226c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags); 227c196adf8SWillem Penninckx 2286db3dfefSJiri Kosina } 2296db3dfefSJiri Kosina 2306db3dfefSJiri Kosina static int usb_kbd_open(struct input_dev *dev) 2316db3dfefSJiri Kosina { 232e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 2336db3dfefSJiri Kosina 2346db3dfefSJiri Kosina kbd->irq->dev = kbd->usbdev; 2356db3dfefSJiri Kosina if (usb_submit_urb(kbd->irq, GFP_KERNEL)) 2366db3dfefSJiri Kosina return -EIO; 2376db3dfefSJiri Kosina 2386db3dfefSJiri Kosina return 0; 2396db3dfefSJiri Kosina } 2406db3dfefSJiri Kosina 2416db3dfefSJiri Kosina static void usb_kbd_close(struct input_dev *dev) 2426db3dfefSJiri Kosina { 243e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev); 2446db3dfefSJiri Kosina 2456db3dfefSJiri Kosina usb_kill_urb(kbd->irq); 2466db3dfefSJiri Kosina } 2476db3dfefSJiri Kosina 2486db3dfefSJiri Kosina static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) 2496db3dfefSJiri Kosina { 2506db3dfefSJiri Kosina if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) 2516db3dfefSJiri Kosina return -1; 2526db3dfefSJiri Kosina if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) 2536db3dfefSJiri Kosina return -1; 254997ea58eSDaniel Mack if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma))) 2556db3dfefSJiri Kosina return -1; 2560ede76fcSAlan Stern if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) 2576db3dfefSJiri Kosina return -1; 258997ea58eSDaniel Mack if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) 2596db3dfefSJiri Kosina return -1; 2606db3dfefSJiri Kosina 2616db3dfefSJiri Kosina return 0; 2626db3dfefSJiri Kosina } 2636db3dfefSJiri Kosina 2646db3dfefSJiri Kosina static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) 2656db3dfefSJiri Kosina { 2666db3dfefSJiri Kosina usb_free_urb(kbd->irq); 2676db3dfefSJiri Kosina usb_free_urb(kbd->led); 268997ea58eSDaniel Mack usb_free_coherent(dev, 8, kbd->new, kbd->new_dma); 2690ede76fcSAlan Stern kfree(kbd->cr); 270997ea58eSDaniel Mack usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma); 2716db3dfefSJiri Kosina } 2726db3dfefSJiri Kosina 2736db3dfefSJiri Kosina static int usb_kbd_probe(struct usb_interface *iface, 2746db3dfefSJiri Kosina const struct usb_device_id *id) 2756db3dfefSJiri Kosina { 2766db3dfefSJiri Kosina struct usb_device *dev = interface_to_usbdev(iface); 2776db3dfefSJiri Kosina struct usb_host_interface *interface; 2786db3dfefSJiri Kosina struct usb_endpoint_descriptor *endpoint; 2796db3dfefSJiri Kosina struct usb_kbd *kbd; 2806db3dfefSJiri Kosina struct input_dev *input_dev; 2816db3dfefSJiri Kosina int i, pipe, maxp; 2825d6341c6SDmitry Torokhov int error = -ENOMEM; 2836db3dfefSJiri Kosina 2846db3dfefSJiri Kosina interface = iface->cur_altsetting; 2856db3dfefSJiri Kosina 2866db3dfefSJiri Kosina if (interface->desc.bNumEndpoints != 1) 2876db3dfefSJiri Kosina return -ENODEV; 2886db3dfefSJiri Kosina 2896db3dfefSJiri Kosina endpoint = &interface->endpoint[0].desc; 2906db3dfefSJiri Kosina if (!usb_endpoint_is_int_in(endpoint)) 2916db3dfefSJiri Kosina return -ENODEV; 2926db3dfefSJiri Kosina 2936db3dfefSJiri Kosina pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 2946db3dfefSJiri Kosina maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); 2956db3dfefSJiri Kosina 2966db3dfefSJiri Kosina kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); 2976db3dfefSJiri Kosina input_dev = input_allocate_device(); 2986db3dfefSJiri Kosina if (!kbd || !input_dev) 2996db3dfefSJiri Kosina goto fail1; 3006db3dfefSJiri Kosina 3016db3dfefSJiri Kosina if (usb_kbd_alloc_mem(dev, kbd)) 3026db3dfefSJiri Kosina goto fail2; 3036db3dfefSJiri Kosina 3046db3dfefSJiri Kosina kbd->usbdev = dev; 3056db3dfefSJiri Kosina kbd->dev = input_dev; 306c196adf8SWillem Penninckx spin_lock_init(&kbd->leds_lock); 3076db3dfefSJiri Kosina 3086db3dfefSJiri Kosina if (dev->manufacturer) 3096db3dfefSJiri Kosina strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); 3106db3dfefSJiri Kosina 3116db3dfefSJiri Kosina if (dev->product) { 3126db3dfefSJiri Kosina if (dev->manufacturer) 3136db3dfefSJiri Kosina strlcat(kbd->name, " ", sizeof(kbd->name)); 3146db3dfefSJiri Kosina strlcat(kbd->name, dev->product, sizeof(kbd->name)); 3156db3dfefSJiri Kosina } 3166db3dfefSJiri Kosina 3176db3dfefSJiri Kosina if (!strlen(kbd->name)) 3186db3dfefSJiri Kosina snprintf(kbd->name, sizeof(kbd->name), 3196db3dfefSJiri Kosina "USB HIDBP Keyboard %04x:%04x", 3206db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idVendor), 3216db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idProduct)); 3226db3dfefSJiri Kosina 3236db3dfefSJiri Kosina usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); 3246236dfaaSMárton Németh strlcat(kbd->phys, "/input0", sizeof(kbd->phys)); 3256db3dfefSJiri Kosina 3266db3dfefSJiri Kosina input_dev->name = kbd->name; 3276db3dfefSJiri Kosina input_dev->phys = kbd->phys; 3286db3dfefSJiri Kosina usb_to_input_id(dev, &input_dev->id); 329e0712985SDmitry Torokhov input_dev->dev.parent = &iface->dev; 330e0712985SDmitry Torokhov 331e0712985SDmitry Torokhov input_set_drvdata(input_dev, kbd); 3326db3dfefSJiri Kosina 3337b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | 3347b19ada2SJiri Slaby BIT_MASK(EV_REP); 3357b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | 3367b19ada2SJiri Slaby BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) | 3377b19ada2SJiri Slaby BIT_MASK(LED_KANA); 3386db3dfefSJiri Kosina 3396db3dfefSJiri Kosina for (i = 0; i < 255; i++) 3406db3dfefSJiri Kosina set_bit(usb_kbd_keycode[i], input_dev->keybit); 3416db3dfefSJiri Kosina clear_bit(0, input_dev->keybit); 3426db3dfefSJiri Kosina 3436db3dfefSJiri Kosina input_dev->event = usb_kbd_event; 3446db3dfefSJiri Kosina input_dev->open = usb_kbd_open; 3456db3dfefSJiri Kosina input_dev->close = usb_kbd_close; 3466db3dfefSJiri Kosina 3476db3dfefSJiri Kosina usb_fill_int_urb(kbd->irq, dev, pipe, 3486db3dfefSJiri Kosina kbd->new, (maxp > 8 ? 8 : maxp), 3496db3dfefSJiri Kosina usb_kbd_irq, kbd, endpoint->bInterval); 3506db3dfefSJiri Kosina kbd->irq->transfer_dma = kbd->new_dma; 3516db3dfefSJiri Kosina kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3526db3dfefSJiri Kosina 3536db3dfefSJiri Kosina kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; 3546db3dfefSJiri Kosina kbd->cr->bRequest = 0x09; 3556db3dfefSJiri Kosina kbd->cr->wValue = cpu_to_le16(0x200); 3566db3dfefSJiri Kosina kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); 3576db3dfefSJiri Kosina kbd->cr->wLength = cpu_to_le16(1); 3586db3dfefSJiri Kosina 3596db3dfefSJiri Kosina usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), 3606db3dfefSJiri Kosina (void *) kbd->cr, kbd->leds, 1, 3616db3dfefSJiri Kosina usb_kbd_led, kbd); 3626db3dfefSJiri Kosina kbd->led->transfer_dma = kbd->leds_dma; 3630ede76fcSAlan Stern kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 3646db3dfefSJiri Kosina 3655d6341c6SDmitry Torokhov error = input_register_device(kbd->dev); 3665d6341c6SDmitry Torokhov if (error) 3675d6341c6SDmitry Torokhov goto fail2; 3686db3dfefSJiri Kosina 3696db3dfefSJiri Kosina usb_set_intfdata(iface, kbd); 3703d61510fSAlan Stern device_set_wakeup_enable(&dev->dev, 1); 3716db3dfefSJiri Kosina return 0; 3726db3dfefSJiri Kosina 3735d6341c6SDmitry Torokhov fail2: 3745d6341c6SDmitry Torokhov usb_kbd_free_mem(dev, kbd); 3755d6341c6SDmitry Torokhov fail1: 3765d6341c6SDmitry Torokhov input_free_device(input_dev); 3776db3dfefSJiri Kosina kfree(kbd); 3785d6341c6SDmitry Torokhov return error; 3796db3dfefSJiri Kosina } 3806db3dfefSJiri Kosina 3816db3dfefSJiri Kosina static void usb_kbd_disconnect(struct usb_interface *intf) 3826db3dfefSJiri Kosina { 3836db3dfefSJiri Kosina struct usb_kbd *kbd = usb_get_intfdata (intf); 3846db3dfefSJiri Kosina 3856db3dfefSJiri Kosina usb_set_intfdata(intf, NULL); 3866db3dfefSJiri Kosina if (kbd) { 3876db3dfefSJiri Kosina usb_kill_urb(kbd->irq); 3886db3dfefSJiri Kosina input_unregister_device(kbd->dev); 389a2b2c20bSWillem Penninckx usb_kill_urb(kbd->led); 3906db3dfefSJiri Kosina usb_kbd_free_mem(interface_to_usbdev(intf), kbd); 3916db3dfefSJiri Kosina kfree(kbd); 3926db3dfefSJiri Kosina } 3936db3dfefSJiri Kosina } 3946db3dfefSJiri Kosina 395*46cb3cf8SArvind Yadav static const struct usb_device_id usb_kbd_id_table[] = { 3966db3dfefSJiri Kosina { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 3976db3dfefSJiri Kosina USB_INTERFACE_PROTOCOL_KEYBOARD) }, 3986db3dfefSJiri Kosina { } /* Terminating entry */ 3996db3dfefSJiri Kosina }; 4006db3dfefSJiri Kosina 4016db3dfefSJiri Kosina MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); 4026db3dfefSJiri Kosina 4036db3dfefSJiri Kosina static struct usb_driver usb_kbd_driver = { 4046db3dfefSJiri Kosina .name = "usbkbd", 4056db3dfefSJiri Kosina .probe = usb_kbd_probe, 4066db3dfefSJiri Kosina .disconnect = usb_kbd_disconnect, 4076db3dfefSJiri Kosina .id_table = usb_kbd_id_table, 4086db3dfefSJiri Kosina }; 4096db3dfefSJiri Kosina 41042f06a13SGreg Kroah-Hartman module_usb_driver(usb_kbd_driver); 411