This adds support for dynamic usb ids to the usb serial core.  The file
"new_id" will show up under the usb serial driver, not the usb driver
associated with the usb-serial driver (yeah, it can be a bit confusing
at first glance...)

This patch also modifies the USB core to allow the usb-serial core to
reuse much of the dynamic id logic.


Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
Signed-off-by: Johannes Hölzl <[EMAIL PROTECTED]>

---

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 113e484..678ac8c 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@ #include <linux/workqueue.h>
 #include "hcd.h"
 #include "usb.h"
 
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id);
-
-struct usb_dynid {
-       struct list_head node;
-       struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  */
-static ssize_t store_new_id(struct device_driver *driver,
-                           const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                        struct device_driver *driver,
+                        const char *buf, size_t count)
 {
-       struct usb_driver *usb_drv = to_usb_driver(driver);
        struct usb_dynid *dynid;
        u32 idVendor = 0;
        u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct devic
        dynid->id.idProduct = idProduct;
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
-       spin_lock(&usb_drv->dynids.lock);
-       list_add_tail(&usb_drv->dynids.list, &dynid->node);
-       spin_unlock(&usb_drv->dynids.lock);
+       spin_lock(&dynids->lock);
+       list_add_tail(&dynids->list, &dynid->node);
+       spin_unlock(&dynids->lock);
 
        if (get_driver(driver)) {
                retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct devic
                return retval;
        return count;
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_driver *usb_drv = to_usb_driver(driver);
+
+       return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+                    const struct usb_device_id *id)
 {
        struct usb_host_interface *intf;
        struct usb_device *dev;
@@ -422,6 +423,8 @@ static int usb_match_one_id(struct usb_i
 
        return 1;
 }
+EXPORT_SYMBOL(usb_match_one_id);
+
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f22..11e6935 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@ exit:
        return retval;
 }
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+       ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+       if (retval >= 0 && &usb_drv->usb_driver != NULL)
+               retval = usb_store_new_id(&usb_drv->usb_driver->dynids, 
+                                         &usb_drv->usb_driver->drvwrap.driver,
+                                         buf, count);
+       return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+       __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+       __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+       struct usb_dynid *dynid, *n;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+               list_del(&dynid->node);
+               kfree(dynid);
+       }
+       spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+       __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 struct bus_type usb_serial_bus_type = {
        .name =         "usb-serial",
        .match =        usb_serial_device_match,
        .probe =        usb_serial_device_probe,
        .remove =       usb_serial_device_remove,
+       .drv_attrs =    drv_attrs,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_s
        int retval;
 
        driver->driver.bus = &usb_serial_bus_type;
+       spin_lock_init(&driver->dynids.lock);
+       INIT_LIST_HEAD(&driver->dynids.list);
+
        retval = driver_register(&driver->driver);
 
        return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_s
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
+       free_dynids(driver);
        driver_unregister(&driver->driver);
 }
 
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 8006e51..f5e96e0 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -43,7 +43,7 @@ #define DRIVER_DESC "USB Serial Driver c
 static void port_free(struct usb_serial_port *port);
 
 /* Driver structure we register with the USB core */
-static struct usb_driver usb_serial_driver = {
+struct usb_driver usb_serial_driver = {
        .name =         "usbserial",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
@@ -595,6 +595,39 @@ static struct usb_serial * create_serial
        return serial;
 }
 
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+                                                   struct usb_serial_driver 
*drv)
+{
+       struct usb_dynid *dynid;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry(dynid, &drv->dynids.list, node) {
+               if (usb_match_one_id(intf, &dynid->id)) {
+                       spin_unlock(&drv->dynids.lock);
+                       return &dynid->id;
+               }
+       }
+       spin_unlock(&drv->dynids.lock);
+       return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+                                               struct usb_interface *intf)
+{
+       const struct usb_device_id *id;
+
+       id = usb_match_id(intf, drv->id_table);
+       if (id) {
+               dbg("static descriptor matches");
+               goto exit;
+       }
+       id = match_dynamic_id(intf, drv);
+       if (id)
+               dbg("dynamic descriptor matches");
+exit:
+       return id;
+}
+
 static struct usb_serial_driver *search_serial_device(struct usb_interface 
*iface)
 {
        struct list_head *p;
@@ -604,11 +637,9 @@ static struct usb_serial_driver *search_
        /* Check if the usb id matches a known device */
        list_for_each(p, &usb_serial_driver_list) {
                t = list_entry(p, struct usb_serial_driver, driver_list);
-               id = usb_match_id(iface, t->id_table);
-               if (id != NULL) {
-                       dbg("descriptor matches");
+               id = get_iface_id(t, iface);
+               if (id)
                        return t;
-               }
        }
 
        return NULL;
@@ -660,7 +691,7 @@ int usb_serial_probe(struct usb_interfac
                        return -EIO;
                }
 
-               id = usb_match_id(interface, type->id_table);
+               id = get_iface_id(type, interface);
                retval = type->probe(serial, id);
                module_put(type->driver.owner);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 5482bfb..83c6c39 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -446,6 +446,8 @@ extern void usb_driver_release_interface
                        struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
                                         const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+                           const struct usb_device_id *id);
 
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
                int minor);
@@ -574,11 +576,21 @@ #define USB_INTERFACE_INFO(cl,sc,pr) \
 
 /* ----------------------------------------------------------------------- */
 
+/* Stuff for dynamic usb ids */
 struct usb_dynids {
        spinlock_t lock;
        struct list_head list;
 };
 
+struct usb_dynid {
+       struct list_head node;
+       struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                               struct device_driver *driver,
+                               const char *buf, size_t count);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 91b3ea2..1c87cb7 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -202,6 +202,8 @@ struct usb_serial_driver {
 
        struct list_head        driver_list;
        struct device_driver    driver;
+       struct usb_driver       *usb_driver;
+       struct usb_dynids       dynids;
 
        int (*probe) (struct usb_serial *serial, const struct usb_device_id 
*id);
        int (*attach) (struct usb_serial *serial);
@@ -272,6 +274,7 @@ extern int usb_serial_bus_register (stru
 extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
 
 extern struct usb_serial_driver usb_serial_generic_device;
+extern struct usb_driver usb_serial_driver;
 extern struct bus_type usb_serial_bus_type;
 extern struct tty_driver *usb_serial_tty_driver;
 




-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to