Here's another iteration of my patch for better Netmos support.
This is against 2.6.12-rc1-mm1.  Kerry and Darac have sucessfully
tested a similar patch with 9835 cards.  I think we're ready for
wider testing, such as -mm.

There's a bugzilla entry for this here:
    http://bugzilla.kernel.org/show_bug.cgi?id=4334

I'd like to hear about any problems or issues (or even better,
about successes, of course :-)).  If you encounter a problem,
please include the dmesg log and the output of "lspci -vvn".


This should fix all the problems I know about with Netmos combo cards:
    - 9735, 9835, and 9855 are not supported
    - combo cards with parallel are erroneously claimed by serial driver
    - serial and parport_serial blindly probe for ports

parport_pc:
    Sort Netmos device IDs, no functional change.
parport_serial:
    Previously supported 9735 and 9835.  Add 9745, 9845, 9855, and
    add init hooks to discover how many serial/parallel ports are
    actually present (the boards are available in various configs).
    Add protection for overflow of static tables.
quirks:
    Detect Netmos combo (parallel + serial) cards and change class from
    SERIAL to OTHER to prevent serial driver from claiming them.
8250:
    Add init hook to discover the number of serial ports present.
    This prevents us from poking at unused BARs.
pci_ids:
    Add Netmos 9745, 9845, and sort.

Signed-off-by: Bjorn Helgaas <[EMAIL PROTECTED]>

diff -u -r 2.6.12-rc1-mm1/drivers/parport/parport_pc.c 
2.6.12-rc1-mm1-netmos/drivers/parport/parport_pc.c
--- 2.6.12-rc1-mm1/drivers/parport/parport_pc.c 2005-03-21 14:45:57.000000000 
-0700
+++ 2.6.12-rc1-mm1-netmos/drivers/parport/parport_pc.c  2005-03-21 
14:52:40.000000000 -0700
@@ -2733,11 +2733,11 @@
        aks_0100,
        mobility_pp,
        netmos_9705,
+       netmos_9715,
+       netmos_9755,
        netmos_9805,
        netmos_9815,
        netmos_9855,
-       netmos_9755,
-       netmos_9715
 };
 
 
@@ -2808,11 +2808,11 @@
        /* aks_0100 */                  { 1, { { 0, -1 }, } },
        /* mobility_pp */               { 1, { { 0, 1 }, } },
        /* netmos_9705 */               { 1, { { 0, -1 }, } }, /* untested */
+        /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* 
untested */
+        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* 
untested */
        /* netmos_9805 */               { 1, { { 0, -1 }, } }, /* untested */
        /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* 
untested */
        /* netmos_9855 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* 
untested */
-        /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* 
untested */
-        /* netmos_9715 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* 
untested */
 };
 
 static struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2885,16 +2885,16 @@
        /* NetMos communication controllers */
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9805,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 },
-       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 },
-       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 },
        { 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
diff -u -r 2.6.12-rc1-mm1/drivers/parport/parport_serial.c 
2.6.12-rc1-mm1-netmos/drivers/parport/parport_serial.c
--- 2.6.12-rc1-mm1/drivers/parport/parport_serial.c     2005-03-02 
00:38:25.000000000 -0700
+++ 2.6.12-rc1-mm1-netmos/drivers/parport/parport_serial.c      2005-03-22 
13:19:08.000000000 -0700
@@ -33,8 +33,7 @@
 enum parport_pc_pci_cards {
        titan_110l = 0,
        titan_210l,
-       netmos_9735,
-       netmos_9835,
+       netmos_9xx5_combo,
        avlab_1s1p,
        avlab_1s1p_650,
        avlab_1s1p_850,
@@ -51,9 +50,8 @@
        siig_2s1p_20x,
 };
 
-
 /* each element directly indexed from enum list, above */
-static struct parport_pc_pci {
+struct parport_pc_pci {
        int numports;
        struct { /* BAR (base address registers) numbers in the config
                     space header */
@@ -65,16 +63,30 @@
        /* If set, this is called immediately after pci_enable_device.
         * If it returns non-zero, no probing will take place and the
         * ports will not be used. */
-       int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
+       int (*preinit_hook) (struct pci_dev *pdev, struct parport_pc_pci *card,
+                               int autoirq, int autodma);
 
        /* If set, this is called after probing for ports.  If 'failed'
         * is non-zero we couldn't use any of the ports. */
-       void (*postinit_hook) (struct pci_dev *pdev, int failed);
-} cards[] __devinitdata = {
+       void (*postinit_hook) (struct pci_dev *pdev,
+                               struct parport_pc_pci *card, int failed);
+};
+
+static int __devinit netmos_parallel_init(struct pci_dev *dev, struct 
parport_pc_pci *card, int autoirq, int autodma)
+{
+       /*
+        * Netmos uses the subdevice ID to indicate the number of parallel
+        * and serial ports.  The form is 0x00PS, where <P> is the number of
+        * parallel ports and <S> is the number of serial ports.
+        */
+       card->numports = (dev->subsystem_device & 0xf0) >> 4;
+       return 0;
+}
+
+static struct parport_pc_pci cards[] __devinitdata = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
-       /* netmos_9735 (not tested) */  { 1, { { 2, -1 }, } },
-       /* netmos_9835 */               { 1, { { 2, -1 }, } },
+       /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, 
netmos_parallel_init },
        /* avlab_1s1p     */            { 1, { { 1, 2}, } },
        /* avlab_1s1p_650 */            { 1, { { 1, 2}, } },
        /* avlab_1s1p_850 */            { 1, { { 1, 2}, } },
@@ -98,9 +110,17 @@
        { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 },
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9745,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 },
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
+       { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
        /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
        { 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p},
        { 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650},
@@ -167,6 +187,12 @@
        return pci_siig20x_fn(dev, enable);
 }
 
+static int __devinit netmos_serial_init(struct pci_dev *dev, struct 
pci_board_no_ids *board, int enable)
+{
+       board->num_ports = dev->subsystem_device & 0xf;
+       return 0;
+}
+
 static struct pci_board_no_ids pci_boards[] __devinitdata = {
        /*
         * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
@@ -180,8 +206,7 @@
 
 /* titan_110l */       { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
 /* titan_210l */       { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-/* netmos_9735 (n/t)*/ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* netmos_9835 */      { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* netmos_9xx5_combo */        { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 
115200, 0, 0, netmos_serial_init },
 /* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
 /* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
 /* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
@@ -204,6 +229,7 @@
        struct pci_board_no_ids ser;
        int num_par;
        struct parport *port[PARPORT_MAX];
+       struct parport_pc_pci par;
 };
 
 static int __devinit get_pci_port (struct pci_dev *dev,
@@ -271,14 +297,15 @@
 static int __devinit serial_register (struct pci_dev *dev,
                                      const struct pci_device_id *id)
 {
-       struct pci_board_no_ids *board = &pci_boards[id->driver_data];
+       struct pci_board_no_ids *board;
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        struct serial_struct serial_req;
        int base_baud;
        int k;
        int success = 0;
 
-       priv->ser = *board;
+       priv->ser = pci_boards[id->driver_data];
+       board = &priv->ser;
        if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
                return 1;
 
@@ -289,6 +316,15 @@
 
        for (k = 0; k < board->num_ports; k++) {
                int line;
+
+               if (priv->num_ser == ARRAY_SIZE (priv->line)) {
+                       printk (KERN_WARNING
+                               "parport_serial: %s: only %u serial lines "
+                               "supported (%d reported)\n", pci_name (dev),
+                               ARRAY_SIZE (priv->line), board->num_ports);
+                       break;
+               }
+
                serial_req.irq = dev->irq;
                if (get_pci_port (dev, board, &serial_req, k))
                        break;
@@ -311,19 +347,31 @@
 static int __devinit parport_register (struct pci_dev *dev,
                                       const struct pci_device_id *id)
 {
+       struct parport_pc_pci *card;
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        int i = id->driver_data, n;
        int success = 0;
 
-       if (cards[i].preinit_hook &&
-           cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+       priv->par = cards[id->driver_data];
+       card = &priv->par;
+       if (card->preinit_hook &&
+           card->preinit_hook (dev, card, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
                return -ENODEV;
 
-       for (n = 0; n < cards[i].numports; n++) {
+       for (n = 0; n < card->numports; n++) {
                struct parport *port;
-               int lo = cards[i].addr[n].lo;
-               int hi = cards[i].addr[n].hi;
+               int lo = card->addr[n].lo;
+               int hi = card->addr[n].hi;
                unsigned long io_lo, io_hi;
+
+               if (priv->num_par == ARRAY_SIZE (priv->port)) {
+                       printk (KERN_WARNING
+                               "parport_serial: %s: only %u parallel ports "
+                               "supported (%d reported)\n", pci_name (dev),
+                               ARRAY_SIZE (priv->port), card->numports);
+                       break;
+               }
+
                io_lo = pci_resource_start (dev, lo);
                io_hi = 0;
                if ((hi >= 0) && (hi <= 6))
@@ -345,8 +393,8 @@
                }
        }
 
-       if (cards[i].postinit_hook)
-               cards[i].postinit_hook (dev, !success);
+       if (card->postinit_hook)
+               card->postinit_hook (dev, card, !success);
 
        return success ? 0 : 1;
 }
diff -u -r 2.6.12-rc1-mm1/drivers/pci/pci.ids 
2.6.12-rc1-mm1-netmos/drivers/pci/pci.ids
--- 2.6.12-rc1-mm1/drivers/pci/pci.ids  2005-03-21 14:46:00.000000000 -0700
+++ 2.6.12-rc1-mm1-netmos/drivers/pci/pci.ids   2005-03-22 13:21:27.000000000 
-0700
@@ -9903,14 +9903,25 @@
        6565  6565
 9710  NetMos Technology
        7780  USB IRDA-port
-       9815  PCI 9815 Multi-I/O Controller
+       9705  PCI 9705 Parallel Port
+       9715  PCI 9715 Dual Parallel Port
+       9735  PCI 9735 Multi-I/O Controller
+               1000 0002  0P2S (2 serial)
+               1000 0012  1P2S (1 parallel + 2 serial)
+       9745  PCI 9745 Multi-I/O Controller
+               1000 0002  0P2S (2 serial)
+               1000 0012  1P2S (1 parallel + 2 serial)
+       9755  PCI 9755 Parallel Port and ISA Bridge
+       9805  PCI 9805 Parallel Port
+       9815  PCI 9815 Dual Parallel Port
                1000 0020  2P0S (2 port parallel adaptor)
        9835  PCI 9835 Multi-I/O Controller
-               1000 0002  2S (16C550 UART)
+               1000 0002  0P2S (16C550 UART)
                1000 0012  1P2S
        9845  PCI 9845 Multi-I/O Controller
                1000 0004  0P4S (4 port 16550A serial card)
-               1000 0006  0P6S (6 port 16550a serial card)
+               1000 0006  0P6S (6 port 16550A serial card)
+               1000 0014  1P4S (4 port 16550A serial card + parallel)
        9855  PCI 9855 Multi-I/O Controller
                1000 0014  1P4S
 9902  Stargen Inc.
diff -u -r 2.6.12-rc1-mm1/drivers/pci/quirks.c 
2.6.12-rc1-mm1-netmos/drivers/pci/quirks.c
--- 2.6.12-rc1-mm1/drivers/pci/quirks.c 2005-03-21 14:46:01.000000000 -0700
+++ 2.6.12-rc1-mm1-netmos/drivers/pci/quirks.c  2005-03-22 13:19:35.000000000 
-0700
@@ -1259,6 +1259,40 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  
quirk_pcie_mch );
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  
quirk_pcie_mch );
 
+static void __devinit quirk_netmos(struct pci_dev *dev)
+{
+       unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
+       unsigned int num_serial = dev->subsystem_device & 0xf;
+
+       /*
+        * These Netmos parts are multiport serial devices with optional
+        * parallel ports.  Even when parallel ports are present, they
+        * are identified as class SERIAL, which means the serial driver
+        * will claim them.  To prevent this, mark them as class OTHER.
+        * These combo devices should be claimed by parport_serial.
+        *
+        * The subdevice ID is of the form 0x00PS, where <P> is the number
+        * of parallel ports and <S> is the number of serial ports.
+        */
+       switch (dev->device) {
+       case PCI_DEVICE_ID_NETMOS_9735:
+       case PCI_DEVICE_ID_NETMOS_9745:
+       case PCI_DEVICE_ID_NETMOS_9835:
+       case PCI_DEVICE_ID_NETMOS_9845:
+       case PCI_DEVICE_ID_NETMOS_9855:
+               if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+                   num_parallel) {
+                       printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+                               "%u serial); changing class SERIAL to OTHER "
+                               "(use parport_serial)\n",
+                               dev->device, num_parallel, num_serial);
+                       dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) |
+                           (dev->class & 0xff);
+               }
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct 
pci_fixup *end)
 {
        while (f < end) {
diff -u -r 2.6.12-rc1-mm1/drivers/serial/8250_pci.c 
2.6.12-rc1-mm1-netmos/drivers/serial/8250_pci.c
--- 2.6.12-rc1-mm1/drivers/serial/8250_pci.c    2005-03-21 14:46:02.000000000 
-0700
+++ 2.6.12-rc1-mm1-netmos/drivers/serial/8250_pci.c     2005-03-22 
13:27:24.000000000 -0700
@@ -577,6 +577,16 @@
        return 0;
 }
 
+static int __devinit pci_netmos_init(struct pci_dev *dev)
+{
+       /* subdevice 0x00PS means <P> parallel, <S> serial */
+       unsigned int num_serial = dev->subsystem_device & 0xf;
+
+       if (num_serial == 0)
+               return -ENODEV;
+       return num_serial;
+}
+
 static int
 pci_default_setup(struct pci_dev *dev, struct pci_board *board,
                  struct uart_port *port, int idx)
@@ -934,6 +944,17 @@
                .setup          = pci_default_setup,
        },
        /*
+        * Netmos cards
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_NETMOS,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = pci_netmos_init,
+               .setup          = pci_default_setup,
+       },
+       /*
         * Default "match everything" terminator entry
         */
        {
diff -u -r 2.6.12-rc1-mm1/include/linux/pci_ids.h 
2.6.12-rc1-mm1-netmos/include/linux/pci_ids.h
--- 2.6.12-rc1-mm1/include/linux/pci_ids.h      2005-03-21 14:46:03.000000000 
-0700
+++ 2.6.12-rc1-mm1-netmos/include/linux/pci_ids.h       2005-03-21 
14:52:40.000000000 -0700
@@ -2533,13 +2533,15 @@
 
 #define PCI_VENDOR_ID_NETMOS           0x9710
 #define PCI_DEVICE_ID_NETMOS_9705      0x9705
+#define PCI_DEVICE_ID_NETMOS_9715      0x9715
 #define PCI_DEVICE_ID_NETMOS_9735      0x9735
+#define PCI_DEVICE_ID_NETMOS_9745      0x9745
+#define PCI_DEVICE_ID_NETMOS_9755      0x9755
 #define PCI_DEVICE_ID_NETMOS_9805      0x9805
 #define PCI_DEVICE_ID_NETMOS_9815      0x9815
 #define PCI_DEVICE_ID_NETMOS_9835      0x9835
+#define PCI_DEVICE_ID_NETMOS_9845      0x9845
 #define PCI_DEVICE_ID_NETMOS_9855      0x9855
-#define PCI_DEVICE_ID_NETMOS_9755      0x9755
-#define PCI_DEVICE_ID_NETMOS_9715      0x9715
 
 #define PCI_SUBVENDOR_ID_EXSYS         0xd84d
 #define PCI_SUBDEVICE_ID_EXSYS_4014    0x4014



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to