patch-2.4.0-test2 linux/drivers/usb/usb.c
Next file: linux/drivers/usb/usbkbd.c
Previous file: linux/drivers/usb/usb-uhci.c
Back to the patch index
Back to the overall index
- Lines: 522
- Date:
Mon Jun 19 13:42:42 2000
- Orig file:
v2.4.0-test1/linux/drivers/usb/usb.c
- Orig date:
Thu May 11 15:30:08 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -6,6 +6,7 @@
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
@@ -31,6 +32,13 @@
#endif
#include <linux/usb.h>
+static const int usb_bandwidth_option =
+#ifdef CONFIG_USB_BANDWIDTH
+ 1;
+#else
+ 0;
+#endif
+
/*
* Prototypes for the device driver probing/loading functions
*/
@@ -61,6 +69,9 @@
}
info("registered new driver %s", new_driver->name);
+
+ init_MUTEX(&new_driver->serialize);
+
/* Add it to the list of known drivers */
list_add(&new_driver->driver_list, &usb_driver_list);
@@ -105,7 +116,9 @@
struct usb_interface *interface = &dev->actconfig->interface[i];
if (interface->driver == driver) {
+ down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
+ up(&driver->serialize);
usb_driver_release_interface(driver, interface);
/*
* This will go through the list looking for another
@@ -142,13 +155,23 @@
}
}
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+{
+ int i;
+
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+ if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
+ return &dev->actconfig->interface[i];
+
+ return NULL;
+}
/*
- * calc_bus_time:
+ * usb_calc_bus_time:
*
* returns (approximate) USB bus time in nanoseconds for a USB transaction.
*/
-static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
+static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
{
unsigned long tmp;
@@ -178,16 +201,16 @@
tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
-} /* end calc_bus_time */
+}
/*
- * check_bandwidth_alloc():
+ * usb_check_bandwidth():
*
* old_alloc is from host_controller->bandwidth_allocated in microseconds;
* bustime is from calc_bus_time(), but converted to microseconds.
*
- * returns 0 if successful,
- * -1 if bandwidth request fails.
+ * returns <bustime in us> if successful,
+ * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails.
*
* FIXME:
* This initial implementation does not use Endpoint.bInterval
@@ -204,21 +227,67 @@
* However, this first cut at USB bandwidth allocation does not
* contain any frame allocation tracking.
*/
-static int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
{
- unsigned int new_alloc;
+ int new_alloc;
+ int old_alloc = dev->bus->bandwidth_allocated;
+ unsigned int pipe = urb->pipe;
+ long bustime;
+
+ bustime = usb_calc_bus_time (usb_pipeslow(pipe), 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 + bustime;
+ new_alloc = old_alloc + (int)bustime;
/* what new total allocated bus time would be */
- dbg("usb-bandwidth-alloc: was: %u, new: %u, "
- "bustime = %ld us, Pipe allowed: %s",
- old_alloc, new_alloc, bustime,
- (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
- "yes" : "no");
+ 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 : USB_ST_BANDWIDTH_ERROR;
+}
+
+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;
+
+ dbg("bw_alloc increased by %d to %d for %d requesters",
+ bustime,
+ dev->bus->bandwidth_allocated,
+ dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+}
+
+/*
+ * 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--;
- return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1;
-} /* end check_bandwidth_alloc */
+ dbg("bw_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);
+ urb->bandwidth = 0;
+}
/*
* New functions for (de)registering a controller
@@ -242,7 +311,7 @@
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD(&bus->bus_list);
- INIT_LIST_HEAD(&bus->inodes);
+ INIT_LIST_HEAD(&bus->inodes);
return bus;
}
@@ -393,7 +462,10 @@
driver_list);
tmp = tmp->next;
- if (!(private = driver->probe(dev, ifnum)))
+ down(&driver->serialize);
+ private = driver->probe(dev, ifnum);
+ up(&driver->serialize);
+ if (!private)
continue;
usb_driver_claim_interface(driver, interface, private);
@@ -452,8 +524,8 @@
dev->bus = bus;
dev->parent = parent;
atomic_set(&dev->refcnt, 1);
- INIT_LIST_HEAD(&dev->inodes);
- INIT_LIST_HEAD(&dev->filelist);
+ INIT_LIST_HEAD(&dev->inodes);
+ INIT_LIST_HEAD(&dev->filelist);
dev->bus->op->allocate(dev);
@@ -659,21 +731,6 @@
}
/*
- * usb_release_bandwidth():
- *
- * called to release an interrupt pipe's bandwidth (in microseconds)
- */
-void usb_release_bandwidth(struct usb_device *dev, int bw_alloc)
-{
- dev->bus->bandwidth_allocated -= bw_alloc;
- dev->bus->bandwidth_int_reqs--;
- dbg("bw_alloc reduced to %d for %d requesters",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs +
- dev->bus->bandwidth_isoc_reqs);
-}
-
-/*
* usb_get_current_frame_number()
*
* returns the current frame number for the parent USB bus/controller
@@ -684,6 +741,7 @@
return usb_dev->bus->op->get_frame_number (usb_dev);
}
/*-------------------------------------------------------------------*/
+
static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
{
struct usb_descriptor_header *header;
@@ -826,7 +884,7 @@
begin = buffer;
numskipped = 0;
- /* Skip over at Interface class or vendor descriptors */
+ /* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
@@ -987,6 +1045,13 @@
if (!dev->config)
return;
+ if (dev->rawdescriptors) {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+ kfree(dev->rawdescriptors[i]);
+
+ kfree(dev->rawdescriptors);
+ }
+
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
@@ -1129,7 +1194,9 @@
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
+ down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
+ up(&driver->serialize);
usb_driver_release_interface(driver, interface);
}
}
@@ -1143,14 +1210,13 @@
}
/* remove /proc/bus/usb entry */
- usbdevfs_remove_device(dev);
+ usbdevfs_remove_device(dev);
/* Free up the device itself, including its device number */
if (dev->devnum > 0)
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-
+
usb_free_dev(dev);
-
}
/*
@@ -1266,7 +1332,7 @@
(duration << 8) | report_id, ifnum, NULL, 0, HZ * SET_TIMEOUT);
}
-static void usb_set_maxpacket(struct usb_device *dev)
+void usb_set_maxpacket(struct usb_device *dev)
{
int i, b;
@@ -1337,15 +1403,10 @@
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
- struct usb_interface *iface = NULL;
- int ret, i;
+ struct usb_interface *iface;
+ int ret;
- for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
- if (dev->actconfig->interface[i].altsetting->bInterfaceNumber == interface) {
- iface = &dev->actconfig->interface[i];
- break;
- }
- }
+ iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
warn("selecting invalid interface %d", interface);
return -EINVAL;
@@ -1407,11 +1468,10 @@
int usb_get_configuration(struct usb_device *dev)
{
- int result;
- unsigned int cfgno;
+ int result;
+ unsigned int cfgno, length;
unsigned char buffer[8];
unsigned char *bigbuffer;
- unsigned int tmp;
struct usb_config_descriptor *desc =
(struct usb_config_descriptor *)buffer;
@@ -1435,9 +1495,14 @@
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor));
- for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
-
+ dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
+ dev->descriptor.bNumConfigurations, GFP_KERNEL);
+ if (!dev->rawdescriptors) {
+ err("out of memory");
+ return -1;
+ }
+ for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
@@ -1445,41 +1510,41 @@
if (result < 0)
err("unable to get descriptor");
else
- err("config descriptor too short (expected %i, got %i)",8,result);
+ err("config descriptor too short (expected %i, got %i)", 8, result);
goto err;
}
/* Get the full buffer */
- le16_to_cpus(&desc->wTotalLength);
+ length = le16_to_cpu(desc->wTotalLength);
- bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL);
+ bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
err("unable to allocate memory for configuration descriptors");
- result=-ENOMEM;
+ result = -ENOMEM;
goto err;
}
- tmp=desc->wTotalLength;
+
/* Now that we know the length, get the whole thing */
- result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength);
+ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
if (result < 0) {
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
}
- if (result < tmp) {
- err("config descriptor too short (expected %i, got %i)",tmp,result);
+ if (result < length) {
+ err("config descriptor too short (expected %i, got %i)", length, result);
kfree(bigbuffer);
goto err;
}
- result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
- kfree(bigbuffer);
+ dev->rawdescriptors[cfgno] = bigbuffer;
+
+ result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
if (result > 0)
dbg("descriptor data left");
- else if (result < 0)
- {
- result=-1;
+ else if (result < 0) {
+ result = -1;
goto err;
}
}
@@ -1560,8 +1625,7 @@
*/
int usb_new_device(struct usb_device *dev)
{
- int addr, err;
- int tmp;
+ int err;
info("USB new device connect, assigned device number %d", dev->devnum);
@@ -1572,10 +1636,15 @@
dev->epmaxpacketin [0] = 8;
dev->epmaxpacketout[0] = 8;
- /* Even though we have assigned an address for the device, we */
- /* haven't told it what it's address is yet */
- addr = dev->devnum;
- dev->devnum = 0;
+ err = usb_set_address(dev);
+ if (err < 0) {
+ err("USB device not accepting new address (error=%d)", err);
+ clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+ dev->devnum = -1;
+ return 1;
+ }
+
+ wait_ms(10); /* Let the SET_ADDRESS settle */
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err < 8) {
@@ -1583,34 +1652,19 @@
err("USB device not responding, giving up (error=%d)", err);
else
err("USB device descriptor short read (expected %i, got %i)",8,err);
- clear_bit(addr, &dev->bus->devmap.devicemap);
+ clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
- dev->devnum = addr;
-
- err = usb_set_address(dev);
-
- if (err < 0) {
- err("USB device not accepting new address (error=%d)", err);
- clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
- dev->devnum = -1;
- return 1;
- }
-
- wait_ms(10); /* Let the SET_ADDRESS settle */
-
- tmp = sizeof(dev->descriptor);
-
err = usb_get_device_descriptor(dev);
- if (err < tmp) {
+ if (err < sizeof(dev->descriptor)) {
if (err < 0)
- err("unable to get device descriptor (error=%d)",err);
+ err("unable to get device descriptor (error=%d)", err);
else
- err("USB device descriptor short read (expected %i, got %i)",tmp,err);
+ err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
@@ -1646,7 +1700,7 @@
#endif
/* now that the basic setup is over, add a /proc/bus/usb entry */
- usbdevfs_add_device(dev);
+ usbdevfs_add_device(dev);
/* find drivers willing to handle this device */
usb_find_drivers(dev);
@@ -1658,16 +1712,25 @@
{
int minor = MINOR(inode->i_rdev);
struct usb_driver *c = usb_minors[minor/16];
+ int err = -ENODEV;
+ struct file_operations *old_fops;
- file->f_op = NULL;
-
- if (c && (file->f_op = c->fops) && file->f_op->open)
- return file->f_op->open(inode,file);
- else
- return -ENODEV;
+ if (!c || !c->fops)
+ return err;
+ old_fops = file->f_op;
+ file->f_op = fops_get(c->fops);
+ if (file->f_op->open)
+ err = file->f_op->open(inode,file);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
+ }
+ fops_put(old_fops);
+ return err;
}
static struct file_operations usb_fops = {
+ owner: THIS_MODULE,
open: usb_open,
};
@@ -1704,6 +1767,8 @@
* into the kernel, and other device drivers are built as modules,
* then these symbols need to be exported for the modules to use.
*/
+EXPORT_SYMBOL(usb_ifnum_to_if);
+
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_alloc_bus);
@@ -1724,6 +1789,9 @@
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_set_address);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)