diff options
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a84216464ca0..99188c92068b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/smp_lock.h> | ||
24 | #include <linux/tty.h> | 25 | #include <linux/tty.h> |
25 | #include <linux/tty_driver.h> | 26 | #include <linux/tty_driver.h> |
26 | #include <linux/tty_flip.h> | 27 | #include <linux/tty_flip.h> |
@@ -31,6 +32,7 @@ | |||
31 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
32 | #include <linux/list.h> | 33 | #include <linux/list.h> |
33 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/serial.h> | ||
34 | #include <linux/usb.h> | 36 | #include <linux/usb.h> |
35 | #include <linux/usb/serial.h> | 37 | #include <linux/usb/serial.h> |
36 | #include "pl2303.h" | 38 | #include "pl2303.h" |
@@ -183,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
183 | struct usb_serial_port *port; | 185 | struct usb_serial_port *port; |
184 | unsigned int portNumber; | 186 | unsigned int portNumber; |
185 | int retval = 0; | 187 | int retval = 0; |
188 | int first = 0; | ||
186 | 189 | ||
187 | dbg("%s", __func__); | 190 | dbg("%s", __func__); |
188 | 191 | ||
@@ -220,8 +223,9 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
220 | tty->driver_data = port; | 223 | tty->driver_data = port; |
221 | tty_port_tty_set(&port->port, tty); | 224 | tty_port_tty_set(&port->port, tty); |
222 | 225 | ||
223 | if (port->port.count == 1) { | 226 | /* If the console is attached, the device is already open */ |
224 | 227 | if (port->port.count == 1 && !port->console) { | |
228 | first = 1; | ||
225 | /* lock this module before we call it | 229 | /* lock this module before we call it |
226 | * this may fail, which means we must bail out, | 230 | * this may fail, which means we must bail out, |
227 | * safe because we are called with BKL held */ | 231 | * safe because we are called with BKL held */ |
@@ -244,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
244 | if (retval) | 248 | if (retval) |
245 | goto bailout_interface_put; | 249 | goto bailout_interface_put; |
246 | mutex_unlock(&serial->disc_mutex); | 250 | mutex_unlock(&serial->disc_mutex); |
251 | set_bit(ASYNCB_INITIALIZED, &port->port.flags); | ||
247 | } | 252 | } |
248 | mutex_unlock(&port->mutex); | 253 | mutex_unlock(&port->mutex); |
249 | /* Now do the correct tty layer semantics */ | 254 | /* Now do the correct tty layer semantics */ |
250 | retval = tty_port_block_til_ready(&port->port, tty, filp); | 255 | retval = tty_port_block_til_ready(&port->port, tty, filp); |
251 | if (retval == 0) | 256 | if (retval == 0) { |
257 | if (!first) | ||
258 | usb_serial_put(serial); | ||
252 | return 0; | 259 | return 0; |
253 | 260 | } | |
261 | mutex_lock(&port->mutex); | ||
262 | if (first == 0) | ||
263 | goto bailout_mutex_unlock; | ||
264 | /* Undo the initial port actions */ | ||
265 | mutex_lock(&serial->disc_mutex); | ||
254 | bailout_interface_put: | 266 | bailout_interface_put: |
255 | usb_autopm_put_interface(serial->interface); | 267 | usb_autopm_put_interface(serial->interface); |
256 | bailout_module_put: | 268 | bailout_module_put: |
@@ -338,6 +350,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp) | |||
338 | 350 | ||
339 | dbg("%s - port %d", __func__, port->number); | 351 | dbg("%s - port %d", __func__, port->number); |
340 | 352 | ||
353 | /* FIXME: | ||
354 | This leaves a very narrow race. Really we should do the | ||
355 | serial_do_free() on tty->shutdown(), but tty->shutdown can | ||
356 | be called from IRQ context and serial_do_free can sleep. | ||
357 | |||
358 | The right fix is probably to make the tty free (which is rare) | ||
359 | and thus tty->shutdown() occur via a work queue and simplify all | ||
360 | the drivers that use it. | ||
361 | */ | ||
362 | if (tty_hung_up_p(filp)) { | ||
363 | /* serial_hangup already called serial_down at this point. | ||
364 | Another user may have already reopened the port but | ||
365 | serial_do_free is refcounted */ | ||
366 | serial_do_free(port); | ||
367 | return; | ||
368 | } | ||
341 | 369 | ||
342 | if (tty_port_close_start(&port->port, tty, filp) == 0) | 370 | if (tty_port_close_start(&port->port, tty, filp) == 0) |
343 | return; | 371 | return; |
@@ -353,7 +381,8 @@ static void serial_hangup(struct tty_struct *tty) | |||
353 | struct usb_serial_port *port = tty->driver_data; | 381 | struct usb_serial_port *port = tty->driver_data; |
354 | serial_do_down(port); | 382 | serial_do_down(port); |
355 | tty_port_hangup(&port->port); | 383 | tty_port_hangup(&port->port); |
356 | serial_do_free(port); | 384 | /* We must not free port yet - the USB serial layer depends on it's |
385 | continued existence */ | ||
357 | } | 386 | } |
358 | 387 | ||
359 | static int serial_write(struct tty_struct *tty, const unsigned char *buf, | 388 | static int serial_write(struct tty_struct *tty, const unsigned char *buf, |
@@ -392,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty) | |||
392 | struct usb_serial_port *port = tty->driver_data; | 421 | struct usb_serial_port *port = tty->driver_data; |
393 | dbg("%s = port %d", __func__, port->number); | 422 | dbg("%s = port %d", __func__, port->number); |
394 | 423 | ||
395 | WARN_ON(!port->port.count); | ||
396 | /* if the device was unplugged then any remaining characters | 424 | /* if the device was unplugged then any remaining characters |
397 | fell out of the connector ;) */ | 425 | fell out of the connector ;) */ |
398 | if (port->serial->disconnected) | 426 | if (port->serial->disconnected) |