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