Date: Wed, 13 Sep 2000 17:17:01 -0400
From: Jeff Garzik <jgarzik@mandrakesoft.com>
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
<craig@qualica.com>)
* 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 tytso@snap.thunk.org
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 majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Fri Sep 15 2000 - 21:00:24 EST