usbatm subdriver registration w/o .driver_info

Roman Kagan rkagan at mail.ru
Thu Jan 27 03:56:54 EST 2005


  Hi Duncan,

Here's a quick patch to usbatm2 making the subdriver registration to not
use .driver_info.  It's based on the technique shamelessly borrowed from
usb-serial, where the core maintains a list of subdrivers updated at
module init/exit, and in probe it searches through the list and finds
the one which succeeds usb_match_id.

I'm concerned a bit whether it (and usb-serial) is using the right list
primitives, because during the search another subdriver can be
(un)loaded and the list may become inconsistent.  I'll go through
include/linux/list.h and try to find better ones (*_rcu ?).

Also the patch adds a trivial __exit function otherwise the module gets
permanent.

I didn't commit directly to avoid interfering with your work.  It's
compile-tested fine and run-tested with an unrelated failure I'll
describe in a separate post.  Please consider as one of the
possibilities.

Cheers,
  Roman.

Index: usbatm.h
===================================================================
RCS file: /home/cvs/usbatm/usbatm.h,v
retrieving revision 1.3
diff -u -r1.3 usbatm.h
--- usbatm.h	25 Jan 2005 08:18:09 -0000	1.3
+++ usbatm.h	27 Jan 2005 08:22:06 -0000
@@ -91,6 +91,7 @@
 
 	/* private */
 	struct usb_driver usb;
+	struct list_head driver_list;
 };
 
 int usbatm_register (struct usbatm_driver *driver);
Index: usbatm2.c
===================================================================
RCS file: /home/cvs/usbatm/usbatm2.c,v
retrieving revision 1.11
diff -u -r1.11 usbatm2.c
--- usbatm2.c	25 Jan 2005 08:18:09 -0000	1.11
+++ usbatm2.c	27 Jan 2005 08:22:06 -0000
@@ -1046,10 +1046,26 @@
 	return 0;
 }
 
+static LIST_HEAD(usbatm_driver_list);
+
+static struct usbatm_driver *search_usbatm_driver(struct usb_interface *intf)
+{
+	struct usbatm_driver *drv;
+
+	/* List trough known devices and see if the usb id matches */
+	list_for_each_entry(drv, &usbatm_driver_list, driver_list) {
+		const struct usb_device_id *id = usb_match_id(intf, drv->id_table);
+		if (id != NULL)
+			return drv;
+	}
+
+	return NULL;
+}
+
 static int usbatm_usb_probe (struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usbatm_driver *driver = (struct usbatm_driver *) id->driver_info;
+	struct usbatm_driver *driver = search_usbatm_driver(intf);
 	struct usbatm_data *instance;
 	char *buf;
 	int error = -ENOMEM;
@@ -1306,12 +1322,15 @@
         usb_driver->disconnect	= usbatm_disconnect;
         usb_driver->id_table	= driver->id_table;
 
+	list_add(&driver->driver_list, &usbatm_driver_list);
+
 	return usb_register(usb_driver);
 }
 EXPORT_SYMBOL_GPL(usbatm_register);
 
 void usbatm_deregister (struct usbatm_driver *driver)
 {
+	list_del(&driver->driver_list);
 	usb_deregister(&driver->usb);
 }
 EXPORT_SYMBOL_GPL(usbatm_deregister);
@@ -1337,6 +1356,11 @@
 }
 module_init(udsl_usb_init);
 
+static void __exit udsl_usb_exit(void)
+{
+}
+module_exit(udsl_usb_exit);
+
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");



More information about the Usbatm mailing list