Ugh, I've been messing with this patch off-and-on for the past week or
so and still haven't gotten it to work properly, so, in the fine
tradition of releasing stuff way-too-early I'm asking for some help
here...
I want to implement the dynamic id stuff for the usb-serial drivers, but
seem to be doing something foolish here and the patch below just does
not work properly. It even oopses at times if you poke at the dynamic
id files a bunch before unloading the modules. If anyone has any spare
time during the holiday break and wants to point out my stupidity,
please do, I could use the help.
This patch should apply cleanly on the last -mm release, or my latest
2.6 patchset at kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
The change to pl2303.c is so I could test it with a device I have.
thanks,
greg k-h
Subject: USB serial: add dynamic id support to usb-serial core
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]>
drivers/usb/core/driver.c | 37 ++++++++++++++++--------------
drivers/usb/serial/bus.c | 49 ++++++++++++++++++++++++++++++++++++++++
drivers/usb/serial/pl2303.c | 4 +--
drivers/usb/serial/usb-serial.c | 43 ++++++++++++++++++++++++++++++-----
drivers/usb/serial/usb-serial.h | 2 +
include/linux/usb.h | 13 ++++++++++
6 files changed, 123 insertions(+), 25 deletions(-)
---
--- gregkh-2.6.orig/drivers/usb/core/driver.c
+++ gregkh-2.6/drivers/usb/core/driver.c
@@ -27,15 +27,6 @@
#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;
-};
-
-
static int generic_probe(struct device *dev)
{
return 0;
@@ -73,10 +64,10 @@ int usb_generic_driver_data;
* 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;
@@ -85,6 +76,7 @@ static ssize_t store_new_id(struct devic
fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
if (fields < 2)
return -EINVAL;
+ printk("GREG: idVendor=%x idProduct=%x\n", idVendor, idProduct);
dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
if (!dynid)
@@ -95,9 +87,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)) {
driver_attach(driver);
@@ -106,6 +98,15 @@ static ssize_t store_new_id(struct devic
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)
@@ -240,8 +241,8 @@ static int usb_unbind_interface(struct d
}
/* 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;
@@ -297,6 +298,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
--- gregkh-2.6.orig/include/linux/usb.h
+++ gregkh-2.6/include/linux/usb.h
@@ -417,6 +417,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);
@@ -531,11 +533,21 @@ static inline int usb_make_path (struct
/* ----------------------------------------------------------------------- */
+/* 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 usb_driver - identifies USB driver to usbcore
* @name: The driver name should be unique among USB drivers,
@@ -1190,6 +1202,7 @@ usb_maxpacket(struct usb_device *udev, i
extern void usb_register_notify(struct notifier_block *nb);
extern void usb_unregister_notify(struct notifier_block *nb);
+
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
__FILE__ , ## arg)
--- gregkh-2.6.orig/drivers/usb/serial/usb-serial.h
+++ gregkh-2.6/drivers/usb/serial/usb-serial.h
@@ -203,6 +203,7 @@ struct usb_serial_driver {
struct list_head driver_list;
struct device_driver driver;
+ struct usb_dynids dynids;
int (*probe) (struct usb_serial *serial, const struct usb_device_id
*id);
int (*attach) (struct usb_serial *serial);
@@ -270,6 +271,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;
--- gregkh-2.6.orig/drivers/usb/serial/bus.c
+++ gregkh-2.6/drivers/usb/serial/bus.c
@@ -37,9 +37,55 @@ static int usb_serial_device_match (stru
return 0;
}
+#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) {
+ /* kick the usb-serial main driver */
+ struct device_driver *driver = &usb_serial_driver.driver;
+ if (get_driver(driver)) {
+ driver_attach(driver);
+ put_driver(driver);
+ }
+ }
+ 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;
+
+ printk("GREG: %s\n", __FUNCTION__);
+ 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,
+ .drv_attrs = drv_attrs,
};
static int usb_serial_device_probe (struct device *dev)
@@ -116,6 +162,8 @@ int usb_serial_bus_register(struct usb_s
driver->driver.bus = &usb_serial_bus_type;
driver->driver.probe = usb_serial_device_probe;
driver->driver.remove = usb_serial_device_remove;
+ spin_lock_init(&driver->dynids.lock);
+ INIT_LIST_HEAD(&driver->dynids.list);
retval = driver_register(&driver->driver);
@@ -124,6 +172,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);
}
--- gregkh-2.6.orig/drivers/usb/serial/usb-serial.c
+++ gregkh-2.6/drivers/usb/serial/usb-serial.c
@@ -42,7 +42,7 @@
#define DRIVER_DESC "USB Serial Driver core"
/* 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,
@@ -578,6 +578,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;
@@ -587,11 +620,9 @@ static struct usb_serial_driver *search_
/* List trough know devices and see if the usb id matches */
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;
@@ -643,7 +674,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);
--- gregkh-2.6.orig/drivers/usb/serial/pl2303.c
+++ gregkh-2.6/drivers/usb/serial/pl2303.c
@@ -58,8 +58,8 @@ static struct usb_device_id id_table []
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
- { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
- { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
+// { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+// { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems? Stop! Download the new AJAX search engine that makes
searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel