Date: Wed, 13 Sep 2000 17:17:01 -0400 From: Jeff Garzik <[EMAIL PROTECTED]> I ran with the idea, and created the attached patch, against 2.4.0-test8. It converts serial.c to the new PCI API (quite compactly, I might add) It should be possible with this patch to now hotplug serial devices, eliminating the need for serial_cb at all. This was a lot easier than I thought it would be. So my concerns about changing this before 2.4.0 are much reduced. OK, here are some patches for folks to try out. They fix a number of other bugs as well. If folks could try this out and let me know how well it works, I'd appreciate it. If I get positive comments, I'll send this to Linus for inclusion in 2.4. - Ted * Applied (by hand) Jeff Garzik's patch to use the new PCI interface. This should allow cardbus devices to work (at least when inserted); getting pulled out may be a different story. :-) * Fixed a bug which could cause us to overflow the flip buffer. (Thanks to Russel King for pointing out this problem.) * Moved ignore_status_mask test outside of special parity/frame/ overflow handling, since if CREAD is not set, all characters must be ignored (this is done by setting UART_LSR_DR). * Make sure the UART is taken out of enhanced mode after we put the UART to sleep, so we avoid accidentally triggering an unexpected UART feature. * Add support for DCI_PCCOM8 board. (Courtesy of Craig Schlenter <[EMAIL PROTECTED]>) * Restored code to prefer registering non-COM1-4 devices starting at ttyS4 if possible on the x86 platform. * Fix stupid comment bug (reversed Transmitter and Receiver FIFO level) Patch generated: on Thu Sep 14 14:36:10 EDT 2000 by [EMAIL PROTECTED] against Linux version 2.4.0test8 =================================================================== 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/09/14 16:39:36 1.1 +++ drivers/char/serial.c 2000/09/14 16:41:33 @@ -59,8 +59,8 @@ * int rs_init(void); */ -static char *serial_version = "5.02"; -static char *serial_revdate = "2000-08-09"; +static char *serial_version = "5.05"; +static char *serial_revdate = "2000-09-14"; /* * Serial driver configuration section. Here are the various options: @@ -560,7 +560,6 @@ { struct tty_struct *tty = info->tty; unsigned char ch; - int ignored = 0; struct async_icount *icount; icount = &info->state->icount; @@ -608,15 +607,8 @@ icount->overrun++; /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. + * Mask off conditions which should be ignored. */ - if (*status & info->ignore_status_mask) { - if (++ignored > 100) - break; - goto ignore_char; - } *status &= info->read_status_mask; #ifdef CONFIG_SERIAL_CONSOLE @@ -635,19 +627,6 @@ *tty->flip.flag_buf_ptr = TTY_PARITY; else if (*status & UART_LSR_FE) *tty->flip.flag_buf_ptr = TTY_FRAME; - if (*status & UART_LSR_OE) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - } } #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) if (break_pressed && info->line == sercons.index) { @@ -660,9 +639,23 @@ break_pressed = 0; } #endif - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + if ((*status & info->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((*status & UART_LSR_OE) && + (tty->flip.count < TTY_FLIPBUF_SIZE)) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + } ignore_char: *status = serial_inp(info, UART_LSR); } while (*status & UART_LSR_DR); @@ -1550,7 +1543,10 @@ /* Arrange to enter sleep mode */ serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_LCR, 0); serial_outp(info, UART_IER, UART_IERX_SLEEP); + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, 0); serial_outp(info, UART_LCR, 0); } if (info->state->type == PORT_16750) { @@ -4573,6 +4569,10 @@ SPCI_FL_BASE0, 1, 520833, 64, 3, NULL, 0x300 }, #endif + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE3, 8, 115200, + 8 }, /* Generic serial board */ { 0, 0, 0, 0, @@ -4622,6 +4622,49 @@ return 1; } +static int __devinit serial_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + struct pci_board *board; + + for (board = pci_boards; board->vendor; board++) { + if (board->vendor != (unsigned short) PCI_ANY_ID && + dev->vendor != board->vendor) + continue; + if (board->device != (unsigned short) PCI_ANY_ID && + dev->device != board->device) + continue; + if (board->subvendor != (unsigned short) PCI_ANY_ID && + pci_get_subvendor(dev) != board->subvendor) + continue; + if (board->subdevice != (unsigned short) PCI_ANY_ID && + pci_get_subdevice(dev) != board->subdevice) + continue; + break; + } + + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) + return -ENODEV; + + start_pci_pnp_board(dev, board); + + return 0; +} + + +static struct pci_device_id serial_pci_tbl[] __devinitdata = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, serial_pci_tbl); + +static struct pci_driver serial_pci_driver = { + name: "serial", + probe: serial_init_one, + id_table: serial_pci_tbl, +}; /* @@ -4633,36 +4676,17 @@ */ static void __init probe_serial_pci(void) { - struct pci_dev *dev = NULL; - struct pci_board *board; - #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - - pci_for_each_dev(dev) { - for (board = pci_boards; board->vendor; board++) { - if (board->vendor != (unsigned short) PCI_ANY_ID && - dev->vendor != board->vendor) - continue; - if (board->device != (unsigned short) PCI_ANY_ID && - dev->device != board->device) - continue; - if (board->subvendor != (unsigned short) PCI_ANY_ID && - pci_get_subvendor(dev) != board->subvendor) - continue; - if (board->subdevice != (unsigned short) PCI_ANY_ID && - pci_get_subdevice(dev) != board->subdevice) - continue; - break; - } - - if (board->vendor == 0 && serial_pci_guess_board(dev, board)) - continue; - - start_pci_pnp_board(dev, board); - } - + + /* Register call PCI serial devices. Null out + * the driver name upon failure, as a signal + * not to attempt to unregister the driver later + */ + if (pci_module_init (&serial_pci_driver) != 0) + serial_pci_driver.name[0] = 0; + #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); #endif @@ -5284,6 +5308,14 @@ (rs_table[i].iomem_base == req->iomem_base)) break; } +#ifdef __i386__ + if (i == NR_PORTS) { + for (i = 4; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } +#endif if (i == NR_PORTS) { for (i = 0; i < NR_PORTS; i++) if ((rs_table[i].type == PORT_UNKNOWN) && @@ -5422,6 +5454,11 @@ tmp_buf = NULL; free_page(pg); } + +#ifdef ENABLE_SERIAL_PCI + if (serial_pci_driver.name[0]) + pci_unregister_driver (&serial_pci_driver); +#endif } module_init(rs_init); =================================================================== 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/09/14 16:39:36 1.1 +++ include/linux/serial_reg.h 2000/09/14 16:39:49 @@ -156,8 +156,8 @@ * These register definitions are for the 16C950 */ #define UART_ASR 0x01 /* Additional Status Register */ -#define UART_RFL 0x03 /* Transmitter FIFO level */ -#define UART_TFL 0x04 /* Receiver FIFO level */ +#define UART_RFL 0x03 /* Receiver FIFO level */ +#define UART_TFL 0x04 /* Transmitter FIFO level */ #define UART_ICR 0x05 /* Index Control Register */ /* The 16950 ICR registers */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] Please read the FAQ at http://www.tux.org/lkml/