xref: /linux/drivers/hid/usbhid/usbkbd.c (revision c196adf87514560f867492978ae350d4bbced0bd)
16db3dfefSJiri Kosina /*
26db3dfefSJiri Kosina  *  Copyright (c) 1999-2001 Vojtech Pavlik
36db3dfefSJiri Kosina  *
46db3dfefSJiri Kosina  *  USB HIDBP Keyboard support
56db3dfefSJiri Kosina  */
66db3dfefSJiri Kosina 
76db3dfefSJiri Kosina /*
86db3dfefSJiri Kosina  * This program is free software; you can redistribute it and/or modify
96db3dfefSJiri Kosina  * it under the terms of the GNU General Public License as published by
106db3dfefSJiri Kosina  * the Free Software Foundation; either version 2 of the License, or
116db3dfefSJiri Kosina  * (at your option) any later version.
126db3dfefSJiri Kosina  *
136db3dfefSJiri Kosina  * This program is distributed in the hope that it will be useful,
146db3dfefSJiri Kosina  * but WITHOUT ANY WARRANTY; without even the implied warranty of
156db3dfefSJiri Kosina  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
166db3dfefSJiri Kosina  * GNU General Public License for more details.
176db3dfefSJiri Kosina  *
186db3dfefSJiri Kosina  * You should have received a copy of the GNU General Public License
196db3dfefSJiri Kosina  * along with this program; if not, write to the Free Software
206db3dfefSJiri Kosina  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
216db3dfefSJiri Kosina  *
226db3dfefSJiri Kosina  * Should you need to contact me, the author, you can do so either by
236db3dfefSJiri Kosina  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
246db3dfefSJiri Kosina  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
256db3dfefSJiri Kosina  */
266db3dfefSJiri Kosina 
274291ee30SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
284291ee30SJoe Perches 
296db3dfefSJiri Kosina #include <linux/kernel.h>
306db3dfefSJiri Kosina #include <linux/slab.h>
316db3dfefSJiri Kosina #include <linux/module.h>
326db3dfefSJiri Kosina #include <linux/init.h>
336db3dfefSJiri Kosina #include <linux/usb/input.h>
346db3dfefSJiri Kosina #include <linux/hid.h>
356db3dfefSJiri Kosina 
366db3dfefSJiri Kosina /*
376db3dfefSJiri Kosina  * Version Information
386db3dfefSJiri Kosina  */
396db3dfefSJiri Kosina #define DRIVER_VERSION ""
406db3dfefSJiri Kosina #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
416db3dfefSJiri Kosina #define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
426db3dfefSJiri Kosina #define DRIVER_LICENSE "GPL"
436db3dfefSJiri Kosina 
446db3dfefSJiri Kosina MODULE_AUTHOR(DRIVER_AUTHOR);
456db3dfefSJiri Kosina MODULE_DESCRIPTION(DRIVER_DESC);
466db3dfefSJiri Kosina MODULE_LICENSE(DRIVER_LICENSE);
476db3dfefSJiri Kosina 
48a44ebcceSMing Lei static const unsigned char usb_kbd_keycode[256] = {
496db3dfefSJiri Kosina 	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
506db3dfefSJiri Kosina 	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
516db3dfefSJiri Kosina 	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
526db3dfefSJiri Kosina 	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
536db3dfefSJiri Kosina 	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
546db3dfefSJiri Kosina 	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
556db3dfefSJiri Kosina 	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
566db3dfefSJiri Kosina 	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
576db3dfefSJiri Kosina 	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
586db3dfefSJiri Kosina 	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
596db3dfefSJiri Kosina 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
606db3dfefSJiri Kosina 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
616db3dfefSJiri Kosina 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
626db3dfefSJiri Kosina 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
636db3dfefSJiri Kosina 	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
646db3dfefSJiri Kosina 	150,158,159,128,136,177,178,176,142,152,173,140
656db3dfefSJiri Kosina };
666db3dfefSJiri Kosina 
67*c196adf8SWillem Penninckx 
68*c196adf8SWillem Penninckx /**
69*c196adf8SWillem Penninckx  * struct usb_kbd - state of each attached keyboard
70*c196adf8SWillem Penninckx  * @dev:	input device associated with this keyboard
71*c196adf8SWillem Penninckx  * @usbdev:	usb device associated with this keyboard
72*c196adf8SWillem Penninckx  * @old:	data received in the past from the @irq URB representing which
73*c196adf8SWillem Penninckx  *		keys were pressed. By comparing with the current list of keys
74*c196adf8SWillem Penninckx  *		that are pressed, we are able to see key releases.
75*c196adf8SWillem Penninckx  * @irq:	URB for receiving a list of keys that are pressed when a
76*c196adf8SWillem Penninckx  *		new key is pressed or a key that was pressed is released.
77*c196adf8SWillem Penninckx  * @led:	URB for sending LEDs (e.g. numlock, ...)
78*c196adf8SWillem Penninckx  * @newleds:	data that will be sent with the @led URB representing which LEDs
79*c196adf8SWillem Penninckx  		should be on
80*c196adf8SWillem Penninckx  * @name:	Name of the keyboard. @dev's name field points to this buffer
81*c196adf8SWillem Penninckx  * @phys:	Physical path of the keyboard. @dev's phys field points to this
82*c196adf8SWillem Penninckx  *		buffer
83*c196adf8SWillem Penninckx  * @new:	Buffer for the @irq URB
84*c196adf8SWillem Penninckx  * @cr:		Control request for @led URB
85*c196adf8SWillem Penninckx  * @leds:	Buffer for the @led URB
86*c196adf8SWillem Penninckx  * @new_dma:	DMA address for @irq URB
87*c196adf8SWillem Penninckx  * @leds_dma:	DMA address for @led URB
88*c196adf8SWillem Penninckx  * @leds_lock:	spinlock that protects @leds, @newleds, and @led_urb_submitted
89*c196adf8SWillem Penninckx  * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
90*c196adf8SWillem Penninckx  *		submitted and its completion handler has not returned yet
91*c196adf8SWillem Penninckx  *		without	resubmitting @led
92*c196adf8SWillem Penninckx  */
936db3dfefSJiri Kosina struct usb_kbd {
946db3dfefSJiri Kosina 	struct input_dev *dev;
956db3dfefSJiri Kosina 	struct usb_device *usbdev;
966db3dfefSJiri Kosina 	unsigned char old[8];
976db3dfefSJiri Kosina 	struct urb *irq, *led;
986db3dfefSJiri Kosina 	unsigned char newleds;
996db3dfefSJiri Kosina 	char name[128];
1006db3dfefSJiri Kosina 	char phys[64];
1016db3dfefSJiri Kosina 
1026db3dfefSJiri Kosina 	unsigned char *new;
1036db3dfefSJiri Kosina 	struct usb_ctrlrequest *cr;
1046db3dfefSJiri Kosina 	unsigned char *leds;
1056db3dfefSJiri Kosina 	dma_addr_t new_dma;
1066db3dfefSJiri Kosina 	dma_addr_t leds_dma;
107*c196adf8SWillem Penninckx 
108*c196adf8SWillem Penninckx 	spinlock_t leds_lock;
109*c196adf8SWillem Penninckx 	bool led_urb_submitted;
110*c196adf8SWillem Penninckx 
1116db3dfefSJiri Kosina };
1126db3dfefSJiri Kosina 
1136db3dfefSJiri Kosina static void usb_kbd_irq(struct urb *urb)
1146db3dfefSJiri Kosina {
1156db3dfefSJiri Kosina 	struct usb_kbd *kbd = urb->context;
1166db3dfefSJiri Kosina 	int i;
1176db3dfefSJiri Kosina 
1186db3dfefSJiri Kosina 	switch (urb->status) {
1196db3dfefSJiri Kosina 	case 0:			/* success */
1206db3dfefSJiri Kosina 		break;
1216db3dfefSJiri Kosina 	case -ECONNRESET:	/* unlink */
1226db3dfefSJiri Kosina 	case -ENOENT:
1236db3dfefSJiri Kosina 	case -ESHUTDOWN:
1246db3dfefSJiri Kosina 		return;
1256db3dfefSJiri Kosina 	/* -EPIPE:  should clear the halt */
1266db3dfefSJiri Kosina 	default:		/* error */
1276db3dfefSJiri Kosina 		goto resubmit;
1286db3dfefSJiri Kosina 	}
1296db3dfefSJiri Kosina 
1306db3dfefSJiri Kosina 	for (i = 0; i < 8; i++)
1316db3dfefSJiri Kosina 		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
1326db3dfefSJiri Kosina 
1336db3dfefSJiri Kosina 	for (i = 2; i < 8; i++) {
1346db3dfefSJiri Kosina 
1356db3dfefSJiri Kosina 		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
1366db3dfefSJiri Kosina 			if (usb_kbd_keycode[kbd->old[i]])
1376db3dfefSJiri Kosina 				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
1386db3dfefSJiri Kosina 			else
1394291ee30SJoe Perches 				hid_info(urb->dev,
1404291ee30SJoe Perches 					 "Unknown key (scancode %#x) released.\n",
1414291ee30SJoe Perches 					 kbd->old[i]);
1426db3dfefSJiri Kosina 		}
1436db3dfefSJiri Kosina 
1446db3dfefSJiri Kosina 		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
1456db3dfefSJiri Kosina 			if (usb_kbd_keycode[kbd->new[i]])
1466db3dfefSJiri Kosina 				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
1476db3dfefSJiri Kosina 			else
1484291ee30SJoe Perches 				hid_info(urb->dev,
1494291ee30SJoe Perches 					 "Unknown key (scancode %#x) released.\n",
1504291ee30SJoe Perches 					 kbd->new[i]);
1516db3dfefSJiri Kosina 		}
1526db3dfefSJiri Kosina 	}
1536db3dfefSJiri Kosina 
1546db3dfefSJiri Kosina 	input_sync(kbd->dev);
1556db3dfefSJiri Kosina 
1566db3dfefSJiri Kosina 	memcpy(kbd->old, kbd->new, 8);
1576db3dfefSJiri Kosina 
1586db3dfefSJiri Kosina resubmit:
1596db3dfefSJiri Kosina 	i = usb_submit_urb (urb, GFP_ATOMIC);
1606db3dfefSJiri Kosina 	if (i)
1614291ee30SJoe Perches 		hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
1626db3dfefSJiri Kosina 			kbd->usbdev->bus->bus_name,
1636db3dfefSJiri Kosina 			kbd->usbdev->devpath, i);
1646db3dfefSJiri Kosina }
1656db3dfefSJiri Kosina 
1666db3dfefSJiri Kosina static int usb_kbd_event(struct input_dev *dev, unsigned int type,
1676db3dfefSJiri Kosina 			 unsigned int code, int value)
1686db3dfefSJiri Kosina {
169*c196adf8SWillem Penninckx 	unsigned long flags;
170e0712985SDmitry Torokhov 	struct usb_kbd *kbd = input_get_drvdata(dev);
1716db3dfefSJiri Kosina 
1726db3dfefSJiri Kosina 	if (type != EV_LED)
1736db3dfefSJiri Kosina 		return -1;
1746db3dfefSJiri Kosina 
175*c196adf8SWillem Penninckx 	spin_lock_irqsave(&kbd->leds_lock, flags);
1766db3dfefSJiri Kosina 	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
1776db3dfefSJiri Kosina 		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
1786db3dfefSJiri Kosina 		       (!!test_bit(LED_NUML,    dev->led));
1796db3dfefSJiri Kosina 
180*c196adf8SWillem Penninckx 	if (kbd->led_urb_submitted){
181*c196adf8SWillem Penninckx 		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1826db3dfefSJiri Kosina 		return 0;
183*c196adf8SWillem Penninckx 	}
1846db3dfefSJiri Kosina 
185*c196adf8SWillem Penninckx 	if (*(kbd->leds) == kbd->newleds){
186*c196adf8SWillem Penninckx 		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1876db3dfefSJiri Kosina 		return 0;
188*c196adf8SWillem Penninckx 	}
1896db3dfefSJiri Kosina 
1906db3dfefSJiri Kosina 	*(kbd->leds) = kbd->newleds;
191*c196adf8SWillem Penninckx 
1926db3dfefSJiri Kosina 	kbd->led->dev = kbd->usbdev;
1936db3dfefSJiri Kosina 	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
1944291ee30SJoe Perches 		pr_err("usb_submit_urb(leds) failed\n");
195*c196adf8SWillem Penninckx 	else
196*c196adf8SWillem Penninckx 		kbd->led_urb_submitted = true;
197*c196adf8SWillem Penninckx 
198*c196adf8SWillem Penninckx 	spin_unlock_irqrestore(&kbd->leds_lock, flags);
1996db3dfefSJiri Kosina 
2006db3dfefSJiri Kosina 	return 0;
2016db3dfefSJiri Kosina }
2026db3dfefSJiri Kosina 
2036db3dfefSJiri Kosina static void usb_kbd_led(struct urb *urb)
2046db3dfefSJiri Kosina {
205*c196adf8SWillem Penninckx 	unsigned long flags;
2066db3dfefSJiri Kosina 	struct usb_kbd *kbd = urb->context;
2076db3dfefSJiri Kosina 
2086db3dfefSJiri Kosina 	if (urb->status)
2094291ee30SJoe Perches 		hid_warn(urb->dev, "led urb status %d received\n",
2107d89fe12SFrom: Greg Kroah-Hartman 			 urb->status);
2116db3dfefSJiri Kosina 
212*c196adf8SWillem Penninckx 	spin_lock_irqsave(&kbd->leds_lock, flags);
213*c196adf8SWillem Penninckx 
214*c196adf8SWillem Penninckx 	if (*(kbd->leds) == kbd->newleds){
215*c196adf8SWillem Penninckx 		kbd->led_urb_submitted = false;
216*c196adf8SWillem Penninckx 		spin_unlock_irqrestore(&kbd->leds_lock, flags);
2176db3dfefSJiri Kosina 		return;
218*c196adf8SWillem Penninckx 	}
2196db3dfefSJiri Kosina 
2206db3dfefSJiri Kosina 	*(kbd->leds) = kbd->newleds;
221*c196adf8SWillem Penninckx 
2226db3dfefSJiri Kosina 	kbd->led->dev = kbd->usbdev;
223*c196adf8SWillem Penninckx 	if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
2244291ee30SJoe Perches 		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
225*c196adf8SWillem Penninckx 		kbd->led_urb_submitted = false;
226*c196adf8SWillem Penninckx 	}
227*c196adf8SWillem Penninckx 	spin_unlock_irqrestore(&kbd->leds_lock, flags);
228*c196adf8SWillem Penninckx 
2296db3dfefSJiri Kosina }
2306db3dfefSJiri Kosina 
2316db3dfefSJiri Kosina static int usb_kbd_open(struct input_dev *dev)
2326db3dfefSJiri Kosina {
233e0712985SDmitry Torokhov 	struct usb_kbd *kbd = input_get_drvdata(dev);
2346db3dfefSJiri Kosina 
2356db3dfefSJiri Kosina 	kbd->irq->dev = kbd->usbdev;
2366db3dfefSJiri Kosina 	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
2376db3dfefSJiri Kosina 		return -EIO;
2386db3dfefSJiri Kosina 
2396db3dfefSJiri Kosina 	return 0;
2406db3dfefSJiri Kosina }
2416db3dfefSJiri Kosina 
2426db3dfefSJiri Kosina static void usb_kbd_close(struct input_dev *dev)
2436db3dfefSJiri Kosina {
244e0712985SDmitry Torokhov 	struct usb_kbd *kbd = input_get_drvdata(dev);
2456db3dfefSJiri Kosina 
2466db3dfefSJiri Kosina 	usb_kill_urb(kbd->irq);
2476db3dfefSJiri Kosina }
2486db3dfefSJiri Kosina 
2496db3dfefSJiri Kosina static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
2506db3dfefSJiri Kosina {
2516db3dfefSJiri Kosina 	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
2526db3dfefSJiri Kosina 		return -1;
2536db3dfefSJiri Kosina 	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
2546db3dfefSJiri Kosina 		return -1;
255997ea58eSDaniel Mack 	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
2566db3dfefSJiri Kosina 		return -1;
2570ede76fcSAlan Stern 	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
2586db3dfefSJiri Kosina 		return -1;
259997ea58eSDaniel Mack 	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
2606db3dfefSJiri Kosina 		return -1;
2616db3dfefSJiri Kosina 
2626db3dfefSJiri Kosina 	return 0;
2636db3dfefSJiri Kosina }
2646db3dfefSJiri Kosina 
2656db3dfefSJiri Kosina static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
2666db3dfefSJiri Kosina {
2676db3dfefSJiri Kosina 	usb_free_urb(kbd->irq);
2686db3dfefSJiri Kosina 	usb_free_urb(kbd->led);
269997ea58eSDaniel Mack 	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
2700ede76fcSAlan Stern 	kfree(kbd->cr);
271997ea58eSDaniel Mack 	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
2726db3dfefSJiri Kosina }
2736db3dfefSJiri Kosina 
2746db3dfefSJiri Kosina static int usb_kbd_probe(struct usb_interface *iface,
2756db3dfefSJiri Kosina 			 const struct usb_device_id *id)
2766db3dfefSJiri Kosina {
2776db3dfefSJiri Kosina 	struct usb_device *dev = interface_to_usbdev(iface);
2786db3dfefSJiri Kosina 	struct usb_host_interface *interface;
2796db3dfefSJiri Kosina 	struct usb_endpoint_descriptor *endpoint;
2806db3dfefSJiri Kosina 	struct usb_kbd *kbd;
2816db3dfefSJiri Kosina 	struct input_dev *input_dev;
2826db3dfefSJiri Kosina 	int i, pipe, maxp;
2835d6341c6SDmitry Torokhov 	int error = -ENOMEM;
2846db3dfefSJiri Kosina 
2856db3dfefSJiri Kosina 	interface = iface->cur_altsetting;
2866db3dfefSJiri Kosina 
2876db3dfefSJiri Kosina 	if (interface->desc.bNumEndpoints != 1)
2886db3dfefSJiri Kosina 		return -ENODEV;
2896db3dfefSJiri Kosina 
2906db3dfefSJiri Kosina 	endpoint = &interface->endpoint[0].desc;
2916db3dfefSJiri Kosina 	if (!usb_endpoint_is_int_in(endpoint))
2926db3dfefSJiri Kosina 		return -ENODEV;
2936db3dfefSJiri Kosina 
2946db3dfefSJiri Kosina 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
2956db3dfefSJiri Kosina 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
2966db3dfefSJiri Kosina 
2976db3dfefSJiri Kosina 	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
2986db3dfefSJiri Kosina 	input_dev = input_allocate_device();
2996db3dfefSJiri Kosina 	if (!kbd || !input_dev)
3006db3dfefSJiri Kosina 		goto fail1;
3016db3dfefSJiri Kosina 
3026db3dfefSJiri Kosina 	if (usb_kbd_alloc_mem(dev, kbd))
3036db3dfefSJiri Kosina 		goto fail2;
3046db3dfefSJiri Kosina 
3056db3dfefSJiri Kosina 	kbd->usbdev = dev;
3066db3dfefSJiri Kosina 	kbd->dev = input_dev;
307*c196adf8SWillem Penninckx 	spin_lock_init(&kbd->leds_lock);
3086db3dfefSJiri Kosina 
3096db3dfefSJiri Kosina 	if (dev->manufacturer)
3106db3dfefSJiri Kosina 		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
3116db3dfefSJiri Kosina 
3126db3dfefSJiri Kosina 	if (dev->product) {
3136db3dfefSJiri Kosina 		if (dev->manufacturer)
3146db3dfefSJiri Kosina 			strlcat(kbd->name, " ", sizeof(kbd->name));
3156db3dfefSJiri Kosina 		strlcat(kbd->name, dev->product, sizeof(kbd->name));
3166db3dfefSJiri Kosina 	}
3176db3dfefSJiri Kosina 
3186db3dfefSJiri Kosina 	if (!strlen(kbd->name))
3196db3dfefSJiri Kosina 		snprintf(kbd->name, sizeof(kbd->name),
3206db3dfefSJiri Kosina 			 "USB HIDBP Keyboard %04x:%04x",
3216db3dfefSJiri Kosina 			 le16_to_cpu(dev->descriptor.idVendor),
3226db3dfefSJiri Kosina 			 le16_to_cpu(dev->descriptor.idProduct));
3236db3dfefSJiri Kosina 
3246db3dfefSJiri Kosina 	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
3256236dfaaSMárton Németh 	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
3266db3dfefSJiri Kosina 
3276db3dfefSJiri Kosina 	input_dev->name = kbd->name;
3286db3dfefSJiri Kosina 	input_dev->phys = kbd->phys;
3296db3dfefSJiri Kosina 	usb_to_input_id(dev, &input_dev->id);
330e0712985SDmitry Torokhov 	input_dev->dev.parent = &iface->dev;
331e0712985SDmitry Torokhov 
332e0712985SDmitry Torokhov 	input_set_drvdata(input_dev, kbd);
3336db3dfefSJiri Kosina 
3347b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
3357b19ada2SJiri Slaby 		BIT_MASK(EV_REP);
3367b19ada2SJiri Slaby 	input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
3377b19ada2SJiri Slaby 		BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
3387b19ada2SJiri Slaby 		BIT_MASK(LED_KANA);
3396db3dfefSJiri Kosina 
3406db3dfefSJiri Kosina 	for (i = 0; i < 255; i++)
3416db3dfefSJiri Kosina 		set_bit(usb_kbd_keycode[i], input_dev->keybit);
3426db3dfefSJiri Kosina 	clear_bit(0, input_dev->keybit);
3436db3dfefSJiri Kosina 
3446db3dfefSJiri Kosina 	input_dev->event = usb_kbd_event;
3456db3dfefSJiri Kosina 	input_dev->open = usb_kbd_open;
3466db3dfefSJiri Kosina 	input_dev->close = usb_kbd_close;
3476db3dfefSJiri Kosina 
3486db3dfefSJiri Kosina 	usb_fill_int_urb(kbd->irq, dev, pipe,
3496db3dfefSJiri Kosina 			 kbd->new, (maxp > 8 ? 8 : maxp),
3506db3dfefSJiri Kosina 			 usb_kbd_irq, kbd, endpoint->bInterval);
3516db3dfefSJiri Kosina 	kbd->irq->transfer_dma = kbd->new_dma;
3526db3dfefSJiri Kosina 	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3536db3dfefSJiri Kosina 
3546db3dfefSJiri Kosina 	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
3556db3dfefSJiri Kosina 	kbd->cr->bRequest = 0x09;
3566db3dfefSJiri Kosina 	kbd->cr->wValue = cpu_to_le16(0x200);
3576db3dfefSJiri Kosina 	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
3586db3dfefSJiri Kosina 	kbd->cr->wLength = cpu_to_le16(1);
3596db3dfefSJiri Kosina 
3606db3dfefSJiri Kosina 	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
3616db3dfefSJiri Kosina 			     (void *) kbd->cr, kbd->leds, 1,
3626db3dfefSJiri Kosina 			     usb_kbd_led, kbd);
3636db3dfefSJiri Kosina 	kbd->led->transfer_dma = kbd->leds_dma;
3640ede76fcSAlan Stern 	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3656db3dfefSJiri Kosina 
3665d6341c6SDmitry Torokhov 	error = input_register_device(kbd->dev);
3675d6341c6SDmitry Torokhov 	if (error)
3685d6341c6SDmitry Torokhov 		goto fail2;
3696db3dfefSJiri Kosina 
3706db3dfefSJiri Kosina 	usb_set_intfdata(iface, kbd);
3713d61510fSAlan Stern 	device_set_wakeup_enable(&dev->dev, 1);
3726db3dfefSJiri Kosina 	return 0;
3736db3dfefSJiri Kosina 
3745d6341c6SDmitry Torokhov fail2:
3755d6341c6SDmitry Torokhov 	usb_kbd_free_mem(dev, kbd);
3765d6341c6SDmitry Torokhov fail1:
3775d6341c6SDmitry Torokhov 	input_free_device(input_dev);
3786db3dfefSJiri Kosina 	kfree(kbd);
3795d6341c6SDmitry Torokhov 	return error;
3806db3dfefSJiri Kosina }
3816db3dfefSJiri Kosina 
3826db3dfefSJiri Kosina static void usb_kbd_disconnect(struct usb_interface *intf)
3836db3dfefSJiri Kosina {
3846db3dfefSJiri Kosina 	struct usb_kbd *kbd = usb_get_intfdata (intf);
3856db3dfefSJiri Kosina 
3866db3dfefSJiri Kosina 	usb_set_intfdata(intf, NULL);
3876db3dfefSJiri Kosina 	if (kbd) {
3886db3dfefSJiri Kosina 		usb_kill_urb(kbd->irq);
3896db3dfefSJiri Kosina 		input_unregister_device(kbd->dev);
3906db3dfefSJiri Kosina 		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
3916db3dfefSJiri Kosina 		kfree(kbd);
3926db3dfefSJiri Kosina 	}
3936db3dfefSJiri Kosina }
3946db3dfefSJiri Kosina 
3956db3dfefSJiri Kosina static struct usb_device_id usb_kbd_id_table [] = {
3966db3dfefSJiri Kosina 	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
3976db3dfefSJiri Kosina 		USB_INTERFACE_PROTOCOL_KEYBOARD) },
3986db3dfefSJiri Kosina 	{ }						/* Terminating entry */
3996db3dfefSJiri Kosina };
4006db3dfefSJiri Kosina 
4016db3dfefSJiri Kosina MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
4026db3dfefSJiri Kosina 
4036db3dfefSJiri Kosina static struct usb_driver usb_kbd_driver = {
4046db3dfefSJiri Kosina 	.name =		"usbkbd",
4056db3dfefSJiri Kosina 	.probe =	usb_kbd_probe,
4066db3dfefSJiri Kosina 	.disconnect =	usb_kbd_disconnect,
4076db3dfefSJiri Kosina 	.id_table =	usb_kbd_id_table,
4086db3dfefSJiri Kosina };
4096db3dfefSJiri Kosina 
4106db3dfefSJiri Kosina static int __init usb_kbd_init(void)
4116db3dfefSJiri Kosina {
4126db3dfefSJiri Kosina 	int result = usb_register(&usb_kbd_driver);
4136db3dfefSJiri Kosina 	if (result == 0)
414ddbe3249SGreg Kroah-Hartman 		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
415ddbe3249SGreg Kroah-Hartman 				DRIVER_DESC "\n");
4166db3dfefSJiri Kosina 	return result;
4176db3dfefSJiri Kosina }
4186db3dfefSJiri Kosina 
4196db3dfefSJiri Kosina static void __exit usb_kbd_exit(void)
4206db3dfefSJiri Kosina {
4216db3dfefSJiri Kosina 	usb_deregister(&usb_kbd_driver);
4226db3dfefSJiri Kosina }
4236db3dfefSJiri Kosina 
4246db3dfefSJiri Kosina module_init(usb_kbd_init);
4256db3dfefSJiri Kosina module_exit(usb_kbd_exit);
426