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/

Reply via email to