diff options
author | Alan Cox <alan@linux.intel.com> | 2009-10-06 11:06:11 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 18:18:04 -0500 |
commit | 64bc397914265a9ead8d73b63bb31ab3bdd25f67 (patch) | |
tree | dc96d1737d3d70bbdebaea7e0f0aedd1377e1000 /drivers/usb/serial/usb-serial.c | |
parent | 894cb91770f7794f1a17db4df2d83999b197da24 (diff) |
tty_port: add "tty_port_open" helper
For the moment this just moves the USB logic over and fixes the 'what if
we open and hangup at the same time' race noticed by Oliver Neukum.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 49 |
1 files changed, 20 insertions, 29 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bd3fa7ff15b1..b0649d92251f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -247,41 +247,31 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) | |||
247 | return retval; | 247 | return retval; |
248 | } | 248 | } |
249 | 249 | ||
250 | static int serial_open(struct tty_struct *tty, struct file *filp) | 250 | static int serial_activate(struct tty_port *tport, struct tty_struct *tty) |
251 | { | 251 | { |
252 | struct usb_serial_port *port = tty->driver_data; | 252 | struct usb_serial_port *port = |
253 | container_of(tport, struct usb_serial_port, port); | ||
253 | struct usb_serial *serial = port->serial; | 254 | struct usb_serial *serial = port->serial; |
254 | int retval; | 255 | int retval; |
255 | 256 | ||
256 | dbg("%s - port %d", __func__, port->number); | 257 | if (mutex_lock_interruptible(&port->mutex)) |
257 | 258 | return -ERESTARTSYS; | |
258 | spin_lock_irq(&port->port.lock); | 259 | mutex_lock(&serial->disc_mutex); |
259 | if (!tty_hung_up_p(filp)) | 260 | if (serial->disconnected) |
260 | ++port->port.count; | 261 | retval = -ENODEV; |
261 | spin_unlock_irq(&port->port.lock); | 262 | else |
262 | tty_port_tty_set(&port->port, tty); | 263 | retval = port->serial->type->open(tty, port); |
264 | mutex_unlock(&serial->disc_mutex); | ||
265 | mutex_unlock(&port->mutex); | ||
266 | return retval; | ||
267 | } | ||
263 | 268 | ||
264 | /* Do the device-specific open only if the hardware isn't | 269 | static int serial_open(struct tty_struct *tty, struct file *filp) |
265 | * already initialized. | 270 | { |
266 | */ | 271 | struct usb_serial_port *port = tty->driver_data; |
267 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { | ||
268 | if (mutex_lock_interruptible(&port->mutex)) | ||
269 | return -ERESTARTSYS; | ||
270 | mutex_lock(&serial->disc_mutex); | ||
271 | if (serial->disconnected) | ||
272 | retval = -ENODEV; | ||
273 | else | ||
274 | retval = port->serial->type->open(tty, port); | ||
275 | mutex_unlock(&serial->disc_mutex); | ||
276 | mutex_unlock(&port->mutex); | ||
277 | if (retval) | ||
278 | return retval; | ||
279 | set_bit(ASYNCB_INITIALIZED, &port->port.flags); | ||
280 | } | ||
281 | 272 | ||
282 | /* Now do the correct tty layer semantics */ | 273 | dbg("%s - port %d", __func__, port->number); |
283 | retval = tty_port_block_til_ready(&port->port, tty, filp); | 274 | return tty_port_open(&port->port, tty, filp); |
284 | return retval; | ||
285 | } | 275 | } |
286 | 276 | ||
287 | /** | 277 | /** |
@@ -725,6 +715,7 @@ static void serial_dtr_rts(struct tty_port *port, int on) | |||
725 | static const struct tty_port_operations serial_port_ops = { | 715 | static const struct tty_port_operations serial_port_ops = { |
726 | .carrier_raised = serial_carrier_raised, | 716 | .carrier_raised = serial_carrier_raised, |
727 | .dtr_rts = serial_dtr_rts, | 717 | .dtr_rts = serial_dtr_rts, |
718 | .activate = serial_activate, | ||
728 | }; | 719 | }; |
729 | 720 | ||
730 | int usb_serial_probe(struct usb_interface *interface, | 721 | int usb_serial_probe(struct usb_interface *interface, |