--- linux-2.6.22-rc1-mm1-orig/drivers/usb/host/ehci-sched.c 2007-07-30 06:07:11.000000000 -0500 +++ linux-2.6.22-rc1-mm1/drivers/usb/host/ehci-sched.c 2007-07-30 08:39:54.000000000 -0500 @@ -547,6 +547,19 @@ static void qh_inactivate_split_intr_qhs wmb(); } +static inline struct ehci_qtd *current_qtd (struct ehci_qh *qh) +{ + struct list_head *entry, *tmp; + struct ehci_qtd *qtd; + + list_for_each_safe (entry, tmp, &qh->qtd_list) { + qtd = list_entry (entry, struct ehci_qtd, qtd_list); + if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current) + return qtd; + } + return NULL; +} + static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci) { struct ehci_qh *qh; @@ -566,12 +582,21 @@ static void qh_reactivate_split_intr_qhs if (safe == 0) { not_done = 1; } else if (safe > 0) { + struct ehci_qtd *qtd; + /* See EHCI 1.0 section 4.15.2.4. */ + qtd = current_qtd(qh); token = qh->hw_token; qh->hw_token = (token | halt) & ~active; wmb(); qh->hw_info1 &= ~inactivate; wmb(); + /* + * nVidia controllers write overlay back to qtd + * when qh is inactivated, so reactivate it too. + */ + if (qtd) + qtd->hw_token = token | qh->was_active; qh->hw_token = (token & ~halt) | qh->was_active; } }