diff options
Diffstat (limited to 'drivers/usb/host/ohci-q.c')
| -rw-r--r-- | drivers/usb/host/ohci-q.c | 23 | 
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index c5a1ea9145f..7482cfbe8c5 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -596,7 +596,6 @@ static void td_submit_urb (  		urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C);  	} -	urb_priv->td_cnt = 0;  	list_add (&urb_priv->pending, &ohci->pending);  	if (data_len) @@ -672,7 +671,8 @@ static void td_submit_urb (  	 * we could often reduce the number of TDs here.  	 */  	case PIPE_ISOCHRONOUS: -		for (cnt = 0; cnt < urb->number_of_packets; cnt++) { +		for (cnt = urb_priv->td_cnt; cnt < urb->number_of_packets; +				cnt++) {  			int	frame = urb->start_frame;  			// FIXME scheduling should handle frame counter @@ -1128,6 +1128,25 @@ dl_done_list (struct ohci_hcd *ohci)  	while (td) {  		struct td	*td_next = td->next_dl_td; +		struct ed	*ed = td->ed; + +		/* +		 * Some OHCI controllers (NVIDIA for sure, maybe others) +		 * occasionally forget to add TDs to the done queue.  Since +		 * TDs for a given endpoint are always processed in order, +		 * if we find a TD on the donelist then all of its +		 * predecessors must be finished as well. +		 */ +		for (;;) { +			struct td	*td2; + +			td2 = list_first_entry(&ed->td_list, struct td, +					td_list); +			if (td2 == td) +				break; +			takeback_td(ohci, td2); +		} +  		takeback_td(ohci, td);  		td = td_next;  	}  |