patch-2.3.99-pre7 linux/drivers/usb/usb-ohci.c

Next file: linux/drivers/usb/usb-storage.c
Previous file: linux/drivers/usb/uhci.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre6/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
@@ -81,12 +81,9 @@
 {
 	urb_priv_t * urb_priv = urb->hcpriv;
 	int i;
-	void * wait;
 	
 	if (!urb_priv) return;
 	
-	wait = urb_priv->wait;
-	
 	for (i = 0; i < urb_priv->length; i++) {
 		if (urb_priv->td [i]) {
 			OHCI_FREE (urb_priv->td [i]);
@@ -94,11 +91,8 @@
 	}
 	kfree (urb->hcpriv);
 	urb->hcpriv = NULL;
-	
-	if (wait) {
-		add_wait_queue (&op_wakeup, wait); 
-		wake_up (&op_wakeup);
-	}
+
+	wake_up (&op_wakeup);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -476,7 +470,6 @@
 	urb_priv->td_cnt = 0;
 	urb_priv->state = 0;
 	urb_priv->ed = ed;	
-	urb_priv->wait = NULL;
 	
 	/* allocate the TDs */
 	for (i = 0; i < size; i++) { 
@@ -527,6 +520,9 @@
 	if (!urb) /* just to be sure */ 
 		return -EINVAL;
 		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
 	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
 
 #ifdef DEBUG
@@ -537,25 +533,31 @@
 		return rh_unlink_urb (urb); /* a request to the virtual root hub */
 	
 	if (urb->hcpriv) { 
-		if (urb->status == USB_ST_URB_PENDING) { /* URB active? */
+		/* URB active? */
+		if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) {
 			urb_priv_t  * urb_priv = urb->hcpriv;
 			urb_priv->state = URB_DEL; 
+
 			/* we want to delete the TDs of an URB from an ed 
-			 * request the deletion, it will be handled at the next USB-frame */
-			urb_priv->wait = &wait;
+			 * request the deletion, it will be handled at the
+			 * next USB-frame */
 			
 			spin_lock_irqsave (&usb_ed_lock, flags);
 			ep_rm_ed (urb->dev, urb_priv->ed);
 			urb_priv->ed->state |= ED_URB_DEL;
 			spin_unlock_irqrestore (&usb_ed_lock, flags);
 
+			add_wait_queue (&op_wakeup, &wait);
 			current->state = TASK_UNINTERRUPTIBLE;
-			if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
-				remove_wait_queue (&op_wakeup, &wait); 
-			else
+			if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
 				err("unlink URB timeout!");
+			remove_wait_queue (&op_wakeup, &wait); 
 		} else 
 			urb_rm_priv (urb);
+
+		urb->status = -ENOENT;	// mark urb as killed		
+		if (urb->complete)
+			urb->complete ((struct urb *) urb);
 		usb_dec_dev_use (urb->dev);		
 	}	
 	return 0;
@@ -611,7 +613,7 @@
   		spin_unlock_irqrestore (&usb_ed_lock, flags);
   		
 		if (cnt > 0) {
-			dev->wait = &wait;
+			add_wait_queue (&op_wakeup, &wait);
 			current->state = TASK_UNINTERRUPTIBLE;
 			schedule_timeout (HZ / 10);
 			remove_wait_queue (&op_wakeup, &wait);
@@ -1160,10 +1162,8 @@
    	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
    	 		ed->state = ED_NEW; 
    	 		/* if all eds are removed wake up sohci_free_dev */
-   	 		if ((! --dev->ed_cnt) && dev->wait) {
-   	 			add_wait_queue (&op_wakeup, dev->wait); 
+   	 		if (!--dev->ed_cnt)
 				wake_up (&op_wakeup);
-			}
    	 	}
    	 	else {
    	 		ed->state &= ~ED_URB_DEL;
@@ -1283,7 +1283,7 @@
 {
 	0x12,       /*  __u8  bLength; */
 	0x01,       /*  __u8  bDescriptorType; Device */
-	0x00,	    /*  __u16 bcdUSB; v1.0 */
+	0x10,	    /*  __u16 bcdUSB; v1.1 */
 	0x01,
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
@@ -1332,7 +1332,7 @@
 	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
 	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
  	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
- 	0x08,       /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
  	0x00,
 	0xff        /*  __u8  ep_bInterval; 255 ms */
 };
@@ -1631,8 +1631,10 @@
 {
 	ohci_t * ohci = urb->dev->bus->hcpriv;
  
-	ohci->rh.send = 0;
-	del_timer (&ohci->rh.rh_int_timer);
+	if (ohci->rh.urb == urb) {
+		ohci->rh.send = 0;
+		del_timer (&ohci->rh.rh_int_timer);
+	}
 	return 0;
 }
  
@@ -1791,11 +1793,29 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* reinitialize after controller reset */
+
+static void hc_reinit_ohci (ohci_t *ohci)
+{
+	int i;
+
+	/* for load balancing of the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+	
+	ohci->ed_rm_list [0] = NULL;
+	ohci->ed_rm_list [1] = NULL;
+
+	/* end of control and bulk lists */	 
+	ohci->ed_isotail     = NULL;
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+} 
+
 /* allocate OHCI */
 
 static ohci_t * hc_alloc_ohci (void * mem_base)
 {
-	int i;
 	ohci_t * ohci;
 	struct usb_bus * bus;
 
@@ -1808,15 +1828,6 @@
 	ohci->irq = -1;
 	ohci->regs = mem_base;   
 
-	/* for load ballancing of the interrupt branches */
-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
-	
-	/* end of control and bulk lists */	 
-	ohci->ed_isotail     = NULL;
-	ohci->ed_controltail = NULL;
-	ohci->ed_bulktail    = NULL;
-
 	bus = usb_alloc_bus (&sohci_device_operations);
 	if (!bus) {
 		free_pages ((unsigned long) ohci, 1);
@@ -1829,6 +1840,7 @@
 	return ohci;
 } 
 
+
 /*-------------------------------------------------------------------------*/
 
 /* De-allocate all resources.. */
@@ -1924,21 +1936,9 @@
 {
 	unsigned long mem_base;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 	mem_base = dev->resource[0].start;
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
-#else
-	u16 cmd;
-
-	mem_base = dev->base_address[0];
-	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	/* Some Mac firmware will switch memory response off */
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
-#endif
 	
 	pci_set_master (dev);
 	mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
@@ -1998,15 +1998,47 @@
 	if (ohci) {
 		switch (rqst) {
 		case PM_SUSPEND:
-			dbg("USB-Bus suspend: %p", ohci->regs);
-			if (ohci->bus->root_hub)
-				usb_disconnect (&ohci->bus->root_hub);
-			hc_reset (ohci);
+			/* act as if usb suspend can always be used */
+			dbg("USB suspend: %p", ohci->regs);
+			ohci->hc_control = OHCI_USB_SUSPEND;
+			writel (ohci->hc_control, &ohci->regs->control);
+			wait_ms (10);
 			break;
+
 		case PM_RESUME:
-			dbg("USB-Bus resume: %p", ohci->regs);
-			if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
-				err ("can't restart controller, %d", temp);
+			/* did we suspend, or were we powered off? */
+			ohci->hc_control = readl (&ohci->regs->control);
+			temp = ohci->hc_control & OHCI_CTRL_HCFS;
+			switch (temp) {
+
+			case OHCI_USB_RESET:	// lost power
+				dbg("USB reset: %p", ohci->regs);
+				ohci->disabled = 1;
+				if (ohci->bus->root_hub)
+					usb_disconnect (&ohci->bus->root_hub);
+				hc_reinit_ohci (ohci);
+				if ((temp = hc_reset (ohci)) < 0
+					|| (temp = hc_start (ohci)) < 0) {
+					ohci->disabled = 1;
+					err ("can't restart, %d", temp);
+				}
+				dbg ("reset done");
+				break;
+
+			case OHCI_USB_SUSPEND:	// host wakeup
+			case OHCI_USB_RESUME:	// remote wakeup
+				dbg("USB resume: %p", ohci->regs);
+				ohci->hc_control = OHCI_USB_RESUME;
+				writel (ohci->hc_control, &ohci->regs->control);
+				wait_ms (20);
+
+				ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+				writel (ohci->hc_control, &ohci->regs->control);
+				break;
+
+			default:
+				warn ("odd PM_RESUME");
+			}
 			break;
 		}
 	}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)