|
@@ -653,6 +653,7 @@ exit:
|
|
return id;
|
|
return id;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Caller must hold table_lock */
|
|
static struct usb_serial_driver *search_serial_device(
|
|
static struct usb_serial_driver *search_serial_device(
|
|
struct usb_interface *iface)
|
|
struct usb_interface *iface)
|
|
{
|
|
{
|
|
@@ -718,17 +719,23 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
int num_ports = 0;
|
|
int num_ports = 0;
|
|
int max_endpoints;
|
|
int max_endpoints;
|
|
|
|
|
|
- lock_kernel(); /* guard against unloading a serial driver module */
|
|
|
|
|
|
+ mutex_lock(&table_lock);
|
|
type = search_serial_device(interface);
|
|
type = search_serial_device(interface);
|
|
if (!type) {
|
|
if (!type) {
|
|
- unlock_kernel();
|
|
|
|
|
|
+ mutex_unlock(&table_lock);
|
|
dbg("none matched");
|
|
dbg("none matched");
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!try_module_get(type->driver.owner)) {
|
|
|
|
+ mutex_unlock(&table_lock);
|
|
|
|
+ dev_err(&interface->dev, "module get failed, exiting\n");
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
+ mutex_unlock(&table_lock);
|
|
|
|
+
|
|
serial = create_serial(dev, interface, type);
|
|
serial = create_serial(dev, interface, type);
|
|
if (!serial) {
|
|
if (!serial) {
|
|
- unlock_kernel();
|
|
|
|
dev_err(&interface->dev, "%s - out of memory\n", __func__);
|
|
dev_err(&interface->dev, "%s - out of memory\n", __func__);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
@@ -737,20 +744,11 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
if (type->probe) {
|
|
if (type->probe) {
|
|
const struct usb_device_id *id;
|
|
const struct usb_device_id *id;
|
|
|
|
|
|
- if (!try_module_get(type->driver.owner)) {
|
|
|
|
- unlock_kernel();
|
|
|
|
- dev_err(&interface->dev,
|
|
|
|
- "module get failed, exiting\n");
|
|
|
|
- kfree(serial);
|
|
|
|
- return -EIO;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
id = get_iface_id(type, interface);
|
|
id = get_iface_id(type, interface);
|
|
retval = type->probe(serial, id);
|
|
retval = type->probe(serial, id);
|
|
module_put(type->driver.owner);
|
|
module_put(type->driver.owner);
|
|
|
|
|
|
if (retval) {
|
|
if (retval) {
|
|
- unlock_kernel();
|
|
|
|
dbg("sub driver rejected device");
|
|
dbg("sub driver rejected device");
|
|
kfree(serial);
|
|
kfree(serial);
|
|
return retval;
|
|
return retval;
|
|
@@ -822,7 +820,6 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
* properly during a later invocation of usb_serial_probe
|
|
* properly during a later invocation of usb_serial_probe
|
|
*/
|
|
*/
|
|
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
|
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
|
- unlock_kernel();
|
|
|
|
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
|
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
|
kfree(serial);
|
|
kfree(serial);
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
@@ -835,7 +832,6 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
if (type == &usb_serial_generic_device) {
|
|
if (type == &usb_serial_generic_device) {
|
|
num_ports = num_bulk_out;
|
|
num_ports = num_bulk_out;
|
|
if (num_ports == 0) {
|
|
if (num_ports == 0) {
|
|
- unlock_kernel();
|
|
|
|
dev_err(&interface->dev,
|
|
dev_err(&interface->dev,
|
|
"Generic device with no bulk out, not allowed.\n");
|
|
"Generic device with no bulk out, not allowed.\n");
|
|
kfree(serial);
|
|
kfree(serial);
|
|
@@ -847,7 +843,6 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
/* if this device type has a calc_num_ports function, call it */
|
|
/* if this device type has a calc_num_ports function, call it */
|
|
if (type->calc_num_ports) {
|
|
if (type->calc_num_ports) {
|
|
if (!try_module_get(type->driver.owner)) {
|
|
if (!try_module_get(type->driver.owner)) {
|
|
- unlock_kernel();
|
|
|
|
dev_err(&interface->dev,
|
|
dev_err(&interface->dev,
|
|
"module get failed, exiting\n");
|
|
"module get failed, exiting\n");
|
|
kfree(serial);
|
|
kfree(serial);
|
|
@@ -878,7 +873,6 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
max_endpoints = max(max_endpoints, num_interrupt_out);
|
|
max_endpoints = max(max_endpoints, num_interrupt_out);
|
|
max_endpoints = max(max_endpoints, (int)serial->num_ports);
|
|
max_endpoints = max(max_endpoints, (int)serial->num_ports);
|
|
serial->num_port_pointers = max_endpoints;
|
|
serial->num_port_pointers = max_endpoints;
|
|
- unlock_kernel();
|
|
|
|
|
|
|
|
dbg("%s - setting up %d port structures for this device",
|
|
dbg("%s - setting up %d port structures for this device",
|
|
__func__, max_endpoints);
|
|
__func__, max_endpoints);
|
|
@@ -1349,6 +1343,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
|
|
driver->description = driver->driver.name;
|
|
driver->description = driver->driver.name;
|
|
|
|
|
|
/* Add this device to our list of devices */
|
|
/* Add this device to our list of devices */
|
|
|
|
+ mutex_lock(&table_lock);
|
|
list_add(&driver->driver_list, &usb_serial_driver_list);
|
|
list_add(&driver->driver_list, &usb_serial_driver_list);
|
|
|
|
|
|
retval = usb_serial_bus_register(driver);
|
|
retval = usb_serial_bus_register(driver);
|
|
@@ -1360,6 +1355,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
|
|
printk(KERN_INFO "USB Serial support registered for %s\n",
|
|
printk(KERN_INFO "USB Serial support registered for %s\n",
|
|
driver->description);
|
|
driver->description);
|
|
|
|
|
|
|
|
+ mutex_unlock(&table_lock);
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(usb_serial_register);
|
|
EXPORT_SYMBOL_GPL(usb_serial_register);
|
|
@@ -1370,8 +1366,10 @@ void usb_serial_deregister(struct usb_serial_driver *device)
|
|
/* must be called with BKL held */
|
|
/* must be called with BKL held */
|
|
printk(KERN_INFO "USB Serial deregistering driver %s\n",
|
|
printk(KERN_INFO "USB Serial deregistering driver %s\n",
|
|
device->description);
|
|
device->description);
|
|
|
|
+ mutex_lock(&table_lock);
|
|
list_del(&device->driver_list);
|
|
list_del(&device->driver_list);
|
|
usb_serial_bus_deregister(device);
|
|
usb_serial_bus_deregister(device);
|
|
|
|
+ mutex_unlock(&table_lock);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(usb_serial_deregister);
|
|
EXPORT_SYMBOL_GPL(usb_serial_deregister);
|
|
|
|
|