diff options
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 184 |
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 |