Virtio console driver
[safe/jmp/linux-2.6] / drivers / char / istallion.c
index 75b1e0c..1f27be1 100644 (file)
@@ -110,7 +110,7 @@ struct stlconf {
        int             irqtype;
 };
 
-static int     stli_nrbrds;
+static unsigned int stli_nrbrds;
 
 /* stli_lock must NOT be taken holding brd_lock */
 static spinlock_t stli_lock;   /* TTY logic lock */
@@ -186,11 +186,10 @@ static struct ktermios            stli_deftermios = {
 static comstats_t      stli_comstats;
 static combrd_t                stli_brdstats;
 static struct asystats stli_cdkstats;
-static struct stlibrd  stli_dummybrd;
-static struct stliport stli_dummyport;
 
 /*****************************************************************************/
 
+static DEFINE_MUTEX(stli_brdslock);
 static struct stlibrd  *stli_brds[STL_MAXBRDS];
 
 static int             stli_shared;
@@ -203,6 +202,7 @@ static int          stli_shared;
  */
 #define        BST_FOUND       0x1
 #define        BST_STARTED     0x2
+#define        BST_PROBED      0x4
 
 /*
  *     Define the set of port state flags. These are marked for internal
@@ -357,6 +357,7 @@ MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,memaddr]");
 module_param_array(board3, charp, NULL, 0);
 MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
 
+#if STLI_EISAPROBE != 0
 /*
  *     Set up a default memory address table for EISA board probing.
  *     The default addresses are all bellow 1Mbyte, which has to be the
@@ -374,6 +375,7 @@ static unsigned long        stli_eisamemprobeaddrs[] = {
 };
 
 static int     stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
+#endif
 
 /*
  *     Define the Stallion PCI vendor and device IDs.
@@ -593,7 +595,6 @@ static struct pci_driver stli_pcidriver;
  */
 
 static int     stli_parsebrd(struct stlconf *confp, char **argp);
-static int     stli_init(void);
 static int     stli_open(struct tty_struct *tty, struct file *filp);
 static void    stli_close(struct tty_struct *tty, struct file *filp);
 static int     stli_write(struct tty_struct *tty, const unsigned char *buf, int count);
@@ -682,11 +683,13 @@ static void       stli_stalinit(struct stlibrd *brdp);
 static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
 static void    stli_stalreset(struct stlibrd *brdp);
 
-static struct stliport *stli_getport(int brdnr, int panelnr, int portnr);
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr);
 
 static int     stli_initecp(struct stlibrd *brdp);
 static int     stli_initonb(struct stlibrd *brdp);
+#if STLI_EISAPROBE != 0
 static int     stli_eisamemprobe(struct stlibrd *brdp);
+#endif
 static int     stli_initports(struct stlibrd *brdp);
 
 /*****************************************************************************/
@@ -740,69 +743,6 @@ static void stli_cleanup_ports(struct stlibrd *brdp)
        }
 }
 
-/*
- *     Loadable module initialization stuff.
- */
-
-static int __init istallion_module_init(void)
-{
-       stli_init();
-       return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit istallion_module_exit(void)
-{
-       struct stlibrd  *brdp;
-       int             i;
-
-       printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
-               stli_drvversion);
-
-       pci_unregister_driver(&stli_pcidriver);
-       /*
-        *      Free up all allocated resources used by the ports. This includes
-        *      memory and interrupts.
-        */
-       if (stli_timeron) {
-               stli_timeron = 0;
-               del_timer_sync(&stli_timerlist);
-       }
-
-       i = tty_unregister_driver(stli_serial);
-       if (i) {
-               printk("STALLION: failed to un-register tty driver, "
-                       "errno=%d\n", -i);
-               return;
-       }
-       put_tty_driver(stli_serial);
-       for (i = 0; i < 4; i++)
-               class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-       class_destroy(istallion_class);
-       if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-               printk("STALLION: failed to un-register serial memory device, "
-                       "errno=%d\n", -i);
-
-       kfree(stli_txcookbuf);
-
-       for (i = 0; (i < stli_nrbrds); i++) {
-               if ((brdp = stli_brds[i]) == NULL)
-                       continue;
-
-               stli_cleanup_ports(brdp);
-
-               iounmap(brdp->membase);
-               if (brdp->iosize > 0)
-                       release_region(brdp->iobase, brdp->iosize);
-               kfree(brdp);
-               stli_brds[i] = NULL;
-       }
-}
-
-module_init(istallion_module_init);
-module_exit(istallion_module_exit);
-
 /*****************************************************************************/
 
 /*
@@ -811,8 +751,8 @@ module_exit(istallion_module_exit);
 
 static int stli_parsebrd(struct stlconf *confp, char **argp)
 {
+       unsigned int i;
        char *sp;
-       int i;
 
        if (argp[0] == NULL || *argp[0] == 0)
                return 0;
@@ -843,8 +783,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
 {
        struct stlibrd *brdp;
        struct stliport *portp;
-       unsigned int minordev;
-       int brdnr, portnr, rc;
+       unsigned int minordev, brdnr, portnr;
+       int rc;
 
        minordev = tty->index;
        brdnr = MINOR2BRD(minordev);
@@ -856,7 +796,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if ((brdp->state & BST_STARTED) == 0)
                return -ENODEV;
        portnr = MINOR2PORT(minordev);
-       if ((portnr < 0) || (portnr > brdp->nrports))
+       if (portnr > brdp->nrports)
                return -ENODEV;
 
        portp = brdp->ports[portnr];
@@ -1232,7 +1172,7 @@ static int stli_setport(struct stliport *portp)
                return -ENODEV;
        if (portp->tty == NULL)
                return -ENODEV;
-       if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return -ENODEV;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1324,7 +1264,7 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1446,7 +1386,7 @@ static void stli_flushchars(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1524,7 +1464,7 @@ static int stli_writeroom(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1572,7 +1512,7 @@ static int stli_charsinbuffer(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == NULL)
                return 0;
-       if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1670,7 +1610,7 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file)
 
        if (portp == NULL)
                return -ENODEV;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1694,7 +1634,7 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
 
        if (portp == NULL)
                return -ENODEV;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1728,7 +1668,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
        portp = tty->driver_data;
        if (portp == NULL)
                return -ENODEV;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return 0;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1806,16 +1746,13 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
                return;
 
        tiosp = tty->termios;
-       if ((tiosp->c_cflag == old->c_cflag) &&
-           (tiosp->c_iflag == old->c_iflag))
-               return;
 
        stli_mkasyport(portp, &aport, tiosp);
        stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
@@ -1921,7 +1858,7 @@ static void stli_hangup(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -1974,7 +1911,7 @@ static void stli_flushbuffer(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -2011,7 +1948,7 @@ static void stli_breakctl(struct tty_struct *tty, int state)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -2058,7 +1995,7 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
        portp = tty->driver_data;
        if (portp == NULL)
                return;
-       if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+       if (portp->brdnr >= stli_nrbrds)
                return;
        brdp = stli_brds[portp->brdnr];
        if (brdp == NULL)
@@ -2151,7 +2088,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
 {
        struct stlibrd *brdp;
        struct stliport *portp;
-       int brdnr, portnr, totalport;
+       unsigned int brdnr, portnr, totalport;
        int curoff, maxoff;
        char *pos;
 
@@ -2226,14 +2163,10 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
        cdkhdr_t __iomem *hdrp;
        cdkctrl_t __iomem *cp;
        unsigned char __iomem *bits;
-       unsigned long flags;
-
-       spin_lock_irqsave(&brd_lock, flags);
 
        if (test_bit(ST_CMDING, &portp->state)) {
                printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
                                (int) cmd);
-               spin_unlock_irqrestore(&brd_lock, flags);
                return;
        }
 
@@ -2254,7 +2187,6 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
        writeb(readb(bits) | portp->portbit, bits);
        set_bit(ST_CMDING, &portp->state);
        EBRDDISABLE(brdp);
-       spin_unlock_irqrestore(&brd_lock, flags);
 }
 
 static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
@@ -2484,7 +2416,6 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
                        if (tty != NULL) {
                                tty_wakeup(tty);
                                EBRDENABLE(brdp);
-                               wake_up_interruptible(&tty->write_wait);
                        }
                }
 
@@ -2603,10 +2534,9 @@ static void stli_poll(unsigned long arg)
 {
        cdkhdr_t __iomem *hdrp;
        struct stlibrd *brdp;
-       int brdnr;
+       unsigned int brdnr;
 
-       stli_timerlist.expires = STLI_TIMEOUT;
-       add_timer(&stli_timerlist);
+       mod_timer(&stli_timerlist, STLI_TIMEOUT);
 
 /*
  *     Check each board and do any servicing required.
@@ -2787,7 +2717,7 @@ static long stli_mktiocm(unsigned long sigvalue)
 static int stli_initports(struct stlibrd *brdp)
 {
        struct stliport *portp;
-       int             i, panelnr, panelport;
+       unsigned int i, panelnr, panelport;
 
        for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
                portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
@@ -3273,19 +3203,20 @@ static int stli_initecp(struct stlibrd *brdp)
        cdkecpsig_t __iomem *sigsp;
        unsigned int status, nxtid;
        char *name;
-       int panelnr, nrports;
+       int retval, panelnr, nrports;
 
-       if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
-               return -EIO;
-       
-       if ((brdp->iobase == 0) || (brdp->memaddr == 0))
-       {
-               release_region(brdp->iobase, brdp->iosize);
-               return -ENODEV;
+       if ((brdp->iobase == 0) || (brdp->memaddr == 0)) {
+               retval = -ENODEV;
+               goto err;
        }
 
        brdp->iosize = ECP_IOSIZE;
 
+       if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+               retval = -EIO;
+               goto err;
+       }
+
 /*
  *     Based on the specific board type setup the common vars to access
  *     and enable shared memory. Set all board specific information now
@@ -3345,8 +3276,8 @@ static int stli_initecp(struct stlibrd *brdp)
                break;
 
        default:
-               release_region(brdp->iobase, brdp->iosize);
-               return -EINVAL;
+               retval = -EINVAL;
+               goto err_reg;
        }
 
 /*
@@ -3358,10 +3289,9 @@ static int stli_initecp(struct stlibrd *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == NULL)
-       {
-               release_region(brdp->iobase, brdp->iosize);
-               return -ENOMEM;
+       if (brdp->membase == NULL) {
+               retval = -ENOMEM;
+               goto err_reg;
        }
 
 /*
@@ -3374,12 +3304,9 @@ static int stli_initecp(struct stlibrd *brdp)
        memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
        EBRDDISABLE(brdp);
 
-       if (sig.magic != cpu_to_le32(ECP_MAGIC))
-       {
-               release_region(brdp->iobase, brdp->iosize);
-               iounmap(brdp->membase);
-               brdp->membase = NULL;
-               return -ENODEV;
+       if (sig.magic != cpu_to_le32(ECP_MAGIC)) {
+               retval = -ENODEV;
+               goto err_unmap;
        }
 
 /*
@@ -3404,6 +3331,13 @@ static int stli_initecp(struct stlibrd *brdp)
 
        brdp->state |= BST_FOUND;
        return 0;
+err_unmap:
+       iounmap(brdp->membase);
+       brdp->membase = NULL;
+err_reg:
+       release_region(brdp->iobase, brdp->iosize);
+err:
+       return retval;
 }
 
 /*****************************************************************************/
@@ -3418,18 +3352,22 @@ static int stli_initonb(struct stlibrd *brdp)
        cdkonbsig_t sig;
        cdkonbsig_t __iomem *sigsp;
        char *name;
-       int i;
+       int i, retval;
 
 /*
  *     Do a basic sanity check on the IO and memory addresses.
  */
-       if (brdp->iobase == 0 || brdp->memaddr == 0)
-               return -ENODEV;
+       if (brdp->iobase == 0 || brdp->memaddr == 0) {
+               retval = -ENODEV;
+               goto err;
+       }
 
        brdp->iosize = ONB_IOSIZE;
        
-       if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
-               return -EIO;
+       if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+               retval = -EIO;
+               goto err;
+       }
 
 /*
  *     Based on the specific board type setup the common vars to access
@@ -3495,8 +3433,8 @@ static int stli_initonb(struct stlibrd *brdp)
                break;
 
        default:
-               release_region(brdp->iobase, brdp->iosize);
-               return -EINVAL;
+               retval = -EINVAL;
+               goto err_reg;
        }
 
 /*
@@ -3508,10 +3446,9 @@ static int stli_initonb(struct stlibrd *brdp)
        EBRDINIT(brdp);
 
        brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
-       if (brdp->membase == NULL)
-       {
-               release_region(brdp->iobase, brdp->iosize);
-               return -ENOMEM;
+       if (brdp->membase == NULL) {
+               retval = -ENOMEM;
+               goto err_reg;
        }
 
 /*
@@ -3527,12 +3464,9 @@ static int stli_initonb(struct stlibrd *brdp)
        if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
            sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
            sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
-           sig.magic3 != cpu_to_le16(ONB_MAGIC3))
-       {
-               release_region(brdp->iobase, brdp->iosize);
-               iounmap(brdp->membase);
-               brdp->membase = NULL;
-               return -ENODEV;
+           sig.magic3 != cpu_to_le16(ONB_MAGIC3)) {
+               retval = -ENODEV;
+               goto err_unmap;
        }
 
 /*
@@ -3554,6 +3488,13 @@ static int stli_initonb(struct stlibrd *brdp)
 
        brdp->state |= BST_FOUND;
        return 0;
+err_unmap:
+       iounmap(brdp->membase);
+       brdp->membase = NULL;
+err_reg:
+       release_region(brdp->iobase, brdp->iosize);
+err:
+       return retval;
 }
 
 /*****************************************************************************/
@@ -3570,8 +3511,9 @@ static int stli_startbrd(struct stlibrd *brdp)
        cdkmem_t __iomem *memp;
        cdkasy_t __iomem *ap;
        unsigned long flags;
+       unsigned int portnr, nrdevs, i;
        struct stliport *portp;
-       int portnr, nrdevs, i, rc = 0;
+       int rc = 0;
        u32 memoff;
 
        spin_lock_irqsave(&brd_lock, flags);
@@ -3658,8 +3600,7 @@ stli_donestartup:
 
        if (! stli_timeron) {
                stli_timeron++;
-               stli_timerlist.expires = STLI_TIMEOUT;
-               add_timer(&stli_timerlist);
+               mod_timer(&stli_timerlist, STLI_TIMEOUT);
        }
 
        return rc;
@@ -3673,35 +3614,30 @@ stli_donestartup:
 
 static int __devinit stli_brdinit(struct stlibrd *brdp)
 {
-       stli_brds[brdp->brdnr] = brdp;
+       int retval;
 
        switch (brdp->brdtype) {
        case BRD_ECP:
        case BRD_ECPE:
        case BRD_ECPMC:
        case BRD_ECPPCI:
-               stli_initecp(brdp);
+               retval = stli_initecp(brdp);
                break;
        case BRD_ONBOARD:
        case BRD_ONBOARDE:
        case BRD_ONBOARD2:
        case BRD_BRUMBY4:
        case BRD_STALLION:
-               stli_initonb(brdp);
+               retval = stli_initonb(brdp);
                break;
        default:
                printk(KERN_ERR "STALLION: board=%d is unknown board "
                                "type=%d\n", brdp->brdnr, brdp->brdtype);
-               return -ENODEV;
+               retval = -ENODEV;
        }
 
-       if ((brdp->state & BST_FOUND) == 0) {
-               printk(KERN_ERR "STALLION: %s board not found, board=%d "
-                               "io=%x mem=%x\n",
-                       stli_brdnames[brdp->brdtype], brdp->brdnr,
-                       brdp->iobase, (int) brdp->memaddr);
-               return -ENODEV;
-       }
+       if (retval)
+               return retval;
 
        stli_initports(brdp);
        printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
@@ -3711,6 +3647,7 @@ static int __devinit stli_brdinit(struct stlibrd *brdp)
        return 0;
 }
 
+#if STLI_EISAPROBE != 0
 /*****************************************************************************/
 
 /*
@@ -3804,10 +3741,11 @@ static int stli_eisamemprobe(struct stlibrd *brdp)
        }
        return 0;
 }
+#endif
 
 static int stli_getbrdnr(void)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < STL_MAXBRDS; i++) {
                if (!stli_brds[i]) {
@@ -3819,6 +3757,7 @@ static int stli_getbrdnr(void)
        return -1;
 }
 
+#if STLI_EISAPROBE != 0
 /*****************************************************************************/
 
 /*
@@ -3834,8 +3773,8 @@ static int stli_getbrdnr(void)
 static int stli_findeisabrds(void)
 {
        struct stlibrd *brdp;
-       unsigned int iobase, eid;
-       int i;
+       unsigned int iobase, eid, i;
+       int brdnr, found = 0;
 
 /*
  *     Firstly check if this is an EISA system.  If this is not an EISA system then
@@ -3873,9 +3812,11 @@ static int stli_findeisabrds(void)
  *             Allocate a board structure and initialize it.
  */
                if ((brdp = stli_allocbrd()) == NULL)
-                       return -ENOMEM;
-               if ((brdp->brdnr = stli_getbrdnr()) < 0)
-                       return -ENOMEM;
+                       return found ? : -ENOMEM;
+               brdnr = stli_getbrdnr();
+               if (brdnr < 0)
+                       return found ? : -ENOMEM;
+               brdp->brdnr = (unsigned int)brdnr;
                eid = inb(iobase + 0xc82);
                if (eid == ECP_EISAID)
                        brdp->brdtype = BRD_ECPE;
@@ -3887,11 +3828,24 @@ static int stli_findeisabrds(void)
                outb(0x1, (iobase + 0xc84));
                if (stli_eisamemprobe(brdp))
                        outb(0, (iobase + 0xc84));
-               stli_brdinit(brdp);
+               if (stli_brdinit(brdp) < 0) {
+                       kfree(brdp);
+                       continue;
+               }
+
+               stli_brds[brdp->brdnr] = brdp;
+               found++;
+
+               for (i = 0; i < brdp->nrports; i++)
+                       tty_register_device(stli_serial,
+                                       brdp->brdnr * STL_MAXPORTS + i, NULL);
        }
 
-       return 0;
+       return found;
 }
+#else
+static inline int stli_findeisabrds(void) { return 0; }
+#endif
 
 /*****************************************************************************/
 
@@ -3911,7 +3865,8 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev,
                const struct pci_device_id *ent)
 {
        struct stlibrd *brdp;
-       int retval = -EIO;
+       unsigned int i;
+       int brdnr, retval = -EIO;
 
        retval = pci_enable_device(pdev);
        if (retval)
@@ -3921,12 +3876,18 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev,
                retval = -ENOMEM;
                goto err;
        }
-       if ((brdp->brdnr = stli_getbrdnr()) < 0) { /* TODO: locking */
+       mutex_lock(&stli_brdslock);
+       brdnr = stli_getbrdnr();
+       if (brdnr < 0) {
                printk(KERN_INFO "STALLION: too many boards found, "
                        "maximum supported %d\n", STL_MAXBRDS);
+               mutex_unlock(&stli_brdslock);
                retval = -EIO;
                goto err_fr;
        }
+       brdp->brdnr = (unsigned int)brdnr;
+       stli_brds[brdp->brdnr] = brdp;
+       mutex_unlock(&stli_brdslock);
        brdp->brdtype = BRD_ECPPCI;
 /*
  *     We have all resources from the board, so lets setup the actual
@@ -3936,11 +3897,22 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev,
        brdp->memaddr = pci_resource_start(pdev, 2);
        retval = stli_brdinit(brdp);
        if (retval)
-               goto err_fr;
+               goto err_null;
 
+       brdp->state |= BST_PROBED;
        pci_set_drvdata(pdev, brdp);
 
+       EBRDENABLE(brdp);
+       brdp->enable = NULL;
+       brdp->disable = NULL;
+
+       for (i = 0; i < brdp->nrports; i++)
+               tty_register_device(stli_serial, brdp->brdnr * STL_MAXPORTS + i,
+                               &pdev->dev);
+
        return 0;
+err_null:
+       stli_brds[brdp->brdnr] = NULL;
 err_fr:
        kfree(brdp);
 err:
@@ -3998,7 +3970,8 @@ static int stli_initbrds(void)
 {
        struct stlibrd *brdp, *nxtbrdp;
        struct stlconf conf;
-       int i, j, retval;
+       unsigned int i, j, found = 0;
+       int retval;
 
        for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp);
                        stli_nrbrds++) {
@@ -4011,14 +3984,21 @@ static int stli_initbrds(void)
                brdp->brdtype = conf.brdtype;
                brdp->iobase = conf.ioaddr1;
                brdp->memaddr = conf.memaddr;
-               stli_brdinit(brdp);
+               if (stli_brdinit(brdp) < 0) {
+                       kfree(brdp);
+                       continue;
+               }
+               stli_brds[brdp->brdnr] = brdp;
+               found++;
+
+               for (i = 0; i < brdp->nrports; i++)
+                       tty_register_device(stli_serial,
+                                       brdp->brdnr * STL_MAXPORTS + i, NULL);
        }
 
-       if (STLI_EISAPROBE)
-               stli_findeisabrds();
-
-       retval = pci_register_driver(&stli_pcidriver);
-       /* TODO: check retval and do something */
+       retval = stli_findeisabrds();
+       if (retval > 0)
+               found += retval;
 
 /*
  *     All found boards are initialized. Now for a little optimization, if
@@ -4058,7 +4038,16 @@ static int stli_initbrds(void)
                }
        }
 
+       retval = pci_register_driver(&stli_pcidriver);
+       if (retval && found == 0) {
+               printk(KERN_ERR "Neither isa nor eisa cards found nor pci "
+                               "driver can be registered!\n");
+               goto err;
+       }
+
        return 0;
+err:
+       return retval;
 }
 
 /*****************************************************************************/
@@ -4074,7 +4063,8 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof
        unsigned long flags;
        void __iomem *memptr;
        struct stlibrd *brdp;
-       int brdnr, size, n;
+       unsigned int brdnr;
+       int size, n;
        void *p;
        loff_t off = *offp;
 
@@ -4138,7 +4128,8 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou
        void __iomem *memptr;
        struct stlibrd *brdp;
        char __user *chbuf;
-       int brdnr, size, n;
+       unsigned int brdnr;
+       int size, n;
        void *p;
        loff_t off = *offp;
 
@@ -4198,7 +4189,7 @@ out:
 static int stli_getbrdstats(combrd_t __user *bp)
 {
        struct stlibrd *brdp;
-       int i;
+       unsigned int i;
 
        if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
                return -EFAULT;
@@ -4234,19 +4225,20 @@ static int stli_getbrdstats(combrd_t __user *bp)
  *     Resolve the referenced port number into a port struct pointer.
  */
 
-static struct stliport *stli_getport(int brdnr, int panelnr, int portnr)
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
+               unsigned int portnr)
 {
        struct stlibrd *brdp;
-       int i;
+       unsigned int i;
 
-       if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+       if (brdnr >= STL_MAXBRDS)
                return NULL;
        brdp = stli_brds[brdnr];
        if (brdp == NULL)
                return NULL;
        for (i = 0; (i < panelnr); i++)
                portnr += brdp->panels[i];
-       if ((portnr < 0) || (portnr >= brdp->nrports))
+       if (portnr >= brdp->nrports)
                return NULL;
        return brdp->ports[portnr];
 }
@@ -4405,6 +4397,7 @@ static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp)
 
 static int stli_getportstruct(struct stliport __user *arg)
 {
+       struct stliport stli_dummyport;
        struct stliport *portp;
 
        if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport)))
@@ -4426,11 +4419,12 @@ static int stli_getportstruct(struct stliport __user *arg)
 
 static int stli_getbrdstruct(struct stlibrd __user *arg)
 {
+       struct stlibrd stli_dummybrd;
        struct stlibrd *brdp;
 
        if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd)))
                return -EFAULT;
-       if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS))
+       if (stli_dummybrd.brdnr >= STL_MAXBRDS)
                return -ENODEV;
        brdp = stli_brds[stli_dummybrd.brdnr];
        if (!brdp)
@@ -4549,46 +4543,53 @@ static const struct tty_operations stli_ops = {
 };
 
 /*****************************************************************************/
+/*
+ *     Loadable module initialization stuff.
+ */
 
-static int __init stli_init(void)
+static void istallion_cleanup_isa(void)
 {
-       int i;
+       struct stlibrd  *brdp;
+       unsigned int j;
+
+       for (j = 0; (j < stli_nrbrds); j++) {
+               if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
+                       continue;
+
+               stli_cleanup_ports(brdp);
+
+               iounmap(brdp->membase);
+               if (brdp->iosize > 0)
+                       release_region(brdp->iobase, brdp->iosize);
+               kfree(brdp);
+               stli_brds[j] = NULL;
+       }
+}
+
+static int __init istallion_module_init(void)
+{
+       unsigned int i;
+       int retval;
+
        printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
        spin_lock_init(&stli_lock);
        spin_lock_init(&brd_lock);
 
-       stli_initbrds();
-
-       stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
-       if (!stli_serial)
-               return -ENOMEM;
-
-/*
- *     Allocate a temporary write buffer.
- */
        stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
-       if (!stli_txcookbuf)
+       if (!stli_txcookbuf) {
                printk(KERN_ERR "STALLION: failed to allocate memory "
                                "(size=%d)\n", STLI_TXBUFSIZE);
+               retval = -ENOMEM;
+               goto err;
+       }
 
-/*
- *     Set up a character driver for the shared memory region. We need this
- *     to down load the slave code image. Also it is a useful debugging tool.
- */
-       if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
-               printk(KERN_ERR "STALLION: failed to register serial memory "
-                               "device\n");
-
-       istallion_class = class_create(THIS_MODULE, "staliomem");
-       for (i = 0; i < 4; i++)
-               class_device_create(istallion_class, NULL,
-                               MKDEV(STL_SIOMEMMAJOR, i),
-                               NULL, "staliomem%d", i);
+       stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+       if (!stli_serial) {
+               retval = -ENOMEM;
+               goto err_free;
+       }
 
-/*
- *     Set up the tty driver structure and register us as a driver.
- */
        stli_serial->owner = THIS_MODULE;
        stli_serial->driver_name = stli_drvname;
        stli_serial->name = stli_serialname;
@@ -4597,15 +4598,77 @@ static int __init stli_init(void)
        stli_serial->type = TTY_DRIVER_TYPE_SERIAL;
        stli_serial->subtype = SERIAL_TYPE_NORMAL;
        stli_serial->init_termios = stli_deftermios;
-       stli_serial->flags = TTY_DRIVER_REAL_RAW;
+       stli_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(stli_serial, &stli_ops);
 
-       if (tty_register_driver(stli_serial)) {
-               put_tty_driver(stli_serial);
+       retval = tty_register_driver(stli_serial);
+       if (retval) {
                printk(KERN_ERR "STALLION: failed to register serial driver\n");
-               return -EBUSY;
+               goto err_ttyput;
        }
+
+       retval = stli_initbrds();
+       if (retval)
+               goto err_ttyunr;
+
+/*
+ *     Set up a character driver for the shared memory region. We need this
+ *     to down load the slave code image. Also it is a useful debugging tool.
+ */
+       retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
+       if (retval) {
+               printk(KERN_ERR "STALLION: failed to register serial memory "
+                               "device\n");
+               goto err_deinit;
+       }
+
+       istallion_class = class_create(THIS_MODULE, "staliomem");
+       for (i = 0; i < 4; i++)
+               device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+                             "staliomem%d", i);
+
        return 0;
+err_deinit:
+       pci_unregister_driver(&stli_pcidriver);
+       istallion_cleanup_isa();
+err_ttyunr:
+       tty_unregister_driver(stli_serial);
+err_ttyput:
+       put_tty_driver(stli_serial);
+err_free:
+       kfree(stli_txcookbuf);
+err:
+       return retval;
 }
 
 /*****************************************************************************/
+
+static void __exit istallion_module_exit(void)
+{
+       unsigned int j;
+
+       printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
+               stli_drvversion);
+
+       if (stli_timeron) {
+               stli_timeron = 0;
+               del_timer_sync(&stli_timerlist);
+       }
+
+       unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+
+       for (j = 0; j < 4; j++)
+               device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
+       class_destroy(istallion_class);
+
+       pci_unregister_driver(&stli_pcidriver);
+       istallion_cleanup_isa();
+
+       tty_unregister_driver(stli_serial);
+       put_tty_driver(stli_serial);
+
+       kfree(stli_txcookbuf);
+}
+
+module_init(istallion_module_init);
+module_exit(istallion_module_exit);