patch-2.2.5 linux/drivers/char/stallion.c
Next file: linux/drivers/char/synclink.c
Previous file: linux/drivers/char/n_hdlc.c
Back to the patch index
Back to the overall index
- Lines: 613
- Date:
Sun Mar 28 09:02:27 1999
- Orig file:
v2.2.4/linux/drivers/char/stallion.c
- Orig date:
Thu Dec 31 10:29:00 1998
diff -u --recursive --new-file v2.2.4/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
@@ -3,7 +3,7 @@
/*
* stallion.c -- stallion multiport serial driver.
*
- * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au).
* Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
*
* This code is loosely based on the Linux serial driver, written by
@@ -27,28 +27,18 @@
/*****************************************************************************/
#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
+#include <linux/malloc.h>
#include <linux/interrupt.h>
-#include <linux/termios.h>
-#include <linux/fcntl.h>
-#include <linux/tty_driver.h>
-#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/cd1400.h>
#include <linux/sc26198.h>
#include <linux/comstats.h>
#include <linux/stallion.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
#include <linux/ioport.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
-#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -78,7 +68,7 @@
* 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 }
+ * { 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:
@@ -105,7 +95,7 @@
} stlconf_t;
static stlconf_t stl_brdconf[] = {
- { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
+ /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
};
static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
@@ -144,7 +134,7 @@
*/
static char *stl_drvtitle = "Stallion Multiport Serial Driver";
static char *stl_drvname = "stallion";
-static char *stl_drvversion = "5.4.7";
+static char *stl_drvversion = "5.5.1";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
@@ -259,6 +249,85 @@
/*****************************************************************************/
+#ifdef MODULE
+/*
+ * Define some string labels for arguments passed from the module
+ * load line. These allow for easy board definitions, and easy
+ * modification of the io, memory and irq resoucres.
+ */
+
+static char *board0[4];
+static char *board1[4];
+static char *board2[4];
+static char *board3[4];
+
+static char **stl_brdsp[] = {
+ (char **) &board0,
+ (char **) &board1,
+ (char **) &board2,
+ (char **) &board3
+};
+
+/*
+ * Define a set of common board names, and types. This is used to
+ * parse any module arguments.
+ */
+
+typedef struct stlbrdtype {
+ char *name;
+ int type;
+} stlbrdtype_t;
+
+static stlbrdtype_t stl_brdstr[] = {
+ { "easyio", BRD_EASYIO },
+ { "eio", BRD_EASYIO },
+ { "20", BRD_EASYIO },
+ { "ec8/32", BRD_ECH },
+ { "ec8/32-at", BRD_ECH },
+ { "ec8/32-isa", BRD_ECH },
+ { "ech", BRD_ECH },
+ { "echat", BRD_ECH },
+ { "21", BRD_ECH },
+ { "ec8/32-mc", BRD_ECHMC },
+ { "ec8/32-mca", BRD_ECHMC },
+ { "echmc", BRD_ECHMC },
+ { "echmca", BRD_ECHMC },
+ { "22", BRD_ECHMC },
+ { "ec8/32-pc", BRD_ECHPCI },
+ { "ec8/32-pci", BRD_ECHPCI },
+ { "26", BRD_ECHPCI },
+ { "ec8/64-pc", BRD_ECH64PCI },
+ { "ec8/64-pci", BRD_ECH64PCI },
+ { "ech-pci", BRD_ECH64PCI },
+ { "echpci", BRD_ECH64PCI },
+ { "echpc", BRD_ECH64PCI },
+ { "27", BRD_ECH64PCI },
+ { "easyio-pc", BRD_EASYIOPCI },
+ { "easyio-pci", BRD_EASYIOPCI },
+ { "eio-pci", BRD_EASYIOPCI },
+ { "eiopci", BRD_EASYIOPCI },
+ { "28", BRD_EASYIOPCI },
+};
+
+/*
+ * Define the module agruments.
+ */
+MODULE_AUTHOR("Greg Ungerer");
+MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
+
+MODULE_PARM(board0, "1-4s");
+MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
+MODULE_PARM(board1, "1-4s");
+MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,ioaddr2][,irq]]");
+MODULE_PARM(board2, "1-4s");
+MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,ioaddr2][,irq]]");
+MODULE_PARM(board3, "1-4s");
+MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,ioaddr2][,irq]]");
+
+#endif
+
+/*****************************************************************************/
+
/*
* Hardware ID bits for the EasyIO and ECH boards. These defines apply
* to the directly accessible io ports of these boards (not the uarts -
@@ -399,9 +468,11 @@
/*
* Define some handy local macros...
*/
-#ifndef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-#endif
+#undef MIN
+#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
+
+#undef TOLOWER
+#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
/*****************************************************************************/
@@ -412,6 +483,10 @@
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
+static void stl_argbrds(void);
+static int stl_parsebrd(stlconf_t *confp, char **argp);
+
+static unsigned long stl_atol(char *str);
#endif
int stl_init(void);
@@ -459,15 +534,17 @@
static void stl_echpci64intr(stlbrd_t *brdp);
static void stl_offintr(void *private);
static void *stl_memalloc(int len);
+static stlbrd_t *stl_allocbrd(void);
static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
static inline int stl_initbrds(void);
static inline int stl_initeio(stlbrd_t *brdp);
static inline int stl_initech(stlbrd_t *brdp);
+static inline int stl_getbrdnr(void);
#ifdef CONFIG_PCI
static inline int stl_findpcibrds(void);
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev);
+static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp);
#endif
/*
@@ -747,7 +824,8 @@
kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE);
for (i = 0; (i < stl_nrbrds); i++) {
- brdp = stl_brds[i];
+ if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
+ continue;
for (j = 0; (j < STL_MAXPANELS); j++) {
panelp = brdp->panels[j];
if (panelp == (stlpanel_t *) NULL)
@@ -779,6 +857,124 @@
restore_flags(flags);
}
+/*****************************************************************************/
+
+/*
+ * Check for any arguments passed in on the module load command line.
+ */
+
+static void stl_argbrds()
+{
+ stlconf_t conf;
+ stlbrd_t *brdp;
+ int nrargs, i;
+
+#if DEBUG
+ printk("stl_argbrds()\n");
+#endif
+
+ nrargs = sizeof(stl_brdsp) / sizeof(char **);
+
+ for (i = stl_nrbrds; (i < nrargs); i++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
+ continue;
+ if ((brdp = stl_allocbrd()) == (stlbrd_t *) 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);
+ }
+}
+
+/*****************************************************************************/
+
+/*
+ * 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 stl_parsebrd(stlconf_t *confp, char **argp)
+{
+ char *sp;
+ int nrbrdnames, i;
+
+#if DEBUG
+ printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
+#endif
+
+ if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
+ return(0);
+
+ for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
+ *sp = TOLOWER(*sp);
+
+ nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t);
+ for (i = 0; (i < nrbrdnames); i++) {
+ if (strcmp(stl_brdstr[i].name, argp[0]) == 0)
+ break;
+ }
+ if (i >= nrbrdnames) {
+ printk("STALLION: unknown board name, %s?\n", argp[0]);
+ return(0);
+ }
+
+ confp->brdtype = stl_brdstr[i].type;
+
+ i = 1;
+ if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
+ confp->ioaddr1 = stl_atol(argp[i]);
+ i++;
+ if (confp->brdtype == BRD_ECH) {
+ if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
+ confp->ioaddr2 = stl_atol(argp[i]);
+ i++;
+ }
+ if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
+ confp->irq = stl_atol(argp[i]);
+ return(1);
+}
+
#endif
/*****************************************************************************/
@@ -794,6 +990,28 @@
/*****************************************************************************/
+/*
+ * Allocate a new board structure. Fill out the basic info in it.
+ */
+
+static stlbrd_t *stl_allocbrd()
+{
+ stlbrd_t *brdp;
+
+ brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
+ if (brdp == (stlbrd_t *) NULL) {
+ printk("STALLION: failed to allocate memory (size=%d)\n",
+ sizeof(stlbrd_t));
+ return((stlbrd_t *) NULL);
+ }
+
+ memset(brdp, 0, sizeof(stlbrd_t));
+ brdp->magic = STL_BOARDMAGIC;
+ return(brdp);
+}
+
+/*****************************************************************************/
+
static int stl_open(struct tty_struct *tty, struct file *filp)
{
stlport_t *portp;
@@ -1121,7 +1339,6 @@
down(&stl_tmpwritesem);
copy_from_user(stl_tmpwritebuf, chbuf, count);
- up(&stl_tmpwritesem);
chbuf = &stl_tmpwritebuf[0];
}
@@ -1154,6 +1371,9 @@
clear_bit(ASYI_TXLOW, &portp->istate);
stl_startrxtx(portp, -1, 1);
+ if (from_user)
+ up(&stl_tmpwritesem);
+
return(count);
}
@@ -2185,12 +2405,12 @@
}
if (check_region(brdp->ioaddr1, brdp->iosize1)) {
- printk("STALLION: Warning, unit %d I/O address %x conflicts "
+ printk("STALLION: Warning, board %d I/O address %x conflicts "
"with another device\n", brdp->brdnr, brdp->ioaddr1);
}
if (brdp->iosize2 > 0) {
if (check_region(brdp->ioaddr2, brdp->iosize2)) {
- printk("STALLION: Warning, unit %d I/O address %x "
+ printk("STALLION: Warning, board %d I/O address %x "
"conflicts with another device\n",
brdp->brdnr, brdp->ioaddr2);
}
@@ -2376,7 +2596,7 @@
conflict = check_region(brdp->ioaddr2, brdp->iosize2) ?
brdp->ioaddr2 : 0;
if (conflict) {
- printk("STALLION: Warning, unit %d I/O address %x conflicts "
+ printk("STALLION: Warning, board %d I/O address %x conflicts "
"with another device\n", brdp->brdnr, conflict);
}
@@ -2499,14 +2719,14 @@
stl_initech(brdp);
break;
default:
- printk("STALLION: unit=%d is unknown board type=%d\n",
+ printk("STALLION: board=%d is unknown board type=%d\n",
brdp->brdnr, brdp->brdtype);
return(ENODEV);
}
stl_brds[brdp->brdnr] = brdp;
if ((brdp->state & BRD_FOUND) == 0) {
- printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n",
+ 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);
@@ -2516,7 +2736,7 @@
if (brdp->panels[i] != (stlpanel_t *) NULL)
stl_initports(brdp, brdp->panels[i]);
- printk("STALLION: %s found, unit=%d io=%x irq=%d "
+ printk("STALLION: %s found, board=%d io=%x irq=%d "
"nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
brdp->nrports);
@@ -2525,6 +2745,26 @@
/*****************************************************************************/
+/*
+ * Find the next available board number that is free.
+ */
+
+static inline int stl_getbrdnr()
+{
+ int i;
+
+ for (i = 0; (i < STL_MAXBRDS); i++) {
+ if (stl_brds[i] == (stlbrd_t *) NULL) {
+ if (i >= stl_nrbrds)
+ stl_nrbrds = i + 1;
+ return(i);
+ }
+ }
+ return(-1);
+}
+
+/*****************************************************************************/
+
#ifdef CONFIG_PCI
/*
@@ -2533,42 +2773,32 @@
* configuration space.
*/
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev)
+static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
{
- unsigned int bar[4];
stlbrd_t *brdp;
- int i;
- unsigned char irq;
#if DEBUG
- printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
- brdtype, dev->bus->number, dev->devfn);
+ printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
+ dev->bus->number, dev->devfn);
#endif
- brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
- if (brdp == (stlbrd_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n",
- sizeof(stlbrd_t));
+ if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
return(-ENOMEM);
+ if ((brdp->brdnr = stl_getbrdnr()) < 0) {
+ printk("STALLION: too many boards found, "
+ "maximum supported %d\n", STL_MAXBRDS);
+ return(0);
}
-
- memset(brdp, 0, sizeof(stlbrd_t));
- brdp->magic = STL_BOARDMAGIC;
- brdp->brdnr = stl_nrbrds++;
brdp->brdtype = brdtype;
/*
- * Read in all the BAR registers from this board. Different Stallion
- * boards use these in different ways, so we just read in the whole
- * lot and then figure out what is what later.
- */
- for (i = 0; (i < 4); i++)
- bar[i] = dev->base_address[i];
- irq = dev->irq;
-
+ * Different Stallion boards use the BAR registers in different ways,
+ * so set up io addresses based on board type.
+ */
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- bar[0], bar[1], bar[2], bar[3], irq);
+ devp->base_address[0], devp->base_address[1],
+ devp->base_address[2], devp->base_address[3], devp->irq);
#endif
/*
@@ -2577,29 +2807,34 @@
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = (bar[0] & PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = (devp->base_address[0] &
+ PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = (devp->base_address[1] &
+ PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = (devp->base_address[2] &
+ PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = (devp->base_address[1] &
+ PCI_BASE_ADDRESS_IO_MASK);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr2 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = (devp->base_address[2] &
+ PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = (devp->base_address[1] &
+ PCI_BASE_ADDRESS_IO_MASK);
break;
default:
printk("STALLION: unknown PCI board type=%d\n", brdtype);
break;
}
- brdp->irq = irq;
+ brdp->irq = devp->irq;
stl_brdinit(brdp);
return(0);
}
-
/*****************************************************************************/
/*
@@ -2621,17 +2856,8 @@
return(0);
for (i = 0; (i < stl_nrpcibrds); i++)
- while ((dev = pci_find_device(stl_pcibrds[i].vendid, stl_pcibrds[i].devid, dev))) {
-
-/*
- * Check that we can handle more boards...
- */
- if (stl_nrbrds >= STL_MAXBRDS) {
- printk("STALLION: too many boards found, "
- "maximum supported %d\n", STL_MAXBRDS);
- i = stl_nrpcibrds;
- break;
- }
+ while ((dev = pci_find_device(stl_pcibrds[i].vendid,
+ stl_pcibrds[i].devid, dev))) {
/*
* Found a device on the PCI bus that has our vendor and
@@ -2680,15 +2906,11 @@
*/
for (i = 0; (i < stl_nrbrds); i++) {
confp = &stl_brdconf[i];
- brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
- if (brdp == (stlbrd_t *) NULL) {
- printk("STALLION: failed to allocate memory "
- "(size=%d)\n", sizeof(stlbrd_t));
+#ifdef MODULE
+ stl_parsebrd(confp, stl_brdsp[i]);
+#endif
+ if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
return(-ENOMEM);
- }
- memset(brdp, 0, sizeof(stlbrd_t));
-
- brdp->magic = STL_BOARDMAGIC;
brdp->brdnr = i;
brdp->brdtype = confp->brdtype;
brdp->ioaddr1 = confp->ioaddr1;
@@ -2698,11 +2920,14 @@
stl_brdinit(brdp);
}
-#ifdef CONFIG_PCI
/*
- * If the PCI BIOS support is compiled in then let's go looking for
- * ECH-PCI boards.
+ * Find any dynamically supported boards. That is via module load
+ * line options or auto-detected on the PCI bus.
*/
+#ifdef MODULE
+ stl_argbrds();
+#endif
+#ifdef CONFIG_PCI
stl_findpcibrds();
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)