Re: [PATCH] Re: [BUG] PCMCIA CardBus problems in 2.4.0-test8

From: Theodore Y. Ts'o (tytso@MIT.EDU)
Date: Thu Sep 14 2000 - 13:56:22 EST


   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