aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/usbhid/hid-core.c184
1 files changed, 105 insertions, 79 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 66061349be87..719f6b02fab1 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);
326 memcpy(usbhid->outbuf, raw_report,
327 usbhid->urbout->transfer_buffer_length);
328 kfree(raw_report);
310 329
311 /* 330 dbg_hid("submitting out urb\n");
312 * if the device hasn't been woken, we leave the output
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
321 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