2009-11-18 14:26:26

by Alan

[permalink] [raw]
Subject: [PATCH 0/7] more beating of serial in the direction of sanity

---

Alan Cox (7):
istallion: tty port open/close methods
stallion: Convert to the tty_port_open/close methods
tty_port: Move the IO_ERROR clear
tty_port: Add IO_ERROR bit handling
riscom8: switch to the tty_port_open API
n_tty: fix throttling
tty_port: Change the buffer allocator locking


drivers/char/istallion.c | 177 ++++++++++++++++------------------------------
drivers/char/n_tty.c | 35 +++++++--
drivers/char/riscom8.c | 89 +++++++++++------------
drivers/char/stallion.c | 118 +++++++++----------------------
drivers/char/tty_port.c | 15 +++-
include/linux/tty.h | 1
6 files changed, 174 insertions(+), 261 deletions(-)


2009-11-18 14:26:35

by Alan

[permalink] [raw]
Subject: [PATCH 1/7] tty_port: Change the buffer allocator locking

We want to be able to do this without regard for the activate/own open
method being used which causes a problem using port->mutex. Add another
mutex for now. Once everything uses port_open to do buffer allocs we can
kill it back off

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/tty_port.c | 9 +++++----
include/linux/tty.h | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)


diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 5c2deef..8825255 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -25,6 +25,7 @@ void tty_port_init(struct tty_port *port)
init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->delta_msr_wait);
mutex_init(&port->mutex);
+ mutex_init(&port->buf_mutex);
spin_lock_init(&port->lock);
port->close_delay = (50 * HZ) / 100;
port->closing_wait = (3000 * HZ) / 100;
@@ -34,10 +35,10 @@ EXPORT_SYMBOL(tty_port_init);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
- mutex_lock(&port->mutex);
+ mutex_lock(&port->buf_mutex);
if (port->xmit_buf == NULL)
port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
- mutex_unlock(&port->mutex);
+ mutex_unlock(&port->buf_mutex);
if (port->xmit_buf == NULL)
return -ENOMEM;
return 0;
@@ -46,12 +47,12 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);

void tty_port_free_xmit_buf(struct tty_port *port)
{
- mutex_lock(&port->mutex);
+ mutex_lock(&port->buf_mutex);
if (port->xmit_buf != NULL) {
free_page((unsigned long)port->xmit_buf);
port->xmit_buf = NULL;
}
- mutex_unlock(&port->mutex);
+ mutex_unlock(&port->buf_mutex);
}
EXPORT_SYMBOL(tty_port_free_xmit_buf);

diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6352ac2..e9269ca 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -212,6 +212,7 @@ struct tty_port {
wait_queue_head_t delta_msr_wait; /* Modem status change */
unsigned long flags; /* TTY flags ASY_*/
struct mutex mutex; /* Locking */
+ struct mutex buf_mutex; /* Buffer alloc lock */
unsigned char *xmit_buf; /* Optional buffer */
unsigned int close_delay; /* Close port delay */
unsigned int closing_wait; /* Delay for output */

2009-11-18 14:26:42

by Alan

[permalink] [raw]
Subject: [PATCH 2/7] n_tty: fix throttling

n_tty inadevertently calls throttle and unthrottle methods during its init.
This happens before the tty device is open and causes problems for the
drivers, in particular they may not have their state and locks even
initialised at this point.

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/n_tty.c | 35 ++++++++++++++++++++++++++---------
1 files changed, 26 insertions(+), 9 deletions(-)


diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 2e50f4d..b45170c 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -178,26 +178,23 @@ static void reset_buffer_flags(struct tty_struct *tty)
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
n_tty_set_room(tty);
- check_unthrottle(tty);
}

/**
- * n_tty_flush_buffer - clean input queue
+ * n_tty_do_flush - clean input queue
* @tty: terminal device
*
* Flush the input buffer. Called when the line discipline is
- * being closed, when the tty layer wants the buffer flushed (eg
- * at hangup) or when the N_TTY line discipline internally has to
- * clean the pending queue (for example some signals).
+ * being closed, or indirectly when the tty layer wants the buffer
+ * flushed (eg at hangup) or when the N_TTY line discipline internally
+ * has to clean the pending queue (for example some signals).
*
* Locking: ctrl_lock, read_lock.
*/

-static void n_tty_flush_buffer(struct tty_struct *tty)
+static void n_tty_do_flush(struct tty_struct *tty)
{
unsigned long flags;
- /* clear everything and unthrottle the driver */
- reset_buffer_flags(tty);

if (!tty->link)
return;
@@ -211,6 +208,25 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
}

/**
+ * n_tty_flush_buffer - clean input queue
+ * @tty: terminal device
+ *
+ * Flush the input buffer. Called when the tty layer wants the buffer
+ * flushed (eg at hangup) or when the N_TTY line discipline internally
+ * has to clean the pending queue (for example some signals).
+ *
+ * Locking: ctrl_lock, read_lock.
+ */
+
+static void n_tty_flush_buffer(struct tty_struct *tty)
+{
+ /* clear everything and unthrottle the driver */
+ reset_buffer_flags(tty);
+ check_unthrottle(tty);
+ n_tty_do_flush(tty);
+}
+
+/**
* n_tty_chars_in_buffer - report available bytes
* @tty: tty device
*
@@ -1535,7 +1551,8 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)

static void n_tty_close(struct tty_struct *tty)
{
- n_tty_flush_buffer(tty);
+ reset_buffer_flags(tty);
+ n_tty_do_flush(tty);
if (tty->read_buf) {
kfree(tty->read_buf);
tty->read_buf = NULL;

2009-11-18 14:26:50

by Alan

[permalink] [raw]
Subject: [PATCH 3/7] riscom8: switch to the tty_port_open API

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/riscom8.c | 89 ++++++++++++++++++++++--------------------------
1 files changed, 41 insertions(+), 48 deletions(-)


diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 3cfa22d..d362272 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -793,26 +793,21 @@ static void rc_change_speed(struct tty_struct *tty, struct riscom_board *bp,
}

/* Must be called with interrupts enabled */
-static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
- struct riscom_port *port)
+static int rc_activate_port(struct tty_port *port, struct tty_struct *tty)
{
+ struct riscom_port *rp = container_of(port, struct riscom_port, port);
+ struct riscom_board *bp = port_Board(rp);
unsigned long flags;

- if (port->port.flags & ASYNC_INITIALIZED)
- return 0;
-
- if (tty_port_alloc_xmit_buf(&port->port) < 0)
+ if (tty_port_alloc_xmit_buf(port) < 0)
return -ENOMEM;

spin_lock_irqsave(&riscom_lock, flags);

clear_bit(TTY_IO_ERROR, &tty->flags);
- if (port->port.count == 1)
- bp->count++;
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- rc_change_speed(tty, bp, port);
- port->port.flags |= ASYNC_INITIALIZED;
-
+ bp->count++;
+ rp->xmit_cnt = rp->xmit_head = rp->xmit_tail = 0;
+ rc_change_speed(tty, bp, rp);
spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -821,9 +816,6 @@ static int rc_setup_port(struct tty_struct *tty, struct riscom_board *bp,
static void rc_shutdown_port(struct tty_struct *tty,
struct riscom_board *bp, struct riscom_port *port)
{
- if (!(port->port.flags & ASYNC_INITIALIZED))
- return;
-
#ifdef RC_REPORT_OVERRUN
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
board_No(bp), port_No(port), port->overrun);
@@ -840,11 +832,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
}
#endif
tty_port_free_xmit_buf(&port->port);
- if (C_HUPCL(tty)) {
- /* Drop DTR */
- bp->DTR |= (1u << port_No(port));
- rc_out(bp, RC_DTR, bp->DTR);
- }

/* Select port */
rc_out(bp, CD180_CAR, port_No(port));
@@ -856,7 +843,6 @@ static void rc_shutdown_port(struct tty_struct *tty,
rc_out(bp, CD180_IER, port->IER);

set_bit(TTY_IO_ERROR, &tty->flags);
- port->port.flags &= ~ASYNC_INITIALIZED;

if (--bp->count < 0) {
printk(KERN_INFO "rc%d: rc_shutdown_port: "
@@ -889,6 +875,20 @@ static int carrier_raised(struct tty_port *port)
return CD;
}

+static void dtr_rts(struct tty_port *port, int onoff)
+{
+ struct riscom_port *p = container_of(port, struct riscom_port, port);
+ struct riscom_board *bp = port_Board(p);
+ unsigned long flags;
+
+ spin_lock_irqsave(&riscom_lock, flags);
+ bp->DTR &= ~(1u << port_No(p));
+ if (onoff == 0)
+ bp->DTR |= (1u << port_No(p));
+ rc_out(bp, RC_DTR, bp->DTR);
+ spin_unlock_irqrestore(&riscom_lock, flags);
+}
+
static int rc_open(struct tty_struct *tty, struct file *filp)
{
int board;
@@ -909,14 +909,7 @@ static int rc_open(struct tty_struct *tty, struct file *filp)
if (error)
return error;

- port->port.count++;
- tty->driver_data = port;
- tty_port_tty_set(&port->port, tty);
-
- error = rc_setup_port(tty, bp, port);
- if (error == 0)
- error = tty_port_block_til_ready(&port->port, tty, filp);
- return error;
+ return tty_port_open(&port->port, tty, filp);
}

static void rc_flush_buffer(struct tty_struct *tty)
@@ -950,24 +943,23 @@ static void rc_close_port(struct tty_port *port)

spin_lock_irqsave(&riscom_lock, flags);
rp->IER &= ~IER_RXD;
- if (port->flags & ASYNC_INITIALIZED) {
- rp->IER &= ~IER_TXRDY;
- rp->IER |= IER_TXEMPTY;
- rc_out(bp, CD180_CAR, port_No(rp));
- rc_out(bp, CD180_IER, rp->IER);
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies + HZ;
- while (rp->IER & IER_TXEMPTY) {
- spin_unlock_irqrestore(&riscom_lock, flags);
- msleep_interruptible(jiffies_to_msecs(rp->timeout));
- spin_lock_irqsave(&riscom_lock, flags);
- if (time_after(jiffies, timeout))
- break;
- }
+
+ rp->IER &= ~IER_TXRDY;
+ rp->IER |= IER_TXEMPTY;
+ rc_out(bp, CD180_CAR, port_No(rp));
+ rc_out(bp, CD180_IER, rp->IER);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ timeout = jiffies + HZ;
+ while (rp->IER & IER_TXEMPTY) {
+ spin_unlock_irqrestore(&riscom_lock, flags);
+ msleep_interruptible(jiffies_to_msecs(rp->timeout));
+ spin_lock_irqsave(&riscom_lock, flags);
+ if (time_after(jiffies, timeout))
+ break;
}
rc_shutdown_port(port->tty, bp, rp);
spin_unlock_irqrestore(&riscom_lock, flags);
@@ -1354,7 +1346,6 @@ static void rc_hangup(struct tty_struct *tty)
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;

- rc_shutdown_port(tty, port_Board(port), port);
tty_port_hangup(&port->port);
}

@@ -1401,7 +1392,9 @@ static const struct tty_operations riscom_ops = {

static const struct tty_port_operations riscom_port_ops = {
.carrier_raised = carrier_raised,
+ .dtr_rts = dtr_rts,
.shutdown = rc_close_port,
+ .activate = rc_activate_port,
};


2009-11-18 14:26:59

by Alan

[permalink] [raw]
Subject: [PATCH 4/7] tty_port: Add IO_ERROR bit handling

To propogate tty_port_open/close to a few other devices we need to start
handling the IO_ERROR flag on the tty. We can do this pretty trivially.

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/tty_port.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)


diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 8825255..beaf599 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -122,8 +122,10 @@ void tty_port_hangup(struct tty_port *port)
spin_lock_irqsave(&port->lock, flags);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
- if (port->tty)
+ if (port->tty) {
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
tty_kref_put(port->tty);
+ }
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
@@ -377,6 +379,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
if (tty_port_close_start(port, tty, filp) == 0)
return;
tty_port_shutdown(port);
+ set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
}
@@ -408,6 +411,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
}
}
set_bit(ASYNCB_INITIALIZED, &port->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
}
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);

2009-11-18 14:27:07

by Alan

[permalink] [raw]
Subject: [PATCH 5/7] tty_port: Move the IO_ERROR clear

Some devices want to set IO_ERROR in their activate methods so that you can
be handed a 'dead' port for operations like setserial. Thus we need to
clear the flag before activate so that activate can choose to set the flag
and still return 0.

This is fine as the file handle/tty are not accessible to the user yet.

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/tty_port.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index beaf599..a413db4 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -403,6 +403,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
mutex_lock(&port->mutex);

if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
if (retval) {
@@ -411,7 +412,6 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
}
}
set_bit(ASYNCB_INITIALIZED, &port->flags);
- clear_bit(TTY_IO_ERROR, &tty->flags);
}
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);

2009-11-18 14:27:15

by Alan

[permalink] [raw]
Subject: [PATCH 6/7] stallion: Convert to the tty_port_open/close methods

The driver is already structured this way so just slice and dice

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/stallion.c | 118 ++++++++++++++---------------------------------
1 files changed, 36 insertions(+), 82 deletions(-)


diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index b4ba5ed..d04a398 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -702,6 +702,24 @@ static struct stlbrd *stl_allocbrd(void)

/*****************************************************************************/

+static int stl_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct stlport *portp = container_of(port, struct stlport, port);
+ if (!portp->tx.buf) {
+ portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
+ if (!portp->tx.buf)
+ return -ENOMEM;
+ portp->tx.head = portp->tx.buf;
+ portp->tx.tail = portp->tx.buf;
+ }
+ stl_setport(portp, tty->termios);
+ portp->sigs = stl_getsignals(portp);
+ stl_setsignals(portp, 1, 1);
+ stl_enablerxtx(portp, 1, 1);
+ stl_startrxtx(portp, 1, 0);
+ return 0;
+}
+
static int stl_open(struct tty_struct *tty, struct file *filp)
{
struct stlport *portp;
@@ -737,32 +755,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
if (portp == NULL)
return -ENODEV;
port = &portp->port;
-
-/*
- * On the first open of the device setup the port hardware, and
- * initialize the per port data structure.
- */
- tty_port_tty_set(port, tty);
- tty->driver_data = portp;
- port->count++;
-
- if ((port->flags & ASYNC_INITIALIZED) == 0) {
- if (!portp->tx.buf) {
- portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
- if (!portp->tx.buf)
- return -ENOMEM;
- portp->tx.head = portp->tx.buf;
- portp->tx.tail = portp->tx.buf;
- }
- stl_setport(portp, tty->termios);
- portp->sigs = stl_getsignals(portp);
- stl_setsignals(portp, 1, 1);
- stl_enablerxtx(portp, 1, 1);
- stl_startrxtx(portp, 1, 0);
- clear_bit(TTY_IO_ERROR, &tty->flags);
- port->flags |= ASYNC_INITIALIZED;
- }
- return tty_port_block_til_ready(port, tty, filp);
+ return tty_port_open(&portp->port, tty, filp);
+
}

/*****************************************************************************/
@@ -826,38 +820,12 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)

/*****************************************************************************/

-static void stl_close(struct tty_struct *tty, struct file *filp)
+static void stl_shutdown(struct tty_port *port)
{
- struct stlport *portp;
- struct tty_port *port;
- unsigned long flags;
-
- pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
-
- portp = tty->driver_data;
- BUG_ON(portp == NULL);
-
- port = &portp->port;
-
- if (tty_port_close_start(port, tty, filp) == 0)
- return;
-/*
- * May want to wait for any data to drain before closing. The BUSY
- * flag keeps track of whether we are still sending or not - it is
- * very accurate for the cd1400, not quite so for the sc26198.
- * (The sc26198 has no "end-of-data" interrupt only empty FIFO)
- */
- stl_waituntilsent(tty, (HZ / 2));
-
- spin_lock_irqsave(&port->lock, flags);
- portp->port.flags &= ~ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&port->lock, flags);
-
+ struct stlport *portp = container_of(port, struct stlport, port);
stl_disableintrs(portp);
- if (tty->termios->c_cflag & HUPCL)
- stl_setsignals(portp, 0, 0);
stl_enablerxtx(portp, 0, 0);
- stl_flushbuffer(tty);
+ stl_flush(portp);
portp->istate = 0;
if (portp->tx.buf != NULL) {
kfree(portp->tx.buf);
@@ -865,9 +833,16 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
portp->tx.head = NULL;
portp->tx.tail = NULL;
}
+}

- tty_port_close_end(port, tty);
- tty_port_tty_set(port, NULL);
+static void stl_close(struct tty_struct *tty, struct file *filp)
+{
+ struct stlport*portp;
+ pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
+
+ portp = tty->driver_data;
+ BUG_ON(portp == NULL);
+ tty_port_close(&portp->port, tty, filp);
}

/*****************************************************************************/
@@ -1314,35 +1289,12 @@ static void stl_stop(struct tty_struct *tty)

static void stl_hangup(struct tty_struct *tty)
{
- struct stlport *portp;
- struct tty_port *port;
- unsigned long flags;
-
+ struct stlport *portp = tty->driver_data;
pr_debug("stl_hangup(tty=%p)\n", tty);

- portp = tty->driver_data;
if (portp == NULL)
return;
- port = &portp->port;
-
- spin_lock_irqsave(&port->lock, flags);
- port->flags &= ~ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&port->lock, flags);
-
- stl_disableintrs(portp);
- if (tty->termios->c_cflag & HUPCL)
- stl_setsignals(portp, 0, 0);
- stl_enablerxtx(portp, 0, 0);
- stl_flushbuffer(tty);
- portp->istate = 0;
- set_bit(TTY_IO_ERROR, &tty->flags);
- if (portp->tx.buf != NULL) {
- kfree(portp->tx.buf);
- portp->tx.buf = NULL;
- portp->tx.head = NULL;
- portp->tx.tail = NULL;
- }
- tty_port_hangup(port);
+ tty_port_hangup(&portp->port);
}

/*****************************************************************************/
@@ -2550,6 +2502,8 @@ static const struct tty_operations stl_ops = {
static const struct tty_port_operations stl_port_ops = {
.carrier_raised = stl_carrier_raised,
.dtr_rts = stl_dtr_rts,
+ .activate = stl_activate,
+ .shutdown = stl_shutdown,
};

/*****************************************************************************/

2009-11-18 14:27:22

by Alan

[permalink] [raw]
Subject: [PATCH 7/7] istallion: tty port open/close methods

Slice/dice/repeat as with the stallion driver this is just code shuffling
and removal

Signed-off-by: Alan Cox <[email protected]>
---

drivers/char/istallion.c | 177 ++++++++++++++++------------------------------
1 files changed, 60 insertions(+), 117 deletions(-)


diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index babfd44..4cd6c52 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -213,7 +213,6 @@ static int stli_shared;
* with the slave. Most of them need to be updated atomically, so always
* use the bit setting operations (unless protected by cli/sti).
*/
-#define ST_INITIALIZING 1
#define ST_OPENING 2
#define ST_CLOSING 3
#define ST_CMDING 4
@@ -783,13 +782,32 @@ static int stli_parsebrd(struct stlconf *confp, char **argp)

/*****************************************************************************/

+/*
+ * On the first open of the device setup the port hardware, and
+ * initialize the per port data structure. Since initializing the port
+ * requires several commands to the board we will need to wait for any
+ * other open that is already initializing the port.
+ *
+ * Locking: protected by the port mutex.
+ */
+
+static int stli_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct stliport *portp = container_of(port, struct stliport, port);
+ struct stlibrd *brdp = stli_brds[portp->brdnr];
+ int rc;
+
+ if ((rc = stli_initopen(tty, brdp, portp)) >= 0)
+ clear_bit(TTY_IO_ERROR, &tty->flags);
+ wake_up_interruptible(&portp->raw_wait);
+ return rc;
+}
+
static int stli_open(struct tty_struct *tty, struct file *filp)
{
struct stlibrd *brdp;
struct stliport *portp;
- struct tty_port *port;
unsigned int minordev, brdnr, portnr;
- int rc;

minordev = tty->index;
brdnr = MINOR2BRD(minordev);
@@ -809,95 +827,56 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
if (portp->devnr < 1)
return -ENODEV;
- port = &portp->port;
-
-/*
- * On the first open of the device setup the port hardware, and
- * initialize the per port data structure. Since initializing the port
- * requires several commands to the board we will need to wait for any
- * other open that is already initializing the port.
- *
- * Review - locking
- */
- tty_port_tty_set(port, tty);
- tty->driver_data = portp;
- port->count++;
-
- wait_event_interruptible(portp->raw_wait,
- !test_bit(ST_INITIALIZING, &portp->state));
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
- set_bit(ST_INITIALIZING, &portp->state);
- if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
- /* Locking */
- port->flags |= ASYNC_INITIALIZED;
- clear_bit(TTY_IO_ERROR, &tty->flags);
- }
- clear_bit(ST_INITIALIZING, &portp->state);
- wake_up_interruptible(&portp->raw_wait);
- if (rc < 0)
- return rc;
- }
- return tty_port_block_til_ready(&portp->port, tty, filp);
+ return tty_port_open(&portp->port, tty, filp);
}

+
/*****************************************************************************/

-static void stli_close(struct tty_struct *tty, struct file *filp)
+static void stli_shutdown(struct tty_port *port)
{
struct stlibrd *brdp;
- struct stliport *portp;
- struct tty_port *port;
+ unsigned long ftype;
unsigned long flags;
+ struct stliport *portp = container_of(port, struct stliport, port);

- portp = tty->driver_data;
- if (portp == NULL)
+ if (portp->brdnr >= stli_nrbrds)
return;
- port = &portp->port;
-
- if (tty_port_close_start(port, tty, filp) == 0)
+ brdp = stli_brds[portp->brdnr];
+ if (brdp == NULL)
return;

-/*
- * May want to wait for data to drain before closing. The BUSY flag
- * keeps track of whether we are still transmitting or not. It is
- * updated by messages from the slave - indicating when all chars
- * really have drained.
- */
- spin_lock_irqsave(&stli_lock, flags);
- if (tty == stli_txcooktty)
- stli_flushchars(tty);
- spin_unlock_irqrestore(&stli_lock, flags);
-
- /* We end up doing this twice for the moment. This needs looking at
- eventually. Note we still use portp->closing_wait as a result */
- if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, portp->closing_wait);
+ /*
+ * May want to wait for data to drain before closing. The BUSY
+ * flag keeps track of whether we are still transmitting or not.
+ * It is updated by messages from the slave - indicating when all
+ * chars really have drained.
+ */

- /* FIXME: port locking here needs attending to */
- port->flags &= ~ASYNC_INITIALIZED;
+ if (!test_bit(ST_CLOSING, &portp->state))
+ stli_rawclose(brdp, portp, 0, 0);

- brdp = stli_brds[portp->brdnr];
- stli_rawclose(brdp, portp, 0, 0);
- if (tty->termios->c_cflag & HUPCL) {
- stli_mkasysigs(&portp->asig, 0, 0);
- if (test_bit(ST_CMDING, &portp->state))
- set_bit(ST_DOSIGS, &portp->state);
- else
- stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig,
- sizeof(asysigs_t), 0);
- }
+ spin_lock_irqsave(&stli_lock, flags);
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
- set_bit(TTY_IO_ERROR, &tty->flags);
- tty_ldisc_flush(tty);
- set_bit(ST_DOFLUSHRX, &portp->state);
- stli_flushbuffer(tty);
+ spin_unlock_irqrestore(&stli_lock, flags);

- tty_port_close_end(port, tty);
- tty_port_tty_set(port, NULL);
+ ftype = FLUSHTX | FLUSHRX;
+ stli_cmdwait(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
+}
+
+static void stli_close(struct tty_struct *tty, struct file *filp)
+{
+ struct stliport *portp = tty->driver_data;
+ unsigned long flags;
+ if (portp == NULL)
+ return;
+ spin_lock_irqsave(&stli_lock, flags);
+ /* Flush any internal buffering out first */
+ if (tty == stli_txcooktty)
+ stli_flushchars(tty);
+ spin_unlock_irqrestore(&stli_lock, flags);
+ tty_port_close(&portp->port, tty, filp);
}

/*****************************************************************************/
@@ -1724,6 +1703,7 @@ static void stli_start(struct tty_struct *tty)

/*****************************************************************************/

+
/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
@@ -1733,47 +1713,8 @@ static void stli_start(struct tty_struct *tty)

static void stli_hangup(struct tty_struct *tty)
{
- struct stliport *portp;
- struct stlibrd *brdp;
- struct tty_port *port;
- unsigned long flags;
-
- portp = tty->driver_data;
- if (portp == NULL)
- return;
- if (portp->brdnr >= stli_nrbrds)
- return;
- brdp = stli_brds[portp->brdnr];
- if (brdp == NULL)
- return;
- port = &portp->port;
-
- spin_lock_irqsave(&port->lock, flags);
- port->flags &= ~ASYNC_INITIALIZED;
- spin_unlock_irqrestore(&port->lock, flags);
-
- if (!test_bit(ST_CLOSING, &portp->state))
- stli_rawclose(brdp, portp, 0, 0);
-
- spin_lock_irqsave(&stli_lock, flags);
- if (tty->termios->c_cflag & HUPCL) {
- stli_mkasysigs(&portp->asig, 0, 0);
- if (test_bit(ST_CMDING, &portp->state)) {
- set_bit(ST_DOSIGS, &portp->state);
- set_bit(ST_DOFLUSHTX, &portp->state);
- set_bit(ST_DOFLUSHRX, &portp->state);
- } else {
- stli_sendcmd(brdp, portp, A_SETSIGNALSF,
- &portp->asig, sizeof(asysigs_t), 0);
- }
- }
-
- clear_bit(ST_TXBUSY, &portp->state);
- clear_bit(ST_RXSTOP, &portp->state);
- set_bit(TTY_IO_ERROR, &tty->flags);
- spin_unlock_irqrestore(&stli_lock, flags);
-
- tty_port_hangup(port);
+ struct stliport *portp = tty->driver_data;
+ tty_port_hangup(&portp->port);
}

/*****************************************************************************/
@@ -4420,6 +4361,8 @@ static const struct tty_operations stli_ops = {
static const struct tty_port_operations stli_port_ops = {
.carrier_raised = stli_carrier_raised,
.dtr_rts = stli_dtr_rts,
+ .activate = stli_activate,
+ .shutdown = stli_shutdown,
};

/*****************************************************************************/