diff options
Diffstat (limited to 'drivers/usb/host/isp116x-hcd.c')
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 214 |
1 files changed, 96 insertions, 118 deletions
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 46873f2534b..c27417f5b9d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c | |||
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) | |||
228 | struct urb, urb_list); | 228 | struct urb, urb_list); |
229 | ptd = &ep->ptd; | 229 | ptd = &ep->ptd; |
230 | len = ep->length; | 230 | len = ep->length; |
231 | spin_lock(&urb->lock); | ||
232 | ep->data = (unsigned char *)urb->transfer_buffer | 231 | ep->data = (unsigned char *)urb->transfer_buffer |
233 | + urb->actual_length; | 232 | + urb->actual_length; |
234 | 233 | ||
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) | |||
264 | | PTD_EP(ep->epnum); | 263 | | PTD_EP(ep->epnum); |
265 | ptd->len = PTD_LEN(len) | PTD_DIR(dir); | 264 | ptd->len = PTD_LEN(len) | PTD_DIR(dir); |
266 | ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); | 265 | ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); |
267 | spin_unlock(&urb->lock); | ||
268 | if (!ep->active) { | 266 | if (!ep->active) { |
269 | ptd->mps |= PTD_LAST_MSK; | 267 | ptd->mps |= PTD_LAST_MSK; |
270 | isp116x->atl_last_dir = dir; | 268 | isp116x->atl_last_dir = dir; |
@@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp116x *isp116x) | |||
275 | } | 273 | } |
276 | 274 | ||
277 | /* | 275 | /* |
276 | Take done or failed requests out of schedule. Give back | ||
277 | processed urbs. | ||
278 | */ | ||
279 | static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, | ||
280 | struct urb *urb, int status) | ||
281 | __releases(isp116x->lock) __acquires(isp116x->lock) | ||
282 | { | ||
283 | unsigned i; | ||
284 | |||
285 | ep->error_count = 0; | ||
286 | |||
287 | if (usb_pipecontrol(urb->pipe)) | ||
288 | ep->nextpid = USB_PID_SETUP; | ||
289 | |||
290 | urb_dbg(urb, "Finish"); | ||
291 | |||
292 | usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); | ||
293 | spin_unlock(&isp116x->lock); | ||
294 | usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); | ||
295 | spin_lock(&isp116x->lock); | ||
296 | |||
297 | /* take idle endpoints out of the schedule */ | ||
298 | if (!list_empty(&ep->hep->urb_list)) | ||
299 | return; | ||
300 | |||
301 | /* async deschedule */ | ||
302 | if (!list_empty(&ep->schedule)) { | ||
303 | list_del_init(&ep->schedule); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | /* periodic deschedule */ | ||
308 | DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); | ||
309 | for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { | ||
310 | struct isp116x_ep *temp; | ||
311 | struct isp116x_ep **prev = &isp116x->periodic[i]; | ||
312 | |||
313 | while (*prev && ((temp = *prev) != ep)) | ||
314 | prev = &temp->next; | ||
315 | if (*prev) | ||
316 | *prev = ep->next; | ||
317 | isp116x->load[i] -= ep->load; | ||
318 | } | ||
319 | ep->branch = PERIODIC_SIZE; | ||
320 | isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= | ||
321 | ep->load / ep->period; | ||
322 | |||
323 | /* switch irq type? */ | ||
324 | if (!--isp116x->periodic_count) { | ||
325 | isp116x->irqenb &= ~HCuPINT_SOF; | ||
326 | isp116x->irqenb |= HCuPINT_ATL; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | /* | ||
278 | Analyze transfer results, handle partial transfers and errors | 331 | Analyze transfer results, handle partial transfers and errors |
279 | */ | 332 | */ |
280 | static void postproc_atl_queue(struct isp116x *isp116x) | 333 | static void postproc_atl_queue(struct isp116x *isp116x) |
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
284 | struct usb_device *udev; | 337 | struct usb_device *udev; |
285 | struct ptd *ptd; | 338 | struct ptd *ptd; |
286 | int short_not_ok; | 339 | int short_not_ok; |
340 | int status; | ||
287 | u8 cc; | 341 | u8 cc; |
288 | 342 | ||
289 | for (ep = isp116x->atl_active; ep; ep = ep->active) { | 343 | for (ep = isp116x->atl_active; ep; ep = ep->active) { |
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
294 | ptd = &ep->ptd; | 348 | ptd = &ep->ptd; |
295 | cc = PTD_GET_CC(ptd); | 349 | cc = PTD_GET_CC(ptd); |
296 | short_not_ok = 1; | 350 | short_not_ok = 1; |
297 | spin_lock(&urb->lock); | 351 | status = -EINPROGRESS; |
298 | 352 | ||
299 | /* Data underrun is special. For allowed underrun | 353 | /* Data underrun is special. For allowed underrun |
300 | we clear the error and continue as normal. For | 354 | we clear the error and continue as normal. For |
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
302 | immediately while for control transfer, | 356 | immediately while for control transfer, |
303 | we do a STATUS stage. */ | 357 | we do a STATUS stage. */ |
304 | if (cc == TD_DATAUNDERRUN) { | 358 | if (cc == TD_DATAUNDERRUN) { |
305 | if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) { | 359 | if (!(urb->transfer_flags & URB_SHORT_NOT_OK) || |
306 | DBG("Allowed data underrun\n"); | 360 | usb_pipecontrol(urb->pipe)) { |
361 | DBG("Allowed or control data underrun\n"); | ||
307 | cc = TD_CC_NOERROR; | 362 | cc = TD_CC_NOERROR; |
308 | short_not_ok = 0; | 363 | short_not_ok = 0; |
309 | } else { | 364 | } else { |
310 | ep->error_count = 1; | 365 | ep->error_count = 1; |
311 | if (usb_pipecontrol(urb->pipe)) | 366 | usb_settoggle(udev, ep->epnum, |
312 | ep->nextpid = USB_PID_ACK; | 367 | ep->nextpid == USB_PID_OUT, |
313 | else | 368 | PTD_GET_TOGGLE(ptd)); |
314 | usb_settoggle(udev, ep->epnum, | ||
315 | ep->nextpid == | ||
316 | USB_PID_OUT, | ||
317 | PTD_GET_TOGGLE(ptd)); | ||
318 | urb->actual_length += PTD_GET_COUNT(ptd); | 369 | urb->actual_length += PTD_GET_COUNT(ptd); |
319 | urb->status = cc_to_error[TD_DATAUNDERRUN]; | 370 | status = cc_to_error[TD_DATAUNDERRUN]; |
320 | spin_unlock(&urb->lock); | 371 | goto done; |
321 | continue; | ||
322 | } | 372 | } |
323 | } | 373 | } |
324 | /* Keep underrun error through the STATUS stage */ | ||
325 | if (urb->status == cc_to_error[TD_DATAUNDERRUN]) | ||
326 | cc = TD_DATAUNDERRUN; | ||
327 | 374 | ||
328 | if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED | 375 | if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED |
329 | && (++ep->error_count >= 3 || cc == TD_CC_STALL | 376 | && (++ep->error_count >= 3 || cc == TD_CC_STALL |
330 | || cc == TD_DATAOVERRUN)) { | 377 | || cc == TD_DATAOVERRUN)) { |
331 | if (urb->status == -EINPROGRESS) | 378 | status = cc_to_error[cc]; |
332 | urb->status = cc_to_error[cc]; | ||
333 | if (ep->nextpid == USB_PID_ACK) | 379 | if (ep->nextpid == USB_PID_ACK) |
334 | ep->nextpid = 0; | 380 | ep->nextpid = 0; |
335 | spin_unlock(&urb->lock); | 381 | goto done; |
336 | continue; | ||
337 | } | 382 | } |
338 | /* According to usb spec, zero-length Int transfer signals | 383 | /* According to usb spec, zero-length Int transfer signals |
339 | finishing of the urb. Hey, does this apply only | 384 | finishing of the urb. Hey, does this apply only |
340 | for IN endpoints? */ | 385 | for IN endpoints? */ |
341 | if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) { | 386 | if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) { |
342 | if (urb->status == -EINPROGRESS) | 387 | status = 0; |
343 | urb->status = 0; | 388 | goto done; |
344 | spin_unlock(&urb->lock); | ||
345 | continue; | ||
346 | } | 389 | } |
347 | 390 | ||
348 | /* Relax after previously failed, but later succeeded | 391 | /* Relax after previously failed, but later succeeded |
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
381 | /* All data for this URB is transferred, let's finish */ | 424 | /* All data for this URB is transferred, let's finish */ |
382 | if (usb_pipecontrol(urb->pipe)) | 425 | if (usb_pipecontrol(urb->pipe)) |
383 | ep->nextpid = USB_PID_ACK; | 426 | ep->nextpid = USB_PID_ACK; |
384 | else if (urb->status == -EINPROGRESS) | 427 | else |
385 | urb->status = 0; | 428 | status = 0; |
386 | break; | 429 | break; |
387 | case USB_PID_SETUP: | 430 | case USB_PID_SETUP: |
388 | if (PTD_GET_ACTIVE(ptd) | 431 | if (PTD_GET_ACTIVE(ptd) |
@@ -402,69 +445,16 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
402 | if (PTD_GET_ACTIVE(ptd) | 445 | if (PTD_GET_ACTIVE(ptd) |
403 | || (cc != TD_CC_NOERROR && cc < 0x0E)) | 446 | || (cc != TD_CC_NOERROR && cc < 0x0E)) |
404 | break; | 447 | break; |
405 | if (urb->status == -EINPROGRESS) | 448 | status = 0; |
406 | urb->status = 0; | ||
407 | ep->nextpid = 0; | 449 | ep->nextpid = 0; |
408 | break; | 450 | break; |
409 | default: | 451 | default: |
410 | BUG(); | 452 | BUG(); |
411 | } | 453 | } |
412 | spin_unlock(&urb->lock); | ||
413 | } | ||
414 | } | ||
415 | 454 | ||
416 | /* | 455 | done: |
417 | Take done or failed requests out of schedule. Give back | 456 | if (status != -EINPROGRESS || urb->unlinked) |
418 | processed urbs. | 457 | finish_request(isp116x, ep, urb, status); |
419 | */ | ||
420 | static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, | ||
421 | struct urb *urb) | ||
422 | __releases(isp116x->lock) __acquires(isp116x->lock) | ||
423 | { | ||
424 | unsigned i; | ||
425 | |||
426 | urb->hcpriv = NULL; | ||
427 | ep->error_count = 0; | ||
428 | |||
429 | if (usb_pipecontrol(urb->pipe)) | ||
430 | ep->nextpid = USB_PID_SETUP; | ||
431 | |||
432 | urb_dbg(urb, "Finish"); | ||
433 | |||
434 | spin_unlock(&isp116x->lock); | ||
435 | usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); | ||
436 | spin_lock(&isp116x->lock); | ||
437 | |||
438 | /* take idle endpoints out of the schedule */ | ||
439 | if (!list_empty(&ep->hep->urb_list)) | ||
440 | return; | ||
441 | |||
442 | /* async deschedule */ | ||
443 | if (!list_empty(&ep->schedule)) { | ||
444 | list_del_init(&ep->schedule); | ||
445 | return; | ||
446 | } | ||
447 | |||
448 | /* periodic deschedule */ | ||
449 | DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); | ||
450 | for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { | ||
451 | struct isp116x_ep *temp; | ||
452 | struct isp116x_ep **prev = &isp116x->periodic[i]; | ||
453 | |||
454 | while (*prev && ((temp = *prev) != ep)) | ||
455 | prev = &temp->next; | ||
456 | if (*prev) | ||
457 | *prev = ep->next; | ||
458 | isp116x->load[i] -= ep->load; | ||
459 | } | ||
460 | ep->branch = PERIODIC_SIZE; | ||
461 | isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= | ||
462 | ep->load / ep->period; | ||
463 | |||
464 | /* switch irq type? */ | ||
465 | if (!--isp116x->periodic_count) { | ||
466 | isp116x->irqenb &= ~HCuPINT_SOF; | ||
467 | isp116x->irqenb |= HCuPINT_ATL; | ||
468 | } | 458 | } |
469 | } | 459 | } |
470 | 460 | ||
@@ -570,9 +560,6 @@ static void start_atl_transfers(struct isp116x *isp116x) | |||
570 | */ | 560 | */ |
571 | static void finish_atl_transfers(struct isp116x *isp116x) | 561 | static void finish_atl_transfers(struct isp116x *isp116x) |
572 | { | 562 | { |
573 | struct isp116x_ep *ep; | ||
574 | struct urb *urb; | ||
575 | |||
576 | if (!isp116x->atl_active) | 563 | if (!isp116x->atl_active) |
577 | return; | 564 | return; |
578 | /* Fifo not ready? */ | 565 | /* Fifo not ready? */ |
@@ -582,16 +569,6 @@ static void finish_atl_transfers(struct isp116x *isp116x) | |||
582 | atomic_inc(&isp116x->atl_finishing); | 569 | atomic_inc(&isp116x->atl_finishing); |
583 | unpack_fifo(isp116x); | 570 | unpack_fifo(isp116x); |
584 | postproc_atl_queue(isp116x); | 571 | postproc_atl_queue(isp116x); |
585 | for (ep = isp116x->atl_active; ep; ep = ep->active) { | ||
586 | urb = | ||
587 | container_of(ep->hep->urb_list.next, struct urb, urb_list); | ||
588 | /* USB_PID_ACK check here avoids finishing of | ||
589 | control transfers, for which TD_DATAUNDERRUN | ||
590 | occured, while URB_SHORT_NOT_OK was set */ | ||
591 | if (urb && urb->status != -EINPROGRESS | ||
592 | && ep->nextpid != USB_PID_ACK) | ||
593 | finish_request(isp116x, ep, urb); | ||
594 | } | ||
595 | atomic_dec(&isp116x->atl_finishing); | 572 | atomic_dec(&isp116x->atl_finishing); |
596 | } | 573 | } |
597 | 574 | ||
@@ -685,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) | |||
685 | /*-----------------------------------------------------------------*/ | 662 | /*-----------------------------------------------------------------*/ |
686 | 663 | ||
687 | static int isp116x_urb_enqueue(struct usb_hcd *hcd, | 664 | static int isp116x_urb_enqueue(struct usb_hcd *hcd, |
688 | struct usb_host_endpoint *hep, struct urb *urb, | 665 | struct urb *urb, |
689 | gfp_t mem_flags) | 666 | gfp_t mem_flags) |
690 | { | 667 | { |
691 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | 668 | struct isp116x *isp116x = hcd_to_isp116x(hcd); |
@@ -694,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
694 | int is_out = !usb_pipein(pipe); | 671 | int is_out = !usb_pipein(pipe); |
695 | int type = usb_pipetype(pipe); | 672 | int type = usb_pipetype(pipe); |
696 | int epnum = usb_pipeendpoint(pipe); | 673 | int epnum = usb_pipeendpoint(pipe); |
674 | struct usb_host_endpoint *hep = urb->ep; | ||
697 | struct isp116x_ep *ep = NULL; | 675 | struct isp116x_ep *ep = NULL; |
698 | unsigned long flags; | 676 | unsigned long flags; |
699 | int i; | 677 | int i; |
@@ -717,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
717 | if (!HC_IS_RUNNING(hcd->state)) { | 695 | if (!HC_IS_RUNNING(hcd->state)) { |
718 | kfree(ep); | 696 | kfree(ep); |
719 | ret = -ENODEV; | 697 | ret = -ENODEV; |
720 | goto fail; | 698 | goto fail_not_linked; |
699 | } | ||
700 | ret = usb_hcd_link_urb_to_ep(hcd, urb); | ||
701 | if (ret) { | ||
702 | kfree(ep); | ||
703 | goto fail_not_linked; | ||
721 | } | 704 | } |
722 | 705 | ||
723 | if (hep->hcpriv) | 706 | if (hep->hcpriv) |
@@ -820,19 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
820 | } | 803 | } |
821 | } | 804 | } |
822 | 805 | ||
823 | /* in case of unlink-during-submit */ | ||
824 | spin_lock(&urb->lock); | ||
825 | if (urb->status != -EINPROGRESS) { | ||
826 | spin_unlock(&urb->lock); | ||
827 | finish_request(isp116x, ep, urb); | ||
828 | ret = 0; | ||
829 | goto fail; | ||
830 | } | ||
831 | urb->hcpriv = hep; | 806 | urb->hcpriv = hep; |
832 | spin_unlock(&urb->lock); | ||
833 | start_atl_transfers(isp116x); | 807 | start_atl_transfers(isp116x); |
834 | 808 | ||
835 | fail: | 809 | fail: |
810 | if (ret) | ||
811 | usb_hcd_unlink_urb_from_ep(hcd, urb); | ||
812 | fail_not_linked: | ||
836 | spin_unlock_irqrestore(&isp116x->lock, flags); | 813 | spin_unlock_irqrestore(&isp116x->lock, flags); |
837 | return ret; | 814 | return ret; |
838 | } | 815 | } |
@@ -840,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
840 | /* | 817 | /* |
841 | Dequeue URBs. | 818 | Dequeue URBs. |
842 | */ | 819 | */ |
843 | static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | 820 | static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, |
821 | int status) | ||
844 | { | 822 | { |
845 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | 823 | struct isp116x *isp116x = hcd_to_isp116x(hcd); |
846 | struct usb_host_endpoint *hep; | 824 | struct usb_host_endpoint *hep; |
847 | struct isp116x_ep *ep, *ep_act; | 825 | struct isp116x_ep *ep, *ep_act; |
848 | unsigned long flags; | 826 | unsigned long flags; |
827 | int rc; | ||
849 | 828 | ||
850 | spin_lock_irqsave(&isp116x->lock, flags); | 829 | spin_lock_irqsave(&isp116x->lock, flags); |
830 | rc = usb_hcd_check_unlink_urb(hcd, urb, status); | ||
831 | if (rc) | ||
832 | goto done; | ||
833 | |||
851 | hep = urb->hcpriv; | 834 | hep = urb->hcpriv; |
852 | /* URB already unlinked (or never linked)? */ | ||
853 | if (!hep) { | ||
854 | spin_unlock_irqrestore(&isp116x->lock, flags); | ||
855 | return 0; | ||
856 | } | ||
857 | ep = hep->hcpriv; | 835 | ep = hep->hcpriv; |
858 | WARN_ON(hep != ep->hep); | 836 | WARN_ON(hep != ep->hep); |
859 | 837 | ||
@@ -870,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | |||
870 | } | 848 | } |
871 | 849 | ||
872 | if (urb) | 850 | if (urb) |
873 | finish_request(isp116x, ep, urb); | 851 | finish_request(isp116x, ep, urb, status); |
874 | 852 | done: | |
875 | spin_unlock_irqrestore(&isp116x->lock, flags); | 853 | spin_unlock_irqrestore(&isp116x->lock, flags); |
876 | return 0; | 854 | return rc; |
877 | } | 855 | } |
878 | 856 | ||
879 | static void isp116x_endpoint_disable(struct usb_hcd *hcd, | 857 | static void isp116x_endpoint_disable(struct usb_hcd *hcd, |