ChangeSet 1.1760.26.25, 2004/06/29 14:33:28-07:00, greg@kroah.com USB: fix bug where removing usb-serial modules or usb serial devices could oops This fixes the issue where the Generic driver would bind to all usb-serial devices, so the disconnect would not properly go to the real driver that controlled the device. This was very bad when unloading the module with the device still connected. Signed-off-by: Greg Kroah-Hartman drivers/usb/serial/generic.c | 33 +++++++++++++++++++++++++++++++++ drivers/usb/serial/usb-serial.c | 28 +--------------------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff -Nru a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c --- a/drivers/usb/serial/generic.c 2004-06-29 16:24:39 -07:00 +++ b/drivers/usb/serial/generic.c 2004-06-29 16:24:39 -07:00 @@ -53,6 +53,32 @@ .num_ports = 1, .shutdown = usb_serial_generic_shutdown, }; + +/* we want to look at all devices, as the vendor/product id can change + * depending on the command line argument */ +static struct usb_device_id generic_serial_ids[] = { + {.driver_info = 42}, + {} +}; + +static int generic_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + const struct usb_device_id *id_pattern; + + id_pattern = usb_match_id(interface, generic_device_ids); + if (id_pattern != NULL) + return usb_serial_probe(interface, id); + return -ENODEV; +} + +static struct usb_driver generic_driver = { + .owner = THIS_MODULE, + .name = "usbserial_generic", + .probe = generic_probe, + .disconnect = usb_serial_disconnect, + .id_table = generic_serial_ids, +}; #endif int usb_serial_generic_register (int _debug) @@ -67,6 +93,12 @@ /* register our generic driver with ourselves */ retval = usb_serial_register (&usb_serial_generic_device); + if (retval) + goto exit; + retval = usb_register(&generic_driver); + if (retval) + usb_serial_deregister(&usb_serial_generic_device); +exit: #endif return retval; } @@ -75,6 +107,7 @@ { #ifdef CONFIG_USB_SERIAL_GENERIC /* remove our generic driver */ + usb_deregister(&generic_driver); usb_serial_deregister (&usb_serial_generic_device); #endif } diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c 2004-06-29 16:24:39 -07:00 +++ b/drivers/usb/serial/usb-serial.c 2004-06-29 16:24:39 -07:00 @@ -355,25 +355,12 @@ #define DRIVER_DESC "USB Serial Driver core" -#ifdef CONFIG_USB_SERIAL_GENERIC -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - -#endif /* CONFIG_USB_SERIAL_GENERIC */ - /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .owner = THIS_MODULE, .name = "usbserial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, -#ifdef CONFIG_USB_SERIAL_GENERIC - .id_table = generic_serial_ids, -#endif }; /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead @@ -1383,22 +1370,9 @@ void usb_serial_deregister(struct usb_serial_device_type *device) { - struct usb_serial *serial; - int i; - info("USB Serial deregistering driver %s", device->name); - - /* clear out the serial_table if the device is attached to a port */ - for(i = 0; i < SERIAL_TTY_MINORS; ++i) { - serial = serial_table[i]; - if ((serial != NULL) && (serial->type == device)) { - usb_driver_release_interface (&usb_serial_driver, serial->interface); - usb_serial_disconnect (serial->interface); - } - } - list_del(&device->driver_list); - usb_serial_bus_deregister (device); + usb_serial_bus_deregister(device); }