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