patch-1.3.64 linux/drivers/char/istallion.c

Next file: linux/drivers/char/stallion.c
Previous file: linux/drivers/char/README.stallion
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.63/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
@@ -3,7 +3,7 @@
 /*
  *	istallion.c  -- stallion intelligent multiport serial driver.
  *
- *	Copyright (C) 1994,1995  Greg Ungerer (gerg@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
  *	Linus Torvalds, Theodore T'so and others.
@@ -26,7 +26,6 @@
 /*****************************************************************************/
 
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -141,6 +140,13 @@
 #include <asm/pgtable.h>
 #endif
 
+/*
+ *	There is some experimental EISA board detection code in this driver.
+ *	By default it is disabled, but for those that want to try it out,
+ *	then set the define below to be 1.
+ */
+#define	STLI_EISAPROBE	0
+
 /*****************************************************************************/
 
 /*
@@ -173,7 +179,7 @@
  *	all the local structures required by a serial tty driver.
  */
 static char	*stli_drvname = "Stallion Intelligent Multiport Serial Driver";
-static char	*stli_drvversion = "1.0.0";
+static char	*stli_drvversion = "1.0.2";
 static char	*stli_serialname = "ttyE";
 static char	*stli_calloutname = "cue";
 
@@ -267,9 +273,10 @@
 	unsigned long		addr;
 	unsigned long		rxoffset;
 	unsigned long		txoffset;
+	unsigned long		sigs;
+	unsigned long		pflag;
 	unsigned int		rxsize;
 	unsigned int		txsize;
-	unsigned long		sigs;
 	unsigned char		reqbit;
 	unsigned char		portidx;
 	unsigned char		portbit;
@@ -287,6 +294,7 @@
 	int		nrports;
 	int		nrdevs;
 	unsigned int	iobase;
+	unsigned long	memaddr;
 	void		*membase;
 	int		memsize;
 	int		pagesize;
@@ -304,7 +312,7 @@
 	stliport_t	*ports[STL_MAXPORTS];
 } stlibrd_t;
 
-static stlibrd_t	*stli_brds;
+static stlibrd_t	*stli_brds[STL_MAXBRDS];
 
 static int		stli_shared = 0;
 
@@ -369,6 +377,30 @@
 	"EC8/32-PCI",
 };
 
+/*
+ *	Set up a default memory address table for EISA board probing.
+ *	The default addresses are all bellow 1Mbyte, which has to be the
+ *	case anyway. They should be safe, since we only read values from
+ *	them, and interrupts are disabled while we do it. If the higher
+ *	memory support is compiled in then we also try probing around
+ *	the 1Gb, 2Gb and 3Gb areas as well...
+ */
+static unsigned long	stli_eisamemprobeaddrs[] = {
+	0xc0000, 0xd0000, 0xe0000, 0xf0000,
+	0x80000000, 0x80010000, 0x80020000, 0x80030000,
+	0x40000000, 0x40010000, 0x40020000, 0x40030000,
+	0xc0000000, 0xc0010000, 0xc0020000, 0xc0030000,
+	0xff000000, 0xff010000, 0xff020000, 0xff030000,
+};
+
+#if STLI_HIMEMORY
+static int	stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
+#else
+static int	stli_eisamempsize = 4;
+#endif
+
+int		stli_eisaprobe = STLI_EISAPROBE;
+
 /*****************************************************************************/
 
 /*
@@ -382,6 +414,8 @@
 #define	ECP_EIPAGESIZE	(64 * 1024)
 #define	ECP_MCPAGESIZE	(4 * 1024)
 
+#define	STL_EISAID	0x8c4e
+
 /*
  *	Important defines for the ISA class of ECP board.
  */
@@ -414,6 +448,8 @@
 #define	ECP_EIADDRSHFTH	24
 #define	ECP_EIBRDENAB	0xc84
 
+#define	ECP_EISAID	0x4
+
 /*
  *	Important defines for the Micro-channel class of ECP board.
  *	(It has a lot in common with the ISA boards.)
@@ -471,6 +507,8 @@
 #define	ONB_EIADDRSHFTH	24
 #define	ONB_EIBRDENAB	0xc84
 
+#define	ONB_EISAID	0x1
+
 /*
  *	Important defines for the Brumby boards. They are pretty simple,
  *	there is not much that is programmably configurable.
@@ -535,7 +573,7 @@
 	(* brdp->getmemptr)(brdp, offset, __LINE__)
 
 /*
- *	Define the maximal baud rate, and he default baud base for ports.
+ *	Define the maximal baud rate, and the default baud base for ports.
  */
 #define	STL_MAXBAUD	230400
 #define	STL_BAUDBASE	115200
@@ -576,7 +614,6 @@
 int		init_module(void);
 void		cleanup_module(void);
 #endif
-static void	*stli_memalloc(int len);
 
 int		stli_init(void);
 static int	stli_open(struct tty_struct *tty, struct file *filp);
@@ -595,9 +632,12 @@
 static void	stli_flushbuffer(struct tty_struct *tty);
 static void	stli_hangup(struct tty_struct *tty);
 
-static int	stli_brdinit(void);
-static int	stli_initecp(stlibrd_t *brdp, stlconf_t *confp);
-static int	stli_initonb(stlibrd_t *brdp, stlconf_t *confp);
+static int	stli_initbrds(void);
+static int	stli_brdinit(stlibrd_t *brdp);
+static int	stli_initecp(stlibrd_t *brdp);
+static int	stli_initonb(stlibrd_t *brdp);
+static int	stli_eisamemprobe(stlibrd_t *brdp);
+static int	stli_findeisabrds(void);
 static int	stli_initports(stlibrd_t *brdp);
 static int	stli_startbrd(stlibrd_t *brdp);
 static int	stli_memread(struct inode *ip, struct file *fp, char *buf, int count);
@@ -621,6 +661,7 @@
 static void	stli_read(stlibrd_t *brdp, stliport_t *portp);
 static void	stli_getserial(stliport_t *portp, struct serial_struct *sp);
 static int	stli_setserial(stliport_t *portp, struct serial_struct *sp);
+static void	*stli_memalloc(int len);
 
 static void	stli_ecpinit(stlibrd_t *brdp);
 static void	stli_ecpenable(stlibrd_t *brdp);
@@ -695,19 +736,18 @@
 static int	stli_timeron = 0;
 
 /*
- *	This is hack to allow for the kernel changes made to add_timer
- *	in the newer 1.3.X kernels (changed around 1.3.1X).
+ *	Define the calculation for the timeout routine.
  */
-#ifdef LINUX_1_2_X_COMPAT
-#define	STLI_TIMEOUT	0
-#else
 #define	STLI_TIMEOUT	(jiffies + 1)
-#endif
 
 /*****************************************************************************/
 
 #ifdef MODULE
 
+/*
+ *	Loadable module initialization stuff.
+ */
+
 int init_module()
 {
 	unsigned long	flags;
@@ -767,7 +807,9 @@
 		kfree_s(stli_txcookbuf, STLI_TXBUFSIZE);
 
 	for (i = 0; (i < stli_nrbrds); i++) {
-		brdp = &stli_brds[i];
+		brdp = stli_brds[i];
+		if (brdp == (stlibrd_t *) NULL)
+			continue;
 		for (j = 0; (j < STL_MAXPORTS); j++) {
 			portp = brdp->ports[j];
 			if (portp != (stliport_t *) NULL) {
@@ -785,8 +827,9 @@
 			release_region(brdp->iobase, ECP_IOSIZE);
 		else
 			release_region(brdp->iobase, ONB_IOSIZE);
+		kfree_s(brdp, sizeof(stlibrd_t));
+		stli_brds[i] = (stlibrd_t *) NULL;
 	}
-	kfree_s(stli_brds, (sizeof(stlibrd_t) * stli_nrbrds));
 
 	restore_flags(flags);
 }
@@ -796,17 +839,12 @@
 /*****************************************************************************/
 
 /*
- *	Local memory allocation routines. These are used so we can deal with
- *	memory allocation at init time and during run-time in a consistent
- *	way. Everbody just calls the stli_memalloc routine to allocate
- *	memory and it will do the right thing. There is no common memory
- *	deallocation code - since this is only done is special cases, all of
- *	which are tightly controlled.
+ *	Local driver kernel malloc routine.
  */
 
 static void *stli_memalloc(int len)
 {
-	return (void *) kmalloc(len, GFP_KERNEL);
+	return((void *) kmalloc(len, GFP_KERNEL));
 }
 
 /*****************************************************************************/
@@ -826,9 +864,9 @@
 	brdnr = MKDEV2BRD(minordev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	if (stli_brds == (stlibrd_t *) NULL)
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
 	if ((brdp->state & BST_STARTED) == 0)
 		return(-ENODEV);
 	portnr = MKDEV2PORT(minordev);
@@ -877,7 +915,7 @@
 			clear_bit(TTY_IO_ERROR, &tty->flags);
 		}
 		clear_bit(ST_INITIALIZING, &portp->state);
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->raw_wait);
 		if (rc < 0)
 			return(rc);
 	}
@@ -985,11 +1023,14 @@
 	}
 
 	portp->flags &= ~ASYNC_INITIALIZED;
-	brdp = &stli_brds[portp->brdnr];
-	stli_rawclose(brdp, portp, 0, 1);
+	brdp = stli_brds[portp->brdnr];
+	stli_rawclose(brdp, portp, 0, 0);
 	if (tty->termios->c_cflag & HUPCL) {
 		stli_mkasysigs(&portp->asig, 0, 0);
-		stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+		if (test_bit(ST_CMDING, &portp->state))
+			set_bit(ST_DOSIGS, &portp->state);
+		else
+			stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
 	}
 	clear_bit(ST_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &portp->state);
@@ -1284,7 +1325,9 @@
 		return(-ENODEV);
 	if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))
 		return(-ENODEV);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 
 	stli_mkasyport(portp, &aport, portp->tty->termios);
 	return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
@@ -1400,7 +1443,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 	chbuf = (unsigned char *) buf;
 
 /*
@@ -1562,7 +1607,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	save_flags(flags);
 	cli();
@@ -1645,7 +1692,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	save_flags(flags);
 	cli();
@@ -1698,7 +1747,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	save_flags(flags);
 	cli();
@@ -1726,6 +1777,7 @@
 static void stli_getserial(stliport_t *portp, struct serial_struct *sp)
 {
 	struct serial_struct	sio;
+	stlibrd_t		*brdp;
 
 #if DEBUG
 	printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
@@ -1734,8 +1786,7 @@
 	memset(&sio, 0, sizeof(struct serial_struct));
 	sio.type = PORT_UNKNOWN;
 	sio.line = portp->portnr;
-	sio.port = stli_brdconf[portp->brdnr].ioaddr1;
-	sio.irq = stli_brdconf[portp->brdnr].irq;
+	sio.irq = 0;
 	sio.flags = portp->flags;
 	sio.baud_base = portp->baud_base;
 	sio.close_delay = portp->close_delay;
@@ -1743,6 +1794,11 @@
 	sio.custom_divisor = portp->custom_divisor;
 	sio.xmit_fifo_size = 0;
 	sio.hub6 = 0;
+
+	brdp = stli_brds[portp->brdnr];
+	if (brdp != (stlibrd_t *) NULL)
+		sio.port = brdp->iobase;
+		
 	memcpy_tofs(sp, &sio, sizeof(struct serial_struct));
 }
 
@@ -1802,7 +1858,9 @@
 		return(-ENODEV);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	rc = 0;
 
@@ -1870,6 +1928,16 @@
 		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
 			rc = stli_setserial(portp, (struct serial_struct *) arg);
 		break;
+	case STL_GETPFLAG:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long))) == 0)
+			put_fs_long(portp->pflag, (unsigned long *) arg);
+		break;
+	case STL_SETPFLAG:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long))) == 0) {
+			portp->pflag = get_fs_long((unsigned long *) arg);
+			stli_setport(portp);
+		}
+		break;
 	case TIOCSERCONFIG:
 	case TIOCSERGWILD:
 	case TIOCSERSWILD:
@@ -1910,7 +1978,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	tiosp = tty->termios;
 	if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
@@ -2004,7 +2074,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	memset(&actrl, 0, sizeof(asyctrl_t));
 	actrl.txctrl = CT_STOPFLOW;
@@ -2036,7 +2108,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	memset(&actrl, 0, sizeof(asyctrl_t));
 	actrl.txctrl = CT_STARTFLOW;
@@ -2098,7 +2172,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	portp->flags &= ~ASYNC_INITIALIZED;
 
@@ -2154,7 +2230,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	save_flags(flags);
 	cli();
@@ -2188,8 +2266,8 @@
  *	carefull of data that will be copied out from shared memory -
  *	containing command results. The command completion is all done from
  *	a poll routine that does not have user coontext. Therefore you cannot
- *	copy back directly into user space, or to the kernel stack. This
- *	routine does not sleep, so can be called from anywhere.
+ *	copy back directly into user space, or to the kernel stack of a
+ *	process. This routine does not sleep, so can be called from anywhere.
  */
 
 static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
@@ -2203,13 +2281,15 @@
 	printk("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback);
 #endif
 
+	save_flags(flags);
+	cli();
+
 	if (test_bit(ST_CMDING, &portp->state)) {
 		printk("STALLION: command already busy, cmd=%x!\n", (int) cmd);
+		restore_flags(flags);
 		return;
 	}
 
-	save_flags(flags);
-	cli();
 	EBRDENABLE(brdp);
 	cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
 	if (size > 0) {
@@ -2520,7 +2600,9 @@
  *	Check each board and do any servicing required.
  */
 	for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
-		brdp = &stli_brds[brdnr];
+		brdp = stli_brds[brdnr];
+		if (brdp == (stlibrd_t *) NULL)
+			continue;
 		if ((brdp->state & BST_STARTED) == 0)
 			continue;
 
@@ -2691,6 +2773,11 @@
 		pp->iflag |= FI_1MARKRXERRS;
 	if (tiosp->c_iflag & BRKINT)
 		portp->rxmarkmsk |= BRKINT;
+
+/*
+ *	Transfer any persistent flags into the asyport structure.
+ */
+	pp->pflag = portp->pflag;
 }
 
 /*****************************************************************************/
@@ -2806,7 +2893,7 @@
 	outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
 	udelay(100);
 
-	memconf = (((unsigned long) brdp->membase) & ECP_ATADDRMASK) >> ECP_ATADDRSHFT;
+	memconf = (brdp->memaddr & ECP_ATADDRMASK) >> ECP_ATADDRSHFT;
 	outb(memconf, (brdp->iobase + ECP_ATMEMAR));
 }
 
@@ -2897,9 +2984,9 @@
 	outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
 	udelay(500);
 
-	memconf = (((unsigned long) brdp->membase) & ECP_EIADDRMASKL) >> ECP_EIADDRSHFTL;
+	memconf = (brdp->memaddr & ECP_EIADDRMASKL) >> ECP_EIADDRSHFTL;
 	outb(memconf, (brdp->iobase + ECP_EIMEMARL));
-	memconf = (((unsigned long) brdp->membase) & ECP_EIADDRMASKH) >> ECP_EIADDRSHFTH;
+	memconf = (brdp->memaddr & ECP_EIADDRMASKH) >> ECP_EIADDRSHFTH;
 	outb(memconf, (brdp->iobase + ECP_EIMEMARH));
 }
 
@@ -3018,10 +3105,10 @@
 	outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
 	udelay(10);
 	outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 
-	memconf = (((unsigned long) brdp->membase) & ONB_ATADDRMASK) >> ONB_ATADDRSHFT;
+	memconf = (brdp->memaddr & ONB_ATADDRMASK) >> ONB_ATADDRSHFT;
 	outb(memconf, (brdp->iobase + ONB_ATMEMAR));
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3079,7 +3166,7 @@
 	outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
 	udelay(10);
 	outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3102,12 +3189,12 @@
 	outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
 	udelay(10);
 	outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 
-	memconf = (((unsigned long) brdp->membase) & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL;
+	memconf = (brdp->memaddr & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL;
 	outb(memconf, (brdp->iobase + ONB_EIMEMARL));
-	memconf = (((unsigned long) brdp->membase) & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH;
+	memconf = (brdp->memaddr & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH;
 	outb(memconf, (brdp->iobase + ONB_EIMEMARH));
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3172,7 +3259,7 @@
 	outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
 	udelay(10);
 	outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3193,7 +3280,7 @@
 	outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
 	udelay(10);
 	outb(0, (brdp->iobase + BBY_ATCONFR));
-	for (i = 0; (i < 500); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3235,7 +3322,7 @@
 	outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
 	udelay(10);
 	outb(0, (brdp->iobase + BBY_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3254,7 +3341,7 @@
 #endif
 
 	outb(0x1, brdp->iobase);
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3291,7 +3378,7 @@
 	vecp = (volatile unsigned long *) (brdp->membase + 0x30);
 	*vecp = 0xffff0000;
 	outb(0, brdp->iobase);
-	for (i = 0; (i < 500); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3336,7 +3423,7 @@
  *	board types.
  */
 
-static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
+static int stli_initecp(stlibrd_t *brdp)
 {
 	cdkecpsig_t	sig;
 	cdkecpsig_t	*sigsp;
@@ -3344,18 +3431,23 @@
 	int		panelnr;
 
 #if DEBUG
-	printk("stli_initecp(brdp=%x,confp=%x)\n", (int) brdp, (int) confp);
+	printk("stli_initecp(brdp=%x)\n", (int) brdp);
 #endif
 
 /*
+ *	Do a basic sanity check on the IO and memory addresses.
+ */
+	if ((brdp->iobase == 0) || (brdp->memaddr == 0))
+		return(-ENODEV);
+
+/*
  *	Based on the specific board type setup the common vars to access
  *	and enable shared memory. Set all board specific information now
  *	as well.
  */
 	switch (brdp->brdtype) {
 	case BRD_ECP:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
 		brdp->pagesize = ECP_ATPAGESIZE;
 		brdp->init = stli_ecpinit;
@@ -3368,8 +3460,7 @@
 		break;
 
 	case BRD_ECPE:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
 		brdp->pagesize = ECP_EIPAGESIZE;
 		brdp->init = stli_ecpeiinit;
@@ -3382,10 +3473,9 @@
 		break;
 
 	case BRD_ECPMC:
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
-		brdp->membase = (void *) confp->memaddr;
 		brdp->pagesize = ECP_MCPAGESIZE;
-		brdp->iobase = confp->ioaddr1;
 		brdp->init = NULL;
 		brdp->enable = stli_ecpmcenable;
 		brdp->reenable = stli_ecpmcenable;
@@ -3408,8 +3498,8 @@
 	EBRDINIT(brdp);
 
 #if STLI_HIMEMORY
-	if (confp->memaddr > 0x100000) {
-		brdp->membase = stli_mapbrdmem(confp->memaddr, brdp->memsize);
+	if (brdp->memaddr > 0x100000) {
+		brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3418,7 +3508,7 @@
 /*
  *	Now that all specific code is set up, enable the shared memory and
  *	look for the a signature area that will tell us exactly what board
- *	this is, and what is connected to it.
+ *	this is, and what it is connected to it.
  */
 	EBRDENABLE(brdp);
 	sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
@@ -3468,17 +3558,23 @@
  *	This handles only these board types.
  */
 
-static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
+static int stli_initonb(stlibrd_t *brdp)
 {
 	cdkonbsig_t	sig;
 	cdkonbsig_t	*sigsp;
 	int		i;
 
 #if DEBUG
-	printk("stli_initonb(brdp=%x,confp=%x)\n", (int) brdp, (int) confp);
+	printk("stli_initonb(brdp=%x)\n", (int) brdp);
 #endif
 
 /*
+ *	Do a basic sanity check on the IO and memory addresses.
+ */
+	if ((brdp->iobase == 0) || (brdp->memaddr == 0))
+		return(-ENODEV);
+
+/*
  *	Based on the specific board type setup the common vars to access
  *	and enable shared memory. Set all board specific information now
  *	as well.
@@ -3489,8 +3585,7 @@
 	case BRD_ONBOARD2:
 	case BRD_ONBOARD2_32:
 	case BRD_ONBOARDRS:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ONB_MEMSIZE;
 		brdp->pagesize = ONB_ATPAGESIZE;
 		brdp->init = stli_onbinit;
@@ -3503,8 +3598,7 @@
 		break;
 
 	case BRD_ONBOARDE:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ONB_EIMEMSIZE;
 		brdp->pagesize = ONB_EIPAGESIZE;
 		brdp->init = stli_onbeinit;
@@ -3519,8 +3613,7 @@
 	case BRD_BRUMBY4:
 	case BRD_BRUMBY8:
 	case BRD_BRUMBY16:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = BBY_MEMSIZE;
 		brdp->pagesize = BBY_PAGESIZE;
 		brdp->init = stli_bbyinit;
@@ -3533,8 +3626,7 @@
 		break;
 
 	case BRD_STALLION:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = STAL_MEMSIZE;
 		brdp->pagesize = STAL_PAGESIZE;
 		brdp->init = stli_stalinit;
@@ -3559,8 +3651,8 @@
 	EBRDINIT(brdp);
 
 #if STLI_HIMEMORY
-	if (confp->memaddr > 0x100000) {
-		brdp->membase = stli_mapbrdmem(confp->memaddr, brdp->memsize);
+	if (brdp->memaddr > 0x100000) {
+		brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3720,75 +3812,297 @@
 /*****************************************************************************/
 
 /*
+ *	Probe and initialize the specified board.
+ */
+
+static int stli_brdinit(stlibrd_t *brdp)
+{
+#if DEBUG
+	printk("stli_brdinit(brdp=%x)\n", (int) brdp);
+#endif
+
+	stli_brds[brdp->brdnr] = brdp;
+
+	switch (brdp->brdtype) {
+	case BRD_ECP:
+	case BRD_ECPE:
+	case BRD_ECPMC:
+		stli_initecp(brdp);
+		break;
+	case BRD_ONBOARD:
+	case BRD_ONBOARDE:
+	case BRD_ONBOARD2:
+	case BRD_ONBOARD32:
+	case BRD_ONBOARD2_32:
+	case BRD_ONBOARDRS:
+	case BRD_BRUMBY4:
+	case BRD_BRUMBY8:
+	case BRD_BRUMBY16:
+	case BRD_STALLION:
+		stli_initonb(brdp);
+		break;
+	case BRD_EASYIO:
+	case BRD_ECH:
+	case BRD_ECHMC:
+	case BRD_ECHPCI:
+		printk("STALLION: %s board type not supported in this driver\n", stli_brdnames[brdp->brdtype]);
+		return(ENODEV);
+	default:
+		printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
+		return(ENODEV);
+	}
+
+	if ((brdp->state & BST_FOUND) == 0) {
+		printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr);
+		return(ENODEV);
+	}
+
+	stli_initports(brdp);
+	printk("STALLION: %s found, unit=%d io=%x mem=%x nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports);
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Probe around trying to find where the EISA boards shared memory
+ *	might be. This is a bit if hack, but it is the best we can do.
+ */
+
+static int stli_eisamemprobe(stlibrd_t *brdp)
+{
+	cdkecpsig_t	ecpsig, *ecpsigp;
+	cdkonbsig_t	onbsig, *onbsigp;
+	int		i, foundit;
+
+#if DEBUG
+	printk("stli_eisamemprobe(brdp=%x)\n", (int) brdp);
+#endif
+
+/*
+ *	First up we reset the board, to get it into a known state. There
+ *	is only 2 board types here we need to worry about. Don;t use the
+ *	standard board init routine here, it programs up the shared
+ *	memopry address, and we don't know it yet...
+ */
+	if (brdp->brdtype == BRD_ECPE) {
+		outb(0x1, (brdp->iobase + ECP_EIBRDENAB));
+		outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
+		udelay(10);
+		outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
+		udelay(500);
+		stli_ecpeienable(brdp);
+	} else if (brdp->brdtype == BRD_ONBOARDE) {
+		outb(0x1, (brdp->iobase + ONB_EIBRDENAB));
+		outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
+		udelay(10);
+		outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
+		for (i = 0; (i < 100); i++)
+			udelay(1000);
+		outb(0x1, brdp->iobase);
+		udelay(1000);
+		stli_onbeenable(brdp);
+	} else {
+		return(-ENODEV);
+	}
+
+	foundit = 0;
+	brdp->memsize = ECP_MEMSIZE;
+
+/*
+ *	Board shared memory is enabled, so now we have a poke around and
+ *	see if we can find it.
+ */
+	for (i = 0; (i < stli_eisamempsize); i++) {
+		brdp->memaddr = stli_eisamemprobeaddrs[i];
+		brdp->membase = (void *) brdp->memaddr;
+#if STLI_HIMEMORY
+		if (brdp->memaddr > 0x100000) {
+			brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
+			if (brdp->membase == (void *) NULL)
+				continue;
+		}
+#endif
+		if (brdp->brdtype == BRD_ECPE) {
+			ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp, CDK_SIGADDR, __LINE__);
+			memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+			if (ecpsig.magic == ECP_MAGIC)
+				foundit = 1;
+		} else {
+			onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp, CDK_SIGADDR, __LINE__);
+			memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
+			if ((onbsig.magic0 == ONB_MAGIC0) && (onbsig.magic1 == ONB_MAGIC1) &&
+					(onbsig.magic2 == ONB_MAGIC2) && (onbsig.magic3 == ONB_MAGIC3))
+				foundit = 1;
+		}
+#if STLI_HIMEMORY
+		if (brdp->memaddr >= 0x100000)
+			vfree(brdp->membase);
+#endif
+		if (foundit)
+			break;
+	}
+
+/*
+ *	Regardless of whether we found the shared memory or not we must
+ *	disable the region. After that return success or failure.
+ */
+	if (brdp->brdtype == BRD_ECPE)
+		stli_ecpeidisable(brdp);
+	else
+		stli_onbedisable(brdp);
+
+	if (! foundit) {
+		brdp->memaddr = 0;
+		brdp->membase = 0;
+		printk("STALLION: failed to probe shared memory region for %s in EISA slot=%d\n", stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
+		return(-ENODEV);
+	}
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Probe around and try to find any EISA boards in system. The biggest
+ *	problem here is finding out what memory address is associated with
+ *	an EISA board after it is found. The registers of the ECPE and
+ *	ONboardE are not readable - so we can't read them from there. We
+ *	don't have access to the EISA CMOS (or EISA BIOS) so we don't
+ *	actually have any way to find out the real value. The best we can
+ *	do is go probing around in the usual places hoping we can find it.
+ */
+
+static int stli_findeisabrds()
+{
+	stlibrd_t	*brdp;
+	unsigned int	iobase, eid;
+	int		i;
+
+#if DEBUG
+	printk("stli_findeisabrds()\n");
+#endif
+
+/*
+ *	Firstly check if this is an EISA system. Do this by probing for
+ *	the system board EISA ID. If this is not an EISA system then
+ *	don't bother going any further!
+ */
+	outb(0xff, 0xc80);
+	if (inb(0xc80) == 0xff)
+		return(0);
+
+/*
+ *	Looks like an EISA system, so go searching for EISA boards.
+ */
+	for (iobase = 0x1000; (iobase <= 0xc000); iobase += 0x1000) {
+		outb(0xff, (iobase + 0xc80));
+		eid = inb(iobase + 0xc80);
+		eid |= inb(iobase + 0xc81) << 8;
+		if (eid != STL_EISAID)
+			continue;
+
+/*
+ *		We have found a board. Need to check if this board was
+ *		statically configured already (just in case!).
+ */
+		for (i = 0; (i < STL_MAXBRDS); i++) {
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
+			if (brdp->iobase == iobase)
+				break;
+		}
+		if (i < STL_MAXBRDS)
+			continue;
+
+/*
+ *		Check that we have room for this new board in our board
+ *		info table.
+ */
+		if (stli_nrbrds >= STL_MAXBRDS) {
+			printk("STALLION: no room for more probed boards, maximum supported %d\n", STL_MAXBRDS);
+			break;
+		}
+
+/*
+ *		We have found a Stallion board and it is not configured already.
+ *		Allocate a board structure and initialize it.
+ */
+		brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
+		if (brdp == (stlibrd_t *) NULL) {
+			printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+			return(-ENOMEM);
+		}
+		memset(brdp, 0, sizeof(stlibrd_t));
+
+		brdp->brdnr = stli_nrbrds++;
+		eid = inb(iobase + 0xc82);
+		if (eid == ECP_EISAID)
+			brdp->brdtype = BRD_ECPE;
+		else if (eid == ONB_EISAID)
+			brdp->brdtype = BRD_ONBOARDE;
+		else
+			brdp->brdtype = BRD_UNKNOWN;
+		brdp->iobase = iobase;
+		outb(0x1, (iobase + 0xc84));
+		if (stli_eisamemprobe(brdp))
+			outb(0, (iobase + 0xc84));
+		stli_brdinit(brdp);
+	}
+
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
  *	Scan through all the boards in the configuration and see what we
  *	can find.
  */
 
-static int stli_brdinit()
+static int stli_initbrds()
 {
-	stlibrd_t	*brdp;
+	stlibrd_t	*brdp, *nxtbrdp;
 	stlconf_t	*confp;
 	int		i, j;
 
 #if DEBUG
-	printk("stli_brdinit()\n");
+	printk("stli_initbrds()\n");
 #endif
 
-	if (stli_nrbrds > STL_MAXBRDS)
-		return(-EINVAL);
-
-	stli_brds = (stlibrd_t *) stli_memalloc((sizeof(stlibrd_t) * stli_nrbrds));
-	if (stli_brds == (stlibrd_t *) NULL) {
-		printk("STALLION: failed to allocate board structures\n");
-		return(-ENOMEM);
+	if (stli_nrbrds > STL_MAXBRDS) {
+		printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
+		stli_nrbrds = STL_MAXBRDS;
 	}
-	memset(stli_brds, 0, (sizeof(stlibrd_t) * stli_nrbrds));
 
+/*
+ *	Firstly scan the list of static boards configured. Allocate
+ *	resources and initialize the boards as found.
+ */
 	for (i = 0; (i < stli_nrbrds); i++) {
-		brdp = &stli_brds[i];
 		confp = &stli_brdconf[i];
-		brdp->brdnr = i;
-		brdp->brdtype = confp->brdtype;
-
-		switch (confp->brdtype) {
-		case BRD_ECP:
-		case BRD_ECPE:
-		case BRD_ECPMC:
-			stli_initecp(brdp, confp);
-			break;
-		case BRD_ONBOARD:
-		case BRD_ONBOARDE:
-		case BRD_ONBOARD2:
-		case BRD_ONBOARD32:
-		case BRD_ONBOARD2_32:
-		case BRD_ONBOARDRS:
-		case BRD_BRUMBY4:
-		case BRD_BRUMBY8:
-		case BRD_BRUMBY16:
-		case BRD_STALLION:
-			stli_initonb(brdp, confp);
-			break;
-		case BRD_EASYIO:
-		case BRD_ECH:
-		case BRD_ECHMC:
-		case BRD_ECHPCI:
-			printk("STALLION: %s board type not supported in this driver\n", stli_brdnames[brdp->brdtype]);
-			break;
-		default:
-			printk("STALLION: unit=%d is unknown board type=%d\n", i, confp->brdtype);
-			break;
-		}
-
-		if ((brdp->state & BST_FOUND) == 0) {
-			printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], i, confp->ioaddr1, (int) confp->memaddr);
-			continue;
+		brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
+		if (brdp == (stlibrd_t *) NULL) {
+			printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+			return(-ENOMEM);
 		}
+		memset(brdp, 0, sizeof(stlibrd_t));
 
-		stli_initports(brdp);
-		printk("STALLION: %s found, unit=%d io=%x mem=%x nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], i, confp->ioaddr1, (int) confp->memaddr, brdp->nrpanels, brdp->nrports);
+		brdp->brdnr = i;
+		brdp->brdtype = confp->brdtype;
+		brdp->iobase = confp->ioaddr1;
+		brdp->memaddr = confp->memaddr;
+		stli_brdinit(brdp);
 	}
 
 /*
+ *	Now go probing for EISA boards if enabled.
+ */
+	if (stli_eisaprobe)
+		stli_findeisabrds();
+
+/*
  *	All found boards are initialized. Now for a little optimization, if
  *	no boards are sharing the "shared memory" regions then we can just
  *	leave them all enabled. This is in fact the usual case.
@@ -3796,10 +4110,14 @@
 	stli_shared = 0;
 	if (stli_nrbrds > 1) {
 		for (i = 0; (i < stli_nrbrds); i++) {
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
 			for (j = i + 1; (j < stli_nrbrds); j++) {
-				brdp = &stli_brds[i];
-				if ((brdp->membase >= stli_brds[j].membase) &&
-						(brdp->membase <= (stli_brds[j].membase + stli_brds[j].memsize - 1))) {
+				nxtbrdp = stli_brds[j];
+				if (nxtbrdp == (stlibrd_t *) NULL)
+					continue;
+				if ((brdp->membase >= nxtbrdp->membase) && (brdp->membase <= (nxtbrdp->membase + nxtbrdp->memsize - 1))) {
 					stli_shared++;
 					break;
 				}
@@ -3809,7 +4127,9 @@
 
 	if (stli_shared == 0) {
 		for (i = 0; (i < stli_nrbrds); i++) {
-			brdp = &stli_brds[i];
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
 			if (brdp->state & BST_FOUND) {
 				EBRDENABLE(brdp);
 				brdp->enable = NULL;
@@ -3843,7 +4163,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 	if (fp->f_pos >= brdp->memsize)
@@ -3891,7 +4213,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 	if (fp->f_pos >= brdp->memsize)
@@ -3937,7 +4261,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 
@@ -3971,11 +4297,11 @@
 
 /*****************************************************************************/
 
-int stli_init(void)
+int stli_init()
 {
 	printk("%s: version %s\n", stli_drvname, stli_drvversion);
 
-	stli_brdinit();
+	stli_initbrds();
 
 /*
  *	Allocate a temporary write buffer.
@@ -4039,7 +4365,7 @@
 	if (tty_register_driver(&stli_callout))
 		printk("STALLION: failed to register callout driver\n");
 
-	return 0;
+	return(0);
 }
 
 /*****************************************************************************/

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this