--- linux-test2-pre11/drivers/usb/usb-ohci.c	Fri Jun 23 10:54:41 2000
+++ linux/drivers/usb/usb-ohci.c	Sun Jun 25 12:26:31 2000
@@ -307,7 +307,7 @@
 
 static void ohci_dump (ohci_t *controller, int verbose)
 {
-	dbg ("OHCI controller %p state", controller->regs);
+	dbg ("OHCI controller %s state", controller->ohci_dev->slot_name);
 
 	// dumps some of the state we know about
 	ohci_dump_status (controller);
@@ -831,8 +831,8 @@
 		}
 		break;
       
-    case INT: 
-      	int_branch = ed->int_branch;
+	case INT: 
+		int_branch = ed->int_branch;
 		interval = ed->int_interval;
 
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
@@ -1392,6 +1392,10 @@
 	__u8 data[8];
 
 	num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP; 
+	if (num_ports > MAX_ROOT_PORTS) {
+		dbg ("bogus roothub registers for OHCI %s", ohci->ohci_dev->slot_name);
+		return 0;
+	}
 	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
 		? 1: 0;
 	ret = *(__u8 *) data;
@@ -1424,8 +1428,12 @@
 	ohci_t * ohci = urb->dev->bus->hcpriv;
 
 	if (ohci->disabled)
-	    return;
-	
+		return;
+
+	/* ignore timers firing during PM suspend, etc */
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
+		return;
+
 	if(ohci->rh.send) { 
 		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
 		if (len > 0) {
@@ -1702,7 +1710,9 @@
 	/* Disable HC interrupts */
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
-	dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
+	dbg("USB HC reset_hc %s: ctrl = %x ;",
+		ohci->ohci_dev->slot_name,
+		readl (&ohci->regs->control));
 
   	/* Reset USB (needed by some controllers) */
 	writel (0, &ohci->regs->control);
@@ -1793,17 +1803,22 @@
 
 	if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
-	} else { 
- 		if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
-			return;
+	} else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
+		return;
 	} 
 
 	// 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");
+		err ("OHCI Unrecoverable Error, controller %s disabled",
+			ohci->ohci_dev->slot_name);
 		// e.g. due to PCI Master/Target Abort
+
+#ifndef	DEBUG
+		// FIXME: be optimistic ... assume it's a hardware bug.
+		// make some non-interrupt context restart the controller.
+#endif
 	}
   
 	if (ints & OHCI_INTR_WDH) {
@@ -1823,7 +1838,8 @@
 		if (ohci->ed_rm_list[!frame] != NULL) {
 			dl_del_list (ohci, !frame);
 		}
-		if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, &regs->intrenable);	
+		if (ohci->ed_rm_list[frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);	
 	}
 	writel (ints, &regs->intrstatus);
 	writel (OHCI_INTR_MIE, &regs->intrenable);	
@@ -1885,20 +1901,20 @@
 
 static void hc_release_ohci (ohci_t * ohci)
 {	
-	dbg("USB HC release ohci");
+	dbg ("USB HC release ohci %s", ohci->ohci_dev->slot_name);
 
 	/* disconnect all devices */    
 	if (ohci->bus->root_hub)
 		usb_disconnect (&ohci->bus->root_hub);
 
-	hc_reset (ohci);
-	writel (OHCI_USB_RESET, &ohci->regs->control);
-	wait_ms (10);
+	if (!ohci->disabled)
+		hc_reset (ohci);
 	
 	if (ohci->irq >= 0) {
 		free_irq (ohci->irq, ohci);
 		ohci->irq = -1;
 	}
+	ohci->ohci_dev->driver_data = 0;
 
 	usb_deregister_bus (ohci->bus);
 	usb_free_bus (ohci->bus);
@@ -1926,13 +1942,15 @@
 #endif
 	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
 		(unsigned long)	mem_base, bufp);
-	printk(KERN_INFO __FILE__ ": %s\n", dev->name);
+	printk(KERN_INFO __FILE__ ": pci slot %s, %s\n", dev->slot_name, dev->name);
     
 	ohci = hc_alloc_ohci (mem_base);
 	if (!ohci) {
 		return -ENOMEM;
 	}
 
+	ohci->ohci_dev = dev;
+	dev->driver_data = ohci;
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
 	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
 
@@ -1960,7 +1978,6 @@
 #ifdef	DEBUG
 		ohci_dump (ohci, 1);
 #endif
-
 		return 0;
  	}	
  	err("request interrupt %d failed", irq);
@@ -2037,7 +2054,7 @@
 		switch (rqst) {
 		case PM_SUSPEND:
 			/* act as if usb suspend can always be used */
-			dbg("USB suspend: %p", ohci->regs);
+			dbg("USB suspend: %s", ohci->ohci_dev->slot_name);
 			ohci->hc_control = OHCI_USB_SUSPEND;
 			writel (ohci->hc_control, &ohci->regs->control);
 			wait_ms (10);
@@ -2050,7 +2067,7 @@
 			switch (temp) {
 
 			case OHCI_USB_RESET:	// lost power
-				dbg("USB reset: %p", ohci->regs);
+				dbg("USB reset: %s", ohci->ohci_dev->slot_name);
 				ohci->disabled = 1;
 				if (ohci->bus->root_hub)
 					usb_disconnect (&ohci->bus->root_hub);
@@ -2058,14 +2075,16 @@
 				if ((temp = hc_reset (ohci)) < 0
 					|| (temp = hc_start (ohci)) < 0) {
 					ohci->disabled = 1;
-					err ("can't restart, %d", temp);
+					err ("can't restart %s, %d",
+						ohci->ohci_dev->slot_name,
+						temp);
 				}
 				dbg ("reset done");
 				break;
 
 			case OHCI_USB_SUSPEND:	// host wakeup
 			case OHCI_USB_RESUME:	// remote wakeup
-				dbg("USB resume: %p", ohci->regs);
+				dbg("USB resume: %s", ohci->ohci_dev->slot_name);
 				ohci->hc_control = OHCI_USB_RESUME;
 				writel (ohci->hc_control, &ohci->regs->control);
 				wait_ms (20);
--- linux-test2-pre11/drivers/usb/usb-ohci.h	Fri Jun 23 10:54:42 2000
+++ linux/drivers/usb/usb-ohci.h	Sun Jun 25 10:42:30 2000
@@ -8,13 +8,9 @@
  */
 
  
-#define MODSTR "ohci: "
-
-
 static int cc_to_error[16] = { 
 
 /* mapping of the OHCI CC status to error codes */ 
-#ifdef USB_ST_CRC /* status codes */
 	/* No  Error  */               USB_ST_NOERROR,
 	/* CRC Error  */               USB_ST_CRC,
 	/* Bit Stuff  */               USB_ST_BITSTUFF,
@@ -33,28 +29,6 @@
 	/* Not Access */               USB_ST_NORESPONSE 
 };
 
-#else  /* error codes */
-	/* No  Error  */               0,
-	/* CRC Error  */               -EILSEQ,
-	/* Bit Stuff  */               -EPROTO,
-	/* Data Togg  */               -EILSEQ,
-	/* Stall      */               -EPIPE,
-	/* DevNotResp */               -ETIMEDOUT,
-	/* PIDCheck   */               -EPROTO,
-	/* UnExpPID   */               -EPROTO,
-	/* DataOver   */               -EOVERFLOW,
-	/* DataUnder  */               -EREMOTEIO,
-	/* reservd    */               -ETIMEDOUT,
-	/* reservd    */               -ETIMEDOUT,
-	/* BufferOver */               -ECOMM,
-	/* BuffUnder  */               -ECOMM,
-	/* Not Access */               -ETIMEDOUT,
-	/* Not Access */               -ETIMEDOUT  
-};
-#define USB_ST_URB_PENDING		-EINPROGRESS
-#endif
-
- 
 
 struct ed;
 struct td;
@@ -410,6 +384,7 @@
 	struct usb_bus * bus;    
 	struct usb_device * dev[128];
 	struct virt_root_hub rh;
+	struct pci_dev *ohci_dev;
 } ohci_t;
 
 
@@ -426,6 +401,7 @@
 #define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
 
 /* hcd */
+static void dl_del_list (ohci_t  * ohci, unsigned int frame);
 /* endpoint */
 static int ep_link(ohci_t * ohci, ed_t * ed);
 static int ep_unlink(ohci_t * ohci, ed_t * ed);

