]> err.no Git - linux-2.6/blobdiff - drivers/char/stallion.c
Fix a potential NULL pointer dereference in write_bulk_callback() in drivers/net...
[linux-2.6] / drivers / char / stallion.c
index 2db2e9fbb5c6476296a9ed3fb8bb67d8416be7ea..4a80b2f864e0b6e5edc468bc33342b4ffd612c3e 100644 (file)
@@ -63,7 +63,7 @@
 #define        BRD_EASYIOPCI   28
 
 struct stlconf {
-       int             brdtype;
+       unsigned int    brdtype;
        int             ioaddr1;
        int             ioaddr2;
        unsigned long   memaddr;
@@ -120,15 +120,6 @@ static struct ktermios             stl_deftermios = {
        .c_ospeed       = 9600,
 };
 
-/*
- *     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.
  */
@@ -200,7 +191,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];
@@ -632,7 +623,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 +685,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);
 
@@ -1556,8 +1547,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,"
@@ -1675,8 +1666,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 +1696,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 +1721,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 +1751,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) {
@@ -1801,7 +1788,6 @@ static void stl_offintr(struct work_struct *work)
        if (tty == NULL)
                return;
 
-       lock_kernel();
        if (test_bit(ASYI_TXLOW, &portp->istate))
                tty_wakeup(tty);
 
@@ -1815,7 +1801,6 @@ static void stl_offintr(struct work_struct *work)
                        if (portp->flags & ASYNC_CHECK_CD)
                                tty_hangup(tty);        /* FIXME: module removal race here - AKPM */
        }
-       unlock_kernel();
 }
 
 /*****************************************************************************/
@@ -1826,8 +1811,9 @@ static void stl_offintr(struct work_struct *work)
 
 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);
 
@@ -2052,8 +2038,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 +2170,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 +2222,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 +2326,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 +2349,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 +2364,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 +2408,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 +2424,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 +2434,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 +2457,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 +2506,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 +2526,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 +2584,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 +2611,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 +2631,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)
@@ -4698,7 +4701,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 +4709,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 +4748,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 +4775,26 @@ 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;
-       }
-
        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 +4807,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);
+       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);