usbkbd.c 11.5 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

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

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
45
MODULE_LICENSE("GPL");
L
Linus Torvalds 已提交
46

47
static const unsigned char usb_kbd_keycode[256] = {
L
Linus Torvalds 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	  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
};

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

/**
 * struct usb_kbd - state of each attached keyboard
 * @dev:	input device associated with this keyboard
 * @usbdev:	usb device associated with this keyboard
 * @old:	data received in the past from the @irq URB representing which
 *		keys were pressed. By comparing with the current list of keys
 *		that are pressed, we are able to see key releases.
 * @irq:	URB for receiving a list of keys that are pressed when a
 *		new key is pressed or a key that was pressed is released.
 * @led:	URB for sending LEDs (e.g. numlock, ...)
 * @newleds:	data that will be sent with the @led URB representing which LEDs
 		should be on
 * @name:	Name of the keyboard. @dev's name field points to this buffer
 * @phys:	Physical path of the keyboard. @dev's phys field points to this
 *		buffer
 * @new:	Buffer for the @irq URB
 * @cr:		Control request for @led URB
 * @leds:	Buffer for the @led URB
 * @new_dma:	DMA address for @irq URB
 * @leds_dma:	DMA address for @led URB
 * @leds_lock:	spinlock that protects @leds, @newleds, and @led_urb_submitted
 * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
 *		submitted and its completion handler has not returned yet
 *		without	resubmitting @led
 */
L
Linus Torvalds 已提交
92
struct usb_kbd {
93
	struct input_dev *dev;
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101 102 103 104 105
	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;
106 107 108 109
	
	spinlock_t leds_lock;
	bool led_urb_submitted;

L
Linus Torvalds 已提交
110 111
};

112
static void usb_kbd_irq(struct urb *urb)
L
Linus Torvalds 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
{
	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++)
130
		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
L
Linus Torvalds 已提交
131 132 133 134 135

	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]])
136
				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
L
Linus Torvalds 已提交
137
			else
138 139 140
				hid_info(urb->dev,
					 "Unknown key (scancode %#x) released.\n",
					 kbd->old[i]);
L
Linus Torvalds 已提交
141 142 143 144
		}

		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
			if (usb_kbd_keycode[kbd->new[i]])
145
				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
L
Linus Torvalds 已提交
146
			else
147
				hid_info(urb->dev,
148
					 "Unknown key (scancode %#x) pressed.\n",
149
					 kbd->new[i]);
L
Linus Torvalds 已提交
150 151 152
		}
	}

153
	input_sync(kbd->dev);
L
Linus Torvalds 已提交
154 155 156 157

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

resubmit:
158
	i = usb_submit_urb (urb, GFP_ATOMIC);
L
Linus Torvalds 已提交
159
	if (i)
160 161 162
		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 已提交
163 164
}

165 166
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
			 unsigned int code, int value)
L
Linus Torvalds 已提交
167
{
168
	unsigned long flags;
169
	struct usb_kbd *kbd = input_get_drvdata(dev);
L
Linus Torvalds 已提交
170 171 172 173

	if (type != EV_LED)
		return -1;

174
	spin_lock_irqsave(&kbd->leds_lock, flags);
L
Linus Torvalds 已提交
175 176 177 178
	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));

179 180
	if (kbd->led_urb_submitted){
		spin_unlock_irqrestore(&kbd->leds_lock, flags);
L
Linus Torvalds 已提交
181
		return 0;
182
	}
L
Linus Torvalds 已提交
183

184 185
	if (*(kbd->leds) == kbd->newleds){
		spin_unlock_irqrestore(&kbd->leds_lock, flags);
L
Linus Torvalds 已提交
186
		return 0;
187
	}
L
Linus Torvalds 已提交
188 189

	*(kbd->leds) = kbd->newleds;
190
	
L
Linus Torvalds 已提交
191 192
	kbd->led->dev = kbd->usbdev;
	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
193
		pr_err("usb_submit_urb(leds) failed\n");
194 195 196 197 198
	else
		kbd->led_urb_submitted = true;
	
	spin_unlock_irqrestore(&kbd->leds_lock, flags);
	
L
Linus Torvalds 已提交
199 200 201
	return 0;
}

202
static void usb_kbd_led(struct urb *urb)
L
Linus Torvalds 已提交
203
{
204
	unsigned long flags;
L
Linus Torvalds 已提交
205 206 207
	struct usb_kbd *kbd = urb->context;

	if (urb->status)
208
		hid_warn(urb->dev, "led urb status %d received\n",
209
			 urb->status);
210

211 212 213 214 215
	spin_lock_irqsave(&kbd->leds_lock, flags);

	if (*(kbd->leds) == kbd->newleds){
		kbd->led_urb_submitted = false;
		spin_unlock_irqrestore(&kbd->leds_lock, flags);
L
Linus Torvalds 已提交
216
		return;
217
	}
L
Linus Torvalds 已提交
218 219

	*(kbd->leds) = kbd->newleds;
220
	
L
Linus Torvalds 已提交
221
	kbd->led->dev = kbd->usbdev;
222
	if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
223
		hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
224 225 226 227
		kbd->led_urb_submitted = false;
	}
	spin_unlock_irqrestore(&kbd->leds_lock, flags);
	
L
Linus Torvalds 已提交
228 229 230 231
}

static int usb_kbd_open(struct input_dev *dev)
{
232
	struct usb_kbd *kbd = input_get_drvdata(dev);
L
Linus Torvalds 已提交
233 234

	kbd->irq->dev = kbd->usbdev;
235
	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
L
Linus Torvalds 已提交
236 237 238 239 240 241 242
		return -EIO;

	return 0;
}

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

245
	usb_kill_urb(kbd->irq);
L
Linus Torvalds 已提交
246 247 248 249 250 251 252 253
}

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;
254
	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
L
Linus Torvalds 已提交
255
		return -1;
256
	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
L
Linus Torvalds 已提交
257
		return -1;
258
	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
L
Linus Torvalds 已提交
259 260 261 262 263 264 265
		return -1;

	return 0;
}

static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
M
Mariusz Kozlowski 已提交
266 267
	usb_free_urb(kbd->irq);
	usb_free_urb(kbd->led);
268
	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
269
	kfree(kbd->cr);
270
	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
L
Linus Torvalds 已提交
271 272
}

273
static int usb_kbd_probe(struct usb_interface *iface,
L
Linus Torvalds 已提交
274 275
			 const struct usb_device_id *id)
{
276
	struct usb_device *dev = interface_to_usbdev(iface);
L
Linus Torvalds 已提交
277 278 279
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_kbd *kbd;
280
	struct input_dev *input_dev;
L
Linus Torvalds 已提交
281
	int i, pipe, maxp;
282
	int error = -ENOMEM;
L
Linus Torvalds 已提交
283 284 285 286 287 288 289

	interface = iface->cur_altsetting;

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

	endpoint = &interface->endpoint[0].desc;
290
	if (!usb_endpoint_is_int_in(endpoint))
L
Linus Torvalds 已提交
291 292 293 294 295
		return -ENODEV;

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

296 297 298 299
	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!kbd || !input_dev)
		goto fail1;
L
Linus Torvalds 已提交
300

301 302
	if (usb_kbd_alloc_mem(dev, kbd))
		goto fail2;
L
Linus Torvalds 已提交
303 304

	kbd->usbdev = dev;
305
	kbd->dev = input_dev;
306
	spin_lock_init(&kbd->leds_lock);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323

	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));
324
	strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
L
Linus Torvalds 已提交
325

326 327 328
	input_dev->name = kbd->name;
	input_dev->phys = kbd->phys;
	usb_to_input_id(dev, &input_dev->id);
329 330 331
	input_dev->dev.parent = &iface->dev;

	input_set_drvdata(input_dev, kbd);
332

333 334 335 336 337
	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 已提交
338 339

	for (i = 0; i < 255; i++)
340 341
		set_bit(usb_kbd_keycode[i], input_dev->keybit);
	clear_bit(0, input_dev->keybit);
342

343 344 345
	input_dev->event = usb_kbd_event;
	input_dev->open = usb_kbd_open;
	input_dev->close = usb_kbd_close;
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

	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;
363
	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
L
Linus Torvalds 已提交
364

365 366 367
	error = input_register_device(kbd->dev);
	if (error)
		goto fail2;
L
Linus Torvalds 已提交
368 369

	usb_set_intfdata(iface, kbd);
370
	device_set_wakeup_enable(&dev->dev, 1);
L
Linus Torvalds 已提交
371
	return 0;
372

373 374 375 376
fail2:	
	usb_kbd_free_mem(dev, kbd);
fail1:	
	input_free_device(input_dev);
377
	kfree(kbd);
378
	return error;
L
Linus Torvalds 已提交
379 380 381 382 383
}

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

L
Linus Torvalds 已提交
385 386 387
	usb_set_intfdata(intf, NULL);
	if (kbd) {
		usb_kill_urb(kbd->irq);
388
		input_unregister_device(kbd->dev);
389
		usb_kill_urb(kbd->led);
L
Linus Torvalds 已提交
390 391 392 393 394 395
		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
		kfree(kbd);
	}
}

static struct usb_device_id usb_kbd_id_table [] = {
396 397
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_KEYBOARD) },
L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405 406 407 408 409
	{ }						/* 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,
};

410
module_usb_driver(usb_kbd_driver);