patch-2.4.0-test10 linux/drivers/usb/usb.c

Next file: linux/drivers/usb/usbmouse.c
Previous file: linux/drivers/usb/usb-uhci.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test9/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -26,6 +26,7 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>  /* for in_interrupt() */
 #include <linux/kmod.h>
+#include <linux/init.h>
 
 
 #ifdef CONFIG_USB_DEBUG
@@ -47,6 +48,9 @@
 				0;
 #endif
 
+extern int  usb_hub_init(void);
+extern void usb_hub_cleanup(void);
+
 /*
  * Prototypes for the device driver probing/loading functions
  */
@@ -462,6 +466,10 @@
  * We now walk the list of registered USB drivers,
  * looking for one that will accept this interface.
  *
+ * "New Style" drivers use a table describing the devices and interfaces
+ * they handle.  Those tables are available to user mode tools deciding
+ * whether to load driver modules for a new device.
+ *
  * The probe return value is changed to be a private pointer.  This way
  * the drivers don't have to dig around in our structures to set the
  * private pointer if they only need one interface. 
@@ -490,7 +498,70 @@
 			
 		tmp = tmp->next;
 		down(&driver->serialize);
-		private = driver->probe(dev, ifnum);
+
+		/* new style driver? */
+		if (driver->bind) {
+		    const struct usb_device_id	*id = driver->id_table;
+
+		    if (id) {
+			/* scan device ids for a match */
+			for (;; id++) {
+			    struct usb_interface_descriptor	*intf = 0;
+
+			    /* done? */
+			    if (!id->idVendor && !id->bDeviceClass && !id->bInterfaceClass) {
+				id = 0;
+				break;
+			    }
+
+			    /* Vendor match, possibly product-specific? */
+			    if (id->idVendor && id->idVendor == dev->descriptor.idVendor) {
+				if (id->idProduct && id->idProduct != dev->descriptor.idProduct)
+				    continue;
+				break;
+			    }
+
+			    /* Device class match? */
+			    if (id->bDeviceClass
+				    && id->bDeviceClass == dev->descriptor.bDeviceClass) {
+				if (id->bDeviceSubClass && id->bDeviceSubClass
+					!= dev->descriptor.bDeviceClass)
+				    continue;
+				if (id->bDeviceProtocol && id->bDeviceProtocol
+					!= dev->descriptor.bDeviceProtocol)
+				    continue;
+				break;
+			    }
+
+			    /* Interface class match? */
+			    if (!interface->altsetting || interface->num_altsetting < 1)
+				continue;
+			    intf = &interface->altsetting [0];
+			    if (id->bInterfaceClass
+				    && id->bInterfaceClass == intf->bInterfaceClass) {
+				if (id->bInterfaceSubClass && id->bInterfaceSubClass
+					!= intf->bInterfaceClass)
+				    continue;
+				if (id->bInterfaceProtocol && id->bInterfaceProtocol
+					!= intf->bInterfaceProtocol)
+				    continue;
+				break;
+			    }
+			} 
+			
+			/* is this driver interested in this interface? */
+			if (id)
+			    private = driver->bind(dev, ifnum, id);
+			else
+			    private = 0;
+		    } else {
+			/* "old style" driver, but using new interface */
+			private = driver->bind(dev, ifnum, 0);
+		    }
+
+		/* "old style" driver */
+		} else
+		    private = driver->probe(dev, ifnum);
 		up(&driver->serialize);
 		if (!private)
 			continue;
@@ -758,6 +829,7 @@
 {
 	atomic_inc(&dev->refcnt);
 }
+
 /* ------------------------------------------------------------------------------------- 
  * New USB Core Functions
  * -------------------------------------------------------------------------------------*/
@@ -836,7 +908,6 @@
 	int status;
   
 	awd.wakeup = &wqh;
-	awd.handler = 0;
 	init_waitqueue_head(&wqh); 	
 	current->state = TASK_INTERRUPTIBLE;
 	add_wait_queue(&wqh, &wait);
@@ -1518,9 +1589,9 @@
 	while (i--) {
 		if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
-			(type << 8) + index, 0, buf, size, HZ * GET_TIMEOUT)) >= 0 ||
+			(type << 8) + index, 0, buf, size, HZ * GET_TIMEOUT)) > 0 ||
 		     result == -EPIPE)
-			break;
+			break;	/* retry if the returned length was 0; flaky device */
 	}
 	return result;
 }
@@ -2028,6 +2099,32 @@
 	return &usb_bus_list;
 }
 #endif
+
+
+/*
+ * Init
+ */
+static int __init usb_init(void)
+{
+	usb_major_init();
+	usbdevfs_init();
+	usb_hub_init();
+
+	return 0;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit usb_exit(void)
+{
+	usb_major_cleanup();
+	usbdevfs_cleanup();
+	usb_hub_cleanup();
+}
+
+module_init(usb_init);
+module_exit(usb_exit);
 
 /*
  * USB may be built into the kernel or be built as modules.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)