headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / char / stallion.c
index 87bda40..db6dcfa 100644 (file)
 /*****************************************************************************/
 
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
+#include <linux/seq_file.h>
 #include <linux/cd1400.h>
 #include <linux/sc26198.h>
 #include <linux/comstats.h>
@@ -63,7 +65,7 @@
 #define        BRD_EASYIOPCI   28
 
 struct stlconf {
-       int             brdtype;
+       unsigned int    brdtype;
        int             ioaddr1;
        int             ioaddr2;
        unsigned long   memaddr;
@@ -121,15 +123,6 @@ static struct ktermios             stl_deftermios = {
 };
 
 /*
- *     Define global stats structures. Not used often, and can be
- *     re-used for each stats call.
- */
-static comstats_t      stl_comstats;
-static combrd_t                stl_brdstats;
-static struct stlbrd           stl_dummybrd;
-static struct stlport  stl_dummyport;
-
-/*
  *     Define global place to put buffer overflow characters.
  */
 static char            stl_unwanted[SC26198_RXFIFOSIZE];
@@ -139,6 +132,8 @@ static char         stl_unwanted[SC26198_RXFIFOSIZE];
 static DEFINE_MUTEX(stl_brdslock);
 static struct stlbrd           *stl_brds[STL_MAXBRDS];
 
+static const struct tty_port_operations stl_port_ops;
+
 /*
  *     Per board state flags. Used with the state field of the board struct.
  *     Not really much here!
@@ -154,8 +149,7 @@ static struct stlbrd                *stl_brds[STL_MAXBRDS];
  */
 #define        ASYI_TXBUSY     1
 #define        ASYI_TXLOW      2
-#define        ASYI_DCDCHANGE  3
-#define        ASYI_TXFLOWED   4
+#define        ASYI_TXFLOWED   3
 
 /*
  *     Define an array of board names as printable strings. Handy for
@@ -200,7 +194,7 @@ static char *stl_brdnames[] = {
  *     load line. These allow for easy board definitions, and easy
  *     modification of the io, memory and irq resoucres.
  */
-static int     stl_nargs = 0;
+static unsigned int stl_nargs;
 static char    *board0[4];
 static char    *board1[4];
 static char    *board2[4];
@@ -415,9 +409,8 @@ static unsigned int stl_baudrates[] = {
 
 static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 static int     stl_brdinit(struct stlbrd *brdp);
-static int     stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int     stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
 static int     stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int     stl_waitcarrier(struct stlport *portp, struct file *filp);
 
 /*
  *     CD1400 uart specific handling functions.
@@ -619,6 +612,25 @@ static const struct file_operations        stl_fsiomem = {
 
 static struct class *stallion_class;
 
+static void stl_cd_change(struct stlport *portp)
+{
+       unsigned int oldsigs = portp->sigs;
+       struct tty_struct *tty = tty_port_tty_get(&portp->port);
+
+       if (!tty)
+               return;
+
+       portp->sigs = stl_getsignals(portp);
+
+       if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
+               wake_up_interruptible(&portp->port.open_wait);
+
+       if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
+               if (portp->port.flags & ASYNC_CHECK_CD)
+                       tty_hangup(tty);
+       tty_kref_put(tty);
+}
+
 /*
  *     Check for any arguments passed in on the module load command line.
  */
@@ -632,20 +644,20 @@ static struct class *stallion_class;
 static int __init stl_parsebrd(struct stlconf *confp, char **argp)
 {
        char    *sp;
-       int     i;
+       unsigned int i;
 
        pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp);
 
        if ((argp[0] == NULL) || (*argp[0] == 0))
                return 0;
 
-       for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
+       for (sp = argp[0], i = 0; (*sp != 0) && (i < 25); sp++, i++)
                *sp = tolower(*sp);
 
-       for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++) {
+       for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++)
                if (strcmp(stl_brdstr[i].name, argp[0]) == 0)
                        break;
-       }
+
        if (i == ARRAY_SIZE(stl_brdstr)) {
                printk("STALLION: unknown board name, %s?\n", argp[0]);
                return 0;
@@ -694,8 +706,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlport  *portp;
        struct stlbrd   *brdp;
-       unsigned int    minordev;
-       int             brdnr, panelnr, portnr, rc;
+       struct tty_port *port;
+       unsigned int    minordev, brdnr, panelnr;
+       int             portnr;
 
        pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
 
@@ -706,8 +719,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        brdp = stl_brds[brdnr];
        if (brdp == NULL)
                return -ENODEV;
+
        minordev = MINOR2PORT(minordev);
-       for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) {
+       for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) {
                if (brdp->panels[panelnr] == NULL)
                        break;
                if (minordev < brdp->panels[panelnr]->nrports) {
@@ -722,16 +736,17 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        portp = brdp->panels[panelnr]->ports[portnr];
        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.
  */
-       portp->tty = tty;
+       tty_port_tty_set(port, tty);
        tty->driver_data = portp;
-       portp->refcount++;
+       port->count++;
 
-       if ((portp->flags & ASYNC_INITIALIZED) == 0) {
+       if ((port->flags & ASYNC_INITIALIZED) == 0) {
                if (!portp->tx.buf) {
                        portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
                        if (!portp->tx.buf)
@@ -745,91 +760,24 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
                stl_enablerxtx(portp, 1, 1);
                stl_startrxtx(portp, 1, 0);
                clear_bit(TTY_IO_ERROR, &tty->flags);
-               portp->flags |= ASYNC_INITIALIZED;
+               port->flags |= ASYNC_INITIALIZED;
        }
-
-/*
- *     Check if this port is in the middle of closing. If so then wait
- *     until it is closed then return error status, based on flag settings.
- *     The sleep here does not need interrupt protection since the wakeup
- *     for it is done with the same context.
- */
-       if (portp->flags & ASYNC_CLOSING) {
-               interruptible_sleep_on(&portp->close_wait);
-               if (portp->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               return -ERESTARTSYS;
-       }
-
-/*
- *     Based on type of open being done check if it can overlap with any
- *     previous opens still in effect. If we are a normal serial device
- *     then also we might have to wait for carrier.
- */
-       if (!(filp->f_flags & O_NONBLOCK)) {
-               if ((rc = stl_waitcarrier(portp, filp)) != 0)
-                       return rc;
-       }
-       portp->flags |= ASYNC_NORMAL_ACTIVE;
-
-       return 0;
+       return tty_port_block_til_ready(port, tty, filp);
 }
 
 /*****************************************************************************/
 
-/*
- *     Possibly need to wait for carrier (DCD signal) to come high. Say
- *     maybe because if we are clocal then we don't need to wait...
- */
-
-static int stl_waitcarrier(struct stlport *portp, struct file *filp)
+static int stl_carrier_raised(struct tty_port *port)
 {
-       unsigned long   flags;
-       int             rc, doclocal;
-
-       pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp);
-
-       rc = 0;
-       doclocal = 0;
-
-       spin_lock_irqsave(&stallion_lock, flags);
-
-       if (portp->tty->termios->c_cflag & CLOCAL)
-               doclocal++;
-
-       portp->openwaitcnt++;
-       if (! tty_hung_up_p(filp))
-               portp->refcount--;
-
-       for (;;) {
-               /* Takes brd_lock internally */
-               stl_setsignals(portp, 1, 1);
-               if (tty_hung_up_p(filp) ||
-                   ((portp->flags & ASYNC_INITIALIZED) == 0)) {
-                       if (portp->flags & ASYNC_HUP_NOTIFY)
-                               rc = -EBUSY;
-                       else
-                               rc = -ERESTARTSYS;
-                       break;
-               }
-               if (((portp->flags & ASYNC_CLOSING) == 0) &&
-                   (doclocal || (portp->sigs & TIOCM_CD))) {
-                       break;
-               }
-               if (signal_pending(current)) {
-                       rc = -ERESTARTSYS;
-                       break;
-               }
-               /* FIXME */
-               interruptible_sleep_on(&portp->open_wait);
-       }
-
-       if (! tty_hung_up_p(filp))
-               portp->refcount++;
-       portp->openwaitcnt--;
-       spin_unlock_irqrestore(&stallion_lock, flags);
+       struct stlport *portp = container_of(port, struct stlport, port);
+       return (portp->sigs & TIOCM_CD) ? 1 : 0;
+}
 
-       return rc;
+static void stl_dtr_rts(struct tty_port *port, int on)
+{
+       struct stlport *portp = container_of(port, struct stlport, port);
+       /* Takes brd_lock internally */
+       stl_setsignals(portp, on, on);
 }
 
 /*****************************************************************************/
@@ -840,8 +788,6 @@ static void stl_flushbuffer(struct tty_struct *tty)
 
        pr_debug("stl_flushbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -859,8 +805,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 
        pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -869,6 +813,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
                timeout = HZ;
        tend = jiffies + timeout;
 
+       lock_kernel();
        while (stl_datastate(portp)) {
                if (signal_pending(current))
                        break;
@@ -876,6 +821,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
                if (time_after_eq(jiffies, tend))
                        break;
        }
+       unlock_kernel();
 }
 
 /*****************************************************************************/
@@ -883,47 +829,29 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 static void stl_close(struct tty_struct *tty, struct file *filp)
 {
        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;
-       if (portp == NULL)
-               return;
-
-       spin_lock_irqsave(&stallion_lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&stallion_lock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (portp->refcount != 1))
-               portp->refcount = 1;
-       if (portp->refcount-- > 1) {
-               spin_unlock_irqrestore(&stallion_lock, flags);
-               return;
-       }
+       BUG_ON(portp == NULL);
 
-       portp->refcount = 0;
-       portp->flags |= ASYNC_CLOSING;
+       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)
  */
-       tty->closing = 1;
-
-       spin_unlock_irqrestore(&stallion_lock, flags);
-
-       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, portp->closing_wait);
        stl_waituntilsent(tty, (HZ / 2));
 
-
-       spin_lock_irqsave(&stallion_lock, flags);
-       portp->flags &= ~ASYNC_INITIALIZED;
-       spin_unlock_irqrestore(&stallion_lock, flags);
+       spin_lock_irqsave(&port->lock, flags);
+       portp->port.flags &= ~ASYNC_INITIALIZED;
+       spin_unlock_irqrestore(&port->lock, flags);
 
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
@@ -937,20 +865,9 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_ldisc_flush(tty);
-
-       tty->closing = 0;
-       portp->tty = NULL;
-
-       if (portp->openwaitcnt) {
-               if (portp->close_delay)
-                       msleep_interruptible(jiffies_to_msecs(portp->close_delay));
-               wake_up_interruptible(&portp->open_wait);
-       }
 
-       portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&portp->close_wait);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 /*****************************************************************************/
@@ -1017,7 +934,7 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
 
 /*****************************************************************************/
 
-static void stl_putchar(struct tty_struct *tty, unsigned char ch)
+static int stl_putchar(struct tty_struct *tty, unsigned char ch)
 {
        struct stlport  *portp;
        unsigned int    len;
@@ -1025,13 +942,11 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch)
 
        pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
-               return;
+               return -EINVAL;
        if (portp->tx.buf == NULL)
-               return;
+               return -EINVAL;
 
        head = portp->tx.head;
        tail = portp->tx.tail;
@@ -1045,6 +960,7 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch)
                        head = portp->tx.buf;
        }       
        portp->tx.head = head;
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1061,8 +977,6 @@ static void stl_flushchars(struct tty_struct *tty)
 
        pr_debug("stl_flushchars(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1081,8 +995,6 @@ static int stl_writeroom(struct tty_struct *tty)
 
        pr_debug("stl_writeroom(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1091,7 +1003,7 @@ static int stl_writeroom(struct tty_struct *tty)
 
        head = portp->tx.head;
        tail = portp->tx.tail;
-       return ((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1));
+       return (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1);
 }
 
 /*****************************************************************************/
@@ -1113,8 +1025,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)
 
        pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return 0;
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
@@ -1145,7 +1055,7 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
        memset(&sio, 0, sizeof(struct serial_struct));
        sio.line = portp->portnr;
        sio.port = portp->ioaddr;
-       sio.flags = portp->flags;
+       sio.flags = portp->port.flags;
        sio.baud_base = portp->baud_base;
        sio.close_delay = portp->close_delay;
        sio.closing_wait = portp->closing_wait;
@@ -1174,8 +1084,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
  *     just quietly ignore any requests to change irq, etc.
  */
 
-static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
 {
+       struct stlport *        portp = tty->driver_data;
        struct serial_struct    sio;
 
        pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
@@ -1186,17 +1097,17 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
                if ((sio.baud_base != portp->baud_base) ||
                    (sio.close_delay != portp->close_delay) ||
                    ((sio.flags & ~ASYNC_USR_MASK) !=
-                   (portp->flags & ~ASYNC_USR_MASK)))
+                   (portp->port.flags & ~ASYNC_USR_MASK)))
                        return -EPERM;
        } 
 
-       portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+       portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
                (sio.flags & ASYNC_USR_MASK);
        portp->baud_base = sio.baud_base;
        portp->close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
        portp->custom_divisor = sio.custom_divisor;
-       stl_setport(portp, portp->tty->termios);
+       stl_setport(portp, tty->termios);
        return 0;
 }
 
@@ -1206,8 +1117,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct stlport  *portp;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1223,8 +1132,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
        struct stlport  *portp;
        int rts = -1, dtr = -1;
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
@@ -1247,47 +1154,34 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
 static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct stlport  *portp;
-       unsigned int    ival;
        int             rc;
        void __user *argp = (void __user *)arg;
 
        pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
                        arg);
 
-       if (tty == NULL)
-               return -ENODEV;
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
 
        if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-           (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+           (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS))
                if (tty->flags & (1 << TTY_IO_ERROR))
                        return -EIO;
-       }
 
        rc = 0;
 
+       lock_kernel();
+
        switch (cmd) {
-       case TIOCGSOFTCAR:
-               rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
-                       (unsigned __user *) argp);
-               break;
-       case TIOCSSOFTCAR:
-               if (get_user(ival, (unsigned int __user *) arg))
-                       return -EFAULT;
-               tty->termios->c_cflag =
-                               (tty->termios->c_cflag & ~CLOCAL) |
-                               (ival ? CLOCAL : 0);
-               break;
        case TIOCGSERIAL:
                rc = stl_getserial(portp, argp);
                break;
        case TIOCSSERIAL:
-               rc = stl_setserial(portp, argp);
+               rc = stl_setserial(tty, argp);
                break;
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(portp, argp);
+               rc = stl_getportstats(tty, portp, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(portp, argp);
@@ -1303,7 +1197,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                rc = -ENOIOCTLCMD;
                break;
        }
-
+       unlock_kernel();
        return rc;
 }
 
@@ -1319,8 +1213,6 @@ static void stl_start(struct tty_struct *tty)
 
        pr_debug("stl_start(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1336,8 +1228,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
 
        pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1355,7 +1245,7 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
                stl_start(tty);
        }
        if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
-               wake_up_interruptible(&portp->open_wait);
+               wake_up_interruptible(&portp->port.open_wait);
 }
 
 /*****************************************************************************/
@@ -1371,8 +1261,6 @@ static void stl_throttle(struct tty_struct *tty)
 
        pr_debug("stl_throttle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1391,8 +1279,6 @@ static void stl_unthrottle(struct tty_struct *tty)
 
        pr_debug("stl_unthrottle(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1412,8 +1298,6 @@ static void stl_stop(struct tty_struct *tty)
 
        pr_debug("stl_stop(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1431,16 +1315,20 @@ 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;
 
        pr_debug("stl_hangup(tty=%p)\n", tty);
 
-       if (tty == NULL)
-               return;
        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);
 
-       portp->flags &= ~ASYNC_INITIALIZED;
        stl_disableintrs(portp);
        if (tty->termios->c_cflag & HUPCL)
                stl_setsignals(portp, 0, 0);
@@ -1454,27 +1342,23 @@ static void stl_hangup(struct tty_struct *tty)
                portp->tx.head = NULL;
                portp->tx.tail = NULL;
        }
-       portp->tty = NULL;
-       portp->flags &= ~ASYNC_NORMAL_ACTIVE;
-       portp->refcount = 0;
-       wake_up_interruptible(&portp->open_wait);
+       tty_port_hangup(port);
 }
 
 /*****************************************************************************/
 
-static void stl_breakctl(struct tty_struct *tty, int state)
+static int stl_breakctl(struct tty_struct *tty, int state)
 {
        struct stlport  *portp;
 
        pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
-               return;
+               return -EINVAL;
 
        stl_sendbreak(portp, ((state == -1) ? 1 : 2));
+       return 0;
 }
 
 /*****************************************************************************/
@@ -1485,8 +1369,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
 
        pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
 
-       if (tty == NULL)
-               return;
        portp = tty->driver_data;
        if (portp == NULL)
                return;
@@ -1499,52 +1381,47 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
                stl_putchar(tty, ch);
 }
 
-/*****************************************************************************/
-
-#define        MAXLINE         80
-
-/*
- *     Format info for a specified port. The line is deliberately limited
- *     to 80 characters. (If it is too long it will be truncated, if too
- *     short then padded with spaces).
- */
-
-static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
+static void stl_portinfo(struct seq_file *m, struct stlport *portp, int portnr)
 {
-       char    *sp;
-       int     sigs, cnt;
+       int     sigs;
+       char sep;
 
-       sp = pos;
-       sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d",
+       seq_printf(m, "%d: uart:%s tx:%d rx:%d",
                portnr, (portp->hwid == 1) ? "SC26198" : "CD1400",
                (int) portp->stats.txtotal, (int) portp->stats.rxtotal);
 
        if (portp->stats.rxframing)
-               sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing);
+               seq_printf(m, " fe:%d", (int) portp->stats.rxframing);
        if (portp->stats.rxparity)
-               sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity);
+               seq_printf(m, " pe:%d", (int) portp->stats.rxparity);
        if (portp->stats.rxbreaks)
-               sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks);
+               seq_printf(m, " brk:%d", (int) portp->stats.rxbreaks);
        if (portp->stats.rxoverrun)
-               sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun);
+               seq_printf(m, " oe:%d", (int) portp->stats.rxoverrun);
 
        sigs = stl_getsignals(portp);
-       cnt = sprintf(sp, "%s%s%s%s%s ",
-               (sigs & TIOCM_RTS) ? "|RTS" : "",
-               (sigs & TIOCM_CTS) ? "|CTS" : "",
-               (sigs & TIOCM_DTR) ? "|DTR" : "",
-               (sigs & TIOCM_CD) ? "|DCD" : "",
-               (sigs & TIOCM_DSR) ? "|DSR" : "");
-       *sp = ' ';
-       sp += cnt;
-
-       for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
-               *sp++ = ' ';
-       if (cnt >= MAXLINE)
-               pos[(MAXLINE - 2)] = '+';
-       pos[(MAXLINE - 1)] = '\n';
-
-       return MAXLINE;
+       sep = ' ';
+       if (sigs & TIOCM_RTS) {
+               seq_printf(m, "%c%s", sep, "RTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CTS) {
+               seq_printf(m, "%c%s", sep, "CTS");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DTR) {
+               seq_printf(m, "%c%s", sep, "DTR");
+               sep = '|';
+       }
+       if (sigs & TIOCM_CD) {
+               seq_printf(m, "%c%s", sep, "DCD");
+               sep = '|';
+       }
+       if (sigs & TIOCM_DSR) {
+               seq_printf(m, "%c%s", sep, "DSR");
+               sep = '|';
+       }
+       seq_putc(m, '\n');
 }
 
 /*****************************************************************************/
@@ -1553,82 +1430,60 @@ static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
  *     Port info, read from the /proc file system.
  */
 
-static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int stl_proc_show(struct seq_file *m, void *v)
 {
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
        struct stlport  *portp;
-       int             brdnr, panelnr, portnr, totalport;
-       int             curoff, maxoff;
-       char            *pos;
+       unsigned int    brdnr, panelnr, portnr;
+       int             totalport;
 
-       pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
-               "data=%p\n", page, start, off, count, eof, data);
-
-       pos = page;
        totalport = 0;
-       curoff = 0;
-
-       if (off == 0) {
-               pos += sprintf(pos, "%s: version %s", stl_drvtitle,
-                       stl_drvversion);
-               while (pos < (page + MAXLINE - 1))
-                       *pos++ = ' ';
-               *pos++ = '\n';
-       }
-       curoff =  MAXLINE;
+
+       seq_printf(m, "%s: version %s\n", stl_drvtitle, stl_drvversion);
 
 /*
  *     We scan through for each board, panel and port. The offset is
  *     calculated on the fly, and irrelevant ports are skipped.
  */
-       for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) {
+       for (brdnr = 0; brdnr < stl_nrbrds; brdnr++) {
                brdp = stl_brds[brdnr];
                if (brdp == NULL)
                        continue;
                if (brdp->state == 0)
                        continue;
 
-               maxoff = curoff + (brdp->nrports * MAXLINE);
-               if (off >= maxoff) {
-                       curoff = maxoff;
-                       continue;
-               }
-
                totalport = brdnr * STL_MAXPORTS;
-               for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
+               for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) {
                        panelp = brdp->panels[panelnr];
                        if (panelp == NULL)
                                continue;
 
-                       maxoff = curoff + (panelp->nrports * MAXLINE);
-                       if (off >= maxoff) {
-                               curoff = maxoff;
-                               totalport += panelp->nrports;
-                               continue;
-                       }
-
-                       for (portnr = 0; (portnr < panelp->nrports); portnr++,
+                       for (portnr = 0; portnr < panelp->nrports; portnr++,
                            totalport++) {
                                portp = panelp->ports[portnr];
                                if (portp == NULL)
                                        continue;
-                               if (off >= (curoff += MAXLINE))
-                                       continue;
-                               if ((pos - page + MAXLINE) > count)
-                                       goto stl_readdone;
-                               pos += stl_portinfo(portp, totalport, pos);
+                               stl_portinfo(m, portp, totalport);
                        }
                }
        }
+       return 0;
+}
 
-       *eof = 1;
-
-stl_readdone:
-       *start = page;
-       return (pos - page);
+static int stl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stl_proc_show, NULL);
 }
 
+static const struct file_operations stl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = stl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*****************************************************************************/
 
 /*
@@ -1640,7 +1495,7 @@ static irqreturn_t stl_intr(int irq, void *dev_id)
 {
        struct stlbrd *brdp = dev_id;
 
-       pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq);
+       pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, brdp->irq);
 
        return IRQ_RETVAL((* brdp->isr)(brdp));
 }
@@ -1677,15 +1532,14 @@ static int stl_eiointr(struct stlbrd *brdp)
 static int stl_echatintr(struct stlbrd *brdp)
 {
        struct stlpanel *panelp;
-       unsigned int    ioaddr;
-       int             bnknr;
+       unsigned int    ioaddr, bnknr;
        int             handled = 0;
 
        outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
 
        while (inb(brdp->iostatus) & ECH_INTRPEND) {
                handled = 1;
-               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+               for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
                        ioaddr = brdp->bnkstataddr[bnknr];
                        if (inb(ioaddr) & ECH_PNLINTRPEND) {
                                panelp = brdp->bnk2panel[bnknr];
@@ -1708,13 +1562,12 @@ static int stl_echatintr(struct stlbrd *brdp)
 static int stl_echmcaintr(struct stlbrd *brdp)
 {
        struct stlpanel *panelp;
-       unsigned int    ioaddr;
-       int             bnknr;
+       unsigned int    ioaddr, bnknr;
        int             handled = 0;
 
        while (inb(brdp->iostatus) & ECH_INTRPEND) {
                handled = 1;
-               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+               for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
                        ioaddr = brdp->bnkstataddr[bnknr];
                        if (inb(ioaddr) & ECH_PNLINTRPEND) {
                                panelp = brdp->bnk2panel[bnknr];
@@ -1734,13 +1587,12 @@ static int stl_echmcaintr(struct stlbrd *brdp)
 static int stl_echpciintr(struct stlbrd *brdp)
 {
        struct stlpanel *panelp;
-       unsigned int    ioaddr;
-       int             bnknr, recheck;
+       unsigned int    ioaddr, bnknr, recheck;
        int             handled = 0;
 
        while (1) {
                recheck = 0;
-               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+               for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
                        outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl);
                        ioaddr = brdp->bnkstataddr[bnknr];
                        if (inb(ioaddr) & ECH_PNLINTRPEND) {
@@ -1765,13 +1617,12 @@ static int stl_echpciintr(struct stlbrd *brdp)
 static int stl_echpci64intr(struct stlbrd *brdp)
 {
        struct stlpanel *panelp;
-       unsigned int    ioaddr;
-       int             bnknr;
+       unsigned int    ioaddr, bnknr;
        int             handled = 0;
 
        while (inb(brdp->ioctrl) & 0x1) {
                handled = 1;
-               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+               for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
                        ioaddr = brdp->bnkstataddr[bnknr];
                        if (inb(ioaddr) & ECH_PNLINTRPEND) {
                                panelp = brdp->bnk2panel[bnknr];
@@ -1786,51 +1637,14 @@ static int stl_echpci64intr(struct stlbrd *brdp)
 /*****************************************************************************/
 
 /*
- *     Service an off-level request for some channel.
- */
-static void stl_offintr(struct work_struct *work)
-{
-       struct stlport          *portp = container_of(work, struct stlport, tqueue);
-       struct tty_struct       *tty;
-       unsigned int            oldsigs;
-
-       pr_debug("stl_offintr(portp=%p)\n", portp);
-
-       if (portp == NULL)
-               return;
-
-       tty = portp->tty;
-       if (tty == NULL)
-               return;
-
-       lock_kernel();
-       if (test_bit(ASYI_TXLOW, &portp->istate)) {
-               tty_wakeup(tty);
-       }
-       if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
-               clear_bit(ASYI_DCDCHANGE, &portp->istate);
-               oldsigs = portp->sigs;
-               portp->sigs = stl_getsignals(portp);
-               if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
-                       wake_up_interruptible(&portp->open_wait);
-               if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
-                       if (portp->flags & ASYNC_CHECK_CD)
-                               tty_hangup(tty);        /* FIXME: module removal race here - AKPM */
-               }
-       }
-       unlock_kernel();
-}
-
-/*****************************************************************************/
-
-/*
  *     Initialize all the ports on a panel.
  */
 
 static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
 {
-       struct stlport  *portp;
-       int             chipmask, i;
+       struct stlport *portp;
+       unsigned int i;
+       int chipmask;
 
        pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp);
 
@@ -1840,14 +1654,15 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
  *     All UART's are initialized (if found!). Now go through and setup
  *     each ports data structures.
  */
-       for (i = 0; (i < panelp->nrports); i++) {
+       for (i = 0; i < panelp->nrports; i++) {
                portp = kzalloc(sizeof(struct stlport), GFP_KERNEL);
                if (!portp) {
                        printk("STALLION: failed to allocate memory "
                                "(size=%Zd)\n", sizeof(struct stlport));
                        break;
                }
-
+               tty_port_init(&portp->port);
+               portp->port.ops = &stl_port_ops;
                portp->magic = STL_PORTMAGIC;
                portp->portnr = i;
                portp->brdnr = panelp->brdnr;
@@ -1857,9 +1672,8 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                portp->baud_base = STL_BAUDBASE;
                portp->close_delay = STL_CLOSEDELAY;
                portp->closing_wait = 30 * HZ;
-               INIT_WORK(&portp->tqueue, stl_offintr);
-               init_waitqueue_head(&portp->open_wait);
-               init_waitqueue_head(&portp->close_wait);
+               init_waitqueue_head(&portp->port.open_wait);
+               init_waitqueue_head(&portp->port.close_wait);
                portp->stats.brd = portp->brdnr;
                portp->stats.panel = portp->panelnr;
                portp->stats.port = portp->portnr;
@@ -1867,7 +1681,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
                stl_portinit(brdp, panelp, portp);
        }
 
-       return(0);
+       return 0;
 }
 
 static void stl_cleanup_panels(struct stlbrd *brdp)
@@ -1875,6 +1689,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
        struct stlpanel *panelp;
        struct stlport *portp;
        unsigned int j, k;
+       struct tty_struct *tty;
 
        for (j = 0; j < STL_MAXPANELS; j++) {
                panelp = brdp->panels[j];
@@ -1884,8 +1699,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
                        portp = panelp->ports[k];
                        if (portp == NULL)
                                continue;
-                       if (portp->tty != NULL)
-                               stl_hangup(portp->tty);
+                       tty = tty_port_tty_get(&portp->port);
+                       if (tty != NULL) {
+                               stl_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                        kfree(portp->tx.buf);
                        kfree(portp);
                }
@@ -2055,8 +1873,8 @@ err:
 static int __devinit stl_initech(struct stlbrd *brdp)
 {
        struct stlpanel *panelp;
-       unsigned int    status, nxtid, ioaddr, conflict;
-       int             panelnr, banknr, i, retval;
+       unsigned int    status, nxtid, ioaddr, conflict, panelnr, banknr, i;
+       int             retval;
        char            *name;
 
        pr_debug("stl_initech(brdp=%p)\n", brdp);
@@ -2092,7 +1910,7 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                outb((status | ECH_BRDRESET), brdp->ioaddr1);
                brdp->ioctrlval = ECH_INTENABLE |
                        ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
-               for (i = 0; (i < 10); i++)
+               for (i = 0; i < 10; i++)
                        outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
                brdp->iosize1 = 2;
                brdp->iosize2 = 32;
@@ -2180,18 +1998,19 @@ static int __devinit stl_initech(struct stlbrd *brdp)
        panelnr = 0;
        nxtid = 0;
 
-       for (i = 0; (i < STL_MAXPANELS); i++) {
+       for (i = 0; i < STL_MAXPANELS; i++) {
                if (brdp->brdtype == BRD_ECHPCI) {
                        outb(nxtid, brdp->ioctrl);
                        ioaddr = brdp->ioaddr2;
                }
                status = inb(ioaddr + ECH_PNLSTATUS);
                if ((status & ECH_PNLIDMASK) != nxtid)
-                       goto err_fr;
+                       break;
                panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
                if (!panelp) {
                        printk("STALLION: failed to allocate memory "
                                "(size=%Zd)\n", sizeof(struct stlpanel));
+                       retval = -ENOMEM;
                        goto err_fr;
                }
                panelp->magic = STL_PANELMAGIC;
@@ -2213,9 +2032,8 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                                brdp->bnkpageaddr[banknr] = nxtid;
                                brdp->bnkstataddr[banknr++] = ioaddr + 4 +
                                        ECH_PNLSTATUS;
-                       } else {
+                       } else
                                panelp->nrports = 8;
-                       }
                } else {
                        panelp->uartp = &stl_cd1400uart;
                        panelp->isr = stl_cd1400echintr;
@@ -2239,8 +2057,10 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                brdp->nrports += panelp->nrports;
                brdp->panels[panelnr++] = panelp;
                if ((brdp->brdtype != BRD_ECHPCI) &&
-                   (ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
+                   (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) {
+                       retval = -EINVAL;
                        goto err_fr;
+               }
        }
 
        brdp->nrpanels = panelnr;
@@ -2311,7 +2131,7 @@ static int __devinit stl_brdinit(struct stlbrd *brdp)
                goto err_free;
        }
 
-       for (i = 0; (i < STL_MAXPANELS); i++)
+       for (i = 0; i < STL_MAXPANELS; i++)
                if (brdp->panels[i] != NULL)
                        stl_initports(brdp, brdp->panels[i]);
 
@@ -2341,16 +2161,16 @@ err:
 
 static int __devinit stl_getbrdnr(void)
 {
-       int     i;
+       unsigned int i;
 
-       for (i = 0; (i < STL_MAXBRDS); i++) {
+       for (i = 0; i < STL_MAXBRDS; i++)
                if (stl_brds[i] == NULL) {
                        if (i >= stl_nrbrds)
                                stl_nrbrds = i + 1;
-                       return(i);
+                       return i;
                }
-       }
-       return(-1);
+
+       return -1;
 }
 
 /*****************************************************************************/
@@ -2364,15 +2184,12 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
                const struct pci_device_id *ent)
 {
        struct stlbrd *brdp;
-       unsigned int brdtype = ent->driver_data;
-       int retval = -ENODEV;
+       unsigned int i, brdtype = ent->driver_data;
+       int brdnr, retval = -ENODEV;
 
        if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
                goto err;
 
-       dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
-                       pdev->vendor, pdev->device, pdev->class);
-
        retval = pci_enable_device(pdev);
        if (retval)
                goto err;
@@ -2382,13 +2199,15 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
                goto err;
        }
        mutex_lock(&stl_brdslock);
-       brdp->brdnr = stl_getbrdnr();
-       if (brdp->brdnr < 0) {
+       brdnr = stl_getbrdnr();
+       if (brdnr < 0) {
                dev_err(&pdev->dev, "too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
                mutex_unlock(&stl_brdslock);
+               retval = -ENODEV;
                goto err_fr;
        }
+       brdp->brdnr = (unsigned int)brdnr;
        stl_brds[brdp->brdnr] = brdp;
        mutex_unlock(&stl_brdslock);
 
@@ -2424,6 +2243,10 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
 
        pci_set_drvdata(pdev, brdp);
 
+       for (i = 0; i < brdp->nrports; i++)
+               tty_register_device(stl_serial,
+                               brdp->brdnr * STL_MAXPORTS + i, &pdev->dev);
+
        return 0;
 err_null:
        stl_brds[brdp->brdnr] = NULL;
@@ -2436,6 +2259,7 @@ err:
 static void __devexit stl_pciremove(struct pci_dev *pdev)
 {
        struct stlbrd *brdp = pci_get_drvdata(pdev);
+       unsigned int i;
 
        free_irq(brdp->irq, brdp);
 
@@ -2445,6 +2269,10 @@ static void __devexit stl_pciremove(struct pci_dev *pdev)
        if (brdp->iosize2 > 0)
                release_region(brdp->ioaddr2, brdp->iosize2);
 
+       for (i = 0; i < brdp->nrports; i++)
+               tty_unregister_device(stl_serial,
+                               brdp->brdnr * STL_MAXPORTS + i);
+
        stl_brds[brdp->brdnr] = NULL;
        kfree(brdp);
 }
@@ -2464,17 +2292,18 @@ static struct pci_driver stl_pcidriver = {
 
 static int stl_getbrdstats(combrd_t __user *bp)
 {
+       combrd_t        stl_brdstats;
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
-       int             i;
+       unsigned int i;
 
        if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)))
                return -EFAULT;
        if (stl_brdstats.brd >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        brdp = stl_brds[stl_brdstats.brd];
        if (brdp == NULL)
-               return(-ENODEV);
+               return -ENODEV;
 
        memset(&stl_brdstats, 0, sizeof(combrd_t));
        stl_brdstats.brd = brdp->brdnr;
@@ -2486,7 +2315,7 @@ static int stl_getbrdstats(combrd_t __user *bp)
        stl_brdstats.irq = brdp->irq;
        stl_brdstats.nrpanels = brdp->nrpanels;
        stl_brdstats.nrports = brdp->nrports;
-       for (i = 0; (i < brdp->nrpanels); i++) {
+       for (i = 0; i < brdp->nrpanels; i++) {
                panelp = brdp->panels[i];
                stl_brdstats.panels[i].panel = i;
                stl_brdstats.panels[i].hwid = panelp->hwid;
@@ -2507,19 +2336,19 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
 
-       if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
-               return(NULL);
+       if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+               return NULL;
        brdp = stl_brds[brdnr];
        if (brdp == NULL)
-               return(NULL);
-       if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
-               return(NULL);
+               return NULL;
+       if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels)
+               return NULL;
        panelp = brdp->panels[panelnr];
        if (panelp == NULL)
-               return(NULL);
-       if ((portnr < 0) || (portnr >= panelp->nrports))
-               return(NULL);
-       return(panelp->ports[portnr]);
+               return NULL;
+       if (portnr < 0 || (unsigned int)portnr >= panelp->nrports)
+               return NULL;
+       return panelp->ports[portnr];
 }
 
 /*****************************************************************************/
@@ -2530,8 +2359,9 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
  *     what port to get stats for (used through board control device).
  */
 
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
 {
+       comstats_t      stl_comstats;
        unsigned char   *head, *tail;
        unsigned long   flags;
 
@@ -2541,11 +2371,11 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
                portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
                        stl_comstats.port);
                if (portp == NULL)
-                       return(-ENODEV);
+                       return -ENODEV;
        }
 
        portp->stats.state = portp->istate;
-       portp->stats.flags = portp->flags;
+       portp->stats.flags = portp->port.flags;
        portp->stats.hwid = portp->hwid;
 
        portp->stats.ttystate = 0;
@@ -2556,25 +2386,23 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
        portp->stats.rxbuffered = 0;
 
        spin_lock_irqsave(&stallion_lock, flags);
-       if (portp->tty != NULL) {
-               if (portp->tty->driver_data == portp) {
-                       portp->stats.ttystate = portp->tty->flags;
-                       /* No longer available as a statistic */
-                       portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */
-                       if (portp->tty->termios != NULL) {
-                               portp->stats.cflags = portp->tty->termios->c_cflag;
-                               portp->stats.iflags = portp->tty->termios->c_iflag;
-                               portp->stats.oflags = portp->tty->termios->c_oflag;
-                               portp->stats.lflags = portp->tty->termios->c_lflag;
-                       }
+       if (tty != NULL && portp->port.tty == tty) {
+               portp->stats.ttystate = tty->flags;
+               /* No longer available as a statistic */
+               portp->stats.rxbuffered = 1; /*tty->flip.count; */
+               if (tty->termios != NULL) {
+                       portp->stats.cflags = tty->termios->c_cflag;
+                       portp->stats.iflags = tty->termios->c_iflag;
+                       portp->stats.oflags = tty->termios->c_oflag;
+                       portp->stats.lflags = tty->termios->c_lflag;
                }
        }
        spin_unlock_irqrestore(&stallion_lock, flags);
 
        head = portp->tx.head;
        tail = portp->tx.tail;
-       portp->stats.txbuffered = ((head >= tail) ? (head - tail) :
-               (STL_TXBUFSIZE - (tail - head)));
+       portp->stats.txbuffered = (head >= tail) ? (head - tail) :
+               (STL_TXBUFSIZE - (tail - head));
 
        portp->stats.signals = (unsigned long) stl_getsignals(portp);
 
@@ -2590,13 +2418,15 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
 
 static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp)
 {
+       comstats_t      stl_comstats;
+
        if (!portp) {
                if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t)))
                        return -EFAULT;
                portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
                        stl_comstats.port);
                if (portp == NULL)
-                       return(-ENODEV);
+                       return -ENODEV;
        }
 
        memset(&portp->stats, 0, sizeof(comstats_t));
@@ -2615,6 +2445,7 @@ static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp)
 
 static int stl_getportstruct(struct stlport __user *arg)
 {
+       struct stlport  stl_dummyport;
        struct stlport  *portp;
 
        if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport)))
@@ -2634,15 +2465,16 @@ static int stl_getportstruct(struct stlport __user *arg)
 
 static int stl_getbrdstruct(struct stlbrd __user *arg)
 {
+       struct stlbrd   stl_dummybrd;
        struct stlbrd   *brdp;
 
        if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd)))
                return -EFAULT;
-       if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS))
+       if (stl_dummybrd.brdnr >= STL_MAXBRDS)
                return -ENODEV;
        brdp = stl_brds[stl_dummybrd.brdnr];
        if (!brdp)
-               return(-ENODEV);
+               return -ENODEV;
        return copy_to_user(arg, brdp, sizeof(struct stlbrd)) ? -EFAULT : 0;
 }
 
@@ -2663,12 +2495,12 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
 
        brdnr = iminor(ip);
        if (brdnr >= STL_MAXBRDS)
-               return(-ENODEV);
+               return -ENODEV;
        rc = 0;
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               rc = stl_getportstats(NULL, argp);
+               rc = stl_getportstats(NULL, NULL, argp);
                break;
        case COM_CLRPORTSTATS:
                rc = stl_clrportstats(NULL, argp);
@@ -2687,7 +2519,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
                break;
        }
 
-       return(rc);
+       return rc;
 }
 
 static const struct tty_operations stl_ops = {
@@ -2709,9 +2541,14 @@ static const struct tty_operations stl_ops = {
        .break_ctl = stl_breakctl,
        .wait_until_sent = stl_waituntilsent,
        .send_xchar = stl_sendxchar,
-       .read_proc = stl_readproc,
        .tiocmget = stl_tiocmget,
        .tiocmset = stl_tiocmset,
+       .proc_fops = &stl_proc_fops,
+};
+
+static const struct tty_port_operations stl_port_ops = {
+       .carrier_raised = stl_carrier_raised,
+       .dtr_rts = stl_dtr_rts,
 };
 
 /*****************************************************************************/
@@ -2732,13 +2569,13 @@ static int stl_cd1400getreg(struct stlport *portp, int regnr)
 
 static void stl_cd1400setreg(struct stlport *portp, int regnr, int value)
 {
-       outb((regnr + portp->uartaddr), portp->ioaddr);
+       outb(regnr + portp->uartaddr, portp->ioaddr);
        outb(value, portp->ioaddr + EREG_DATA);
 }
 
 static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value)
 {
-       outb((regnr + portp->uartaddr), portp->ioaddr);
+       outb(regnr + portp->uartaddr, portp->ioaddr);
        if (inb(portp->ioaddr + EREG_DATA) != value) {
                outb(value, portp->ioaddr + EREG_DATA);
                return 1;
@@ -2771,13 +2608,12 @@ static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
  */
        chipmask = 0;
        nrchips = panelp->nrports / CD1400_PORTS;
-       for (i = 0; (i < nrchips); i++) {
+       for (i = 0; i < nrchips; i++) {
                if (brdp->brdtype == BRD_ECHPCI) {
                        outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
                        ioaddr = panelp->iobase;
-               } else {
+               } else
                        ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
-               }
                uartaddr = (i & 0x01) ? 0x080 : 0;
                outb((GFRCR + uartaddr), ioaddr);
                outb(0, (ioaddr + EREG_DATA));
@@ -2785,10 +2621,10 @@ static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
                outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
                outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
                outb((GFRCR + uartaddr), ioaddr);
-               for (j = 0; (j < CCR_MAXWAIT); j++) {
+               for (j = 0; j < CCR_MAXWAIT; j++)
                        if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
                                break;
-               }
+
                if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
                        printk("STALLION: cd1400 not responding, "
                                "brd=%d panel=%d chip=%d\n",
@@ -2846,11 +2682,9 @@ static void stl_cd1400ccrwait(struct stlport *portp)
 {
        int     i;
 
-       for (i = 0; (i < CCR_MAXWAIT); i++) {
-               if (stl_cd1400getreg(portp, CCR) == 0) {
+       for (i = 0; i < CCR_MAXWAIT; i++)
+               if (stl_cd1400getreg(portp, CCR) == 0)
                        return;
-               }
-       }
 
        printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n",
                portp->portnr, portp->panelnr, portp->brdnr);
@@ -2971,23 +2805,23 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp)
        }
        baudrate = stl_baudrates[baudrate];
        if ((tiosp->c_cflag & CBAUD) == B38400) {
-               if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+               if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
                        baudrate = 57600;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
                        baudrate = 115200;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
                        baudrate = 230400;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
                        baudrate = 460800;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
                        baudrate = (portp->baud_base / portp->custom_divisor);
        }
        if (baudrate > STL_CD1400MAXBAUD)
                baudrate = STL_CD1400MAXBAUD;
 
        if (baudrate > 0) {
-               for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
-                       clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate);
+               for (clk = 0; clk < CD1400_NUMCLKS; clk++) {
+                       clkdiv = (portp->clk / stl_cd1400clkdivs[clk]) / baudrate;
                        if (clkdiv < 0x100)
                                break;
                }
@@ -3001,10 +2835,9 @@ static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp)
                mcor1 |= MCOR1_DCD;
                mcor2 |= MCOR2_DCD;
                sreron |= SRER_MODEM;
-               portp->flags |= ASYNC_CHECK_CD;
-       } else {
-               portp->flags &= ~ASYNC_CHECK_CD;
-       }
+               portp->port.flags |= ASYNC_CHECK_CD;
+       } else
+               portp->port.flags &= ~ASYNC_CHECK_CD;
 
 /*
  *     Setup cd1400 enhanced modes if we can. In particular we want to
@@ -3275,7 +3108,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3320,6 +3153,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3337,7 +3171,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -3357,6 +3191,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -3510,6 +3345,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        int             len, stlen;
        char            *head, *tail;
        unsigned char   ioack, srer;
+       struct tty_struct *tty;
 
        pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
 
@@ -3536,7 +3372,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               schedule_work(&portp->tqueue);
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -3552,7 +3392,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
        } else {
                len = min(len, CD1400_TXFIFOSIZE);
                portp->stats.txtotal += len;
-               stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               stlen = min_t(unsigned int, len,
+                               (portp->tx.buf + STL_TXBUFSIZE) - tail);
                outb((TDR + portp->uartaddr), ioaddr);
                outsb((ioaddr + EREG_DATA), tail, stlen);
                len -= stlen;
@@ -3599,13 +3440,13 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                return;
        }
        portp = panelp->ports[(ioack >> 3)];
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
 
        if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
                outb((RDCR + portp->uartaddr), ioaddr);
                len = inb(ioaddr + EREG_DATA);
                if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
-                       len = min(len, sizeof(stl_unwanted));
+                       len = min_t(unsigned int, len, sizeof(stl_unwanted));
                        outb((RDSR + portp->uartaddr), ioaddr);
                        insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
@@ -3644,31 +3485,31 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                        if (portp->rxmarkmsk & status) {
                                if (status & ST_BREAK) {
                                        status = TTY_BREAK;
-                                       if (portp->flags & ASYNC_SAK) {
+                                       if (portp->port.flags & ASYNC_SAK) {
                                                do_SAK(tty);
                                                BRDENABLE(portp->brdnr, portp->pagenr);
                                        }
-                               } else if (status & ST_PARITY) {
+                               } else if (status & ST_PARITY)
                                        status = TTY_PARITY;
-                               } else if (status & ST_FRAMING) {
+                               else if (status & ST_FRAMING)
                                        status = TTY_FRAME;
-                               } else if(status & ST_OVERRUN) {
+                               else if(status & ST_OVERRUN)
                                        status = TTY_OVERRUN;
-                               } else {
+                               else
                                        status = 0;
-                               }
-                       } else {
+                       } else
                                status = 0;
-                       }
                        tty_insert_flip_char(tty, ch, status);
                        tty_schedule_flip(tty);
                }
        } else {
                printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+               tty_kref_put(tty);
                return;
        }
 
 stl_rxalldone:
+       tty_kref_put(tty);
        outb((EOSRR + portp->uartaddr), ioaddr);
        outb(0, (ioaddr + EREG_DATA));
 }
@@ -3700,8 +3541,7 @@ static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr)
        outb((MISR + portp->uartaddr), ioaddr);
        misr = inb(ioaddr + EREG_DATA);
        if (misr & MISR_DCD) {
-               set_bit(ASYI_DCDCHANGE, &portp->istate);
-               schedule_work(&portp->tqueue);
+               stl_cd_change(portp);
                portp->stats.modem++;
        }
 
@@ -3786,7 +3626,7 @@ static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
        if (brdp->brdtype == BRD_ECHPCI)
                outb(panelp->pagenr, brdp->ioctrl);
 
-       for (i = 0; (i < nrchips); i++) {
+       for (i = 0; i < nrchips; i++) {
                ioaddr = panelp->iobase + (i * 4); 
                outb(SCCR, (ioaddr + XP_ADDR));
                outb(CR_RESETALL, (ioaddr + XP_DATA));
@@ -3906,9 +3746,8 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp)
                        mr1 |= (MR1_PARENB | MR1_PARODD);
                else
                        mr1 |= (MR1_PARENB | MR1_PAREVEN);
-       } else {
+       } else
                mr1 |= MR1_PARNONE;
-       }
 
        mr1 |= MR1_ERRBLOCK;
 
@@ -3934,36 +3773,34 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp)
        }
        baudrate = stl_baudrates[baudrate];
        if ((tiosp->c_cflag & CBAUD) == B38400) {
-               if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+               if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
                        baudrate = 57600;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
                        baudrate = 115200;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
                        baudrate = 230400;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
                        baudrate = 460800;
-               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+               else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
                        baudrate = (portp->baud_base / portp->custom_divisor);
        }
        if (baudrate > STL_SC26198MAXBAUD)
                baudrate = STL_SC26198MAXBAUD;
 
-       if (baudrate > 0) {
-               for (clk = 0; (clk < SC26198_NRBAUDS); clk++) {
+       if (baudrate > 0)
+               for (clk = 0; clk < SC26198_NRBAUDS; clk++)
                        if (baudrate <= sc26198_baudtable[clk])
                                break;
-               }
-       }
 
 /*
  *     Check what form of modem signaling is required and set it up.
  */
        if (tiosp->c_cflag & CLOCAL) {
-               portp->flags &= ~ASYNC_CHECK_CD;
+               portp->port.flags &= ~ASYNC_CHECK_CD;
        } else {
                iopr |= IOPR_DCDCOS;
                imron |= IR_IOPORT;
-               portp->flags |= ASYNC_CHECK_CD;
+               portp->port.flags |= ASYNC_CHECK_CD;
        }
 
 /*
@@ -3975,9 +3812,9 @@ static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp)
        if (tiosp->c_iflag & IXON) {
                mr0 |= MR0_SWFTX | MR0_SWFT;
                imron |= IR_XONXOFF;
-       } else {
+       } else
                imroff |= IR_XONXOFF;
-       }
+
        if (tiosp->c_iflag & IXOFF)
                mr0 |= MR0_SWFRX;
 
@@ -4188,9 +4025,9 @@ static void stl_sc26198sendbreak(struct stlport *portp, int len)
        if (len == 1) {
                stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
                portp->stats.txbreaks++;
-       } else {
+       } else
                stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
-       }
+
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
 }
@@ -4211,7 +4048,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4262,6 +4099,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
 
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4280,7 +4118,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
 
        if (portp == NULL)
                return;
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        if (tty == NULL)
                return;
 
@@ -4305,6 +4143,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
        }
        BRDDISABLE(portp->brdnr);
        spin_unlock_irqrestore(&brd_lock, flags);
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4374,7 +4213,7 @@ static void stl_sc26198wait(struct stlport *portp)
        if (portp == NULL)
                return;
 
-       for (i = 0; (i < 20); i++)
+       for (i = 0; i < 20; i++)
                stl_sc26198getglobreg(portp, TSTR);
 }
 
@@ -4444,6 +4283,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
 
 static void stl_sc26198txisr(struct stlport *portp)
 {
+       struct tty_struct *tty;
        unsigned int    ioaddr;
        unsigned char   mr0;
        int             len, stlen;
@@ -4458,7 +4298,11 @@ static void stl_sc26198txisr(struct stlport *portp)
        if ((len == 0) || ((len < STL_TXBUFLOW) &&
            (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
                set_bit(ASYI_TXLOW, &portp->istate);
-               schedule_work(&portp->tqueue); 
+               tty = tty_port_tty_get(&portp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
        }
 
        if (len == 0) {
@@ -4476,7 +4320,8 @@ static void stl_sc26198txisr(struct stlport *portp)
        } else {
                len = min(len, SC26198_TXFIFOSIZE);
                portp->stats.txtotal += len;
-               stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               stlen = min_t(unsigned int, len,
+                               (portp->tx.buf + STL_TXBUFSIZE) - tail);
                outb(GTXFIFO, (ioaddr + XP_ADDR));
                outsb((ioaddr + XP_DATA), tail, stlen);
                len -= stlen;
@@ -4510,14 +4355,14 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
 
        pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
 
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
        outb(GIBCR, (ioaddr + XP_ADDR));
        len = inb(ioaddr + XP_DATA) + 1;
 
        if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
                if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
-                       len = min(len, sizeof(stl_unwanted));
+                       len = min_t(unsigned int, len, sizeof(stl_unwanted));
                        outb(GRXFIFO, (ioaddr + XP_ADDR));
                        insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
                        portp->stats.rxlost += len;
@@ -4549,6 +4394,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
                        stl_sc26198txunflow(portp, tty);
                }
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4562,7 +4408,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
        struct tty_struct       *tty;
        unsigned int            ioaddr;
 
-       tty = portp->tty;
+       tty = tty_port_tty_get(&portp->port);
        ioaddr = portp->ioaddr;
 
        if (status & SR_RXPARITY)
@@ -4579,22 +4425,20 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
                if (portp->rxmarkmsk & status) {
                        if (status & SR_RXBREAK) {
                                status = TTY_BREAK;
-                               if (portp->flags & ASYNC_SAK) {
+                               if (portp->port.flags & ASYNC_SAK) {
                                        do_SAK(tty);
                                        BRDENABLE(portp->brdnr, portp->pagenr);
                                }
-                       } else if (status & SR_RXPARITY) {
+                       } else if (status & SR_RXPARITY)
                                status = TTY_PARITY;
-                       } else if (status & SR_RXFRAMING) {
+                       else if (status & SR_RXFRAMING)
                                status = TTY_FRAME;
-                       } else if(status & SR_RXOVERRUN) {
+                       else if(status & SR_RXOVERRUN)
                                status = TTY_OVERRUN;
-                       } else {
+                       else
                                status = 0;
-                       }
-               } else {
+               } else
                        status = 0;
-               }
 
                tty_insert_flip_char(tty, ch, status);
                tty_schedule_flip(tty);
@@ -4602,6 +4446,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
                if (status == 0)
                        portp->stats.rxtotal++;
        }
+       tty_kref_put(tty);
 }
 
 /*****************************************************************************/
@@ -4660,8 +4505,7 @@ static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack)
        case CIR_SUBCOS:
                ipr = stl_sc26198getreg(portp, IPR);
                if (ipr & IPR_DCDCHANGE) {
-                       set_bit(ASYI_DCDCHANGE, &portp->istate);
-                       schedule_work(&portp->tqueue); 
+                       stl_cd_change(portp);
                        portp->stats.modem++;
                }
                break;
@@ -4714,7 +4558,7 @@ static int __init stallion_module_init(void)
 {
        struct stlbrd   *brdp;
        struct stlconf  conf;
-       unsigned int i;
+       unsigned int i, j;
        int retval;
 
        printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
@@ -4722,6 +4566,29 @@ static int __init stallion_module_init(void)
        spin_lock_init(&stallion_lock);
        spin_lock_init(&brd_lock);
 
+       stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+       if (!stl_serial) {
+               retval = -ENOMEM;
+               goto err;
+       }
+
+       stl_serial->owner = THIS_MODULE;
+       stl_serial->driver_name = stl_drvname;
+       stl_serial->name = "ttyE";
+       stl_serial->major = STL_SERIALMAJOR;
+       stl_serial->minor_start = 0;
+       stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
+       stl_serial->subtype = SERIAL_TYPE_NORMAL;
+       stl_serial->init_termios = stl_deftermios;
+       stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       tty_set_operations(stl_serial, &stl_ops);
+
+       retval = tty_register_driver(stl_serial);
+       if (retval) {
+               printk("STALLION: failed to register serial driver\n");
+               goto err_frtty;
+       }
+
 /*
  *     Find any dynamically supported boards. That is via module load
  *     line options.
@@ -4738,23 +4605,23 @@ static int __init stallion_module_init(void)
                brdp->ioaddr2 = conf.ioaddr2;
                brdp->irq = conf.irq;
                brdp->irqtype = conf.irqtype;
-               if (stl_brdinit(brdp))
+               stl_brds[brdp->brdnr] = brdp;
+               if (stl_brdinit(brdp)) {
+                       stl_brds[brdp->brdnr] = NULL;
                        kfree(brdp);
-               else {
-                       stl_brds[brdp->brdnr] = brdp;
+               } else {
+                       for (j = 0; j < brdp->nrports; j++)
+                               tty_register_device(stl_serial,
+                                       brdp->brdnr * STL_MAXPORTS + j, NULL);
                        stl_nrbrds = i + 1;
                }
        }
 
        /* this has to be _after_ isa finding because of locking */
        retval = pci_register_driver(&stl_pcidriver);
-       if (retval && stl_nrbrds == 0)
-               goto err;
-
-       stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
-       if (!stl_serial) {
-               retval = -ENOMEM;
-               goto err_pcidr;
+       if (retval && stl_nrbrds == 0) {
+               printk(KERN_ERR "STALLION: can't register pci driver\n");
+               goto err_unrtty;
        }
 
 /*
@@ -4765,50 +4632,25 @@ static int __init stallion_module_init(void)
                printk("STALLION: failed to register serial board device\n");
 
        stallion_class = class_create(THIS_MODULE, "staliomem");
-       if (IS_ERR(stallion_class)) {
-               retval = PTR_ERR(stallion_class);
-               goto err_reg;
-       }
+       if (IS_ERR(stallion_class))
+               printk("STALLION: failed to create class\n");
        for (i = 0; i < 4; i++)
-               class_device_create(stallion_class, NULL,
-                                   MKDEV(STL_SIOMEMMAJOR, i), NULL,
-                                   "staliomem%d", i);
-
-       stl_serial->owner = THIS_MODULE;
-       stl_serial->driver_name = stl_drvname;
-       stl_serial->name = "ttyE";
-       stl_serial->major = STL_SERIALMAJOR;
-       stl_serial->minor_start = 0;
-       stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
-       stl_serial->subtype = SERIAL_TYPE_NORMAL;
-       stl_serial->init_termios = stl_deftermios;
-       stl_serial->flags = TTY_DRIVER_REAL_RAW;
-       tty_set_operations(stl_serial, &stl_ops);
-
-       retval = tty_register_driver(stl_serial);
-       if (retval) {
-               printk("STALLION: failed to register serial driver\n");
-               goto err_clsdev;
-       }
+               device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+                             NULL, "staliomem%d", i);
 
        return 0;
-err_clsdev:
-       for (i = 0; i < 4; i++)
-               class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       class_destroy(stallion_class);
-err_reg:
-       unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+err_unrtty:
+       tty_unregister_driver(stl_serial);
+err_frtty:
        put_tty_driver(stl_serial);
-err_pcidr:
-       pci_unregister_driver(&stl_pcidriver);
-       stl_free_isabrds();
 err:
        return retval;
 }
 
 static void __exit stallion_module_exit(void)
 {
-       int             i;
+       struct stlbrd *brdp;
+       unsigned int i, j;
 
        pr_debug("cleanup_module()\n");
 
@@ -4821,19 +4663,25 @@ static void __exit stallion_module_exit(void)
  *     a hangup on every open port - to try to flush out any processes
  *     hanging onto ports.
  */
-       tty_unregister_driver(stl_serial);
-       put_tty_driver(stl_serial);
+       for (i = 0; i < stl_nrbrds; i++) {
+               if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+                       continue;
+               for (j = 0; j < brdp->nrports; j++)
+                       tty_unregister_device(stl_serial,
+                               brdp->brdnr * STL_MAXPORTS + j);
+       }
 
        for (i = 0; i < 4; i++)
-               class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-               printk("STALLION: failed to un-register serial memory device, "
-                       "errno=%d\n", -i);
+               device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+       unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
        class_destroy(stallion_class);
 
        pci_unregister_driver(&stl_pcidriver);
 
        stl_free_isabrds();
+
+       tty_unregister_driver(stl_serial);
+       put_tty_driver(stl_serial);
 }
 
 module_init(stallion_module_init);