summaryrefslogtreecommitdiff
path: root/drivers/char/generic_serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/generic_serial.c')
-rw-r--r--drivers/char/generic_serial.c76
1 files changed, 44 insertions, 32 deletions
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index c6090f84a2e4..9e4e569dc00d 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -376,7 +376,8 @@ static void gs_shutdown_port (struct gs_port *port)
void gs_hangup(struct tty_struct *tty)
{
- struct gs_port *port;
+ struct gs_port *port;
+ unsigned long flags;
func_enter ();
@@ -386,9 +387,11 @@ void gs_hangup(struct tty_struct *tty)
return;
gs_shutdown_port (port);
+ spin_lock_irqsave(&port->port.lock, flags);
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
port->port.tty = NULL;
port->port.count = 0;
+ spin_unlock_irqrestore(&port->port.lock, flags);
wake_up_interruptible(&port->port.open_wait);
func_exit ();
@@ -397,7 +400,8 @@ void gs_hangup(struct tty_struct *tty)
int gs_block_til_ready(void *port_, struct file * filp)
{
- struct gs_port *port = port_;
+ struct gs_port *gp = port_;
+ struct tty_port *port = &gp->port;
DECLARE_WAITQUEUE(wait, current);
int retval;
int do_clocal = 0;
@@ -409,16 +413,16 @@ int gs_block_til_ready(void *port_, struct file * filp)
if (!port) return 0;
- tty = port->port.tty;
+ tty = port->tty;
gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n");
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
- if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&port->port.close_wait);
- if (port->port.flags & ASYNC_HUP_NOTIFY)
+ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&port->close_wait);
+ if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
@@ -432,7 +436,7 @@ int gs_block_til_ready(void *port_, struct file * filp)
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
- port->port.flags |= ASYNC_NORMAL_ACTIVE;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -444,34 +448,34 @@ int gs_block_til_ready(void *port_, struct file * filp)
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
- * this loop, port->port.count is dropped by one, so that
+ * this loop, port->count is dropped by one, so that
* rs_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
- add_wait_queue(&port->port.open_wait, &wait);
+ add_wait_queue(&port->open_wait, &wait);
gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n");
- spin_lock_irqsave(&port->driver_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
- port->port.count--;
+ port->count--;
}
- spin_unlock_irqrestore(&port->driver_lock, flags);
- port->port.blocked_open++;
+ port->blocked_open++;
+ spin_unlock_irqrestore(&port->lock, flags);
while (1) {
- CD = port->rd->get_CD (port);
+ CD = tty_port_carrier_raised(port);
gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
set_current_state (TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(port->port.flags & ASYNC_INITIALIZED)) {
- if (port->port.flags & ASYNC_HUP_NOTIFY)
+ !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
- if (!(port->port.flags & ASYNC_CLOSING) &&
+ if (!(port->flags & ASYNC_CLOSING) &&
(do_clocal || CD))
break;
gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n",
@@ -483,19 +487,20 @@ int gs_block_til_ready(void *port_, struct file * filp)
schedule();
}
gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
- port->port.blocked_open);
+ port->blocked_open);
set_current_state (TASK_RUNNING);
- remove_wait_queue(&port->port.open_wait, &wait);
+ remove_wait_queue(&port->open_wait, &wait);
+
+ spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp)) {
- port->port.count++;
+ port->count++;
}
- port->port.blocked_open--;
- if (retval)
- return retval;
-
- port->port.flags |= ASYNC_NORMAL_ACTIVE;
+ port->blocked_open--;
+ if (retval == 0)
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ spin_unlock_irqrestore(&port->lock, flags);
func_exit ();
- return 0;
+ return retval;
}
@@ -506,7 +511,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
func_enter ();
- port = (struct gs_port *) tty->driver_data;
+ port = tty->driver_data;
if (!port) return;
@@ -516,10 +521,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
port->port.tty = tty;
}
- spin_lock_irqsave(&port->driver_lock, flags);
+ spin_lock_irqsave(&port->port.lock, flags);
if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&port->driver_lock, flags);
+ spin_unlock_irqrestore(&port->port.lock, flags);
if (port->rd->hungup)
port->rd->hungup (port);
func_exit ();
@@ -538,7 +543,7 @@ void gs_close(struct tty_struct * tty, struct file * filp)
if (port->port.count) {
gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count);
- spin_unlock_irqrestore(&port->driver_lock, flags);
+ spin_unlock_irqrestore(&port->port.lock, flags);
func_exit ();
return;
}
@@ -559,8 +564,10 @@ void gs_close(struct tty_struct * tty, struct file * filp)
* line status register.
*/
+ spin_lock_irqsave(&port->driver_lock, flags);
port->rd->disable_rx_interrupts (port);
spin_unlock_irqrestore(&port->driver_lock, flags);
+ spin_unlock_irqrestore(&port->port.lock, flags);
/* close has no way of returning "EINTR", so discard return value */
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
@@ -573,20 +580,25 @@ void gs_close(struct tty_struct * tty, struct file * filp)
tty_ldisc_flush(tty);
tty->closing = 0;
+ spin_lock_irqsave(&port->driver_lock, flags);
port->event = 0;
port->rd->close (port);
port->rd->shutdown_port (port);
+ spin_unlock_irqrestore(&port->driver_lock, flags);
+
+ spin_lock_irqsave(&port->port.lock, flags);
port->port.tty = NULL;
if (port->port.blocked_open) {
if (port->close_delay) {
- spin_unlock_irqrestore(&port->driver_lock, flags);
+ spin_unlock_irqrestore(&port->port.lock, flags);
msleep_interruptible(jiffies_to_msecs(port->close_delay));
- spin_lock_irqsave(&port->driver_lock, flags);
+ spin_lock_irqsave(&port->port.lock, flags);
}
wake_up_interruptible(&port->port.open_wait);
}
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
+ spin_unlock_irqrestore(&port->port.lock, flags);
wake_up_interruptible(&port->port.close_wait);
func_exit ();