usbkbd.c 10.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 *
 *  USB HIDBP Keyboard support
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
L
Linus Torvalds 已提交
11
 * (at your option) any later version.
12
 *
L
Linus Torvalds 已提交
13 14 15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
17
 *
L
Linus Torvalds 已提交
18 19 20
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
 *
L
Linus Torvalds 已提交
22 23 24 25 26
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 */

27 28
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

L
Linus Torvalds 已提交
29 30 31 32
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
33
#include <linux/usb/input.h>
34
#include <linux/hid.h>
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47

/*
 * Version Information
 */
#define DRIVER_VERSION ""
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
#define DRIVER_LICENSE "GPL"

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);

48
static const unsigned char usb_kbd_keycode[256] = {
L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
	150,158,159,128,136,177,178,176,142,152,173,140
};

struct usb_kbd {
68
	struct input_dev *dev;
L
Linus Torvalds 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82
	struct usb_device *usbdev;
	unsigned char old[8];
	struct urb *irq, *led;
	unsigned char newleds;
	char name[128];
	char phys[64];

	unsigned char *new;
	struct usb_ctrlrequest *cr;
	unsigned char *leds;
	dma_addr_t new_dma;
	dma_addr_t leds_dma;
};

83
static void usb_kbd_irq(struct urb *urb)
L
Linus Torvalds 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
{
	struct usb_kbd *kbd = urb->context;
	int i;

	switch (urb->status) {
	case 0:			/* success */
		break;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:
		return;
	/* -EPIPE:  should clear the halt */
	default:		/* error */
		goto resubmit;
	}

	for (i = 0; i < 8; i++)
101
		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
L
Linus Torvalds 已提交
102 103 104 105 106

	for (i = 2; i < 8; i++) {

		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
			if (usb_kbd_keycode[kbd->old[i]])
107
				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
L
Linus Torvalds 已提交
108
			else
109 110 111
				hid_info(urb->dev,
					 "Unknown key (scancode %#x) released.\n",
					 kbd->old[i]);
L
Linus Torvalds 已提交
112 113 114 115
		}

		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
			if (usb_kbd_keycode[kbd->new[i]])
116
				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
L
Linus Torvalds 已提交
117
			else
118 119 120
				hid_info(urb->dev,
					 "Unknown key (scancode %#x) released.\n",
					 kbd->new[i]);
L
Linus Torvalds 已提交
121 122 123
		}
	}

124
	input_sync(kbd->dev);
L
Linus Torvalds 已提交
125 126 127 128

	memcpy(kbd->old, kbd->new, 8);

resubmit:
129
	i = usb_submit_urb (urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
130
	if (i)
131 132 133
		hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
			kbd->usbdev->bus->bus_name,
			kbd->usbdev->devpath, i);
L
Linus Torvalds 已提交
134 135
}

136 137
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
			 unsigned int code, int value)
L
Linus Torvalds 已提交
138
{
139
	struct usb_kbd *kbd = input_get_drvdata(dev);
L
Linus Torvalds 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

	if (type != EV_LED)
		return -1;

	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
		       (!!test_bit(LED_NUML,    dev->led));

	if (kbd->led->status == -EINPROGRESS)
		return 0;

	if (*(kbd->leds) == kbd->newleds)
		return 0;

	*(kbd->leds) = kbd->newleds;
	kbd->led->dev = kbd->usbdev;
	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
157
		pr_err("usb_submit_urb(leds) failed\n");
L
Linus Torvalds 已提交
158 159 160 161

	return 0;
}

162
static void usb_kbd_led(struct urb *urb)
L
Linus Torvalds 已提交
163 164 165 166
{
	struct usb_kbd *kbd = urb->context;

	if (urb->status)
167
		hid_warn(urb->dev, "led urb status %d received\n",
168
			 urb->status);
169

L
Linus Torvalds 已提交
170 171 172 173 174 175
	if (*(kbd->leds) == kbd->newleds)
		return;

	*(kbd->leds) = kbd->newleds;
	kbd->led->dev = kbd->usbdev;
	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
176
		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
L
Linus Torvalds 已提交
177 178 179 180
}

static int usb_kbd_open(struct input_dev *dev)
{
181
	struct usb_kbd *kbd = input_get_drvdata(dev);
L
Linus Torvalds 已提交
182 183

	kbd->irq->dev = kbd->usbdev;
184
	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
L
Linus Torvalds 已提交
185 186 187 188 189 190 191
		return -EIO;

	return 0;
}

static void usb_kbd_close(struct input_dev *dev)
{
192
	struct usb_kbd *kbd = input_get_drvdata(dev);
L
Linus Torvalds 已提交
193

194
	usb_kill_urb(kbd->irq);
L
Linus Torvalds 已提交
195 196 197 198 199 200 201 202
}

static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
		return -1;
	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
		return -1;
203
	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
L
Linus Torvalds 已提交
204
		return -1;
205
	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
L
Linus Torvalds 已提交
206
		return -1;
207
	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
L
Linus Torvalds 已提交
208 209 210 211 212 213 214
		return -1;

	return 0;
}

static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
M
Mariusz Kozlowski 已提交
215 216
	usb_free_urb(kbd->irq);
	usb_free_urb(kbd->led);
217
	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
218
	kfree(kbd->cr);
219
	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
L
Linus Torvalds 已提交
220 221
}

222
static int usb_kbd_probe(struct usb_interface *iface,
L
Linus Torvalds 已提交
223 224
			 const struct usb_device_id *id)
{
225
	struct usb_device *dev = interface_to_usbdev(iface);
L
Linus Torvalds 已提交
226 227 228
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_kbd *kbd;
229
	struct input_dev *input_dev;
L
Linus Torvalds 已提交
230
	int i, pipe, maxp;
231
	int error = -ENOMEM;
L
Linus Torvalds 已提交
232 233 234 235 236 237 238

	interface = iface->cur_altsetting;

	if (interface->desc.bNumEndpoints != 1)
		return -ENODEV;

	endpoint = &interface->endpoint[0].desc;
239
	if (!usb_endpoint_is_int_in(endpoint))
L
Linus Torvalds 已提交
240 241 242 243 244
		return -ENODEV;

	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

245 246 247 248
	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!kbd || !input_dev)
		goto fail1;
L
Linus Torvalds 已提交
249

250 251
	if (usb_kbd_alloc_mem(dev, kbd))
		goto fail2;
L
Linus Torvalds 已提交
252 253

	kbd->usbdev = dev;
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
	kbd->dev = input_dev;

	if (dev->manufacturer)
		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));

	if (dev->product) {
		if (dev->manufacturer)
			strlcat(kbd->name, " ", sizeof(kbd->name));
		strlcat(kbd->name, dev->product, sizeof(kbd->name));
	}

	if (!strlen(kbd->name))
		snprintf(kbd->name, sizeof(kbd->name),
			 "USB HIDBP Keyboard %04x:%04x",
			 le16_to_cpu(dev->descriptor.idVendor),
			 le16_to_cpu(dev->descriptor.idProduct));

	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
272
	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
L
Linus Torvalds 已提交
273

274 275 276
	input_dev->name = kbd->name;
	input_dev->phys = kbd->phys;
	usb_to_input_id(dev, &input_dev->id);
277 278 279
	input_dev->dev.parent = &iface->dev;

	input_set_drvdata(input_dev, kbd);
280

281 282 283 284 285
	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
		BIT_MASK(EV_REP);
	input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
		BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
		BIT_MASK(LED_KANA);
L
Linus Torvalds 已提交
286 287

	for (i = 0; i < 255; i++)
288 289
		set_bit(usb_kbd_keycode[i], input_dev->keybit);
	clear_bit(0, input_dev->keybit);
290

291 292 293
	input_dev->event = usb_kbd_event;
	input_dev->open = usb_kbd_open;
	input_dev->close = usb_kbd_close;
L
Linus Torvalds 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

	usb_fill_int_urb(kbd->irq, dev, pipe,
			 kbd->new, (maxp > 8 ? 8 : maxp),
			 usb_kbd_irq, kbd, endpoint->bInterval);
	kbd->irq->transfer_dma = kbd->new_dma;
	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
	kbd->cr->bRequest = 0x09;
	kbd->cr->wValue = cpu_to_le16(0x200);
	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
	kbd->cr->wLength = cpu_to_le16(1);

	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
			     (void *) kbd->cr, kbd->leds, 1,
			     usb_kbd_led, kbd);
	kbd->led->transfer_dma = kbd->leds_dma;
311
	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
L
Linus Torvalds 已提交
312

313 314 315
	error = input_register_device(kbd->dev);
	if (error)
		goto fail2;
L
Linus Torvalds 已提交
316 317

	usb_set_intfdata(iface, kbd);
318
	device_set_wakeup_enable(&dev->dev, 1);
L
Linus Torvalds 已提交
319
	return 0;
320

321 322 323 324
fail2:	
	usb_kbd_free_mem(dev, kbd);
fail1:	
	input_free_device(input_dev);
325
	kfree(kbd);
326
	return error;
L
Linus Torvalds 已提交
327 328 329 330 331
}

static void usb_kbd_disconnect(struct usb_interface *intf)
{
	struct usb_kbd *kbd = usb_get_intfdata (intf);
332

L
Linus Torvalds 已提交
333 334 335
	usb_set_intfdata(intf, NULL);
	if (kbd) {
		usb_kill_urb(kbd->irq);
336
		input_unregister_device(kbd->dev);
L
Linus Torvalds 已提交
337 338 339 340 341 342
		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
		kfree(kbd);
	}
}

static struct usb_device_id usb_kbd_id_table [] = {
343 344
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_KEYBOARD) },
L
Linus Torvalds 已提交
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	{ }						/* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);

static struct usb_driver usb_kbd_driver = {
	.name =		"usbkbd",
	.probe =	usb_kbd_probe,
	.disconnect =	usb_kbd_disconnect,
	.id_table =	usb_kbd_id_table,
};

static int __init usb_kbd_init(void)
{
	int result = usb_register(&usb_kbd_driver);
	if (result == 0)
361 362
		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
				DRIVER_DESC "\n");
L
Linus Torvalds 已提交
363 364 365 366 367 368 369 370 371 372
	return result;
}

static void __exit usb_kbd_exit(void)
{
	usb_deregister(&usb_kbd_driver);
}

module_init(usb_kbd_init);
module_exit(usb_kbd_exit);