# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.426 -> 1.427 # drivers/usb/usb-ohci.c 1.27 -> 1.28 # drivers/usb/hcd.h 1.1 -> 1.2 # include/linux/usb.h 1.21 -> 1.22 # drivers/usb/devices.c 1.6 -> 1.7 # drivers/usb/usb-uhci.c 1.28 -> 1.29 # drivers/usb/usb.c 1.33 -> 1.34 # drivers/usb/hcd.c 1.9 -> 1.10 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/02/27 david-b@packbell.net 1.427 # This is another USB API cleanup patch. It's against 2.5.5: # # - Moves 8 functions from usb.[hc] to hcd.[hc] # - Also moves some data structures and types # - Now usbdevfs and "old" HCDs #include "hcd.h" # - Minor tweaks to the "hcd" layer (one less FIXME) # - Minor kernel doc and comment cleanups # # Basically this continues moving the HCD-only functionality # out of the way of normal USB device drivers. Converging # "usb_bus" and "usb_hcd" (later!) will be a bit easier too. # # I did basic sanity tests, there's little to break ... :) # # There are still a few functions in usb.c that aren't for # general driver use. They're mostly for enumeration, # in areas where the hub driver and HCD root hubs # need to do various kinds of magic. It wasn't clear # how to decouple those, they can certainly wait. # -------------------------------------------- # diff -Nru a/drivers/usb/devices.c b/drivers/usb/devices.c --- a/drivers/usb/devices.c Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/devices.c Wed Feb 27 15:44:31 2002 @@ -4,8 +4,6 @@ * (C) Copyright 1999,2000 Thomas Sailer . (proc file per device) * (C) Copyright 1999 Deti Fliegl (new USB architecture) * - * $id$ - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -61,6 +59,8 @@ #include #include +#include "hcd.h" + #define MAX_TOPO_LEVEL 6 /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */ @@ -429,6 +429,10 @@ * count = device count at this level */ /* If this is the root hub, display the bandwidth information */ + /* FIXME high speed reserves 20% frametime for non-periodic, + * while full/low speed reserves only 10% ... so this is wrong + * for high speed busses. also, change how bandwidth is recorded. + */ if (level == 0) data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC, diff -Nru a/drivers/usb/hcd.c b/drivers/usb/hcd.c --- a/drivers/usb/hcd.c Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/hcd.c Wed Feb 27 15:44:31 2002 @@ -1,5 +1,11 @@ /* - * Copyright (c) 2001 by David Brownell + * (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 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,9 +39,6 @@ #include #include /* for UTS_SYSNAME */ -#ifndef CONFIG_USB_DEBUG - #define CONFIG_USB_DEBUG /* this is experimental! */ -#endif #ifdef CONFIG_USB_DEBUG #define DEBUG @@ -53,6 +56,8 @@ #include +// #define USB_BANDWIDTH_MESSAGES + /*-------------------------------------------------------------------------*/ /* @@ -78,19 +83,28 @@ * usb client device drivers. * * Contributors of ideas or unattributed patches include: David Brownell, - * Roman Weissgaerber, Rory Bolt, ... + * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... * * HISTORY: + * 2002-02-21 Pull in most of the usb_bus support from usb.c; some + * associated cleanup. "usb_hcd" still != "usb_bus". * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. */ /*-------------------------------------------------------------------------*/ /* host controllers we manage */ -static LIST_HEAD (hcd_list); +LIST_HEAD (usb_bus_list); + +/* used when allocating bus numbers */ +#define USB_MAXBUS 64 +struct usb_busmap { + unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; +}; +static struct usb_busmap busmap; /* used when updating list of hcds */ -static DECLARE_MUTEX (hcd_list_lock); +DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ /* used when updating hcd data */ static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; @@ -105,6 +119,9 @@ /*-------------------------------------------------------------------------*/ +#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) +#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) + /* usb 2.0 root hub device descriptor */ static const u8 usb2_rh_dev_descriptor [18] = { 0x12, /* __u8 bLength; */ @@ -118,7 +135,7 @@ 0x00, 0x00, /* __u16 idVendor; */ 0x00, 0x00, /* __u16 idProduct; */ - 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -141,7 +158,7 @@ 0x00, 0x00, /* __u16 idVendor; */ 0x00, 0x00, /* __u16 idProduct; */ - 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -506,6 +523,346 @@ /*-------------------------------------------------------------------------*/ +/* exported only within usbcore */ +void usb_bus_get (struct usb_bus *bus) +{ + atomic_inc (&bus->refcnt); +} + +/* exported only within usbcore */ +void usb_bus_put (struct usb_bus *bus) +{ + if (atomic_dec_and_test (&bus->refcnt)) + kfree (bus); +} + +/*-------------------------------------------------------------------------*/ + +/* shared initialization code */ +static void usb_init_bus (struct usb_bus *bus) +{ + memset (&bus->devmap, 0, sizeof(struct usb_devmap)); + +#ifdef DEVNUM_ROUND_ROBIN + bus->devnum_next = 1; +#endif /* DEVNUM_ROUND_ROBIN */ + + bus->root_hub = NULL; + bus->hcpriv = NULL; + bus->busnum = -1; + bus->bandwidth_allocated = 0; + bus->bandwidth_int_reqs = 0; + bus->bandwidth_isoc_reqs = 0; + + INIT_LIST_HEAD (&bus->bus_list); + + atomic_set (&bus->refcnt, 1); +} + +/** + * usb_alloc_bus - creates a new USB host controller structure + * @op: pointer to a struct usb_operations that this bus structure should use + * Context: !in_interrupt() + * + * Creates a USB host controller bus structure with the specified + * usb_operations and initializes all the necessary internal objects. + * + * If no memory is available, NULL is returned. + * + * The caller should call usb_free_bus() when it is finished with the structure. + */ +struct usb_bus *usb_alloc_bus (struct usb_operations *op) +{ + struct usb_bus *bus; + + bus = kmalloc (sizeof *bus, GFP_KERNEL); + if (!bus) + return NULL; + usb_init_bus (bus); + bus->op = op; + return bus; +} +EXPORT_SYMBOL (usb_alloc_bus); + +/** + * usb_free_bus - frees the memory used by a bus structure + * @bus: pointer to the bus to free + * + * To be invoked by a HCD, only as the last step of decoupling from + * hardware. It is an error to call this if the reference count is + * anything but one. That would indicate that some system component + * did not correctly shut down, and thought the hardware was still + * accessible. + */ +void usb_free_bus (struct usb_bus *bus) +{ + if (!bus) + return; + if (atomic_read (&bus->refcnt) != 1) + err ("usb_free_bus #%d, count != 1", bus->busnum); + usb_bus_put (bus); +} +EXPORT_SYMBOL (usb_free_bus); + +/*-------------------------------------------------------------------------*/ + +/** + * usb_register_bus - registers the USB host controller with the usb core + * @bus: pointer to the bus to register + * Context: !in_interrupt() + * + * Assigns a bus number, and links the controller into usbcore data + * structures so that it can be seen by scanning the bus list. + */ +void usb_register_bus(struct usb_bus *bus) +{ + int busnum; + + down (&usb_bus_list_lock); + busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); + if (busnum < USB_MAXBUS) { + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; + } else + warn ("too many buses"); + + usb_bus_get (bus); + + /* Add it to the list of buses */ + list_add (&bus->bus_list, &usb_bus_list); + up (&usb_bus_list_lock); + + usbfs_add_bus (bus); + + info ("new USB bus registered, assigned bus number %d", bus->busnum); +} +EXPORT_SYMBOL (usb_register_bus); + +/** + * usb_deregister_bus - deregisters the USB host controller + * @bus: pointer to the bus to deregister + * Context: !in_interrupt() + * + * 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) +{ + info ("USB bus %d deregistered", bus->busnum); + + /* + * NOTE: make sure that all the devices are removed by the + * controller code, as well as having it call this when cleaning + * itself up + */ + down (&usb_bus_list_lock); + list_del (&bus->bus_list); + up (&usb_bus_list_lock); + + usbfs_remove_bus (bus); + + clear_bit (bus->busnum, busmap.busmap); + + usb_bus_put (bus); +} +EXPORT_SYMBOL (usb_deregister_bus); + +/** + * usb_register_root_hub - called by HCD to register its root hub + * @usb_dev: the usb root hub device to be registered. + * @parent_dev: the parent device of 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 driverfs tree, and then calls usb_new_device() to register the + * usb device. + */ +int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) +{ + int retval; + + usb_dev->dev.parent = parent_dev; + strcpy (&usb_dev->dev.name[0], "usb_name"); + strcpy (&usb_dev->dev.bus_id[0], "usb_bus"); + retval = usb_new_device (usb_dev); + if (retval) + put_device (&usb_dev->dev); + return retval; +} +EXPORT_SYMBOL (usb_register_root_hub); + + +/*-------------------------------------------------------------------------*/ + +/* + * usb_calc_bus_time: + * Returns approximate bus time in nanoseconds for a periodic transaction. + * See USB 2.0 spec section 5.11.3 + */ +static long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) +{ + unsigned long tmp; + + switch (speed) { + case USB_SPEED_LOW: /* INTR only */ + if (is_input) { + tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } else { + tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + case USB_SPEED_FULL: /* ISOC or INTR */ + if (isoc) { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + } else { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (9107L + BW_HOST_DELAY + tmp); + } + case USB_SPEED_HIGH: /* ISOC or INTR */ + // FIXME merge from EHCI code; caller will need to handle + // each part of a split separately. + return 0; + default: + dbg ("bogus device speed!"); + return -1; + } +} + +/* + * usb_check_bandwidth(): + * + * old_alloc is from host_controller->bandwidth_allocated in microseconds; + * bustime is from calc_bus_time(), but converted to microseconds. + * + * returns if successful, + * or -ENOSPC if bandwidth request fails. + * + * FIXME: + * This initial implementation does not use Endpoint.bInterval + * in managing bandwidth allocation. + * It probably needs to be expanded to use Endpoint.bInterval. + * This can be done as a later enhancement (correction). + * + * This will also probably require some kind of + * frame allocation tracking...meaning, for example, + * that if multiple drivers request interrupts every 10 USB frames, + * they don't all have to be allocated at + * frame numbers N, N+10, N+20, etc. Some of them could be at + * N+11, N+21, N+31, etc., and others at + * N+12, N+22, N+32, etc. + * + * Similarly for isochronous transfers... + * + * Individual HCDs can schedule more directly ... this logic + * is not correct for high speed transfers. + */ +int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) +{ + unsigned int pipe = urb->pipe; + long bustime; + int is_in = usb_pipein (pipe); + int is_iso = usb_pipeisoc (pipe); + int old_alloc = dev->bus->bandwidth_allocated; + int new_alloc; + + + bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, + usb_maxpacket (dev, pipe, !is_in))); + if (is_iso) + bustime /= urb->number_of_packets; + + new_alloc = old_alloc + (int) bustime; + if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { +#ifdef DEBUG + char *mode = +#ifdef CONFIG_USB_BANDWIDTH + ""; +#else + "would have "; +#endif + dbg ("usb_check_bandwidth %sFAILED: %d + %ld = %d usec", + mode, old_alloc, bustime, new_alloc); +#endif +#ifdef CONFIG_USB_BANDWIDTH + bustime = -ENOSPC; /* report error */ +#endif + } + + return bustime; +} +EXPORT_SYMBOL (usb_check_bandwidth); + + +/** + * usb_claim_bandwidth - records bandwidth for a periodic transfer + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @bustime: bandwidth consumed, in (average) microseconds per frame + * @isoc: true iff the request is isochronous + * + * Bus bandwidth reservations are recorded purely for diagnostic purposes. + * HCDs are expected not to overcommit periodic bandwidth, and to record such + * reservations whenever endpoints are added to the periodic schedule. + * + * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's + * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable + * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how + * large its periodic schedule is. + */ +void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) +{ + dev->bus->bandwidth_allocated += bustime; + if (isoc) + dev->bus->bandwidth_isoc_reqs++; + else + dev->bus->bandwidth_int_reqs++; + urb->bandwidth = bustime; + +#ifdef USB_BANDWIDTH_MESSAGES + dbg ("bandwidth alloc increased by %d (%s) to %d for %d requesters", + bustime, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif +} +EXPORT_SYMBOL (usb_claim_bandwidth); + + +/** + * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @isoc: true iff the request is isochronous + * + * This records that previously allocated bandwidth has been released. + * Bandwidth is released when endpoints are removed from the host controller's + * periodic schedule. + */ +void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) +{ + dev->bus->bandwidth_allocated -= urb->bandwidth; + if (isoc) + dev->bus->bandwidth_isoc_reqs--; + else + dev->bus->bandwidth_int_reqs--; + +#ifdef USB_BANDWIDTH_MESSAGES + dbg ("bandwidth alloc reduced by %d (%s) to %d for %d requesters", + urb->bandwidth, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif + urb->bandwidth = 0; +} +EXPORT_SYMBOL (usb_release_bandwidth); + + +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_PCI /* PCI-based HCs are normal, but custom bus glue should be ok */ @@ -522,6 +879,7 @@ * usb_hcd_pci_probe - initialize PCI-based HCDs * @dev: USB Host Controller being probed * @id: pci hotplug id connecting controller to HCD framework + * Context: !in_interrupt() * * Allocates basic PCI resources for this USB host controller, and * then invokes the start() method for the HCD associated with it @@ -535,7 +893,6 @@ unsigned long resource, len; void *base; u8 latency, limit; - struct usb_bus *bus; struct usb_hcd *hcd; int retval, region; char buf [8], *bufp = buf; @@ -631,7 +988,6 @@ != 0) { err ("request interrupt %s failed", bufp); retval = -EBUSY; -clean_3: driver->hcd_free (hcd); goto clean_2; } @@ -643,26 +999,15 @@ (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", base); -// FIXME simpler: make "bus" be that data, not pointer to it. - bus = usb_alloc_bus (&hcd_operations); - if (bus == NULL) { - dbg ("usb_alloc_bus fail"); - retval = -ENOMEM; - free_irq (dev->irq, hcd); - goto clean_3; - } - hcd->bus = bus; + usb_init_bus (&hcd->self); + hcd->self.op = &hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->bus = &hcd->self; hcd->bus_name = dev->slot_name; - bus->hcpriv = (void *) hcd; INIT_LIST_HEAD (&hcd->dev_list); - INIT_LIST_HEAD (&hcd->hcd_list); - down (&hcd_list_lock); - list_add (&hcd->hcd_list, &hcd_list); - up (&hcd_list_lock); - - usb_register_bus (bus); + usb_register_bus (&hcd->self); if ((retval = driver->start (hcd)) < 0) usb_hcd_pci_remove (dev); @@ -678,6 +1023,7 @@ /** * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs * @dev: USB Host Controller being removed + * Context: !in_interrupt() * * Reverses the effect of usb_hcd_pci_probe(), first invoking * the HCD's stop() method. It is always called from a thread @@ -717,12 +1063,9 @@ pci_resource_len (dev, hcd->region)); } - down (&hcd_list_lock); - list_del (&hcd->hcd_list); - up (&hcd_list_lock); - usb_deregister_bus (hcd->bus); - usb_free_bus (hcd->bus); + if (atomic_read (&hcd->self.refcnt) != 1) + err ("usb_hcd_pci_remove %s, count != 1", hcd->bus_name); hcd->bus = NULL; hcd->driver->hcd_free (hcd); @@ -1257,6 +1600,7 @@ * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its * completion function. The HCD has freed all per-urb resources @@ -1279,16 +1623,9 @@ struct usb_device *dev; /* Release periodic transfer bandwidth */ - if (urb->bandwidth) { - switch (usb_pipetype (urb->pipe)) { - case PIPE_INTERRUPT: - usb_release_bandwidth (urb->dev, urb, 0); - break; - case PIPE_ISOCHRONOUS: - usb_release_bandwidth (urb->dev, urb, 1); - break; - } - } + if (urb->bandwidth) + usb_release_bandwidth (urb->dev, urb, + usb_pipeisoc (urb->pipe)); /* clear all state linking urb to this dev (and hcd) */ diff -Nru a/drivers/usb/hcd.h b/drivers/usb/hcd.h --- a/drivers/usb/hcd.h Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/hcd.h Wed Feb 27 15:44:31 2002 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001 by David Brownell - * + * Copyright (c) 2001-2002 by David Brownell + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -17,6 +17,8 @@ */ +#ifdef __KERNEL__ + /*-------------------------------------------------------------------------*/ /* @@ -33,8 +35,8 @@ /* * housekeeping */ - struct usb_bus *bus; /* hcd is-a bus */ - struct list_head hcd_list; + struct usb_bus *bus; /* FIXME only use "self" */ + struct usb_bus self; /* hcd is-a bus */ const char *bus_name; @@ -98,6 +100,19 @@ /*-------------------------------------------------------------------------*/ +/* + * FIXME usb_operations should vanish or become hc_driver, + * when usb_bus and usb_hcd become the same thing. + */ + +struct usb_operations { + int (*allocate)(struct usb_device *); + int (*deallocate)(struct usb_device *); + int (*get_frame_number) (struct usb_device *usb_dev); + int (*submit_urb) (struct urb *urb, int mem_flags); + int (*unlink_urb) (struct urb *urb); +}; + /* each driver provides one of these, and hardware init support */ struct hc_driver { @@ -126,8 +141,6 @@ /* return current frame number */ int (*get_frame_number) (struct usb_hcd *hcd); -// FIXME: rework generic-to-specific HCD linkage (specific contains generic) - /* memory lifecycle */ struct usb_hcd *(*hcd_alloc) (void); void (*hcd_free) (struct usb_hcd *hcd); @@ -152,7 +165,8 @@ extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); #ifdef CONFIG_PCI - +struct pci_dev; +struct pci_device_id; extern int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id); extern void usb_hcd_pci_remove (struct pci_dev *dev); @@ -206,6 +220,59 @@ /*-------------------------------------------------------------------------*/ +/* + * Generic bandwidth allocation constants/support + */ +#define FRAME_TIME_USECS 1000L +#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ + /* Trying not to use worst-case bit-stuffing + of (7/6 * 8 * bytecount) = 9.33 * bytecount */ + /* bytecount = data payload byte count */ + +#define NS_TO_US(ns) ((ns + 500L) / 1000L) + /* convert & round nanoseconds to microseconds */ + +extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, + int bustime, int isoc); +extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, + int isoc); + +/* + * Full/low speed bandwidth allocation constants/support. + */ +#define BW_HOST_DELAY 1000L /* nanoseconds */ +#define BW_HUB_LS_SETUP 333L /* nanoseconds */ + /* 4 full-speed bit times (est.) */ + +#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ +#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) +#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) + +extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); + +/*-------------------------------------------------------------------------*/ + +extern struct usb_bus *usb_alloc_bus (struct usb_operations *); +extern void usb_free_bus (struct usb_bus *); + +extern void usb_register_bus (struct usb_bus *); +extern void usb_deregister_bus (struct usb_bus *); + +extern int usb_register_root_hub (struct usb_device *usb_dev, + struct device *parent_dev); + +/*-------------------------------------------------------------------------*/ + +/* exported only within usbcore */ + +extern struct list_head usb_bus_list; +extern struct semaphore usb_bus_list_lock; + +extern void usb_bus_get (struct usb_bus *bus); +extern void usb_bus_put (struct usb_bus *bus); + +/*-------------------------------------------------------------------------*/ + /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ // bleech -- resurfaced in 2.4.11 or 2.4.12 #define bitmap DeviceRemovable @@ -217,3 +284,7 @@ #define RUN_CONTEXT (in_irq () ? "in_irq" \ : (in_interrupt () ? "in_interrupt" : "can sleep")) + + +#endif /* __KERNEL__ */ + diff -Nru a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c --- a/drivers/usb/usb-ohci.c Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/usb-ohci.c Wed Feb 27 15:44:31 2002 @@ -73,6 +73,7 @@ #define OHCI_USE_NPS // force NoPowerSwitching mode // #define OHCI_VERBOSE_DEBUG /* not always helpful */ +#include "hcd.h" #include "usb-ohci.h" diff -Nru a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c --- a/drivers/usb/usb-uhci.c Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/usb-uhci.c Wed Feb 27 15:44:31 2002 @@ -57,6 +57,7 @@ #define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__ #include +#include "hcd.h" #include "usb-uhci.h" #include "usb-uhci-debug.h" diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c --- a/drivers/usb/usb.c Wed Feb 27 15:44:31 2002 +++ b/drivers/usb/usb.c Wed Feb 27 15:44:31 2002 @@ -40,12 +40,7 @@ #endif #include -static const int usb_bandwidth_option = -#ifdef CONFIG_USB_BANDWIDTH - 1; -#else - 0; -#endif +#include "hcd.h" extern int usb_hub_init(void); extern void usb_hub_cleanup(void); @@ -61,13 +56,9 @@ * We have a per-interface "registered driver" list. */ LIST_HEAD(usb_driver_list); -LIST_HEAD(usb_bus_list); -struct semaphore usb_bus_list_lock; devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ -static struct usb_busmap busmap; - static struct usb_driver *usb_minors[16]; /** @@ -105,6 +96,7 @@ /** * usb_scan_devices - scans all unclaimed USB interfaces + * Context: !in_interrupt () * * Goes through all unclaimed USB interfaces, and offers them to all * registered USB drivers through the 'probe' function. @@ -173,6 +165,7 @@ /** * usb_deregister - unregister a USB driver * @driver: USB operations of the driver to unregister + * Context: !in_interrupt () * * Unlinks the specified driver from the internal USB driver list. */ @@ -258,259 +251,6 @@ } /* - * usb_calc_bus_time: - * - * returns (approximate) USB bus time in nanoseconds for a USB transaction. - */ -static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount) -{ - unsigned long tmp; - - if (low_speed) /* no isoc. here */ - { - if (input_dir) - { - tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - else - { - tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - } - - /* for full-speed: */ - - if (!isoc) /* Input or Output */ - { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); - } /* end not Isoc */ - - /* for isoc: */ - - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); -} - -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * However, this first cut at USB bandwidth allocation does not - * contain any frame allocation tracking. - */ -int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - int new_alloc; - int old_alloc = dev->bus->bandwidth_allocated; - unsigned int pipe = urb->pipe; - long bustime; - - bustime = usb_calc_bus_time (dev->speed == USB_SPEED_LOW, - usb_pipein(pipe), usb_pipeisoc(pipe), - usb_maxpacket(dev, pipe, usb_pipeout(pipe))); - if (usb_pipeisoc(pipe)) - bustime = NS_TO_US(bustime) / urb->number_of_packets; - else - bustime = NS_TO_US(bustime); - - new_alloc = old_alloc + (int)bustime; - /* what new total allocated bus time would be */ - - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) - dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us", - usb_bandwidth_option ? "" : "would have ", - old_alloc, new_alloc, bustime); - - if (!usb_bandwidth_option) /* don't enforce it */ - return (bustime); - return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : -ENOSPC; -} - -void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dbg("bandwidth alloc increased by %d to %d for %d requesters", - bustime, - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} - -/* - * usb_release_bandwidth(): - * - * called to release a pipe's bandwidth (in microseconds) - */ -void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dbg("bandwidth alloc reduced by %d to %d for %d requesters", - urb->bandwidth, - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} - -static void usb_bus_get(struct usb_bus *bus) -{ - atomic_inc(&bus->refcnt); -} - -static void usb_bus_put(struct usb_bus *bus) -{ - if (atomic_dec_and_test(&bus->refcnt)) - kfree(bus); -} - -/** - * usb_alloc_bus - creates a new USB host controller structure (usbcore-internal) - * @op: pointer to a struct usb_operations that this bus structure should use - * - * Creates a USB host controller bus structure with the specified - * usb_operations and initializes all the necessary internal objects. - * (For use only by USB Host Controller Drivers.) - * - * If no memory is available, NULL is returned. - * - * The caller should call usb_free_bus() when it is finished with the structure. - */ -struct usb_bus *usb_alloc_bus(struct usb_operations *op) -{ - struct usb_bus *bus; - - bus = kmalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) - return NULL; - - memset(&bus->devmap, 0, sizeof(struct usb_devmap)); - -#ifdef DEVNUM_ROUND_ROBIN - bus->devnum_next = 1; -#endif /* DEVNUM_ROUND_ROBIN */ - - bus->op = op; - bus->root_hub = NULL; - bus->hcpriv = NULL; - bus->busnum = -1; - bus->bandwidth_allocated = 0; - bus->bandwidth_int_reqs = 0; - bus->bandwidth_isoc_reqs = 0; - - INIT_LIST_HEAD(&bus->bus_list); - - atomic_set(&bus->refcnt, 1); - - return bus; -} - -/** - * usb_free_bus - frees the memory used by a bus structure (usbcore-internal) - * @bus: pointer to the bus to free - * - * (For use only by USB Host Controller Drivers.) - */ -void usb_free_bus(struct usb_bus *bus) -{ - if (!bus) - return; - - usb_bus_put(bus); -} - -/** - * usb_register_bus - registers the USB host controller with the usb core (usbcore-internal) - * @bus: pointer to the bus to register - * - * (For use only by USB Host Controller Drivers.) - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_register_bus(struct usb_bus *bus) -{ - int busnum; - - down (&usb_bus_list_lock); - busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit(busnum, busmap.busmap); - bus->busnum = busnum; - } else - warn("too many buses"); - - usb_bus_get(bus); - - /* Add it to the list of buses */ - list_add(&bus->bus_list, &usb_bus_list); - up (&usb_bus_list_lock); - - usbfs_add_bus(bus); - - info("new USB bus registered, assigned bus number %d", bus->busnum); -} - -/** - * usb_deregister_bus - deregisters the USB host controller (usbcore-internal) - * @bus: pointer to the bus to deregister - * - * (For use only by USB Host Controller Drivers.) - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_deregister_bus(struct usb_bus *bus) -{ - info("USB bus %d deregistered", bus->busnum); - - /* - * NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning - * itself up - */ - down (&usb_bus_list_lock); - list_del(&bus->bus_list); - up (&usb_bus_list_lock); - - usbfs_remove_bus(bus); - - clear_bit(bus->busnum, busmap.busmap); - - usb_bus_put(bus); -} - -/* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */ @@ -1016,6 +756,7 @@ * usb_alloc_dev - allocate a usb device structure (usbcore-internal) * @parent: hub to which device is connected * @bus: bus used to access the device + * Context: !in_interrupt () * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -1078,14 +819,12 @@ atomic_inc(&dev->refcnt); } -/* ---------------------------------------------------------------------- - * New USB Core Functions - * ----------------------------------------------------------------------*/ /** * usb_alloc_urb - creates a new urb for a USB driver to use * @iso_packets: number of iso packets for this urb - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this. + * @mem_flags: the type of memory to allocate, see kmalloc() for a list of + * valid options for this. * * Creates an urb for the USB driver to use, initializes a few internal * structures, incrementes the usage counter, and returns a pointer to it. @@ -1129,8 +868,10 @@ void usb_free_urb(struct urb *urb) { if (urb) - if (atomic_dec_and_test(&urb->count)) + if (atomic_dec_and_test(&urb->count)) { + info ("really freeing urb"); kfree(urb); + } } /** @@ -1158,7 +899,8 @@ /** * usb_submit_urb - asynchronously issue a transfer request for an endpoint * @urb: pointer to the urb describing the request - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this. + * @mem_flags: the type of memory to allocate, see kmalloc() for a list + * of valid options for this. * * This submits a transfer request, and transfers control of the URB * describing that request to the USB subsystem. Request completion will @@ -1393,7 +1135,9 @@ * @index: USB message index value * @data: pointer to the data to send * @size: length in bytes of the data to send - * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () * * This function sends a simple control message to a specified endpoint * and waits for the message to complete, or timeout. @@ -1401,7 +1145,7 @@ * If successful, it returns 0, otherwise a negative error number. * * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need a asyncronous message, or need to send + * bottom half handler. If you need an asynchronous message, or need to send * a message from within interrupt context, use usb_submit_urb() */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, @@ -1436,7 +1180,9 @@ * @data: pointer to the data to send * @len: length in bytes of the data to send * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () * * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. @@ -1446,7 +1192,7 @@ * actual_length paramater. * * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need a asyncronous message, or need to + * bottom half handler. If you need an asynchronous message, or need to * send a message from within interrupt context, use usb_submit_urb() */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, @@ -1474,6 +1220,11 @@ * Returns the current frame number for the USB host controller * used with the given USB device. This can be used when scheduling * isochronous requests. + * + * Note that different kinds of host controller have different + * "scheduling horizons". While one type might support scheduling only + * 32 frames into the future, others could support scheduling up to + * 1024 frames into the future. */ int usb_get_current_frame_number(struct usb_device *dev) { @@ -1946,6 +1697,7 @@ /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected + * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. * @@ -2069,6 +1821,7 @@ * @index: the number of the descriptor * @buf: where to put the descriptor * @size: how big is "buf"? + * Context: !in_interrupt () * * Gets a USB descriptor. Convenience functions exist to simplify * getting some types of descriptors. Use @@ -2110,6 +1863,7 @@ * @index: the number of the descriptor * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, * in little-endian byte order). @@ -2135,6 +1889,7 @@ /** * usb_get_device_descriptor - (re)reads the device descriptor * @dev: the device whose device descriptor is being updated + * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, * which dedicates space for this purpose. Note that several fields are @@ -2169,6 +1924,7 @@ * @type: USB_RECIP_*; for device, interface, or endpoint * @target: zero (for device), else interface or endpoint number * @data: pointer to two bytes of bitmap data + * Context: !in_interrupt () * * Returns device, interface, or endpoint status. Normally only of * interest to see if the device is self powered, or has enabled the @@ -2227,6 +1983,7 @@ * usb_clear_halt - tells device to clear endpoint halt/stall condition * @dev: device whose endpoint is halted * @pipe: endpoint "pipe" being cleared + * Context: !in_interrupt () * * This is used to clear halt conditions for bulk and interrupt endpoints, * as reported by URB completion status. Endpoints that are halted are @@ -2298,6 +2055,7 @@ * @dev: the device whose interface is being updated * @interface: the interface being updated * @alternate: the setting being chosen. + * Context: !in_interrupt () * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. @@ -2378,6 +2136,7 @@ * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. + * Context: !in_interrupt () * * This is used to enable non-default device modes. Not all devices * support this kind of configurability. By default, configuration @@ -2540,6 +2299,7 @@ * @index: the number of the descriptor * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * This converts the UTF-16LE encoded strings returned by devices, from * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones @@ -2619,8 +2379,11 @@ * @dev: the device whose path is being constructed * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * Returns length of the string (>= 0) or out of memory status (< 0). + * + * NOTE: prefer to use use dev->devpath directly. */ int usb_make_path(struct usb_device *dev, char *buf, size_t size) { @@ -2768,29 +2531,6 @@ return 0; } -/** - * usb_register_root_hub - called by a usb host controller to register the root hub device in the system - * @usb_dev: the usb root hub device to be registered. - * @parent_dev: the parent device of 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 driverfs tree, and then calls usb_new_device() to register the - * usb device. - */ -int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) -{ - int retval; - - usb_dev->dev.parent = parent_dev; - strcpy (&usb_dev->dev.name[0], "usb_name"); - strcpy (&usb_dev->dev.bus_id[0], "usb_bus"); - retval = usb_new_device (usb_dev); - if (retval) - put_device (&usb_dev->dev); - return retval; -} - static int usb_open(struct inode * inode, struct file * file) { int minor = minor(inode->i_rdev); @@ -2859,7 +2599,6 @@ */ static int __init usb_init(void) { - init_MUTEX(&usb_bus_list_lock); usb_major_init(); usbfs_init(); usb_hub_init(); @@ -2892,11 +2631,7 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_scan_devices); -EXPORT_SYMBOL(usb_alloc_bus); -EXPORT_SYMBOL(usb_free_bus); -EXPORT_SYMBOL(usb_register_bus); -EXPORT_SYMBOL(usb_deregister_bus); -EXPORT_SYMBOL(usb_register_root_hub); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_inc_dev_use); @@ -2911,10 +2646,6 @@ EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_connect); EXPORT_SYMBOL(usb_disconnect); - -EXPORT_SYMBOL(usb_check_bandwidth); -EXPORT_SYMBOL(usb_claim_bandwidth); -EXPORT_SYMBOL(usb_release_bandwidth); EXPORT_SYMBOL(__usb_get_extra_descriptor); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Wed Feb 27 15:44:31 2002 +++ b/include/linux/usb.h Wed Feb 27 15:44:31 2002 @@ -44,8 +44,8 @@ /* * USB directions */ -#define USB_DIR_OUT 0 -#define USB_DIR_IN 0x80 +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ /* * Endpoints @@ -148,12 +148,6 @@ unsigned long devicemap[128 / (8*sizeof(unsigned long))]; }; -#define USB_MAXBUS 64 - -struct usb_busmap { - unsigned long busmap[USB_MAXBUS / (8*sizeof(unsigned long))]; -}; - struct usb_device; /*-------------------------------------------------------------------------*/ @@ -516,7 +510,8 @@ * work to connect to a device should be done when the device is opened, * and undone at the last close. The disconnect code needs to address * concurrency issues with respect to open() and close() methods, as - * well as cancel any I/O requests that are still pending. + * well as forcing all pending I/O requests to complete (by unlinking + * them as necessary, and blocking until the unlinks complete). */ struct usb_driver { struct module *owner; @@ -905,13 +900,7 @@ /* Host Controller Driver (HCD) support */ -struct usb_operations { - int (*allocate)(struct usb_device *); - int (*deallocate)(struct usb_device *); - int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, int mem_flags); - int (*unlink_urb) (struct urb *urb); -}; +struct usb_operations; #define DEVNUM_ROUND_ROBIN /***** OPTION *****/ @@ -944,41 +933,12 @@ atomic_t refcnt; }; -extern struct usb_bus *usb_alloc_bus(struct usb_operations *); -extern void usb_free_bus(struct usb_bus *); -extern void usb_register_bus(struct usb_bus *); -extern void usb_deregister_bus(struct usb_bus *); -extern int usb_register_root_hub(struct usb_device *usb_dev, struct device *parent_dev); - -extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); -extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, - int bustime, int isoc); -extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, - int isoc); +// FIXME: root_hub_string vanishes when "usb_hcd" conversion is done, +// along with pre-hcd versions of the OHCI and UHCI drivers. extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len); /* - * Some USB 1.1 bandwidth allocation constants. - */ -#define BW_HOST_DELAY 1000L /* nanoseconds */ -#define BW_HUB_LS_SETUP 333L /* nanoseconds */ - /* 4 full-speed bit times (est.) */ - -#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ -#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) -#define FRAME_TIME_USECS 1000L -#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) - -#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ - /* Trying not to use worst-case bit-stuffing - of (7/6 * 8 * bytecount) = 9.33 * bytecount */ - /* bytecount = data payload byte count */ - -#define NS_TO_US(ns) ((ns + 500L) / 1000L) - /* convert & round nanoseconds to microseconds */ - -/* * As of USB 2.0, full/low speed devices are segregated into trees. * One type grows from USB 1.1 host controllers (OHCI, UHCI etc). * The other type grows from high speed hubs when they connect to @@ -1209,13 +1169,11 @@ /* -------------------------------------------------------------------------- */ /* - * bus and driver list + * driver list * exported only for usbfs (not visible outside usbcore) */ extern struct list_head usb_driver_list; -extern struct list_head usb_bus_list; -extern struct semaphore usb_bus_list_lock; /* * USB device fs stuff