diff options
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 497e29a700ca..3ce98e8d7bce 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp) | |||
225 | goto bailout_mutex_unlock; | 225 | goto bailout_mutex_unlock; |
226 | } | 226 | } |
227 | 227 | ||
228 | retval = usb_autopm_get_interface(serial->interface); | ||
229 | if (retval) | ||
230 | goto bailout_module_put; | ||
228 | /* only call the device specific open if this | 231 | /* only call the device specific open if this |
229 | * is the first time the port is opened */ | 232 | * is the first time the port is opened */ |
230 | retval = serial->type->open(port, filp); | 233 | retval = serial->type->open(port, filp); |
231 | if (retval) | 234 | if (retval) |
232 | goto bailout_module_put; | 235 | goto bailout_interface_put; |
233 | } | 236 | } |
234 | 237 | ||
235 | mutex_unlock(&port->mutex); | 238 | mutex_unlock(&port->mutex); |
236 | return 0; | 239 | return 0; |
237 | 240 | ||
241 | bailout_interface_put: | ||
242 | usb_autopm_put_interface(serial->interface); | ||
238 | bailout_module_put: | 243 | bailout_module_put: |
239 | module_put(serial->type->driver.owner); | 244 | module_put(serial->type->driver.owner); |
240 | bailout_mutex_unlock: | 245 | bailout_mutex_unlock: |
@@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp) | |||
264 | } | 269 | } |
265 | 270 | ||
266 | --port->open_count; | 271 | --port->open_count; |
267 | if (port->open_count == 0) { | 272 | if (port->open_count == 0) |
268 | /* only call the device specific close if this | 273 | /* only call the device specific close if this |
269 | * port is being closed by the last owner */ | 274 | * port is being closed by the last owner */ |
270 | port->serial->type->close(port, filp); | 275 | port->serial->type->close(port, filp); |
271 | 276 | ||
277 | if (port->open_count == (port->console? 1 : 0)) { | ||
272 | if (port->tty) { | 278 | if (port->tty) { |
273 | if (port->tty->driver_data) | 279 | if (port->tty->driver_data) |
274 | port->tty->driver_data = NULL; | 280 | port->tty->driver_data = NULL; |
275 | port->tty = NULL; | 281 | port->tty = NULL; |
276 | } | 282 | } |
283 | } | ||
277 | 284 | ||
285 | if (port->open_count == 0) { | ||
286 | usb_autopm_put_interface(port->serial->interface); | ||
278 | module_put(port->serial->type->driver.owner); | 287 | module_put(port->serial->type->driver.owner); |
279 | } | 288 | } |
280 | 289 | ||
@@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, | |||
625 | serial->type = driver; | 634 | serial->type = driver; |
626 | serial->interface = interface; | 635 | serial->interface = interface; |
627 | kref_init(&serial->kref); | 636 | kref_init(&serial->kref); |
637 | mutex_init(&serial->disc_mutex); | ||
628 | 638 | ||
629 | return serial; | 639 | return serial; |
630 | } | 640 | } |
@@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1080 | usb_serial_console_disconnect(serial); | 1090 | usb_serial_console_disconnect(serial); |
1081 | dbg ("%s", __FUNCTION__); | 1091 | dbg ("%s", __FUNCTION__); |
1082 | 1092 | ||
1093 | mutex_lock(&serial->disc_mutex); | ||
1083 | usb_set_intfdata (interface, NULL); | 1094 | usb_set_intfdata (interface, NULL); |
1084 | if (serial) { | 1095 | /* must set a flag, to signal subdrivers */ |
1085 | for (i = 0; i < serial->num_ports; ++i) { | 1096 | serial->disconnected = 1; |
1086 | port = serial->port[i]; | 1097 | for (i = 0; i < serial->num_ports; ++i) { |
1087 | if (port) { | 1098 | port = serial->port[i]; |
1088 | if (port->tty) | 1099 | if (port) { |
1089 | tty_hangup(port->tty); | 1100 | if (port->tty) |
1090 | kill_traffic(port); | 1101 | tty_hangup(port->tty); |
1091 | } | 1102 | kill_traffic(port); |
1092 | } | 1103 | } |
1093 | /* let the last holder of this object | ||
1094 | * cause it to be cleaned up */ | ||
1095 | usb_serial_put(serial); | ||
1096 | } | 1104 | } |
1105 | /* let the last holder of this object | ||
1106 | * cause it to be cleaned up */ | ||
1107 | mutex_unlock(&serial->disc_mutex); | ||
1108 | usb_serial_put(serial); | ||
1097 | dev_info(dev, "device disconnected\n"); | 1109 | dev_info(dev, "device disconnected\n"); |
1098 | } | 1110 | } |
1099 | 1111 | ||
@@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) | |||
1103 | struct usb_serial_port *port; | 1115 | struct usb_serial_port *port; |
1104 | int i, r = 0; | 1116 | int i, r = 0; |
1105 | 1117 | ||
1106 | if (!serial) /* device has been disconnected */ | ||
1107 | return 0; | ||
1108 | |||
1109 | for (i = 0; i < serial->num_ports; ++i) { | 1118 | for (i = 0; i < serial->num_ports; ++i) { |
1110 | port = serial->port[i]; | 1119 | port = serial->port[i]; |
1111 | if (port) | 1120 | if (port) |
@@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device) | |||
1253 | set_to_generic_if_null(device, read_bulk_callback); | 1262 | set_to_generic_if_null(device, read_bulk_callback); |
1254 | set_to_generic_if_null(device, write_bulk_callback); | 1263 | set_to_generic_if_null(device, write_bulk_callback); |
1255 | set_to_generic_if_null(device, shutdown); | 1264 | set_to_generic_if_null(device, shutdown); |
1265 | set_to_generic_if_null(device, resume); | ||
1256 | } | 1266 | } |
1257 | 1267 | ||
1258 | int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ | 1268 | int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ |