diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/bus.c | 45 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 41 |
2 files changed, 81 insertions, 5 deletions
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6542f220468f..c08a38402b93 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c | |||
@@ -103,11 +103,52 @@ exit: | |||
103 | return retval; | 103 | return retval; |
104 | } | 104 | } |
105 | 105 | ||
106 | #ifdef CONFIG_HOTPLUG | ||
107 | static ssize_t store_new_id(struct device_driver *driver, | ||
108 | const char *buf, size_t count) | ||
109 | { | ||
110 | struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); | ||
111 | ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); | ||
112 | |||
113 | if (retval >= 0 && usb_drv->usb_driver != NULL) | ||
114 | retval = usb_store_new_id(&usb_drv->usb_driver->dynids, | ||
115 | &usb_drv->usb_driver->drvwrap.driver, | ||
116 | buf, count); | ||
117 | return retval; | ||
118 | } | ||
119 | |||
120 | static struct driver_attribute drv_attrs[] = { | ||
121 | __ATTR(new_id, S_IWUSR, NULL, store_new_id), | ||
122 | __ATTR_NULL, | ||
123 | }; | ||
124 | |||
125 | static void free_dynids(struct usb_serial_driver *drv) | ||
126 | { | ||
127 | struct usb_dynid *dynid, *n; | ||
128 | |||
129 | spin_lock(&drv->dynids.lock); | ||
130 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { | ||
131 | list_del(&dynid->node); | ||
132 | kfree(dynid); | ||
133 | } | ||
134 | spin_unlock(&drv->dynids.lock); | ||
135 | } | ||
136 | |||
137 | #else | ||
138 | static struct driver_attribute drv_attrs[] = { | ||
139 | __ATTR_NULL, | ||
140 | }; | ||
141 | static inline void free_dynids(struct usb_driver *drv) | ||
142 | { | ||
143 | } | ||
144 | #endif | ||
145 | |||
106 | struct bus_type usb_serial_bus_type = { | 146 | struct bus_type usb_serial_bus_type = { |
107 | .name = "usb-serial", | 147 | .name = "usb-serial", |
108 | .match = usb_serial_device_match, | 148 | .match = usb_serial_device_match, |
109 | .probe = usb_serial_device_probe, | 149 | .probe = usb_serial_device_probe, |
110 | .remove = usb_serial_device_remove, | 150 | .remove = usb_serial_device_remove, |
151 | .drv_attrs = drv_attrs, | ||
111 | }; | 152 | }; |
112 | 153 | ||
113 | int usb_serial_bus_register(struct usb_serial_driver *driver) | 154 | int usb_serial_bus_register(struct usb_serial_driver *driver) |
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) | |||
115 | int retval; | 156 | int retval; |
116 | 157 | ||
117 | driver->driver.bus = &usb_serial_bus_type; | 158 | driver->driver.bus = &usb_serial_bus_type; |
159 | spin_lock_init(&driver->dynids.lock); | ||
160 | INIT_LIST_HEAD(&driver->dynids.list); | ||
161 | |||
118 | retval = driver_register(&driver->driver); | 162 | retval = driver_register(&driver->driver); |
119 | 163 | ||
120 | return retval; | 164 | return retval; |
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) | |||
122 | 166 | ||
123 | void usb_serial_bus_deregister(struct usb_serial_driver *driver) | 167 | void usb_serial_bus_deregister(struct usb_serial_driver *driver) |
124 | { | 168 | { |
169 | free_dynids(driver); | ||
125 | driver_unregister(&driver->driver); | 170 | driver_unregister(&driver->driver); |
126 | } | 171 | } |
127 | 172 | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc89..90beb5c50e59 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -596,6 +596,39 @@ static struct usb_serial * create_serial (struct usb_device *dev, | |||
596 | return serial; | 596 | return serial; |
597 | } | 597 | } |
598 | 598 | ||
599 | static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, | ||
600 | struct usb_serial_driver *drv) | ||
601 | { | ||
602 | struct usb_dynid *dynid; | ||
603 | |||
604 | spin_lock(&drv->dynids.lock); | ||
605 | list_for_each_entry(dynid, &drv->dynids.list, node) { | ||
606 | if (usb_match_one_id(intf, &dynid->id)) { | ||
607 | spin_unlock(&drv->dynids.lock); | ||
608 | return &dynid->id; | ||
609 | } | ||
610 | } | ||
611 | spin_unlock(&drv->dynids.lock); | ||
612 | return NULL; | ||
613 | } | ||
614 | |||
615 | static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, | ||
616 | struct usb_interface *intf) | ||
617 | { | ||
618 | const struct usb_device_id *id; | ||
619 | |||
620 | id = usb_match_id(intf, drv->id_table); | ||
621 | if (id) { | ||
622 | dbg("static descriptor matches"); | ||
623 | goto exit; | ||
624 | } | ||
625 | id = match_dynamic_id(intf, drv); | ||
626 | if (id) | ||
627 | dbg("dynamic descriptor matches"); | ||
628 | exit: | ||
629 | return id; | ||
630 | } | ||
631 | |||
599 | static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) | 632 | static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) |
600 | { | 633 | { |
601 | struct list_head *p; | 634 | struct list_head *p; |
@@ -605,11 +638,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac | |||
605 | /* Check if the usb id matches a known device */ | 638 | /* Check if the usb id matches a known device */ |
606 | list_for_each(p, &usb_serial_driver_list) { | 639 | list_for_each(p, &usb_serial_driver_list) { |
607 | t = list_entry(p, struct usb_serial_driver, driver_list); | 640 | t = list_entry(p, struct usb_serial_driver, driver_list); |
608 | id = usb_match_id(iface, t->id_table); | 641 | id = get_iface_id(t, iface); |
609 | if (id != NULL) { | 642 | if (id) |
610 | dbg("descriptor matches"); | ||
611 | return t; | 643 | return t; |
612 | } | ||
613 | } | 644 | } |
614 | 645 | ||
615 | return NULL; | 646 | return NULL; |
@@ -661,7 +692,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
661 | return -EIO; | 692 | return -EIO; |
662 | } | 693 | } |
663 | 694 | ||
664 | id = usb_match_id(interface, type->id_table); | 695 | id = get_iface_id(type, interface); |
665 | retval = type->probe(serial, id); | 696 | retval = type->probe(serial, id); |
666 | module_put(type->driver.owner); | 697 | module_put(type->driver.owner); |
667 | 698 | ||