USB serial: add dynamic id support to usb-serial core

Thanks to Johannes Hölzl <johannes.hoelzl@gmx.de> for fixing a few
things and getting it all working properly.

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 <gregkh@suse.de>
Signed-off-by: Johannes Hölzl <johannes.hoelzl@gmx.de>


diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 716f680..90beb5c 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -596,6 +596,39 @@
 	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;
@@ -605,11 +638,9 @@
 	/* 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;
@@ -661,7 +692,7 @@
 			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);