On Wed, 4 Jan 2012, Alan Stern wrote: > David, can you test this patch in place of the earlier one? Forget about that patch. After discussing this with a bunch of people, I came up with a completely different solution. Here's the patch to try next. Alan Stern Index: usb-3.2/include/linux/usb/serial.h =================================================================== --- usb-3.2.orig/include/linux/usb/serial.h +++ usb-3.2/include/linux/usb/serial.h @@ -300,8 +300,14 @@ struct usb_serial_driver { #define to_usb_serial_driver(d) \ container_of(d, struct usb_serial_driver, driver) +/* To be removed soon... */ extern int usb_serial_register(struct usb_serial_driver *driver); extern void usb_serial_deregister(struct usb_serial_driver *driver); + +extern int usb_serial_register_drivers(struct usb_driver *udriver, + struct usb_serial_driver *serial_drivers[]); +extern void usb_serial_deregister_drivers(struct usb_driver *udriver, + struct usb_serial_driver *serial_drivers[]); extern void usb_serial_port_softint(struct usb_serial_port *port); extern int usb_serial_probe(struct usb_interface *iface, Index: usb-3.2/drivers/usb/serial/usb-serial.c =================================================================== --- usb-3.2.orig/drivers/usb/serial/usb-serial.c +++ usb-3.2/drivers/usb/serial/usb-serial.c @@ -1386,6 +1386,76 @@ void usb_serial_deregister(struct usb_se } EXPORT_SYMBOL_GPL(usb_serial_deregister); +/** + * usb_serial_register_drivers - register drivers for a usb-serial module + * @udriver: usb_driver used for matching devices/interfaces + * @serial_drivers: NULL-terminated array of pointers to drivers + * + * Registers @udriver and all the drivers in the @serial_drivers array. + * Automatically fills in the .no_dynamic_id field in @udriver and + * the .usb_driver field in each serial driver. + */ +int usb_serial_register_drivers(struct usb_driver *udriver, + struct usb_serial_driver *serial_drivers[]) +{ + int rc; + const struct usb_device_id *saved_id_table; + struct usb_serial_driver **sd; + + /* + * udriver must be registered before any of the serial drivers, + * because the store_new_id() routine for the serial drivers (in + * bus.c) probes udriver. + * + * Performance hack: We don't want udriver to be probed until + * the serial drivers are registered, because the probe would + * simply fail for lack of a matching serial driver. + * Therefore save off udriver's id_table until we are all set. + */ + saved_id_table = udriver->id_table; + udriver->id_table = NULL; + + udriver->no_dynamic_id = 1; + rc = usb_register(udriver); + if (rc) + return rc; + + for (sd = serial_drivers; *sd; ++sd) { + (*sd)->usb_driver = udriver; + rc = usb_serial_register(*sd); + if (rc) + goto failed; + } + + /* Now restore udriver's id_table and look for matches */ + udriver->id_table = saved_id_table; + rc = driver_attach(&udriver->drvwrap.driver); + return 0; + + failed: + while (sd-- > serial_drivers) + usb_serial_deregister(*sd); + usb_deregister(udriver); + return rc; +} +EXPORT_SYMBOL_GPL(usb_serial_register_drivers); + +/** + * usb_serial_deregister_drivers - deregister drivers for a usb-serial module + * @udriver: usb_driver used for matching devices/interfaces + * @serial_drivers: NULL-terminated array of pointers to drivers + * + * Deregisters @udriver and all the drivers in the @serial_drivers array. + */ +void usb_serial_deregister_drivers(struct usb_driver *udriver, + struct usb_serial_driver *serial_drivers[]) +{ + for (; *serial_drivers; ++serial_drivers) + usb_serial_deregister(*serial_drivers); + usb_deregister(udriver); +} +EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); + /* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); Index: usb-3.2/drivers/usb/serial/ftdi_sio.c =================================================================== --- usb-3.2.orig/drivers/usb/serial/ftdi_sio.c +++ usb-3.2/drivers/usb/serial/ftdi_sio.c @@ -852,7 +852,6 @@ static struct usb_driver ftdi_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, - .no_dynamic_id = 1, }; static const char *ftdi_chip_name[] = { @@ -910,7 +909,6 @@ static struct usb_serial_driver ftdi_sio .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", - .usb_driver = &ftdi_driver, .id_table = id_table_combined, .num_ports = 1, .bulk_in_size = 512, @@ -933,6 +931,10 @@ static struct usb_serial_driver ftdi_sio .break_ctl = ftdi_break_ctl, }; +static struct usb_serial_driver *serial_drivers[] = { + &ftdi_sio_device, NULL +}; + #define WDR_TIMEOUT 5000 /* default urb timeout */ #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ @@ -2413,19 +2415,10 @@ static int __init ftdi_init(void) id_table_combined[i].idVendor = vendor; id_table_combined[i].idProduct = product; } - retval = usb_serial_register(&ftdi_sio_device); - if (retval) - goto failed_sio_register; - retval = usb_register(&ftdi_driver); - if (retval) - goto failed_usb_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return 0; -failed_usb_register: - usb_serial_deregister(&ftdi_sio_device); -failed_sio_register: + retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers); + if (retval == 0) + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return retval; } @@ -2433,8 +2426,7 @@ static void __exit ftdi_exit(void) { dbg("%s", __func__); - usb_deregister(&ftdi_driver); - usb_serial_deregister(&ftdi_sio_device); + usb_serial_deregister_drivers(&ftdi_driver, serial_drivers); } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html