Skip to content

Commit

Permalink
tty: Make epca use the port helpers
Browse files Browse the repository at this point in the history
Now the locking is straight and the port kref usage is straight we can
replace lots of chunks of code with the standard port helpers

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Alan Cox authored and Linus Torvalds committed Jan 2, 2009
1 parent 3969ffb commit 6ed1dba
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 149 deletions.
172 changes: 24 additions & 148 deletions drivers/char/epca.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,58 +432,15 @@ static void pc_close(struct tty_struct *tty, struct file *filp)
return;
port = &ch->port;

spin_lock_irqsave(&port->lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&port->lock, flags);
return;
}
if (port->count-- > 1) {
/* Begin channel is open more than once */
/*
* Return without doing anything. Someone might still
* be using the channel.
*/
spin_unlock_irqrestore(&port->lock, flags);
if (tty_port_close_start(port, tty, filp) == 0)
return;
}
/* Port open only once go ahead with shutdown & reset */
WARN_ON(port->count < 0);

/*
* Let the rest of the driver know the channel is being closed.
* This becomes important if an open is attempted before close
* is finished.
*/
port->flags |= ASYNC_CLOSING;
tty->closing = 1;

spin_unlock_irqrestore(&port->lock, flags);

if (port->flags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the
transmit buffer empties */
setup_empty_event(tty, ch);
/* 30 seconds timeout */
tty_wait_until_sent(tty, 3000);
}
pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch, tty);

spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
ch->event = 0;
tty_port_close_end(port, tty);
ch->event = 0; /* FIXME: review ch->event locking */
tty_port_tty_set(port, NULL);
spin_unlock_irqrestore(&port->lock, flags);

if (port->blocked_open) {
if (ch->close_delay)
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
wake_up_interruptible(&port->open_wait);
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
}

static void shutdown(struct channel *ch, struct tty_struct *tty)
Expand Down Expand Up @@ -527,7 +484,6 @@ static void shutdown(struct channel *ch, struct tty_struct *tty)
static void pc_hangup(struct tty_struct *tty)
{
struct channel *ch;
struct tty_port *port;

/*
* verifyChannel returns the channel from the tty struct if it is
Expand All @@ -536,19 +492,13 @@ static void pc_hangup(struct tty_struct *tty)
ch = verifyChannel(tty);
if (ch != NULL) {
unsigned long flags;
port = &ch->port;

pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch, tty);

spin_lock_irqsave(&port->lock, flags);
port->tty = NULL;
ch->event = 0; /* FIXME: review locking of ch->event */
port->count = 0;
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
tty_port_hangup(&ch->port);
}
}

Expand Down Expand Up @@ -792,98 +742,18 @@ static void pc_flush_chars(struct tty_struct *tty)
}
}

static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
static int epca_carrier_raised(struct tty_port *port)
{
DECLARE_WAITQUEUE(wait, current);
int retval, do_clocal = 0;
unsigned long flags;
struct tty_port *port = &ch->port;

if (tty_hung_up_p(filp)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
return retval;
}

/*
* If the device is in the middle of being closed, then block until
* it's done, and then try again.
*/
if (port->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&port->close_wait);

if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
}

if (filp->f_flags & O_NONBLOCK) {
/*
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/* Block waiting for the carrier detect and the line to become free */

retval = 0;
add_wait_queue(&port->open_wait, &wait);

spin_lock_irqsave(&port->lock, flags);
/* We dec count so that pc_close will know when to free things */
if (!tty_hung_up_p(filp))
port->count--;
port->blocked_open++;
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
}
if (!(port->flags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
spin_unlock_irqrestore(&port->lock, flags);
/*
* Allow someone else to be scheduled. We will occasionally go
* through this loop until one of the above conditions change.
* The below schedule call will allow other processes to enter
* and prevent this loop from hogging the cpu.
*/
schedule();
spin_lock_irqsave(&port->lock, flags);
}

__set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
if (!tty_hung_up_p(filp))
port->count++;
port->blocked_open--;

spin_unlock_irqrestore(&port->lock, flags);

if (retval)
return retval;

port->flags |= ASYNC_NORMAL_ACTIVE;
struct channel *ch = container_of(port, struct channel, port);
if (ch->imodem & ch->dcd)
return 1;
return 0;
}

static void epca_raise_dtr_rts(struct tty_port *port0
{
}

static int pc_open(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
Expand Down Expand Up @@ -978,7 +848,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
port->flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&port->lock, flags);

retval = block_til_ready(tty, filp, ch);
retval = tty_port_block_til_ready(port, tty, filp);
if (retval)
return retval;
/*
Expand Down Expand Up @@ -1058,6 +928,11 @@ static const struct tty_operations pc_ops = {
.break_ctl = pc_send_break
};

static const struct tty_port_operations epca_port_ops = {
.carrier_raised = epca_carrier_raised,
.raise_dtr_rts = epca_raise_dtr_rts,
};

static int info_open(struct tty_struct *tty, struct file *filp)
{
return 0;
Expand Down Expand Up @@ -1393,6 +1268,7 @@ static void post_fep_init(unsigned int crd)
u16 tseg, rseg;

tty_port_init(&ch->port);
ch->port.ops - &epca_port_ops;
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint);
Expand Down Expand Up @@ -1526,7 +1402,7 @@ static void post_fep_init(unsigned int crd)
ch->fepstartca = 0;
ch->fepstopca = 0;

ch->close_delay = 50;
ch->port.close_delay = 50;

spin_unlock_irqrestore(&epca_lock, flags);
}
Expand Down Expand Up @@ -1647,7 +1523,7 @@ static void doevent(int crd)
if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (ch->port.flags & ASYNC_CHECK_CD) {
if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
/* We are now receiving dcd */
if (mstat & ch->dcd)
wake_up_interruptible(&ch->port.open_wait);
Expand Down Expand Up @@ -1894,9 +1770,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* that the driver will wait on carrier detect.
*/
if (ts->c_cflag & CLOCAL)
ch->port.flags &= ~ASYNC_CHECK_CD;
clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
else
ch->port.flags |= ASYNC_CHECK_CD;
set_bit(ASYNC_CHECK_CD, &ch->port.flags);
mval = ch->m_dtr | ch->m_rts;
} /* End CBAUD not detected */
iflag = termios2digi_i(ch, ts->c_iflag);
Expand Down Expand Up @@ -2373,7 +2249,7 @@ static void do_softint(struct work_struct *work)
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty);
wake_up_interruptible(&ch->port.open_wait);
ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
}
}
tty_kref_put(tty);
Expand Down
3 changes: 2 additions & 1 deletion drivers/char/tty_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
port->flags |= ASYNC_CLOSING;
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
if (port->flags & ASYNC_INITIALIZED &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
return 1;
}
Expand Down

0 comments on commit 6ed1dba

Please sign in to comment.