diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2009-06-02 11:54:11 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-16 00:44:47 -0400 |
commit | c706ebdfc8955b850e477255a8c0f93f9f14712d (patch) | |
tree | 1f880601cdd2663ee4206783092d5fa9d90c8922 /drivers/usb/serial | |
parent | c6994e6f067cf0fc4c6cca3d164018b1150916f8 (diff) |
USB: usb-serial: call port_probe and port_remove at the right times
This patch (as1253) prevents the usb-serial core from calling a
driver's port_probe and port_remove methods more than once per port.
It also removes some unnecessary try_module_get() calls and adds a
missing port_remove method call in a failure path.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/bus.c | 27 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 24 |
2 files changed, 33 insertions, 18 deletions
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 83bbb5bca2ef..ba555c528cc6 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c | |||
@@ -59,23 +59,22 @@ static int usb_serial_device_probe(struct device *dev) | |||
59 | retval = -ENODEV; | 59 | retval = -ENODEV; |
60 | goto exit; | 60 | goto exit; |
61 | } | 61 | } |
62 | if (port->dev_state != PORT_REGISTERING) | ||
63 | goto exit; | ||
62 | 64 | ||
63 | driver = port->serial->type; | 65 | driver = port->serial->type; |
64 | if (driver->port_probe) { | 66 | if (driver->port_probe) { |
65 | if (!try_module_get(driver->driver.owner)) { | ||
66 | dev_err(dev, "module get failed, exiting\n"); | ||
67 | retval = -EIO; | ||
68 | goto exit; | ||
69 | } | ||
70 | retval = driver->port_probe(port); | 67 | retval = driver->port_probe(port); |
71 | module_put(driver->driver.owner); | ||
72 | if (retval) | 68 | if (retval) |
73 | goto exit; | 69 | goto exit; |
74 | } | 70 | } |
75 | 71 | ||
76 | retval = device_create_file(dev, &dev_attr_port_number); | 72 | retval = device_create_file(dev, &dev_attr_port_number); |
77 | if (retval) | 73 | if (retval) { |
74 | if (driver->port_remove) | ||
75 | retval = driver->port_remove(port); | ||
78 | goto exit; | 76 | goto exit; |
77 | } | ||
79 | 78 | ||
80 | minor = port->number; | 79 | minor = port->number; |
81 | tty_register_device(usb_serial_tty_driver, minor, dev); | 80 | tty_register_device(usb_serial_tty_driver, minor, dev); |
@@ -98,19 +97,15 @@ static int usb_serial_device_remove(struct device *dev) | |||
98 | if (!port) | 97 | if (!port) |
99 | return -ENODEV; | 98 | return -ENODEV; |
100 | 99 | ||
100 | if (port->dev_state != PORT_UNREGISTERING) | ||
101 | return retval; | ||
102 | |||
101 | device_remove_file(&port->dev, &dev_attr_port_number); | 103 | device_remove_file(&port->dev, &dev_attr_port_number); |
102 | 104 | ||
103 | driver = port->serial->type; | 105 | driver = port->serial->type; |
104 | if (driver->port_remove) { | 106 | if (driver->port_remove) |
105 | if (!try_module_get(driver->driver.owner)) { | ||
106 | dev_err(dev, "module get failed, exiting\n"); | ||
107 | retval = -EIO; | ||
108 | goto exit; | ||
109 | } | ||
110 | retval = driver->port_remove(port); | 107 | retval = driver->port_remove(port); |
111 | module_put(driver->driver.owner); | 108 | |
112 | } | ||
113 | exit: | ||
114 | minor = port->number; | 109 | minor = port->number; |
115 | tty_unregister_device(usb_serial_tty_driver, minor); | 110 | tty_unregister_device(usb_serial_tty_driver, minor); |
116 | dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", | 111 | dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", |
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1967a7edc10c..da890f030fac 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -1046,10 +1046,15 @@ int usb_serial_probe(struct usb_interface *interface, | |||
1046 | 1046 | ||
1047 | dev_set_name(&port->dev, "ttyUSB%d", port->number); | 1047 | dev_set_name(&port->dev, "ttyUSB%d", port->number); |
1048 | dbg ("%s - registering %s", __func__, dev_name(&port->dev)); | 1048 | dbg ("%s - registering %s", __func__, dev_name(&port->dev)); |
1049 | port->dev_state = PORT_REGISTERING; | ||
1049 | retval = device_register(&port->dev); | 1050 | retval = device_register(&port->dev); |
1050 | if (retval) | 1051 | if (retval) { |
1051 | dev_err(&port->dev, "Error registering port device, " | 1052 | dev_err(&port->dev, "Error registering port device, " |
1052 | "continuing\n"); | 1053 | "continuing\n"); |
1054 | port->dev_state = PORT_UNREGISTERED; | ||
1055 | } else { | ||
1056 | port->dev_state = PORT_REGISTERED; | ||
1057 | } | ||
1053 | } | 1058 | } |
1054 | 1059 | ||
1055 | usb_serial_console_init(debug, minor); | 1060 | usb_serial_console_init(debug, minor); |
@@ -1130,7 +1135,22 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1130 | } | 1135 | } |
1131 | kill_traffic(port); | 1136 | kill_traffic(port); |
1132 | cancel_work_sync(&port->work); | 1137 | cancel_work_sync(&port->work); |
1133 | device_del(&port->dev); | 1138 | if (port->dev_state == PORT_REGISTERED) { |
1139 | |||
1140 | /* Make sure the port is bound so that the | ||
1141 | * driver's port_remove method is called. | ||
1142 | */ | ||
1143 | if (!port->dev.driver) { | ||
1144 | int rc; | ||
1145 | |||
1146 | port->dev.driver = | ||
1147 | &serial->type->driver; | ||
1148 | rc = device_bind_driver(&port->dev); | ||
1149 | } | ||
1150 | port->dev_state = PORT_UNREGISTERING; | ||
1151 | device_del(&port->dev); | ||
1152 | port->dev_state = PORT_UNREGISTERED; | ||
1153 | } | ||
1134 | } | 1154 | } |
1135 | } | 1155 | } |
1136 | serial->type->shutdown(serial); | 1156 | serial->type->shutdown(serial); |