blob: 065817329f03b68fe1e100a78559baddd568ce9e [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 Torokhov05f091a2005-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 Torokhov05f091a2005-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 Torokhov05f091a2005-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 Torokhov05f091a2005-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
67struct usb_kbd {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -050068 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 struct usb_device *usbdev;
70 unsigned char old[8];
71 struct urb *irq, *led;
72 unsigned char newleds;
73 char name[128];
74 char phys[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 unsigned char *new;
77 struct usb_ctrlrequest *cr;
78 unsigned char *leds;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 dma_addr_t new_dma;
80 dma_addr_t leds_dma;
81};
82
David Howells7d12e782006-10-05 14:55:46 +010083static void usb_kbd_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
85 struct usb_kbd *kbd = urb->context;
86 int i;
87
88 switch (urb->status) {
89 case 0: /* success */
90 break;
91 case -ECONNRESET: /* unlink */
92 case -ENOENT:
93 case -ESHUTDOWN:
94 return;
95 /* -EPIPE: should clear the halt */
96 default: /* error */
97 goto resubmit;
98 }
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 for (i = 0; i < 8; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500101 input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 for (i = 2; i < 8; i++) {
104
105 if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
106 if (usb_kbd_keycode[kbd->old[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500107 input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 else
Joe Perches4291ee32010-12-09 19:29:03 -0800109 hid_info(urb->dev,
110 "Unknown key (scancode %#x) released.\n",
111 kbd->old[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 }
113
114 if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
115 if (usb_kbd_keycode[kbd->new[i]])
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500116 input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 else
Joe Perches4291ee32010-12-09 19:29:03 -0800118 hid_info(urb->dev,
119 "Unknown key (scancode %#x) released.\n",
120 kbd->new[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 }
122 }
123
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500124 input_sync(kbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 memcpy(kbd->old, kbd->new, 8);
127
128resubmit:
Christoph Lameter54e6ecb2006-12-06 20:33:16 -0800129 i = usb_submit_urb (urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 if (i)
Joe Perches4291ee32010-12-09 19:29:03 -0800131 hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
132 kbd->usbdev->bus->bus_name,
133 kbd->usbdev->devpath, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134}
135
Adrian Bunkbe5e33832005-04-22 15:07:00 -0700136static int usb_kbd_event(struct input_dev *dev, unsigned int type,
137 unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200139 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 if (type != EV_LED)
142 return -1;
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
145 (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
146 (!!test_bit(LED_NUML, dev->led));
147
148 if (kbd->led->status == -EINPROGRESS)
149 return 0;
150
151 if (*(kbd->leds) == kbd->newleds)
152 return 0;
153
154 *(kbd->leds) = kbd->newleds;
155 kbd->led->dev = kbd->usbdev;
156 if (usb_submit_urb(kbd->led, GFP_ATOMIC))
Joe Perches4291ee32010-12-09 19:29:03 -0800157 pr_err("usb_submit_urb(leds) failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 return 0;
160}
161
David Howells7d12e782006-10-05 14:55:46 +0100162static void usb_kbd_led(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163{
164 struct usb_kbd *kbd = urb->context;
165
166 if (urb->status)
Joe Perches4291ee32010-12-09 19:29:03 -0800167 hid_warn(urb->dev, "led urb status %d received\n",
From: Greg Kroah-Hartman7d89fe12008-10-12 00:25:51 +0200168 urb->status);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 if (*(kbd->leds) == kbd->newleds)
171 return;
172
173 *(kbd->leds) = kbd->newleds;
174 kbd->led->dev = kbd->usbdev;
175 if (usb_submit_urb(kbd->led, GFP_ATOMIC))
Joe Perches4291ee32010-12-09 19:29:03 -0800176 hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
178
179static int usb_kbd_open(struct input_dev *dev)
180{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200181 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 kbd->irq->dev = kbd->usbdev;
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500184 if (usb_submit_urb(kbd->irq, GFP_KERNEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
187 return 0;
188}
189
190static void usb_kbd_close(struct input_dev *dev)
191{
Dmitry Torokhove0712982007-05-09 10:17:31 +0200192 struct usb_kbd *kbd = input_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Dmitry Torokhov65cde542005-05-29 02:29:38 -0500194 usb_kill_urb(kbd->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195}
196
197static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
198{
199 if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
200 return -1;
201 if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
202 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200203 if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 return -1;
Alan Stern0ede76f2010-03-05 15:10:17 -0500205 if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return -1;
Daniel Mack997ea582010-04-12 13:17:25 +0200207 if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return -1;
209
210 return 0;
211}
212
213static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
214{
Mariusz Kozlowski4ba0b2e2006-11-08 15:35:58 +0100215 usb_free_urb(kbd->irq);
216 usb_free_urb(kbd->led);
Daniel Mack997ea582010-04-12 13:17:25 +0200217 usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
Alan Stern0ede76f2010-03-05 15:10:17 -0500218 kfree(kbd->cr);
Daniel Mack997ea582010-04-12 13:17:25 +0200219 usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500222static int usb_kbd_probe(struct usb_interface *iface,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 const struct usb_device_id *id)
224{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500225 struct usb_device *dev = interface_to_usbdev(iface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 struct usb_host_interface *interface;
227 struct usb_endpoint_descriptor *endpoint;
228 struct usb_kbd *kbd;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500229 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 int i, pipe, maxp;
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200231 int error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 interface = iface->cur_altsetting;
234
235 if (interface->desc.bNumEndpoints != 1)
236 return -ENODEV;
237
238 endpoint = &interface->endpoint[0].desc;
Luiz Fernando N. Capitulinoa20c3142006-10-26 13:02:59 -0300239 if (!usb_endpoint_is_int_in(endpoint))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 return -ENODEV;
241
242 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
243 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
244
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500245 kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
246 input_dev = input_allocate_device();
247 if (!kbd || !input_dev)
248 goto fail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500250 if (usb_kbd_alloc_mem(dev, kbd))
251 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 kbd->usbdev = dev;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500254 kbd->dev = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500256 if (dev->manufacturer)
257 strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
258
259 if (dev->product) {
260 if (dev->manufacturer)
261 strlcat(kbd->name, " ", sizeof(kbd->name));
262 strlcat(kbd->name, dev->product, sizeof(kbd->name));
263 }
264
265 if (!strlen(kbd->name))
266 snprintf(kbd->name, sizeof(kbd->name),
267 "USB HIDBP Keyboard %04x:%04x",
268 le16_to_cpu(dev->descriptor.idVendor),
269 le16_to_cpu(dev->descriptor.idProduct));
270
271 usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
Márton Németh6236dfa2009-11-23 08:26:38 -0800272 strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500273
274 input_dev->name = kbd->name;
275 input_dev->phys = kbd->phys;
276 usb_to_input_id(dev, &input_dev->id);
Dmitry Torokhove0712982007-05-09 10:17:31 +0200277 input_dev->dev.parent = &iface->dev;
278
279 input_set_drvdata(input_dev, kbd);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500280
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700281 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
282 BIT_MASK(EV_REP);
283 input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
284 BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
285 BIT_MASK(LED_KANA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 for (i = 0; i < 255; i++)
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500288 set_bit(usb_kbd_keycode[i], input_dev->keybit);
289 clear_bit(0, input_dev->keybit);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500290
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500291 input_dev->event = usb_kbd_event;
292 input_dev->open = usb_kbd_open;
293 input_dev->close = usb_kbd_close;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 usb_fill_int_urb(kbd->irq, dev, pipe,
296 kbd->new, (maxp > 8 ? 8 : maxp),
297 usb_kbd_irq, kbd, endpoint->bInterval);
298 kbd->irq->transfer_dma = kbd->new_dma;
299 kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
300
301 kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
302 kbd->cr->bRequest = 0x09;
303 kbd->cr->wValue = cpu_to_le16(0x200);
304 kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
305 kbd->cr->wLength = cpu_to_le16(1);
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
308 (void *) kbd->cr, kbd->leds, 1,
309 usb_kbd_led, kbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 kbd->led->transfer_dma = kbd->leds_dma;
Alan Stern0ede76f2010-03-05 15:10:17 -0500311 kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200313 error = input_register_device(kbd->dev);
314 if (error)
315 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 usb_set_intfdata(iface, kbd);
Alan Stern3d615102010-04-02 13:21:58 -0400318 device_set_wakeup_enable(&dev->dev, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 return 0;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500320
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200321fail2:
322 usb_kbd_free_mem(dev, kbd);
323fail1:
324 input_free_device(input_dev);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500325 kfree(kbd);
Dmitry Torokhov5d6341c2007-04-04 10:40:57 +0200326 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
329static void usb_kbd_disconnect(struct usb_interface *intf)
330{
331 struct usb_kbd *kbd = usb_get_intfdata (intf);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 usb_set_intfdata(intf, NULL);
334 if (kbd) {
335 usb_kill_urb(kbd->irq);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500336 input_unregister_device(kbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
338 kfree(kbd);
339 }
340}
341
342static struct usb_device_id usb_kbd_id_table [] = {
Michael Opdenacker4ef2e232007-02-21 22:51:25 +0100343 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
344 USB_INTERFACE_PROTOCOL_KEYBOARD) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 { } /* Terminating entry */
346};
347
348MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
349
350static struct usb_driver usb_kbd_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 .name = "usbkbd",
352 .probe = usb_kbd_probe,
353 .disconnect = usb_kbd_disconnect,
354 .id_table = usb_kbd_id_table,
355};
356
357static int __init usb_kbd_init(void)
358{
359 int result = usb_register(&usb_kbd_driver);
360 if (result == 0)
Greg Kroah-Hartmanddbe3242008-10-12 00:14:23 +0200361 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
362 DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return result;
364}
365
366static void __exit usb_kbd_exit(void)
367{
368 usb_deregister(&usb_kbd_driver);
369}
370
371module_init(usb_kbd_init);
372module_exit(usb_kbd_exit);