forked from luck/tmp_suning_uos_patched
[PATCH] Char: stallion, implement fail paths
This driver expect everything to work. Implement fail paths logic to release regions, irq hangler, memory... if something is in bad state. Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
fefaf9a789
commit
3b85b3413d
@ -779,7 +779,8 @@ static void __init stl_argbrds(void)
|
||||
brdp->ioaddr2 = conf.ioaddr2;
|
||||
brdp->irq = conf.irq;
|
||||
brdp->irqtype = conf.irqtype;
|
||||
stl_brdinit(brdp);
|
||||
if (stl_brdinit(brdp))
|
||||
kfree(brdp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1965,6 +1966,29 @@ static int __init stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void stl_cleanup_panels(struct stlbrd *brdp)
|
||||
{
|
||||
struct stlpanel *panelp;
|
||||
struct stlport *portp;
|
||||
unsigned int j, k;
|
||||
|
||||
for (j = 0; j < STL_MAXPANELS; j++) {
|
||||
panelp = brdp->panels[j];
|
||||
if (panelp == NULL)
|
||||
continue;
|
||||
for (k = 0; k < STL_PORTSPERPANEL; k++) {
|
||||
portp = panelp->ports[k];
|
||||
if (portp == NULL)
|
||||
continue;
|
||||
if (portp->tty != NULL)
|
||||
stl_hangup(portp->tty);
|
||||
kfree(portp->tx.buf);
|
||||
kfree(portp);
|
||||
}
|
||||
kfree(panelp);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -1976,7 +2000,7 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
struct stlpanel *panelp;
|
||||
unsigned int status;
|
||||
char *name;
|
||||
int rc;
|
||||
int retval;
|
||||
|
||||
pr_debug("stl_initeio(brdp=%p)\n", brdp);
|
||||
|
||||
@ -2003,18 +2027,20 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
|
||||
printk("STALLION: invalid irq=%d for brd=%d\n",
|
||||
brdp->irq, brdp->brdnr);
|
||||
return(-EINVAL);
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
outb((stl_vecmap[brdp->irq] | EIO_0WS |
|
||||
((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
|
||||
brdp->ioctrl);
|
||||
}
|
||||
|
||||
retval = -EBUSY;
|
||||
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
|
||||
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
|
||||
"%x conflicts with another device\n", brdp->brdnr,
|
||||
brdp->ioaddr1);
|
||||
return(-EBUSY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (brdp->iosize2 > 0)
|
||||
@ -2025,8 +2051,7 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
printk(KERN_WARNING "STALLION: Warning, also "
|
||||
"releasing board %d I/O address %x \n",
|
||||
brdp->brdnr, brdp->ioaddr1);
|
||||
release_region(brdp->ioaddr1, brdp->iosize1);
|
||||
return(-EBUSY);
|
||||
goto err_rel1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2035,6 +2060,7 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
brdp->clk = CD1400_CLK;
|
||||
brdp->isr = stl_eiointr;
|
||||
|
||||
retval = -ENODEV;
|
||||
switch (status & EIO_IDBITMASK) {
|
||||
case EIO_8PORTM:
|
||||
brdp->clk = CD1400_CLK8M;
|
||||
@ -2058,11 +2084,11 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
brdp->nrports = 16;
|
||||
break;
|
||||
default:
|
||||
return(-ENODEV);
|
||||
goto err_rel2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return(-ENODEV);
|
||||
goto err_rel2;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2074,7 +2100,8 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
if (!panelp) {
|
||||
printk(KERN_WARNING "STALLION: failed to allocate memory "
|
||||
"(size=%Zd)\n", sizeof(struct stlpanel));
|
||||
return -ENOMEM;
|
||||
retval = -ENOMEM;
|
||||
goto err_rel2;
|
||||
}
|
||||
|
||||
panelp->magic = STL_PANELMAGIC;
|
||||
@ -2098,11 +2125,20 @@ static int __init stl_initeio(struct stlbrd *brdp)
|
||||
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
|
||||
printk("STALLION: failed to register interrupt "
|
||||
"routine for %s irq=%d\n", name, brdp->irq);
|
||||
rc = -ENODEV;
|
||||
} else {
|
||||
rc = 0;
|
||||
retval = -ENODEV;
|
||||
goto err_fr;
|
||||
}
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
err_fr:
|
||||
stl_cleanup_panels(brdp);
|
||||
err_rel2:
|
||||
if (brdp->iosize2 > 0)
|
||||
release_region(brdp->ioaddr2, brdp->iosize2);
|
||||
err_rel1:
|
||||
release_region(brdp->ioaddr1, brdp->iosize1);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -2116,7 +2152,7 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
{
|
||||
struct stlpanel *panelp;
|
||||
unsigned int status, nxtid, ioaddr, conflict;
|
||||
int panelnr, banknr, i;
|
||||
int panelnr, banknr, i, retval;
|
||||
char *name;
|
||||
|
||||
pr_debug("stl_initech(brdp=%p)\n", brdp);
|
||||
@ -2136,13 +2172,16 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
brdp->ioctrl = brdp->ioaddr1 + 1;
|
||||
brdp->iostatus = brdp->ioaddr1 + 1;
|
||||
status = inb(brdp->iostatus);
|
||||
if ((status & ECH_IDBITMASK) != ECH_ID)
|
||||
return(-ENODEV);
|
||||
if ((status & ECH_IDBITMASK) != ECH_ID) {
|
||||
retval = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
if ((brdp->irq < 0) || (brdp->irq > 15) ||
|
||||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
|
||||
printk("STALLION: invalid irq=%d for brd=%d\n",
|
||||
brdp->irq, brdp->brdnr);
|
||||
return(-EINVAL);
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
|
||||
status |= (stl_vecmap[brdp->irq] << 1);
|
||||
@ -2162,13 +2201,16 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
brdp->ioctrl = brdp->ioaddr1 + 0x20;
|
||||
brdp->iostatus = brdp->ioctrl;
|
||||
status = inb(brdp->iostatus);
|
||||
if ((status & ECH_IDBITMASK) != ECH_ID)
|
||||
return(-ENODEV);
|
||||
if ((status & ECH_IDBITMASK) != ECH_ID) {
|
||||
retval = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
if ((brdp->irq < 0) || (brdp->irq > 15) ||
|
||||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
|
||||
printk("STALLION: invalid irq=%d for brd=%d\n",
|
||||
brdp->irq, brdp->brdnr);
|
||||
return(-EINVAL);
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
outb(ECHMC_BRDRESET, brdp->ioctrl);
|
||||
outb(ECHMC_INTENABLE, brdp->ioctrl);
|
||||
@ -2195,19 +2237,20 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
|
||||
default:
|
||||
printk("STALLION: unknown board type=%d\n", brdp->brdtype);
|
||||
return(-EINVAL);
|
||||
break;
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check boards for possible IO address conflicts and return fail status
|
||||
* if an IO conflict found.
|
||||
*/
|
||||
retval = -EBUSY;
|
||||
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
|
||||
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
|
||||
"%x conflicts with another device\n", brdp->brdnr,
|
||||
brdp->ioaddr1);
|
||||
return(-EBUSY);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (brdp->iosize2 > 0)
|
||||
@ -2218,8 +2261,7 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
printk(KERN_WARNING "STALLION: Warning, also "
|
||||
"releasing board %d I/O address %x \n",
|
||||
brdp->brdnr, brdp->ioaddr1);
|
||||
release_region(brdp->ioaddr1, brdp->iosize1);
|
||||
return(-EBUSY);
|
||||
goto err_rel1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2241,12 +2283,12 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
}
|
||||
status = inb(ioaddr + ECH_PNLSTATUS);
|
||||
if ((status & ECH_PNLIDMASK) != nxtid)
|
||||
break;
|
||||
goto err_fr;
|
||||
panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
|
||||
if (!panelp) {
|
||||
printk("STALLION: failed to allocate memory "
|
||||
"(size=%Zd)\n", sizeof(struct stlpanel));
|
||||
break;
|
||||
goto err_fr;
|
||||
}
|
||||
panelp->magic = STL_PANELMAGIC;
|
||||
panelp->brdnr = brdp->brdnr;
|
||||
@ -2294,7 +2336,7 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
brdp->panels[panelnr++] = panelp;
|
||||
if ((brdp->brdtype != BRD_ECHPCI) &&
|
||||
(ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
|
||||
break;
|
||||
goto err_fr;
|
||||
}
|
||||
|
||||
brdp->nrpanels = panelnr;
|
||||
@ -2306,12 +2348,19 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
|
||||
printk("STALLION: failed to register interrupt "
|
||||
"routine for %s irq=%d\n", name, brdp->irq);
|
||||
i = -ENODEV;
|
||||
} else {
|
||||
i = 0;
|
||||
retval = -ENODEV;
|
||||
goto err_fr;
|
||||
}
|
||||
|
||||
return(i);
|
||||
return 0;
|
||||
err_fr:
|
||||
stl_cleanup_panels(brdp);
|
||||
if (brdp->iosize2 > 0)
|
||||
release_region(brdp->ioaddr2, brdp->iosize2);
|
||||
err_rel1:
|
||||
release_region(brdp->ioaddr1, brdp->iosize1);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -2325,25 +2374,30 @@ static int __init stl_initech(struct stlbrd *brdp)
|
||||
|
||||
static int __init stl_brdinit(struct stlbrd *brdp)
|
||||
{
|
||||
int i;
|
||||
int i, retval;
|
||||
|
||||
pr_debug("stl_brdinit(brdp=%p)\n", brdp);
|
||||
|
||||
switch (brdp->brdtype) {
|
||||
case BRD_EASYIO:
|
||||
case BRD_EASYIOPCI:
|
||||
stl_initeio(brdp);
|
||||
retval = stl_initeio(brdp);
|
||||
if (retval)
|
||||
goto err;
|
||||
break;
|
||||
case BRD_ECH:
|
||||
case BRD_ECHMC:
|
||||
case BRD_ECHPCI:
|
||||
case BRD_ECH64PCI:
|
||||
stl_initech(brdp);
|
||||
retval = stl_initech(brdp);
|
||||
if (retval)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
printk("STALLION: board=%d is unknown board type=%d\n",
|
||||
brdp->brdnr, brdp->brdtype);
|
||||
return(ENODEV);
|
||||
retval = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
stl_brds[brdp->brdnr] = brdp;
|
||||
@ -2351,7 +2405,7 @@ static int __init stl_brdinit(struct stlbrd *brdp)
|
||||
printk("STALLION: %s board not found, board=%d io=%x irq=%d\n",
|
||||
stl_brdnames[brdp->brdtype], brdp->brdnr,
|
||||
brdp->ioaddr1, brdp->irq);
|
||||
return(ENODEV);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
for (i = 0; (i < STL_MAXPANELS); i++)
|
||||
@ -2362,7 +2416,20 @@ static int __init stl_brdinit(struct stlbrd *brdp)
|
||||
"nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
|
||||
brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
|
||||
brdp->nrports);
|
||||
return(0);
|
||||
|
||||
return 0;
|
||||
err_free:
|
||||
free_irq(brdp->irq, brdp);
|
||||
|
||||
stl_cleanup_panels(brdp);
|
||||
|
||||
release_region(brdp->ioaddr1, brdp->iosize1);
|
||||
if (brdp->iosize2 > 0)
|
||||
release_region(brdp->ioaddr2, brdp->iosize2);
|
||||
|
||||
stl_brds[brdp->brdnr] = NULL;
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -2385,29 +2452,6 @@ static int __init stl_getbrdnr(void)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static void stl_cleanup_panels(struct stlbrd *brdp)
|
||||
{
|
||||
struct stlpanel *panelp;
|
||||
struct stlport *portp;
|
||||
unsigned int j, k;
|
||||
|
||||
for (j = 0; j < STL_MAXPANELS; j++) {
|
||||
panelp = brdp->panels[j];
|
||||
if (panelp == NULL)
|
||||
continue;
|
||||
for (k = 0; k < STL_PORTSPERPANEL; k++) {
|
||||
portp = panelp->ports[k];
|
||||
if (portp == NULL)
|
||||
continue;
|
||||
if (portp->tty != NULL)
|
||||
stl_hangup(portp->tty);
|
||||
kfree(portp->tx.buf);
|
||||
kfree(portp);
|
||||
}
|
||||
kfree(panelp);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* We have a Stallion board. Allocate a board structure and
|
||||
@ -2420,21 +2464,27 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
|
||||
{
|
||||
struct stlbrd *brdp;
|
||||
unsigned int brdtype = ent->driver_data;
|
||||
int retval = -ENODEV;
|
||||
|
||||
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
|
||||
return -ENODEV;
|
||||
goto err;
|
||||
|
||||
dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
|
||||
pdev->vendor, pdev->device, pdev->class);
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
return(-EIO);
|
||||
if ((brdp = stl_allocbrd()) == NULL)
|
||||
return(-ENOMEM);
|
||||
if ((brdp->brdnr = stl_getbrdnr()) < 0) {
|
||||
retval = pci_enable_device(pdev);
|
||||
if (retval)
|
||||
goto err;
|
||||
brdp = stl_allocbrd();
|
||||
if (brdp == NULL) {
|
||||
retval = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
brdp->brdnr = stl_getbrdnr();
|
||||
if (brdp->brdnr < 0) {
|
||||
dev_err(&pdev->dev, "too many boards found, "
|
||||
"maximum supported %d\n", STL_MAXBRDS);
|
||||
return(0);
|
||||
goto err_fr;
|
||||
}
|
||||
brdp->brdtype = brdtype;
|
||||
|
||||
@ -2461,11 +2511,17 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
brdp->irq = pdev->irq;
|
||||
stl_brdinit(brdp);
|
||||
retval = stl_brdinit(brdp);
|
||||
if (retval)
|
||||
goto err_fr;
|
||||
|
||||
pci_set_drvdata(pdev, brdp);
|
||||
|
||||
return(0);
|
||||
return 0;
|
||||
err_fr:
|
||||
kfree(brdp);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __devexit stl_pciremove(struct pci_dev *pdev)
|
||||
@ -2528,7 +2584,8 @@ static int __init stl_initbrds(void)
|
||||
brdp->ioaddr2 = confp->ioaddr2;
|
||||
brdp->irq = confp->irq;
|
||||
brdp->irqtype = confp->irqtype;
|
||||
stl_brdinit(brdp);
|
||||
if (stl_brdinit(brdp))
|
||||
kfree(brdp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user