Commit 15b7329c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

USB: hcd cleanups and documentation

Implement many of the hcd cleanups that David Brownell had previously submitted.
parent 306ef798
/* /*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000-2002 * (C) Copyright David Brownell 2000-2002
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
...@@ -39,8 +33,6 @@ ...@@ -39,8 +33,6 @@
/* PCI-based HCs are normal, but custom bus glue should be ok */ /* PCI-based HCs are normal, but custom bus glue should be ok */
static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
static void hc_died (struct usb_hcd *hcd);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -156,7 +148,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -156,7 +148,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
#else #else
bufp = __irq_itoa(dev->irq); bufp = __irq_itoa(dev->irq);
#endif #endif
if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd) if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
!= 0) { != 0) {
err ("request interrupt %s failed", bufp); err ("request interrupt %s failed", bufp);
retval = -EBUSY; retval = -EBUSY;
...@@ -171,8 +163,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -171,8 +163,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base", (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base); base);
usb_init_bus (&hcd->self); usb_bus_init (&hcd->self);
hcd->self.op = &hcd_operations; hcd->self.op = &usb_hcd_operations;
hcd->self.hcpriv = (void *) hcd; hcd->self.hcpriv = (void *) hcd;
hcd->self.bus_name = dev->slot_name; hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->name; hcd->product_desc = dev->name;
...@@ -336,7 +328,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -336,7 +328,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
retval = hcd->driver->resume (hcd); retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) { if (!HCD_IS_RUNNING (hcd->state)) {
dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval); dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
hc_died (hcd); usb_hc_died (hcd);
// FIXME: recover, reset etc. // FIXME: recover, reset etc.
} else { } else {
// FIXME for all connected devices, root-to-leaf: // FIXME for all connected devices, root-to-leaf:
...@@ -352,50 +344,4 @@ EXPORT_SYMBOL (usb_hcd_pci_resume); ...@@ -352,50 +344,4 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
{
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return;
hcd->driver->irq (hcd);
if (hcd->state != start && hcd->state == USB_STATE_HALT)
hc_died (hcd);
}
/*-------------------------------------------------------------------------*/
static void hc_died (struct usb_hcd *hcd)
{
struct list_head *devlist, *urblist;
struct hcd_dev *dev;
struct urb *urb;
unsigned long flags;
/* flag every pending urb as done */
spin_lock_irqsave (&hcd_data_lock, flags);
list_for_each (devlist, &hcd->dev_list) {
dev = list_entry (devlist, struct hcd_dev, dev_list);
list_for_each (urblist, &dev->urb_list) {
urb = list_entry (urblist, struct urb, urb_list);
dbg ("shutdown %s urb %p pipe %x, current status %d",
hcd->self.bus_name, urb, urb->pipe, urb->status);
if (urb->status == -EINPROGRESS)
urb->status = -ESHUTDOWN;
}
}
urb = (struct urb *) hcd->rh_timer.data;
if (urb)
urb->status = -ESHUTDOWN;
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (urb)
usb_rh_status_dequeue (hcd, urb);
hcd->driver->stop (hcd);
}
...@@ -92,9 +92,7 @@ static struct usb_busmap busmap; ...@@ -92,9 +92,7 @@ static struct usb_busmap busmap;
DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */
/* used when updating hcd data */ /* used when updating hcd data */
spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
struct usb_operations hcd_operations;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -571,8 +569,14 @@ void usb_bus_put (struct usb_bus *bus) ...@@ -571,8 +569,14 @@ void usb_bus_put (struct usb_bus *bus)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* shared initialization code */ /**
void usb_init_bus (struct usb_bus *bus) * usb_bus_init - shared initialization code
* @bus: the bus structure being initialized
*
* This code is used to initialize a usb_bus structure, memory for which is
* separately managed.
*/
void usb_bus_init (struct usb_bus *bus)
{ {
memset (&bus->devmap, 0, sizeof(struct usb_devmap)); memset (&bus->devmap, 0, sizeof(struct usb_devmap));
...@@ -591,6 +595,7 @@ void usb_init_bus (struct usb_bus *bus) ...@@ -591,6 +595,7 @@ void usb_init_bus (struct usb_bus *bus)
atomic_set (&bus->refcnt, 1); atomic_set (&bus->refcnt, 1);
} }
EXPORT_SYMBOL (usb_bus_init);
/** /**
* usb_alloc_bus - creates a new USB host controller structure * usb_alloc_bus - creates a new USB host controller structure
...@@ -611,7 +616,7 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) ...@@ -611,7 +616,7 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op)
bus = kmalloc (sizeof *bus, GFP_KERNEL); bus = kmalloc (sizeof *bus, GFP_KERNEL);
if (!bus) if (!bus)
return NULL; return NULL;
usb_init_bus (bus); usb_bus_init (bus);
bus->op = op; bus->op = op;
return bus; return bus;
} }
...@@ -1226,13 +1231,21 @@ static int hcd_free_dev (struct usb_device *udev) ...@@ -1226,13 +1231,21 @@ static int hcd_free_dev (struct usb_device *udev)
return 0; return 0;
} }
struct usb_operations hcd_operations = { /**
* usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
*
* When registering a USB bus through the HCD framework code, use this
* usb_operations vector. The PCI glue layer does so automatically; only
* bus glue for non-PCI system busses will need to use this.
*/
struct usb_operations usb_hcd_operations = {
allocate: hcd_alloc_dev, allocate: hcd_alloc_dev,
get_frame_number: hcd_get_frame_number, get_frame_number: hcd_get_frame_number,
submit_urb: hcd_submit_urb, submit_urb: hcd_submit_urb,
unlink_urb: hcd_unlink_urb, unlink_urb: hcd_unlink_urb,
deallocate: hcd_free_dev, deallocate: hcd_free_dev,
}; };
EXPORT_SYMBOL (usb_hcd_operations);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1272,3 +1285,70 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) ...@@ -1272,3 +1285,70 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
usb_put_urb (urb); usb_put_urb (urb);
} }
EXPORT_SYMBOL (usb_hcd_giveback_urb); EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
/**
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
* @__hcd: pointer to the HCD whose IRQ is beinng signaled
* @r: saved hardware registers (not passed to HCD)
*
* When registering a USB bus through the HCD framework code, use this
* to handle interrupts. The PCI glue layer does so automatically; only
* bus glue for non-PCI system busses will need to use this.
*/
void usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
{
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return;
hcd->driver->irq (hcd);
if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd);
}
EXPORT_SYMBOL (usb_hcd_irq);
/*-------------------------------------------------------------------------*/
/**
* usb_hc_died - report abnormal shutdown of a host controller (bus glue)
* @hcd: pointer to the HCD representing the controller
*
* This is called by bus glue to report a USB host controller that died
* while operations may still have been pending. It's called automatically
* by the PCI glue, so only glue for non-PCI busses should need to call it.
*/
void usb_hc_died (struct usb_hcd *hcd)
{
struct list_head *devlist, *urblist;
struct hcd_dev *dev;
struct urb *urb;
unsigned long flags;
/* flag every pending urb as done */
spin_lock_irqsave (&hcd_data_lock, flags);
list_for_each (devlist, &hcd->dev_list) {
dev = list_entry (devlist, struct hcd_dev, dev_list);
list_for_each (urblist, &dev->urb_list) {
urb = list_entry (urblist, struct urb, urb_list);
dbg ("shutdown %s urb %p pipe %x, current status %d",
hcd->self.bus_name, urb, urb->pipe, urb->status);
if (urb->status == -EINPROGRESS)
urb->status = -ESHUTDOWN;
}
}
urb = (struct urb *) hcd->rh_timer.data;
if (urb)
urb->status = -ESHUTDOWN;
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (urb)
usb_rh_status_dequeue (hcd, urb);
hcd->driver->stop (hcd);
}
EXPORT_SYMBOL (usb_hc_died);
...@@ -161,12 +161,9 @@ struct hc_driver { ...@@ -161,12 +161,9 @@ struct hc_driver {
}; };
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
extern void usb_init_bus (struct usb_bus *bus); extern void usb_bus_init (struct usb_bus *bus);
extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb); extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
extern spinlock_t hcd_data_lock;
extern struct usb_operations hcd_operations;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
struct pci_dev; struct pci_dev;
struct pci_device_id; struct pci_device_id;
...@@ -184,6 +181,11 @@ extern int usb_hcd_pci_resume (struct pci_dev *dev); ...@@ -184,6 +181,11 @@ extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* generic bus glue, needed for host controllers that don't use PCI */
extern struct usb_operations usb_hcd_operations;
extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
extern void usb_hc_died (struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Enumeration is only for the hub driver, or HCD virtual root hubs */ /* Enumeration is only for the hub driver, or HCD virtual root hubs */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment