11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26db3dfefSJiri Kosina /*
36db3dfefSJiri Kosina * Copyright (c) 1999-2001 Vojtech Pavlik
46db3dfefSJiri Kosina *
56db3dfefSJiri Kosina * USB HIDBP Keyboard support
66db3dfefSJiri Kosina */
76db3dfefSJiri Kosina
86db3dfefSJiri Kosina /*
96db3dfefSJiri Kosina *
106db3dfefSJiri Kosina * Should you need to contact me, the author, you can do so either by
116db3dfefSJiri Kosina * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
126db3dfefSJiri Kosina * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
136db3dfefSJiri Kosina */
146db3dfefSJiri Kosina
154291ee30SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
164291ee30SJoe Perches
176db3dfefSJiri Kosina #include <linux/kernel.h>
186db3dfefSJiri Kosina #include <linux/slab.h>
196db3dfefSJiri Kosina #include <linux/module.h>
206db3dfefSJiri Kosina #include <linux/init.h>
216db3dfefSJiri Kosina #include <linux/usb/input.h>
226db3dfefSJiri Kosina #include <linux/hid.h>
236db3dfefSJiri Kosina
246db3dfefSJiri Kosina /*
256db3dfefSJiri Kosina * Version Information
266db3dfefSJiri Kosina */
276db3dfefSJiri Kosina #define DRIVER_VERSION ""
286db3dfefSJiri Kosina #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
296db3dfefSJiri Kosina #define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
306db3dfefSJiri Kosina
316db3dfefSJiri Kosina MODULE_AUTHOR(DRIVER_AUTHOR);
326db3dfefSJiri Kosina MODULE_DESCRIPTION(DRIVER_DESC);
337021b600SGrant Grundler MODULE_LICENSE("GPL");
346db3dfefSJiri Kosina
35a44ebcceSMing Lei static const unsigned char usb_kbd_keycode[256] = {
366db3dfefSJiri Kosina 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
376db3dfefSJiri Kosina 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
386db3dfefSJiri Kosina 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
396db3dfefSJiri Kosina 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
406db3dfefSJiri Kosina 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
416db3dfefSJiri Kosina 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
426db3dfefSJiri Kosina 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
436db3dfefSJiri Kosina 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
446db3dfefSJiri Kosina 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
456db3dfefSJiri Kosina 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
466db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
476db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
486db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
496db3dfefSJiri Kosina 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
506db3dfefSJiri Kosina 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
516db3dfefSJiri Kosina 150,158,159,128,136,177,178,176,142,152,173,140
526db3dfefSJiri Kosina };
536db3dfefSJiri Kosina
54c196adf8SWillem Penninckx
55c196adf8SWillem Penninckx /**
56c196adf8SWillem Penninckx * struct usb_kbd - state of each attached keyboard
57c196adf8SWillem Penninckx * @dev: input device associated with this keyboard
58c196adf8SWillem Penninckx * @usbdev: usb device associated with this keyboard
59c196adf8SWillem Penninckx * @old: data received in the past from the @irq URB representing which
60c196adf8SWillem Penninckx * keys were pressed. By comparing with the current list of keys
61c196adf8SWillem Penninckx * that are pressed, we are able to see key releases.
62c196adf8SWillem Penninckx * @irq: URB for receiving a list of keys that are pressed when a
63c196adf8SWillem Penninckx * new key is pressed or a key that was pressed is released.
64c196adf8SWillem Penninckx * @led: URB for sending LEDs (e.g. numlock, ...)
65c196adf8SWillem Penninckx * @newleds: data that will be sent with the @led URB representing which LEDs
664cbf8aa7SLee Jones * should be on
67c196adf8SWillem Penninckx * @name: Name of the keyboard. @dev's name field points to this buffer
68c196adf8SWillem Penninckx * @phys: Physical path of the keyboard. @dev's phys field points to this
69c196adf8SWillem Penninckx * buffer
70c196adf8SWillem Penninckx * @new: Buffer for the @irq URB
71c196adf8SWillem Penninckx * @cr: Control request for @led URB
72c196adf8SWillem Penninckx * @leds: Buffer for the @led URB
73c196adf8SWillem Penninckx * @new_dma: DMA address for @irq URB
74c196adf8SWillem Penninckx * @leds_dma: DMA address for @led URB
75c196adf8SWillem Penninckx * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted
76c196adf8SWillem Penninckx * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
77c196adf8SWillem Penninckx * submitted and its completion handler has not returned yet
78c196adf8SWillem Penninckx * without resubmitting @led
79c196adf8SWillem Penninckx */
806db3dfefSJiri Kosina struct usb_kbd {
816db3dfefSJiri Kosina struct input_dev *dev;
826db3dfefSJiri Kosina struct usb_device *usbdev;
836db3dfefSJiri Kosina unsigned char old[8];
846db3dfefSJiri Kosina struct urb *irq, *led;
856db3dfefSJiri Kosina unsigned char newleds;
866db3dfefSJiri Kosina char name[128];
876db3dfefSJiri Kosina char phys[64];
886db3dfefSJiri Kosina
896db3dfefSJiri Kosina unsigned char *new;
906db3dfefSJiri Kosina struct usb_ctrlrequest *cr;
916db3dfefSJiri Kosina unsigned char *leds;
926db3dfefSJiri Kosina dma_addr_t new_dma;
936db3dfefSJiri Kosina dma_addr_t leds_dma;
94c196adf8SWillem Penninckx
95c196adf8SWillem Penninckx spinlock_t leds_lock;
96c196adf8SWillem Penninckx bool led_urb_submitted;
97c196adf8SWillem Penninckx
986db3dfefSJiri Kosina };
996db3dfefSJiri Kosina
usb_kbd_irq(struct urb * urb)1006db3dfefSJiri Kosina static void usb_kbd_irq(struct urb *urb)
1016db3dfefSJiri Kosina {
1026db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context;
1036db3dfefSJiri Kosina int i;
1046db3dfefSJiri Kosina
1056db3dfefSJiri Kosina switch (urb->status) {
1066db3dfefSJiri Kosina case 0: /* success */
1076db3dfefSJiri Kosina break;
1086db3dfefSJiri Kosina case -ECONNRESET: /* unlink */
1096db3dfefSJiri Kosina case -ENOENT:
1106db3dfefSJiri Kosina case -ESHUTDOWN:
1116db3dfefSJiri Kosina return;
1126db3dfefSJiri Kosina /* -EPIPE: should clear the halt */
1136db3dfefSJiri Kosina default: /* error */
1146db3dfefSJiri Kosina goto resubmit;
1156db3dfefSJiri Kosina }
1166db3dfefSJiri Kosina
1176db3dfefSJiri Kosina for (i = 0; i < 8; i++)
1186db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
1196db3dfefSJiri Kosina
1206db3dfefSJiri Kosina for (i = 2; i < 8; i++) {
1216db3dfefSJiri Kosina
1226db3dfefSJiri Kosina if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
1236db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->old[i]])
1246db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
1256db3dfefSJiri Kosina else
1264291ee30SJoe Perches hid_info(urb->dev,
1274291ee30SJoe Perches "Unknown key (scancode %#x) released.\n",
1284291ee30SJoe Perches kbd->old[i]);
1296db3dfefSJiri Kosina }
1306db3dfefSJiri Kosina
1316db3dfefSJiri Kosina if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
1326db3dfefSJiri Kosina if (usb_kbd_keycode[kbd->new[i]])
1336db3dfefSJiri Kosina input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
1346db3dfefSJiri Kosina else
1354291ee30SJoe Perches hid_info(urb->dev,
1369fee8240SAdam Cozzette "Unknown key (scancode %#x) pressed.\n",
1374291ee30SJoe Perches kbd->new[i]);
1386db3dfefSJiri Kosina }
1396db3dfefSJiri Kosina }
1406db3dfefSJiri Kosina
1416db3dfefSJiri Kosina input_sync(kbd->dev);
1426db3dfefSJiri Kosina
1436db3dfefSJiri Kosina memcpy(kbd->old, kbd->new, 8);
1446db3dfefSJiri Kosina
1456db3dfefSJiri Kosina resubmit:
1466db3dfefSJiri Kosina i = usb_submit_urb (urb, GFP_ATOMIC);
1476db3dfefSJiri Kosina if (i)
1484291ee30SJoe Perches hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
1496db3dfefSJiri Kosina kbd->usbdev->bus->bus_name,
1506db3dfefSJiri Kosina kbd->usbdev->devpath, i);
1516db3dfefSJiri Kosina }
1526db3dfefSJiri Kosina
usb_kbd_event(struct input_dev * dev,unsigned int type,unsigned int code,int value)1536db3dfefSJiri Kosina static int usb_kbd_event(struct input_dev *dev, unsigned int type,
1546db3dfefSJiri Kosina unsigned int code, int value)
1556db3dfefSJiri Kosina {
156c196adf8SWillem Penninckx unsigned long flags;
157e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev);
1586db3dfefSJiri Kosina
1596db3dfefSJiri Kosina if (type != EV_LED)
1606db3dfefSJiri Kosina return -1;
1616db3dfefSJiri Kosina
162c196adf8SWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags);
1636db3dfefSJiri Kosina kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
1646db3dfefSJiri Kosina (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
1656db3dfefSJiri Kosina (!!test_bit(LED_NUML, dev->led));
1666db3dfefSJiri Kosina
167c196adf8SWillem Penninckx if (kbd->led_urb_submitted){
168c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags);
1696db3dfefSJiri Kosina return 0;
170c196adf8SWillem Penninckx }
1716db3dfefSJiri Kosina
172c196adf8SWillem Penninckx if (*(kbd->leds) == kbd->newleds){
173c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags);
1746db3dfefSJiri Kosina return 0;
175c196adf8SWillem Penninckx }
1766db3dfefSJiri Kosina
1776db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds;
178c196adf8SWillem Penninckx
1796db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev;
1806db3dfefSJiri Kosina if (usb_submit_urb(kbd->led, GFP_ATOMIC))
1814291ee30SJoe Perches pr_err("usb_submit_urb(leds) failed\n");
182c196adf8SWillem Penninckx else
183c196adf8SWillem Penninckx kbd->led_urb_submitted = true;
184c196adf8SWillem Penninckx
185c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags);
1866db3dfefSJiri Kosina
1876db3dfefSJiri Kosina return 0;
1886db3dfefSJiri Kosina }
1896db3dfefSJiri Kosina
usb_kbd_led(struct urb * urb)1906db3dfefSJiri Kosina static void usb_kbd_led(struct urb *urb)
1916db3dfefSJiri Kosina {
192c196adf8SWillem Penninckx unsigned long flags;
1936db3dfefSJiri Kosina struct usb_kbd *kbd = urb->context;
1946db3dfefSJiri Kosina
1956db3dfefSJiri Kosina if (urb->status)
1964291ee30SJoe Perches hid_warn(urb->dev, "led urb status %d received\n",
1977d89fe12SFrom: Greg Kroah-Hartman urb->status);
1986db3dfefSJiri Kosina
199c196adf8SWillem Penninckx spin_lock_irqsave(&kbd->leds_lock, flags);
200c196adf8SWillem Penninckx
201c196adf8SWillem Penninckx if (*(kbd->leds) == kbd->newleds){
202c196adf8SWillem Penninckx kbd->led_urb_submitted = false;
203c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags);
2046db3dfefSJiri Kosina return;
205c196adf8SWillem Penninckx }
2066db3dfefSJiri Kosina
2076db3dfefSJiri Kosina *(kbd->leds) = kbd->newleds;
208c196adf8SWillem Penninckx
2096db3dfefSJiri Kosina kbd->led->dev = kbd->usbdev;
210c196adf8SWillem Penninckx if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
2114291ee30SJoe Perches hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
212c196adf8SWillem Penninckx kbd->led_urb_submitted = false;
213c196adf8SWillem Penninckx }
214c196adf8SWillem Penninckx spin_unlock_irqrestore(&kbd->leds_lock, flags);
215c196adf8SWillem Penninckx
2166db3dfefSJiri Kosina }
2176db3dfefSJiri Kosina
usb_kbd_open(struct input_dev * dev)2186db3dfefSJiri Kosina static int usb_kbd_open(struct input_dev *dev)
2196db3dfefSJiri Kosina {
220e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev);
2216db3dfefSJiri Kosina
2226db3dfefSJiri Kosina kbd->irq->dev = kbd->usbdev;
2236db3dfefSJiri Kosina if (usb_submit_urb(kbd->irq, GFP_KERNEL))
2246db3dfefSJiri Kosina return -EIO;
2256db3dfefSJiri Kosina
2266db3dfefSJiri Kosina return 0;
2276db3dfefSJiri Kosina }
2286db3dfefSJiri Kosina
usb_kbd_close(struct input_dev * dev)2296db3dfefSJiri Kosina static void usb_kbd_close(struct input_dev *dev)
2306db3dfefSJiri Kosina {
231e0712985SDmitry Torokhov struct usb_kbd *kbd = input_get_drvdata(dev);
2326db3dfefSJiri Kosina
2336db3dfefSJiri Kosina usb_kill_urb(kbd->irq);
2346db3dfefSJiri Kosina }
2356db3dfefSJiri Kosina
usb_kbd_alloc_mem(struct usb_device * dev,struct usb_kbd * kbd)2366db3dfefSJiri Kosina static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
2376db3dfefSJiri Kosina {
2386db3dfefSJiri Kosina if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
2396db3dfefSJiri Kosina return -1;
2406db3dfefSJiri Kosina if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
2416db3dfefSJiri Kosina return -1;
242a3af901cSHyeonggon Yoo if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbd->new_dma)))
2436db3dfefSJiri Kosina return -1;
2440ede76fcSAlan Stern if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
2456db3dfefSJiri Kosina return -1;
246a3af901cSHyeonggon Yoo if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_KERNEL, &kbd->leds_dma)))
2476db3dfefSJiri Kosina return -1;
2486db3dfefSJiri Kosina
2496db3dfefSJiri Kosina return 0;
2506db3dfefSJiri Kosina }
2516db3dfefSJiri Kosina
usb_kbd_free_mem(struct usb_device * dev,struct usb_kbd * kbd)2526db3dfefSJiri Kosina static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
2536db3dfefSJiri Kosina {
2546db3dfefSJiri Kosina usb_free_urb(kbd->irq);
2556db3dfefSJiri Kosina usb_free_urb(kbd->led);
256997ea58eSDaniel Mack usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
2570ede76fcSAlan Stern kfree(kbd->cr);
258997ea58eSDaniel Mack usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
2596db3dfefSJiri Kosina }
2606db3dfefSJiri Kosina
usb_kbd_probe(struct usb_interface * iface,const struct usb_device_id * id)2616db3dfefSJiri Kosina static int usb_kbd_probe(struct usb_interface *iface,
2626db3dfefSJiri Kosina const struct usb_device_id *id)
2636db3dfefSJiri Kosina {
2646db3dfefSJiri Kosina struct usb_device *dev = interface_to_usbdev(iface);
2656db3dfefSJiri Kosina struct usb_host_interface *interface;
2666db3dfefSJiri Kosina struct usb_endpoint_descriptor *endpoint;
2676db3dfefSJiri Kosina struct usb_kbd *kbd;
2686db3dfefSJiri Kosina struct input_dev *input_dev;
2696db3dfefSJiri Kosina int i, pipe, maxp;
2705d6341c6SDmitry Torokhov int error = -ENOMEM;
2716db3dfefSJiri Kosina
2726db3dfefSJiri Kosina interface = iface->cur_altsetting;
2736db3dfefSJiri Kosina
2746db3dfefSJiri Kosina if (interface->desc.bNumEndpoints != 1)
2756db3dfefSJiri Kosina return -ENODEV;
2766db3dfefSJiri Kosina
2776db3dfefSJiri Kosina endpoint = &interface->endpoint[0].desc;
2786db3dfefSJiri Kosina if (!usb_endpoint_is_int_in(endpoint))
2796db3dfefSJiri Kosina return -ENODEV;
2806db3dfefSJiri Kosina
2816db3dfefSJiri Kosina pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
282b45cde33SVincent Mailhol maxp = usb_maxpacket(dev, pipe);
2836db3dfefSJiri Kosina
2846db3dfefSJiri Kosina kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
2856db3dfefSJiri Kosina input_dev = input_allocate_device();
2866db3dfefSJiri Kosina if (!kbd || !input_dev)
2876db3dfefSJiri Kosina goto fail1;
2886db3dfefSJiri Kosina
2896db3dfefSJiri Kosina if (usb_kbd_alloc_mem(dev, kbd))
2906db3dfefSJiri Kosina goto fail2;
2916db3dfefSJiri Kosina
2926db3dfefSJiri Kosina kbd->usbdev = dev;
2936db3dfefSJiri Kosina kbd->dev = input_dev;
294c196adf8SWillem Penninckx spin_lock_init(&kbd->leds_lock);
2956db3dfefSJiri Kosina
2966db3dfefSJiri Kosina if (dev->manufacturer)
297*eeeec27dSWolfram Sang strscpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
2986db3dfefSJiri Kosina
2996db3dfefSJiri Kosina if (dev->product) {
3006db3dfefSJiri Kosina if (dev->manufacturer)
3016db3dfefSJiri Kosina strlcat(kbd->name, " ", sizeof(kbd->name));
3026db3dfefSJiri Kosina strlcat(kbd->name, dev->product, sizeof(kbd->name));
3036db3dfefSJiri Kosina }
3046db3dfefSJiri Kosina
3056db3dfefSJiri Kosina if (!strlen(kbd->name))
3066db3dfefSJiri Kosina snprintf(kbd->name, sizeof(kbd->name),
3076db3dfefSJiri Kosina "USB HIDBP Keyboard %04x:%04x",
3086db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idVendor),
3096db3dfefSJiri Kosina le16_to_cpu(dev->descriptor.idProduct));
3106db3dfefSJiri Kosina
3116db3dfefSJiri Kosina usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
3126236dfaaSMárton Németh strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
3136db3dfefSJiri Kosina
3146db3dfefSJiri Kosina input_dev->name = kbd->name;
3156db3dfefSJiri Kosina input_dev->phys = kbd->phys;
3166db3dfefSJiri Kosina usb_to_input_id(dev, &input_dev->id);
317e0712985SDmitry Torokhov input_dev->dev.parent = &iface->dev;
318e0712985SDmitry Torokhov
319e0712985SDmitry Torokhov input_set_drvdata(input_dev, kbd);
3206db3dfefSJiri Kosina
3217b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
3227b19ada2SJiri Slaby BIT_MASK(EV_REP);
3237b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
3247b19ada2SJiri Slaby BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
3257b19ada2SJiri Slaby BIT_MASK(LED_KANA);
3266db3dfefSJiri Kosina
3276db3dfefSJiri Kosina for (i = 0; i < 255; i++)
3286db3dfefSJiri Kosina set_bit(usb_kbd_keycode[i], input_dev->keybit);
3296db3dfefSJiri Kosina clear_bit(0, input_dev->keybit);
3306db3dfefSJiri Kosina
3316db3dfefSJiri Kosina input_dev->event = usb_kbd_event;
3326db3dfefSJiri Kosina input_dev->open = usb_kbd_open;
3336db3dfefSJiri Kosina input_dev->close = usb_kbd_close;
3346db3dfefSJiri Kosina
3356db3dfefSJiri Kosina usb_fill_int_urb(kbd->irq, dev, pipe,
3366db3dfefSJiri Kosina kbd->new, (maxp > 8 ? 8 : maxp),
3376db3dfefSJiri Kosina usb_kbd_irq, kbd, endpoint->bInterval);
3386db3dfefSJiri Kosina kbd->irq->transfer_dma = kbd->new_dma;
3396db3dfefSJiri Kosina kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3406db3dfefSJiri Kosina
3416db3dfefSJiri Kosina kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
3426db3dfefSJiri Kosina kbd->cr->bRequest = 0x09;
3436db3dfefSJiri Kosina kbd->cr->wValue = cpu_to_le16(0x200);
3446db3dfefSJiri Kosina kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
3456db3dfefSJiri Kosina kbd->cr->wLength = cpu_to_le16(1);
3466db3dfefSJiri Kosina
3476db3dfefSJiri Kosina usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
3486db3dfefSJiri Kosina (void *) kbd->cr, kbd->leds, 1,
3496db3dfefSJiri Kosina usb_kbd_led, kbd);
3506db3dfefSJiri Kosina kbd->led->transfer_dma = kbd->leds_dma;
3510ede76fcSAlan Stern kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3526db3dfefSJiri Kosina
3535d6341c6SDmitry Torokhov error = input_register_device(kbd->dev);
3545d6341c6SDmitry Torokhov if (error)
3555d6341c6SDmitry Torokhov goto fail2;
3566db3dfefSJiri Kosina
3576db3dfefSJiri Kosina usb_set_intfdata(iface, kbd);
3583d61510fSAlan Stern device_set_wakeup_enable(&dev->dev, 1);
3596db3dfefSJiri Kosina return 0;
3606db3dfefSJiri Kosina
3615d6341c6SDmitry Torokhov fail2:
3625d6341c6SDmitry Torokhov usb_kbd_free_mem(dev, kbd);
3635d6341c6SDmitry Torokhov fail1:
3645d6341c6SDmitry Torokhov input_free_device(input_dev);
3656db3dfefSJiri Kosina kfree(kbd);
3665d6341c6SDmitry Torokhov return error;
3676db3dfefSJiri Kosina }
3686db3dfefSJiri Kosina
usb_kbd_disconnect(struct usb_interface * intf)3696db3dfefSJiri Kosina static void usb_kbd_disconnect(struct usb_interface *intf)
3706db3dfefSJiri Kosina {
3716db3dfefSJiri Kosina struct usb_kbd *kbd = usb_get_intfdata (intf);
3726db3dfefSJiri Kosina
3736db3dfefSJiri Kosina usb_set_intfdata(intf, NULL);
3746db3dfefSJiri Kosina if (kbd) {
3756db3dfefSJiri Kosina usb_kill_urb(kbd->irq);
3766db3dfefSJiri Kosina input_unregister_device(kbd->dev);
377a2b2c20bSWillem Penninckx usb_kill_urb(kbd->led);
3786db3dfefSJiri Kosina usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
3796db3dfefSJiri Kosina kfree(kbd);
3806db3dfefSJiri Kosina }
3816db3dfefSJiri Kosina }
3826db3dfefSJiri Kosina
38346cb3cf8SArvind Yadav static const struct usb_device_id usb_kbd_id_table[] = {
3846db3dfefSJiri Kosina { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
3856db3dfefSJiri Kosina USB_INTERFACE_PROTOCOL_KEYBOARD) },
3866db3dfefSJiri Kosina { } /* Terminating entry */
3876db3dfefSJiri Kosina };
3886db3dfefSJiri Kosina
3896db3dfefSJiri Kosina MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
3906db3dfefSJiri Kosina
3916db3dfefSJiri Kosina static struct usb_driver usb_kbd_driver = {
3926db3dfefSJiri Kosina .name = "usbkbd",
3936db3dfefSJiri Kosina .probe = usb_kbd_probe,
3946db3dfefSJiri Kosina .disconnect = usb_kbd_disconnect,
3956db3dfefSJiri Kosina .id_table = usb_kbd_id_table,
3966db3dfefSJiri Kosina };
3976db3dfefSJiri Kosina
39842f06a13SGreg Kroah-Hartman module_usb_driver(usb_kbd_driver);
399