--- usb-dist/usb-ohci.h Sat Mar 18 20:40:53 2000 +++ linux/drivers/usb/usb-ohci.h Mon Mar 20 13:10:23 2000 @@ -347,23 +347,25 @@ typedef struct ohci { - struct ohci_hcca hcca; /* hcca */ + struct ohci_hcca hcca; /* hcca */ int irq; - struct ohci_regs * regs; /* OHCI controller's memory */ - struct list_head ohci_hcd_list; /* list of all ohci_hcd */ + int disabled; /* e.g. got a UE, we're hung */ + + struct ohci_regs * regs; /* OHCI controller's memory */ + struct list_head ohci_hcd_list; /* list of all ohci_hcd */ struct ohci * next; // chain of uhci device contexts struct list_head urb_list; // list of all pending urbs spinlock_t urb_list_lock; // lock to keep consistency - int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load ballancing)*/ + int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */ ed_t * ed_bulktail; /* last endpoint of bulk list */ ed_t * ed_controltail; /* last endpoint of control list */ ed_t * ed_isotail; /* last endpoint of iso list */ int intrstatus; - __u32 hc_control; /* copy of the hc control reg */ + __u32 hc_control; /* copy of the hc control reg */ struct usb_bus * bus; struct usb_device * dev[128]; struct virt_root_hub rh; --- usb-dist/usb-ohci.c Sat Mar 18 20:42:25 2000 +++ linux/drivers/usb/usb-ohci.c Mon Mar 20 13:19:09 2000 @@ -262,8 +262,14 @@ urb_print (urb, "SUB", usb_pipein (pipe)); #endif + /* a request to the virtual root hub */ if (usb_pipedevice (pipe) == ohci->rh.devnum) - return rh_submit_urb (urb); /* a request to the virtual root hub */ + return rh_submit_urb (urb); + + /* when controller's hung, permit only hub cleanup attempts + * such as powering down ports */ + if (ohci->disabled) + return -ESHUTDOWN; /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) { @@ -1222,13 +1379,16 @@ urb_t * urb = (urb_t *) ptr; ohci_t * ohci = urb->dev->bus->hcpriv; + + if (ohci->disabled) + return; if(ohci->rh.send) { len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length); if (len > 0) { urb->actual_length = len; #ifdef DEBUG - urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe)); + urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe)); #endif if (urb->complete) urb->complete (urb); } @@ -1472,6 +1478,7 @@ } udelay (1); } + ohci->disabled = 0; } /*-------------------------------------------------------------------------*/ @@ -1502,7 +1509,7 @@ writel (0x628, &ohci->regs->lsthresh); /* Choose the interrupts we care about now, others later on demand */ - mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO; + mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */ writel (mask, &ohci->regs->intrenable); @@ -1550,6 +1557,11 @@ dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no)); + if (ints & OHCI_INTR_UE) { + ohci->disabled++; + err ("OHCI Unrecoverable Error, controller disabled"); + } + if (ints & OHCI_INTR_WDH) { writel (OHCI_INTR_WDH, ®s->intrdisable); dl_done_list (ohci, dl_reverse_done_list (ohci));