blob: 9a332e683db77d170f2f1b281e813db02896df4a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (c) 1999-2001 Vojtech Pavlik
3 *
4 * USB HIDBP Keyboard support
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050010 * the Free Software Foundation; either version 2 of the License, or
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * (at your option) any later version.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050012 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -050021 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * Should you need to contact me, the author, you can do so either by
23 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
24 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
25 */
26
Joe Perches4291ee32010-12-09 19:29:03 -080027#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/kernel.h>
30#include <linux/slab.h>
31#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/init.h>
David Brownellae0dadc2006-06-13 10:04:34 -070033#include <linux/usb/input.h>
Michael Opdenacker4ef2e232007-02-21 22:51:25 +010034#include <linux/hid.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36/*
37 * Version Information
38 */
39#define DRIVER_VERSION ""
40#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
41#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
42#define DRIVER_LICENSE "GPL"
43
44MODULE_AUTHOR(DRIVER_AUTHOR);
45MODULE_DESCRIPTION(DRIVER_DESC);
46MODULE_LICENSE(DRIVER_LICENSE);
47
Ming Leia44ebcc2008-06-08 16:15:16 +080048static const unsigned char usb_kbd_keycode[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
51 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
52 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
53 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
54 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
55 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
56 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
57 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
58 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
64 150,158,159,128,136,177,178,176,142,152,173,140
65};
66
Willem Penninckxc196adf2011-11-23 11:25:34 +010067
68/**
69 * struct usb_kbd - state of each attached keyboard
70 * @dev: input device associated with this keyboard
71 * @usbdev: usb device associated with this keyboard
72 * @old: data received in the past from the @irq URB representing which
73 * keys were pressed. By comparing with the current list of keys
74 * that are pressed, we are able to see key releases.
75 * @irq: URB for receiving a list of keys that are pressed when a
76 * new key is pressed or a key that was pressed is released.
77 * @led: URB for sending LEDs (e.g. numlock, ...)
78 * @newleds: data that will be sent with the @led URB representing which LEDs
79 should be on
80 * @name: Name of the keyboard. @dev's name field points to this buffer
81 * @phys: Physical path of the keyboard. @dev's phys field points to this
82 * buffer
83 * @new: Buffer for the @irq URB
84 * @cr: Control request for @led URB
85 * @leds: Buffer for the @led URB
86 * @new_dma: DMA address for @irq URB
87 * @leds_dma: DMA address for @led URB
88 * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted
89 * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
90 * submitted and its completion handler has not returned yet
91 * without resubmitting @led
92 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093struct usb_kbd {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -050094 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 struct usb_device *usbdev;
96 unsigned char old[8];
97 struct urb *irq, *led;
98 unsigned char newleds;
99 char name[128];
100 char phys[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102 unsigned char *new;
103 struct usb_ctrlrequest *cr;
104 unsigned char *leds;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 dma_addr_t new_dma;
106 dma_addr_t leds_dma;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100107
108 spinlock_t leds_lock;
109 bool led_urb_submitted;
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
David Howells7d12e782006-10-05 14:55:46 +0100113static void usb_kbd_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 struct usb_kbd *kbd = urb->context;
116 int i;
117
118 switch (urb->status) {
119 case 0: /* success */
120 break;
121 case -ECONNRESET: /* unlink */
122 case -ENOENT:
123 case -ESHUTDOWN:
124 return;
125 /* -EPIPE: should clear the halt */
126 default: /* error */
127 goto resubmit;
128 }
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 for (i = 0; i < 8; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500131 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133 for (i = 2; i < 8; i++) {
134
135 if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
136 if (usb_kbd_keycode[kbd->old[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500137 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 else
Joe Perches4291ee32010-12-09 19:29:03 -0800139 hid_info(urb->dev,
140 "Unknown key (scancode %#x) released.\n",
141 kbd->old[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 }
143
144 if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
145 if (usb_kbd_keycode[kbd->new[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500146 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 else
Joe Perches4291ee32010-12-09 19:29:03 -0800148 hid_info(urb->dev,
Adam Cozzette9fee8242013-11-17 13:51:23 -0800149 "Unknown key (scancode %#x) pressed.\n",
Joe Perches4291ee32010-12-09 19:29:03 -0800150 kbd->new[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
152 }
153
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500154 input_sync(kbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 memcpy(kbd->old, kbd->new, 8);
157
158resubmit:
Christoph Lameter54e6ecb2006-12-06 20:33:16 -0800159 i = usb_submit_urb (urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 if (i)
Joe Perches4291ee32010-12-09 19:29:03 -0800161 hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
162 kbd->usbdev->bus->bus_name,
163 kbd->usbdev->devpath, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Adrian Bunkbe5e33832005-04-22 15:07:00 -0700166static int usb_kbd_event(struct input_dev *dev, unsigned int type,
167 unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
Willem Penninckxc196adf2011-11-23 11:25:34 +0100169 unsigned long flags;
Dmitry Torokhove0712982007-05-09 10:17:31 +0200170 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 if (type != EV_LED)
173 return -1;
174
Willem Penninckxc196adf2011-11-23 11:25:34 +0100175 spin_lock_irqsave(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
177 (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
178 (!!test_bit(LED_NUML, dev->led));
179
Willem Penninckxc196adf2011-11-23 11:25:34 +0100180 if (kbd->led_urb_submitted){
181 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 return 0;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Willem Penninckxc196adf2011-11-23 11:25:34 +0100185 if (*(kbd->leds) == kbd->newleds){
186 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return 0;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 *(kbd->leds) = kbd->newleds;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 kbd->led->dev = kbd->usbdev;
193 if (usb_submit_urb(kbd->led, GFP_ATOMIC))
Joe Perches4291ee32010-12-09 19:29:03 -0800194 pr_err("usb_submit_urb(leds) failed\n");
Willem Penninckxc196adf2011-11-23 11:25:34 +0100195 else
196 kbd->led_urb_submitted = true;
197
198 spin_unlock_irqrestore(&kbd->leds_lock, flags);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 return 0;
201}
202
David Howells7d12e782006-10-05 14:55:46 +0100203static void usb_kbd_led(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Willem Penninckxc196adf2011-11-23 11:25:34 +0100205 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 struct usb_kbd *kbd = urb->context;
207
208 if (urb->status)
Joe Perches4291ee32010-12-09 19:29:03 -0800209 hid_warn(urb->dev, "led urb status %d received\n",
From: Greg Kroah-Hartman7d89fe12008-10-12 00:25:51 +0200210 urb->status);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500211
Willem Penninckxc196adf2011-11-23 11:25:34 +0100212 spin_lock_irqsave(&kbd->leds_lock, flags);
213
214 if (*(kbd->leds) == kbd->newleds){
215 kbd->led_urb_submitted = false;
216 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 *(kbd->leds) = kbd->newleds;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 kbd->led->dev = kbd->usbdev;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100223 if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
Joe Perches4291ee32010-12-09 19:29:03 -0800224 hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
Willem Penninckxc196adf2011-11-23 11:25:34 +0100225 kbd->led_urb_submitted = false;
226 }
227 spin_unlock_irqrestore(&kbd->leds_lock, flags);
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
231static int usb_kbd_open(struct input_dev *dev)
232{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200233 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 kbd->irq->dev = kbd->usbdev;
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500236 if (usb_submit_urb(kbd->irq, GFP_KERNEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 return 0;
240}
241
242static void usb_kbd_close(struct input_dev *dev)
243{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200244 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500246 usb_kill_urb(kbd->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
250{
251 if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
252 return -1;
253 if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
254 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200255 if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return -1;
Alan Stern0ede76f2010-03-05 15:10:17 -0500257 if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200259 if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 return -1;
261
262 return 0;
263}
264
265static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
266{
Mariusz Kozlowski4ba0b2e2006-11-08 15:35:58 +0100267 usb_free_urb(kbd->irq);
268 usb_free_urb(kbd->led);
Daniel Mack997ea582010-04-12 13:17:25 +0200269 usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
Alan Stern0ede76f2010-03-05 15:10:17 -0500270 kfree(kbd->cr);
Daniel Mack997ea582010-04-12 13:17:25 +0200271 usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500274static int usb_kbd_probe(struct usb_interface *iface,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 const struct usb_device_id *id)
276{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500277 struct usb_device *dev = interface_to_usbdev(iface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct usb_host_interface *interface;
279 struct usb_endpoint_descriptor *endpoint;
280 struct usb_kbd *kbd;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500281 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 int i, pipe, maxp;
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200283 int error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 interface = iface->cur_altsetting;
286
287 if (interface->desc.bNumEndpoints != 1)
288 return -ENODEV;
289
290 endpoint = &interface->endpoint[0].desc;
Luiz Fernando N. Capitulinoa20c3142006-10-26 13:02:59 -0300291 if (!usb_endpoint_is_int_in(endpoint))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -ENODEV;
293
294 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
295 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
296
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500297 kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
298 input_dev = input_allocate_device();
299 if (!kbd || !input_dev)
300 goto fail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500302 if (usb_kbd_alloc_mem(dev, kbd))
303 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 kbd->usbdev = dev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500306 kbd->dev = input_dev;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100307 spin_lock_init(&kbd->leds_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500309 if (dev->manufacturer)
310 strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
311
312 if (dev->product) {
313 if (dev->manufacturer)
314 strlcat(kbd->name, " ", sizeof(kbd->name));
315 strlcat(kbd->name, dev->product, sizeof(kbd->name));
316 }
317
318 if (!strlen(kbd->name))
319 snprintf(kbd->name, sizeof(kbd->name),
320 "USB HIDBP Keyboard %04x:%04x",
321 le16_to_cpu(dev->descriptor.idVendor),
322 le16_to_cpu(dev->descriptor.idProduct));
323
324 usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
Márton Németh6236dfa2009-11-23 08:26:38 -0800325 strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500326
327 input_dev->name = kbd->name;
328 input_dev->phys = kbd->phys;
329 usb_to_input_id(dev, &input_dev->id);
Dmitry Torokhove0712982007-05-09 10:17:31 +0200330 input_dev->dev.parent = &iface->dev;
331
332 input_set_drvdata(input_dev, kbd);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500333
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700334 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
335 BIT_MASK(EV_REP);
336 input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
337 BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
338 BIT_MASK(LED_KANA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 for (i = 0; i < 255; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500341 set_bit(usb_kbd_keycode[i], input_dev->keybit);
342 clear_bit(0, input_dev->keybit);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500343
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500344 input_dev->event = usb_kbd_event;
345 input_dev->open = usb_kbd_open;
346 input_dev->close = usb_kbd_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 usb_fill_int_urb(kbd->irq, dev, pipe,
349 kbd->new, (maxp > 8 ? 8 : maxp),
350 usb_kbd_irq, kbd, endpoint->bInterval);
351 kbd->irq->transfer_dma = kbd->new_dma;
352 kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
353
354 kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
355 kbd->cr->bRequest = 0x09;
356 kbd->cr->wValue = cpu_to_le16(0x200);
357 kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
358 kbd->cr->wLength = cpu_to_le16(1);
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
361 (void *) kbd->cr, kbd->leds, 1,
362 usb_kbd_led, kbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 kbd->led->transfer_dma = kbd->leds_dma;
Alan Stern0ede76f2010-03-05 15:10:17 -0500364 kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200366 error = input_register_device(kbd->dev);
367 if (error)
368 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 usb_set_intfdata(iface, kbd);
Alan Stern3d615102010-04-02 13:21:58 -0400371 device_set_wakeup_enable(&dev->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return 0;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500373
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200374fail2:
375 usb_kbd_free_mem(dev, kbd);
376fail1:
377 input_free_device(input_dev);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500378 kfree(kbd);
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200379 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
382static void usb_kbd_disconnect(struct usb_interface *intf)
383{
384 struct usb_kbd *kbd = usb_get_intfdata (intf);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 usb_set_intfdata(intf, NULL);
387 if (kbd) {
388 usb_kill_urb(kbd->irq);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500389 input_unregister_device(kbd->dev);
Willem Penninckxa2b2c202011-11-23 11:26:45 +0100390 usb_kill_urb(kbd->led);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
392 kfree(kbd);
393 }
394}
395
396static struct usb_device_id usb_kbd_id_table [] = {
Michael Opdenacker4ef2e232007-02-21 22:51:25 +0100397 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
398 USB_INTERFACE_PROTOCOL_KEYBOARD) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 { } /* Terminating entry */
400};
401
402MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
403
404static struct usb_driver usb_kbd_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 .name = "usbkbd",
406 .probe = usb_kbd_probe,
407 .disconnect = usb_kbd_disconnect,
408 .id_table = usb_kbd_id_table,
409};
410
Greg Kroah-Hartman42f06a12011-11-18 09:49:34 -0800411module_usb_driver(usb_kbd_driver);