X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fhcd.c;h=9e82afc3389c9078b4aad89bd293cfd22d8c15d8;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=dc67f3ddf425272fb11505578067a4d0003a9a56;hpb=5167311cae6aa3a5ff5afd39f88c32a435c969ef;p=linux-2.6.git diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index dc67f3ddf..9e82afc33 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -23,28 +23,25 @@ */ #include - -#ifdef CONFIG_USB_DEBUG -#define DEBUG -#endif - #include #include #include #include #include -#include /* for UTS_SYSNAME */ +#include #include #include #include #include #include +#include #include #include #include "usb.h" #include "hcd.h" +#include "hub.h" // #define USB_BANDWIDTH_MESSAGES @@ -99,8 +96,11 @@ static struct usb_busmap busmap; DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ EXPORT_SYMBOL_GPL (usb_bus_list_lock); +/* used for controlling access to virtual root hubs */ +static DEFINE_SPINLOCK(hcd_root_hub_lock); + /* used when updating hcd data */ -static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(hcd_data_lock); /* wait queue for synchronous unlinks */ DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); @@ -120,16 +120,16 @@ DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); static const u8 usb2_rh_dev_descriptor [18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ - 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ + 0x00, 0x02, /* __le16 bcdUSB; v2.0 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ + 0x00, 0x00, /* __le16 idVendor; */ + 0x00, 0x00, /* __le16 idProduct; */ + KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -143,16 +143,16 @@ static const u8 usb2_rh_dev_descriptor [18] = { static const u8 usb11_rh_dev_descriptor [18] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ - 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ + 0x10, 0x01, /* __le16 bcdUSB; v1.1 */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ + 0x00, 0x00, /* __le16 idVendor; */ + 0x00, 0x00, /* __le16 idProduct; */ + KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -170,7 +170,7 @@ static const u8 fs_rh_config_descriptor [] = { /* one configuration */ 0x09, /* __u8 bLength; */ 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ + 0x19, 0x00, /* __le16 wTotalLength; */ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ @@ -208,7 +208,7 @@ static const u8 fs_rh_config_descriptor [] = { 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; @@ -217,7 +217,7 @@ static const u8 hs_rh_config_descriptor [] = { /* one configuration */ 0x09, /* __u8 bLength; */ 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ + 0x19, 0x00, /* __le16 wTotalLength; */ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ @@ -255,7 +255,7 @@ static const u8 hs_rh_config_descriptor [] = { 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ }; @@ -273,6 +273,10 @@ static int ascii2utf (char *s, u8 *utf, int utfmax) *utf++ = *s++; *utf++ = 0; } + if (utfmax > 0) { + *utf = *s; + ++retval; + } return retval; } @@ -297,30 +301,40 @@ static int rh_string ( // language ids if (id == 0) { - *data++ = 4; *data++ = 3; /* 4 bytes string data */ - *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */ - return 4; + buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ + buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ + len = min (len, 4); + memcpy (data, buf, len); + return len; // serial number } else if (id == 1) { - strcpy (buf, hcd->self.bus_name); + strlcpy (buf, hcd->self.bus_name, sizeof buf); // product description } else if (id == 2) { - strcpy (buf, hcd->product_desc); + strlcpy (buf, hcd->product_desc, sizeof buf); // id 3 == vendor description } else if (id == 3) { - sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, - hcd->description); + snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname, + system_utsname.release, hcd->driver->description); // unsupported IDs --> "protocol stall" } else - return 0; + return -EPIPE; - data [0] = 2 * (strlen (buf) + 1); - data [1] = 3; /* type == string */ - return 2 + ascii2utf (buf, data + 2, len - 2); + switch (len) { /* All cases fall through */ + default: + len = 2 + ascii2utf (buf, data + 2, len - 2); + case 2: + data [1] = 3; /* type == string */ + case 1: + data [0] = 2 * (strlen (buf) + 1); + case 0: + ; /* Compiler wants a statement here */ + } + return len; } @@ -329,11 +343,15 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) { struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; - const u8 *bufp = NULL; u8 *ubuf = urb->transfer_buffer; + u8 tbuf [sizeof (struct usb_hub_descriptor)] + __attribute__((aligned(4))); + const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; unsigned long flags; + int status = 0; + int n; cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; @@ -344,17 +362,16 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) if (wLength > urb->transfer_buffer_length) goto error; - /* set up for success */ - urb->status = 0; - urb->actual_length = wLength; + urb->actual_length = 0; switch (typeReq) { /* DEVICE REQUESTS */ case DeviceRequest | USB_REQ_GET_STATUS: - ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) + tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); - ubuf [1] = 0; + tbuf [1] = 0; + len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (wValue == USB_DEVICE_REMOTE_WAKEUP) @@ -369,7 +386,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) goto error; break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - ubuf [0] = 1; + tbuf [0] = 1; + len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: break; @@ -396,16 +414,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) patch_wakeup = 1; break; case USB_DT_STRING << 8: - urb->actual_length = rh_string ( - wValue & 0xff, hcd, - ubuf, wLength); + n = rh_string (wValue & 0xff, hcd, ubuf, wLength); + if (n < 0) + goto error; + urb->actual_length = n; break; default: goto error; } break; case DeviceRequest | USB_REQ_GET_INTERFACE: - ubuf [0] = 0; + tbuf [0] = 0; + len = 1; /* FALLTHROUGH */ case DeviceOutRequest | USB_REQ_SET_INTERFACE: break; @@ -421,8 +441,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) case EndpointRequest | USB_REQ_GET_STATUS: // ENDPOINT_HALT flag - ubuf [0] = 0; - ubuf [1] = 0; + tbuf [0] = 0; + tbuf [1] = 0; + len = 2; /* FALLTHROUGH */ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_SET_FEATURE: @@ -433,28 +454,35 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) default: /* non-generic request */ - if (HCD_IS_SUSPENDED (hcd->state)) - urb->status = -EAGAIN; - else - urb->status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - ubuf, wLength); + switch (typeReq) { + case GetHubStatus: + case GetPortStatus: + len = 4; + break; + case GetHubDescriptor: + len = sizeof (struct usb_hub_descriptor); + break; + } + status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + tbuf, wLength); break; error: /* "protocol stall" on error */ - urb->status = -EPIPE; + status = -EPIPE; } - if (urb->status) { - urb->actual_length = 0; - if (urb->status != -EPIPE) { + + if (status) { + len = 0; + if (status != -EPIPE) { dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x " "idx=0x%x len=%d ==> %d\n", typeReq, wValue, wIndex, - wLength, urb->status); + wLength, status); } } - if (bufp) { + if (len) { if (urb->transfer_buffer_length < len) len = urb->transfer_buffer_length; urb->actual_length = len; @@ -462,13 +490,19 @@ error: memcpy (ubuf, bufp, len); /* report whether RH hardware supports remote wakeup */ - if (patch_wakeup) + if (patch_wakeup && + len > offsetof (struct usb_config_descriptor, + bmAttributes)) ((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } /* any errors get returned through the urb completion */ local_irq_save (flags); + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock (&urb->lock); usb_hcd_giveback_urb (hcd, urb, NULL); local_irq_restore (flags); return 0; @@ -477,119 +511,120 @@ error: /*-------------------------------------------------------------------------*/ /* - * Root Hub interrupt transfers are synthesized with a timer. - * Completions are called in_interrupt() but not in_irq(). + * Root Hub interrupt transfers are polled using a timer if the + * driver requests it; otherwise the driver is responsible for + * calling usb_hcd_poll_rh_status() when an event occurs. * - * Note: some root hubs (including common UHCI based designs) can't - * correctly issue port change IRQs. They're the ones that _need_ a - * timer; most other root hubs don't. Some systems could save a - * lot of battery power by eliminating these root hub timer IRQs. + * Completions are called in_interrupt(), but they may or may not + * be in_irq(). */ +void usb_hcd_poll_rh_status(struct usb_hcd *hcd) +{ + struct urb *urb; + int length; + unsigned long flags; + char buffer[4]; /* Any root hubs with > 31 ports? */ -static void rh_report_status (unsigned long ptr); + if (!hcd->uses_new_polling && !hcd->status_urb) + return; -static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) -{ - int len = 1 + (urb->dev->maxchild / 8); + length = hcd->driver->hub_status_data(hcd, buffer); + if (length > 0) { - /* rh_timer protected by hcd_data_lock */ - if (hcd->rh_timer.data || urb->transfer_buffer_length < len) { - dev_dbg (hcd->self.controller, - "not queuing rh status urb, stat %d\n", - urb->status); - return -EINVAL; + /* try to complete the status urb */ + local_irq_save (flags); + spin_lock(&hcd_root_hub_lock); + urb = hcd->status_urb; + if (urb) { + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) { + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + } else /* urb has been unlinked */ + length = 0; + spin_unlock(&urb->lock); + } else + length = 0; + spin_unlock(&hcd_root_hub_lock); + + /* local irqs are always blocked in completions */ + if (length > 0) + usb_hcd_giveback_urb (hcd, urb, NULL); + else + hcd->poll_pending = 1; + local_irq_restore (flags); } - init_timer (&hcd->rh_timer); - hcd->rh_timer.function = rh_report_status; - hcd->rh_timer.data = (unsigned long) urb; - /* USB 2.0 spec says 256msec; this is close enough */ - hcd->rh_timer.expires = jiffies + HZ/4; - add_timer (&hcd->rh_timer); - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ - return 0; + /* The USB 2.0 spec says 256 ms. This is close enough and won't + * exceed that limit if HZ is 100. */ + if (hcd->uses_new_polling ? hcd->poll_rh : + (length == 0 && hcd->status_urb != NULL)) + mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250)); } +EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); /* timer callback */ +static void rh_timer_func (unsigned long _hcd) +{ + usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); +} + +/*-------------------------------------------------------------------------*/ -static void rh_report_status (unsigned long ptr) +static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) { - struct urb *urb; - struct usb_hcd *hcd; - int length = 0; + int retval; unsigned long flags; + int len = 1 + (urb->dev->maxchild / 8); + + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (urb->status != -EINPROGRESS) /* already unlinked */ + retval = urb->status; + else if (hcd->status_urb || urb->transfer_buffer_length < len) { + dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); + retval = -EINVAL; + } else { + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ - urb = (struct urb *) ptr; - local_irq_save (flags); - spin_lock (&urb->lock); - - /* do nothing if the urb's been unlinked */ - if (!urb->dev - || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == 0) { - spin_unlock (&urb->lock); - local_irq_restore (flags); - return; - } + if (!hcd->uses_new_polling) + mod_timer (&hcd->rh_timer, jiffies + + msecs_to_jiffies(250)); - /* complete the status urb, or retrigger the timer */ - spin_lock (&hcd_data_lock); - if (urb->dev->state == USB_STATE_CONFIGURED) { - length = hcd->driver->hub_status_data ( - hcd, urb->transfer_buffer); - if (length > 0) { - hcd->rh_timer.data = 0; - urb->actual_length = length; - urb->status = 0; - urb->hcpriv = NULL; - } else - mod_timer (&hcd->rh_timer, jiffies + HZ/4); + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer (&hcd->rh_timer, jiffies); + retval = 0; } - spin_unlock (&hcd_data_lock); - spin_unlock (&urb->lock); - - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); + return retval; } -/*-------------------------------------------------------------------------*/ - static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) { - int retval; - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - retval = rh_status_urb (hcd, urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - return retval; - } + if (usb_pipeint (urb->pipe)) + return rh_queue_status (hcd, urb); if (usb_pipecontrol (urb->pipe)) return rh_call_control (hcd, urb); - else - return -EINVAL; + return -EINVAL; } /*-------------------------------------------------------------------------*/ +/* Asynchronous unlinks of root-hub control URBs are legal, but they + * don't do anything. Status URB unlinks must be made in process context + * with interrupts enabled. + */ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - - /* note: always a synchronous unlink */ - if ((unsigned long) urb == hcd->rh_timer.data) { - del_timer_sync (&hcd->rh_timer); - hcd->rh_timer.data = 0; - - local_irq_save (flags); - urb->hcpriv = NULL; - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); + if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (in_interrupt()) + return 0; /* nothing to do */ - } else if (usb_pipeendpoint(urb->pipe) == 0) { spin_lock_irq(&urb->lock); /* from usb_kill_urb */ ++urb->reject; spin_unlock_irq(&urb->lock); @@ -600,8 +635,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) spin_lock_irq(&urb->lock); --urb->reject; spin_unlock_irq(&urb->lock); - } else - return -EINVAL; + + } else { /* Status URB */ + if (!hcd->uses_new_polling) + del_timer_sync (&hcd->rh_timer); + local_irq_disable (); + spin_lock (&hcd_root_hub_lock); + if (urb == hcd->status_urb) { + hcd->status_urb = NULL; + urb->hcpriv = NULL; + } else + urb = NULL; /* wasn't fully queued */ + spin_unlock (&hcd_root_hub_lock); + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_enable (); + } return 0; } @@ -609,50 +658,45 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) /*-------------------------------------------------------------------------*/ /* exported only within usbcore */ -struct usb_bus *usb_bus_get (struct usb_bus *bus) +struct usb_bus *usb_bus_get(struct usb_bus *bus) { - struct class_device *tmp; + if (bus) + kref_get(&bus->kref); + return bus; +} - if (!bus) - return NULL; +static void usb_host_release(struct kref *kref) +{ + struct usb_bus *bus = container_of(kref, struct usb_bus, kref); - tmp = class_device_get(&bus->class_dev); - if (tmp) - return to_usb_bus(tmp); - else - return NULL; + if (bus->release) + bus->release(bus); } /* exported only within usbcore */ -void usb_bus_put (struct usb_bus *bus) +void usb_bus_put(struct usb_bus *bus) { if (bus) - class_device_put(&bus->class_dev); + kref_put(&bus->kref, usb_host_release); } /*-------------------------------------------------------------------------*/ -static void usb_host_release(struct class_device *class_dev) -{ - struct usb_bus *bus = to_usb_bus(class_dev); - - if (bus->release) - bus->release(bus); -} - -static struct class usb_host_class = { - .name = "usb_host", - .release = &usb_host_release, -}; +static struct class *usb_host_class; int usb_host_init(void) { - return class_register(&usb_host_class); + int retval = 0; + + usb_host_class = class_create(THIS_MODULE, "usb_host"); + if (IS_ERR(usb_host_class)) + retval = PTR_ERR(usb_host_class); + return retval; } void usb_host_cleanup(void) { - class_unregister(&usb_host_class); + class_destroy(usb_host_class); } /** @@ -662,7 +706,7 @@ void usb_host_cleanup(void) * This code is used to initialize a usb_bus structure, memory for which is * separately managed. */ -void usb_bus_init (struct usb_bus *bus) +static void usb_bus_init (struct usb_bus *bus) { memset (&bus->devmap, 0, sizeof(struct usb_devmap)); @@ -676,8 +720,9 @@ void usb_bus_init (struct usb_bus *bus) bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); + + kref_init(&bus->kref); } -EXPORT_SYMBOL (usb_bus_init); /** * usb_alloc_bus - creates a new USB host controller structure @@ -695,15 +740,13 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) { struct usb_bus *bus; - bus = kmalloc (sizeof *bus, GFP_KERNEL); + bus = kzalloc (sizeof *bus, GFP_KERNEL); if (!bus) return NULL; - memset(bus, 0, sizeof(struct usb_bus)); usb_bus_init (bus); bus->op = op; return bus; } -EXPORT_SYMBOL (usb_alloc_bus); /*-------------------------------------------------------------------------*/ @@ -715,10 +758,9 @@ EXPORT_SYMBOL (usb_alloc_bus); * Assigns a bus number, and links the controller into usbcore data * structures so that it can be seen by scanning the bus list. */ -int usb_register_bus(struct usb_bus *bus) +static int usb_register_bus(struct usb_bus *bus) { int busnum; - int retval; down (&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); @@ -731,26 +773,25 @@ int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); - bus->class_dev.class = &usb_host_class; - bus->class_dev.dev = bus->controller; - retval = class_device_register(&bus->class_dev); - if (retval) { + bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), + bus->controller, "usb_host%d", busnum); + if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); - return retval; + return PTR_ERR(bus->class_dev); } + class_set_devdata(bus->class_dev, bus); + /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); - usbfs_add_bus (bus); + usb_notify_add_bus(bus); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); return 0; } -EXPORT_SYMBOL (usb_register_bus); /** * usb_deregister_bus - deregisters the USB host controller @@ -760,7 +801,7 @@ EXPORT_SYMBOL (usb_register_bus); * Recycles the bus number, and unlinks the controller from usbcore data * structures so that it won't be seen by scanning the bus list. */ -void usb_deregister_bus (struct usb_bus *bus) +static void usb_deregister_bus (struct usb_bus *bus) { dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum); @@ -773,27 +814,27 @@ void usb_deregister_bus (struct usb_bus *bus) list_del (&bus->bus_list); up (&usb_bus_list_lock); - usbfs_remove_bus (bus); + usb_notify_remove_bus(bus); clear_bit (bus->busnum, busmap.busmap); - class_device_unregister(&bus->class_dev); + class_device_unregister(bus->class_dev); } -EXPORT_SYMBOL (usb_deregister_bus); /** - * usb_register_root_hub - called by HCD to register its root hub + * register_root_hub - called by usb_add_hcd() to register a root hub * @usb_dev: the usb root hub device to be registered. - * @parent_dev: the parent device of this root hub. + * @hcd: host controller for this root hub * - * The USB host controller calls this function to register the root hub - * properly with the USB subsystem. It sets up the device properly in - * the device tree and stores the root_hub pointer in the bus structure, - * then calls usb_new_device() to register the usb device. It also - * assigns the root hub's USB address (always 1). + * This function registers the root hub with the USB subsystem. It sets up + * the device properly in the device tree and stores the root_hub pointer + * in the bus structure, then calls usb_new_device() to register the usb + * device. It also assigns the root hub's USB address (always 1). */ -int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) +static int register_root_hub (struct usb_device *usb_dev, + struct usb_hcd *hcd) { + struct device *parent_dev = hcd->self.controller; const int devnum = 1; int retval; @@ -807,7 +848,7 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev down (&usb_bus_list_lock); usb_dev->bus->root_hub = usb_dev; - usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64; + usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { usb_dev->bus->root_hub = NULL; @@ -817,18 +858,36 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev return (retval < 0) ? retval : -EMSGSIZE; } - usb_lock_device (usb_dev); retval = usb_new_device (usb_dev); - usb_unlock_device (usb_dev); if (retval) { usb_dev->bus->root_hub = NULL; dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); } up (&usb_bus_list_lock); + + if (retval == 0) { + spin_lock_irq (&hcd_root_hub_lock); + hcd->rh_registered = 1; + spin_unlock_irq (&hcd_root_hub_lock); + + /* Did the HC die before the root hub was registered? */ + if (hcd->state == HC_STATE_HALT) + usb_hc_died (hcd); /* This time clean up */ + } + return retval; } -EXPORT_SYMBOL (usb_register_root_hub); + +void usb_enable_root_hub_irq (struct usb_bus *bus) +{ + struct usb_hcd *hcd; + + hcd = container_of (bus, struct usb_hcd, self); + if (hcd->driver->hub_irq_enable && !hcd->poll_rh && + hcd->state != HC_STATE_HALT) + hcd->driver->hub_irq_enable (hcd); +} /*-------------------------------------------------------------------------*/ @@ -868,9 +927,9 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) case USB_SPEED_HIGH: /* ISOC or INTR */ // FIXME adjust for input vs output if (isoc) - tmp = HS_USECS (bytecount); + tmp = HS_NSECS_ISO (bytecount); else - tmp = HS_USECS_ISO (bytecount); + tmp = HS_NSECS (bytecount); return tmp; default: pr_debug ("%s: bogus device speed!\n", usbcore_name); @@ -1018,40 +1077,6 @@ EXPORT_SYMBOL (usb_release_bandwidth); /*-------------------------------------------------------------------------*/ -/* called from khubd, or root hub init threads for hcd-private init */ -static int hcd_alloc_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || udev->hcpriv) - return -EINVAL; - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - hcd = udev->bus->hcpriv; - if (hcd->state == USB_STATE_QUIESCING) - return -ENOLINK; - - dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - memset (dev, 0, sizeof *dev); - - INIT_LIST_HEAD (&dev->dev_list); - INIT_LIST_HEAD (&dev->urb_list); - - spin_lock_irqsave (&hcd_data_lock, flags); - list_add (&dev->dev_list, &hcd->dev_list); - // refcount is implicit - udev->hcpriv = dev; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - static void urb_unlink (struct urb *urb) { unsigned long flags; @@ -1075,24 +1100,17 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, int mem_flags) +static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; - struct hcd_dev *dev = urb->dev->hcpriv; + struct usb_host_endpoint *ep; unsigned long flags; - if (!hcd || !dev) + if (!hcd) return -ENODEV; - /* - * FIXME: make urb timeouts be generic, keeping the HCD cores - * as simple as possible. - */ - - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) - // It would catch submission paths for all urbs. + usbmon_urb_submit(&hcd->self, urb); /* * Atomically queue the urb, first to our records, then to the HCD. @@ -1103,15 +1121,29 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) // FIXME: verify that quiescing hc works right (RH cleans up) spin_lock_irqsave (&hcd_data_lock, flags); - if (unlikely (urb->reject)) + ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (unlikely (!ep)) + status = -ENOENT; + else if (unlikely (urb->reject)) status = -EPERM; else switch (hcd->state) { - case USB_STATE_RUNNING: - case USB_STATE_RESUMING: + case HC_STATE_RUNNING: + case HC_STATE_RESUMING: +doit: usb_get_dev (urb->dev); - list_add_tail (&urb->urb_list, &dev->urb_list); + list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; + case HC_STATE_SUSPENDED: + /* HC upstream links (register access, wakeup signaling) can work + * even when the downstream links (and DMA etc) are quiesced; let + * usbcore talk to the root hub. + */ + if (hcd->self.controller->power.power_state.event == PM_EVENT_ON + && urb->dev->parent == NULL) + goto doit; + /* FALL THROUGH */ default: status = -ESHUTDOWN; break; @@ -1119,6 +1151,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) spin_unlock_irqrestore (&hcd_data_lock, flags); if (status) { INIT_LIST_HEAD (&urb->urb_list); + usbmon_urb_submit_error(&hcd->self, urb, status); return status; } @@ -1135,8 +1168,6 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) * valid and usb_buffer_{sync,unmap}() not be needed, since * they could clobber root hub response data. */ - urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); status = rh_urb_enqueue (hcd, urb); goto done; } @@ -1163,7 +1194,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) : DMA_TO_DEVICE); } - status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); + status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); done: if (unlikely (status)) { urb_unlink (urb); @@ -1171,6 +1202,7 @@ done: if (urb->reject) wake_up (&usb_kill_urb_queue); usb_put_urb (urb); + usbmon_urb_submit_error(&hcd->self, urb, status); } return status; } @@ -1181,7 +1213,7 @@ done: static int hcd_get_frame_number (struct usb_device *udev) { struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; - if (!HCD_IS_RUNNING (hcd->state)) + if (!HC_IS_RUNNING (hcd->state)) return -ESHUTDOWN; return hcd->driver->get_frame_number (hcd); } @@ -1222,7 +1254,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ static int hcd_unlink_urb (struct urb *urb, int status) { - struct hcd_dev *dev; + struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; @@ -1231,6 +1263,12 @@ static int hcd_unlink_urb (struct urb *urb, int status) if (!urb) return -EINVAL; + if (!urb->dev || !urb->dev->bus) + return -ENODEV; + ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENODEV; /* * we contend for urb->status with the hcd core, @@ -1246,27 +1284,15 @@ static int hcd_unlink_urb (struct urb *urb, int status) spin_lock_irqsave (&urb->lock, flags); spin_lock (&hcd_data_lock); - if (!urb->dev || !urb->dev->bus) { - retval = -ENODEV; - goto done; - } - - dev = urb->dev->hcpriv; sys = &urb->dev->dev; hcd = urb->dev->bus->hcpriv; - if (!dev || !hcd) { + if (hcd == NULL) { retval = -ENODEV; goto done; } - /* running ~= hc unlink handshake works (irq, timer, etc) - * halted ~= no unlink handshake is needed - * suspended, resuming == should never happen - */ - WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); - /* insist the urb is still queued */ - list_for_each(tmp, &dev->urb_list) { + list_for_each(tmp, &ep->urb_list) { if (tmp == &urb->urb_list) break; } @@ -1283,15 +1309,17 @@ static int hcd_unlink_urb (struct urb *urb, int status) goto done; } - /* PCI IRQ setup can easily be broken so that USB controllers + /* IRQ setup can easily be broken so that USB controllers * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address(). + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. */ - if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) { + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) + && hcd->self.root_hub != urb->dev) { dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Different ACPI or APIC settings may help." + "Controller is probably using the wrong IRQ." "\n"); - hcd->saw_irq = 1; + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } urb->status = status; @@ -1318,46 +1346,37 @@ done: * the hcd to make sure all endpoint state is gone from hardware. use for * set_configuration, set_interface, driver removal, physical disconnect. * - * example: a qh stored in hcd_dev.ep[], holding state related to endpoint + * example: a qh stored in ep->hcpriv, holding state related to endpoint * type, maxpacket size, toggle, halt status, and scheduling. */ -static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) +static void +hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) { - struct hcd_dev *dev; - struct usb_hcd *hcd; - struct urb *urb; - unsigned epnum = endpoint & USB_ENDPOINT_NUMBER_MASK; + struct usb_hcd *hcd; + struct urb *urb; - dev = udev->hcpriv; hcd = udev->bus->hcpriv; - WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); + WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && + udev->state != USB_STATE_NOTATTACHED); local_irq_disable (); -rescan: - /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) - udev->epmaxpacketin [epnum] = 0; - else - udev->epmaxpacketout [epnum] = 0; + /* FIXME move most of this into message.c as part of its + * endpoint disable logic + */ - /* then kill any current requests */ + /* ep is already gone from udev->ep_{in,out}[]; no more submits */ +rescan: spin_lock (&hcd_data_lock); - list_for_each_entry (urb, &dev->urb_list, urb_list) { - int tmp = urb->pipe; - - /* ignore urbs for other endpoints */ - if (usb_pipeendpoint (tmp) != epnum) - continue; - /* NOTE assumption that only ep0 is a control endpoint */ - if (epnum != 0 && ((tmp ^ endpoint) & USB_DIR_IN)) - continue; + list_for_each_entry (urb, &ep->urb_list, urb_list) { + int tmp; /* another cpu may be in hcd, spinning on hcd_data_lock * to giveback() this urb. the races here should be * small, but a full fix needs a new "can't submit" * urb state. + * FIXME urb->reject should allow that... */ if (urb->status != -EINPROGRESS) continue; @@ -1399,32 +1418,116 @@ rescan: */ might_sleep (); if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, dev, endpoint); + hcd->driver->endpoint_disable (hcd, ep); } /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM -static int hcd_hub_suspend (struct usb_bus *bus) +int hcd_bus_suspend (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_suspend) - return hcd->driver->hub_suspend (hcd); - return 0; + if (!hcd->driver->bus_suspend) + return -ENOENT; + hcd->state = HC_STATE_QUIESCING; + status = hcd->driver->bus_suspend (hcd); + if (status == 0) + hcd->state = HC_STATE_SUSPENDED; + else + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "suspend", status); + return status; } -static int hcd_hub_resume (struct usb_bus *bus) +int hcd_bus_resume (struct usb_bus *bus) { struct usb_hcd *hcd; + int status; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_resume) - return hcd->driver->hub_resume (hcd); - return 0; + if (!hcd->driver->bus_resume) + return -ENOENT; + if (hcd->state == HC_STATE_RUNNING) + return 0; + hcd->state = HC_STATE_RESUMING; + status = hcd->driver->bus_resume (hcd); + if (status == 0) + hcd->state = HC_STATE_RUNNING; + else { + dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n", + "resume", status); + usb_hc_died(hcd); + } + return status; +} + +/* + * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports + * @hcd: host controller for this root hub + * + * This call arranges that usb_hcd_resume_root_hub() is safe to call later; + * that the HCD's root hub polling is deactivated; and that the root's hub + * driver is suspended. HCDs may call this to autosuspend when their root + * hub's downstream ports are all inactive: unpowered, disconnected, + * disabled, or suspended. + * + * The HCD will autoresume on device connect change detection (using SRP + * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling + * from any ports that are suspended (if that is enabled). In most cases, + * overcurrent signaling (on powered ports) will also start autoresume. + * + * Always called with IRQs blocked. + */ +void usb_hcd_suspend_root_hub (struct usb_hcd *hcd) +{ + struct urb *urb; + + spin_lock (&hcd_root_hub_lock); + usb_suspend_root_hub (hcd->self.root_hub); + + /* force status urb to complete/unlink while suspended */ + if (hcd->status_urb) { + urb = hcd->status_urb; + urb->status = -ECONNRESET; + urb->hcpriv = NULL; + urb->actual_length = 0; + + del_timer (&hcd->rh_timer); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + } else + urb = NULL; + spin_unlock (&hcd_root_hub_lock); + hcd->state = HC_STATE_SUSPENDED; + + if (urb) + usb_hcd_giveback_urb (hcd, urb, NULL); } +EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub); + +/** + * usb_hcd_resume_root_hub - called by HCD to resume its root hub + * @hcd: host controller for this root hub + * + * The USB host controller calls this function when its root hub is + * suspended (with the remote wakeup feature enabled) and a remote + * wakeup request is received. It queues a request for khubd to + * resume the root hub (that is, manage its downstream ports again). + */ +void usb_hcd_resume_root_hub (struct usb_hcd *hcd) +{ + unsigned long flags; + + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (hcd->rh_registered) + usb_resume_root_hub (hcd->self.root_hub); + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); +} +EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); #endif @@ -1435,7 +1538,7 @@ static int hcd_hub_resume (struct usb_bus *bus) /** * usb_bus_start_enum - start immediate enumeration (for OTG) * @bus: the bus (must use hcd framework) - * @port: 1-based number of port; usually bus->otg_port + * @port_num: 1-based number of port; usually bus->otg_port * Context: in_interrupt() * * Starts enumeration, with an immediate reset followed later by @@ -1469,66 +1572,17 @@ EXPORT_SYMBOL (usb_bus_start_enum); /*-------------------------------------------------------------------------*/ -/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup. - * we're guaranteed that the device is fully quiesced. also, that each - * endpoint has been hcd_endpoint_disabled. - */ - -static int hcd_free_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || !udev->hcpriv) - return -EINVAL; - - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - - // should udev->devnum == -1 ?? - - dev = udev->hcpriv; - hcd = udev->bus->hcpriv; - - /* device driver problem with refcounts? */ - if (!list_empty (&dev->urb_list)) { - dev_dbg (hcd->self.controller, "free busy dev, %s devnum %d (bug!)\n", - hcd->self.bus_name, udev->devnum); - return -EINVAL; - } - - spin_lock_irqsave (&hcd_data_lock, flags); - list_del (&dev->dev_list); - udev->hcpriv = NULL; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - kfree (dev); - return 0; -} - /* * 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, +static struct usb_operations usb_hcd_operations = { .get_frame_number = hcd_get_frame_number, .submit_urb = hcd_submit_urb, .unlink_urb = hcd_unlink_urb, - .deallocate = hcd_free_dev, .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, .disable = hcd_endpoint_disable, -#ifdef CONFIG_USB_SUSPEND - .hub_suspend = hcd_hub_suspend, - .hub_resume = hcd_hub_resume, -#endif }; -EXPORT_SYMBOL (usb_hcd_operations); /*-------------------------------------------------------------------------*/ @@ -1547,14 +1601,13 @@ EXPORT_SYMBOL (usb_hcd_operations); */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { - urb_unlink (urb); + int at_root_hub; - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) - // It would catch exit/unlink paths for all urbs. + at_root_hub = (urb->dev == hcd->self.root_hub); + urb_unlink (urb); /* lower level hcd code should use *_dma exclusively */ - if (hcd->self.controller->dma_mask) { + if (hcd->self.controller->dma_mask && !at_root_hub) { if (usb_pipecontrol (urb->pipe) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, @@ -1570,6 +1623,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs : DMA_TO_DEVICE); } + usbmon_urb_complete (&hcd->self, urb); /* pass ownership to the completion handler */ urb->complete (urb, regs); atomic_dec (&urb->use_count); @@ -1584,29 +1638,29 @@ 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 + * @__hcd: pointer to the HCD whose IRQ is being signaled * @r: saved hardware registers * - * 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. + * If the controller isn't HALTed, calls the driver's irq handler. + * Checks whether the controller is now dead. */ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) { struct usb_hcd *hcd = __hcd; int start = hcd->state; - if (start == USB_STATE_HALT) + if (unlikely(start == HC_STATE_HALT || + !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) return IRQ_NONE; if (hcd->driver->irq (hcd, r) == IRQ_NONE) return IRQ_NONE; - hcd->saw_irq = 1; - if (hcd->state != start && hcd->state == USB_STATE_HALT) + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + + if (unlikely(hcd->state == HC_STATE_HALT)) usb_hc_died (hcd); return IRQ_HANDLED; } -EXPORT_SYMBOL (usb_hcd_irq); /*-------------------------------------------------------------------------*/ @@ -1620,21 +1674,277 @@ EXPORT_SYMBOL (usb_hcd_irq); */ void usb_hc_died (struct usb_hcd *hcd) { + unsigned long flags; + dev_err (hcd->self.controller, "HC died; cleaning up\n"); - /* make khubd clean up old urbs and devices */ - usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED); - mod_timer(&hcd->rh_timer, jiffies); + spin_lock_irqsave (&hcd_root_hub_lock, flags); + if (hcd->rh_registered) { + hcd->poll_rh = 0; + + /* make khubd clean up old urbs and devices */ + usb_set_device_state (hcd->self.root_hub, + USB_STATE_NOTATTACHED); + usb_kick_khubd (hcd->self.root_hub); + } + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } -EXPORT_SYMBOL (usb_hc_died); +EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ -void usb_hcd_release(struct usb_bus *bus) +static void hcd_release (struct usb_bus *bus) { struct usb_hcd *hcd; - hcd = container_of (bus, struct usb_hcd, self); + hcd = container_of(bus, struct usb_hcd, self); kfree(hcd); } -EXPORT_SYMBOL (usb_hcd_release); + +/** + * 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 + * @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 + * HC driver's private data. Initialize the generic members of the + * hcd structure. + * + * If memory is unavailable, returns NULL. + */ +struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, + struct device *dev, char *bus_name) +{ + struct usb_hcd *hcd; + + hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); + if (!hcd) { + dev_dbg (dev, "hcd alloc failed\n"); + return NULL; + } + dev_set_drvdata(dev, hcd); + + 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); + hcd->rh_timer.function = rh_timer_func; + hcd->rh_timer.data = (unsigned long) hcd; + + hcd->driver = driver; + hcd->product_desc = (driver->product_desc) ? driver->product_desc : + "USB Host Controller"; + + return hcd; +} +EXPORT_SYMBOL (usb_create_hcd); + +void usb_put_hcd (struct usb_hcd *hcd) +{ + dev_set_drvdata(hcd->self.controller, NULL); + 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 + * @irqflags: Interrupt type flags + * + * 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, unsigned long irqflags) +{ + int retval; + struct usb_device *rhdev; + + dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* 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 err_register_bus; + + if (hcd->driver->irq) { + char buf[8], *bufp = buf; + +#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, &usb_hcd_irq, irqflags, + hcd->irq_descr, hcd)) != 0) { + dev_err(hcd->self.controller, + "request interrupt %s failed\n", bufp); + goto err_request_irq; + } + hcd->irq = irqnum; + dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, + (hcd->driver->flags & HCD_MEMORY) ? + "io mem" : "io base", + (unsigned long long)hcd->rsrc_start); + } else { + hcd->irq = -1; + if (hcd->rsrc_start) + dev_info(hcd->self.controller, "%s 0x%08llx\n", + (hcd->driver->flags & HCD_MEMORY) ? + "io mem" : "io base", + (unsigned long long)hcd->rsrc_start); + } + + /* Allocate the root hub before calling hcd->driver->start(), + * but don't register it until afterward so that the hardware + * is running. + */ + if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { + dev_err(hcd->self.controller, "unable to allocate root hub\n"); + retval = -ENOMEM; + goto err_allocate_root_hub; + } + + /* Although in principle hcd->driver->start() might need to use rhdev, + * none of the current drivers do. + */ + if ((retval = hcd->driver->start(hcd)) < 0) { + dev_err(hcd->self.controller, "startup error %d\n", retval); + goto err_hcd_driver_start; + } + + /* hcd->driver->start() reported can_wakeup, probably with + * assistance from board's boot firmware. + * NOTE: normal devices won't enable wakeup by default. + */ + if (hcd->can_wakeup) + dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + hcd->remote_wakeup = hcd->can_wakeup; + + rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : + USB_SPEED_FULL; + rhdev->bus_mA = min(500u, hcd->power_budget); + if ((retval = register_root_hub(rhdev, hcd)) != 0) + goto err_register_root_hub; + + if (hcd->uses_new_polling && hcd->poll_rh) + usb_hcd_poll_rh_status(hcd); + return retval; + + err_register_root_hub: + hcd->driver->stop(hcd); + + err_hcd_driver_start: + usb_put_dev(rhdev); + + err_allocate_root_hub: + if (hcd->irq >= 0) + free_irq(irqnum, hcd); + + err_request_irq: + usb_deregister_bus(&hcd->self); + + err_register_bus: + 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 (HC_IS_RUNNING (hcd->state)) + hcd->state = HC_STATE_QUIESCING; + + dev_dbg(hcd->self.controller, "roothub graceful disconnect\n"); + spin_lock_irq (&hcd_root_hub_lock); + hcd->rh_registered = 0; + spin_unlock_irq (&hcd_root_hub_lock); + + down(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + up(&usb_bus_list_lock); + + hcd->poll_rh = 0; + del_timer_sync(&hcd->rh_timer); + + hcd->driver->stop(hcd); + hcd->state = HC_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); + +/*-------------------------------------------------------------------------*/ + +#if defined(CONFIG_USB_MON) + +struct usb_mon_operations *mon_ops; + +/* + * The registration is unlocked. + * We do it this way because we do not want to lock in hot paths. + * + * Notice that the code is minimally error-proof. Because usbmon needs + * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. + */ + +int usb_mon_register (struct usb_mon_operations *ops) +{ + + if (mon_ops) + return -EBUSY; + + mon_ops = ops; + mb(); + return 0; +} +EXPORT_SYMBOL_GPL (usb_mon_register); + +void usb_mon_deregister (void) +{ + + if (mon_ops == NULL) { + printk(KERN_ERR "USB: monitor was not registered\n"); + return; + } + mon_ops = NULL; + mb(); +} +EXPORT_SYMBOL_GPL (usb_mon_deregister); + +#endif /* CONFIG_USB_MON */