speedtch testatm.c,1.4,1.5

Duncan Sands duncan at infradead.org
Thu Apr 7 18:16:20 EDT 2005


Update of /home/cvs/speedtch
In directory phoenix.infradead.org:/tmp/cvs-serv22983

Modified Files:
	testatm.c 
Log Message:
Add a driver that claims all interfaces (and drops them all whenever any
one of them is disconnected).  It seems to have exposed a USB bug: if you
plug in a device with more than one interface and use driver 8 on it, then
force a logical (rather than a physical) disconnect, then afterwards the
module cannot be unloaded and rmmod spins taking up all CPU.  For example,
just try to remove the testatm module without unplugging the device.


Index: testatm.c
===================================================================
RCS file: /home/cvs/speedtch/testatm.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- testatm.c	7 Feb 2005 17:42:29 -0000	1.4
+++ testatm.c	7 Apr 2005 22:16:18 -0000	1.5
@@ -31,25 +31,29 @@
 uint	idProduct;
 module_param(idProduct, uint, 0444);
 
-static int accept_bind(struct usbatm_data *usbatm, struct usb_interface *intf, int *need_heavy_init)
+static int accept_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id, int *need_heavy_init)
 {
 	dbg("accept_bind");
 
 	return 0;
 }
 
-static int refuse_bind(struct usbatm_data *usbatm, struct usb_interface *intf, int *need_heavy_init)
+static int refuse_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id, int *need_heavy_init)
 {
 	dbg("refuse_bind");
 
 	return -1;
 }
 
+static int claim_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id, int *need_heavy_init);
+
 void testatm_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
 	dbg("testatm_unbind");
 }
 
+void claim_unbind(struct usbatm_data *usbatm, struct usb_interface *intf);
+
 static int accept_atm(struct usbatm_data *usbatm, struct atm_dev *dev)
 {
 	dbg("accept_atm");
@@ -183,6 +187,13 @@
 
 		.atm_start	= accept_atm,
 		.atm_stop	= testatm_atm_stop
+	},
+	{
+		.owner          = THIS_MODULE,
+	        .driver_name    = "testatm_8",
+
+		.bind		= claim_bind,
+		.unbind		= claim_unbind,
 	}
 };
 
@@ -205,6 +216,54 @@
 	.id_table	= testatm_usb_ids
 };
 
+static void release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
+	struct usb_interface *cur_intf;
+	int i;
+
+	for(i = 0; i < num_interfaces; i++)
+		if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
+			usb_set_intfdata(cur_intf, NULL);
+			usb_driver_release_interface(&testatm_usb_driver, cur_intf);
+		}
+}
+
+static int claim_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id, int *need_heavy_init)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct usb_interface *cur_intf;
+	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
+	int i, ret;
+
+	dbg("claim_bind");
+
+	for (i=0; i < num_interfaces; i++) {
+		cur_intf = usb_ifnum_to_if(usb_dev, i);
+
+		if ((i != ifnum) && cur_intf) {
+			ret = usb_driver_claim_interface(&testatm_usb_driver, cur_intf, usbatm);
+
+			if (ret < 0) {
+				usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
+				release_interfaces(usb_dev, i);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void claim_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
+
+	dbg("claim_unbind");
+
+	release_interfaces(usb_dev, num_interfaces);
+}
+
 static int __init testatm_init(void)
 {
 	struct usbatm_driver *test_driver = &testatm_drivers[driver];




More information about the Usbatm-commits mailing list