On Wed, May 04, 2005 at 10:30:57AM +0400, Roman Kagan wrote:
> On Fri, Apr 29, 2005 at 02:34:59PM -0400, Alan Stern wrote:
> > Does the patch look good? If you like it, I'll submit it to Greg.
>
> Yes it looks reasonable. At the moment I can't test the problematic
> multi-interface USB device case where that bug revealed itself, which
> was observed by Duncan Sands; I'm attaching a simple test case we've
> been using to trigger the problem, so you may want to try it out before
> submitting. To do that, you need to load the test driver giving vendor and
> product IDs of your multi-interface device as module parameters, and
> then rmmod the driver while the device is still plugged in: it used to
> spin forever
Sorry, forgot to attach the test case (it's very simple but can save you
a bit of typing).
Roman.
===============================================================
#define DEBUG
#include <linux/module.h>
#include <linux/usb.h>
unsigned short vendor;
module_param(vendor, ushort, 0444);
unsigned short product;
module_param(product, ushort, 0444);
static int test_usb_probe(struct usb_interface *intf, const struct
usb_device_id *id);
void test_usb_disconnect(struct usb_interface *intf);
static struct usb_device_id test_usb_ids[2];
static struct usb_driver test_usb_driver = {
.owner = THIS_MODULE,
.name = "test",
.probe = test_usb_probe,
.disconnect = test_usb_disconnect,
.id_table = test_usb_ids
};
static void release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
struct usb_interface *cur_intf;
int i;
dbg("%s entered", __func__);
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(&test_usb_driver,
cur_intf);
}
}
static int test_usb_probe(struct usb_interface *intf, const struct
usb_device_id *id)
{
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("%s entered: intf 0x%p driver 0x%p", __func__, intf,
intf->dev.driver);
for (i=0; i < num_interfaces; i++) {
cur_intf = usb_ifnum_to_if(usb_dev, i);
if ((i != ifnum) && cur_intf) {
dbg("%s: claiming intf 0x%p", __func__, cur_intf);
ret = usb_driver_claim_interface(&test_usb_driver,
cur_intf, usb_dev);
if (ret < 0) {
dbg("%s: failed to claim interface %d (%d)\n",
__func__, i, ret);
release_interfaces(usb_dev, i);
return ret;
}
dbg("%s: claimed intf 0x%p driver 0x%p", __func__,
cur_intf, cur_intf->dev.driver);
}
}
return 0;
}
void test_usb_disconnect(struct usb_interface *intf)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
int i = 0;
struct list_head *l, *n;
dbg("%s entered: intf 0x%p driver 0x%p", __func__, intf,
intf->dev.driver);
if (intf->dev.driver)
list_for_each_safe(l, n, &intf->dev.driver->devices)
i++;
dbg("%s: driver 0x%p has %d devices", __func__, intf->dev.driver, i);
if (usb_get_intfdata(intf))
release_interfaces(usb_dev, num_interfaces);
else
dbg("NULL instance");
}
static int __init test_init(void)
{
dbg("%s entered", __func__);
printk("vendor: %04x, product: %04x\n", vendor, product);
test_usb_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
test_usb_ids[0].idVendor = vendor;
test_usb_ids[0].idProduct = product;
return usb_register(&test_usb_driver);
}
module_init(test_init);
static void __exit test_exit(void)
{
dbg("%s entered", __func__);
usb_deregister(&test_usb_driver);
}
module_exit(test_exit);
MODULE_LICENSE("GPL");
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4
opportunities to win big! Highest score wins.NEC IT Guy Games. Play to
win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel