Merge commit 'v2.6.26-rc8' into x86/xen
[safe/jmp/linux-2.6] / drivers / char / stallion.c
index 2db2e9f..d17be10 100644 (file)
@@ -63,7 +63,7 @@
 #define        BRD_EASYIOPCI   28
 
 struct stlconf {
-       int             brdtype;
+       unsigned int    brdtype;
        int             ioaddr1;
        int             ioaddr2;
        unsigned long   memaddr;
@@ -121,15 +121,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];
@@ -154,8 +145,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 +190,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];
@@ -619,6 +609,23 @@ 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;
+
+       if (!portp->tty)
+               return;
+
+       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(portp->tty);
+}
+
 /*
  *     Check for any arguments passed in on the module load command line.
  */
@@ -632,7 +639,7 @@ 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);
 
@@ -694,8 +701,8 @@ 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;
+       unsigned int    minordev, brdnr, panelnr;
+       int             portnr, rc;
 
        pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
 
@@ -868,6 +875,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;
@@ -875,6 +883,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
                if (time_after_eq(jiffies, tend))
                        break;
        }
+       unlock_kernel();
 }
 
 /*****************************************************************************/
@@ -1266,18 +1275,9 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
 
        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;
@@ -1301,7 +1301,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                rc = -ENOIOCTLCMD;
                break;
        }
-
+       unlock_kernel();
        return rc;
 }
 
@@ -1556,8 +1556,8 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof
        struct stlbrd   *brdp;
        struct stlpanel *panelp;
        struct stlport  *portp;
-       int             brdnr, panelnr, portnr, totalport;
-       int             curoff, maxoff;
+       unsigned int    brdnr, panelnr, portnr;
+       int             totalport, curoff, maxoff;
        char            *pos;
 
        pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
@@ -1638,7 +1638,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));
 }
@@ -1675,8 +1675,7 @@ 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);
@@ -1706,8 +1705,7 @@ 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) {
@@ -1732,8 +1730,7 @@ 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) {
@@ -1763,8 +1760,7 @@ 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) {
@@ -1784,50 +1780,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);
 
@@ -1854,7 +1814,6 @@ 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);
                portp->stats.brd = portp->brdnr;
@@ -2052,8 +2011,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);
@@ -2184,11 +2143,12 @@ static int __devinit stl_initech(struct stlbrd *brdp)
                }
                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;
@@ -2235,8 +2195,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;
@@ -2337,7 +2299,7 @@ err:
 
 static int __devinit stl_getbrdnr(void)
 {
-       int     i;
+       unsigned int i;
 
        for (i = 0; i < STL_MAXBRDS; i++)
                if (stl_brds[i] == NULL) {
@@ -2360,15 +2322,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;
@@ -2378,13 +2337,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);
 
@@ -2420,6 +2381,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;
@@ -2432,6 +2397,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);
 
@@ -2441,6 +2407,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);
 }
@@ -2460,9 +2430,10 @@ 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;
@@ -2508,12 +2479,12 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
        brdp = stl_brds[brdnr];
        if (brdp == NULL)
                return NULL;
-       if (panelnr < 0 || panelnr >= brdp->nrpanels)
+       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)
+       if (portnr < 0 || (unsigned int)portnr >= panelp->nrports)
                return NULL;
        return panelp->ports[portnr];
 }
@@ -2528,6 +2499,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
 
 static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
 {
+       comstats_t      stl_comstats;
        unsigned char   *head, *tail;
        unsigned long   flags;
 
@@ -2585,6 +2557,8 @@ 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;
@@ -2610,6 +2584,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)))
@@ -2629,11 +2604,12 @@ 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)
@@ -3527,7 +3503,8 @@ 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);
+               if (portp->tty)
+                       tty_wakeup(portp->tty);
        }
 
        if (len == 0) {
@@ -3543,7 +3520,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;
@@ -3596,7 +3574,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
                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;
@@ -3689,8 +3667,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++;
        }
 
@@ -4444,7 +4421,8 @@ 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); 
+               if (portp->tty)
+                       tty_wakeup(portp->tty);
        }
 
        if (len == 0) {
@@ -4462,7 +4440,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;
@@ -4503,7 +4482,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
 
        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;
@@ -4644,8 +4623,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;
@@ -4698,7 +4676,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);
@@ -4706,6 +4684,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.
@@ -4722,23 +4723,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;
        }
 
 /*
@@ -4749,50 +4750,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),
+                             "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");
 
@@ -4805,19 +4781,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);