18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) 1999-2001 Vojtech Pavlik
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  USB HIDBP Keyboard support
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Should you need to contact me, the author, you can do so either by
118c2ecf20Sopenharmony_ci * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
128c2ecf20Sopenharmony_ci * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/init.h>
218c2ecf20Sopenharmony_ci#include <linux/usb/input.h>
228c2ecf20Sopenharmony_ci#include <linux/hid.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * Version Information
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci#define DRIVER_VERSION ""
288c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
298c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const unsigned char usb_kbd_keycode[256] = {
368c2ecf20Sopenharmony_ci	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
378c2ecf20Sopenharmony_ci	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
388c2ecf20Sopenharmony_ci	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
398c2ecf20Sopenharmony_ci	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
408c2ecf20Sopenharmony_ci	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
418c2ecf20Sopenharmony_ci	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
428c2ecf20Sopenharmony_ci	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
438c2ecf20Sopenharmony_ci	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
448c2ecf20Sopenharmony_ci	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
458c2ecf20Sopenharmony_ci	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
468c2ecf20Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
478c2ecf20Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
488c2ecf20Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
498c2ecf20Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
508c2ecf20Sopenharmony_ci	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
518c2ecf20Sopenharmony_ci	150,158,159,128,136,177,178,176,142,152,173,140
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/**
568c2ecf20Sopenharmony_ci * struct usb_kbd - state of each attached keyboard
578c2ecf20Sopenharmony_ci * @dev:	input device associated with this keyboard
588c2ecf20Sopenharmony_ci * @usbdev:	usb device associated with this keyboard
598c2ecf20Sopenharmony_ci * @old:	data received in the past from the @irq URB representing which
608c2ecf20Sopenharmony_ci *		keys were pressed. By comparing with the current list of keys
618c2ecf20Sopenharmony_ci *		that are pressed, we are able to see key releases.
628c2ecf20Sopenharmony_ci * @irq:	URB for receiving a list of keys that are pressed when a
638c2ecf20Sopenharmony_ci *		new key is pressed or a key that was pressed is released.
648c2ecf20Sopenharmony_ci * @led:	URB for sending LEDs (e.g. numlock, ...)
658c2ecf20Sopenharmony_ci * @newleds:	data that will be sent with the @led URB representing which LEDs
668c2ecf20Sopenharmony_ci 		should be on
678c2ecf20Sopenharmony_ci * @name:	Name of the keyboard. @dev's name field points to this buffer
688c2ecf20Sopenharmony_ci * @phys:	Physical path of the keyboard. @dev's phys field points to this
698c2ecf20Sopenharmony_ci *		buffer
708c2ecf20Sopenharmony_ci * @new:	Buffer for the @irq URB
718c2ecf20Sopenharmony_ci * @cr:		Control request for @led URB
728c2ecf20Sopenharmony_ci * @leds:	Buffer for the @led URB
738c2ecf20Sopenharmony_ci * @new_dma:	DMA address for @irq URB
748c2ecf20Sopenharmony_ci * @leds_dma:	DMA address for @led URB
758c2ecf20Sopenharmony_ci * @leds_lock:	spinlock that protects @leds, @newleds, and @led_urb_submitted
768c2ecf20Sopenharmony_ci * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
778c2ecf20Sopenharmony_ci *		submitted and its completion handler has not returned yet
788c2ecf20Sopenharmony_ci *		without	resubmitting @led
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_cistruct usb_kbd {
818c2ecf20Sopenharmony_ci	struct input_dev *dev;
828c2ecf20Sopenharmony_ci	struct usb_device *usbdev;
838c2ecf20Sopenharmony_ci	unsigned char old[8];
848c2ecf20Sopenharmony_ci	struct urb *irq, *led;
858c2ecf20Sopenharmony_ci	unsigned char newleds;
868c2ecf20Sopenharmony_ci	char name[128];
878c2ecf20Sopenharmony_ci	char phys[64];
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	unsigned char *new;
908c2ecf20Sopenharmony_ci	struct usb_ctrlrequest *cr;
918c2ecf20Sopenharmony_ci	unsigned char *leds;
928c2ecf20Sopenharmony_ci	dma_addr_t new_dma;
938c2ecf20Sopenharmony_ci	dma_addr_t leds_dma;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	spinlock_t leds_lock;
968c2ecf20Sopenharmony_ci	bool led_urb_submitted;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void usb_kbd_irq(struct urb *urb)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = urb->context;
1038c2ecf20Sopenharmony_ci	int i;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	switch (urb->status) {
1068c2ecf20Sopenharmony_ci	case 0:			/* success */
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci	case -ECONNRESET:	/* unlink */
1098c2ecf20Sopenharmony_ci	case -ENOENT:
1108c2ecf20Sopenharmony_ci	case -ESHUTDOWN:
1118c2ecf20Sopenharmony_ci		return;
1128c2ecf20Sopenharmony_ci	/* -EPIPE:  should clear the halt */
1138c2ecf20Sopenharmony_ci	default:		/* error */
1148c2ecf20Sopenharmony_ci		goto resubmit;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++)
1188c2ecf20Sopenharmony_ci		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	for (i = 2; i < 8; i++) {
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
1238c2ecf20Sopenharmony_ci			if (usb_kbd_keycode[kbd->old[i]])
1248c2ecf20Sopenharmony_ci				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
1258c2ecf20Sopenharmony_ci			else
1268c2ecf20Sopenharmony_ci				hid_info(urb->dev,
1278c2ecf20Sopenharmony_ci					 "Unknown key (scancode %#x) released.\n",
1288c2ecf20Sopenharmony_ci					 kbd->old[i]);
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
1328c2ecf20Sopenharmony_ci			if (usb_kbd_keycode[kbd->new[i]])
1338c2ecf20Sopenharmony_ci				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
1348c2ecf20Sopenharmony_ci			else
1358c2ecf20Sopenharmony_ci				hid_info(urb->dev,
1368c2ecf20Sopenharmony_ci					 "Unknown key (scancode %#x) pressed.\n",
1378c2ecf20Sopenharmony_ci					 kbd->new[i]);
1388c2ecf20Sopenharmony_ci		}
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	input_sync(kbd->dev);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	memcpy(kbd->old, kbd->new, 8);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciresubmit:
1468c2ecf20Sopenharmony_ci	i = usb_submit_urb (urb, GFP_ATOMIC);
1478c2ecf20Sopenharmony_ci	if (i)
1488c2ecf20Sopenharmony_ci		hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
1498c2ecf20Sopenharmony_ci			kbd->usbdev->bus->bus_name,
1508c2ecf20Sopenharmony_ci			kbd->usbdev->devpath, i);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int usb_kbd_event(struct input_dev *dev, unsigned int type,
1548c2ecf20Sopenharmony_ci			 unsigned int code, int value)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	unsigned long flags;
1578c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (type != EV_LED)
1608c2ecf20Sopenharmony_ci		return -1;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&kbd->leds_lock, flags);
1638c2ecf20Sopenharmony_ci	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
1648c2ecf20Sopenharmony_ci		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
1658c2ecf20Sopenharmony_ci		       (!!test_bit(LED_NUML,    dev->led));
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (kbd->led_urb_submitted){
1688c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1698c2ecf20Sopenharmony_ci		return 0;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (*(kbd->leds) == kbd->newleds){
1738c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
1748c2ecf20Sopenharmony_ci		return 0;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	*(kbd->leds) = kbd->newleds;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	kbd->led->dev = kbd->usbdev;
1808c2ecf20Sopenharmony_ci	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
1818c2ecf20Sopenharmony_ci		pr_err("usb_submit_urb(leds) failed\n");
1828c2ecf20Sopenharmony_ci	else
1838c2ecf20Sopenharmony_ci		kbd->led_urb_submitted = true;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&kbd->leds_lock, flags);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return 0;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic void usb_kbd_led(struct urb *urb)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	unsigned long flags;
1938c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = urb->context;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (urb->status)
1968c2ecf20Sopenharmony_ci		hid_warn(urb->dev, "led urb status %d received\n",
1978c2ecf20Sopenharmony_ci			 urb->status);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	spin_lock_irqsave(&kbd->leds_lock, flags);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (*(kbd->leds) == kbd->newleds){
2028c2ecf20Sopenharmony_ci		kbd->led_urb_submitted = false;
2038c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
2048c2ecf20Sopenharmony_ci		return;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	*(kbd->leds) = kbd->newleds;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	kbd->led->dev = kbd->usbdev;
2108c2ecf20Sopenharmony_ci	if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
2118c2ecf20Sopenharmony_ci		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
2128c2ecf20Sopenharmony_ci		kbd->led_urb_submitted = false;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&kbd->leds_lock, flags);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int usb_kbd_open(struct input_dev *dev)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	kbd->irq->dev = kbd->usbdev;
2238c2ecf20Sopenharmony_ci	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
2248c2ecf20Sopenharmony_ci		return -EIO;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void usb_kbd_close(struct input_dev *dev)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	usb_kill_urb(kbd->irq);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
2398c2ecf20Sopenharmony_ci		return -1;
2408c2ecf20Sopenharmony_ci	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
2418c2ecf20Sopenharmony_ci		return -1;
2428c2ecf20Sopenharmony_ci	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
2438c2ecf20Sopenharmony_ci		return -1;
2448c2ecf20Sopenharmony_ci	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
2458c2ecf20Sopenharmony_ci		return -1;
2468c2ecf20Sopenharmony_ci	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
2478c2ecf20Sopenharmony_ci		return -1;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	usb_free_urb(kbd->irq);
2558c2ecf20Sopenharmony_ci	usb_free_urb(kbd->led);
2568c2ecf20Sopenharmony_ci	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
2578c2ecf20Sopenharmony_ci	kfree(kbd->cr);
2588c2ecf20Sopenharmony_ci	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int usb_kbd_probe(struct usb_interface *iface,
2628c2ecf20Sopenharmony_ci			 const struct usb_device_id *id)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(iface);
2658c2ecf20Sopenharmony_ci	struct usb_host_interface *interface;
2668c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *endpoint;
2678c2ecf20Sopenharmony_ci	struct usb_kbd *kbd;
2688c2ecf20Sopenharmony_ci	struct input_dev *input_dev;
2698c2ecf20Sopenharmony_ci	int i, pipe, maxp;
2708c2ecf20Sopenharmony_ci	int error = -ENOMEM;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	interface = iface->cur_altsetting;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (interface->desc.bNumEndpoints != 1)
2758c2ecf20Sopenharmony_ci		return -ENODEV;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	endpoint = &interface->endpoint[0].desc;
2788c2ecf20Sopenharmony_ci	if (!usb_endpoint_is_int_in(endpoint))
2798c2ecf20Sopenharmony_ci		return -ENODEV;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
2828c2ecf20Sopenharmony_ci	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
2858c2ecf20Sopenharmony_ci	input_dev = input_allocate_device();
2868c2ecf20Sopenharmony_ci	if (!kbd || !input_dev)
2878c2ecf20Sopenharmony_ci		goto fail1;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (usb_kbd_alloc_mem(dev, kbd))
2908c2ecf20Sopenharmony_ci		goto fail2;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	kbd->usbdev = dev;
2938c2ecf20Sopenharmony_ci	kbd->dev = input_dev;
2948c2ecf20Sopenharmony_ci	spin_lock_init(&kbd->leds_lock);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (dev->manufacturer)
2978c2ecf20Sopenharmony_ci		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (dev->product) {
3008c2ecf20Sopenharmony_ci		if (dev->manufacturer)
3018c2ecf20Sopenharmony_ci			strlcat(kbd->name, " ", sizeof(kbd->name));
3028c2ecf20Sopenharmony_ci		strlcat(kbd->name, dev->product, sizeof(kbd->name));
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (!strlen(kbd->name))
3068c2ecf20Sopenharmony_ci		snprintf(kbd->name, sizeof(kbd->name),
3078c2ecf20Sopenharmony_ci			 "USB HIDBP Keyboard %04x:%04x",
3088c2ecf20Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idVendor),
3098c2ecf20Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idProduct));
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
3128c2ecf20Sopenharmony_ci	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	input_dev->name = kbd->name;
3158c2ecf20Sopenharmony_ci	input_dev->phys = kbd->phys;
3168c2ecf20Sopenharmony_ci	usb_to_input_id(dev, &input_dev->id);
3178c2ecf20Sopenharmony_ci	input_dev->dev.parent = &iface->dev;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	input_set_drvdata(input_dev, kbd);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
3228c2ecf20Sopenharmony_ci		BIT_MASK(EV_REP);
3238c2ecf20Sopenharmony_ci	input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
3248c2ecf20Sopenharmony_ci		BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
3258c2ecf20Sopenharmony_ci		BIT_MASK(LED_KANA);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	for (i = 0; i < 255; i++)
3288c2ecf20Sopenharmony_ci		set_bit(usb_kbd_keycode[i], input_dev->keybit);
3298c2ecf20Sopenharmony_ci	clear_bit(0, input_dev->keybit);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	input_dev->event = usb_kbd_event;
3328c2ecf20Sopenharmony_ci	input_dev->open = usb_kbd_open;
3338c2ecf20Sopenharmony_ci	input_dev->close = usb_kbd_close;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	usb_fill_int_urb(kbd->irq, dev, pipe,
3368c2ecf20Sopenharmony_ci			 kbd->new, (maxp > 8 ? 8 : maxp),
3378c2ecf20Sopenharmony_ci			 usb_kbd_irq, kbd, endpoint->bInterval);
3388c2ecf20Sopenharmony_ci	kbd->irq->transfer_dma = kbd->new_dma;
3398c2ecf20Sopenharmony_ci	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
3428c2ecf20Sopenharmony_ci	kbd->cr->bRequest = 0x09;
3438c2ecf20Sopenharmony_ci	kbd->cr->wValue = cpu_to_le16(0x200);
3448c2ecf20Sopenharmony_ci	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
3458c2ecf20Sopenharmony_ci	kbd->cr->wLength = cpu_to_le16(1);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
3488c2ecf20Sopenharmony_ci			     (void *) kbd->cr, kbd->leds, 1,
3498c2ecf20Sopenharmony_ci			     usb_kbd_led, kbd);
3508c2ecf20Sopenharmony_ci	kbd->led->transfer_dma = kbd->leds_dma;
3518c2ecf20Sopenharmony_ci	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	error = input_register_device(kbd->dev);
3548c2ecf20Sopenharmony_ci	if (error)
3558c2ecf20Sopenharmony_ci		goto fail2;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	usb_set_intfdata(iface, kbd);
3588c2ecf20Sopenharmony_ci	device_set_wakeup_enable(&dev->dev, 1);
3598c2ecf20Sopenharmony_ci	return 0;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cifail2:
3628c2ecf20Sopenharmony_ci	usb_kbd_free_mem(dev, kbd);
3638c2ecf20Sopenharmony_cifail1:
3648c2ecf20Sopenharmony_ci	input_free_device(input_dev);
3658c2ecf20Sopenharmony_ci	kfree(kbd);
3668c2ecf20Sopenharmony_ci	return error;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void usb_kbd_disconnect(struct usb_interface *intf)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct usb_kbd *kbd = usb_get_intfdata (intf);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, NULL);
3748c2ecf20Sopenharmony_ci	if (kbd) {
3758c2ecf20Sopenharmony_ci		usb_kill_urb(kbd->irq);
3768c2ecf20Sopenharmony_ci		input_unregister_device(kbd->dev);
3778c2ecf20Sopenharmony_ci		usb_kill_urb(kbd->led);
3788c2ecf20Sopenharmony_ci		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
3798c2ecf20Sopenharmony_ci		kfree(kbd);
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic const struct usb_device_id usb_kbd_id_table[] = {
3848c2ecf20Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
3858c2ecf20Sopenharmony_ci		USB_INTERFACE_PROTOCOL_KEYBOARD) },
3868c2ecf20Sopenharmony_ci	{ }						/* Terminating entry */
3878c2ecf20Sopenharmony_ci};
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic struct usb_driver usb_kbd_driver = {
3928c2ecf20Sopenharmony_ci	.name =		"usbkbd",
3938c2ecf20Sopenharmony_ci	.probe =	usb_kbd_probe,
3948c2ecf20Sopenharmony_ci	.disconnect =	usb_kbd_disconnect,
3958c2ecf20Sopenharmony_ci	.id_table =	usb_kbd_id_table,
3968c2ecf20Sopenharmony_ci};
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cimodule_usb_driver(usb_kbd_driver);
399