Hi Linus,
Enclosed please find updates to the serial driver, versus Linux
2-3.99pre9-3. Could you please apply these patches to the mainline?
(These patches are identical to the previous set of patches, except
they're against 2.3.99pre9-3.)
Thanks!!
The changes here are:
* Fixed binary incompatibility problem introduced in 2.3.99pre2 for
64-bit platforms (i.e. Alpha, et. al)
* When TIOCMIWAIT is called, turn on monitoring of status
interrupts so they are counted correctly.
* Add a flag (ASYNC_BUGGY_UART) which skips some sanity checks
in deference to buggy UARTs. (Warning! If there isn't a
UART at the port, this can cause kernel lockups.)
* Pass the flag ASYNC_AUTOPROBE back to userland for ports which
were autodetected (i.e., via PCI or PNP code). This
is needed by setserial so it knows which ports' state
needs to be saved.
* Add generic autodetection for ISA PnP modems.
* Add support for a number of new cards:
RSA-DV II/S
Megawolf Romulus PCI
VS SPCOM800
EKF Intel i960 serial boards
A variety of PnP boards.
- Ted
Patch generated: on Mon May 22 12:33:28 EDT 2000 by tytso@snap.thunk.org
against Linux version 2.3.99pre9-3
===================================================================
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/05/22 11:27:00 1.1
+++ drivers/char/serial.c 2000/05/22 11:27:03
@@ -43,13 +43,16 @@
* few races on freeing buffers too.
* Alan Modra <alan@linuxcare.com>
*
+ * 5/00: Support for the RSA-DV II/S card added.
+ * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/
-static char *serial_version = "4.93";
-static char *serial_revdate = "2000-03-20";
+static char *serial_version = "4.95";
+static char *serial_revdate = "2000-05-21";
/*
* Serial driver configuration section. Here are the various options:
@@ -134,6 +137,8 @@
#endif
#endif
+#define CONFIG_SERIAL_RSA
+
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
@@ -277,9 +282,20 @@
UART_STARTECH },
{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
+ { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
{ 0, 0}
};
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+
+#define PORT_RSA_MAX 4
+static int probe_rsa[PORT_RSA_MAX];
+static int force_rsa[PORT_RSA_MAX];
+
+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+#endif /* CONFIG_SERIAL_RSA */
+
static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
@@ -293,11 +309,8 @@
static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
static int serial_pci_board_idx = 0;
#endif
-#ifndef PCI_BASE_ADDRESS
-#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
-#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 & \
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_IO)
#endif
#ifndef PCI_IRQ_RESOURCE
@@ -314,7 +327,8 @@
#define ACTIVATE_FUNC(dev) (dev->activate)
#define DEACTIVATE_FUNC(dev) (dev->deactivate)
#endif
-
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
@@ -1090,6 +1104,50 @@
IRQ_timeout[irq] = timeout ? timeout : 1;
}
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO. Returns zero on failure */
+static int enable_rsa(struct async_struct *info)
+{
+ unsigned char mode;
+ int result;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+
+ if (!result) {
+ serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+ }
+
+ restore_flags(flags);
+ return result;
+}
+
+/* Attempts to turn off the RSA FIFO. Returns zero on failure */
+static int disable_rsa(struct async_struct *info)
+{
+ unsigned char mode;
+ int result;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+
+ if (!result) {
+ serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+ }
+
+ restore_flags(flags);
+ return result;
+}
+#endif /* CONFIG_SERIAL_RSA */
+
static int startup(struct async_struct * info)
{
unsigned long flags;
@@ -1127,7 +1185,7 @@
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
#endif
- if (uart_config[info->state->type].flags & UART_STARTECH) {
+ if (uart_config[state->type].flags & UART_STARTECH) {
/* Wake up UART */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
@@ -1145,7 +1203,7 @@
/*
* For a XR16C850, we need to set the trigger levels
*/
- if (info->state->type == PORT_16850) {
+ if (state->type == PORT_16850) {
serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
UART_FCTR_RX);
serial_outp(info, UART_TRG, UART_TRG_96);
@@ -1156,12 +1214,12 @@
serial_outp(info, UART_LCR, 0);
}
- if (info->state->type == PORT_16750) {
+ if (state->type == PORT_16750) {
/* Wake up UART */
serial_outp(info, UART_IER, 0);
}
- if (info->state->type == PORT_16C950) {
+ if (state->type == PORT_16C950) {
/* Wake up and initialize UART */
info->ACR = 0;
serial_outp(info, UART_LCR, 0xBF);
@@ -1174,6 +1232,20 @@
serial_outp(info, UART_LCR, 0);
}
+#ifdef CONFIG_SERIAL_RSA
+ /*
+ * If this is an RSA port, see if we can kick it up to the
+ * higher speed clock.
+ */
+ if (state->type == PORT_RSA) {
+ if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
+ enable_rsa(info))
+ state->baud_base = SERIAL_RSA_BAUD_BASE;
+ if (state->baud_base == SERIAL_RSA_BAUD_BASE)
+ serial_outp(info, UART_RSA_FRR, 0);
+ }
+#endif
+
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
@@ -1199,7 +1271,8 @@
* if it is, then bail out, because there's likely no UART
* here.
*/
- if (serial_inp(info, UART_LSR) == 0xff) {
+ if (!(info->flags & ASYNC_BUGGY_UART) &&
+ (serial_inp(info, UART_LSR) == 0xff)) {
printk("LSR safety check engaged!\n");
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
@@ -1425,6 +1498,17 @@
UART_FCR_CLEAR_XMIT));
serial_outp(info, UART_FCR, 0);
+#ifdef CONFIG_SERIAL_RSA
+ /*
+ * Reset the RSA board back to 115kbps compat mode.
+ */
+ if ((state->type == PORT_RSA) &&
+ (state->baud_base == SERIAL_RSA_BAUD_BASE &&
+ disable_rsa(info)))
+ state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+
+
(void)serial_in(info, UART_RX); /* read data port to reset things */
if (info->tty)
@@ -1522,6 +1606,12 @@
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+ if ((info->state->type == PORT_RSA) &&
+ (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+ enable_rsa(info))
+ info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
baud_base = info->state->baud_base;
if (info->state->type == PORT_16C950) {
if (baud <= baud_base)
@@ -1583,6 +1673,10 @@
if (uart_config[info->state->type].flags & UART_USE_FIFO) {
if ((info->state->baud_base / quot) < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_RSA
+ else if (info->state->type == PORT_RSA)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
}
@@ -1912,6 +2006,10 @@
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
+ if (HIGH_BITS_OFFSET)
+ tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+ else
+ tmp.port_high = 0;
tmp.irq = state->irq;
tmp.flags = state->flags;
tmp.xmit_fifo_size = state->xmit_fifo_size;
@@ -1933,14 +2031,19 @@
struct serial_state old_state, *state;
unsigned int i,change_irq,change_port;
int retval = 0;
+ unsigned long new_port;
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
state = info->state;
old_state = *state;
-
+
+ new_port = new_serial.port;
+ if (HIGH_BITS_OFFSET)
+ new_port += new_serial.port_high << HIGH_BITS_OFFSET;
+
change_irq = new_serial.irq != state->irq;
- change_port = (new_serial.port != state->port) ||
+ change_port = (new_port != ((int) state->port)) ||
(new_serial.hub6 != state->hub6);
if (!capable(CAP_SYS_ADMIN)) {
@@ -1978,7 +2081,7 @@
if (new_serial.type) {
for (i = 0 ; i < NR_PORTS; i++)
if ((state != &rs_table[i]) &&
- (rs_table[i].port == new_serial.port) &&
+ (rs_table[i].port == new_port) &&
rs_table[i].type)
return -EADDRINUSE;
}
@@ -2005,8 +2108,14 @@
info->xmit_fifo_size = state->xmit_fifo_size =
new_serial.xmit_fifo_size;
- if ((state->type != PORT_UNKNOWN) && state->port)
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (old_state.type == PORT_RSA)
+ release_region(state->port + UART_RSA_BASE, 16);
+ else
+#endif
release_region(state->port,8);
+ }
state->type = new_serial.type;
if (change_port || change_irq) {
/*
@@ -2015,15 +2124,22 @@
*/
shutdown(info);
state->irq = new_serial.irq;
- info->port = state->port = new_serial.port;
+ info->port = state->port = new_port;
info->hub6 = state->hub6 = new_serial.hub6;
if (info->hub6)
info->io_type = state->io_type = SERIAL_IO_HUB6;
else if (info->io_type == SERIAL_IO_HUB6)
info->io_type = state->io_type = SERIAL_IO_PORT;
}
- if ((state->type != PORT_UNKNOWN) && state->port)
- request_region(state->port,8,"serial(set)");
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ request_region(state->port + UART_RSA_BASE,
+ 16, "serial_rsa(set)");
+ else
+#endif
+ request_region(state->port,8,"serial(set)");
+ }
check_and_exit:
@@ -2462,6 +2578,9 @@
/* note the counters on entry */
cprev = info->state->icount;
restore_flags(flags);
+ /* Force modem status interrupts on */
+ info->IER |= UART_IER_MSI;
+ serial_out(info, UART_IER, info->IER);
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
@@ -3348,6 +3467,16 @@
* LSR register (which serial_icr_read does)
*/
if (state->type == PORT_16550A) {
+ /*
+ * EFR [4] must be set else this test fails
+ *
+ * This shouldn't be necessary, but Mike Hudson
+ * (Exoray@isys.ca) claims that it's needed for 952
+ * dual UART's (which are not recommended for new designs).
+ */
+ serial_out(info, UART_LCR, 0xBF);
+ serial_out(info, UART_EFR, 0x10);
+ serial_out(info, UART_LCR, 0x00);
/* Check for Oxford Semiconductor 16C950 */
scratch = serial_icr_read(info, UART_ID1);
scratch2 = serial_icr_read(info, UART_ID2);
@@ -3434,7 +3563,8 @@
save_flags(flags); cli();
- if (!state->iomem_base) {
+ if (!(state->flags & ASYNC_BUGGY_UART) &&
+ !state->iomem_base) {
/*
* Do a simple existence test first; if we fail this,
* there's no point trying anything else.
@@ -3459,8 +3589,9 @@
serial_outp(info, UART_IER, scratch);
if (scratch2 || scratch3 != 0x0F) {
#ifdef SERIAL_DEBUG_AUTOCONF
- printk("serial: ttyS%d: simple autoconfig failed\n",
- state->line);
+ printk("serial: ttyS%d: simple autoconfig failed "
+ "(%02x, %02x)\n", state->line,
+ scratch2, scratch3);
#endif
restore_flags(flags);
return; /* We failed; there's nothing here */
@@ -3545,6 +3676,25 @@
}
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
}
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_16550A) {
+ int i;
+
+ for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+ if (!probe_rsa[i] && !force_rsa[i])
+ break;
+ if (((probe_rsa[i] != state->port) ||
+ check_region(state->port + UART_RSA_BASE, 16)) &&
+ (force_rsa[i] != state->port))
+ continue;
+ if (!enable_rsa(info))
+ continue;
+ state->type = PORT_RSA;
+ state->baud_base = SERIAL_RSA_BAUD_BASE;
+ break;
+ }
+ }
+#endif
serial_outp(info, UART_LCR, save_lcr);
if (state->type == PORT_16450) {
scratch = serial_in(info, UART_SCR);
@@ -3564,12 +3714,23 @@
return;
}
- if (info->port)
- request_region(info->port,8,"serial(auto)");
+ if (info->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ request_region(info->port + UART_RSA_BASE, 16,
+ "serial_rsa(auto)");
+ else
+#endif
+ request_region(info->port,8,"serial(auto)");
+ }
/*
* Reset the UART.
*/
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ serial_outp(info, UART_RSA_FRR, 0);
+#endif
serial_outp(info, UART_MCR, save_mcr);
serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
@@ -3614,7 +3775,7 @@
static _INLINE_ int get_pci_port(struct pci_dev *dev,
struct pci_board *board,
- struct serial_struct *state,
+ struct serial_struct *req,
int idx)
{
unsigned long port;
@@ -3626,24 +3787,28 @@
base_idx += idx;
if (board->flags & SPCI_FL_REGION_SZ_CAP) {
- max_port = PCI_BASE_REGION_SIZE(dev, base_idx) / 8;
+ max_port = pci_resource_len(dev, base_idx) / 8;
if (idx >= max_port)
return 1;
}
- port = PCI_BASE_ADDRESS(dev, base_idx) + board->first_uart_offset;
+ port = pci_resource_start(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;
+ req->port = port;
+ if (HIGH_BITS_OFFSET)
+ req->port_high = port >> HIGH_BITS_OFFSET;
+ else
+ req->port_high = 0;
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;
+ req->io_type = SERIAL_IO_MEM;
+ req->iomem_base = ioremap(port, board->uart_offset);
+ req->iomem_reg_shift = board->reg_shift;
+ req->port = 0;
return 0;
}
@@ -3670,23 +3835,28 @@
struct pci_board *board)
{
int k, line;
- struct serial_struct fake_state;
+ struct serial_struct serial_req;
int base_baud;
if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
- printk("SERIAL: PNP device '");
+ 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("serial: PNP device '");
printk_pnp_dev_id(board->vendor, board->device);
printk("' activate failed\n");
return;
}
+ if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) {
+ printk("serial: PCI device enable failed\n");
+ return;
+ }
+
/*
* Run the initialization function, if any
*/
@@ -3710,18 +3880,18 @@
base_baud = board->base_baud;
if (!base_baud)
base_baud = BASE_BAUD;
- memset(&fake_state, 0, sizeof(fake_state));
+ memset(&serial_req, 0, sizeof(serial_req));
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))
+ serial_req.irq = get_pci_irq(dev, board, k);
+ if (get_pci_port(dev, board, &serial_req, k))
break;
- fake_state.flags = ASYNC_SKIP_TEST;
+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
#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);
+ serial_req.port, serial_req.irq, serial_req.io_type);
#endif
- line = register_serial(&fake_state);
+ line = register_serial(&serial_req);
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
@@ -3742,28 +3912,45 @@
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
- u8 data, *p, scratch;
+ u8 data, *p, irq_config;
+ int pci_config;
+ irq_config = 0x41;
+ pci_config = PCI_COMMAND_MEMORY;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ irq_config = 0x43;
+ if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+ (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) {
+ /*
+ * As the megawolf cards have the int pins active
+ * high, and have 2 UART chips, both ints must be
+ * enabled on the 9050. Also, the UARTS are set in
+ * 16450 mode by default, so we have to enable the
+ * 16C950 'enhanced' mode so that we can use the deep
+ * FIFOs
+ */
+ irq_config = 0x5b;
+ pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ }
+
pci_read_config_byte(dev, PCI_COMMAND, &data);
if (enable)
pci_write_config_byte(dev, PCI_COMMAND,
- data | PCI_COMMAND_MEMORY);
+ data | pci_config);
/* enable/disable interrupts */
- p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
- scratch = 0x41;
- if (dev->vendor == PCI_VENDOR_ID_PANACOM)
- scratch = 0x43;
- writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c);
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
+ writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
iounmap(p);
if (!enable)
pci_write_config_byte(dev, PCI_COMMAND,
- data & ~PCI_COMMAND_MEMORY);
+ data & ~pci_config);
return 0;
}
+
/*
* SIIG serial cards have an PCI interface chip which also controls
* the UART clocking frequency. Each UART can be clocked independently
@@ -3796,7 +3983,7 @@
if (!enable) return 0;
- p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
switch (dev->device & 0xfff8) {
case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
@@ -3841,6 +4028,36 @@
return 0;
}
+/* Added for EKF Intel i960 serial boards */
+static int
+#ifndef MODULE
+__init
+#endif
+pci_inteli960ni_fn(struct pci_dev *dev,
+ struct pci_board *board,
+ int enable)
+{
+ unsigned long oldval;
+
+ if (!(board->subdevice & 0x1000))
+ return(-1);
+
+ if (!enable) /* is there something to deinit? */
+ return(0);
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
+ (unsigned long) board->subdevice);
+#endif
+ /* is firmware started? */
+ pci_read_config_dword(dev, 0x44, (void*) &oldval);
+ if (oldval == 0x00001000L) { /* RESET value */
+ printk(KERN_DEBUG "Local i960 firmware missing");
+ return(-1);
+ }
+ return(0);
+}
+
/*
* This is the configuration table for all of the PCI serial boards
@@ -3851,8 +4068,9 @@
* Vendor ID, Device ID,
* Subvendor ID, Subdevice ID,
* PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
- * Offset to get to next UART's registers
- * Register shift to use for memory-mapped I/O
+ * Offset to get to next UART's registers,
+ * Register shift to use for memory-mapped I/O,
+ * Initialization function, first UART offset
*/
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
@@ -3942,6 +4160,10 @@
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ /* VScom SPCOM800, from sl@s.pl */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2, 8, 921600 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_KEYSPAN,
PCI_SUBDEVICE_ID_KEYSPAN_SX2,
@@ -3979,6 +4201,12 @@
PCI_SUBVENDOR_ID_CHASE_PCIRAS,
PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
SPCI_FL_BASE2, 8, 460800 },
+ /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+ /* (Exoray@isys.ca) */
+ { PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS,
+ 0x10b5, 0x106a,
+ SPCI_FL_BASE2, 4, 921600,
+ 0x20, 2, pci_plx9050_fn, 0x03 },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE1, 4, 115200 },
@@ -4164,7 +4392,7 @@
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
0, 0, pci_siig20x_fn },
- /* Computone devices submitted by Doug McNash dougm@computone.com */
+ /* 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_BASE0, 4, 921600, /* IOMEM */
@@ -4198,6 +4426,11 @@
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0, 4, 921600 },
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { PCI_VENDOR_ID_INTEL, 0x1960,
+ 0xE4BF, PCI_ANY_ID,
+ SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
+ 8<<2, 2, pci_inteli960ni_fn, 0x10000},
/*
* Untested PCI modems, sent in from various folks...
*/
@@ -4221,12 +4454,12 @@
};
/*
- * Given a complete unknown PCI device, try to use some hueristics to
+ * Given a complete unknown PCI device, try to use some heuristics 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)
+static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
+ struct pci_board *board)
{
int num_iomem = 0, num_port = 0, first_port = -1;
int i;
@@ -4281,13 +4514,6 @@
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 &&
@@ -4305,7 +4531,7 @@
break;
}
- if (board->vendor == 0 && serial_guess_board(dev, board))
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
continue;
start_pci_pnp_board(dev, board);
@@ -4322,13 +4548,13 @@
#ifdef ENABLE_SERIAL_PNP
static struct pci_board pnp_devices[] __initdata = {
- /* Motorola VoiceSURFR 56K Modem */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
1, 115200 },
+ /* ASKEY 56K Plug&Play Modem */
+ { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x0000), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* AZT3005 PnP SOUND DEVICE */
{ ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
@@ -4338,12 +4564,18 @@
/* Boca Research 33,600 ACF Modem */
{ ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Davicom 33.6 PNP Modem */
+ { ISAPNP_VENDOR('D', 'A', 'V'), ISAPNP_DEVICE(0x0336), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Creative Modem Blaster Flash56 DI5601-1 */
{ ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Creative Modem Blaster V.90 DI5660 */
{ ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Motorola VoiceSURFR 56K Modem */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Pace 56 Voice Internal Plug & Play Modem */
{ ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
@@ -4356,6 +4588,9 @@
/* U.S. Robotics 56K FAX INT */
{ ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* U.S. Robotics 56k FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3050), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Viking 56K FAX INT */
{ ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
@@ -4373,6 +4608,10 @@
/* Generic 16550A-compatible COM port */
{ ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Generic ISA PnP serial board */
+ { 0, 0, 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+ 1, 115200 },
{ 0, }
};
@@ -4394,6 +4633,65 @@
irq->map = map;
}
+static char *modem_names[] = {
+ "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+ "56K", "56k", "K56", "33.6", "28.8", "14.4",
+ "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+ "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int check_name(char *name)
+{
+ char **tmp = modem_names;
+
+ while (*tmp) {
+ if (strstr(name, *tmp))
+ return 1;
+ tmp++;
+ }
+ return 0;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ * - dev->name or dev->bus->name must contain "modem" substring;
+ * - device must have only one IO region (8 byte long) with base adress
+ * 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+ struct pci_board *board)
+{
+ struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+ struct isapnp_resources *resa;
+
+ if (dev->active)
+ return 1;
+
+ if (!(check_name(dev->name) || check_name(dev->bus->name)))
+ return 1;
+
+ if (res->next)
+ return 1;
+
+ for (resa = res->alt; resa; resa = resa->alt) {
+ struct isapnp_port *port;
+ for (port = res->port; port; port = port->next)
+ if ((port->size == 8) &&
+ ((port->min == 0x2f8) ||
+ (port->min == 0x3f8) ||
+ (port->min == 0x2e8) ||
+ (port->min == 0x3e8)))
+ return 0;
+ }
+
+ return 1;
+}
+
static void __init probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
@@ -4409,13 +4707,18 @@
return;
}
- for (board = pnp_devices; board->vendor; board++) {
- while ((dev = isapnp_find_dev(NULL, board->vendor,
- board->device, dev))) {
- if (board->flags & SPCI_FL_NO_SHIRQ)
- avoid_irq_share(dev);
- start_pci_pnp_board(dev, board);
- }
+ isapnp_for_each_dev(dev) {
+ for (board = pnp_devices; board->vendor; board++)
+ if ((dev->vendor == board->vendor) &&
+ (dev->device == board->device))
+ break;
+
+ if (board->vendor == 0 && serial_pnp_guess_board(dev, board))
+ continue;
+
+ if (board->flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+ start_pci_pnp_board(dev, board);
}
#ifdef SERIAL_DEBUG_PNP
@@ -4477,7 +4780,7 @@
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
-#ifdef CONFIG_DEVFS_FS
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
serial_driver.name = "tts/%d";
#else
serial_driver.name = "ttyS";
@@ -4525,7 +4828,7 @@
* major number and the subtype code.
*/
callout_driver = serial_driver;
-#ifdef CONFIG_DEVFS_FS
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
callout_driver.name = "cua/%d";
#else
callout_driver.name = "cua";
@@ -4615,10 +4918,15 @@
unsigned long flags;
struct serial_state *state;
struct async_struct *info;
+ unsigned long port;
+
+ port = req->port;
+ if (HIGH_BITS_OFFSET)
+ port += req->port_high << HIGH_BITS_OFFSET;
save_flags(flags); cli();
for (i = 0; i < NR_PORTS; i++) {
- if ((rs_table[i].port == req->port) &&
+ if ((rs_table[i].port == port) &&
(rs_table[i].iomem_base == req->iomem_base))
break;
}
@@ -4636,11 +4944,11 @@
if (rs_table[i].count) {
restore_flags(flags);
printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
- "device already open\n", i, req->port, req->irq);
+ "device already open\n", i, port, req->irq);
return -1;
}
state->irq = req->irq;
- state->port = req->port;
+ state->port = port;
state->flags = req->flags;
state->io_type = req->io_type;
state->iomem_base = req->iomem_base;
@@ -4648,7 +4956,7 @@
if (req->baud_base)
state->baud_base = req->baud_base;
if ((info = state->info) != NULL) {
- info->port = req->port;
+ info->port = port;
info->flags = req->flags;
info->io_type = req->io_type;
info->iomem_base = req->iomem_base;
@@ -4721,10 +5029,10 @@
timer_table[RS_TIMER].expires = 0;
remove_bh(SERIAL_BH);
if ((e1 = tty_unregister_driver(&serial_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
+ printk("serial: failed to unregister serial driver (%d)\n",
e1);
if ((e2 = tty_unregister_driver(&callout_driver)))
- printk("SERIAL: failed to unregister callout driver (%d)\n",
+ printk("serial: failed to unregister callout driver (%d)\n",
e2);
restore_flags(flags);
@@ -4733,8 +5041,15 @@
rs_table[i].info = NULL;
kfree_s(info, sizeof(struct async_struct));
}
- if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port)
- release_region(rs_table[i].port, 8);
+ if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (rs_table[i].type == PORT_RSA)
+ release_region(rs_table[i].port +
+ UART_RSA_BASE, 16);
+ else
+#endif
+ release_region(rs_table[i].port, 8);
+ }
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
if (rs_table[i].iomem_base)
iounmap(rs_table[i].iomem_base);
@@ -5023,6 +5338,6 @@
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i586 -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 2000/05/22 11:27:00 1.1
+++ include/linux/serial.h 2000/05/22 11:50:53
@@ -10,6 +10,7 @@
#ifndef _LINUX_SERIAL_H
#define _LINUX_SERIAL_H
+#ifdef __KERNEL__
#include <asm/page.h>
/*
@@ -27,10 +28,12 @@
*/
#define SERIAL_XMIT_SIZE PAGE_SIZE
+#endif
+
struct serial_struct {
int type;
int line;
- unsigned long port;
+ unsigned int port;
int irq;
int flags;
int xmit_fifo_size;
@@ -44,7 +47,8 @@
unsigned short closing_wait2; /* no longer used... */
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
- int reserved[2];
+ unsigned int port_high;
+ int reserved[1];
};
/*
@@ -70,7 +74,8 @@
#define PORT_16C950 10 /* Oxford Semiconductor */
#define PORT_16654 11
#define PORT_16850 12
-#define PORT_MAX 12
+#define PORT_RSA 13 /* RSA-DV II/S card */
+#define PORT_MAX 13
#define SERIAL_IO_PORT 0
#define SERIAL_IO_HUB6 1
@@ -115,7 +120,10 @@
#define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
-#define ASYNC_FLAGS 0x3FFF /* Possible legal async flags */
+#define ASYNC_BUGGY_UART 0x4000 /* This is a buggy UART, skip some safety
+ * checks. Note: can be dangerous! */
+
+#define ASYNC_FLAGS 0x7FFF /* Possible legal async flags */
#define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged
* users can set or reset */
@@ -127,7 +135,9 @@
#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */
#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards */
+#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards
+ --- no longer used */
+#define ASYNC_AUTOPROBE 0x00800000 /* Port was autoprobed */
#define ASYNC_INTERNAL_FLAGS 0xFF000000 /* Internal flags */
===================================================================
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 2000/05/22 11:27:00 1.1
+++ include/linux/serial_reg.h 2000/05/22 11:27:03
@@ -229,5 +229,54 @@
#define UART_TRG_120 0x78
#define UART_TRG_128 0x80
+/*
+ * These definitions are for the RSA-DV II/S card, from
+ *
+ * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ */
+
+#define UART_RSA_BASE (-8)
+
+#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
+
+#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
+#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
+#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
+#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
+
+#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
+
+#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
+#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
+#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
+#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
+#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
+
+#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
+
+#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
+#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
+#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
+#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
+#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
+#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
+#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occured (1) */
+#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occured */
+
+#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
+
+#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
+
+#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
+
+#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
+
+/*
+ * The RSA DSV/II board has two fixed clock frequencies. One is the
+ * standard rate, and the other is 8 times faster.
+ */
+#define SERIAL_RSA_BAUD_BASE (921600)
+#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
+
#endif /* _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/05/22 11:27:00 1.1
+++ include/linux/serialP.h 2000/05/22 11:53:31
@@ -24,6 +24,11 @@
#include <linux/tqueue.h>
#include <linux/circ_buf.h>
#include <linux/wait.h>
+#if (LINUX_VERSION_CODE < 0x020300)
+/* Unfortunate, but Linux 2.2 needs async_icount defined here and
+ * it got moved in 2.3 */
+#include <linux/serial.h>
+#endif
struct serial_state {
int magic;
@@ -190,6 +195,9 @@
/* Do not use irq sharing for this device */
#define SPCI_FL_NO_SHIRQ 0x1000
-#define SPCI_FL_PNPDEFAULT (SPCI_FL_IRQRESOURCE)
+/* This is a PNP device */
+#define SPCI_FL_ISPNP 0x2000
+
+#define SPCI_FL_PNPDEFAULT (SPCI_FL_IRQRESOURCE|SPCI_FL_ISPNP)
#endif /* _LINUX_SERIAL_H */
===================================================================
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/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/05/22 11:27:00 1.1
+++ include/linux/pci_ids.h 2000/05/22 11:27:03
@@ -542,6 +542,8 @@
#define PCI_DEVICE_ID_DATABOOK_87144 0xb106
#define PCI_VENDOR_ID_PLX 0x10b5
+#define PCI_VENDOR_ID_PLX_ROMULUS 0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076
#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
#define PCI_DEVICE_ID_PLX_9050 0x9050
#define PCI_DEVICE_ID_PLX_9060 0x9060
-
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/
This archive was generated by hypermail 2b29 : Tue May 23 2000 - 21:00:22 EST