diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-08-29 03:30:41 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-08-29 03:31:47 -0400 |
| commit | eebc57f73d42095b778e899f6aa90ad050c72655 (patch) | |
| tree | 2ba80c75e9284093e6d7606dbb1b6a4bb752a2a5 /drivers/usb/serial/usb-serial.c | |
| parent | d3a247bfb2c26f5b67367d58af7ad8c2efbbc6c1 (diff) | |
| parent | 2a4ab640d3c28c2952967e5f63ea495555bf2a5f (diff) | |
Merge branch 'for-ingo' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-sfi-2.6 into x86/apic
Merge reason: the SFI (Simple Firmware Interface) feature in the ACPI
tree needs this cleanup, pull it into the APIC branch as
well so that there's no interactions.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
| -rw-r--r-- | drivers/usb/serial/usb-serial.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bd7581b3a48a..99188c92068b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
| 33 | #include <linux/list.h> | 33 | #include <linux/list.h> |
| 34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
| 35 | #include <linux/serial.h> | ||
| 35 | #include <linux/usb.h> | 36 | #include <linux/usb.h> |
| 36 | #include <linux/usb/serial.h> | 37 | #include <linux/usb/serial.h> |
| 37 | #include "pl2303.h" | 38 | #include "pl2303.h" |
| @@ -184,6 +185,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
| 184 | struct usb_serial_port *port; | 185 | struct usb_serial_port *port; |
| 185 | unsigned int portNumber; | 186 | unsigned int portNumber; |
| 186 | int retval = 0; | 187 | int retval = 0; |
| 188 | int first = 0; | ||
| 187 | 189 | ||
| 188 | dbg("%s", __func__); | 190 | dbg("%s", __func__); |
| 189 | 191 | ||
| @@ -223,7 +225,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
| 223 | 225 | ||
| 224 | /* If the console is attached, the device is already open */ | 226 | /* If the console is attached, the device is already open */ |
| 225 | if (port->port.count == 1 && !port->console) { | 227 | if (port->port.count == 1 && !port->console) { |
| 226 | 228 | first = 1; | |
| 227 | /* lock this module before we call it | 229 | /* lock this module before we call it |
| 228 | * this may fail, which means we must bail out, | 230 | * this may fail, which means we must bail out, |
| 229 | * safe because we are called with BKL held */ | 231 | * safe because we are called with BKL held */ |
| @@ -246,13 +248,21 @@ static int serial_open (struct tty_struct *tty, struct file *filp) | |||
| 246 | if (retval) | 248 | if (retval) |
| 247 | goto bailout_interface_put; | 249 | goto bailout_interface_put; |
| 248 | mutex_unlock(&serial->disc_mutex); | 250 | mutex_unlock(&serial->disc_mutex); |
| 251 | set_bit(ASYNCB_INITIALIZED, &port->port.flags); | ||
| 249 | } | 252 | } |
| 250 | mutex_unlock(&port->mutex); | 253 | mutex_unlock(&port->mutex); |
| 251 | /* Now do the correct tty layer semantics */ | 254 | /* Now do the correct tty layer semantics */ |
| 252 | retval = tty_port_block_til_ready(&port->port, tty, filp); | 255 | retval = tty_port_block_til_ready(&port->port, tty, filp); |
| 253 | if (retval == 0) | 256 | if (retval == 0) { |
| 257 | if (!first) | ||
| 258 | usb_serial_put(serial); | ||
| 254 | return 0; | 259 | return 0; |
| 255 | 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); | ||
| 256 | bailout_interface_put: | 266 | bailout_interface_put: |
| 257 | usb_autopm_put_interface(serial->interface); | 267 | usb_autopm_put_interface(serial->interface); |
| 258 | bailout_module_put: | 268 | bailout_module_put: |
| @@ -340,6 +350,22 @@ static void serial_close(struct tty_struct *tty, struct file *filp) | |||
| 340 | 350 | ||
| 341 | dbg("%s - port %d", __func__, port->number); | 351 | dbg("%s - port %d", __func__, port->number); |
| 342 | 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 | } | ||
| 343 | 369 | ||
| 344 | if (tty_port_close_start(&port->port, tty, filp) == 0) | 370 | if (tty_port_close_start(&port->port, tty, filp) == 0) |
| 345 | return; | 371 | return; |
| @@ -355,7 +381,8 @@ static void serial_hangup(struct tty_struct *tty) | |||
| 355 | struct usb_serial_port *port = tty->driver_data; | 381 | struct usb_serial_port *port = tty->driver_data; |
| 356 | serial_do_down(port); | 382 | serial_do_down(port); |
| 357 | tty_port_hangup(&port->port); | 383 | tty_port_hangup(&port->port); |
| 358 | serial_do_free(port); | 384 | /* We must not free port yet - the USB serial layer depends on it's |
| 385 | continued existence */ | ||
| 359 | } | 386 | } |
| 360 | 387 | ||
| 361 | 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, |
| @@ -394,7 +421,6 @@ static int serial_chars_in_buffer(struct tty_struct *tty) | |||
| 394 | struct usb_serial_port *port = tty->driver_data; | 421 | struct usb_serial_port *port = tty->driver_data; |
| 395 | dbg("%s = port %d", __func__, port->number); | 422 | dbg("%s = port %d", __func__, port->number); |
| 396 | 423 | ||
| 397 | WARN_ON(!port->port.count); | ||
| 398 | /* if the device was unplugged then any remaining characters | 424 | /* if the device was unplugged then any remaining characters |
| 399 | fell out of the connector ;) */ | 425 | fell out of the connector ;) */ |
| 400 | if (port->serial->disconnected) | 426 | if (port->serial->disconnected) |
