patch-2.3.4 linux/drivers/usb/usb.c
Next file: linux/drivers/usb/usb.h
Previous file: linux/drivers/usb/usb-debug.c
Back to the patch index
Back to the overall index
- Lines: 472
- Date:
Mon May 31 09:01:50 1999
- Orig file:
v2.3.3/linux/drivers/usb/usb.c
- Orig date:
Sat May 15 23:46:04 1999
diff -u --recursive --new-file v2.3.3/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -36,110 +36,149 @@
* 6 wLength 2 Count Bytes for data
*/
+#include <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
#include "usb.h"
-#ifdef CONFIG_USB_UHCI
-int uhci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI
-int ohci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-int ohci_hcd_init(void);
-#endif
-
-int usb_init(void)
-{
-#ifdef CONFIG_USB_UHCI
- uhci_init();
-#endif
-#ifdef CONFIG_USB_OHCI
- ohci_init();
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
- ohci_hcd_init();
-#endif
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
- usb_kbd_init();
-#endif
-#ifdef CONFIG_USB_AUDIO
- usb_audio_init();
-#endif
-#ifdef CONFIG_USB_ACM
- usb_acm_init();
-#endif
-#ifdef CONFIG_USB_CPIA
- usb_cpia_init();
-#endif
-
- usb_hub_init();
- return 0;
-}
-
-void cleanup_drivers(void)
-{
- hub_cleanup();
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_cleanup();
-#endif
-}
-
/*
* We have a per-interface "registered driver" list.
*/
static LIST_HEAD(usb_driver_list);
+static LIST_HEAD(usb_bus_list);
int usb_register(struct usb_driver *new_driver)
{
+ struct list_head *tmp = usb_bus_list.next;
/* Add it to the list of known drivers */
list_add(&new_driver->driver_list, &usb_driver_list);
/*
- * We should go through all existing devices, and see if any of
- * them would be acceptable to the new driver.. Let's do that
- * in version 2.0.
+ * We go through all existing devices, and see if any of them would
+ * be acceptable to the new driver.. This is done using a depth-first
+ * search for devices without a registered driver already, then
+ * running 'probe' with each of the drivers registered on every one
+ * of these.
*/
+ while (tmp!= &usb_bus_list) {
+ struct usb_bus * bus = list_entry(tmp,struct
+ usb_bus,bus_list);
+ tmp=tmp->next;
+ usb_check_support(bus->root_hub);
+ }
return 0;
}
void usb_deregister(struct usb_driver *driver)
{
+ struct list_head *tmp = usb_bus_list.next;
+ /*first we remove the driver, to be sure it doesn't get used by
+ *another thread while we are stepping through removing entries
+ */
list_del(&driver->driver_list);
+ printk("usbcore: deregistering driver\n");
+ while (tmp!= &usb_bus_list) {
+ struct usb_bus * bus = list_entry(tmp,struct
+ usb_bus,bus_list);
+ tmp=tmp->next;
+ usb_driver_purge(driver,bus->root_hub);
+ }
+}
+
+/* This function is part of a depth-first search down the device tree,
+ * removing any instances of a device driver.
+ */
+void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev)
+{
+ int i;
+ if (dev==NULL){
+ printk("null device being passed in!!!\n");
+ return;
+ }
+ for (i=0;i<USB_MAXCHILDREN;i++)
+ if (dev->children[i]!=NULL)
+ usb_driver_purge(driver,dev->children[i]);
+ /*now we check this device*/
+ if(dev->driver==driver) {
+ /*
+ * Note: this is not the correct way to do this, this
+ * uninitializes and reinitializes EVERY driver
+ */
+ printk("disconnecting driverless device\n");
+ dev->driver->disconnect(dev);
+ dev->driver=NULL;
+ /* This will go back through the list looking for a driver
+ * that can handle the device
+ */
+ usb_device_descriptor(dev);
+ }
+}
+
+/*
+ * New functions for (de)registering a controller
+ */
+void usb_register_bus(struct usb_bus *new_bus)
+{
+ /* Add it to the list of buses */
+ list_add(&new_bus->bus_list, &usb_bus_list);
+ printk("New bus registered");
+}
+
+void usb_deregister_bus(struct usb_bus *bus)
+{
+ /* NOTE: make sure that all the devices are removed by the
+ * controller code, as well as having it call this when cleaning
+ * itself up
+ */
+ list_del(&bus->bus_list);
}
/*
+ * This function is for doing a depth-first search for devices which
+ * have support, for dynamic loading of driver modules.
+ */
+void usb_check_support(struct usb_device *dev)
+{
+ int i;
+ if (dev==NULL)
+ {
+ printk("null device being passed in!!!\n");
+ return;
+ }
+ for (i=0;i<USB_MAXCHILDREN;i++)
+ if ((dev->children[i]!=NULL)&&
+ (dev->children[i]->driver==NULL))
+ usb_check_support(dev->children[i]);
+ /*now we check this device*/
+ usb_device_descriptor(dev);
+}
+/*
* This entrypoint gets called for each new device.
*
* We now walk the list of registered USB drivers,
* looking for one that will accept this device as
* his..
*/
-void usb_device_descriptor(struct usb_device *dev)
+int usb_device_descriptor(struct usb_device *dev)
{
struct list_head *tmp = usb_driver_list.next;
while (tmp != &usb_driver_list) {
- struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+ struct usb_driver *driver = list_entry(tmp, struct usb_driver,
+ driver_list);
tmp = tmp->next;
if (driver->probe(dev))
continue;
dev->driver = driver;
- return;
+ return 1;
}
-
/*
* Ok, no driver accepted the device, so show the info
* for debugging..
*/
- printk("Unknown new USB device:\n");
- usb_show_device(dev);
+ return 0;
}
/*
@@ -370,6 +409,7 @@
if(dev->config==NULL)
return;
+
for(c=0;c<dev->descriptor.bNumConfigurations;c++)
{
cf=&dev->config[c];
@@ -385,6 +425,11 @@
kfree(cf->interface);
}
kfree(dev->config);
+
+ if (dev->stringindex)
+ kfree(dev->stringindex);
+ if (dev->stringtable)
+ kfree(dev->stringtable);
}
void usb_init_root_hub(struct usb_device *dev)
@@ -462,6 +507,8 @@
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
devrequest dr;
+ int i = 5;
+ int result;
dr.requesttype = 0x80;
dr.request = USB_REQ_GET_DESCRIPTOR;
@@ -469,7 +516,30 @@
dr.index = 0;
dr.length = size;
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+ while (i--) {
+ if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
+ break;
+ }
+ return result;
+}
+
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+{
+ devrequest dr;
+ int i = 5;
+ int result;
+
+ dr.requesttype = 0x80;
+ dr.request = USB_REQ_GET_DESCRIPTOR;
+ dr.value = (USB_DT_STRING << 8) + index;
+ dr.index = langid;
+ dr.length = size;
+
+ while (i--) {
+ if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
+ break;
+ }
+ return result;
}
int usb_get_device_descriptor(struct usb_device *dev)
@@ -593,6 +663,24 @@
return 0;
}
+static void usb_set_maxpacket(struct usb_device *dev)
+{
+ struct usb_endpoint_descriptor *ep;
+ struct usb_interface_descriptor *ip = dev->actconfig->interface;
+ int i;
+
+ for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
+ if (dev->actconfig->interface[i].bInterfaceNumber == dev->ifnum) {
+ ip = &dev->actconfig->interface[i];
+ break;
+ }
+ }
+ ep = ip->endpoint;
+ for (i=0; i<ip->bNumEndpoints; i++) {
+ dev->epmaxpacket[ep[i].bEndpointAddress & 0x0f] = ep[i].wMaxPacketSize;
+ }
+}
+
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
devrequest dr;
@@ -606,6 +694,8 @@
if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
return -1;
+ dev->ifnum = interface;
+ usb_set_maxpacket(dev);
return 0;
}
@@ -613,16 +703,31 @@
int usb_set_configuration(struct usb_device *dev, int configuration)
{
devrequest dr;
-
+ int i;
+ struct usb_config_descriptor *cp = NULL;
+
dr.requesttype = 0;
dr.request = USB_REQ_SET_CONFIGURATION;
dr.value = configuration;
dr.index = 0;
dr.length = 0;
+ for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+ if (dev->config[i].bConfigurationValue == configuration) {
+ cp = &dev->config[i];
+ break;
+ }
+ }
+ if (!cp) {
+ printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration);
+ return -1;
+ }
if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
return -1;
+ dev->actconfig = cp;
+ dev->toggle = 0;
+ usb_set_maxpacket(dev);
return 0;
}
@@ -671,6 +776,61 @@
return usb_parse_configuration(dev, buffer, bufptr - buffer);
}
+int usb_get_stringtable(struct usb_device *dev)
+{
+ int i;
+ int maxindex;
+ int langid;
+ unsigned char buffer[256];
+ int totalchars;
+ struct usb_string_descriptor *sd = (struct usb_string_descriptor *)buffer;
+ char *string;
+ __u8 bLengths[USB_MAXSTRINGS+1];
+ int j;
+
+ dev->maxstring = 0;
+ if(usb_get_string(dev, 0, 0, buffer, 2) ||
+ usb_get_string(dev, 0, 0, buffer, sd->bLength))
+ return -1;
+ /* we are going to assume that the first ID is good */
+ langid = sd->wData[0];
+
+ /* whip through and find total length and max index */
+ for (maxindex = 1, totalchars = 0; maxindex<=USB_MAXSTRINGS; maxindex++) {
+ if(usb_get_string(dev, langid, maxindex, buffer, 2))
+ break;
+ totalchars += (sd->bLength - 2)/2 + 1;
+ bLengths[maxindex] = sd->bLength;
+ }
+ if (--maxindex <= 0)
+ return -1;
+
+ /* get space for strings and index */
+ dev->stringindex = kmalloc(sizeof(char *)*maxindex, GFP_KERNEL);
+ if (!dev->stringindex)
+ return -1;
+ dev->stringtable = kmalloc(totalchars, GFP_KERNEL);
+ if (!dev->stringtable) {
+ kfree(dev->stringindex);
+ dev->stringindex = NULL;
+ return -1;
+ }
+
+ /* fill them in */
+ memset(dev->stringindex, 0, sizeof(char *)*maxindex);
+ for (i=1, string = dev->stringtable; i <= maxindex; i++) {
+ if (usb_get_string(dev, langid, i, buffer, bLengths[i]))
+ continue;
+ dev->stringindex[i] = string;
+ for (j=0; j < (bLengths[i] - 2)/2; j++) {
+ *string++ = sd->wData[j];
+ }
+ *string++ = '\0';
+ }
+ dev->maxstring = maxindex;
+ return 0;
+}
+
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
@@ -684,10 +844,12 @@
dev->devnum);
dev->maxpacketsize = 0; /* Default to 8 byte max packet size */
+ dev->epmaxpacket[0] = 8;
addr = dev->devnum;
dev->devnum = 0;
+#if 1
/* Slow devices */
for (i = 0; i < 5; i++) {
if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
@@ -700,10 +862,12 @@
printk("giving up\n");
return;
}
+#endif
#if 0
printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
#endif
+ dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0;
switch (dev->descriptor.bMaxPacketSize0) {
case 8: dev->maxpacketsize = 0; break;
case 16: dev->maxpacketsize = 1; break;
@@ -716,11 +880,15 @@
dev->devnum = addr;
+#if 1
if (usb_set_address(dev)) {
printk("Unable to set address\n");
/* FIXME: We should disable the port */
return;
}
+#else
+ usb_set_address(dev);
+#endif
wait_ms(10); /* Let the SET_ADDRESS settle */
@@ -734,12 +902,30 @@
return;
}
+ usb_get_stringtable(dev);
+
+ dev->actconfig = dev->config;
+ dev->ifnum = 0;
+ usb_set_maxpacket(dev);
+
+ usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
+ usb_show_string(dev, "Product", dev->descriptor.iProduct);
+ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+
#if 0
printk("Vendor: %X\n", dev->descriptor.idVendor);
printk("Product: %X\n", dev->descriptor.idProduct);
#endif
- usb_device_descriptor(dev);
+ if (usb_device_descriptor(dev)==0)
+ {
+ /*
+ * Ok, no driver accepted the device, so show the info for
+ * debugging
+ */
+ printk ("Unknown new USB device:\n");
+ usb_show_device(dev);
+ }
}
int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)