11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (c) 1999-2001 Vojtech Pavlik
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  USB HIDBP Keyboard support
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
1005f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov * the Free Software Foundation; either version 2 of the License, or
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
1205f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
1705f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
274291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
284291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
33ae0dadcf0f912cbab2ac84caa437454620bf71b2David Brownell#include <linux/usb/input.h>
344ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker#include <linux/hid.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION ""
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_LICENSE "GPL"
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(DRIVER_AUTHOR);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE(DRIVER_LICENSE);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48a44ebccea873cf7d58b63605f1cdd6da9dfec70fMing Leistatic const unsigned char usb_kbd_keycode[256] = {
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	150,158,159,128,136,177,178,176,142,152,173,140
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
68c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx/**
69c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * struct usb_kbd - state of each attached keyboard
70c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @dev:	input device associated with this keyboard
71c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @usbdev:	usb device associated with this keyboard
72c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @old:	data received in the past from the @irq URB representing which
73c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		keys were pressed. By comparing with the current list of keys
74c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		that are pressed, we are able to see key releases.
75c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @irq:	URB for receiving a list of keys that are pressed when a
76c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		new key is pressed or a key that was pressed is released.
77c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @led:	URB for sending LEDs (e.g. numlock, ...)
78c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @newleds:	data that will be sent with the @led URB representing which LEDs
79c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx 		should be on
80c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @name:	Name of the keyboard. @dev's name field points to this buffer
81c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @phys:	Physical path of the keyboard. @dev's phys field points to this
82c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		buffer
83c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @new:	Buffer for the @irq URB
84c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @cr:		Control request for @led URB
85c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds:	Buffer for the @led URB
86c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @new_dma:	DMA address for @irq URB
87c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds_dma:	DMA address for @led URB
88c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @leds_lock:	spinlock that protects @leds, @newleds, and @led_urb_submitted
89c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
90c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		submitted and its completion handler has not returned yet
91c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx *		without	resubmitting @led
92c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct usb_kbd {
94c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	struct input_dev *dev;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_device *usbdev;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char old[8];
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb *irq, *led;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char newleds;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char name[128];
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char phys[64];
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *new;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ctrlrequest *cr;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *leds;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t new_dma;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t leds_dma;
107c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
108c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spinlock_t leds_lock;
109c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	bool led_urb_submitted;
110c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1137d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void usb_kbd_irq(struct urb *urb)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_kbd *kbd = urb->context;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (urb->status) {
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:			/* success */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ECONNRESET:	/* unlink */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ENOENT:
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case -ESHUTDOWN:
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* -EPIPE:  should clear the halt */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:		/* error */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto resubmit;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i++)
131c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 2; i < 8; i++) {
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (usb_kbd_keycode[kbd->old[i]])
137c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
1394291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches				hid_info(urb->dev,
1404291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches					 "Unknown key (scancode %#x) released.\n",
1414291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches					 kbd->old[i]);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (usb_kbd_keycode[kbd->new[i]])
146c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
1484291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches				hid_info(urb->dev,
1494291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches					 "Unknown key (scancode %#x) released.\n",
1504291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches					 kbd->new[i]);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_sync(kbd->dev);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(kbd->old, kbd->new, 8);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsresubmit:
15954e6ecb23951b195d02433a741c7f7cb0b796c78Christoph Lameter	i = usb_submit_urb (urb, GFP_ATOMIC);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i)
1614291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
1624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			kbd->usbdev->bus->bus_name,
1634291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			kbd->usbdev->devpath, i);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166be5e3383a95446e933be198d3025df10a072794bAdrian Bunkstatic int usb_kbd_event(struct input_dev *dev, unsigned int type,
167be5e3383a95446e933be198d3025df10a072794bAdrian Bunk			 unsigned int code, int value)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
169c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	unsigned long flags;
170e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov	struct usb_kbd *kbd = input_get_drvdata(dev);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (type != EV_LED)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spin_lock_irqsave(&kbd->leds_lock, flags);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (!!test_bit(LED_NUML,    dev->led));
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
180c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	if (kbd->led_urb_submitted){
181c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
183c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	if (*(kbd->leds) == kbd->newleds){
186c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
188c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(kbd->leds) = kbd->newleds;
191c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->led->dev = kbd->usbdev;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
1944291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		pr_err("usb_submit_urb(leds) failed\n");
195c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	else
196c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		kbd->led_urb_submitted = true;
197c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
198c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spin_unlock_irqrestore(&kbd->leds_lock, flags);
199c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2037d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void usb_kbd_led(struct urb *urb)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
205c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	unsigned long flags;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_kbd *kbd = urb->context;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (urb->status)
2094291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_warn(urb->dev, "led urb status %d received\n",
2107d89fe12bd21f1383a6a240114221bf31fd71904Greg Kroah-Hartman			 urb->status);
21105f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov
212c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spin_lock_irqsave(&kbd->leds_lock, flags);
213c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
214c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	if (*(kbd->leds) == kbd->newleds){
215c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		kbd->led_urb_submitted = false;
216c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		spin_unlock_irqrestore(&kbd->leds_lock, flags);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
218c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*(kbd->leds) = kbd->newleds;
221c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->led->dev = kbd->usbdev;
223c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
2244291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
225c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx		kbd->led_urb_submitted = false;
226c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	}
227c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spin_unlock_irqrestore(&kbd->leds_lock, flags);
228c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_kbd_open(struct input_dev *dev)
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
233e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov	struct usb_kbd *kbd = input_get_drvdata(dev);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->irq->dev = kbd->usbdev;
23665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_close(struct input_dev *dev)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
244e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov	struct usb_kbd *kbd = input_get_drvdata(dev);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24665cde54b8b0299d7e46b8705338b01d1e44a5eb0Dmitry Torokhov	usb_kill_urb(kbd->irq);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
255997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2570ede76fcec5415ef82a423a95120286895822e2dAlan Stern	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
259997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2674ba0b2ed583b80cb26b9c8d8a8b418f677ec4a83Mariusz Kozlowski	usb_free_urb(kbd->irq);
2684ba0b2ed583b80cb26b9c8d8a8b418f677ec4a83Mariusz Kozlowski	usb_free_urb(kbd->led);
269997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
2700ede76fcec5415ef82a423a95120286895822e2dAlan Stern	kfree(kbd->cr);
271997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27405f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhovstatic int usb_kbd_probe(struct usb_interface *iface,
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 const struct usb_device_id *id)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
277c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	struct usb_device *dev = interface_to_usbdev(iface);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_host_interface *interface;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_endpoint_descriptor *endpoint;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_kbd *kbd;
281c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	struct input_dev *input_dev;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, pipe, maxp;
2835d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	int error = -ENOMEM;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	interface = iface->cur_altsetting;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (interface->desc.bNumEndpoints != 1)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	endpoint = &interface->endpoint[0].desc;
291a20c314412b9e9e029a73dbb4dd951e36499eb58Luiz Fernando N. Capitulino	if (!usb_endpoint_is_int_in(endpoint))
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
297c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
298c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev = input_allocate_device();
299c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	if (!kbd || !input_dev)
300c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		goto fail1;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	if (usb_kbd_alloc_mem(dev, kbd))
303c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		goto fail2;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->usbdev = dev;
306c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	kbd->dev = input_dev;
307c196adf87514560f867492978ae350d4bbced0bdWillem Penninckx	spin_lock_init(&kbd->leds_lock);
308c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
309c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	if (dev->manufacturer)
310c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
311c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
312c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	if (dev->product) {
313c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		if (dev->manufacturer)
314c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov			strlcat(kbd->name, " ", sizeof(kbd->name));
315c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		strlcat(kbd->name, dev->product, sizeof(kbd->name));
316c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	}
317c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
318c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	if (!strlen(kbd->name))
319c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		snprintf(kbd->name, sizeof(kbd->name),
320c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov			 "USB HIDBP Keyboard %04x:%04x",
321c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov			 le16_to_cpu(dev->descriptor.idVendor),
322c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov			 le16_to_cpu(dev->descriptor.idProduct));
323c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
324c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
3256236dfaa908d9e9c84a8c4d029f443104ed2c47fMárton Németh	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
327c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev->name = kbd->name;
328c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev->phys = kbd->phys;
329c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	usb_to_input_id(dev, &input_dev->id);
330e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov	input_dev->dev.parent = &iface->dev;
331e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov
332e071298589418076ef0a9813677f2d7032b65baaDmitry Torokhov	input_set_drvdata(input_dev, kbd);
333c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
3347b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
3357b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby		BIT_MASK(EV_REP);
3367b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby	input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
3377b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby		BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
3387b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby		BIT_MASK(LED_KANA);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 255; i++)
341c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		set_bit(usb_kbd_keycode[i], input_dev->keybit);
342c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	clear_bit(0, input_dev->keybit);
34305f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov
344c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev->event = usb_kbd_event;
345c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev->open = usb_kbd_open;
346c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	input_dev->close = usb_kbd_close;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_fill_int_urb(kbd->irq, dev, pipe,
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 kbd->new, (maxp > 8 ? 8 : maxp),
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 usb_kbd_irq, kbd, endpoint->bInterval);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->irq->transfer_dma = kbd->new_dma;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->cr->bRequest = 0x09;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->cr->wValue = cpu_to_le16(0x200);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->cr->wLength = cpu_to_le16(1);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     (void *) kbd->cr, kbd->leds, 1,
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     usb_kbd_led, kbd);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd->led->transfer_dma = kbd->leds_dma;
3640ede76fcec5415ef82a423a95120286895822e2dAlan Stern	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3665d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	error = input_register_device(kbd->dev);
3675d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	if (error)
3685d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov		goto fail2;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_set_intfdata(iface, kbd);
3713d61510f4ecacfe47c75c0eb51c0659dfa77fb1bAlan Stern	device_set_wakeup_enable(&dev->dev, 1);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
373c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov
3745d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhovfail2:
3755d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	usb_kbd_free_mem(dev, kbd);
3765d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhovfail1:
3775d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	input_free_device(input_dev);
378c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov	kfree(kbd);
3795d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4Dmitry Torokhov	return error;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_kbd_disconnect(struct usb_interface *intf)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_kbd *kbd = usb_get_intfdata (intf);
38505f091ab4c8c1f12f8dd38ee789489904fea327dDmitry Torokhov
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_set_intfdata(intf, NULL);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kbd) {
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_kill_urb(kbd->irq);
389c5b7c7c395a34f12cdf246d66c1feeff2933d584Dmitry Torokhov		input_unregister_device(kbd->dev);
390a2b2c20ba2f6e22c065f401d63f7f883779cf642Willem Penninckx		usb_kill_urb(kbd->led);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(kbd);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id usb_kbd_id_table [] = {
3974ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
3984ef2e23f03c597e2073b649e7287b840f8fb9274Michael Opdenacker		USB_INTERFACE_PROTOCOL_KEYBOARD) },
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }						/* Terminating entry */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver usb_kbd_driver = {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"usbkbd",
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =	usb_kbd_probe,
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =	usb_kbd_disconnect,
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =	usb_kbd_id_table,
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41142f06a13445bffae96c5e42fdd721ef65fed6abfGreg Kroah-Hartmanmodule_usb_driver(usb_kbd_driver);
412