PATCH: Update for the serial driver.

tytso@mit.edu
Tue, 31 Aug 1999 15:40:42 -0400


Hi Linus,

Enclosed please find updates to the serial driver versus Linux
2.3.15. This driver adds support for PCI serial boards, and the
following new UART's: Oxford Semiconductor 16C950, the StarTech 16854,
and the StarTech 16654.

I've coordinated various PCI patches from Otto Moerbeck, Henning
Schmiedehausen, Stuart MacDonald (from Connect Tech) and others, and the
merged driver has been tested by a number of folks before I've submitted
it to you. I therefore expect it to be BugFree(tm), although some
further updates to support additional PCI serial boards may be coming in
the next couple of weeks.

I'd appreciate it if you would merge this into the 2.3 kernel tree.
Thanks!!

- Ted

Patch generated: on Tue Aug 31 15:21:46 EDT 1999 by tytso@snap.thunk.org
against Linux version 2.3.15

===================================================================
RCS file: drivers/char/RCS/serial.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/serial.c
--- drivers/char/serial.c 1999/08/28 19:56:42 1.1
+++ drivers/char/serial.c 1999/08/31 18:58:45
@@ -2,6 +2,8 @@
* linux/drivers/char/serial.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
+ * 1998, 1999 Theodore Ts'o
*
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
@@ -32,6 +34,11 @@
* 4/98: Added changes to support the ARM architecture proposed by
* Russell King
*
+ * 5/99: Updated to include support for the XR16C850 and ST16C654
+ * uarts. Stuart MacDonald <stuartm@connecttech.com>
+ *
+ * 8/99: Generalized PCI support added. Theodore Ts'o
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -62,13 +69,16 @@
* ever possible.
*/

+#include <linux/config.h>
+#include <linux/version.h>
+
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
+#define CONFIG_SERIAL_PCI_MEMMAPPED

#if 0
-/* Normally these defines are controlled by the autoconf.h */
-
+/* These defines are normally controlled by the autoconf.h */
#define CONFIG_SERIAL_MANY_PORTS
#define CONFIG_SERIAL_SHARE_IRQ
#define CONFIG_SERIAL_DETECT_IRQ
@@ -76,6 +86,19 @@
#define CONFIG_HUB6
#endif

+#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072))
+#define ENABLE_SERIAL_PCI
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_PCI
+
/* Sanity checks */

#ifdef CONFIG_SERIAL_MULTIPORT
@@ -93,18 +116,11 @@
#endif
#endif

-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256

#define IRQ_T(state) \
- ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+ ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)

#define SERIAL_INLINE

@@ -119,8 +135,34 @@
* End of serial driver configuration section.
*/

-#include <linux/config.h>
+#if (LINUX_VERSION_CODE > 66304)
+#define NEW_MODULES
+#ifdef LOCAL_HEADERS /* We're building standalone */
+#define MODULE
+#endif
+#endif
+
+#ifdef NEW_MODULES
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
#include <linux/module.h>
+#else /* !NEW_MODULES */
+#ifdef MODVERSIONS
+#define MODULE
+#endif
+#include <linux/module.h>
+#endif /* NEW_MODULES */
+
+#ifdef LOCAL_HEADERS
+#include "serial_local.h"
+#else
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+static char *serial_version = "4.30";
+#endif
+
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -128,8 +170,6 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
@@ -137,31 +177,47 @@
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
+#else
+#define __initfunc(x) x
+#endif
#include <linux/delay.h>
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
#endif
+#ifdef ENABLE_SERIAL_PCI
+#include <linux/pci.h>
+#endif

#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include <asm/serial.h>
+
+#ifdef CONFIG_MAC_SERIAL
+#define SERIAL_DEV_OFFSET 2
+#else
+#define SERIAL_DEV_OFFSET 0
+#endif

#ifdef SERIAL_INLINE
#define _INLINE_ inline
#endif

static char *serial_name = "Serial driver";
-static char *serial_version = "4.27";

static DECLARE_TASK_QUEUE(tq_serial);

static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;

+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#endif
+
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256

@@ -194,20 +250,37 @@
{ "16450", 1, 0 },
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
- { "cirrus", 1, 0 },
- { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+ { "cirrus", 1, 0 }, /* usurped by cyclades.c */
+ { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
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},
+ { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
+ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
{ 0, 0}
};

-static struct serial_state rs_table[] = {
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};

#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))

+#ifdef ENABLE_SERIAL_PCI
+#define NR_PCI_BOARDS 8
+static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
+static int serial_pci_board_idx = 0;
+#ifdef PCI_REGION_EXISTS
+#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
+#else
+#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r])
+#endif
+#endif /* ENABLE_SERIAL_PCI */
+
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
@@ -226,7 +299,93 @@
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+/*
+ * Provide backwards compatibility for kernels prior to 2.1.XX.
+ */
+#if (LINUX_VERSION_CODE < 0x20000)
+typedef dev_t kdev_t;
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02017E)
+static signed long schedule_timeout(signed long timeout)
+{
+ unsigned long expire;
+
+ expire = timeout + jiffies;
+
+ current->timeout = jiffies + timeout;
+ schedule();
+
+ timeout = expire - jiffies;
+ return timeout < 0 ? 0 : timeout;
+}
+#endif
+
+#ifndef time_after
+#define time_after(a,b) ((long)(b) - (long)(a) < 0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020100)
+static inline int irq_cannonicalize(int irq)
+{
+ return ((irq == 2) ? 9 : irq);
+}
+#endif
+
+#if (LINUX_VERSION_CODE < 131336)
+static int copy_from_user(void *to, const void *from_user, unsigned long len)
+{
+ int error;
+
+ error = verify_area(VERIFY_READ, from_user, len);
+ if (error)
+ return len;
+ memcpy_fromfs(to, from_user, len);
+ return 0;
+}
+
+static int copy_to_user(void *to_user, const void *from, unsigned long len)
+{
+ int error;
+
+ error = verify_area(VERIFY_WRITE, to_user, len);
+ if (error)
+ return len;
+ memcpy_tofs(to_user, from, len);
+ return 0;
+}
+
+static inline int signal_pending(struct task_struct *p)
+{
+ return (p->signal & (~p->blocked != 0));
+}
+
+#else
+#include <asm/uaccess.h>
+#endif
+
+#ifdef CAP_SYS_ADMIN
+#define serial_isroot() (capable(CAP_SYS_ADMIN))
+#else
+#define serial_isroot() (suser())
+#endif
+
+#if (LINUX_VERSION_CODE < 131394) /* 2.1.66 */
+#define test_and_clear_bit(x,y) clear_bit(x,y)
+
+static inline void remove_bh(int nr)
+{
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+}
+#endif
+

static inline int serial_paranoia_check(struct async_struct *info,
kdev_t device, const char *routine)
@@ -257,6 +416,11 @@
return inb(info->port+1);
} else
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (info->iomem_base)
+ return readb(info->iomem_base + (offset<<info->iomem_reg_shift));
+ else
+#endif
return inb(info->port + offset);
}

@@ -268,6 +432,11 @@
return inb_p(info->port+1);
} else
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (info->iomem_base)
+ return readb(info->iomem_base + (offset<<info->iomem_reg_shift));
+ else
+#endif
#ifdef CONFIG_SERIAL_NOPAUSE_IO
return inb(info->port + offset);
#else
@@ -283,6 +452,11 @@
outb(value, info->port+1);
} else
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (info->iomem_base)
+ writeb(value, info->iomem_base + (offset<<info->iomem_reg_shift));
+ else
+#endif
outb(value, info->port+offset);
}

@@ -295,6 +469,11 @@
outb_p(value, info->port+1);
} else
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ if (info->iomem_base)
+ writeb(value, info->iomem_base + (offset<<info->iomem_reg_shift));
+ else
+#endif
#ifdef CONFIG_SERIAL_NOPAUSE_IO
outb(value, info->port+offset);
#else
@@ -303,6 +482,26 @@
}

/*
+ * For the 16C950
+ */
+void serial_icr_write(struct async_struct *info, int offset, int value)
+{
+ serial_out(info, UART_SCR, offset);
+ serial_out(info, UART_ICR, value);
+}
+
+unsigned int serial_icr_read(struct async_struct *info, int offset)
+{
+ int value;
+
+ serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
+ serial_out(info, UART_SCR, offset);
+ value = serial_in(info, UART_ICR);
+ serial_icr_write(info, UART_ACR, info->ACR);
+ return value;
+}
+
+/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
@@ -323,6 +522,10 @@
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
+ if (info->state->type == PORT_16C950) {
+ info->ACR |= UART_ACR_TXDIS;
+ serial_icr_write(info, UART_ACR, info->ACR);
+ }
restore_flags(flags);
}

@@ -339,6 +542,10 @@
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
+ if (info->state->type == PORT_16C950) {
+ info->ACR &= ~UART_ACR_TXDIS;
+ serial_icr_write(info, UART_ACR, info->ACR);
+ }
restore_flags(flags);
}

@@ -453,7 +660,11 @@
ignore_char:
*status = serial_inp(info, UART_LSR);
} while (*status & UART_LSR_DR);
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
tty_flip_buffer_push(tty);
+#else
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
}

static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -932,7 +1143,7 @@
goto errout;
}

- if (!state->port || !state->type) {
+ if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
@@ -951,8 +1162,28 @@
/* Wake up UART */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ /*
+ * Turn off LCR == 0xBF so we actually set the IER
+ * register on the XR16C850
+ */
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, 0);
+ /*
+ * Now reset LCR so we can turn off the ECB bit
+ */
+ serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, 0);
+ /*
+ * For a XR16C850, we need to set the trigger levels
+ */
+ if (info->state->type == PORT_16850) {
+ serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+ UART_FCTR_RX);
+ serial_outp(info, UART_TRG, UART_TRG_96);
+ serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+ UART_FCTR_TX);
+ serial_outp(info, UART_TRG, UART_TRG_96);
+ }
serial_outp(info, UART_LCR, 0);
}

@@ -961,13 +1192,38 @@
serial_outp(info, UART_IER, 0);
}

+ if (info->state->type == PORT_16C950) {
+ /* Wake up and initialize UART */
+ info->ACR = 0;
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_IER, 0);
+ serial_outp(info, UART_LCR, 0);
+ serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
+ }
+
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
- if (uart_config[state->type].flags & UART_CLEAR_FIFO)
- serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+ if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
+ serial_outp(info, UART_FCR, 0);
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) serial_inp(info, UART_LSR);
+ (void) serial_inp(info, UART_RX);
+ (void) serial_inp(info, UART_IIR);
+ (void) serial_inp(info, UART_MSR);

/*
* At this point there's no way the LSR could still be 0xFF;
@@ -975,7 +1231,8 @@
* here.
*/
if (serial_inp(info, UART_LSR) == 0xff) {
- if (capable(CAP_SYS_ADMIN)) {
+ printk("LSR safety check engaged!\n");
+ if (serial_isroot()) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
} else
@@ -1007,7 +1264,7 @@
retval = request_irq(state->irq, handler, IRQ_T(state),
"serial", NULL);
if (retval) {
- if (capable(CAP_SYS_ADMIN)) {
+ if (serial_isroot()) {
if (info->tty)
set_bit(TTY_IO_ERROR,
&info->tty->flags);
@@ -1028,14 +1285,6 @@
figure_IRQ_timeout(state->irq);

/*
- * Clear the interrupt registers.
- */
- /* (void) serial_inp(info, UART_LSR); */ /* (see above) */
- (void) serial_inp(info, UART_RX);
- (void) serial_inp(info, UART_IIR);
- (void) serial_inp(info, UART_MSR);
-
- /*
* Now, initialize the UART
*/
serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
@@ -1053,12 +1302,7 @@
if (state->irq != 0)
info->MCR |= UART_MCR_OUT2;
}
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_outp(info, UART_MCR, info->MCR);

/*
@@ -1097,6 +1341,7 @@
/*
* Set up the tty->alt_speed kludge
*/
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if (info->tty) {
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
@@ -1107,6 +1352,7 @@
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
+#endif

/*
* and set the speed of the serial port
@@ -1193,12 +1439,7 @@
} else
#endif
info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */

/* disable break condition */
serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
@@ -1230,6 +1471,37 @@
restore_flags(flags);
}

+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300,
+ 600, 1200, 1800, 2400, 4800, 9600, 19200,
+ 38400, 57600, 115200, 230400, 460800, 0 };
+
+static int tty_get_baud_rate(struct tty_struct *tty)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ unsigned int cflag, i;
+
+ cflag = tty->termios->c_cflag;
+
+ i = cflag & CBAUD;
+ if (i & CBAUDEX) {
+ i &= ~CBAUDEX;
+ if (i < 1 || i > 2)
+ tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ i += 15;
+ }
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i += 1;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i += 2;
+ }
+ return baud_table[i];
+}
+#endif
+
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
@@ -1237,7 +1509,6 @@
static void change_speed(struct async_struct *info,
struct termios *old_termios)
{
- unsigned short port;
int quot = 0, baud_base, baud;
unsigned cflag, cval, fcr = 0;
int bits;
@@ -1246,7 +1517,7 @@
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
+ if (!CONFIGURED_SERIAL_PORT(info))
return;

/* byte size and parity */
@@ -1278,6 +1549,18 @@
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
baud_base = info->state->baud_base;
+ if (info->state->type == PORT_16C950) {
+ if (baud <= baud_base)
+ serial_icr_write(info, UART_TCR, 0);
+ else if (baud <= 2*baud_base) {
+ serial_icr_write(info, UART_TCR, 0x8);
+ baud_base = baud_base * 2;
+ } else if (baud <= 4*baud_base) {
+ serial_icr_write(info, UART_TCR, 0x4);
+ baud_base = baud_base * 4;
+ } else
+ serial_icr_write(info, UART_TCR, 0);
+ }
if (baud == 38400 &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->state->custom_divisor;
@@ -1383,6 +1666,7 @@
if (info->state->type == PORT_16750)
serial_outp(info, UART_FCR, fcr); /* set fcr */
serial_outp(info, UART_LCR, cval); /* reset DLAB */
+ info->LCR = cval; /* Save LCR */
if (info->state->type != PORT_16750)
serial_outp(info, UART_FCR, fcr); /* set fcr */
restore_flags(flags);
@@ -1664,7 +1948,7 @@
change_port = (new_serial.port != state->port) ||
(new_serial.hub6 != state->hub6);

- if (!capable(CAP_SYS_ADMIN)) {
+ if (!serial_isroot()) {
if (change_irq || change_port ||
(new_serial.baud_base != state->baud_base) ||
(new_serial.type != state->type) ||
@@ -1721,11 +2005,14 @@
state->type = new_serial.type;
state->close_delay = new_serial.close_delay * HZ/100;
state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x200100)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
info->xmit_fifo_size = state->xmit_fifo_size =
new_serial.xmit_fifo_size;

- release_region(state->port,8);
+ if (state->port)
+ release_region(state->port,8);
if (change_port || change_irq) {
/*
* We need to shutdown the serial port at the old
@@ -1736,7 +2023,7 @@
info->port = state->port = new_serial.port;
info->hub6 = state->hub6 = new_serial.hub6;
}
- if (state->type != PORT_UNKNOWN)
+ if ((state->type != PORT_UNKNOWN) && state->port)
request_region(state->port,8,"serial(set)");


@@ -1747,6 +2034,7 @@
if (((old_state.flags & ASYNC_SPD_MASK) !=
(state->flags & ASYNC_SPD_MASK)) ||
(old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
@@ -1755,6 +2043,7 @@
info->tty->alt_speed = 230400;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
+#endif
change_speed(info, 0);
}
} else
@@ -1783,7 +2072,9 @@
status = serial_in(info, UART_LSR);
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
}


@@ -1807,19 +2098,21 @@
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- return put_user(result,value);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
}

static int set_modem_info(struct async_struct * info, unsigned int cmd,
unsigned int *value)
{
- int error;
unsigned int arg;
unsigned long flags;

- error = get_user(arg, value);
- if (error)
- return error;
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
@@ -1863,6 +2156,7 @@
return -EINVAL;
}
save_flags(flags); cli();
+ info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_out(info, UART_MCR, info->MCR);
restore_flags(flags);
return 0;
@@ -1872,7 +2166,7 @@
{
int retval;

- if (!capable(CAP_SYS_ADMIN))
+ if (!serial_isroot())
return -EPERM;

if (info->state->count > 1)
@@ -1895,6 +2189,22 @@
/*
* rs_break() --- routine which turns the break handling on or off
*/
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break( struct async_struct * info, int duration)
+{
+ if (!CONFIGURED_SERIAL_PORT(info))
+ return;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+ cli();
+ info->LCR |= UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
+ schedule();
+ info->LCR &= ~UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
+ sti();
+}
+#else
static void rs_break(struct tty_struct *tty, int break_state)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
@@ -1903,17 +2213,17 @@
if (serial_paranoia_check(info, tty->device, "rs_break"))
return;

- if (!info->port)
+ if (!CONFIGURED_SERIAL_PORT(info))
return;
save_flags(flags); cli();
if (break_state == -1)
- serial_out(info, UART_LCR,
- serial_inp(info, UART_LCR) | UART_LCR_SBC);
+ info->LCR |= UART_LCR_SBC;
else
- serial_out(info, UART_LCR,
- serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+ info->LCR &= ~UART_LCR_SBC;
+ serial_out(info, UART_LCR, info->LCR);
restore_flags(flags);
}
+#endif

#ifdef CONFIG_SERIAL_MULTIPORT
static int get_multiport_struct(struct async_struct * info,
@@ -1959,7 +2269,7 @@
int retval;
void (*handler)(int, void *, struct pt_regs *);

- if (!capable(CAP_SYS_ADMIN))
+ if (!serial_isroot())
return -EPERM;
state = info->state;

@@ -2032,11 +2342,13 @@
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct *p_cuser; /* user space */
+ struct serial_icounter_struct icount;
unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ int retval, tmp;
+#endif

if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -2049,6 +2361,45 @@
}

switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ if (!arg) {
+ send_break(info, HZ/4); /* 1/4 second */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+ case TIOCGSOFTCAR:
+ tmp = C_CLOCAL(tty) ? 1 : 0;
+ if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case TIOCSSOFTCAR:
+ if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+ return -EFAULT;
+
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (tmp ? CLOCAL : 0));
+ return 0;
+#endif
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
@@ -2124,31 +2475,21 @@
save_flags(flags); cli();
cnow = info->state->icount;
restore_flags(flags);
- p_cuser = (struct serial_icounter_struct *) arg;
- error = put_user(cnow.cts, &p_cuser->cts);
- if (error) return error;
- error = put_user(cnow.dsr, &p_cuser->dsr);
- if (error) return error;
- error = put_user(cnow.rng, &p_cuser->rng);
- if (error) return error;
- error = put_user(cnow.dcd, &p_cuser->dcd);
- if (error) return error;
- error = put_user(cnow.rx, &p_cuser->rx);
- if (error) return error;
- error = put_user(cnow.tx, &p_cuser->tx);
- if (error) return error;
- error = put_user(cnow.frame, &p_cuser->frame);
- if (error) return error;
- error = put_user(cnow.overrun, &p_cuser->overrun);
- if (error) return error;
- error = put_user(cnow.parity, &p_cuser->parity);
- if (error) return error;
- error = put_user(cnow.brk, &p_cuser->brk);
- if (error) return error;
- error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
- if (error) return error;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
return 0;
-
case TIOCSERGWILD:
case TIOCSERSWILD:
/* "setserial -W" is called in Debian boot */
@@ -2422,7 +2763,11 @@
static int block_til_ready(struct tty_struct *tty, struct file * filp,
struct async_struct *info)
{
+#ifdef DECLARE_WAITQUEUE
DECLARE_WAITQUEUE(wait, current);
+#else
+ struct wait_queue wait = { current, NULL };
+#endif
struct serial_state *state = info->state;
int retval;
int do_clocal = 0, extra_count = 0;
@@ -2571,12 +2916,18 @@
return -ENOMEM;
}
memset(info, 0, sizeof(struct async_struct));
+#ifdef DECLARE_WAITQUEUE
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait);
+#endif
info->magic = SERIAL_MAGIC;
info->port = sstate->port;
info->flags = sstate->flags;
+#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;
@@ -2616,21 +2967,20 @@
}
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "rs_open")) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
- }

#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
info->state->count);
#endif
+#if (LINUX_VERSION_CODE > 0x20100)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif

if (!tmp_buf) {
page = get_free_page(GFP_KERNEL);
if (!page) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
return -ENOMEM;
}
if (tmp_buf)
@@ -2646,7 +2996,6 @@
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
@@ -2660,13 +3009,11 @@
*/
retval = startup(info);
if (retval) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
return retval;
}

retval = block_til_ready(tty, filp, info);
if (retval) {
- /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open returning after block_til_ready with %d\n",
retval);
@@ -2838,6 +3185,13 @@
printk(" DETECT_IRQ");
#define SERIAL_OPT
#endif
+#ifdef ENABLE_SERIAL_PCI
+ printk(" SERIAL_PCI");
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ printk(" PCI_IOMEM");
+#endif
+#define SERIAL_OPT
+#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
#else
@@ -2913,51 +3267,155 @@
}

/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct async_struct *info)
+{
+ unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+ int count;
+
+ old_fcr = serial_inp(info, UART_FCR);
+ old_mcr = serial_inp(info, UART_MCR);
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ serial_outp(info, UART_MCR, UART_MCR_LOOP);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ old_dll = serial_inp(info, UART_DLL);
+ old_dlm = serial_inp(info, UART_DLM);
+ serial_outp(info, UART_DLL, 0x01);
+ serial_outp(info, UART_DLM, 0x00);
+ serial_outp(info, UART_LCR, 0x03);
+ for (count = 0; count < 256; count++)
+ serial_outp(info, UART_TX, count);
+ mdelay(20);
+ for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+ (count < 256); count++)
+ serial_inp(info, UART_RX);
+ serial_outp(info, UART_FCR, old_fcr);
+ serial_outp(info, UART_MCR, old_mcr);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
+ serial_outp(info, UART_DLL, old_dll);
+ serial_outp(info, UART_DLM, old_dlm);
+
+ return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar UART's. When
+ * this function is called we know it is at least a StarTech 16650 V2,
+ * but it might be one of several StarTech UARTs, or one of its
+ * clones. (We treat the broken original StarTech 16650 V1 as a
+ * 16550A, and why not? Startech doesn't seem to even acknowledge its
+ * existence.)
+ *
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_startech_uarts(struct async_struct *info,
+ struct serial_state *state,
+ unsigned long flags)
+{
+ unsigned char scratch, status1, status2, old_fctr, old_emsr;
+
+ /*
+ * Here we check for the XR16C85x family. We do this by
+ * checking for to see if we can replace the scratch register
+ * with the receive FIFO count register.
+ *
+ * XXX I don't have one of these chips, but it should also be
+ * possible to check for them by setting DLL and DLM to 0, and
+ * then reading back DLL and DLM. If the DLM reads back as
+ * 0x10, then the UART is a XR16C850 and the DLL contains the
+ * chip revision.
+ */
+ old_fctr = serial_inp(info, UART_FCTR);
+ serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP);
+ old_emsr = serial_inp(info, UART_EMSR);
+ serial_outp(info, UART_EMSR, 0x00);
+ serial_outp(info, UART_LCR, 0x00);
+ scratch = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, 0xa5);
+ status1 = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, 0x5a);
+ status2 = serial_in(info, UART_SCR);
+ serial_outp(info, UART_SCR, scratch);
+ if ((status1 != 0xa5) || (status2 != 0x5a)) {
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_FCTR, old_fctr | UART_FCTR_SCR_SWAP);
+ serial_outp(info, UART_EMSR, old_emsr);
+ serial_outp(info, UART_FCTR, old_fctr);
+ state->type = PORT_16850;
+ return;
+ }
+ serial_outp(info, UART_IER, old_fctr);
+
+ /*
+ * We distinguish between the '654 and the '650 by counting
+ * how many bytes are in the FIFO. I'm using this for now,
+ * since that's the technique that was sent to me in the
+ * serial driver update, but I'm not convinced this works.
+ * I've had problems doing this in the past. -TYT
+ */
+ if (size_fifo(info) == 64)
+ state->type = PORT_16654;
+ else
+ state->type = PORT_16650V2;
+}
+
+/*
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A, since this will determine
- * whether or not we can use its FIFO features.
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
*/
static void autoconfig(struct serial_state * state)
{
- unsigned char status1, status2, scratch, scratch2;
+ unsigned char status1, status2, scratch, scratch2, scratch3;
struct async_struct *info, scr_info;
unsigned long flags;

state->type = PORT_UNKNOWN;

- if (!state->port)
+ if (!CONFIGURED_SERIAL_PORT(state))
return;

info = &scr_info; /* This is just for serial_{in,out} */

info->magic = SERIAL_MAGIC;
+ info->state = state;
info->port = state->port;
info->flags = state->flags;
#ifdef CONFIG_HUB6
info->hub6 = state->hub6;
#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+#endif

save_flags(flags); cli();

- /*
- * Do a simple existence test first; if we fail this, there's
- * no point trying anything else.
- *
- * 0x80 is used as a nonsense port to prevent against false
- * positives due to ISA bus float. The assumption is that
- * 0x80 is a non-existent port; which should be safe since
- * include/asm/io.h also makes this assumption.
- */
- scratch = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, 0);
- outb(0xff, 0x080);
- scratch2 = serial_inp(info, UART_IER);
- serial_outp(info, UART_IER, scratch);
- if (scratch2) {
- restore_flags(flags);
- return; /* We failed; there's nothing here */
+ if (!state->iomem_base) {
+ /*
+ * Do a simple existence test first; if we fail this,
+ * there's no point trying anything else.
+ *
+ * 0x80 is used as a nonsense port to prevent against
+ * false positives due to ISA bus float. The
+ * assumption is that 0x80 is a non-existent port;
+ * which should be safe since include/asm/io.h also
+ * makes this assumption.
+ */
+ scratch = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, 0);
+ outb(0xff, 0x080);
+ scratch2 = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, scratch);
+ if (scratch2) {
+ restore_flags(flags);
+ return; /* We failed; there's nothing here */
+ }
}

/*
@@ -2980,7 +3438,7 @@
return;
}
}
-
+
scratch2 = serial_in(info, UART_LCR);
serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
@@ -3002,14 +3460,27 @@
break;
}
if (state->type == PORT_16550A) {
+ /* Check for Oxford Semiconductor 16C950 */
+ scratch = serial_icr_read(info, UART_ID1);
+ scratch2 = serial_icr_read(info, UART_ID2);
+ scratch3 = serial_icr_read(info, UART_ID3);
+
+ if (scratch == 0x16 && scratch2 == 0xC9 &&
+ (scratch3 == 0x50 || scratch3 == 0x52 ||
+ scratch3 == 0x54)) {
+ state->type = PORT_16C950;
+ state->revision = serial_icr_read(info, UART_REV);
+ }
+ }
+ if (state->type == PORT_16550A) {
/* Check for Startech UART's */
- serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+ serial_outp(info, UART_LCR, UART_LCR_DLAB);
if (serial_in(info, UART_EFR) == 0) {
state->type = PORT_16650;
} else {
serial_outp(info, UART_LCR, 0xBF);
if (serial_in(info, UART_EFR) == 0)
- state->type = PORT_16650V2;
+ autoconfig_startech_uarts(info, state, flags);
}
}
if (state->type == PORT_16550A) {
@@ -3019,7 +3490,16 @@
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 7) {
+ /*
+ * If this is a 16750, and not a cheap UART
+ * clone, then it should only go into 64 byte
+ * mode if the UART_FCR7_64BYTE bit was set
+ * while UART_LCR_DLAB was latched.
+ */
+ serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_outp(info, UART_LCR, 0);
+ serial_outp(info, UART_FCR,
+ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(info, UART_IIR) >> 5;
if (scratch == 6)
state->type = PORT_16750;
@@ -3045,20 +3525,13 @@
return;
}

- request_region(info->port,8,"serial(auto)");
+ if (info->port)
+ request_region(info->port,8,"serial(auto)");

/*
* Reset the UART.
*/
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * I wonder what DEC did to the OUT1 and OUT2 lines?
- * clearing them results in endless interrupts.
- */
- serial_outp(info, UART_MCR, 0x0c);
-#else
- serial_outp(info, UART_MCR, 0x00);
-#endif
+ serial_outp(info, UART_MCR, 0x00 | ALPHA_KLUDGE_MCR); /* Don't ask */
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
(void)serial_in(info, UART_RX);
@@ -3070,13 +3543,321 @@
int register_serial(struct serial_struct *req);
void unregister_serial(int line);

+#if (LINUX_VERSION_CODE > 0x20100)
EXPORT_SYMBOL(register_serial);
EXPORT_SYMBOL(unregister_serial);
+#else
+static struct symbol_table serial_syms = {
+#include <linux/symtab_begin.h>
+ X(register_serial),
+ X(unregister_serial),
+#include <linux/symtab_end.h>
+};
+#endif
+
+#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 void __init pci_plx9050_fn(struct pci_dev *dev,
+ struct pci_board *board,
+ int enable)
+{
+ u8 data, *p;
+
+ pci_read_config_byte(dev, PCI_COMMAND, &data);
+
+ if (enable)
+ pci_write_config_byte(dev, PCI_COMMAND,
+ data | PCI_COMMAND_MEMORY);
+
+ /* enable/disable interrupts */
+ p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
+ writel(enable ? 0x41 : 0x00, p + 0x4c);
+ iounmap(p);
+
+ if (!enable)
+ pci_write_config_byte(dev, PCI_COMMAND,
+ data & ~PCI_COMMAND_MEMORY);
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.
+ */
+static struct pci_board pci_boards[] = {
+ /*
+ * Vendor ID, Device ID,
+ * Subvendor ID, Subdevice ID,
+ * Number of Ports, Base (Maximum) Baud Rate,
+ * Offset of register holding Uart register offset
+ * Mask to apply to above register's value
+ */
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+ SPCI_FL_BASE1, 8, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+ SPCI_FL_BASE1, 4, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+ SPCI_FL_BASE1, 2, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+ SPCI_FL_BASE1, 8, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+ SPCI_FL_BASE1, 4, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+ SPCI_FL_BASE1, 2, 1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+ SPCI_FL_BASE1, 2, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+ SPCI_FL_BASE1, 8, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+ SPCI_FL_BASE1, 4, 921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+ SPCI_FL_BASE1, 2, 921600 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 8, 115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ { 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,
+ 0x400, 7, pci_plx9050_fn },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_IOMEM, 4, 921600,
+ 0x400, 7, pci_plx9050_fn },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600,
+ 0x400, 7, pci_plx9050_fn },
+ { 0, }
+};
+
+/*
+ * 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)
+{
+ u16 subvendor, subdevice;
+ 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;
+ }
+
+ for(dev=pci_devices; dev; dev=dev->next) {
+ pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID,
+ &subvendor);
+ pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice);
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ subvendor != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ subdevice != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0) {
+#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));
+#endif
+ continue;
+ }
+
+ /*
+ * Run the initialization function, if any
+ */
+ if (board->init_fn)
+ (board->init_fn)(dev, board, 1);
+
+ /*
+ * Register the serial board in the array so we can
+ * shutdown the board later, if necessary.
+ */
+ serial_pci_board[serial_pci_board_idx].board = board;
+ serial_pci_board[serial_pci_board_idx].dev = dev;
+ serial_pci_board_idx++;
+
+ base_idx = board->flags & SPCI_FL_BASE_MASK;
+ 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;
+
+ /*
+ * 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");
+#endif
+ continue;
+ }
+#endif
+ memset(&fake_state, 0, sizeof(fake_state));
+
+#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 (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.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");
+#endif
+ return;
+}
+
+#endif /* ENABLE_SERIAL_PCI */

/*
* The serial driver boot-time initialization code!
*/
-__initfunc(int rs_init(void))
+int __init rs_init(void)
{
int i;
struct serial_state * state;
@@ -3120,10 +3901,12 @@

memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
+#endif
serial_driver.name = "ttyS";
serial_driver.major = TTY_MAJOR;
- serial_driver.minor_start = 64;
+ serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver.num = NR_PORTS;
serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
serial_driver.subtype = SERIAL_TYPE_NORMAL;
@@ -3147,14 +3930,18 @@
serial_driver.ioctl = rs_ioctl;
serial_driver.throttle = rs_throttle;
serial_driver.unthrottle = rs_unthrottle;
- serial_driver.send_xchar = rs_send_xchar;
serial_driver.set_termios = rs_set_termios;
serial_driver.stop = rs_stop;
serial_driver.start = rs_start;
serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+ serial_driver.send_xchar = rs_send_xchar;
serial_driver.wait_until_sent = rs_wait_until_sent;
serial_driver.read_proc = rs_read_proc;
+#endif

/*
* The callout device is just like normal device except for
@@ -3164,8 +3951,10 @@
callout_driver.name = "cua";
callout_driver.major = TTYAUX_MAJOR;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
callout_driver.read_proc = 0;
callout_driver.proc_entry = 0;
+#endif

if (tty_register_driver(&serial_driver))
panic("Couldn't register serial driver\n");
@@ -3187,15 +3976,11 @@
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
state->irq = irq_cannonicalize(state->irq);
- if (check_region(state->port,8))
+ if (state->port && check_region(state->port,8))
continue;
if (state->flags & ASYNC_BOOT_AUTOCONF)
autoconfig(state);
}
- /*
- * Detect the IRQ only once every port is initialised,
- * because some 16450 do not reset to 0 the MCR register.
- */
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
if (state->type == PORT_UNKNOWN)
continue;
@@ -3204,11 +3989,14 @@
&& (state->port != 0))
state->irq = detect_uart_irq(state);
printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
- state->line,
+ state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
uart_config[state->type].name);
}
+#ifdef ENABLE_SERIAL_PCI
+ probe_serial_pci();
+#endif
return 0;
}

@@ -3225,7 +4013,8 @@
save_flags(flags);
cli();
for (i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].port == req->port)
+ if ((rs_table[i].port == req->port) &&
+ (rs_table[i].iomem_base == req->iomem_base))
break;
}
if (i == NR_PORTS) {
@@ -3248,6 +4037,10 @@
state->irq = req->irq;
state->port = req->port;
state->flags = req->flags;
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ state->iomem_base = req->iomem_base;
+ state->iomem_reg_shift = req->iomem_reg_shift;
+#endif

autoconfig(state);
if (state->type == PORT_UNKNOWN) {
@@ -3257,13 +4050,16 @@
}
restore_flags(flags);

- if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0))
+ if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
state->irq = detect_uart_irq(state);

- printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
- state->line, state->port, state->irq,
- uart_config[state->type].name);
- return state->line;
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+ state->line + SERIAL_DEV_OFFSET,
+ state->iomem_base ? "iomem" : "port",
+ state->iomem_base ? (unsigned long)state->iomem_base :
+ (unsigned long)state->port,
+ state->irq, uart_config[state->type].name);
+ return state->line + SERIAL_DEV_OFFSET;
}

void unregister_serial(int line)
@@ -3308,9 +4104,21 @@
restore_flags(flags);

for (i = 0; i < NR_PORTS; i++) {
- if (rs_table[i].type != PORT_UNKNOWN)
+ 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 (rs_table[i].iomem_base)
+ iounmap(rs_table[i].iomem_base);
+#endif
+ }
+#ifdef ENABLE_SERIAL_PCI
+ 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);
}
+#endif
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
@@ -3556,3 +4364,9 @@
return kmem_start;
}
#endif
+
+/*
+ Local variables:
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ End:
+*/
===================================================================
RCS file: include/linux/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial.h
--- include/linux/serial.h 1999/08/28 19:56:42 1.1
+++ include/linux/serial.h 1999/08/31 18:59:36
@@ -24,7 +24,9 @@
int hub6;
unsigned short closing_wait; /* time to wait before closing */
unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
+ unsigned char *iomem_base;
+ unsigned short iomem_reg_shift;
+ int reserved[2];
};

/*
@@ -47,7 +49,10 @@
#define PORT_16650V2 7
#define PORT_16750 8
#define PORT_STARTECH 9 /* usurped by cyclades.c */
-#define PORT_MAX 9
+#define PORT_16C950 10 /* Oxford Semiconductor */
+#define PORT_16654 11
+#define PORT_16850 12
+#define PORT_MAX 12

struct serial_uart_config {
char *name;
===================================================================
RCS file: include/linux/RCS/serialP.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serialP.h
--- include/linux/serialP.h 1999/08/28 19:56:42 1.1
+++ include/linux/serialP.h 1999/08/31 19:01:23
@@ -21,6 +21,10 @@

#include <linux/termios.h>
#include <linux/tqueue.h>
+#include <linux/wait.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif

/*
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
@@ -40,9 +44,12 @@
int hub6;
int type;
int line;
+ int revision; /* Chip revision (950) */
int xmit_fifo_size;
int custom_divisor;
int count;
+ u8 *iomem_base;
+ u16 iomem_reg_shift;
unsigned short close_delay;
unsigned short closing_wait; /* time to wait before closing */
struct async_icount icount;
@@ -69,6 +76,8 @@
unsigned short closing_wait2;
int IER; /* Interrupt Enable Register */
int MCR; /* Modem control register */
+ int LCR; /* Line control register */
+ int ACR; /* 16950 Additional Control Reg. */
unsigned long event;
unsigned long last_active;
int line;
@@ -79,14 +88,24 @@
int xmit_head;
int xmit_tail;
int xmit_cnt;
+ u8 *iomem_base;
+ u16 iomem_reg_shift;
struct tq_struct tqueue;
+#ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
+#else
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+#endif
struct async_struct *next_port; /* For the linked list */
struct async_struct *prev_port;
};

+#define CONFIGURED_SERIAL_PORT(info) ((info)->port || ((info)->iomem_base))
+
#define SERIAL_MAGIC 0x5301
#define SSTATE_MAGIC 0x5302

@@ -115,5 +134,51 @@
unsigned char mask4, match4;
int port_monitor;
};
+
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+/*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on at least some ALPHA's. The failure mode is that if either
+ * is cleared, the machine locks up with endless interrupts.
+ */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
+#else
+#define ALPHA_KLUDGE_MCR 0
+#endif
+
+/*
+ * Structures and definitions for PCI support
+ */
+struct pci_board {
+ unsigned short vendor;
+ unsigned short device;
+ unsigned short subvendor;
+ unsigned short subdevice;
+ int flags;
+ int num_ports;
+ int base_baud;
+ int uart_offset;
+ int reg_shift;
+ void (*init_fn)(struct pci_dev *dev, struct pci_board *board,
+ int enable);
+};
+
+struct pci_board_inst {
+ struct pci_board *board;
+ struct pci_dev *dev;
+};
+
+#ifndef PCI_ANY_ID
+#define PCI_ANY_ID (~0)
+#endif
+
+#define SPCI_FL_BASE_MASK 0x0007
+#define SPCI_FL_BASE0 0x0000
+#define SPCI_FL_BASE1 0x0001
+#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 */

#endif /* _LINUX_SERIAL_H */
===================================================================
RCS file: include/linux/RCS/serial_reg.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/serial_reg.h
--- include/linux/serial_reg.h 1999/08/28 19:56:42 1.1
+++ include/linux/serial_reg.h 1999/08/29 22:46:18
@@ -17,17 +17,29 @@
#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+ * In: Fifo count
+ * Out: Fifo custom trigger levels
+ * XR16C85x only */
+
#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
#define UART_IER 1 /* Out: Interrupt Enable Register */
+#define UART_FCTR 1 /* (LCR=BF) Feature Control Register
+ * XR16C85x only */
+
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_EFR 2 /* I/O: Extended Features Register */
/* (DLAB=1, 16C660 only) */
+
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_LSR 5 /* In: Line Status Register */
#define UART_MSR 6 /* In: Modem Status Register */
#define UART_SCR 7 /* I/O: Scratch Register */
+#define UART_EMSR 7 /* (LCR=BF) Extended Mode Select Register
+ * FCTR bit 6 selects SCR or EMSR
+ * XR16c85x only */

/*
* These are the definitions for the FIFO Control Register
@@ -139,6 +151,83 @@
/*
* the low four bits control software flow control
*/
+
+/*
+ * These register definitions are for the 16C950
+ */
+#define UART_ASR 0x01 /* Additional Status Register */
+#define UART_RFL 0x03 /* Transmitter FIFO level */
+#define UART_TFL 0x04 /* Receiver FIFO level */
+#define UART_ICR 0x05 /* Index Control Register */
+
+/* The 16950 ICR registers */
+#define UART_ACR 0x00 /* Additional Control Register */
+#define UART_CPR 0x01 /* Clock Prescalar Register */
+#define UART_TCR 0x02 /* Times Clock Register */
+#define UART_CKS 0x03 /* Clock Select Register */
+#define UART_TTL 0x04 /* Transmitter Interrupt Trigger Level */
+#define UART_RTL 0x05 /* Receiver Interrupt Trigger Level */
+#define UART_FCL 0x06 /* Flow Control Level Lower */
+#define UART_FCH 0x07 /* Flow Control Level Higher */
+#define UART_ID1 0x08 /* ID #1 */
+#define UART_ID2 0x09 /* ID #2 */
+#define UART_ID3 0x0A /* ID #3 */
+#define UART_REV 0x0B /* Revision */
+#define UART_CSR 0x0C /* Channel Software Reset */
+#define UART_NMR 0x0D /* Nine-bit Mode Register */
+#define UART_CTR 0xFF
+
+/*
+ * The 16C950 Additional Control Reigster
+ */
+#define UART_ACR_RXDIS 0x01 /* Receiver disable */
+#define UART_ACR_TXDIS 0x02 /* Receiver disable */
+#define UART_ACR_DSRFC 0x04 /* DSR Flow Control */
+#define UART_ACR_TLENB 0x20 /* 950 trigger levels enable */
+#define UART_ACR_ICRRD 0x40 /* ICR Read enable */
+#define UART_ACR_ASREN 0x80 /* Additional status enable */
+
+/*
+ * These are the definitions for the Feature Control Register
+ * (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
+ * Register, UART register #1)
+ */
+#define UART_FCTR_RTS_NODELAY 0x00 /* RTS flow control delay */
+#define UART_FCTR_RTS_4DELAY 0x01
+#define UART_FCTR_RTS_6DELAY 0x02
+#define UART_FCTR_RTS_8DELAY 0x03
+#define UART_FCTR_IRDA 0x04 /* IrDa data encode select */
+#define UART_FCTR_TX_INT 0x08 /* Tx interrupt type select */
+#define UART_FCTR_TRGA 0x00 /* Tx/Rx 550 trigger table select */
+#define UART_FCTR_TRGB 0x10 /* Tx/Rx 650 trigger table select */
+#define UART_FCTR_TRGC 0x20 /* Tx/Rx 654 trigger table select */
+#define UART_FCTR_TRGD 0x30 /* Tx/Rx 850 programmable trigger select */
+#define UART_FCTR_SCR_SWAP 0x40 /* Scratch pad register swap */
+#define UART_FCTR_RX 0x00 /* Programmable trigger mode select */
+#define UART_FCTR_TX 0x80 /* Programmable trigger mode select */
+
+/*
+ * These are the definitions for the Enhanced Mode Select Register
+ * (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
+ * Scratch register, UART register #7)
+ */
+#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
+#define UART_EMSR_ALT_COUNT 0x02 /* Alternating count select */
+
+/*
+ * These are the definitions for the Programmable Trigger
+ * Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
+ * register, UART register #0)
+ */
+#define UART_TRG_1 0x01
+#define UART_TRG_4 0x04
+#define UART_TRG_8 0x08
+#define UART_TRG_16 0x10
+#define UART_TRG_32 0x20
+#define UART_TRG_64 0x40
+#define UART_TRG_96 0x60
+#define UART_TRG_120 0x78
+#define UART_TRG_128 0x80

#endif /* _LINUX_SERIAL_REG_H */

===================================================================
RCS file: include/linux/RCS/pci.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci.h
--- include/linux/pci.h 1999/08/30 04:30:49 1.1
+++ include/linux/pci.h 1999/08/31 18:54:13
@@ -721,11 +721,13 @@
#define PCI_DEVICE_ID_DATABOOK_87144 0xb106

#define PCI_VENDOR_ID_PLX 0x10b5
+#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
#define PCI_DEVICE_ID_PLX_9050 0x9050
#define PCI_DEVICE_ID_PLX_9060 0x9060
#define PCI_DEVICE_ID_PLX_9060ES 0x906E
#define PCI_DEVICE_ID_PLX_9060SD 0x906D
#define PCI_DEVICE_ID_PLX_9080 0x9080
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001

#define PCI_VENDOR_ID_MADGE 0x10b6
#define PCI_DEVICE_ID_MADGE_MK2 0x0002
@@ -969,8 +971,8 @@
#define PCI_VENDOR_ID_OMEGA 0x119b
#define PCI_DEVICE_ID_OMEGA_82C092G 0x1221

-#define PCI_VENDOR_ID_GALILEO 0x11ab
-#define PCI_DEVICE_ID_GALILEO_GT64011 0x4146
+#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334

#define PCI_VENDOR_ID_GALILEO 0x11ab
#define PCI_DEVICE_ID_GALILEO_GT64011 0x4146
@@ -978,6 +980,12 @@
#define PCI_VENDOR_ID_LITEON 0x11ad
#define PCI_DEVICE_ID_LITEON_LNE100TX 0x0002

+#define PCI_VENDOR_ID_V3 0x11b0
+#define PCI_DEVICE_ID_V3_V960 0x0001
+#define PCI_DEVICE_ID_V3_V350 0x0001
+#define PCI_DEVICE_ID_V3_V960V2 0x0002
+#define PCI_DEVICE_ID_V3_V350V2 0x0002
+
#define PCI_VENDOR_ID_NP 0x11bc
#define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001

@@ -1082,6 +1090,16 @@
#define PCI_VENDOR_ID_ALTEON 0x12ae
#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001

+#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008
+
#define PCI_VENDOR_ID_PICTUREL 0x12c5
#define PCI_DEVICE_ID_PICTUREL_PCIVST 0x0081

@@ -1112,6 +1130,14 @@
#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062

+#define PCI_VENDOR_ID_SEALEVEL 0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801
+
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a

@@ -1119,6 +1145,10 @@
#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */
#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */
+
+#define PCI_VENDOR_ID_PANACOM 0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402

#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
===================================================================
RCS file: include/asm-ppc/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-ppc/serial.h
--- include/asm-ppc/serial.h 1999/08/31 18:52:58 1.1
+++ include/asm-ppc/serial.h 1999/08/31 18:53:06
@@ -8,116 +8,14 @@
#include <asm-m68k/serial.h>
#else

-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
#define BASE_BAUD ( 1843200 / 16 )

-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
+#define SERIAL_PORT_DFNS

#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
+#define RS_TABLE_SIZE 64
#else
-#define HUB6_SERIAL_PORT_DFNS
+#define RS_TABLE_SIZE 4
#endif
-
-#define MCA_SERIAL_PORT_DFNS
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS \
- MCA_SERIAL_PORT_DFNS

#endif /* CONFIG_APUS */
===================================================================
RCS file: include/asm-i386/RCS/serial.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/serial.h
--- include/asm-i386/serial.h 1999/08/30 15:25:05 1.1
+++ include/asm-i386/serial.h 1999/08/30 15:25:16
@@ -27,6 +27,9 @@
#define ACCENT_FLAGS 0
#define BOCA_FLAGS 0
#define HUB6_FLAGS 0
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE
#endif

/*

-
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/