diff options
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 241 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 5 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbhid.h | 3 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbkbd.c | 64 |
4 files changed, 207 insertions, 106 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index b403fcef0b86..5bf91dbad59d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -197,16 +197,24 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid) | |||
197 | { | 197 | { |
198 | struct hid_device *hid = usb_get_intfdata(usbhid->intf); | 198 | struct hid_device *hid = usb_get_intfdata(usbhid->intf); |
199 | int kicked; | 199 | int kicked; |
200 | int r; | ||
200 | 201 | ||
201 | if (!hid) | 202 | if (!hid) |
202 | return 0; | 203 | return 0; |
203 | 204 | ||
204 | if ((kicked = (usbhid->outhead != usbhid->outtail))) { | 205 | if ((kicked = (usbhid->outhead != usbhid->outtail))) { |
205 | dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); | 206 | dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); |
207 | |||
208 | r = usb_autopm_get_interface_async(usbhid->intf); | ||
209 | if (r < 0) | ||
210 | return r; | ||
211 | /* Asynchronously flush queue. */ | ||
212 | set_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
206 | if (hid_submit_out(hid)) { | 213 | if (hid_submit_out(hid)) { |
207 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | 214 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); |
208 | wake_up(&usbhid->wait); | 215 | usb_autopm_put_interface_async(usbhid->intf); |
209 | } | 216 | } |
217 | wake_up(&usbhid->wait); | ||
210 | } | 218 | } |
211 | return kicked; | 219 | return kicked; |
212 | } | 220 | } |
@@ -215,6 +223,7 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) | |||
215 | { | 223 | { |
216 | struct hid_device *hid = usb_get_intfdata(usbhid->intf); | 224 | struct hid_device *hid = usb_get_intfdata(usbhid->intf); |
217 | int kicked; | 225 | int kicked; |
226 | int r; | ||
218 | 227 | ||
219 | WARN_ON(hid == NULL); | 228 | WARN_ON(hid == NULL); |
220 | if (!hid) | 229 | if (!hid) |
@@ -222,10 +231,17 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) | |||
222 | 231 | ||
223 | if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { | 232 | if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { |
224 | dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); | 233 | dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); |
234 | |||
235 | r = usb_autopm_get_interface_async(usbhid->intf); | ||
236 | if (r < 0) | ||
237 | return r; | ||
238 | /* Asynchronously flush queue. */ | ||
239 | set_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
225 | if (hid_submit_ctrl(hid)) { | 240 | if (hid_submit_ctrl(hid)) { |
226 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | 241 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); |
227 | wake_up(&usbhid->wait); | 242 | usb_autopm_put_interface_async(usbhid->intf); |
228 | } | 243 | } |
244 | wake_up(&usbhid->wait); | ||
229 | } | 245 | } |
230 | return kicked; | 246 | return kicked; |
231 | } | 247 | } |
@@ -304,30 +320,21 @@ static int hid_submit_out(struct hid_device *hid) | |||
304 | report = usbhid->out[usbhid->outtail].report; | 320 | report = usbhid->out[usbhid->outtail].report; |
305 | raw_report = usbhid->out[usbhid->outtail].raw_report; | 321 | raw_report = usbhid->out[usbhid->outtail].raw_report; |
306 | 322 | ||
307 | r = usb_autopm_get_interface_async(usbhid->intf); | 323 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + |
308 | if (r < 0) | 324 | 1 + (report->id > 0); |
309 | return -1; | 325 | usbhid->urbout->dev = hid_to_usb_dev(hid); |
310 | 326 | memcpy(usbhid->outbuf, raw_report, | |
311 | /* | 327 | usbhid->urbout->transfer_buffer_length); |
312 | * if the device hasn't been woken, we leave the output | 328 | kfree(raw_report); |
313 | * to resume() | ||
314 | */ | ||
315 | if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { | ||
316 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); | ||
317 | usbhid->urbout->dev = hid_to_usb_dev(hid); | ||
318 | memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); | ||
319 | kfree(raw_report); | ||
320 | 329 | ||
321 | dbg_hid("submitting out urb\n"); | 330 | dbg_hid("submitting out urb\n"); |
322 | 331 | ||
323 | if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { | 332 | r = usb_submit_urb(usbhid->urbout, GFP_ATOMIC); |
324 | hid_err(hid, "usb_submit_urb(out) failed\n"); | 333 | if (r < 0) { |
325 | usb_autopm_put_interface_async(usbhid->intf); | 334 | hid_err(hid, "usb_submit_urb(out) failed: %d\n", r); |
326 | return -1; | 335 | return r; |
327 | } | ||
328 | usbhid->last_out = jiffies; | ||
329 | } | 336 | } |
330 | 337 | usbhid->last_out = jiffies; | |
331 | return 0; | 338 | return 0; |
332 | } | 339 | } |
333 | 340 | ||
@@ -343,50 +350,48 @@ static int hid_submit_ctrl(struct hid_device *hid) | |||
343 | raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; | 350 | raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; |
344 | dir = usbhid->ctrl[usbhid->ctrltail].dir; | 351 | dir = usbhid->ctrl[usbhid->ctrltail].dir; |
345 | 352 | ||
346 | r = usb_autopm_get_interface_async(usbhid->intf); | 353 | len = ((report->size - 1) >> 3) + 1 + (report->id > 0); |
347 | if (r < 0) | 354 | if (dir == USB_DIR_OUT) { |
348 | return -1; | 355 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); |
349 | if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { | 356 | usbhid->urbctrl->transfer_buffer_length = len; |
350 | len = ((report->size - 1) >> 3) + 1 + (report->id > 0); | 357 | memcpy(usbhid->ctrlbuf, raw_report, len); |
351 | if (dir == USB_DIR_OUT) { | 358 | kfree(raw_report); |
352 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); | 359 | } else { |
353 | usbhid->urbctrl->transfer_buffer_length = len; | 360 | int maxpacket, padlen; |
354 | memcpy(usbhid->ctrlbuf, raw_report, len); | 361 | |
355 | kfree(raw_report); | 362 | usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); |
356 | } else { | 363 | maxpacket = usb_maxpacket(hid_to_usb_dev(hid), |
357 | int maxpacket, padlen; | 364 | usbhid->urbctrl->pipe, 0); |
358 | 365 | if (maxpacket > 0) { | |
359 | usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); | 366 | padlen = DIV_ROUND_UP(len, maxpacket); |
360 | maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0); | 367 | padlen *= maxpacket; |
361 | if (maxpacket > 0) { | 368 | if (padlen > usbhid->bufsize) |
362 | padlen = DIV_ROUND_UP(len, maxpacket); | 369 | padlen = usbhid->bufsize; |
363 | padlen *= maxpacket; | 370 | } else |
364 | if (padlen > usbhid->bufsize) | 371 | padlen = 0; |
365 | padlen = usbhid->bufsize; | 372 | usbhid->urbctrl->transfer_buffer_length = padlen; |
366 | } else | ||
367 | padlen = 0; | ||
368 | usbhid->urbctrl->transfer_buffer_length = padlen; | ||
369 | } | ||
370 | usbhid->urbctrl->dev = hid_to_usb_dev(hid); | ||
371 | |||
372 | usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; | ||
373 | usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; | ||
374 | usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); | ||
375 | usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); | ||
376 | usbhid->cr->wLength = cpu_to_le16(len); | ||
377 | |||
378 | dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n", | ||
379 | usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", | ||
380 | usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); | ||
381 | |||
382 | if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { | ||
383 | usb_autopm_put_interface_async(usbhid->intf); | ||
384 | hid_err(hid, "usb_submit_urb(ctrl) failed\n"); | ||
385 | return -1; | ||
386 | } | ||
387 | usbhid->last_ctrl = jiffies; | ||
388 | } | 373 | } |
389 | 374 | usbhid->urbctrl->dev = hid_to_usb_dev(hid); | |
375 | |||
376 | usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; | ||
377 | usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : | ||
378 | HID_REQ_GET_REPORT; | ||
379 | usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | | ||
380 | report->id); | ||
381 | usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); | ||
382 | usbhid->cr->wLength = cpu_to_le16(len); | ||
383 | |||
384 | dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n", | ||
385 | usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : | ||
386 | "Get_Report", | ||
387 | usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); | ||
388 | |||
389 | r = usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC); | ||
390 | if (r < 0) { | ||
391 | hid_err(hid, "usb_submit_urb(ctrl) failed: %d\n", r); | ||
392 | return r; | ||
393 | } | ||
394 | usbhid->last_ctrl = jiffies; | ||
390 | return 0; | 395 | return 0; |
391 | } | 396 | } |
392 | 397 | ||
@@ -423,11 +428,8 @@ static void hid_irq_out(struct urb *urb) | |||
423 | else | 428 | else |
424 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); | 429 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); |
425 | 430 | ||
426 | if (usbhid->outhead != usbhid->outtail) { | 431 | if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) { |
427 | if (hid_submit_out(hid)) { | 432 | /* Successfully submitted next urb in queue */ |
428 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
429 | wake_up(&usbhid->wait); | ||
430 | } | ||
431 | spin_unlock_irqrestore(&usbhid->lock, flags); | 433 | spin_unlock_irqrestore(&usbhid->lock, flags); |
432 | return; | 434 | return; |
433 | } | 435 | } |
@@ -474,13 +476,9 @@ static void hid_ctrl(struct urb *urb) | |||
474 | else | 476 | else |
475 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | 477 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); |
476 | 478 | ||
477 | if (usbhid->ctrlhead != usbhid->ctrltail) { | 479 | if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) { |
478 | if (hid_submit_ctrl(hid)) { | 480 | /* Successfully submitted next urb in queue */ |
479 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
480 | wake_up(&usbhid->wait); | ||
481 | } | ||
482 | spin_unlock(&usbhid->lock); | 481 | spin_unlock(&usbhid->lock); |
483 | usb_autopm_put_interface_async(usbhid->intf); | ||
484 | return; | 482 | return; |
485 | } | 483 | } |
486 | 484 | ||
@@ -515,9 +513,23 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
515 | usbhid->out[usbhid->outhead].report = report; | 513 | usbhid->out[usbhid->outhead].report = report; |
516 | usbhid->outhead = head; | 514 | usbhid->outhead = head; |
517 | 515 | ||
516 | /* Try to awake from autosuspend... */ | ||
517 | if (usb_autopm_get_interface_async(usbhid->intf) < 0) | ||
518 | return; | ||
519 | |||
520 | /* | ||
521 | * But if still suspended, leave urb enqueued, don't submit. | ||
522 | * Submission will occur if/when resume() drains the queue. | ||
523 | */ | ||
524 | if (test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) | ||
525 | return; | ||
526 | |||
518 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { | 527 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { |
519 | if (hid_submit_out(hid)) | 528 | if (hid_submit_out(hid)) { |
520 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | 529 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); |
530 | usb_autopm_put_interface_async(usbhid->intf); | ||
531 | } | ||
532 | wake_up(&usbhid->wait); | ||
521 | } else { | 533 | } else { |
522 | /* | 534 | /* |
523 | * the queue is known to run | 535 | * the queue is known to run |
@@ -549,9 +561,23 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
549 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; | 561 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; |
550 | usbhid->ctrlhead = head; | 562 | usbhid->ctrlhead = head; |
551 | 563 | ||
564 | /* Try to awake from autosuspend... */ | ||
565 | if (usb_autopm_get_interface_async(usbhid->intf) < 0) | ||
566 | return; | ||
567 | |||
568 | /* | ||
569 | * If already suspended, leave urb enqueued, but don't submit. | ||
570 | * Submission will occur if/when resume() drains the queue. | ||
571 | */ | ||
572 | if (test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) | ||
573 | return; | ||
574 | |||
552 | if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { | 575 | if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { |
553 | if (hid_submit_ctrl(hid)) | 576 | if (hid_submit_ctrl(hid)) { |
554 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | 577 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); |
578 | usb_autopm_put_interface_async(usbhid->intf); | ||
579 | } | ||
580 | wake_up(&usbhid->wait); | ||
555 | } else { | 581 | } else { |
556 | /* | 582 | /* |
557 | * the queue is known to run | 583 | * the queue is known to run |
@@ -576,6 +602,30 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns | |||
576 | } | 602 | } |
577 | EXPORT_SYMBOL_GPL(usbhid_submit_report); | 603 | EXPORT_SYMBOL_GPL(usbhid_submit_report); |
578 | 604 | ||
605 | /* Workqueue routine to send requests to change LEDs */ | ||
606 | static void hid_led(struct work_struct *work) | ||
607 | { | ||
608 | struct usbhid_device *usbhid = | ||
609 | container_of(work, struct usbhid_device, led_work); | ||
610 | struct hid_device *hid = usbhid->hid; | ||
611 | struct hid_field *field; | ||
612 | unsigned long flags; | ||
613 | |||
614 | field = hidinput_get_led_field(hid); | ||
615 | if (!field) { | ||
616 | hid_warn(hid, "LED event field not found\n"); | ||
617 | return; | ||
618 | } | ||
619 | |||
620 | spin_lock_irqsave(&usbhid->lock, flags); | ||
621 | if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) { | ||
622 | usbhid->ledcount = hidinput_count_leds(hid); | ||
623 | hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount); | ||
624 | __usbhid_submit_report(hid, field->report, USB_DIR_OUT); | ||
625 | } | ||
626 | spin_unlock_irqrestore(&usbhid->lock, flags); | ||
627 | } | ||
628 | |||
579 | static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 629 | static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
580 | { | 630 | { |
581 | struct hid_device *hid = input_get_drvdata(dev); | 631 | struct hid_device *hid = input_get_drvdata(dev); |
@@ -595,17 +645,15 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un | |||
595 | return -1; | 645 | return -1; |
596 | } | 646 | } |
597 | 647 | ||
648 | spin_lock_irqsave(&usbhid->lock, flags); | ||
598 | hid_set_field(field, offset, value); | 649 | hid_set_field(field, offset, value); |
599 | if (value) { | 650 | spin_unlock_irqrestore(&usbhid->lock, flags); |
600 | spin_lock_irqsave(&usbhid->lock, flags); | 651 | |
601 | usbhid->ledcount++; | 652 | /* |
602 | spin_unlock_irqrestore(&usbhid->lock, flags); | 653 | * Defer performing requested LED action. |
603 | } else { | 654 | * This is more likely gather all LED changes into a single URB. |
604 | spin_lock_irqsave(&usbhid->lock, flags); | 655 | */ |
605 | usbhid->ledcount--; | 656 | schedule_work(&usbhid->led_work); |
606 | spin_unlock_irqrestore(&usbhid->lock, flags); | ||
607 | } | ||
608 | usbhid_submit_report(hid, field->report, USB_DIR_OUT); | ||
609 | 657 | ||
610 | return 0; | 658 | return 0; |
611 | } | 659 | } |
@@ -1100,7 +1148,7 @@ static void usbhid_stop(struct hid_device *hid) | |||
1100 | return; | 1148 | return; |
1101 | 1149 | ||
1102 | clear_bit(HID_STARTED, &usbhid->iofl); | 1150 | clear_bit(HID_STARTED, &usbhid->iofl); |
1103 | spin_lock_irq(&usbhid->lock); /* Sync with error handler */ | 1151 | spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ |
1104 | set_bit(HID_DISCONNECTED, &usbhid->iofl); | 1152 | set_bit(HID_DISCONNECTED, &usbhid->iofl); |
1105 | spin_unlock_irq(&usbhid->lock); | 1153 | spin_unlock_irq(&usbhid->lock); |
1106 | usb_kill_urb(usbhid->urbin); | 1154 | usb_kill_urb(usbhid->urbin); |
@@ -1234,6 +1282,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * | |||
1234 | setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); | 1282 | setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); |
1235 | spin_lock_init(&usbhid->lock); | 1283 | spin_lock_init(&usbhid->lock); |
1236 | 1284 | ||
1285 | INIT_WORK(&usbhid->led_work, hid_led); | ||
1286 | |||
1237 | ret = hid_add_device(hid); | 1287 | ret = hid_add_device(hid); |
1238 | if (ret) { | 1288 | if (ret) { |
1239 | if (ret != -ENODEV) | 1289 | if (ret != -ENODEV) |
@@ -1266,6 +1316,7 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid) | |||
1266 | { | 1316 | { |
1267 | del_timer_sync(&usbhid->io_retry); | 1317 | del_timer_sync(&usbhid->io_retry); |
1268 | cancel_work_sync(&usbhid->reset_work); | 1318 | cancel_work_sync(&usbhid->reset_work); |
1319 | cancel_work_sync(&usbhid->led_work); | ||
1269 | } | 1320 | } |
1270 | 1321 | ||
1271 | static void hid_cease_io(struct usbhid_device *usbhid) | 1322 | static void hid_cease_io(struct usbhid_device *usbhid) |
@@ -1367,16 +1418,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1367 | return -EIO; | 1418 | return -EIO; |
1368 | } | 1419 | } |
1369 | 1420 | ||
1370 | if (!ignoreled && PMSG_IS_AUTO(message)) { | ||
1371 | spin_lock_irq(&usbhid->lock); | ||
1372 | if (test_bit(HID_LED_ON, &usbhid->iofl)) { | ||
1373 | spin_unlock_irq(&usbhid->lock); | ||
1374 | usbhid_mark_busy(usbhid); | ||
1375 | return -EBUSY; | ||
1376 | } | ||
1377 | spin_unlock_irq(&usbhid->lock); | ||
1378 | } | ||
1379 | |||
1380 | hid_cancel_delayed_stuff(usbhid); | 1421 | hid_cancel_delayed_stuff(usbhid); |
1381 | hid_cease_io(usbhid); | 1422 | hid_cease_io(usbhid); |
1382 | 1423 | ||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4ea464151c3b..c831af937481 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/hid.h> | 18 | #include <linux/hid.h> |
19 | #include <linux/export.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | 21 | ||
21 | #include "../hid-ids.h" | 22 | #include "../hid-ids.h" |
@@ -46,6 +47,7 @@ static const struct hid_blacklist { | |||
46 | 47 | ||
47 | { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, | 48 | { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, |
48 | 49 | ||
50 | { USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II, HID_QUIRK_MULTI_INPUT }, | ||
49 | { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, | 51 | { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, |
50 | { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT }, | 52 | { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT }, |
51 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, | 53 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, |
@@ -66,6 +68,9 @@ static const struct hid_blacklist { | |||
66 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, | 68 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, |
67 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, | 69 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, |
68 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, | 70 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, |
71 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, | ||
72 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, | ||
73 | { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, | ||
69 | { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, | 74 | { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, |
70 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, | 75 | { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, |
71 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | 76 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 1673cac93d77..cb8f703efde5 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h | |||
@@ -55,7 +55,6 @@ struct usb_interface *usbhid_find_interface(int minor); | |||
55 | #define HID_STARTED 8 | 55 | #define HID_STARTED 8 |
56 | #define HID_REPORTED_IDLE 9 | 56 | #define HID_REPORTED_IDLE 9 |
57 | #define HID_KEYS_PRESSED 10 | 57 | #define HID_KEYS_PRESSED 10 |
58 | #define HID_LED_ON 11 | ||
59 | 58 | ||
60 | /* | 59 | /* |
61 | * USB-specific HID struct, to be pointed to | 60 | * USB-specific HID struct, to be pointed to |
@@ -97,6 +96,8 @@ struct usbhid_device { | |||
97 | struct work_struct reset_work; /* Task context for resets */ | 96 | struct work_struct reset_work; /* Task context for resets */ |
98 | wait_queue_head_t wait; /* For sleeping */ | 97 | wait_queue_head_t wait; /* For sleeping */ |
99 | int ledcount; /* counting the number of active leds */ | 98 | int ledcount; /* counting the number of active leds */ |
99 | |||
100 | struct work_struct led_work; /* Task context for setting LEDs */ | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | #define hid_to_usb_dev(hid_dev) \ | 103 | #define hid_to_usb_dev(hid_dev) \ |
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 065817329f03..a7b925aeaf2e 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c | |||
@@ -64,6 +64,32 @@ static const unsigned char usb_kbd_keycode[256] = { | |||
64 | 150,158,159,128,136,177,178,176,142,152,173,140 | 64 | 150,158,159,128,136,177,178,176,142,152,173,140 |
65 | }; | 65 | }; |
66 | 66 | ||
67 | |||
68 | /** | ||
69 | * struct usb_kbd - state of each attached keyboard | ||
70 | * @dev: input device associated with this keyboard | ||
71 | * @usbdev: usb device associated with this keyboard | ||
72 | * @old: data received in the past from the @irq URB representing which | ||
73 | * keys were pressed. By comparing with the current list of keys | ||
74 | * that are pressed, we are able to see key releases. | ||
75 | * @irq: URB for receiving a list of keys that are pressed when a | ||
76 | * new key is pressed or a key that was pressed is released. | ||
77 | * @led: URB for sending LEDs (e.g. numlock, ...) | ||
78 | * @newleds: data that will be sent with the @led URB representing which LEDs | ||
79 | should be on | ||
80 | * @name: Name of the keyboard. @dev's name field points to this buffer | ||
81 | * @phys: Physical path of the keyboard. @dev's phys field points to this | ||
82 | * buffer | ||
83 | * @new: Buffer for the @irq URB | ||
84 | * @cr: Control request for @led URB | ||
85 | * @leds: Buffer for the @led URB | ||
86 | * @new_dma: DMA address for @irq URB | ||
87 | * @leds_dma: DMA address for @led URB | ||
88 | * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted | ||
89 | * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been | ||
90 | * submitted and its completion handler has not returned yet | ||
91 | * without resubmitting @led | ||
92 | */ | ||
67 | struct usb_kbd { | 93 | struct usb_kbd { |
68 | struct input_dev *dev; | 94 | struct input_dev *dev; |
69 | struct usb_device *usbdev; | 95 | struct usb_device *usbdev; |
@@ -78,6 +104,10 @@ struct usb_kbd { | |||
78 | unsigned char *leds; | 104 | unsigned char *leds; |
79 | dma_addr_t new_dma; | 105 | dma_addr_t new_dma; |
80 | dma_addr_t leds_dma; | 106 | dma_addr_t leds_dma; |
107 | |||
108 | spinlock_t leds_lock; | ||
109 | bool led_urb_submitted; | ||
110 | |||
81 | }; | 111 | }; |
82 | 112 | ||
83 | static void usb_kbd_irq(struct urb *urb) | 113 | static void usb_kbd_irq(struct urb *urb) |
@@ -136,44 +166,66 @@ resubmit: | |||
136 | static int usb_kbd_event(struct input_dev *dev, unsigned int type, | 166 | static int usb_kbd_event(struct input_dev *dev, unsigned int type, |
137 | unsigned int code, int value) | 167 | unsigned int code, int value) |
138 | { | 168 | { |
169 | unsigned long flags; | ||
139 | struct usb_kbd *kbd = input_get_drvdata(dev); | 170 | struct usb_kbd *kbd = input_get_drvdata(dev); |
140 | 171 | ||
141 | if (type != EV_LED) | 172 | if (type != EV_LED) |
142 | return -1; | 173 | return -1; |
143 | 174 | ||
175 | spin_lock_irqsave(&kbd->leds_lock, flags); | ||
144 | kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | | 176 | kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | |
145 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | | 177 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | |
146 | (!!test_bit(LED_NUML, dev->led)); | 178 | (!!test_bit(LED_NUML, dev->led)); |
147 | 179 | ||
148 | if (kbd->led->status == -EINPROGRESS) | 180 | if (kbd->led_urb_submitted){ |
181 | spin_unlock_irqrestore(&kbd->leds_lock, flags); | ||
149 | return 0; | 182 | return 0; |
183 | } | ||
150 | 184 | ||
151 | if (*(kbd->leds) == kbd->newleds) | 185 | if (*(kbd->leds) == kbd->newleds){ |
186 | spin_unlock_irqrestore(&kbd->leds_lock, flags); | ||
152 | return 0; | 187 | return 0; |
188 | } | ||
153 | 189 | ||
154 | *(kbd->leds) = kbd->newleds; | 190 | *(kbd->leds) = kbd->newleds; |
191 | |||
155 | kbd->led->dev = kbd->usbdev; | 192 | kbd->led->dev = kbd->usbdev; |
156 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)) | 193 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)) |
157 | pr_err("usb_submit_urb(leds) failed\n"); | 194 | pr_err("usb_submit_urb(leds) failed\n"); |
158 | 195 | else | |
196 | kbd->led_urb_submitted = true; | ||
197 | |||
198 | spin_unlock_irqrestore(&kbd->leds_lock, flags); | ||
199 | |||
159 | return 0; | 200 | return 0; |
160 | } | 201 | } |
161 | 202 | ||
162 | static void usb_kbd_led(struct urb *urb) | 203 | static void usb_kbd_led(struct urb *urb) |
163 | { | 204 | { |
205 | unsigned long flags; | ||
164 | struct usb_kbd *kbd = urb->context; | 206 | struct usb_kbd *kbd = urb->context; |
165 | 207 | ||
166 | if (urb->status) | 208 | if (urb->status) |
167 | hid_warn(urb->dev, "led urb status %d received\n", | 209 | hid_warn(urb->dev, "led urb status %d received\n", |
168 | urb->status); | 210 | urb->status); |
169 | 211 | ||
170 | if (*(kbd->leds) == kbd->newleds) | 212 | spin_lock_irqsave(&kbd->leds_lock, flags); |
213 | |||
214 | if (*(kbd->leds) == kbd->newleds){ | ||
215 | kbd->led_urb_submitted = false; | ||
216 | spin_unlock_irqrestore(&kbd->leds_lock, flags); | ||
171 | return; | 217 | return; |
218 | } | ||
172 | 219 | ||
173 | *(kbd->leds) = kbd->newleds; | 220 | *(kbd->leds) = kbd->newleds; |
221 | |||
174 | kbd->led->dev = kbd->usbdev; | 222 | kbd->led->dev = kbd->usbdev; |
175 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)) | 223 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)){ |
176 | hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); | 224 | hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); |
225 | kbd->led_urb_submitted = false; | ||
226 | } | ||
227 | spin_unlock_irqrestore(&kbd->leds_lock, flags); | ||
228 | |||
177 | } | 229 | } |
178 | 230 | ||
179 | static int usb_kbd_open(struct input_dev *dev) | 231 | static int usb_kbd_open(struct input_dev *dev) |
@@ -252,6 +304,7 @@ static int usb_kbd_probe(struct usb_interface *iface, | |||
252 | 304 | ||
253 | kbd->usbdev = dev; | 305 | kbd->usbdev = dev; |
254 | kbd->dev = input_dev; | 306 | kbd->dev = input_dev; |
307 | spin_lock_init(&kbd->leds_lock); | ||
255 | 308 | ||
256 | if (dev->manufacturer) | 309 | if (dev->manufacturer) |
257 | strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); | 310 | strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); |
@@ -334,6 +387,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf) | |||
334 | if (kbd) { | 387 | if (kbd) { |
335 | usb_kill_urb(kbd->irq); | 388 | usb_kill_urb(kbd->irq); |
336 | input_unregister_device(kbd->dev); | 389 | input_unregister_device(kbd->dev); |
390 | usb_kill_urb(kbd->led); | ||
337 | usb_kbd_free_mem(interface_to_usbdev(intf), kbd); | 391 | usb_kbd_free_mem(interface_to_usbdev(intf), kbd); |
338 | kfree(kbd); | 392 | kfree(kbd); |
339 | } | 393 | } |