[LWN Logo]

Date:	Thu, 27 Jan 2000 17:39:17 -0500
To:	torvalds@transmeta.com
Subject: Update for the serial driver
From:	tytso@mit.edu

Hi Linus,

Enclosed please find an update for the serial driver.  I would
appreciate it if you would fold this into the next 2.3 kernel release.
Thanks!!

Changes include:

* The most important new feature in this driver is the addition of ISA
	PNP support.  This support is based on Andrey Panin, but it has
	been changed so that as much code as possible is shared between
	the PCI support code and the PNP support code.  This made a lot
	of sense, given that high-level the PNP framework uses the PCI
	code as a base.

* A number of new PCI serial and modem boards are now supported with
	this driver, and the driver attempts to add some generic
	hueristics to support cards that allegedly conform the
	conventions specified in the PCI spec.  I've seen a lot of cards
	that don't, and so right now the hueristics are extremely
	conservative.

* A potential SMP race condition in the hangup code has been fixed.

* Support for turning on the loopback mode using the TIOCMSET/TIOCMGET
	ioctls has been added.  This should allow for a user-mode
	base_baud autodetection program to be written.  I've also
	updated all of the architecture's termbits to add support for
	TIOCM_OUT1, TIOCM_OUT2, and TIOCM_LOOP, for consistency's sake.

* A number of #ifdef's have been cleaned up and removed, where they
	didn't make much sense.  (The configuration option of IO mapped
	memory didn't save much, if at all, and added more complexity
	than it saved.)  Also, #ifdef's related to modules support for
	Linux 1.2 and Linxu 1.3 systems have been removed.

* Fixed a bug identified by David Hinds where if an non-existent serial
	port is opened (for example, by setserial or kudzu), subsequent
	registration of that unused serial port by a PCMCIA driver
	caused the port to fail until "setserial /dev/ttySx irq 0" ;
	"setserial /dev/ttySx irq x" was done.

* Added a workaround for a nasty baud rate calculation hardware bug
	which is needed for certain specific Oxford Semiconductor UARTs
	(the 16C952 rev. B).

A stand-alone version of the driver, along with complete a ChangeLog,
can be found at: 

	http://web.mit.edu/tytso/www/linux/serial/

After this driver goes through more shakedown and testing, I tend to ask
that it be also included into the next Linux 2.2 stable kernel as a
driver refresh, as this fixes a number of bugs which also affect the
Linux 2.2 serial driver.

						- Ted


Patch generated: on Thu Jan 27 16:10:09 EST 2000 by tytso@universal.thunk.org
against Linux version 2.3.40
 
===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c	2000/01/26 21:27:57	1.1
+++ drivers/char/serial.c	2000/01/27 18:57:44
@@ -44,8 +44,8 @@
  *	int rs_init(void);
  */
 
-static char *serial_version = "4.91";
-static char *serial_revdate = "1999-11-17";
+static char *serial_version = "4.92";
+static char *serial_revdate = "2000-1-27";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -74,12 +74,10 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
-#include <linux/sysrq.h>
 
 #undef SERIAL_PARANOIA_CHECK
 #define CONFIG_SERIAL_NOPAUSE_IO
 #define SERIAL_DO_RESTART
-#define CONFIG_SERIAL_PCI_MEMMAPPED
 
 #if 0
 /* These defines are normally controlled by the autoconf.h */
@@ -100,6 +98,12 @@
 #endif
 #endif
 
+#ifdef CONFIG_ISAPNP
+#ifndef ENABLE_SERIAL_PNP
+#define ENABLE_SERIAL_PNP
+#endif
+#endif
+
 /* Set of debugging defines */
 
 #undef SERIAL_DEBUG_INTR
@@ -133,31 +137,13 @@
 #define SERIAL_INLINE
 #endif
   
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
-#else
-#define DBG_CNT(s)
-#endif
-
 /*
  * End of serial driver configuration section.
  */
 
-#define NEW_MODULES
-#ifdef LOCAL_HEADERS		/* We're building standalone */
-#define MODULE
-#endif
-
-#ifdef NEW_MODULES
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
-#else /* !NEW_MODULES */
-#ifdef MODVERSIONS
-#define MODULE
-#endif
-#endif /* NEW_MODULES */
 #include <linux/module.h>
 
 #include <linux/types.h>
@@ -198,13 +184,19 @@
 #ifdef ENABLE_SERIAL_PCI
 #include <linux/pci.h>
 #endif
+#ifdef ENABLE_SERIAL_PNP
+#include <linux/isapnp.h>
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
 
 /*
  * All of the compatibilty code so we can compile serial.c against
  * older kernels is hidden in serial_compat.h
  */
-#if (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
-#include "serial_compat.h"	
+#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#include "serial_compat.h"
 #endif
 
 #include <asm/system.h>
@@ -276,7 +268,7 @@
 		  UART_STARTECH }, 
 	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
 	{ "Startech", 1, 0},	/* usurped by cyclades.c */
-	{ "16C950", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
 	{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
 		  UART_STARTECH }, 
 	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
@@ -290,16 +282,35 @@
 
 #define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
 
-#ifdef ENABLE_SERIAL_PCI
+#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
 #define NR_PCI_BOARDS	8
+#ifdef MODULE
+/* We don't unregister PCI boards right now */
 static struct pci_board_inst	serial_pci_board[NR_PCI_BOARDS];
 static int serial_pci_board_idx = 0;
-#ifdef PCI_NUM_RESOURCES
+#endif
+#ifndef PCI_BASE_ADDRESS
 #define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
-#else
-#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r])
+#define PCI_BASE_REGION_SIZE(dev, r) ((dev)->resource[r].end - \
+				      (dev)->resource[r].start)
+#define IS_PCI_REGION_IOPORT(dev, r) ((dev)->resource[r].flags & \
+				      IORESOURCE_IO)
+#endif
+#ifndef PCI_IRQ_RESOURCE
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
+#endif
+#ifndef pci_get_subvendor
+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
+#define pci_get_subdevice(dev)  ((dev)->subsystem_device)
+#endif
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP  */
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev)  (dev->prepare)
+#define ACTIVATE_FUNC(dev)  (dev->activate)
+#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
 #endif
-#endif	/* ENABLE_SERIAL_PCI  */
+	
 
 static struct tty_struct *serial_table[NR_PORTS];
 static struct termios *serial_termios[NR_PORTS];
@@ -309,6 +320,13 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the copy_from_user blocks while swapping in a page,
@@ -355,11 +373,9 @@
 		outb(info->hub6 - 1 + offset, info->port);
 		return inb(info->port+1);
 #endif
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	case SERIAL_IO_MEM:
 		return readb(info->iomem_base +
 			     (offset<<info->iomem_reg_shift));
-#endif
 #ifdef CONFIG_SERIAL_GSC
 	case SERIAL_IO_GSC:
 		return gsc_readb(info->iomem_base + offset);
@@ -379,12 +395,10 @@
 		outb(value, info->port+1);
 		break;
 #endif
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	case SERIAL_IO_MEM:
 		writeb(value, info->iomem_base +
 			      (offset<<info->iomem_reg_shift));
 		break;
-#endif
 #ifdef CONFIG_SERIAL_GSC
 	case SERIAL_IO_GSC:
 		gsc_writeb(value, info->iomem_base + offset);
@@ -905,11 +919,16 @@
 			continue;
 
 		info = IRQ_ports[irq];
+		/*
+		 * The user was a bonehead, and misconfigured their
+		 * multiport info.  Rather than lock up the kernel
+		 * in an infinite loop, if we loop too many times,
+		 * print a message and break out of the loop.
+		 */
 		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 1
-			printk("rs_multi loop break\n");
-#endif
-			break; 	/* Prevent infinite loops */
+			printk("Misconfigured multiport serial info "
+			       "for irq %d.  Breaking out irq loop\n", irq);
+			break; 
 		}
 		if (multi->port_monitor)
 			printk("rs port monitor irq %d: 0x%x, 0x%x\n",
@@ -1540,6 +1559,15 @@
 	/* As a last resort, if the quotient is zero, default to 9600 bps */
 	if (!quot)
 		quot = baud_base / 9600;
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+	    (info->state->revision == 0x5202))
+		quot++;
+	
 	info->quot = quot;
 	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
@@ -2090,6 +2118,8 @@
 		if (arg & TIOCM_OUT2)
 			info->MCR |= UART_MCR_OUT2;
 #endif
+		if (arg & TIOCM_LOOP)
+			info->MCR |= UART_MCR_LOOP;
 		break;
 	case TIOCMBIC:
 		if (arg & TIOCM_RTS)
@@ -2102,6 +2132,8 @@
 		if (arg & TIOCM_OUT2)
 			info->MCR &= ~UART_MCR_OUT2;
 #endif
+		if (arg & TIOCM_LOOP)
+			info->MCR &= ~UART_MCR_LOOP;
 		break;
 	case TIOCMSET:
 		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
@@ -2109,12 +2141,14 @@
 					    UART_MCR_OUT1 |
 					    UART_MCR_OUT2 |
 #endif
+					    UART_MCR_LOOP |
 					    UART_MCR_DTR))
 			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
 #ifdef TIOCM_OUT1
 			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
 			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
 #endif
+			     | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
 			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
 		break;
 	default:
@@ -2579,6 +2613,7 @@
 		return;
 	}
 	info->flags |= ASYNC_CLOSING;
+	restore_flags(flags);
 	/*
 	 * Save the termios structure, since this port may have
 	 * separate termios for callout and dialin.
@@ -2630,7 +2665,6 @@
 			 ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
-	restore_flags(flags);
 }
 
 /*
@@ -2712,6 +2746,8 @@
 	state = info->state;
 	
 	rs_flush_buffer(tty);
+	if (info->flags & ASYNC_CLOSING)
+		return;
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
@@ -2884,10 +2920,8 @@
 	info->port = sstate->port;
 	info->flags = sstate->flags;
 	info->io_type = sstate->io_type;
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	info->iomem_base = sstate->iomem_base;
 	info->iomem_reg_shift = sstate->iomem_reg_shift;
-#endif
 	info->xmit_fifo_size = sstate->xmit_fifo_size;
 	info->line = line;
 	info->tqueue.routine = do_softint;
@@ -3123,43 +3157,47 @@
  * number, and identifies which options were configured into this
  * driver.
  */
-static _INLINE_ void show_serial_version(void)
-{
- 	printk(KERN_INFO "%s version %s%s (%s) with", serial_name,
-	       serial_version, LOCAL_VERSTRING, serial_revdate);
+static char serial_options[] __initdata =
 #ifdef CONFIG_HUB6
-	printk(" HUB-6");
+       " HUB-6"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_MANY_PORTS
-	printk(" MANY_PORTS");
+       " MANY_PORTS"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_MULTIPORT
-	printk(" MULTIPORT");
+       " MULTIPORT"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_SHARE_IRQ
-	printk(" SHARE_IRQ");
+       " SHARE_IRQ"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-	printk(" DETECT_IRQ");
+       " DETECT_IRQ"
 #define SERIAL_OPT
 #endif
 #ifdef ENABLE_SERIAL_PCI
-	printk(" SERIAL_PCI");
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
-	printk(" PCI_IOMEM");
+       " SERIAL_PCI"
+#define SERIAL_OPT
 #endif
+#ifdef ENABLE_SERIAL_PNP
+       " ISAPNP"
 #define SERIAL_OPT
 #endif
 #ifdef SERIAL_OPT
-	printk(" enabled\n");
+       " enabled\n";
 #else
-	printk(" no serial options enabled\n");
+       " no serial options enabled\n";
 #endif
 #undef SERIAL_OPT
+
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+	       serial_version, LOCAL_VERSTRING, serial_revdate,
+	       serial_options);
 }
 
 /*
@@ -3188,11 +3226,15 @@
 	}
 #endif
 	scr_info.magic = SERIAL_MAGIC;
+	scr_info.state = state;
 	scr_info.port = state->port;
 	scr_info.flags = state->flags;
 #ifdef CONFIG_HUB6
 	scr_info.hub6 = state->hub6;
 #endif
+	scr_info.io_type = state->io_type;
+	scr_info.iomem_base = state->iomem_base;
+	scr_info.iomem_reg_shift = state->iomem_reg_shift;
 
 	/* forget possible initially masked and pending IRQ */
 	probe_irq_off(probe_irq_on());
@@ -3296,7 +3338,8 @@
 		    (scratch3 == 0x50 || scratch3 == 0x52 ||
 		     scratch3 == 0x54)) {
 			state->type = PORT_16C950;
-			state->revision = serial_icr_read(info, UART_REV);
+			state->revision = serial_icr_read(info, UART_REV) |
+				(scratch3 << 8);
 			return;
 		}
 	}
@@ -3367,10 +3410,8 @@
 	info->hub6 = state->hub6;
 #endif
 	info->io_type = state->io_type;
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	info->iomem_base = state->iomem_base;
 	info->iomem_reg_shift = state->iomem_reg_shift;
-#endif
 
 	save_flags(flags); cli();
 	
@@ -3536,18 +3577,151 @@
 };
 #endif
 
+
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) 
+
+static void __init printk_pnp_dev_id(unsigned short vendor,
+				     unsigned short device)
+{
+	printk("%c%c%c%x%x%x%x",
+	       'A' + ((vendor >> 2) & 0x3f) - 1,
+	       'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+	       'A' + ((vendor >> 8) & 0x1f) - 1,
+	       (device >> 4) & 0x0f,
+	       device & 0x0f,
+	       (device >> 12) & 0x0f,
+	       (device >> 8) & 0x0f);
+}
+
+static _INLINE_ int get_pci_port(struct pci_dev *dev,
+				  struct pci_board *board,
+				  struct serial_struct *state,
+				  int idx)
+{
+	unsigned long port;
+	int base_idx;
+	int max_port;
+
+	base_idx = SPCI_FL_GET_BASE(board->flags);
+	if (board->flags & SPCI_FL_BASE_TABLE)
+		base_idx += idx;
+
+	if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+		max_port = PCI_BASE_REGION_SIZE(dev, base_idx) / 8;
+		if (idx >= max_port)
+			return 1;
+	}
+			
+	port = PCI_BASE_ADDRESS(dev, base_idx) + board->first_uart_offset;
+
+	if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+		port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+	if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
+		state->port = port;
+		return 0;
+	}
+	state->io_type = SERIAL_IO_MEM;
+	state->iomem_base = ioremap(port, board->uart_offset);
+	state->iomem_reg_shift = board->reg_shift;
+	state->port = 0;
+	return 0;
+}
+
+static _INLINE_ int get_pci_irq(struct pci_dev *dev,
+				struct pci_board *board,
+				int idx)
+{
+	int base_idx;
+
+	if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
+		return dev->irq;
+
+	base_idx = SPCI_FL_GET_IRQBASE(board->flags);
+	if (board->flags & SPCI_FL_IRQ_TABLE)
+		base_idx += idx;
+	
+	return PCI_IRQ_RESOURCE(dev, base_idx);
+}
+
+/*
+ * Common enabler code shared by both PCI and ISAPNP probes
+ */
+static void __init start_pci_pnp_board(struct pci_dev *dev,
+				       struct pci_board *board)
+{
+	int k, line;
+	struct serial_struct fake_state;
+	int base_baud;
+
+       if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+	       printk("SERIAL: PNP device '");
+	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk("' prepare failed\n");
+	       return;
+       }
+
+       if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+	       printk("SERIAL: PNP device '");
+	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk("' activate failed\n");
+	       return;
+       }
+
+	/*
+	 * Run the initialization function, if any
+	 */
+	if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
+		return;
+
+#ifdef MODULE
+	/*
+	 * Register the serial board in the array if we need to
+	 * shutdown the board on a module unload.
+	 */
+	if (DEACTIVATE_FUNC(dev) || board->init_fn) {
+		if (serial_pci_board_idx >= NR_PCI_BOARDS)
+			return;
+		serial_pci_board[serial_pci_board_idx].board = *board;
+		serial_pci_board[serial_pci_board_idx].dev = dev;
+		serial_pci_board_idx++;
+	}
+#endif
+
+	base_baud = board->base_baud;
+	if (!base_baud)
+		base_baud = BASE_BAUD;
+	memset(&fake_state, 0, sizeof(fake_state));
+
+	for (k=0; k < board->num_ports; k++) {
+		fake_state.irq = get_pci_irq(dev, board, k);
+		if (get_pci_port(dev, board, &fake_state, k))
+			break;
+		fake_state.flags = ASYNC_SKIP_TEST;
+#ifdef SERIAL_DEBUG_PCI
+		printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
+		       fake_state.port, fake_state.irq, fake_state.io_type);
+#endif
+		line = register_serial(&fake_state);
+		if (line < 0)
+			break;
+		rs_table[line].baud_base = base_baud;
+	}
+}
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+
 #ifdef ENABLE_SERIAL_PCI
 /*
  * Some PCI serial cards using the PLX 9050 PCI interface chip require
  * that the card interrupt be explicitly enabled or disabled.  This
  * seems to be mainly needed on card using the PLX which also use I/O
  * mapped memory.
- * 
- * Note that __init is a no-op if MODULE is defined; we depend on this.
  */
-static int __init pci_plx9050_fn(struct pci_dev *dev,
-				  struct pci_board *board,
-				  int enable)
+static int
+#ifndef MODULE
+__init
+#endif
+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
 	u8 data, *p, scratch;
 
@@ -3559,7 +3733,7 @@
 	
 	/* enable/disable interrupts */
 	p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
-	if (board->vendor == PCI_VENDOR_ID_PANACOM) {
+	if (dev->vendor == PCI_VENDOR_ID_PANACOM) {
 		scratch = readl(p + 0x4c);
 		if (enable)
 			scratch |= 0x40;
@@ -3598,9 +3772,11 @@
 #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
 
-static int __init pci_siig10x_fn(struct pci_dev *dev,
-                                 struct pci_board *board,
-                                 int enable)
+static int
+#ifndef MODULE
+__init
+#endif
+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u16 data, *p;
 
@@ -3628,9 +3804,11 @@
 #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
 
-static int __init pci_siig20x_fn(struct pci_dev *dev,
-                                 struct pci_board *board,
-                                 int enable)
+static int
+#ifndef MODULE
+__init
+#endif
+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u8 data;
 
@@ -3649,11 +3827,12 @@
        return 0;
 }
 
+
 /*
  * This is the configuration table for all of the PCI serial boards
  * which we support.
  */
-static struct pci_board pci_boards[] = {
+static struct pci_board pci_boards[] __initdata = {
 	/*
 	 * Vendor ID, 	Device ID,
 	 * Subvendor ID,	Subdevice ID,
@@ -3752,7 +3931,7 @@
 	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 		PCI_SUBVENDOR_ID_KEYSPAN,
 		PCI_SUBDEVICE_ID_KEYSPAN_SX2,
-		SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600,
+		SPCI_FL_BASE2, 2, 921600, /* IOMEM */
 		0x400, 7, pci_plx9050_fn },
 	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
 		PCI_ANY_ID, PCI_ANY_ID,
@@ -3798,18 +3977,47 @@
 	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE1, 8, 115200 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-		SPCI_FL_BASE0 , 4, 115200 },
 	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
 		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
 		SPCI_FL_BASE0 , 4, 921600 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 , 4, 115200 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 , 2, 115200 },
+		/* This board uses the size of PCI Base region 0 to
+		 * signal now many ports are available */
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 },
 	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE0 , 2, 921600 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_SERIAL,
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 },
 	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE2, 1, 460800,
@@ -3945,60 +4153,105 @@
 	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-		SPCI_FL_IOMEM | SPCI_FL_BASE0, 4, 921600,
+		SPCI_FL_BASE0, 4, 921600, /* IOMEM */
 		0x40, 2, NULL, 0x200 },
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-		SPCI_FL_IOMEM | SPCI_FL_BASE0, 8, 921600,
+		SPCI_FL_BASE0, 8, 921600, /* IOMEM */
 		0x40, 2, NULL, 0x200 },
 	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
 		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-		SPCI_FL_IOMEM | SPCI_FL_BASE0, 6, 921600,
+		SPCI_FL_BASE0, 6, 921600, /* IOMEM */
 		0x40, 2, NULL, 0x200 },
-	/*
-	 * Untested PCI modems, sent in from various folks...
-	 */
-	/* at+t zoom 56K faxmodem, from dougd@shieldsbag.com */	
-	{	PCI_VENDOR_ID_ATT, 0x442,
+	/* Digitan DS560-558, from jimd@esoft.com */
+	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
 		PCI_ANY_ID, PCI_ANY_ID,
 		SPCI_FL_BASE1, 1, 115200 },
-	/* at&t unknown modem, from jimd@esoft.com */
-	{	PCI_VENDOR_ID_ATT, 0x480,
+	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+	{	PCI_VENDOR_ID_USR, 0x1008,
 		PCI_ANY_ID, PCI_ANY_ID,
-		SPCI_FL_BASE1, 1, 115200 },
+		SPCI_FL_BASE0, 1, 115200 },
+	/*
+	 * Untested PCI modems, sent in from various folks...
+	 */
 	/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
 	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
 		0x1048, 0x1500, 
 		SPCI_FL_BASE1, 1, 115200 },
-	/* 3Com US Robotics 56k* Voice Internal PCI, model# 2884 */
-	/* from evidal@iti.upv.es */
-	/* XXX complete guess this may not work!!! */
-	{	PCI_VENDOR_ID_USR, 0x1006,
-		0x12b9, 0x0060,
-		SPCI_FL_BASE1 | SPCI_FL_IOMEM, 1, 115200 },
-	{	0, }
+	/* Generic serial board */
+	{	0, 0,
+		0, 0,
+		SPCI_FL_BASE0, 1, 115200 },
 };
 
 /*
+ * Given a complete unknown PCI device, try to use some hueristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int _INLINE_ serial_guess_board(struct pci_dev *dev,
+				       struct pci_board *board)
+{
+	int	num_iomem = 0, num_port = 0, first_port = -1;
+	int	i;
+	
+	/*
+	 * If it is not a communications device or the programming
+	 * interface is greater than 6, give up.
+	 *
+	 * (Should we try to make guesses for multiport serial devices
+	 * later?) 
+	 */
+	if ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL ||
+	    (dev->class & 0xff) > 6)
+		return 1;
+
+	for (i=0; i < 6; i++) {
+		if (IS_PCI_REGION_IOPORT(dev, i)) {
+			num_port = 0;
+			if (first_port == -1)
+				first_port = i;
+		} else {
+			num_iomem++;
+		}
+	}
+
+	/*
+	 * If there is 1 or 0 iomem regions, and exactly one port, use
+	 * it.
+	 */
+	if (num_iomem <= 1 && num_port == 1) {
+		board->flags = first_port;
+		return 0;
+	}
+	return 1;
+}
+
+
+
+/*
  * Query PCI space for known serial boards
  * If found, add them to the PCI device space in rs_table[]
  *
  * Accept a maximum of eight boards
  *
  */
-static void probe_serial_pci(void) 
+static void __init probe_serial_pci(void) 
 {
-	int k, line;
 	struct pci_dev *dev = NULL;
 	struct pci_board *board;
-	struct serial_struct fake_state;
-	int uart_offset, base_baud, base_idx;
-	unsigned long port;
 
 #ifdef SERIAL_DEBUG_PCI
 	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
 #endif
   
+	if (!pcibios_present()) {
+#ifdef SERIAL_DEBUG_PCI
+		printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
+#endif
+		return;
+	}
+
 	pci_for_each_dev(dev) {
 		for (board = pci_boards; board->vendor; board++) {
 			if (board->vendor != (unsigned short) PCI_ANY_ID &&
@@ -4008,121 +4261,87 @@
 			    dev->device != board->device)
 				continue;
 			if (board->subvendor != (unsigned short) PCI_ANY_ID &&
-			    dev->subsystem_vendor != board->subvendor)
+			    pci_get_subvendor(dev) != board->subvendor)
 				continue;
 			if (board->subdevice != (unsigned short) PCI_ANY_ID &&
-			    dev->subsystem_device != board->subdevice)
+			    pci_get_subdevice(dev) != board->subdevice)
 				continue;
 			break;
 		}
 	
-		if (board->vendor == 0) {
+		if (board->vendor == 0 && serial_guess_board(dev, board))
+			continue;
+		
+		start_pci_pnp_board(dev, board);
+	}
+	
 #ifdef SERIAL_DEBUG_PCI
-		printk(KERN_DEBUG
-		       "Found unknown serial board: %x:%x, %x:%x, %x\n",
-		       dev->vendor, dev->device, subvendor, subdevice,
-		       dev->class);
-		printk(KERN_DEBUG
-		       "   Addresses: %lx, %lx, %lx, %lx\n",
-		       PCI_BASE_ADDRESS(dev, 0), PCI_BASE_ADDRESS(dev, 1), 
-		       PCI_BASE_ADDRESS(dev, 2), PCI_BASE_ADDRESS(dev, 3));
+	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
 #endif
-			continue; 
-		}
+	return;
+}
 
-		/*
-		 * Run the initialization function, if any
-		 */
-		if (board->init_fn)
-			if ((board->init_fn)(dev, board, 1) != 0)
-				continue;
+#endif /* ENABLE_SERIAL_PCI */
 
-		/*
-		 * Register the serial board in the array so we can
-		 * shutdown the board later, if necessary.
-		 */
-		if (serial_pci_board_idx >= NR_PCI_BOARDS)
-			continue;
-		serial_pci_board[serial_pci_board_idx].board = board;
-		serial_pci_board[serial_pci_board_idx].dev = dev;
-		serial_pci_board_idx++;
+#ifdef ENABLE_SERIAL_PNP
 
-		base_idx = board->flags & SPCI_FL_BASE_MASK;
-		port = PCI_BASE_ADDRESS(dev, base_idx) +
-			board->first_uart_offset;
-		if (board->flags & SPCI_FL_IOMEM)
-			port &= PCI_BASE_ADDRESS_MEM_MASK;
-		else
-			port &= PCI_BASE_ADDRESS_IO_MASK;
+static struct pci_board pnp_devices[] __initdata = {
+	/* Rockwell 56K ACF II Fax+Data+Voice Modem */
+	{	ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Boca Research 33,600 ACF Modem */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Best Data Products Inc. Smart One 336F PnP Modem */
+	{	ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* These ID's are taken from M$ documentation */
+	/* Compaq 14400 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Compaq 2400/9600 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Generic standard PC COM port	 */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Generic 16550A-compatible COM port */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	{	0, }
+};
 
-		/*
-		 * Set some defaults for the loop below, which 
-		 * actually registers each serial port belonging to
-		 * the card.
-		 */
-		uart_offset = board->uart_offset;
-		if (!uart_offset)
-			uart_offset = 8;
-		base_baud = board->base_baud;
-		if (!base_baud)
-			base_baud = BASE_BAUD;
-#ifndef CONFIG_SERIAL_PCI_MEMMAPPED
-		if (board->flags & SPCI_FL_IOMEM) {
-#ifdef SERIAL_DEBUG_PCI
-			printk(KERN_DEBUG
-		           "Can't support memory mapped PCI serial device\n");
+static void __init probe_serial_pnp(void)
+{
+       struct pci_dev *dev = NULL;
+       struct pci_board *board;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Entered probe_serial_pnp()\n");
 #endif
-			continue; 
-		}
+       if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+               printk("Leaving probe_serial_pnp() (no isapnp)\n");
 #endif
-		memset(&fake_state, 0, sizeof(fake_state));
+               return;
+       }
 
-#ifdef SERIAL_DEBUG_PCI
-		printk(KERN_DEBUG
-		       "Found Serial PCI device: %x:%x, %x:%x, %x\n",
-		       dev->vendor, dev->device, subvendor, subdevice,
-		       dev->class);
-		printk(KERN_DEBUG
-		       "   IRQ: %d, base: %lx (%s), num_ports: %d\n",
-		       dev->irq, port, board->flags & SPCI_FL_IOMEM ?
-		       "iomem" : "port", board->num_ports);
-#endif
+       for (board = pnp_devices; board->vendor; board++) {
+               while ((dev = isapnp_find_dev(NULL, board->vendor,
+					     board->device, dev))) {
+
+		       start_pci_pnp_board(dev, board);
 		       
-		for (k=0; k < board->num_ports; k++) {
-			if (board->flags & SPCI_FL_BASE_TABLE) {
-				port = PCI_BASE_ADDRESS(dev, base_idx++);
-				if (board->flags & SPCI_FL_IOMEM)
-					port &= PCI_BASE_ADDRESS_MEM_MASK;
-				else
-					port &= PCI_BASE_ADDRESS_IO_MASK;
-			}
-			fake_state.irq = dev->irq;
-			fake_state.port = port;
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
-			if (board->flags & SPCI_FL_IOMEM) {
-				fake_state.io_type = SERIAL_IO_MEM;
-				fake_state.iomem_base =
-					ioremap(port, board->uart_offset);
-				fake_state.iomem_reg_shift = board->reg_shift;
-				fake_state.port = 0;
-			}
-#endif
-			port += uart_offset;
-			fake_state.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-			line = register_serial(&fake_state);
-			if (line < 0)
-				break;
-			rs_table[line].baud_base = base_baud;
-		}
-	}
-	
-#ifdef SERIAL_DEBUG_PCI
-	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+               }
+       }
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Leaving probe_serial_pnp() (probe finished)\n");
 #endif
-	return;
+       return;
 }
 
-#endif /* ENABLE_SERIAL_PCI */
+#endif /* ENABLE_SERIAL_PNP */
 
 /*
  * The serial driver boot-time initialization code!
@@ -4270,6 +4489,9 @@
 #ifdef ENABLE_SERIAL_PCI
 	probe_serial_pci();
 #endif
+#ifdef ENABLE_SERIAL_PNP
+       probe_serial_pnp();
+#endif
 	return 0;
 }
 
@@ -4282,6 +4504,7 @@
 	int i;
 	unsigned long flags;
 	struct serial_state *state;
+	struct async_struct *info;
 
 	save_flags(flags);
 	cli();
@@ -4311,13 +4534,17 @@
 	state->port = req->port;
 	state->flags = req->flags;
 	state->io_type = req->io_type;
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	state->iomem_base = req->iomem_base;
 	state->iomem_reg_shift = req->iomem_reg_shift;
-#endif
 	if (req->baud_base)
 		state->baud_base = req->baud_base;
-
+	if ((info = state->info) != NULL) {
+		info->port = req->port;
+		info->flags = req->flags;
+		info->io_type = req->io_type;
+		info->iomem_base = req->iomem_base;
+		info->iomem_reg_shift = req->iomem_reg_shift;
+	}
 	autoconfig(state);
 	if (state->type == PORT_UNKNOWN) {
 		restore_flags(flags);
@@ -4387,17 +4614,20 @@
 		}
 		if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port)
 			release_region(rs_table[i].port, 8);
-#if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED)
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
 		if (rs_table[i].iomem_base)
 			iounmap(rs_table[i].iomem_base);
 #endif
 	}
-#ifdef ENABLE_SERIAL_PCI
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
 	for (i=0; i < serial_pci_board_idx; i++) {
 		struct pci_board_inst *brd = &serial_pci_board[i];
 		
-		if (brd->board->init_fn)
-			(brd->board->init_fn)(brd->dev, brd->board, 0);
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
 	}
 #endif	
 	if (tmp_buf) {
@@ -4599,10 +4829,8 @@
 	info->hub6 = state->hub6;
 #endif
 	info->io_type = state->io_type;
-#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
 	info->iomem_base = state->iomem_base;
 	info->iomem_reg_shift = state->iomem_reg_shift;
-#endif
 	quot = state->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
 #if defined(__powerpc__) || defined(__alpha__)
===================================================================
RCS file: include/linux/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial.h
--- include/linux/serial.h	2000/01/26 21:27:57	1.1
+++ include/linux/serial.h	2000/01/27 18:57:44
@@ -38,20 +38,6 @@
 #define ASYNC_CLOSING_WAIT_NONE	65535
 
 /*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Counters of the input lines (CTS, DSR, RI, CD) interrupts
- */
-struct async_icount {
-	__u32	cts, dsr, rng, dcd, tx, rx;
-	__u32	frame, parity, overrun, brk;
-	__u32	buf_overrun;
-};
-
-/*
  * These are the supported serial types.
  */
 #define PORT_UNKNOWN	0
===================================================================
RCS file: include/linux/RCS/serial_reg.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial_reg.h
===================================================================
RCS file: include/linux/RCS/serialP.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serialP.h
--- include/linux/serialP.h	2000/01/26 21:27:57	1.1
+++ include/linux/serialP.h	2000/01/27 18:57:44
@@ -19,11 +19,18 @@
  * For definitions of the flags field, see tty.h
  */
 
-#include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
 
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+	__u32	cts, dsr, rng, dcd, tx, rx;
+	__u32	frame, parity, overrun, brk;
+	__u32	buf_overrun;
+};
 
 struct serial_state {
 	int	magic;
@@ -158,7 +165,7 @@
 };
 
 struct pci_board_inst {
-	struct pci_board	*board;
+	struct pci_board	board;
 	struct pci_dev		*dev;
 };
 
@@ -172,7 +179,28 @@
 #define SPCI_FL_BASE2	0x0002
 #define SPCI_FL_BASE3	0x0003
 #define SPCI_FL_BASE4	0x0004
-#define SPCI_FL_IOMEM		0x0008 /* Use I/O mapped memory */
-#define SPCI_FL_BASE_TABLE	0x0010 /* Use base address table for UART */
+#define SPCI_FL_GET_BASE(x)	(x & SPCI_FL_BASE_MASK)
 
+#define SPCI_FL_IRQ_MASK       (0x0007 << 4)
+#define SPCI_FL_IRQBASE0       (0x0000 << 4)
+#define SPCI_FL_IRQBASE1       (0x0001 << 4)
+#define SPCI_FL_IRQBASE2       (0x0002 << 4)
+#define SPCI_FL_IRQBASE3       (0x0003 << 4)
+#define SPCI_FL_IRQBASE4       (0x0004 << 4)
+#define SPCI_FL_GET_IRQBASE(x)        ((x & SPCI_FL_IRQ_MASK) >> 4)
+	
+/* Use sucessiveentries base resource table */
+#define SPCI_FL_BASE_TABLE	0x0100
+	
+/* Use successive entries in the irq resource table */
+#define SPCI_FL_IRQ_TABLE	0x0200
+	
+/* Use the irq resource table instead of dev->irq */
+#define SPCI_FL_IRQRESOURCE	0x0400
+
+/* Use the Base address register size to cap number of ports */
+#define SPCI_FL_REGION_SZ_CAP	0x0800
+	
+#define SPCI_FL_PNPDEFAULT	(SPCI_FL_IRQRESOURCE)
+	
 #endif /* _LINUX_SERIAL_H */
===================================================================
RCS file: include/linux/RCS/pci_ids.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci_ids.h
--- include/linux/pci_ids.h	2000/01/27 16:36:06	1.1
+++ include/linux/pci_ids.h	2000/01/27 17:00:17
@@ -828,6 +828,7 @@
 
 #define PCI_VENDOR_ID_ATT		0x11c1
 #define PCI_DEVICE_ID_ATT_L56XMF	0x0440
+#define PCI_DEVICE_ID_ATT_VENUS_MODEM	0x480
 
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
 #define PCI_DEVICE_ID_SPECIALIX_IO8	0x2000
@@ -1019,7 +1020,15 @@
 #define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
 
 #define PCI_VENDOR_ID_LAVA		0x1407
-#define PCI_DEVICE_ID_LAVA_DUAL_SERIAL	0x0100
+#define PCI_DEVICE_ID_LAVA_DSERIAL	0x0100 /* 2x 16550 */
+#define PCI_DEVICE_ID_LAVA_QUATRO_A	0x0101 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUATRO_B	0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS	0x0200 /* 2x 16650 */
+#define PCI_DEVICE_ID_LAVA_QUAD_A	0x0201 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUAD_B	0x0202 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_SSERIAL	0x0500 /* 1x 16550 */
+#define PCI_DEVICE_ID_LAVA_PORT_650	0x0600 /* 1x 16650 */
+
 #define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
@@ -1030,6 +1039,8 @@
 
 #define PCI_VENDOR_ID_OXSEMI            0x1415
 #define PCI_DEVICE_ID_OXSEMI_16PCI954   0x9501
+#define PCI_DEVICE_ID_OXSEMI_16PCI952	0x950A
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N	0x9511
 
 #define PCI_VENDOR_ID_PANACOM		0x14d4
 #define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
===================================================================
RCS file: include/asm-i386/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/serial.h
===================================================================
RCS file: include/asm-i386/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/termios.h
--- include/asm-i386/termios.h	2000/01/26 21:27:57	1.1
+++ include/asm-i386/termios.h	2000/01/26 21:28:01
@@ -35,6 +35,7 @@
 #define TIOCM_RI	TIOCM_RNG
 #define TIOCM_OUT1	0x2000
 #define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
===================================================================
RCS file: include/asm-alpha/RCS/ioctls.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-alpha/ioctls.h
--- include/asm-alpha/ioctls.h	2000/01/26 21:27:57	1.1
+++ include/asm-alpha/ioctls.h	2000/01/26 21:28:01
@@ -61,6 +61,9 @@
 # define TIOCM_DSR	0x100
 # define TIOCM_CD	TIOCM_CAR
 # define TIOCM_RI	TIOCM_RNG
+# define TIOCM_OUT1	0x2000
+# define TIOCM_OUT2	0x4000
+# define TIOCM_LOOP	0x8000
 
 #define TIOCGSOFTCAR	0x5419
 #define TIOCSSOFTCAR	0x541A
===================================================================
RCS file: include/asm-m68k/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-m68k/termios.h
--- include/asm-m68k/termios.h	2000/01/26 21:27:57	1.1
+++ include/asm-m68k/termios.h	2000/01/26 21:28:01
@@ -43,6 +43,9 @@
 #define TIOCM_DSR	0x100
 #define TIOCM_CD	TIOCM_CAR
 #define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
===================================================================
RCS file: include/asm-mips/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-mips/termios.h
--- include/asm-mips/termios.h	2000/01/26 21:27:57	1.1
+++ include/asm-mips/termios.h	2000/01/26 21:28:01
@@ -83,6 +83,7 @@
 #define TIOCM_DSR	0x400		/* data set ready */
 #define TIOCM_OUT1	0x2000
 #define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* line disciplines */
 #define N_TTY		0
===================================================================
RCS file: include/asm-arm/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-arm/termios.h
--- include/asm-arm/termios.h	2000/01/26 21:27:57	1.1
+++ include/asm-arm/termios.h	2000/01/26 21:28:01
@@ -45,6 +45,7 @@
 #define TIOCM_RI	TIOCM_RNG
 #define TIOCM_OUT1	0x2000
 #define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
===================================================================
RCS file: include/asm-sh/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-sh/termbits.h
===================================================================
RCS file: include/asm-ppc/RCS/termios.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-ppc/termios.h
--- include/asm-ppc/termios.h	2000/01/26 21:27:57	1.1
+++ include/asm-ppc/termios.h	2000/01/26 21:28:01
@@ -166,6 +166,9 @@
 #define TIOCM_DSR	0x100
 #define TIOCM_CD	TIOCM_CAR
 #define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
===================================================================
RCS file: include/asm-sparc/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-sparc/termbits.h
--- include/asm-sparc/termbits.h	2000/01/26 21:27:57	1.1
+++ include/asm-sparc/termbits.h	2000/01/26 21:28:01
@@ -203,6 +203,9 @@
 #define TIOCM_DSR	0x100
 #define TIOCM_CD	TIOCM_CAR
 #define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
===================================================================
RCS file: include/asm-sparc64/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-sparc64/termbits.h
--- include/asm-sparc64/termbits.h	2000/01/26 21:27:57	1.1
+++ include/asm-sparc64/termbits.h	2000/01/26 21:28:01
@@ -204,6 +204,9 @@
 #define TIOCM_DSR	0x100
 #define TIOCM_CD	TIOCM_CAR
 #define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
 
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/