#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PCI
#include <linux/pci.h>
-#endif
/*****************************************************************************/
#define BRD_ECH64PCI 27
#define BRD_EASYIOPCI 28
-/*
- * Define a configuration structure to hold the board configuration.
- * Need to set this up in the code (for now) with the boards that are
- * to be configured into the system. This is what needs to be modified
- * when adding/removing/modifying boards. Each line entry in the
- * stl_brdconf[] array is a board. Each line contains io/irq/memory
- * ranges for that board (as well as what type of board it is).
- * Some examples:
- * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
- * This line would configure an EasyIO board (4 or 8, no difference),
- * at io address 2a0 and irq 10.
- * Another example:
- * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 },
- * This line will configure an EasyConnection 8/32 board at primary io
- * address 2a8, secondary io address 280 and irq 12.
- * Enter as many lines into this array as you want (only the first 4
- * will actually be used!). Any combination of EasyIO and EasyConnection
- * boards can be specified. EasyConnection 8/32 boards can share their
- * secondary io addresses between each other.
- *
- * NOTE: there is no need to put any entries in this table for PCI
- * boards. They will be found automatically by the driver - provided
- * PCI BIOS32 support is compiled into the kernel.
- */
-
-static struct stlconf {
- int brdtype;
+struct stlconf {
+ unsigned int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
-} stl_brdconf[] = {
- /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
};
-static int stl_nrbrds = ARRAY_SIZE(stl_brdconf);
+static unsigned int stl_nrbrds;
/*****************************************************************************/
.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.
*/
/*****************************************************************************/
+static DEFINE_MUTEX(stl_brdslock);
static struct stlbrd *stl_brds[STL_MAXBRDS];
/*
* Not really much here!
*/
#define BRD_FOUND 0x1
+#define STL_PROBED 0x2
+
/*
* Define the port structure istate flags. These set of flags are
* 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];
9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
};
-/*
- * Define some handy local macros...
- */
-#undef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-
-#undef TOLOWER
-#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
-
/*****************************************************************************/
/*
/*****************************************************************************/
-/*
- * Convert an ascii string number into an unsigned long.
- */
-
-static unsigned long stl_atol(char *str)
-{
- unsigned long val;
- int base, c;
- char *sp;
-
- val = 0;
- sp = str;
- if ((*sp == '0') && (*(sp+1) == 'x')) {
- base = 16;
- sp += 2;
- } else if (*sp == '0') {
- base = 8;
- sp++;
- } else {
- base = 10;
- }
-
- for (; (*sp != 0); sp++) {
- c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
- if ((c < 0) || (c >= base)) {
- printk("STALLION: invalid argument %s\n", str);
- val = 0;
- break;
- }
- val = (val * base) + c;
- }
- return val;
-}
-
-/*****************************************************************************/
-
/*
* Parse the supplied argument string, into the board conf struct.
*/
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++)
- *sp = TOLOWER(*sp);
+ 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;
i = 1;
if ((argp[i] != NULL) && (*argp[i] != 0))
- confp->ioaddr1 = stl_atol(argp[i]);
+ confp->ioaddr1 = simple_strtoul(argp[i], NULL, 0);
i++;
if (confp->brdtype == BRD_ECH) {
if ((argp[i] != NULL) && (*argp[i] != 0))
- confp->ioaddr2 = stl_atol(argp[i]);
+ confp->ioaddr2 = simple_strtoul(argp[i], NULL, 0);
i++;
}
if ((argp[i] != NULL) && (*argp[i] != 0))
- confp->irq = stl_atol(argp[i]);
+ confp->irq = simple_strtoul(argp[i], NULL, 0);
return 1;
}
return brdp;
}
-static void __init stl_argbrds(void)
-{
- struct stlconf conf;
- struct stlbrd *brdp;
- int i;
-
- pr_debug("stl_argbrds()\n");
-
- for (i = stl_nrbrds; (i < stl_nargs); i++) {
- memset(&conf, 0, sizeof(conf));
- if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
- continue;
- if ((brdp = stl_allocbrd()) == NULL)
- continue;
- stl_nrbrds = i + 1;
- brdp->brdnr = i;
- brdp->brdtype = conf.brdtype;
- brdp->ioaddr1 = conf.ioaddr1;
- brdp->ioaddr2 = conf.ioaddr2;
- brdp->irq = conf.irq;
- brdp->irqtype = conf.irqtype;
- stl_brdinit(brdp);
- }
-}
-
/*****************************************************************************/
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);
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) {
* 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 (!(filp->f_flags & O_NONBLOCK))
if ((rc = stl_waitcarrier(portp, filp)) != 0)
return rc;
- }
+
portp->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
break;
}
if (((portp->flags & ASYNC_CLOSING) == 0) &&
- (doclocal || (portp->sigs & TIOCM_CD))) {
+ (doclocal || (portp->sigs & TIOCM_CD)))
break;
- }
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
stlen = len;
}
- len = MIN(len, count);
+ len = min(len, (unsigned int)count);
count = 0;
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy(head, chbuf, stlen);
len -= stlen;
chbuf += stlen;
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);
}
/*****************************************************************************/
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;
*sp = ' ';
sp += cnt;
- for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
+ for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)
*sp++ = ' ';
if (cnt >= MAXLINE)
pos[(MAXLINE - 2)] = '+';
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,"
* 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;
}
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;
continue;
}
- for (portnr = 0; (portnr < panelp->nrports); portnr++,
+ for (portnr = 0; portnr < panelp->nrports; portnr++,
totalport++) {
portp = panelp->ports[portnr];
if (portp == NULL)
stl_readdone:
*start = page;
- return (pos - page);
+ return pos - page;
}
/*****************************************************************************/
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];
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];
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) {
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];
return;
lock_kernel();
- if (test_bit(ASYI_TXLOW, &portp->istate)) {
+ 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 ((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 __init stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
+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);
* 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 "
stl_portinit(brdp, panelp, portp);
}
- return(0);
+ 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);
+ }
}
/*****************************************************************************/
* Try to find and initialize an EasyIO board.
*/
-static int __init stl_initeio(struct stlbrd *brdp)
+static int __devinit 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);
(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)
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;
}
/*
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
+ retval = -ENODEV;
switch (status & EIO_IDBITMASK) {
case EIO_8PORTM:
brdp->clk = CD1400_CLK8M;
brdp->nrports = 16;
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
/*
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;
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;
}
/*****************************************************************************/
* dealing with all types of ECH board.
*/
-static int __init stl_initech(struct stlbrd *brdp)
+static int __devinit stl_initech(struct stlbrd *brdp)
{
struct stlpanel *panelp;
- unsigned int status, nxtid, ioaddr, conflict;
- int panelnr, banknr, i;
+ unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i;
+ int retval;
char *name;
pr_debug("stl_initech(brdp=%p)\n", 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);
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;
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);
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)
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;
}
/*
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)
- 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;
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;
brdp->panels[panelnr++] = panelp;
if ((brdp->brdtype != BRD_ECHPCI) &&
(ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
- break;
+ goto err_fr;
}
brdp->nrpanels = panelnr;
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;
}
/*****************************************************************************/
* since the initial search and setup is very different.
*/
-static int __init stl_brdinit(struct stlbrd *brdp)
+static int __devinit 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;
if ((brdp->state & BRD_FOUND) == 0) {
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++)
+ for (i = 0; i < STL_MAXPANELS; i++)
if (brdp->panels[i] != NULL)
stl_initports(brdp, brdp->panels[i]);
"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);
+err:
+ return retval;
}
/*****************************************************************************/
* Find the next available board number that is free.
*/
-static int __init stl_getbrdnr(void)
+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);
-}
-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);
- }
+ return -1;
}
/*****************************************************************************/
const struct pci_device_id *ent)
{
struct stlbrd *brdp;
- unsigned int brdtype = ent->driver_data;
-
- pr_debug("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
- pdev->bus->number, pdev->devfn);
+ unsigned int i, brdtype = ent->driver_data;
+ int brdnr, 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) {
- printk("STALLION: too many boards found, "
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+ brdp = stl_allocbrd();
+ if (brdp == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ mutex_lock(&stl_brdslock);
+ brdnr = stl_getbrdnr();
+ if (brdnr < 0) {
+ dev_err(&pdev->dev, "too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return(0);
+ mutex_unlock(&stl_brdslock);
+ goto err_fr;
}
- brdp->brdtype = brdtype;
+ brdp->brdnr = (unsigned int)brdnr;
+ stl_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stl_brdslock);
-/*
- * Different Stallion boards use the BAR registers in different ways,
- * so set up io addresses based on board type.
- */
- pr_debug("%s(%d): BAR[]=%Lx,%Lx,%Lx,%Lx IRQ=%x\n", __FILE__, __LINE__,
- pci_resource_start(pdev, 0), pci_resource_start(pdev, 1),
- pci_resource_start(pdev, 2), pci_resource_start(pdev, 3), pdev->irq);
+ brdp->brdtype = brdtype;
+ brdp->state |= STL_PROBED;
/*
* We have all resources from the board, so let's setup the actual
brdp->ioaddr2 = pci_resource_start(pdev, 1);
break;
default:
- printk("STALLION: unknown PCI board type=%d\n", brdtype);
+ dev_err(&pdev->dev, "unknown PCI board type=%u\n", brdtype);
break;
}
brdp->irq = pdev->irq;
- stl_brdinit(brdp);
+ retval = stl_brdinit(brdp);
+ if (retval)
+ goto err_null;
pci_set_drvdata(pdev, brdp);
- return(0);
+ 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;
+err_fr:
+ kfree(brdp);
+err:
+ return retval;
}
static void __devexit stl_pciremove(struct pci_dev *pdev)
{
struct stlbrd *brdp = pci_get_drvdata(pdev);
+ unsigned int i;
free_irq(brdp->irq, brdp);
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);
}
/*****************************************************************************/
-/*
- * Scan through all the boards in the configuration and see what we
- * can find. Handle EIO and the ECH boards a little differently here
- * since the initial search and setup is too different.
- */
-
-static int __init stl_initbrds(void)
-{
- struct stlbrd *brdp;
- struct stlconf *confp;
- int i;
-
- pr_debug("stl_initbrds()\n");
-
- if (stl_nrbrds > STL_MAXBRDS) {
- printk("STALLION: too many boards in configuration table, "
- "truncating to %d\n", STL_MAXBRDS);
- stl_nrbrds = STL_MAXBRDS;
- }
-
-/*
- * Firstly scan the list of static boards configured. Allocate
- * resources and initialize the boards as found.
- */
- for (i = 0; (i < stl_nrbrds); i++) {
- confp = &stl_brdconf[i];
- stl_parsebrd(confp, stl_brdsp[i]);
- if ((brdp = stl_allocbrd()) == NULL)
- return(-ENOMEM);
- brdp->brdnr = i;
- brdp->brdtype = confp->brdtype;
- brdp->ioaddr1 = confp->ioaddr1;
- brdp->ioaddr2 = confp->ioaddr2;
- brdp->irq = confp->irq;
- brdp->irqtype = confp->irqtype;
- stl_brdinit(brdp);
- }
-
-/*
- * Find any dynamically supported boards. That is via module load
- * line options or auto-detected on the PCI bus.
- */
- stl_argbrds();
-
- return(0);
-}
-
-/*****************************************************************************/
-
/*
* Return the board stats structure to user app.
*/
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;
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;
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];
}
/*****************************************************************************/
static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
{
+ comstats_t stl_comstats;
unsigned char *head, *tail;
unsigned long flags;
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.rxbuffered = 0;
spin_lock_irqsave(&stallion_lock, flags);
- if (portp->tty != NULL) {
+ if (portp->tty != NULL)
if (portp->tty->driver_data == portp) {
portp->stats.ttystate = portp->tty->flags;
/* No longer available as a statistic */
portp->stats.lflags = portp->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);
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));
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)))
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;
}
brdnr = iminor(ip);
if (brdnr >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
rc = 0;
switch (cmd) {
break;
}
- return(rc);
+ return rc;
}
static const struct tty_operations stl_ops = {
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;
*/
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));
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",
{
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);
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;
}
mcor2 |= MCOR2_DCD;
sreron |= SRER_MODEM;
portp->flags |= ASYNC_CHECK_CD;
- } else {
+ } else
portp->flags &= ~ASYNC_CHECK_CD;
- }
/*
* Setup cd1400 enhanced modes if we can. In particular we want to
}
outb(srer, (ioaddr + EREG_DATA));
} else {
- len = MIN(len, CD1400_TXFIFOSIZE);
+ len = min(len, CD1400_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb((TDR + portp->uartaddr), ioaddr);
outsb((ioaddr + EREG_DATA), tail, stlen);
len -= stlen;
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(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb((RDSR + portp->uartaddr), ioaddr);
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);
}
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));
mr1 |= (MR1_PARENB | MR1_PARODD);
else
mr1 |= (MR1_PARENB | MR1_PAREVEN);
- } else {
+ } else
mr1 |= MR1_PARNONE;
- }
mr1 |= MR1_ERRBLOCK;
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_iflag & IXON) {
mr0 |= MR0_SWFTX | MR0_SWFT;
imron |= IR_XONXOFF;
- } else {
+ } else
imroff |= IR_XONXOFF;
- }
+
if (tiosp->c_iflag & IXOFF)
mr0 |= MR0_SWFRX;
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);
}
if (portp == NULL)
return;
- for (i = 0; (i < 20); i++)
+ for (i = 0; i < 20; i++)
stl_sc26198getglobreg(portp, TSTR);
}
outb(mr0, (ioaddr + XP_DATA));
}
} else {
- len = MIN(len, SC26198_TXFIFOSIZE);
+ len = min(len, SC26198_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb(GTXFIFO, (ioaddr + XP_ADDR));
outsb((ioaddr + XP_DATA), tail, stlen);
len -= stlen;
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(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb(GRXFIFO, (ioaddr + XP_ADDR));
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);
}
}
+static void stl_free_isabrds(void)
+{
+ struct stlbrd *brdp;
+ unsigned int i;
+
+ for (i = 0; i < stl_nrbrds; i++) {
+ if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+ continue;
+
+ 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);
+
+ kfree(brdp);
+ stl_brds[i] = NULL;
+ }
+}
+
/*
* Loadable module initialization stuff.
*/
static int __init stallion_module_init(void)
{
- unsigned int i, retval;
+ struct stlbrd *brdp;
+ struct stlconf conf;
+ unsigned int i, j;
+ int retval;
printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
spin_lock_init(&stallion_lock);
spin_lock_init(&brd_lock);
- stl_initbrds();
+/*
+ * Find any dynamically supported boards. That is via module load
+ * line options.
+ */
+ for (i = stl_nrbrds; i < stl_nargs; i++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
+ continue;
+ if ((brdp = stl_allocbrd()) == NULL)
+ continue;
+ brdp->brdnr = i;
+ brdp->brdtype = conf.brdtype;
+ brdp->ioaddr1 = conf.ioaddr1;
+ brdp->ioaddr2 = conf.ioaddr2;
+ brdp->irq = conf.irq;
+ brdp->irqtype = conf.irqtype;
+ if (stl_brdinit(brdp))
+ kfree(brdp);
+ else {
+ for (j = 0; j < brdp->nrports; j++)
+ tty_register_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + j, NULL);
+ stl_brds[brdp->brdnr] = brdp;
+ stl_nrbrds = i + 1;
+ }
+ }
+ /* this has to be _after_ isa finding because of locking */
retval = pci_register_driver(&stl_pcidriver);
- if (retval)
+ if (retval && stl_nrbrds == 0)
goto err;
stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stl_serial)
- return -1;
+ if (!stl_serial) {
+ retval = -ENOMEM;
+ goto err_pcidr;
+ }
/*
* Set up a character driver for per board stuff. This is mainly used
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;
+ }
for (i = 0; i < 4; i++)
class_device_create(stallion_class, NULL,
MKDEV(STL_SIOMEMMAJOR, i), NULL,
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;
+ stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(stl_serial, &stl_ops);
- if (tty_register_driver(stl_serial)) {
- put_tty_driver(stl_serial);
+ retval = tty_register_driver(stl_serial);
+ if (retval) {
printk("STALLION: failed to register serial driver\n");
- return -1;
+ 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");
+ 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)
{
- struct stlbrd *brdp;
- int i;
+ struct stlbrd *brdp;
+ unsigned int i, j;
+ int retval;
pr_debug("cleanup_module()\n");
* a hangup on every open port - to try to flush out any processes
* hanging onto ports.
*/
- i = tty_unregister_driver(stl_serial);
- put_tty_driver(stl_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
+ 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);
}
+ tty_unregister_driver(stl_serial);
+ put_tty_driver(stl_serial);
+
for (i = 0; i < 4; i++)
class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+ if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
+ "errno=%d\n", -retval);
class_destroy(stallion_class);
pci_unregister_driver(&stl_pcidriver);
- for (i = 0; (i < stl_nrbrds); i++) {
- if ((brdp = stl_brds[i]) == NULL)
- continue;
-
- 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);
-
- kfree(brdp);
- stl_brds[i] = NULL;
- }
+ stl_free_isabrds();
}
module_init(stallion_module_init);