summaryrefslogtreecommitdiffstats
path: root/drivers/char/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/serial.c')
-rw-r--r--drivers/char/serial.c833
1 files changed, 695 insertions, 138 deletions
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 458cbad6e..82d1bf131 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -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 = "5.01";
+static char *serial_revdate = "2000-05-29";
/*
* Serial driver configuration section. Here are the various options:
@@ -134,6 +137,8 @@ static char *serial_revdate = "2000-03-20";
#endif
#endif
+#define CONFIG_SERIAL_RSA
+
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
@@ -277,9 +282,20 @@ static struct serial_uart_config uart_config[] = {
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 serial_state rs_table[RS_TABLE_SIZE] = {
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 @@ static int serial_pci_board_idx = 0;
#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];
@@ -996,6 +1010,9 @@ static void do_softint(void *private_)
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
}
}
@@ -1090,6 +1107,50 @@ static void figure_IRQ_timeout(int irq)
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 +1188,7 @@ static int startup(struct async_struct * info)
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 +1206,7 @@ static int startup(struct async_struct * info)
/*
* 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 +1217,12 @@ static int startup(struct async_struct * info)
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 +1235,20 @@ static int startup(struct async_struct * info)
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 +1274,8 @@ static int startup(struct async_struct * info)
* 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 +1501,17 @@ static void shutdown(struct async_struct * info)
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 +1609,12 @@ static void change_speed(struct async_struct *info,
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 +1676,10 @@ static void change_speed(struct async_struct *info,
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;
}
@@ -1810,6 +1907,9 @@ static void rs_flush_buffer(struct tty_struct *tty)
info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1912,6 +2012,10 @@ static int get_serial_info(struct async_struct * info,
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 +2037,19 @@ static int set_serial_info(struct async_struct * info,
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 +2087,7 @@ static int set_serial_info(struct async_struct * info,
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 +2114,14 @@ static int set_serial_info(struct async_struct * info,
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 +2130,22 @@ static int set_serial_info(struct async_struct * info,
*/
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 +2584,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
/* 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 +3473,16 @@ static void autoconfig_startech_uarts(struct async_struct *info,
* 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 +3569,8 @@ static void autoconfig(struct serial_state * state)
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 +3595,9 @@ static void autoconfig(struct serial_state * state)
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 +3682,25 @@ static void autoconfig(struct serial_state * state)
}
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
}
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+ 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 +3720,23 @@ static void autoconfig(struct serial_state * state)
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 +3781,7 @@ static void __init printk_pnp_dev_id(unsigned short vendor,
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 +3793,28 @@ static _INLINE_ int get_pci_port(struct pci_dev *dev,
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 +3841,28 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
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 +3886,18 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
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 +3918,45 @@ __init
#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 +3989,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
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 +4034,36 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
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 +4074,9 @@ static struct pci_board pci_boards[] __initdata = {
* 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 +4166,10 @@ static struct pci_board pci_boards[] __initdata = {
{ 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 +4207,12 @@ static struct pci_board pci_boards[] __initdata = {
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 +4398,7 @@ static struct pci_board pci_boards[] __initdata = {
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 +4432,15 @@ static struct pci_board pci_boards[] __initdata = {
{ 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},
+ /* RAStel 2 port modem, gerg@moreton.com.au */
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
/*
* Untested PCI modems, sent in from various folks...
*/
@@ -4222,12 +4465,12 @@ static struct pci_board pci_boards[] __initdata = {
};
/*
- * 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;
@@ -4282,13 +4525,6 @@ static void __init probe_serial_pci(void)
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 &&
@@ -4306,7 +4542,7 @@ static void __init probe_serial_pci(void)
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,58 +4558,280 @@ static void __init probe_serial_pci(void)
#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 },
+struct pnp_board {
+ unsigned short vendor;
+ unsigned short device;
+};
+
+static struct pnp_board pnp_devices[] __initdata = {
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* Anchor Datacomm BV */
+ /* SXPro 144 External Data Fax Modem Plug & Play */
+ { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
+ /* SXPro 288 External Data Fax Modem Plug & Play */
+ { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
/* 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 },
+ { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
/* AZT3005 PnP SOUND DEVICE */
- { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
/* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+ /* Boca Research */
+ /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
/* Boca Research 33,600 ACF Modem */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+ /* Computer Peripherals Inc */
+ /* EuroViVa CommCenter-33.6 SP PnP */
+ { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
+ /* Creative Labs */
+ /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+ { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
+ /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+ { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
+ /* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
/* Creative Modem Blaster V.90 DI5660 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
+ /* FUJITSU */
+ /* Fujitsu 33600 PnP-I2 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
+ /* Fujitsu FMV-FX431 Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
+ /* Fujitsu 33600 PnP-I4 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
+ /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* Hayes */
+ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
+ /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
+ /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
+ /* Hayes Accura 56K Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
+ /* Hayes 288, V.34 + FAX */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
+ /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
+ /* IBM */
+ /* IBM Thinkpad 701 Internal Modem Voice */
+ { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
+ /* Intertex */
+ /* Intertex 28k8 33k6 Voice EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
+ /* Intertex 33k6 56k Voice EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
+ /* Intertex 28k8 33k6 Voice SP INT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
+ /* Kortex International */
+ /* KORTEX 28800 Externe PnP */
+ { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
+ /* KXPro 33.6 Vocal ASVD PnP */
+ { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
+ /* Lasat */
+ /* LASAT Internet 33600 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
+ /* Lasat Safire 560 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
+ /* Lasat Safire 336 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
+ /* Microcom, Inc. */
+ /* Microcom TravelPorte FAST V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
+ /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
+ /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
+ /* Microcom DeskPorte 28.8P Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+ /* Microcom DeskPorte 28.8S Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
+ /* Motorola */
+ /* Motorola BitSURFR Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
+ /* Motorola TA210 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
+ /* Motorola HMTA 200 (ISDN) Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
+ /* Motorola BitSURFR Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
+ /* Motorola Lifestyle 28.8 Internal */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
+ /* Motorola V.3400 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
+ /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
+ /* Motorola Power 28.8 V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
+ /* Motorola ModemSURFR External 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
+ /* Motorola Premier 33.6 Desktop Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
+ /* Motorola VoiceSURFR 56K External PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
+ /* Motorola ModemSURFR 56K External PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
+ /* Motorola ModemSURFR 56K Internal PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
+ /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
+ /* Motorola Premier 33.6 Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
+ /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
+ /* Motorola VoiceSURFR 56K Internal PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
+ /* Com 1 */
+ /* Deskline K56 Phone System PnP */
+ { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
+ /* PC Rider K56 Phone System PnP */
+ { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
/* 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 },
- /* SupraExpress 28.8 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* US Robotics Sporster 33600 Modem */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* U.S. Robotics 56K FAX INT */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 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 },
-
- /* These ID's are taken from M$ documentation */
- /* Compaq 14400 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Compaq 2400/9600 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
+ /* Generic */
/* Generic standard PC COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
/* Generic 16550A-compatible COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+ /* Compaq 14400 Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
+ /* Compaq 2400/9600 Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
+ /* Dial-Up Networking Serial Cable between 2 PCs */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
+ /* Dial-Up Networking Parallel Cable between 2 PCs */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
+ /* Standard 28800 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
+ /* Standard Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
+ /* Standard 9600 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
+ /* Standard 14400 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
+ /* Standard 28800 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
+ /* Standard 28800 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
+ /* Standard 28800 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
+ /* Standard PCMCIA Card Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
+ /* Rockwell */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF Internal PnP */
+ /* Modular Technology 33.6 Internal PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
+ /* Kortex International */
+ /* KORTEX 14400 Externe PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
+ /* Viking Components, Inc */
+ /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
+ /* Rockwell */
+ /* British Telecom */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF External PnP */
+ /* BT Prologue 33.6 External PnP */
+ /* Modular Technology 33.6 External PnP */
+ { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
+ /* Viking 56K FAX INT */
+ { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
+ /* SupraExpress 28.8 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
+ /* Phoebe Micro */
+ /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+ { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* 3Com Corp. */
+ /* Gateway Telepath IIvi 33.6 */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
+ /* Sportster Vi 14.4 PnP FAX Voicemail */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
+ /* U.S. Robotics 33.6K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
+ /* U.S. Robotics 56K FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
+ /* U.S. Robotics 56K Message */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
+ /* U.S. Robotics 56K FAX EXT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
+ /* U.S. Robotics 56K FAX INT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
+ /* U.S. Robotics 56K Voice EXT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
+ /* U.S. Robotics 56K Voice INT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
{ 0, }
};
@@ -4395,10 +4853,80 @@ static void inline avoid_irq_share(struct pci_dev *dev)
irq->map = map;
}
+static char *modem_names[] __initdata = {
+ "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 __init check_name(char *name)
+{
+ char **tmp = modem_names;
+
+ while (*tmp) {
+ if (strstr(name, *tmp))
+ return 1;
+ tmp++;
+ }
+ return 0;
+}
+
+static int inline check_compatible_id(struct pci_dev *dev)
+{
+ int i;
+ for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
+ if ((dev->vendor_compatible[i] ==
+ ISAPNP_VENDOR('P', 'N', 'P')) &&
+ (swab16(dev->device_compatible[i]) >= 0xc000) &&
+ (swab16(dev->device_compatible[i]) <= 0xdfff))
+ return 0;
+ return 1;
+}
+
+/*
+ * 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 (!(check_name(dev->name) || check_name(dev->bus->name)) &&
+ !(check_compatible_id(dev)))
+ return 1;
+
+ if (!res || 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;
- struct pci_board *board;
+ struct pnp_board *pnp_board;
+ struct pci_board board;
#ifdef SERIAL_DEBUG_PNP
printk("Entered probe_serial_pnp()\n");
@@ -4410,13 +4938,35 @@ static void __init probe_serial_pnp(void)
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) {
+ if (dev->active)
+ continue;
+
+ memset(&board, 0, sizeof(board));
+ board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
+ board.num_ports = 1;
+ board.base_baud = 115200;
+
+ for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
+ if ((dev->vendor == pnp_board->vendor) &&
+ (dev->device == pnp_board->device))
+ break;
+
+ if (pnp_board->vendor) {
+ board.vendor = pnp_board->vendor;
+ board.device = pnp_board->device;
+ /* Special case that's more efficient to hardcode */
+ if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+ board.device == ISAPNP_DEVICE(0x1021)))
+ board.flags |= SPCI_FL_NO_SHIRQ;
+ } else {
+ if (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
@@ -4478,7 +5028,7 @@ int __init rs_init(void)
#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";
@@ -4526,7 +5076,7 @@ int __init rs_init(void)
* 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";
@@ -4616,14 +5166,25 @@ int register_serial(struct serial_struct *req)
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;
}
if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+ if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
(rs_table[i].count == 0))
@@ -4637,11 +5198,11 @@ int register_serial(struct serial_struct *req)
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;
@@ -4649,7 +5210,7 @@ int register_serial(struct serial_struct *req)
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;
@@ -4722,10 +5283,10 @@ void rs_fini(void)
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);
@@ -4734,8 +5295,15 @@ void rs_fini(void)
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);
@@ -4882,9 +5450,6 @@ static int __init serial_console_setup(struct console *co, char *options)
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
-#if defined(CONFIG_KDB)
- extern int kdb_port;
-#endif
if (options) {
baud = simple_strtoul(options, NULL, 10);
@@ -4988,14 +5553,6 @@ static int __init serial_console_setup(struct console *co, char *options)
if (serial_in(info, UART_LSR) == 0xff)
return -1;
-#if defined(CONFIG_KDB)
- /*
- * Remember I/O port for kdb
- */
- if (kdb_port == 0 )
- kdb_port = ser->port;
-#endif /* CONFIG_KDB */
-
return 0;
}
@@ -5024,6 +5581,6 @@ void __init serial_console_init(void)
/*
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 -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/