patch-2.3.18 linux/drivers/usb/usb.c
Next file: linux/drivers/usb/usb.h
Previous file: linux/drivers/usb/uhci.c
Back to the patch index
Back to the overall index
- Lines: 270
- Date:
Fri Sep 10 12:59:49 1999
- Orig file:
v2.3.17/linux/drivers/usb/usb.c
- Orig date:
Tue Aug 31 17:29:14 1999
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -13,6 +13,8 @@
* are evil.
*/
+#define USB_DEBUG 1
+
#include <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
@@ -110,6 +112,82 @@
}
/*
+ * 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)
+{
+ 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);
+} /* end calc_bus_time */
+
+/*
+ * check_bandwidth_alloc():
+ *
+ * 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.
+ *
+ * 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 check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+{
+ unsigned int new_alloc;
+
+ new_alloc = old_alloc + bustime;
+ /* what new total allocated bus time would be */
+
+ PRINTD ("usb-bandwidth-alloc: was: %ld, new: %ld, bustime = %ld us, Pipe allowed: %s",
+ old_alloc, new_alloc, bustime,
+ (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
+ "yes" : "no");
+
+ return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1;
+} /* end check_bandwidth_alloc */
+
+/*
* New functions for (de)registering a controller
*/
struct usb_bus *usb_alloc_bus(struct usb_operations *op)
@@ -125,6 +203,9 @@
bus->op = op;
bus->root_hub = NULL;
bus->hcpriv = NULL;
+ bus->bandwidth_allocated = 0;
+ bus->bandwidth_int_reqs = 0;
+ bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD(&bus->bus_list);
@@ -237,9 +318,9 @@
{
if (atomic_dec_and_test(&dev->refcnt)) {
usb_destroy_configuration(dev);
- kfree(dev);
dev->bus->op->deallocate(dev);
+ kfree(dev);
}
}
@@ -609,7 +690,7 @@
int i = 5;
int result;
- dr.requesttype = 0x80;
+ dr.requesttype = USB_DIR_IN;
dr.request = USB_REQ_GET_DESCRIPTOR;
dr.value = (type << 8) + index;
dr.index = 0;
@@ -627,7 +708,7 @@
{
devrequest dr;
- dr.requesttype = 0x80;
+ dr.requesttype = USB_DIR_IN;
dr.request = USB_REQ_GET_DESCRIPTOR;
dr.value = (USB_DT_STRING << 8) + index;
dr.index = langid;
@@ -667,7 +748,7 @@
unsigned char buf[8];
devrequest dr;
- dr.requesttype = USB_RT_HIDD | 0x80;
+ dr.requesttype = USB_RT_HIDD | USB_DIR_IN;
dr.request = USB_REQ_GET_PROTOCOL;
dr.value = 0;
dr.index = 1;
@@ -764,7 +845,7 @@
return result;
#if 1 /* let's be really tough */
- dr.requesttype = 0x80 | USB_RT_ENDPOINT;
+ dr.requesttype = USB_DIR_IN | USB_RT_ENDPOINT;
dr.request = USB_REQ_GET_STATUS;
dr.length = 2;
status = 0xffff;
@@ -840,7 +921,7 @@
{
devrequest dr;
- dr.requesttype = USB_RT_HIDD | 0x80;
+ dr.requesttype = USB_RT_HIDD | USB_DIR_IN;
dr.request = USB_REQ_GET_REPORT;
dr.value = (type << 8) + id;
dr.index = index;
@@ -1047,9 +1128,32 @@
return dev->bus->op->control_msg(dev, pipe, &dr, data, size);
}
-void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
{
- return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+ long bustime;
+ int ret;
+
+ *handle = NULL;
+
+ /* Check host controller's bandwidth for this int. request. */
+ bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
+ usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+ bustime = NS_TO_US(bustime); /* work in microseconds */
+ if (check_bandwidth_alloc (dev->bus->bandwidth_allocated, bustime))
+ return (USB_ST_BANDWIDTH_ERROR);
+
+ ret = dev->bus->op->request_irq(dev, pipe, handler, period, dev_id, handle);
+
+ /* Claim the USB bandwidth if no error. */
+ if (!ret) {
+ dev->bus->bandwidth_allocated += bustime;
+ dev->bus->bandwidth_int_reqs++;
+ PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+ dev->bus->bandwidth_allocated,
+ dev->bus->bandwidth_int_reqs);
+ }
+
+ return ret;
}
void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
@@ -1062,9 +1166,26 @@
return dev->bus->op->terminate_bulk(dev, first);
}
-int usb_release_irq(struct usb_device *dev, void *handle)
+int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe)
{
- return dev->bus->op->release_irq(dev, handle);
+ long bustime;
+ int err;
+
+ err = dev->bus->op->release_irq(dev, handle);
+
+ /* Return the USB bandwidth if no error. */
+ if (!err) {
+ bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
+ usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+ bustime = NS_TO_US(bustime);
+ dev->bus->bandwidth_allocated -= bustime;
+ dev->bus->bandwidth_int_reqs--;
+ PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+ dev->bus->bandwidth_allocated,
+ dev->bus->bandwidth_int_reqs);
+ }
+
+ return err;
}
/*
@@ -1084,11 +1205,46 @@
void *context,
struct usb_isoc_desc **isocdesc)
{
- return usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc);
+ long bustime;
+ int err;
+
+ /* Check host controller's bandwidth for this Isoc. request. */
+ /* TBD: some way to factor in frame_spacing ??? */
+ bustime = calc_bus_time (0, usb_pipein(pipe), 1,
+ usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)));
+ bustime = NS_TO_US(bustime); /* work in microseconds */
+ if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime))
+ return USB_ST_BANDWIDTH_ERROR;
+
+ err = usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc);
+
+ /* Claim the USB bandwidth if no error. */
+ if (!err) {
+ usb_dev->bus->bandwidth_allocated += bustime;
+ usb_dev->bus->bandwidth_isoc_reqs++;
+ PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+ usb_dev->bus->bandwidth_allocated,
+ usb_dev->bus->bandwidth_isoc_reqs);
+ }
+
+ return err;
}
void usb_free_isoc (struct usb_isoc_desc *isocdesc)
{
+ long bustime;
+
+ /* Return the USB bandwidth. */
+ bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1,
+ usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe,
+ usb_pipeout(isocdesc->pipe)));
+ bustime = NS_TO_US(bustime);
+ isocdesc->usb_dev->bus->bandwidth_allocated -= bustime;
+ isocdesc->usb_dev->bus->bandwidth_isoc_reqs--;
+ PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+ isocdesc->usb_dev->bus->bandwidth_allocated,
+ isocdesc->usb_dev->bus->bandwidth_isoc_reqs);
+
isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)