diff options
-rw-r--r-- | drivers/char/tty_port.c | 36 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 49 | ||||
-rw-r--r-- | include/linux/tty.h | 10 |
3 files changed, 64 insertions, 31 deletions
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index c63f3d33914a..b22a61a4fbe5 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c | |||
@@ -99,10 +99,11 @@ EXPORT_SYMBOL(tty_port_tty_set); | |||
99 | 99 | ||
100 | static void tty_port_shutdown(struct tty_port *port) | 100 | static void tty_port_shutdown(struct tty_port *port) |
101 | { | 101 | { |
102 | mutex_lock(&port->mutex); | ||
102 | if (port->ops->shutdown && | 103 | if (port->ops->shutdown && |
103 | test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) | 104 | test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) |
104 | port->ops->shutdown(port); | 105 | port->ops->shutdown(port); |
105 | 106 | mutex_unlock(&port->mutex); | |
106 | } | 107 | } |
107 | 108 | ||
108 | /** | 109 | /** |
@@ -381,3 +382,36 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, | |||
381 | tty_port_tty_set(port, NULL); | 382 | tty_port_tty_set(port, NULL); |
382 | } | 383 | } |
383 | EXPORT_SYMBOL(tty_port_close); | 384 | EXPORT_SYMBOL(tty_port_close); |
385 | |||
386 | int tty_port_open(struct tty_port *port, struct tty_struct *tty, | ||
387 | struct file *filp) | ||
388 | { | ||
389 | spin_lock_irq(&port->lock); | ||
390 | if (!tty_hung_up_p(filp)) | ||
391 | ++port->count; | ||
392 | spin_unlock_irq(&port->lock); | ||
393 | tty_port_tty_set(port, tty); | ||
394 | |||
395 | /* | ||
396 | * Do the device-specific open only if the hardware isn't | ||
397 | * already initialized. Serialize open and shutdown using the | ||
398 | * port mutex. | ||
399 | */ | ||
400 | |||
401 | mutex_lock(&port->mutex); | ||
402 | |||
403 | if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { | ||
404 | if (port->ops->activate) { | ||
405 | int retval = port->ops->activate(port, tty); | ||
406 | if (retval) { | ||
407 | mutex_unlock(&port->mutex); | ||
408 | return retval; | ||
409 | } | ||
410 | } | ||
411 | set_bit(ASYNCB_INITIALIZED, &port->flags); | ||
412 | } | ||
413 | mutex_unlock(&port->mutex); | ||
414 | return tty_port_block_til_ready(port, tty, filp); | ||
415 | } | ||
416 | |||
417 | EXPORT_SYMBOL(tty_port_open); | ||
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, |
diff --git a/include/linux/tty.h b/include/linux/tty.h index f0f43d08d8b8..6352ac257fcb 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -190,9 +190,15 @@ struct tty_port_operations { | |||
190 | /* Control the DTR line */ | 190 | /* Control the DTR line */ |
191 | void (*dtr_rts)(struct tty_port *port, int raise); | 191 | void (*dtr_rts)(struct tty_port *port, int raise); |
192 | /* Called when the last close completes or a hangup finishes | 192 | /* Called when the last close completes or a hangup finishes |
193 | IFF the port was initialized. Do not use to free resources */ | 193 | IFF the port was initialized. Do not use to free resources. Called |
194 | under the port mutex to serialize against activate/shutdowns */ | ||
194 | void (*shutdown)(struct tty_port *port); | 195 | void (*shutdown)(struct tty_port *port); |
195 | void (*drop)(struct tty_port *port); | 196 | void (*drop)(struct tty_port *port); |
197 | /* Called under the port mutex from tty_port_open, serialized using | ||
198 | the port mutex */ | ||
199 | /* FIXME: long term getting the tty argument *out* of this would be | ||
200 | good for consoles */ | ||
201 | int (*activate)(struct tty_port *port, struct tty_struct *tty); | ||
196 | }; | 202 | }; |
197 | 203 | ||
198 | struct tty_port { | 204 | struct tty_port { |
@@ -467,6 +473,8 @@ extern int tty_port_close_start(struct tty_port *port, | |||
467 | extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); | 473 | extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); |
468 | extern void tty_port_close(struct tty_port *port, | 474 | extern void tty_port_close(struct tty_port *port, |
469 | struct tty_struct *tty, struct file *filp); | 475 | struct tty_struct *tty, struct file *filp); |
476 | extern int tty_port_open(struct tty_port *port, | ||
477 | struct tty_struct *tty, struct file *filp); | ||
470 | extern inline int tty_port_users(struct tty_port *port) | 478 | extern inline int tty_port_users(struct tty_port *port) |
471 | { | 479 | { |
472 | return port->count + port->blocked_open; | 480 | return port->count + port->blocked_open; |