Date: Sun, 21 May 2000 01:05:00 -0400 To: torvalds@transmeta.com Subject: PATCH: Serial driver update, versus 2.3.99pre9-2 From: tytso@mit.edu Hi Linus, Enclosed please find updates to the serial driver, versus Linux 2-3.99pre9-2. Could you please apply these patches to the mainline? 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 Sun May 21 00:56:52 EDT 2000 by tytso@snap.thunk.org against Linux version 2.3.99pre9-2 =================================================================== 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/21 02:48:46 1.1 +++ drivers/char/serial.c 2000/05/21 04:30:25 @@ -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/21 02:48:46 1.1 +++ include/linux/serial.h 2000/05/21 04:30:25 @@ -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/21 02:48:46 1.1 +++ include/linux/serial_reg.h 2000/05/21 02:50:26 @@ -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/21 02:48:46 1.1 +++ include/linux/serialP.h 2000/05/21 04:30:47 @@ -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/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/21 02:48:46 1.1 +++ include/linux/pci_ids.h 2000/05/21 02:49:45 @@ -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/