Greg:

This and the next few patches centralize most of the functionality
required for creating, registering, and removing hcd and bus structures
into the core.  They remove a lot of duplication among various HC drivers
and also fix a bug that affected all the drivers, causing them to call
their stop() routines when start() returned an error.

This patch contains the core modifications: the new functions are added to 
hcd.c and the messy code in hcd-pci.c can simply call the new routines (a 
big cleanup).  It also changes the string used when registering a driver's 
IRQ line to include the bus number as well as the driver name -- which was 
the original impetus for writing all these patches in the first place!

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

diff -u a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c        Sat Dec 18 13:54:45 2004
+++ b/drivers/usb/core/hcd-pci.c        Sat Dec 18 15:36:09 2004
@@ -60,7 +60,6 @@
        void __iomem            *base;
        struct usb_hcd          *hcd;
        int                     retval, region;
-       char                    buf [8], *bufp = buf;
 
        if (usb_disabled())
                return -ENODEV;
@@ -78,7 +77,7 @@
                        "Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",
                        pci_name(dev));
                retval = -ENODEV;
-               goto done;
+               goto err1;
         }
        
        if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
@@ -88,23 +87,20 @@
                if (!request_mem_region (resource, len, driver->description)) {
                        dev_dbg (&dev->dev, "controller already in use\n");
                        retval = -EBUSY;
-                       goto done;
+                       goto err1;
                }
                base = ioremap_nocache (resource, len);
                if (base == NULL) {
                        dev_dbg (&dev->dev, "error mapping memory\n");
                        retval = -EFAULT;
-clean_1:
-                       release_mem_region (resource, len);
-                       dev_err (&dev->dev, "init %s fail, %d\n",
-                               pci_name(dev), retval);
-                       goto done;
+                       goto err2;
                }
 
        } else {                                // UHCI
                resource = len = 0;
                for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+                       if (!(pci_resource_flags (dev, region) &
+                                       IORESOURCE_IO))
                                continue;
 
                        resource = pci_resource_start (dev, region);
@@ -116,84 +112,43 @@
                if (region == PCI_ROM_RESOURCE) {
                        dev_dbg (&dev->dev, "no i/o regions available\n");
                        retval = -EBUSY;
-                       goto done;
+                       goto err1;
                }
                base = (void __iomem *) resource;
        }
 
-       // driver->reset(), later on, will transfer device from
-       // control by SMM/BIOS to control by Linux (if needed)
-
-       hcd = usb_create_hcd (driver);
-       if (hcd == NULL){
-               dev_dbg (&dev->dev, "hcd alloc fail\n");
+       hcd = usb_create_hcd (driver, &dev->dev, base, pci_name(dev));
+       if (!hcd) {
                retval = -ENOMEM;
-clean_2:
-               if (driver->flags & HCD_MEMORY) {
-                       iounmap (base);
-                       goto clean_1;
-               } else {
-                       release_region (resource, len);
-                       dev_err (&dev->dev, "init %s fail, %d\n",
-                               pci_name(dev), retval);
-                       goto done;
-               }
+               goto err3;
        }
-       // hcd zeroed everything
-       hcd->regs = base;
-       hcd->region = region;
 
-       pci_set_drvdata (dev, hcd);
-       hcd->self.bus_name = pci_name(dev);
+       hcd->region = region;
 #ifdef CONFIG_PCI_NAMES
        hcd->product_desc = dev->pretty_name;
 #endif
-       hcd->self.controller = &dev->dev;
-
-       if ((retval = hcd_buffer_create (hcd)) != 0) {
-clean_3:
-               pci_set_drvdata (dev, NULL);
-               usb_put_hcd (hcd);
-               goto clean_2;
-       }
-
-       dev_info (hcd->self.controller, "%s\n", hcd->product_desc);
-
-       /* till now HC has been in an indeterminate state ... */
-       if (driver->reset && (retval = driver->reset (hcd)) < 0) {
-               dev_err (hcd->self.controller, "can't reset\n");
-               goto clean_3;
-       }
 
+       pci_set_drvdata (dev, hcd);
        pci_set_master (dev);
-#ifndef __sparc__
-       sprintf (buf, "%d", dev->irq);
-#else
-       bufp = __irq_itoa(dev->irq);
-#endif
-       retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
-                               hcd->driver->description, hcd);
-       if (retval != 0) {
-               dev_err (hcd->self.controller,
-                               "request interrupt %s failed\n", bufp);
-               goto clean_3;
-       }
-       hcd->irq = dev->irq;
-
-       dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
-               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
-               resource);
 
-       usb_register_bus (&hcd->self);
-
-       if ((retval = driver->start (hcd)) < 0) {
-               dev_err (hcd->self.controller, "init error %d\n", retval);
-               usb_hcd_pci_remove (dev);
-       }
+       if ((retval = usb_add_hcd (hcd, dev->irq, usb_hcd_irq, SA_SHIRQ,
+                       resource)) != 0)
+               goto err4;
+       return retval;
 
-done:
-       if (retval != 0)
-               pci_disable_device (dev);
+ err4:
+       pci_set_drvdata (dev, NULL);
+       usb_put_hcd (hcd);
+ err3:
+       if (driver->flags & HCD_MEMORY) {
+               iounmap (base);
+ err2:
+               release_mem_region (resource, len);
+       } else
+               release_region (resource, len);
+       dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
+ err1:
+       pci_disable_device (dev);
        return retval;
 } 
 EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -220,23 +175,10 @@
        hcd = pci_get_drvdata(dev);
        if (!hcd)
                return;
-       dev_info (hcd->self.controller, "remove, state %x\n", hcd->state);
 
-       if (in_interrupt ())
-               BUG ();
+       usb_remove_hcd (hcd);
+       pci_set_drvdata (dev, NULL);
 
-       if (HCD_IS_RUNNING (hcd->state))
-               hcd->state = USB_STATE_QUIESCING;
-
-       dev_dbg (hcd->self.controller, "roothub graceful disconnect\n");
-       usb_disconnect (&hcd->self.root_hub);
-
-       hcd->driver->stop (hcd);
-       hcd_buffer_destroy (hcd);
-       hcd->state = USB_STATE_HALT;
-       pci_set_drvdata(dev, NULL);
-
-       free_irq (hcd->irq, hcd);
        if (hcd->driver->flags & HCD_MEMORY) {
                iounmap (hcd->regs);
                release_mem_region (pci_resource_start (dev, 0),
@@ -245,9 +187,7 @@
                release_region (pci_resource_start (dev, hcd->region),
                        pci_resource_len (dev, hcd->region));
        }
-
-       usb_deregister_bus (&hcd->self);
-
+       usb_put_hcd (hcd);
        pci_disable_device(dev);
 }
 EXPORT_SYMBOL (usb_hcd_pci_remove);
diff -u a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c    Sat Dec 18 13:54:45 2004
+++ b/drivers/usb/core/hcd.c    Sat Dec 18 15:36:09 2004
@@ -779,7 +779,7 @@
 
        clear_bit (bus->busnum, busmap.busmap);
 
-       class_device_unregister(&bus->class_dev);
+       class_device_del(&bus->class_dev);
 }
 EXPORT_SYMBOL (usb_deregister_bus);
 
@@ -1557,6 +1557,9 @@
 /**
  * usb_create_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @regs: value to store in hcd->regs
+ * @bus_name: value to store in hcd->self.bus_name
  * Context: !in_interrupt()
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
@@ -1565,18 +1568,23 @@
  *
  * If memory is unavailable, returns NULL.
  */
-struct usb_hcd *usb_create_hcd (const struct hc_driver *driver)
+struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+               struct device *dev, void __iomem *regs, char *bus_name)
 {
        struct usb_hcd *hcd;
 
        hcd = kcalloc(1, sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
-       if (!hcd)
+       if (!hcd) {
+               dev_dbg (dev, "hcd alloc failed\n");
                return NULL;
+       }
 
        usb_bus_init(&hcd->self);
        hcd->self.op = &usb_hcd_operations;
        hcd->self.hcpriv = hcd;
        hcd->self.release = &hcd_release;
+       hcd->self.controller = dev;
+       hcd->self.bus_name = bus_name;
 
        init_timer(&hcd->rh_timer);
 
@@ -1584,6 +1592,7 @@
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
                        "USB Host Controller";
        hcd->state = USB_STATE_HALT;
+       hcd->regs = regs;
 
        return hcd;
 }
@@ -1594,3 +1603,109 @@
        usb_bus_put(&hcd->self);
 }
 EXPORT_SYMBOL (usb_put_hcd);
+
+/**
+ * usb_add_hcd - finish generic HCD structure initialization and register
+ * @hcd: the usb_hcd structure to initialize
+ * @irqnum: Interrupt line to allocate
+ * @irqfunc: IRQ handler function
+ * @irqflags: Interrupt type flags
+ * @resource: I/O or memory resource value
+ *
+ * Finish the remaining parts of generic HCD initialization: allocate the
+ * buffers of consistent memory, register the bus, request the IRQ line,
+ * and call the driver's reset() and start() routines.
+ */
+int usb_add_hcd(struct usb_hcd *hcd,
+               unsigned int irqnum,
+               irqreturn_t (*irqfunc)(int, void *, struct pt_regs *),
+               unsigned long irqflags,
+               unsigned long resource)
+{
+       char    buf[8], *bufp = buf;
+       int     retval;
+
+       dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+
+       /* till now HC has been in an indeterminate state ... */
+       if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+               dev_err(hcd->self.controller, "can't reset\n");
+               return retval;
+       }
+
+       if ((retval = hcd_buffer_create(hcd)) != 0) {
+               dev_dbg(hcd->self.controller, "pool alloc failed\n");
+               return retval;
+       }
+
+       if ((retval = usb_register_bus(&hcd->self)) < 0)
+               goto err1;
+
+       if (irqfunc) {
+
+#ifdef __sparc__
+               bufp = __irq_itoa(irqnum);
+#else
+               sprintf(buf, "%d", irqnum);
+#endif
+
+               snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+                               hcd->driver->description, hcd->self.busnum);
+               if ((retval = request_irq(irqnum, irqfunc, irqflags,
+                               hcd->irq_descr, hcd)) != 0) {
+                       dev_err(hcd->self.controller,
+                                       "request interrupt %s failed\n", bufp);
+                       goto err2;
+               }
+               hcd->irq = irqnum;
+               dev_info(hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
+                               (hcd->driver->flags & HCD_MEMORY) ?
+                                       "pci mem" : "io base", resource);
+       } else
+               hcd->irq = -1;
+
+       if ((retval = hcd->driver->start(hcd)) < 0) {
+               dev_err(hcd->self.controller, "startup error %d\n", retval);
+               goto err3;
+       }
+
+       return retval;
+
+ err3:
+       if (irqfunc)
+               free_irq(irqnum, hcd);
+ err2:
+       usb_deregister_bus(&hcd->self);
+ err1:
+       hcd_buffer_destroy(hcd);
+       return retval;
+} 
+EXPORT_SYMBOL (usb_add_hcd);
+
+/**
+ * usb_remove_hcd - shutdown processing for generic HCDs
+ * @hcd: the usb_hcd structure to remove
+ * Context: !in_interrupt()
+ *
+ * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() method.
+ */
+void usb_remove_hcd(struct usb_hcd *hcd)
+{
+       dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
+
+       if (HCD_IS_RUNNING (hcd->state))
+               hcd->state = USB_STATE_QUIESCING;
+
+       dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");
+       usb_disconnect(&hcd->self.root_hub);
+
+       hcd->driver->stop(hcd);
+       hcd->state = USB_STATE_HALT;
+
+       if (hcd->irq >= 0)
+               free_irq(hcd->irq, hcd);
+       usb_deregister_bus(&hcd->self);
+       hcd_buffer_destroy(hcd);
+}
+EXPORT_SYMBOL (usb_remove_hcd);
diff -u a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h    Sat Dec 18 13:54:45 2004
+++ b/drivers/usb/core/hcd.h    Sat Dec 18 15:36:09 2004
@@ -63,6 +63,7 @@
        struct usb_bus          self;           /* hcd is-a bus */
 
        const char              *product_desc;  /* product/vendor string */
+       char                    irq_descr[24];  /* driver + bus # */
 
        struct timer_list       rh_timer;       /* drives root hub */
 
@@ -211,9 +212,15 @@
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct 
pt_regs *regs);
 extern void usb_bus_init (struct usb_bus *bus);
 
-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver);
+extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+               struct device *dev, void __iomem *regs, char *bus_name);
 extern void usb_put_hcd (struct usb_hcd *hcd);
-
+extern int usb_add_hcd(struct usb_hcd *hcd,
+               unsigned int irqnum,
+               irqreturn_t (*irqfunc)(int, void *, struct pt_regs *),
+               unsigned long irqflags,
+               unsigned long resource);
+extern void usb_remove_hcd(struct usb_hcd *hcd);
 
 #ifdef CONFIG_PCI
 struct pci_dev;



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. 
http://productguide.itmanagersjournal.com/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to