patch-2.3.4 linux/drivers/usb/ohci-hcd.c

Next file: linux/drivers/usb/ohci-hcd.h
Previous file: linux/drivers/usb/mouse.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.3/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
@@ -3,12 +3,14 @@
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
  *
- * The OHCI HCD layer is a simple but nearly complete implementation of what the
- * USB people would call a HCD  for the OHCI. 
+ * The OHCI HCD layer is a simple but nearly complete implementation of what 
+ * the USB people would call a HCD  for the OHCI. 
  * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
- * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * The layer on top of it, is for interfacing to the alternate-usb 
+ * device-drivers.
  * 
- * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments 
+ * (0.03c source tree). ]
  * [ Open Host Controller Interface driver for USB. ]
  * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
  * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
@@ -51,9 +53,6 @@
 
 #include "usb.h"
 #include "ohci-hcd.h"
-#include "inits.h" 
-
- 
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
@@ -62,7 +61,7 @@
 #endif
 
  
-
+static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
 static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
 static DECLARE_WAIT_QUEUE_HEAD(root_hub);
  
@@ -122,7 +121,19 @@
 	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
     return 0;                       
 } 
-                                                             
+
+static int sohci_bulk_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
+{  
+	*(int * )lw0 = status;
+	wake_up(&bulk_wakeup);
+
+	OHCI_DEBUG( { int i; printk("USB HC BULK<<<: %x:", ep_addr, ctrl_len);)
+	OHCI_DEBUG( printk(" data(%d):", data_len);) 
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+    return 0;                       
+}
+                                                           
 static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
 	struct ohci * ohci = usb_dev->bus->hcpriv;
@@ -179,6 +190,40 @@
 	return cc_to_status[status & 0x0f];
 }
 
+static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	int status;
+	union ep_addr_ ep_addr;
+
+    ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */		
+				| (pipe  & 0x80)  				/* direction */
+				|  (11 << 5);					/* type = bulk*/
+	ep_addr.bep.fa	= ((pipe >> 8) & 0x7f);				/* device address */
+	
+	status = 0xf; /* CC not Accessed */
+	OHCI_DEBUG( { int i; printk("USB HC BULK>>>: %x:", ep_addr.iep);)
+	OHCI_DEBUG( printk(" data(%d):", len);) 
+	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk("\n"); })
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_bulk_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+	current->state = TASK_UNINTERRUPTIBLE;
+    add_wait_queue(&bulk_wakeup, &wait);   
+ 
+	ohci_trans_req(ohci, ep_addr.iep, 0, NULL, data, len, (__OHCI_BAG) &status, 0);
+
+	schedule_timeout(HZ/10);
+
+    remove_wait_queue(&bulk_wakeup, &wait); 
+     
+    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
+     
+	return cc_to_status[status & 0x0f];
+}
 
 static int sohci_usb_deallocate(struct usb_device *usb_dev) {
     struct ohci_device *dev = usb_to_ohci(usb_dev); 
@@ -234,8 +279,6 @@
 	return usb_dev;
 }
 
-/* FIXME! */
-#define sohci_bulk_msg NULL
 
 struct usb_operations sohci_device_operations = {
 	sohci_usb_allocate,
@@ -567,7 +610,7 @@
   }
   writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
   writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
-  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
+  writel_set((0x03<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
 
   spin_unlock_irqrestore(&usb_ed_lock, flags);
   
@@ -915,6 +958,7 @@
 {
    /*  int fminterval; */
     unsigned int mask;
+    int port_nr;
   /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
 	reset_hc(ohci); */
  
@@ -926,16 +970,19 @@
 	/* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
 		OHCI_INTR_FNO */
 		
-
+	if(readl(&ohci->regs->roothub.a) & 0x100) /* global power on */
+ 		writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
+	else { /* port power on */
+ 		for(port_nr=0; port_nr < (ohci->regs->roothub.a & 0xff); port_nr++)
+	     		 writel(0x100, &ohci->regs->roothub.portstatus[port_nr]);
+	}
+	wait_ms(50); 		
 	 
 	writel((0x00), &ohci->regs->control); /* USB Reset BUS */
 	wait_ms(10);
 	  
-	writel((0x97), &ohci->regs->control); /* USB Operational  */
-	
- 	writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
-	wait_ms(50); 
-		
+	writel((0xB7), &ohci->regs->control); /* USB Operational  */
+ 		
 	OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
  	OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
  	OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
@@ -952,15 +999,15 @@
 
 	struct usb_device * usb_dev;
 	struct ohci_device *dev;
-
-	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	struct ohci_device *tmp_root_hub= usb_to_ohci(ohci->bus->root_hub);
+	usb_dev = sohci_usb_allocate(tmp_root_hub->usb);
 	dev = usb_dev->hcpriv; 
 
 	dev->ohci = ohci; 
 
 	usb_connect(usb_dev);
 
-	ohci->root_hub->usb->children[0] = usb_dev;
+	tmp_root_hub->usb->children[0] = usb_dev;
 
 	usb_new_device(usb_dev);
 	}
@@ -1037,6 +1084,7 @@
 {
 	struct usb_device *usb_dev;
     struct ohci_device *dev;
+	struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub);
 	OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
 
 	/*
@@ -1046,7 +1094,7 @@
 	 *
 	 * So start off by getting rid of any old devices..
 	 */
-	usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
+	usb_disconnect(&tmp_root_hub->usb->children[port_nr]);
 
 	 if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
 	 	writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
@@ -1056,11 +1104,11 @@
 	 * Ok, we got a new connection. Allocate a device to it,
 	 * and find out what it wants to do..
 	 */
-	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	usb_dev = sohci_usb_allocate(tmp_root_hub->usb);
 	dev = usb_dev->hcpriv; 
 	dev->ohci = ohci; 
 	usb_connect(dev->usb);
-	ohci->root_hub->usb->children[port_nr] = usb_dev;
+	tmp_root_hub->usb->children[port_nr] = usb_dev;
 	wait_ms(200); /* wait for powerup */
     /* reset port/device */
  	writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
@@ -1205,10 +1253,9 @@
 	if (!usb)
 		return NULL;
 
-	dev = ohci->root_hub = usb_to_ohci(usb);
-
+	dev = usb_to_ohci(usb);
 	usb->bus = bus;
-	/* bus->root_hub = ohci_to_usb(ohci->root_hub); */
+	bus->root_hub = usb;
 	dev->ohci = ohci;
 	
 	/* Initialize the root hub */
@@ -1227,10 +1274,11 @@
 static void release_ohci(struct ohci *ohci)
 {
 	int i;
+	struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub);
 	union ep_addr_ ep_addr;
 	ep_addr.iep = 0;
 	
-    OHCI_DEBUG(printk("USB HC release ohci \n");)
+	OHCI_DEBUG(printk("USB HC release ohci \n"););
     
 	if (ohci->irq >= 0) {
 		free_irq(ohci->irq, ohci);
@@ -1248,25 +1296,22 @@
 	ohci_rm_eds(ohci); /* remove eds */
 	
     /* disconnect all devices */    
-	if(ohci->root_hub)
-		for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
-			  usb_disconnect(ohci->root_hub->usb->children + i);
+	if(ohci->bus->root_hub)
+		for(i = 0; i < tmp_root_hub->usb->maxchild; i++)
+			usb_disconnect(tmp_root_hub->usb->children + i);
 	    
-    USB_FREE(ohci->root_hub->usb);
-    USB_FREE(ohci->root_hub);
+    usb_deregister_bus(ohci->bus);
+    USB_FREE(tmp_root_hub->usb);
+    USB_FREE(tmp_root_hub);
     USB_FREE(ohci->bus);
     
 	/* unmap the IO address space */
 	iounmap(ohci->regs);
        
-	
 	free_pages((unsigned int) ohci->hc_area, 1);
 	
 }
 
- 
-void cleanup_drivers(void);
-
 static int ohci_roothub_thread(void * __ohci)
 {
         struct ohci *ohci = (struct ohci *)__ohci;
@@ -1288,6 +1333,7 @@
 		start_hc(ohci);
 		writel( 0x10000, &ohci->regs->roothub.status);
 		wait_ms(50); /* root hub power on */
+	usb_register_bus(ohci->bus);
          do {
 #ifdef CONFIG_APM
 		if (apm_resume) {
@@ -1297,7 +1343,7 @@
 		}
 #endif
  	 
-         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
+		OHCI_DEBUG(printk("USB RH tasks: int: %x\n",ohci->intrstatus););
 #ifndef VROOTHUB
 		/*	if (ohci->intrstatus & OHCI_INTR_RHSC)  */
 			{
@@ -1332,9 +1378,6 @@
         return 0;
 }
 
-
- 
-
 /*
  * Increment the module usage count, start the control thread and
  * return success.
@@ -1432,20 +1475,6 @@
 }
 #endif
 
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-	apm_unregister_callback(&handle_apm_event);
-#endif
-}
-
-#define ohci_hcd_init init_module
-
-#endif
-
 #define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
 #define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
  
@@ -1471,3 +1500,17 @@
   }
   return retval;
 }
+
+#ifdef MODULE
+int init_module(void){
+	return ohci_hcd_init();
+}
+
+void cleanup_module(void)
+{
+#	ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#	endif
+}
+#endif //MODULE
+

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