162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) 1999-2001 Vojtech Pavlik
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  USB HIDBP Keyboard support
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Should you need to contact me, the author, you can do so either by
1162306a36Sopenharmony_ci * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
1262306a36Sopenharmony_ci * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/init.h>
2162306a36Sopenharmony_ci#include <linux/usb/input.h>
2262306a36Sopenharmony_ci#include <linux/hid.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * Version Information
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#define DRIVER_VERSION ""
2862306a36Sopenharmony_ci#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
2962306a36Sopenharmony_ci#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
3262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
3362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const unsigned char usb_kbd_keycode[256] = {
3662306a36Sopenharmony_ci	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
3762306a36Sopenharmony_ci	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
3862306a36Sopenharmony_ci	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
3962306a36Sopenharmony_ci	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
4062306a36Sopenharmony_ci	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
4162306a36Sopenharmony_ci	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
4262306a36Sopenharmony_ci	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
4362306a36Sopenharmony_ci	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
4462306a36Sopenharmony_ci	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
4562306a36Sopenharmony_ci	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4662306a36Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4762306a36Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4862306a36Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4962306a36Sopenharmony_ci	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
5062306a36Sopenharmony_ci	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
5162306a36Sopenharmony_ci	150,158,159,128,136,177,178,176,142,152,173,140
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/**
5662306a36Sopenharmony_ci * struct usb_kbd - state of each attached keyboard
5762306a36Sopenharmony_ci * @dev:	input device associated with this keyboard
5862306a36Sopenharmony_ci * @usbdev:	usb device associated with this keyboard
5962306a36Sopenharmony_ci * @old:	data received in the past from the @irq URB representing which
6062306a36Sopenharmony_ci *		keys were pressed. By comparing with the current list of keys
6162306a36Sopenharmony_ci *		that are pressed, we are able to see key releases.
6262306a36Sopenharmony_ci * @irq:	URB for receiving a list of keys that are pressed when a
6362306a36Sopenharmony_ci *		new key is pressed or a key that was pressed is released.
6462306a36Sopenharmony_ci * @led:	URB for sending LEDs (e.g. numlock, ...)
6562306a36Sopenharmony_ci * @newleds:	data that will be sent with the @led URB representing which LEDs
6662306a36Sopenharmony_ci *		should be on
6762306a36Sopenharmony_ci * @name:	Name of the keyboard. @dev's name field points to this buffer
6862306a36Sopenharmony_ci * @phys:	Physical path of the keyboard. @dev's phys field points to this
6962306a36Sopenharmony_ci *		buffer
7062306a36Sopenharmony_ci * @new:	Buffer for the @irq URB
7162306a36Sopenharmony_ci * @cr:		Control request for @led URB
7262306a36Sopenharmony_ci * @leds:	Buffer for the @led URB
7362306a36Sopenharmony_ci * @new_dma:	DMA address for @irq URB
7462306a36Sopenharmony_ci * @leds_dma:	DMA address for @led URB
7562306a36Sopenharmony_ci * @leds_lock:	spinlock that protects @leds, @newleds, and @led_urb_submitted
7662306a36Sopenharmony_ci * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
7762306a36Sopenharmony_ci *		submitted and its completion handler has not returned yet
7862306a36Sopenharmony_ci *		without	resubmitting @led
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistruct usb_kbd {
8162306a36Sopenharmony_ci	struct input_dev *dev;
8262306a36Sopenharmony_ci	struct usb_device *usbdev;
8362306a36Sopenharmony_ci	unsigned char old[8];
8462306a36Sopenharmony_ci	struct urb *irq, *led;
8562306a36Sopenharmony_ci	unsigned char newleds;
8662306a36Sopenharmony_ci	char name[128];
8762306a36Sopenharmony_ci	char phys[64];
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	unsigned char *new;
9062306a36Sopenharmony_ci	struct usb_ctrlrequest *cr;
9162306a36Sopenharmony_ci	unsigned char *leds;
9262306a36Sopenharmony_ci	dma_addr_t new_dma;
9362306a36Sopenharmony_ci	dma_addr_t leds_dma;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	spinlock_t leds_lock;
9662306a36Sopenharmony_ci	bool led_urb_submitted;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void usb_kbd_irq(struct urb *urb)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct usb_kbd *kbd = urb->context;
10362306a36Sopenharmony_ci	int i;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	switch (urb->status) {
10662306a36Sopenharmony_ci	case 0:			/* success */
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case -ECONNRESET:	/* unlink */
10962306a36Sopenharmony_ci	case -ENOENT:
11062306a36Sopenharmony_ci	case -ESHUTDOWN:
11162306a36Sopenharmony_ci		return;
11262306a36Sopenharmony_ci	/* -EPIPE:  should clear the halt */
11362306a36Sopenharmony_ci	default:		/* error */
11462306a36Sopenharmony_ci		goto resubmit;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
11862306a36Sopenharmony_ci		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	for (i = 2; i < 8; i++) {
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
12362306a36Sopenharmony_ci			if (usb_kbd_keycode[kbd->old[i]])
12462306a36Sopenharmony_ci				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
12562306a36Sopenharmony_ci			else
12662306a36Sopenharmony_ci				hid_info(urb->dev,
12762306a36Sopenharmony_ci					 "Unknown key (scancode %#x) released.\n",
12862306a36Sopenharmony_ci					 kbd->old[i]);
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
13262306a36Sopenharmony_ci			if (usb_kbd_keycode[kbd->new[i]])
13362306a36Sopenharmony_ci				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
13462306a36Sopenharmony_ci			else
13562306a36Sopenharmony_ci				hid_info(urb->dev,
13662306a36Sopenharmony_ci					 "Unknown key (scancode %#x) pressed.\n",
13762306a36Sopenharmony_ci					 kbd->new[i]);
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	input_sync(kbd->dev);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	memcpy(kbd->old, kbd->new, 8);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciresubmit:
14662306a36Sopenharmony_ci	i = usb_submit_urb (urb, GFP_ATOMIC);
14762306a36Sopenharmony_ci	if (i)
14862306a36Sopenharmony_ci		hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
14962306a36Sopenharmony_ci			kbd->usbdev->bus->bus_name,
15062306a36Sopenharmony_ci			kbd->usbdev->devpath, i);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int usb_kbd_event(struct input_dev *dev, unsigned int type,
15462306a36Sopenharmony_ci			 unsigned int code, int value)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	unsigned long flags;
15762306a36Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (type != EV_LED)
16062306a36Sopenharmony_ci		return -1;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	spin_lock_irqsave(&kbd->leds_lock, flags);
16362306a36Sopenharmony_ci	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
16462306a36Sopenharmony_ci		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
16562306a36Sopenharmony_ci		       (!!test_bit(LED_NUML,    dev->led));
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (kbd->led_urb_submitted){
16862306a36Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
16962306a36Sopenharmony_ci		return 0;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (*(kbd->leds) == kbd->newleds){
17362306a36Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
17462306a36Sopenharmony_ci		return 0;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	*(kbd->leds) = kbd->newleds;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	kbd->led->dev = kbd->usbdev;
18062306a36Sopenharmony_ci	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
18162306a36Sopenharmony_ci		pr_err("usb_submit_urb(leds) failed\n");
18262306a36Sopenharmony_ci	else
18362306a36Sopenharmony_ci		kbd->led_urb_submitted = true;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	spin_unlock_irqrestore(&kbd->leds_lock, flags);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return 0;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic void usb_kbd_led(struct urb *urb)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	unsigned long flags;
19362306a36Sopenharmony_ci	struct usb_kbd *kbd = urb->context;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (urb->status)
19662306a36Sopenharmony_ci		hid_warn(urb->dev, "led urb status %d received\n",
19762306a36Sopenharmony_ci			 urb->status);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	spin_lock_irqsave(&kbd->leds_lock, flags);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (*(kbd->leds) == kbd->newleds){
20262306a36Sopenharmony_ci		kbd->led_urb_submitted = false;
20362306a36Sopenharmony_ci		spin_unlock_irqrestore(&kbd->leds_lock, flags);
20462306a36Sopenharmony_ci		return;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	*(kbd->leds) = kbd->newleds;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	kbd->led->dev = kbd->usbdev;
21062306a36Sopenharmony_ci	if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
21162306a36Sopenharmony_ci		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
21262306a36Sopenharmony_ci		kbd->led_urb_submitted = false;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	spin_unlock_irqrestore(&kbd->leds_lock, flags);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int usb_kbd_open(struct input_dev *dev)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	kbd->irq->dev = kbd->usbdev;
22362306a36Sopenharmony_ci	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
22462306a36Sopenharmony_ci		return -EIO;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void usb_kbd_close(struct input_dev *dev)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct usb_kbd *kbd = input_get_drvdata(dev);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	usb_kill_urb(kbd->irq);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
23962306a36Sopenharmony_ci		return -1;
24062306a36Sopenharmony_ci	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
24162306a36Sopenharmony_ci		return -1;
24262306a36Sopenharmony_ci	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbd->new_dma)))
24362306a36Sopenharmony_ci		return -1;
24462306a36Sopenharmony_ci	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
24562306a36Sopenharmony_ci		return -1;
24662306a36Sopenharmony_ci	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_KERNEL, &kbd->leds_dma)))
24762306a36Sopenharmony_ci		return -1;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	usb_free_urb(kbd->irq);
25562306a36Sopenharmony_ci	usb_free_urb(kbd->led);
25662306a36Sopenharmony_ci	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
25762306a36Sopenharmony_ci	kfree(kbd->cr);
25862306a36Sopenharmony_ci	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int usb_kbd_probe(struct usb_interface *iface,
26262306a36Sopenharmony_ci			 const struct usb_device_id *id)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct usb_device *dev = interface_to_usbdev(iface);
26562306a36Sopenharmony_ci	struct usb_host_interface *interface;
26662306a36Sopenharmony_ci	struct usb_endpoint_descriptor *endpoint;
26762306a36Sopenharmony_ci	struct usb_kbd *kbd;
26862306a36Sopenharmony_ci	struct input_dev *input_dev;
26962306a36Sopenharmony_ci	int i, pipe, maxp;
27062306a36Sopenharmony_ci	int error = -ENOMEM;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	interface = iface->cur_altsetting;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (interface->desc.bNumEndpoints != 1)
27562306a36Sopenharmony_ci		return -ENODEV;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	endpoint = &interface->endpoint[0].desc;
27862306a36Sopenharmony_ci	if (!usb_endpoint_is_int_in(endpoint))
27962306a36Sopenharmony_ci		return -ENODEV;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
28262306a36Sopenharmony_ci	maxp = usb_maxpacket(dev, pipe);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
28562306a36Sopenharmony_ci	input_dev = input_allocate_device();
28662306a36Sopenharmony_ci	if (!kbd || !input_dev)
28762306a36Sopenharmony_ci		goto fail1;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (usb_kbd_alloc_mem(dev, kbd))
29062306a36Sopenharmony_ci		goto fail2;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	kbd->usbdev = dev;
29362306a36Sopenharmony_ci	kbd->dev = input_dev;
29462306a36Sopenharmony_ci	spin_lock_init(&kbd->leds_lock);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (dev->manufacturer)
29762306a36Sopenharmony_ci		strscpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (dev->product) {
30062306a36Sopenharmony_ci		if (dev->manufacturer)
30162306a36Sopenharmony_ci			strlcat(kbd->name, " ", sizeof(kbd->name));
30262306a36Sopenharmony_ci		strlcat(kbd->name, dev->product, sizeof(kbd->name));
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (!strlen(kbd->name))
30662306a36Sopenharmony_ci		snprintf(kbd->name, sizeof(kbd->name),
30762306a36Sopenharmony_ci			 "USB HIDBP Keyboard %04x:%04x",
30862306a36Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idVendor),
30962306a36Sopenharmony_ci			 le16_to_cpu(dev->descriptor.idProduct));
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
31262306a36Sopenharmony_ci	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	input_dev->name = kbd->name;
31562306a36Sopenharmony_ci	input_dev->phys = kbd->phys;
31662306a36Sopenharmony_ci	usb_to_input_id(dev, &input_dev->id);
31762306a36Sopenharmony_ci	input_dev->dev.parent = &iface->dev;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	input_set_drvdata(input_dev, kbd);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
32262306a36Sopenharmony_ci		BIT_MASK(EV_REP);
32362306a36Sopenharmony_ci	input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
32462306a36Sopenharmony_ci		BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
32562306a36Sopenharmony_ci		BIT_MASK(LED_KANA);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	for (i = 0; i < 255; i++)
32862306a36Sopenharmony_ci		set_bit(usb_kbd_keycode[i], input_dev->keybit);
32962306a36Sopenharmony_ci	clear_bit(0, input_dev->keybit);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	input_dev->event = usb_kbd_event;
33262306a36Sopenharmony_ci	input_dev->open = usb_kbd_open;
33362306a36Sopenharmony_ci	input_dev->close = usb_kbd_close;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	usb_fill_int_urb(kbd->irq, dev, pipe,
33662306a36Sopenharmony_ci			 kbd->new, (maxp > 8 ? 8 : maxp),
33762306a36Sopenharmony_ci			 usb_kbd_irq, kbd, endpoint->bInterval);
33862306a36Sopenharmony_ci	kbd->irq->transfer_dma = kbd->new_dma;
33962306a36Sopenharmony_ci	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
34262306a36Sopenharmony_ci	kbd->cr->bRequest = 0x09;
34362306a36Sopenharmony_ci	kbd->cr->wValue = cpu_to_le16(0x200);
34462306a36Sopenharmony_ci	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
34562306a36Sopenharmony_ci	kbd->cr->wLength = cpu_to_le16(1);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
34862306a36Sopenharmony_ci			     (void *) kbd->cr, kbd->leds, 1,
34962306a36Sopenharmony_ci			     usb_kbd_led, kbd);
35062306a36Sopenharmony_ci	kbd->led->transfer_dma = kbd->leds_dma;
35162306a36Sopenharmony_ci	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	error = input_register_device(kbd->dev);
35462306a36Sopenharmony_ci	if (error)
35562306a36Sopenharmony_ci		goto fail2;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	usb_set_intfdata(iface, kbd);
35862306a36Sopenharmony_ci	device_set_wakeup_enable(&dev->dev, 1);
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cifail2:
36262306a36Sopenharmony_ci	usb_kbd_free_mem(dev, kbd);
36362306a36Sopenharmony_cifail1:
36462306a36Sopenharmony_ci	input_free_device(input_dev);
36562306a36Sopenharmony_ci	kfree(kbd);
36662306a36Sopenharmony_ci	return error;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void usb_kbd_disconnect(struct usb_interface *intf)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct usb_kbd *kbd = usb_get_intfdata (intf);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
37462306a36Sopenharmony_ci	if (kbd) {
37562306a36Sopenharmony_ci		usb_kill_urb(kbd->irq);
37662306a36Sopenharmony_ci		input_unregister_device(kbd->dev);
37762306a36Sopenharmony_ci		usb_kill_urb(kbd->led);
37862306a36Sopenharmony_ci		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
37962306a36Sopenharmony_ci		kfree(kbd);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic const struct usb_device_id usb_kbd_id_table[] = {
38462306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
38562306a36Sopenharmony_ci		USB_INTERFACE_PROTOCOL_KEYBOARD) },
38662306a36Sopenharmony_ci	{ }						/* Terminating entry */
38762306a36Sopenharmony_ci};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic struct usb_driver usb_kbd_driver = {
39262306a36Sopenharmony_ci	.name =		"usbkbd",
39362306a36Sopenharmony_ci	.probe =	usb_kbd_probe,
39462306a36Sopenharmony_ci	.disconnect =	usb_kbd_disconnect,
39562306a36Sopenharmony_ci	.id_table =	usb_kbd_id_table,
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cimodule_usb_driver(usb_kbd_driver);
399