blob: ed01dc425d29dbc8890915d6547fd3424e1ae2fc [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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43MODULE_AUTHOR(DRIVER_AUTHOR);
44MODULE_DESCRIPTION(DRIVER_DESC);
Grant Grundler7021b602017-01-05 11:07:04 -080045MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Ming Leia44ebcc2008-06-08 16:15:16 +080047static const unsigned char usb_kbd_keycode[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
49 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
50 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
51 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
52 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
53 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
54 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
55 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
56 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
57 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 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 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
63 150,158,159,128,136,177,178,176,142,152,173,140
64};
65
Willem Penninckxc196adf2011-11-23 11:25:34 +010066
67/**
68 * struct usb_kbd - state of each attached keyboard
69 * @dev: input device associated with this keyboard
70 * @usbdev: usb device associated with this keyboard
71 * @old: data received in the past from the @irq URB representing which
72 * keys were pressed. By comparing with the current list of keys
73 * that are pressed, we are able to see key releases.
74 * @irq: URB for receiving a list of keys that are pressed when a
75 * new key is pressed or a key that was pressed is released.
76 * @led: URB for sending LEDs (e.g. numlock, ...)
77 * @newleds: data that will be sent with the @led URB representing which LEDs
78 should be on
79 * @name: Name of the keyboard. @dev's name field points to this buffer
80 * @phys: Physical path of the keyboard. @dev's phys field points to this
81 * buffer
82 * @new: Buffer for the @irq URB
83 * @cr: Control request for @led URB
84 * @leds: Buffer for the @led URB
85 * @new_dma: DMA address for @irq URB
86 * @leds_dma: DMA address for @led URB
87 * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted
88 * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
89 * submitted and its completion handler has not returned yet
90 * without resubmitting @led
91 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092struct usb_kbd {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -050093 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 struct usb_device *usbdev;
95 unsigned char old[8];
96 struct urb *irq, *led;
97 unsigned char newleds;
98 char name[128];
99 char phys[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101 unsigned char *new;
102 struct usb_ctrlrequest *cr;
103 unsigned char *leds;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 dma_addr_t new_dma;
105 dma_addr_t leds_dma;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100106
107 spinlock_t leds_lock;
108 bool led_urb_submitted;
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
David Howells7d12e782006-10-05 14:55:46 +0100112static void usb_kbd_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 struct usb_kbd *kbd = urb->context;
115 int i;
116
117 switch (urb->status) {
118 case 0: /* success */
119 break;
120 case -ECONNRESET: /* unlink */
121 case -ENOENT:
122 case -ESHUTDOWN:
123 return;
124 /* -EPIPE: should clear the halt */
125 default: /* error */
126 goto resubmit;
127 }
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 for (i = 0; i < 8; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500130 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 for (i = 2; i < 8; i++) {
133
134 if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
135 if (usb_kbd_keycode[kbd->old[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500136 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 else
Joe Perches4291ee32010-12-09 19:29:03 -0800138 hid_info(urb->dev,
139 "Unknown key (scancode %#x) released.\n",
140 kbd->old[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 }
142
143 if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
144 if (usb_kbd_keycode[kbd->new[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500145 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 else
Joe Perches4291ee32010-12-09 19:29:03 -0800147 hid_info(urb->dev,
Adam Cozzette9fee8242013-11-17 13:51:23 -0800148 "Unknown key (scancode %#x) pressed.\n",
Joe Perches4291ee32010-12-09 19:29:03 -0800149 kbd->new[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 }
151 }
152
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500153 input_sync(kbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 memcpy(kbd->old, kbd->new, 8);
156
157resubmit:
Christoph Lameter54e6ecb2006-12-06 20:33:16 -0800158 i = usb_submit_urb (urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if (i)
Joe Perches4291ee32010-12-09 19:29:03 -0800160 hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
161 kbd->usbdev->bus->bus_name,
162 kbd->usbdev->devpath, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
Adrian Bunkbe5e33832005-04-22 15:07:00 -0700165static int usb_kbd_event(struct input_dev *dev, unsigned int type,
166 unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
Willem Penninckxc196adf2011-11-23 11:25:34 +0100168 unsigned long flags;
Dmitry Torokhove0712982007-05-09 10:17:31 +0200169 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 if (type != EV_LED)
172 return -1;
173
Willem Penninckxc196adf2011-11-23 11:25:34 +0100174 spin_lock_irqsave(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
176 (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
177 (!!test_bit(LED_NUML, dev->led));
178
Willem Penninckxc196adf2011-11-23 11:25:34 +0100179 if (kbd->led_urb_submitted){
180 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return 0;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Willem Penninckxc196adf2011-11-23 11:25:34 +0100184 if (*(kbd->leds) == kbd->newleds){
185 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 return 0;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 *(kbd->leds) = kbd->newleds;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 kbd->led->dev = kbd->usbdev;
192 if (usb_submit_urb(kbd->led, GFP_ATOMIC))
Joe Perches4291ee32010-12-09 19:29:03 -0800193 pr_err("usb_submit_urb(leds) failed\n");
Willem Penninckxc196adf2011-11-23 11:25:34 +0100194 else
195 kbd->led_urb_submitted = true;
196
197 spin_unlock_irqrestore(&kbd->leds_lock, flags);
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 return 0;
200}
201
David Howells7d12e782006-10-05 14:55:46 +0100202static void usb_kbd_led(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
Willem Penninckxc196adf2011-11-23 11:25:34 +0100204 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct usb_kbd *kbd = urb->context;
206
207 if (urb->status)
Joe Perches4291ee32010-12-09 19:29:03 -0800208 hid_warn(urb->dev, "led urb status %d received\n",
From: Greg Kroah-Hartman7d89fe12008-10-12 00:25:51 +0200209 urb->status);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500210
Willem Penninckxc196adf2011-11-23 11:25:34 +0100211 spin_lock_irqsave(&kbd->leds_lock, flags);
212
213 if (*(kbd->leds) == kbd->newleds){
214 kbd->led_urb_submitted = false;
215 spin_unlock_irqrestore(&kbd->leds_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 return;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 *(kbd->leds) = kbd->newleds;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 kbd->led->dev = kbd->usbdev;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100222 if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
Joe Perches4291ee32010-12-09 19:29:03 -0800223 hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
Willem Penninckxc196adf2011-11-23 11:25:34 +0100224 kbd->led_urb_submitted = false;
225 }
226 spin_unlock_irqrestore(&kbd->leds_lock, flags);
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
229
230static int usb_kbd_open(struct input_dev *dev)
231{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200232 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 kbd->irq->dev = kbd->usbdev;
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500235 if (usb_submit_urb(kbd->irq, GFP_KERNEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 return 0;
239}
240
241static void usb_kbd_close(struct input_dev *dev)
242{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200243 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500245 usb_kill_urb(kbd->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
248static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
249{
250 if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
251 return -1;
252 if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
253 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200254 if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return -1;
Alan Stern0ede76f2010-03-05 15:10:17 -0500256 if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200258 if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return -1;
260
261 return 0;
262}
263
264static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
265{
Mariusz Kozlowski4ba0b2e2006-11-08 15:35:58 +0100266 usb_free_urb(kbd->irq);
267 usb_free_urb(kbd->led);
Daniel Mack997ea582010-04-12 13:17:25 +0200268 usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
Alan Stern0ede76f2010-03-05 15:10:17 -0500269 kfree(kbd->cr);
Daniel Mack997ea582010-04-12 13:17:25 +0200270 usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500273static int usb_kbd_probe(struct usb_interface *iface,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 const struct usb_device_id *id)
275{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500276 struct usb_device *dev = interface_to_usbdev(iface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 struct usb_host_interface *interface;
278 struct usb_endpoint_descriptor *endpoint;
279 struct usb_kbd *kbd;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500280 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 int i, pipe, maxp;
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200282 int error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 interface = iface->cur_altsetting;
285
286 if (interface->desc.bNumEndpoints != 1)
287 return -ENODEV;
288
289 endpoint = &interface->endpoint[0].desc;
Luiz Fernando N. Capitulinoa20c3142006-10-26 13:02:59 -0300290 if (!usb_endpoint_is_int_in(endpoint))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return -ENODEV;
292
293 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
294 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
295
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500296 kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
297 input_dev = input_allocate_device();
298 if (!kbd || !input_dev)
299 goto fail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500301 if (usb_kbd_alloc_mem(dev, kbd))
302 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 kbd->usbdev = dev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500305 kbd->dev = input_dev;
Willem Penninckxc196adf2011-11-23 11:25:34 +0100306 spin_lock_init(&kbd->leds_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500308 if (dev->manufacturer)
309 strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
310
311 if (dev->product) {
312 if (dev->manufacturer)
313 strlcat(kbd->name, " ", sizeof(kbd->name));
314 strlcat(kbd->name, dev->product, sizeof(kbd->name));
315 }
316
317 if (!strlen(kbd->name))
318 snprintf(kbd->name, sizeof(kbd->name),
319 "USB HIDBP Keyboard %04x:%04x",
320 le16_to_cpu(dev->descriptor.idVendor),
321 le16_to_cpu(dev->descriptor.idProduct));
322
323 usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
Márton Németh6236dfa2009-11-23 08:26:38 -0800324 strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500325
326 input_dev->name = kbd->name;
327 input_dev->phys = kbd->phys;
328 usb_to_input_id(dev, &input_dev->id);
Dmitry Torokhove0712982007-05-09 10:17:31 +0200329 input_dev->dev.parent = &iface->dev;
330
331 input_set_drvdata(input_dev, kbd);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500332
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700333 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
334 BIT_MASK(EV_REP);
335 input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
336 BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
337 BIT_MASK(LED_KANA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 for (i = 0; i < 255; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500340 set_bit(usb_kbd_keycode[i], input_dev->keybit);
341 clear_bit(0, input_dev->keybit);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500342
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500343 input_dev->event = usb_kbd_event;
344 input_dev->open = usb_kbd_open;
345 input_dev->close = usb_kbd_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 usb_fill_int_urb(kbd->irq, dev, pipe,
348 kbd->new, (maxp > 8 ? 8 : maxp),
349 usb_kbd_irq, kbd, endpoint->bInterval);
350 kbd->irq->transfer_dma = kbd->new_dma;
351 kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
352
353 kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
354 kbd->cr->bRequest = 0x09;
355 kbd->cr->wValue = cpu_to_le16(0x200);
356 kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
357 kbd->cr->wLength = cpu_to_le16(1);
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
360 (void *) kbd->cr, kbd->leds, 1,
361 usb_kbd_led, kbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 kbd->led->transfer_dma = kbd->leds_dma;
Alan Stern0ede76f2010-03-05 15:10:17 -0500363 kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200365 error = input_register_device(kbd->dev);
366 if (error)
367 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 usb_set_intfdata(iface, kbd);
Alan Stern3d615102010-04-02 13:21:58 -0400370 device_set_wakeup_enable(&dev->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return 0;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500372
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200373fail2:
374 usb_kbd_free_mem(dev, kbd);
375fail1:
376 input_free_device(input_dev);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500377 kfree(kbd);
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200378 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
380
381static void usb_kbd_disconnect(struct usb_interface *intf)
382{
383 struct usb_kbd *kbd = usb_get_intfdata (intf);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 usb_set_intfdata(intf, NULL);
386 if (kbd) {
387 usb_kill_urb(kbd->irq);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500388 input_unregister_device(kbd->dev);
Willem Penninckxa2b2c202011-11-23 11:26:45 +0100389 usb_kill_urb(kbd->led);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
391 kfree(kbd);
392 }
393}
394
Arvind Yadav46cb3cf2017-08-09 23:51:34 +0530395static const struct usb_device_id usb_kbd_id_table[] = {
Michael Opdenacker4ef2e232007-02-21 22:51:25 +0100396 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
397 USB_INTERFACE_PROTOCOL_KEYBOARD) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 { } /* Terminating entry */
399};
400
401MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
402
403static struct usb_driver usb_kbd_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 .name = "usbkbd",
405 .probe = usb_kbd_probe,
406 .disconnect = usb_kbd_disconnect,
407 .id_table = usb_kbd_id_table,
408};
409
Greg Kroah-Hartman42f06a12011-11-18 09:49:34 -0800410module_usb_driver(usb_kbd_driver);