patch-1.3.85 linux/drivers/char/pcxx.c

Next file: linux/drivers/char/pcxx.h
Previous file: linux/drivers/char/misc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.84/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
@@ -25,6 +25,9 @@
  *		allocation harmonized with 1.3.X Series.
  *  1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh
  *		instead of direct assigment to kernel arrays.
+ *  1.5.5 April 5, 1996 Major device numbers corrected.
+ *              Mike McLagan<mike.mclagan@linux.org>: Add setup
+ *              variable handling, instead of using the old pcxxconfig.h
  *
  */
 
@@ -49,18 +52,21 @@
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
-#include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
 #include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
 
-#define VERSION 	"1.5.4"
+#define VERSION 	"1.5.5"
+static char *banner = "Digiboard PC/X{i,e,eve,em} driver v1.5.5.  Christoph Lameter <clameter@fuller.edu>.";
+
 /*#define	DEFAULT_HW_FLOW	1 */
 /*#define	DEBUG_IOCTL */
 
@@ -69,21 +75,26 @@
 #include "pcxx.h"
 #include "digi_fep.h"
 #include "digi_bios.h"
-#include "pcxxconfig.h"
-
-#define DIGIMAJOR   30
-#define DIGICUMAJOR 31 
-
-#define MAXPORTS 16     /* Max ports per PC/Xx type board */
-#define NBDEVS   (NUMCARDS * MAXPORTS)
-#define PORTNUM(x)  ((x)->dev % MAXPORTS)
-#define LINENUM(x)  (MINOR((x)->device) - (x)->driver.minor_start)
 
+/* Define one default setting if no digi= config line is used.
+ * Default is ALTPIN = ON, PC/16E, 16 ports, I/O 200h Memory 0D0000h
+ */
+static struct board_info boards[MAX_DIGI_BOARDS] = { {	ENABLED, 0, ON, 16, 0x200, 0xd0000,0 } };
+ 
+static int               numcards = 1;
+static int               nbdevs = 0;
+ 
+/* C is a pain!  I want a pointer to an array of structs */
+static struct channel    *(*digi_channels);
+
+/* this is supposed to be a pointer to an array of pointers */
+static struct tty_struct *(*pcxe_table)[];
+static struct termios    *(*pcxe_termios)[];
+static struct termios    *(*pcxe_termios_locked)[];
+ 
 int pcxx_ncook=sizeof(pcxx_cook);
 int pcxx_nbios=sizeof(pcxx_bios);
 
-struct channel digi_channels[NBDEVS];
-
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #define pcxxassert(x, msg)  if(!(x)) pcxx_error(__LINE__, msg)
 
@@ -97,9 +108,6 @@
 static int pcxe_refcount;
 
 DECLARE_TASK_QUEUE(tq_pcxx);
-static struct tty_struct *pcxe_table[NBDEVS];
-static struct termios *pcxe_termios[NBDEVS];
-static struct termios *pcxe_termios_locked[NBDEVS];
 
 static void pcxxpoll(void);
 static void pcxxdelay(int);
@@ -142,7 +150,7 @@
 {
 	if (tty) {
 		register struct channel *ch=(struct channel *)tty->driver_data;
-		if ((ch >= &digi_channels[0]) && (ch < &digi_channels[NBDEVS])) {
+		if ((ch >= &((*digi_channels)[0])) && (ch < &((*digi_channels)[nbdevs]))) {
 			if (ch->magic==PCXX_MAGIC)
 				return ch;
 		}
@@ -293,20 +301,25 @@
 	int retval;
 
 	line = MINOR(tty->device) - tty->driver.minor_start;
-	if(line < 0 || line >= NBDEVS) {
+
+	if(line < 0 || line >= nbdevs) {
 		printk("line out of range in pcxe_open\n");
 		tty->driver_data = NULL;
 		return(-ENODEV);
 	}
 
-	boardnum = line / 16;
-	if(boardnum >= NUMCARDS || boards[boardnum].status == DISABLED ||
-								(line % MAXPORTS) >= boards[boardnum].numports) {
+	for(boardnum=0;boardnum<numcards;boardnum++)
+		if ((line >= boards[boardnum].first_minor) && 
+			(line <= boards[boardnum].first_minor + boards[boardnum].numports))
+		break;
+
+	if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
+		(line - boards[boardnum].first_minor) >= boards[boardnum].numports) {
 		tty->driver_data = NULL;   /* Mark this device as 'down' */
 		return(-ENODEV);
 	}
-	
-	ch = &digi_channels[line];
+
+	ch = &((*digi_channels)[line]);
 
 	if(ch->brdchan == 0) {
 		tty->driver_data = NULL;
@@ -746,10 +759,211 @@
 	}
 }
 
+/* Flag if lilo configuration option is used. If so the
+ * default settings are removed
+ */
+
+static int liloconfig=0;
+
+void pcxx_setup(char *str, int *ints)
+{
+
+	struct board_info board;
+	int               i, j, last;
+	char              *temp, *t2;
+	unsigned          len;
+
+#if 0
+	if (!numcards)
+		memset(&boards, 0, sizeof(boards));
+#endif
+	if (liloconfig==0) { liloconfig=1;numcards=0; }
+
+	memset(&board, 0, sizeof(board));
+
+	for(last=0,i=1;i<=ints[0];i++)
+		switch(i)
+		{
+			case 1:
+				board.status = ints[i];
+				last = i;
+				break;
+
+			case 2:
+				board.type = ints[i];
+				last = i;
+				break;
+
+			case 3:
+				board.altpin = ints[i];
+				last = i;
+				break;
+
+			case 4:
+				board.numports = ints[i];
+				last = i;
+				break;
+
+			case 5:
+				board.port = ints[i];
+				last = i;
+				break;
+
+			case 6:
+				board.membase = ints[i];
+				last = i;
+				break;
+
+			default:
+				printk("PC/Xx: Too many integer parms\n");
+				return;
+		}
+
+	
+	while (str && *str) 
+	{
+		/* find the next comma or terminator */
+		temp = str;
+		while (*temp && (*temp != ','))
+			temp++;
+
+		if (!*temp)
+			temp = NULL;
+		else
+			*temp++ = 0;
+
+		i = last + 1;
+
+		switch(i)
+		{
+			case 1:
+				len = strlen(str);
+				if (strncmp("Disable", str, len) == 0) 
+					board.status = 0;
+				else
+					if (strncmp("Enable", str, len) == 0)
+						board.status = 1;
+					else
+					{
+						printk("PC/Xx: Invalid status %s\n", str);
+						return;
+					}
+				last = i;
+				break;
+
+			case 2:
+				for(j=0;j<PCXX_NUM_TYPES;j++)
+					if (strcmp(board_desc[j], str) == 0)
+						break;
+
+				if (i<PCXX_NUM_TYPES) 
+					board.type = j;
+				else
+				{
+					printk("PC/Xx: Invalid board name: %s\n", str);
+					return;
+				}
+				last = i;
+				break;
+
+			case 3:
+				len = strlen(str);
+				if (strncmp("Disable", str, len) == 0) 
+					board.altpin = 0;
+				else
+					if (strncmp("Enable", str, len) == 0)
+						board.altpin = 1;
+					else
+					{
+						printk("PC/Xx: Invalid altpin %s\n", str);
+						return;
+					}
+				last = i;
+				break;
+
+			case 4:
+				t2 = str;
+				while (isdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk("PC/Xx: Invalid port count %s\n", str);
+					return;
+				}
+
+				board.numports = simple_strtoul(str, NULL, 0);
+				last = i;
+				break;
+
+			case 5:
+				t2 = str;
+				while (isxdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk("PC/Xx: Invalid port count %s\n", str);
+					return;
+				}
+
+				board.port = simple_strtoul(str, NULL, 16);
+				last = i;
+				break;
+
+			case 6:
+				t2 = str;
+				while (isxdigit(*t2))
+					t2++;
+
+				if (*t2)
+				{
+					printk("PC/Xx: Invalid memory base %s\n", str);
+					return;
+				}
+
+				board.membase = simple_strtoul(str, NULL, 16);
+				last = i;
+				break;
+
+			default:
+				printk("PC/Xx: Too many string parms\n");
+				return;
+		}
+		str = temp;
+	}
+
+	if (last < 6)  
+	{
+		printk("PC/Xx: Insufficient parms specified\n");
+		return;
+	}
+ 
+        /* I should REALLY validate the stuff here */
+
+	memcpy(&boards[numcards],&board, sizeof(board));
+	printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", 
+		numcards, board_desc[board.type], board_mem[board.type], 
+		board.numports, board.port, (unsigned int) board.membase);
+
+	/* keep track of my inital minor number */
+        if (numcards)
+		boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;
+	else
+		boards[numcards].first_minor = 0;
+
+	/* yeha!  string parameter was successful! */
+	numcards++;
+}
+
 
 int pcxe_init(void)
 {
-	ulong flags, save_loops_per_sec, memory_seg=0, memory_size;
+#if 0
+	ulong save_loops_per_sec;
+#endif
+
+	ulong flags, memory_seg=0, memory_size;
 	int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
 	unchar *fepos, *memaddr, *bios, v;
 	volatile struct global_data *gd;
@@ -757,6 +971,45 @@
 	volatile struct board_chan *bc;
 	struct channel *ch;
 
+	printk("%s\n", banner);
+
+	if (numcards <= 0)
+	{
+		printk("PC/Xx: No cards configured, exiting.\n");
+		return(0);
+	}
+
+	for (i=0;i<numcards;i++)
+		nbdevs += boards[i].numports;
+
+	if (nbdevs <= 0)
+	{
+		printk("PC/Xx: No devices activated, exiting.\n");
+		return(0);
+	}
+
+	/*
+	 * this turns out to be more memory efficient, as there are no 
+	 * unused spaces.  There is *NO* way I'm going to explain these
+	 * convoluted casts, suffice it to say they WORK!  :)
+	 */
+	digi_channels = (struct channel **) kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
+	if (!digi_channels)
+		panic("Unable to allocate digi_channel struct");
+
+	pcxe_table = (struct tty_struct *(*)[]) kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
+	if (!pcxe_table)
+		panic("Unable to allocate pcxe_table struct");
+
+	pcxe_termios = (struct termios *(*)[]) kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
+	if (!pcxe_termios)
+		panic("Unable to allocate pcxe_termios struct");
+
+	pcxe_termios_locked = (struct termios *(*)[]) kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
+	if (!pcxe_termios_locked)
+		panic("Unable to allocate pcxe_termios_locked struct");
+
+
 	init_bh(DIGI_BH,do_pcxe_bh);
 	enable_bh(DIGI_BH);
 
@@ -766,18 +1019,21 @@
 	memset(&pcxe_driver, 0, sizeof(struct tty_driver));
 	pcxe_driver.magic = TTY_DRIVER_MAGIC;
 	pcxe_driver.name = "ttyd";
-	pcxe_driver.major = DIGIMAJOR; 
+	pcxe_driver.major = DIGI_MAJOR; 
 	pcxe_driver.minor_start = 0;
-	pcxe_driver.num = NBDEVS;
+
+	pcxe_driver.num = nbdevs;
+
 	pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
 	pcxe_driver.init_termios = tty_std_termios;
 	pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
 	pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
 	pcxe_driver.refcount = &pcxe_refcount;
-	pcxe_driver.table = pcxe_table;
-	pcxe_driver.termios = pcxe_termios;
-	pcxe_driver.termios_locked = pcxe_termios_locked;
+
+	pcxe_driver.table = *pcxe_table;
+	pcxe_driver.termios = *pcxe_termios;
+	pcxe_driver.termios_locked = *pcxe_termios_locked;
 
 	pcxe_driver.open = pcxe_open;
 	pcxe_driver.close = pcxe_close;
@@ -797,28 +1053,33 @@
 
 	pcxe_callout = pcxe_driver;
 	pcxe_callout.name = "ttyD";
-	pcxe_callout.major = DIGICUMAJOR;
+	pcxe_callout.major = DIGICU_MAJOR;
 	pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
 	pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
 
+#if 0 
+
+/* strangely enough, this is FALSE */
+
 	/* 
 	 * loops_per_sec hasn't been set at this point :-(, so fake it out... 
 	 * I set it so that I can use the __delay() function.
 	 */
 	save_loops_per_sec = loops_per_sec;
 	loops_per_sec = 13L*500000L;
+#endif
 
 	save_flags(flags);
 	cli();
 
-	for(crd=0; crd < NUMCARDS; crd++) {
+	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
 		outb(FEPRST, bd->port);
 		pcxxdelay(1);
 
 		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
 			if(i > 1000) {
-				printk("Board not found at port 0x%x! Check switch settings.\n",
+				printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
 					bd->port);
 				bd->status = DISABLED;
 				break;
@@ -854,7 +1115,7 @@
 		} else {
 			if((v & 0x1) == 0x1) {
 				bd->status = DISABLED;   /* PC/Xm unsupported card */
-				printk("PC/Xm at 0x%x not supported!!\n", bd->port);
+				printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);
 				continue;
 			} else {
 				if(v & 0xC0) {    
@@ -877,7 +1138,7 @@
 
 		for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
 			if(i > 10000) {
-				printk("%s not resetting at port 0x%x! Check switch settings.\n",
+				printk("PC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
 					board_desc[bd->type], bd->port);
 				bd->status = DISABLED;
 				break;
@@ -893,7 +1154,7 @@
 
 		if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||
 					*(ulong *)(memaddr + topwin) != 0x5aa5c33c) {
-			printk("Failed memory test at %lx for %s at port %x, check switch settings.\n",
+			printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",
 				bd->membase, board_desc[bd->type], bd->port);
 			bd->status = DISABLED;
 			continue;
@@ -917,7 +1178,7 @@
 				pcxxdelay(1);
 			}
 
-			printk("BIOS download failed on the %s at 0x%x!\n",
+			printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
 							board_desc[bd->type], bd->port);
 			bd->status = DISABLED;
 			continue;
@@ -939,7 +1200,7 @@
 				pcxxdelay(1);
 			}
 
-			printk("BIOS download failed on the %s at 0x%x!\n",
+			printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
 				board_desc[bd->type], bd->port);
 			bd->status = DISABLED;
 			continue;
@@ -966,7 +1227,7 @@
 
 		for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {
 			if(i > 2000) {
-				printk("Command failed for the %s at 0x%x!\n",
+				printk("PC/Xx: Command failed for the %s at 0x%x!\n",
 					board_desc[bd->type], bd->port);
 				bd->status = DISABLED;
 				break;
@@ -988,7 +1249,7 @@
 
 		for(i=0; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
 			if(i > 10000) {
-				printk("FEP/OS download failed on the %s at 0x%x!\n",
+				printk("PC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
 					board_desc[bd->type], bd->port);
 				bd->status = DISABLED;
 				break;
@@ -998,8 +1259,8 @@
 		if(bd->status == DISABLED)
 			continue;
 
-		ch = &digi_channels[MAXPORTS * crd];
-		pcxxassert(ch <= &digi_channels[NBDEVS-1], "ch out of range");
+		ch = &((*digi_channels)[bd->first_minor]);
+		pcxxassert(ch < &((*digi_channels)[nbdevs]), "ch out of range");
 
 		bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);
 		gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);
@@ -1035,7 +1296,7 @@
 			ch->boardnum = crd;
 			ch->channelnum = i;
 
-			ch->dev = (MAXPORTS * crd) + i;
+			ch->dev = bd->first_minor + i;
 			ch->tty = 0;
 
 			if(shrinkmem) {
@@ -1089,8 +1350,9 @@
 			ch->close_wait = 0;
 		}
 
-		printk("DigiBoard PC/Xx Driver V%s:  %s I/O=0x%x Mem=0x%lx Ports=%d\n", 
-				VERSION, board_desc[bd->type], bd->port, bd->membase, bd->numports);
+		printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 
+			board_desc[bd->type], board_mem[bd->type], bd->port, 
+			bd->membase, bd->numports);
 
 		memwinoff(bd, 0);
 	}
@@ -1101,8 +1363,9 @@
 	if(tty_register_driver(&pcxe_callout))
 		panic("Couldn't register PC/Xe callout");
 
-
+#if 0
 	loops_per_sec = save_loops_per_sec;  /* reset it to what it should be */
+#endif
 
 	/*
 	 * Start up the poller to check for events on all enabled boards
@@ -1125,9 +1388,10 @@
 	save_flags(flags);
 	cli();
 
-	for(crd=0; crd < NUMCARDS; crd++) {
+	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
-		ch = &digi_channels[MAXPORTS*crd];
+
+		ch = &((*digi_channels)[bd->first_minor]);
 
 		if(bd->status == DISABLED)
 			continue;
@@ -1164,8 +1428,9 @@
 
 	bd = &boards[crd];
 
-	chan0 = &digi_channels[MAXPORTS * crd];
-	pcxxassert(chan0 <= &digi_channels[NBDEVS-1], "ch out of range");
+	chan0 = &((*digi_channels)[bd->first_minor]);
+	pcxxassert(chan0 < &((*digi_channels)[nbdevs]), "ch out of range");
+
 
 	assertgwinon(chan0);
 
@@ -1292,12 +1557,15 @@
 
 	if(bytecmd) {
 		*(unchar *)(memaddr+head+CSTART+0) = cmd;
-		*(unchar *)(memaddr+head+CSTART+1) = PORTNUM(ch);
+
+		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
+
 		*(unchar *)(memaddr+head+CSTART+2) = word_or_byte;
 		*(unchar *)(memaddr+head+CSTART+3) = byte2;
 	} else {
 		*(unchar *)(memaddr+head+CSTART+0) = cmd;
-		*(unchar *)(memaddr+head+CSTART+1) = PORTNUM(ch);
+
+		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;
 		*(ushort*)(memaddr+head+CSTART+2) = word_or_byte;
 	}
 
@@ -1660,7 +1928,7 @@
 					break;
 
 				case TIOCMBIC:
-					ch->modemfake |= mflag;
+					ch->modemfake &= ~mflag;
 					ch->modem &= ~mflag;
 					break;
 			}
@@ -1964,4 +2232,3 @@
 	memoff(ch);
 	restore_flags(flags);
 }
-

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