Hi,
below is a patch that moves parport_serial.c from drivers/parport/
to drivers/char/ - this fixes the wrong link order when the drivers
are compiled into the kernel. The patch is large, but this is just
because it moves the file - no changes to paport_serial.c contents.
Now parport_serial is initialized after serial, but still before
any drivers that might need the parallel ports: lp, paride, plip...
This fixes serial ports on PCI parallel+serial I/O cards not being
initialized correctly (all shown as ttyS00) in a non-modular kernel.
I need this for NM9835 support (working fine here on two machines) -
I'd like to submit a separate patch for this (so the parport_serial.c
NM9835-related changes are easy to see, after the file is moved to
the new place). Please let me know if you see any problems with
this patch - it certainly looks like a bug fix to me...
Thanks,
Marek
diff -urN orig/linux-2.4.20-pre8/drivers/char/ChangeLog linux-2.4.20-pre8/drivers/char/ChangeLog
--- orig/linux-2.4.20-pre8/drivers/char/ChangeLog Tue Aug 14 01:37:33 2001
+++ linux-2.4.20-pre8/drivers/char/ChangeLog Thu Sep 26 21:37:59 2002
@@ -1,3 +1,8 @@
+2002-09-21 Marek Michalkiewicz <[email protected]>
+
+ * parport_serial.c: Move from ../parport/ here, must be initialised
+ after serial.c for register_serial to work.
+
2001-08-11 Tim Waugh <[email protected]>
* serial.c (get_pci_port): Deal with awkward Titan cards.
diff -urN orig/linux-2.4.20-pre8/drivers/char/Makefile linux-2.4.20-pre8/drivers/char/Makefile
--- orig/linux-2.4.20-pre8/drivers/char/Makefile Thu Sep 26 21:31:12 2002
+++ linux-2.4.20-pre8/drivers/char/Makefile Thu Sep 26 21:36:36 2002
@@ -153,6 +153,7 @@
obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
obj-$(CONFIG_SERIAL) += $(SERIAL)
+obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o
obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
obj-$(CONFIG_SERIAL_21285) += serial_21285.o
obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
diff -urN orig/linux-2.4.20-pre8/drivers/char/parport_serial.c linux-2.4.20-pre8/drivers/char/parport_serial.c
--- orig/linux-2.4.20-pre8/drivers/char/parport_serial.c Thu Jan 1 01:00:00 1970
+++ linux-2.4.20-pre8/drivers/char/parport_serial.c Sat Aug 3 02:39:44 2002
@@ -0,0 +1,426 @@
+/*
+ * Support for common PCI multi-I/O cards (which is most of them)
+ *
+ * Copyright (C) 2001 Tim Waugh <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Multi-function PCI cards are supposed to present separate logical
+ * devices on the bus. A common thing to do seems to be to just use
+ * one logical device with lots of base address registers for both
+ * parallel ports and serial ports. This driver is for dealing with
+ * that.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/list.h>
+
+#include <asm/serial.h>
+
+enum parport_pc_pci_cards {
+ titan_110l = 0,
+ titan_210l,
+ avlab_1s1p,
+ avlab_1s1p_650,
+ avlab_1s1p_850,
+ avlab_1s2p,
+ avlab_1s2p_650,
+ avlab_1s2p_850,
+ avlab_2s1p,
+ avlab_2s1p_650,
+ avlab_2s1p_850,
+ siig_1s1p_10x,
+ siig_2s1p_10x,
+ siig_2p1s_20x,
+ siig_1s1p_20x,
+ siig_2s1p_20x,
+};
+
+
+/* each element directly indexed from enum list, above */
+static struct parport_pc_pci {
+ int numports;
+ struct { /* BAR (base address registers) numbers in the config
+ space header */
+ int lo;
+ int hi; /* -1 if not there, >6 for offset-method (max
+ BAR is 6) */
+ } addr[4];
+
+ /* 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);
+
+ /* 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 = {
+ /* titan_110l */ { 1, { { 3, -1 }, } },
+ /* titan_210l */ { 1, { { 3, -1 }, } },
+ /* avlab_1s1p */ { 1, { { 1, 2}, } },
+ /* avlab_1s1p_650 */ { 1, { { 1, 2}, } },
+ /* avlab_1s1p_850 */ { 1, { { 1, 2}, } },
+ /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
+ /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} },
+ /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} },
+ /* avlab_2s1p */ { 1, { { 2, 3}, } },
+ /* avlab_2s1p_650 */ { 1, { { 2, 3}, } },
+ /* avlab_2s1p_850 */ { 1, { { 2, 3}, } },
+ /* siig_1s1p_10x */ { 1, { { 3, 4 }, } },
+ /* siig_2s1p_10x */ { 1, { { 4, 5 }, } },
+ /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } },
+ /* siig_1s1p_20x */ { 1, { { 1, 2 }, } },
+ /* siig_2s1p_20x */ { 1, { { 2, 3 }, } },
+};
+
+static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = {
+ /* PCI cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
+ /* 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},
+ { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850},
+ { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p},
+ { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650},
+ { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850},
+ { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p},
+ { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650},
+ { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850},
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
+
+ { 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
+
+struct pci_board_no_ids {
+ int flags;
+ int num_ports;
+ int base_baud;
+ int uart_offset;
+ int reg_shift;
+ int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board,
+ int enable);
+ int first_uart_offset;
+};
+
+static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
+{
+ return pci_siig10x_fn(dev, NULL, enable);
+}
+
+static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
+{
+ return pci_siig20x_fn(dev, NULL, enable);
+}
+
+static struct pci_board_no_ids pci_boards[] __devinitdata = {
+ /*
+ * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+ * Offset to get to next UART's registers,
+ * Register shift to use for memory-mapped I/O,
+ * Initialization function, first UART offset
+ */
+
+// Cards not tested are marked n/t
+// If you have one of these cards and it works for you, please tell me..
+
+/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
+/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
+/* 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 },
+/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn },
+/* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn },
+/* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
+/* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
+/* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
+};
+
+struct parport_serial_private {
+ int num_ser;
+ int line[20];
+ struct pci_board_no_ids ser;
+ int num_par;
+ struct parport *port[PARPORT_MAX];
+};
+
+static int __devinit get_pci_port (struct pci_dev *dev,
+ struct pci_board_no_ids *board,
+ struct serial_struct *req,
+ int idx)
+{
+ unsigned long port;
+ int base_idx;
+ int max_port;
+ int offset;
+
+ base_idx = SPCI_FL_GET_BASE(board->flags);
+ if (board->flags & SPCI_FL_BASE_TABLE)
+ base_idx += idx;
+
+ if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+ max_port = pci_resource_len(dev, base_idx) / 8;
+ if (idx >= max_port)
+ return 1;
+ }
+
+ offset = board->first_uart_offset;
+
+ /* Timedia/SUNIX uses a mixture of BARs and offsets */
+ /* Ugh, this is ugly as all hell --- TYT */
+ if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */
+ switch(idx) {
+ case 0: base_idx=0;
+ break;
+ case 1: base_idx=0; offset=8;
+ break;
+ case 2: base_idx=1;
+ break;
+ case 3: base_idx=1; offset=8;
+ break;
+ case 4: /* BAR 2*/
+ case 5: /* BAR 3 */
+ case 6: /* BAR 4*/
+ case 7: base_idx=idx-2; /* BAR 5*/
+ }
+
+ port = pci_resource_start(dev, base_idx) + offset;
+
+ if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+ port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+ if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) {
+ int high_bits_offset = ((sizeof(long)-sizeof(int))*8);
+ req->port = port;
+ if (high_bits_offset)
+ req->port_high = port >> high_bits_offset;
+ else
+ req->port_high = 0;
+ return 0;
+ }
+ req->io_type = SERIAL_IO_MEM;
+ req->iomem_base = ioremap(port, board->uart_offset);
+ req->iomem_reg_shift = board->reg_shift;
+ req->port = 0;
+ return req->iomem_base ? 0 : 1;
+}
+
+/* Register the serial port(s) of a PCI card. */
+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 parport_serial_private *priv = pci_get_drvdata (dev);
+ struct serial_struct serial_req;
+ int base_baud;
+ int k;
+ int success = 0;
+
+ priv->ser = *board;
+ if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
+ return 1;
+
+ base_baud = board->base_baud;
+ if (!base_baud)
+ base_baud = BASE_BAUD;
+ memset (&serial_req, 0, sizeof (serial_req));
+
+ for (k = 0; k < board->num_ports; k++) {
+ int line;
+ serial_req.irq = dev->irq;
+ if (get_pci_port (dev, board, &serial_req, k))
+ break;
+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+ serial_req.baud_base = base_baud;
+ line = register_serial (&serial_req);
+ if (line < 0) {
+ printk (KERN_DEBUG
+ "parport_serial: register_serial failed\n");
+ continue;
+ }
+ priv->line[priv->num_ser++] = line;
+ success = 1;
+ }
+
+ return success ? 0 : 1;
+}
+
+/* Register the parallel port(s) of a PCI card. */
+static int __devinit parport_register (struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ 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))
+ return -ENODEV;
+
+ for (n = 0; n < cards[i].numports; n++) {
+ struct parport *port;
+ int lo = cards[i].addr[n].lo;
+ int hi = cards[i].addr[n].hi;
+ unsigned long io_lo, io_hi;
+ io_lo = pci_resource_start (dev, lo);
+ io_hi = 0;
+ if ((hi >= 0) && (hi <= 6))
+ io_hi = pci_resource_start (dev, hi);
+ else if (hi > 6)
+ io_lo += hi; /* Reinterpret the meaning of
+ "hi" as an offset (see SYBA
+ def.) */
+ /* TODO: test if sharing interrupts works */
+ printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
+ "I/O at %#lx(%#lx)\n",
+ parport_serial_pci_tbl[i].vendor,
+ parport_serial_pci_tbl[i].device, io_lo, io_hi);
+ port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
+ PARPORT_DMA_NONE, dev);
+ if (port) {
+ priv->port[priv->num_par++] = port;
+ success = 1;
+ }
+ }
+
+ if (cards[i].postinit_hook)
+ cards[i].postinit_hook (dev, !success);
+
+ return success ? 0 : 1;
+}
+
+static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct parport_serial_private *priv;
+ int err;
+
+ priv = kmalloc (sizeof *priv, GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->num_ser = priv->num_par = 0;
+ pci_set_drvdata (dev, priv);
+
+ err = pci_enable_device (dev);
+ if (err) {
+ pci_set_drvdata (dev, NULL);
+ kfree (priv);
+ return err;
+ }
+
+ if (parport_register (dev, id)) {
+ pci_set_drvdata (dev, NULL);
+ kfree (priv);
+ return -ENODEV;
+ }
+
+ if (serial_register (dev, id)) {
+ int i;
+ for (i = 0; i < priv->num_par; i++)
+ parport_pc_unregister_port (priv->port[i]);
+ pci_set_drvdata (dev, NULL);
+ kfree (priv);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
+{
+ struct parport_serial_private *priv = pci_get_drvdata (dev);
+ int i;
+
+ // Serial ports
+ for (i = 0; i < priv->num_ser; i++) {
+ unregister_serial (priv->line[i]);
+
+ if (priv->ser.init_fn)
+ (priv->ser.init_fn) (dev, &priv->ser, 0);
+ }
+ pci_set_drvdata (dev, NULL);
+
+ // Parallel ports
+ for (i = 0; i < priv->num_par; i++)
+ parport_pc_unregister_port (priv->port[i]);
+
+ kfree (priv);
+ return;
+}
+
+static struct pci_driver parport_serial_pci_driver = {
+ name: "parport_serial",
+ id_table: parport_serial_pci_tbl,
+ probe: parport_serial_pci_probe,
+ remove: __devexit_p(parport_serial_pci_remove),
+};
+
+
+static int __init parport_serial_init (void)
+{
+ return pci_module_init (&parport_serial_pci_driver);
+}
+
+static void __exit parport_serial_exit (void)
+{
+ pci_unregister_driver (&parport_serial_pci_driver);
+ return;
+}
+
+MODULE_AUTHOR("Tim Waugh <[email protected]>");
+MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
+MODULE_LICENSE("GPL");
+
+module_init(parport_serial_init);
+module_exit(parport_serial_exit);
diff -urN orig/linux-2.4.20-pre8/drivers/parport/ChangeLog linux-2.4.20-pre8/drivers/parport/ChangeLog
--- orig/linux-2.4.20-pre8/drivers/parport/ChangeLog Sat Aug 3 02:39:44 2002
+++ linux-2.4.20-pre8/drivers/parport/ChangeLog Thu Sep 26 21:37:25 2002
@@ -1,3 +1,8 @@
+2002-09-21 Marek Michalkiewicz <[email protected]>
+
+ * parport_serial.c: Move from here to ../char/, must be initialised
+ after serial.c for register_serial to work.
+
2002-04-25 Tim Waugh <[email protected]>
* parport_serial.c, parport_pc.c: Move some SIIG cards around.
diff -urN orig/linux-2.4.20-pre8/drivers/parport/Makefile linux-2.4.20-pre8/drivers/parport/Makefile
--- orig/linux-2.4.20-pre8/drivers/parport/Makefile Fri Sep 14 01:04:43 2001
+++ linux-2.4.20-pre8/drivers/parport/Makefile Thu Sep 26 21:36:36 2002
@@ -22,7 +22,6 @@
obj-$(CONFIG_PARPORT) += parport.o
obj-$(CONFIG_PARPORT_PC) += parport_pc.o
-obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o
obj-$(CONFIG_PARPORT_PC_PCMCIA)+= parport_cs.o
obj-$(CONFIG_PARPORT_AMIGA) += parport_amiga.o
obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
diff -urN orig/linux-2.4.20-pre8/drivers/parport/parport_serial.c linux-2.4.20-pre8/drivers/parport/parport_serial.c
--- orig/linux-2.4.20-pre8/drivers/parport/parport_serial.c Sat Aug 3 02:39:44 2002
+++ linux-2.4.20-pre8/drivers/parport/parport_serial.c Thu Jan 1 01:00:00 1970
@@ -1,426 +0,0 @@
-/*
- * Support for common PCI multi-I/O cards (which is most of them)
- *
- * Copyright (C) 2001 Tim Waugh <[email protected]>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- *
- * Multi-function PCI cards are supposed to present separate logical
- * devices on the bus. A common thing to do seems to be to just use
- * one logical device with lots of base address registers for both
- * parallel ports and serial ports. This driver is for dealing with
- * that.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/parport.h>
-#include <linux/parport_pc.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/list.h>
-
-#include <asm/serial.h>
-
-enum parport_pc_pci_cards {
- titan_110l = 0,
- titan_210l,
- avlab_1s1p,
- avlab_1s1p_650,
- avlab_1s1p_850,
- avlab_1s2p,
- avlab_1s2p_650,
- avlab_1s2p_850,
- avlab_2s1p,
- avlab_2s1p_650,
- avlab_2s1p_850,
- siig_1s1p_10x,
- siig_2s1p_10x,
- siig_2p1s_20x,
- siig_1s1p_20x,
- siig_2s1p_20x,
-};
-
-
-/* each element directly indexed from enum list, above */
-static struct parport_pc_pci {
- int numports;
- struct { /* BAR (base address registers) numbers in the config
- space header */
- int lo;
- int hi; /* -1 if not there, >6 for offset-method (max
- BAR is 6) */
- } addr[4];
-
- /* 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);
-
- /* 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 = {
- /* titan_110l */ { 1, { { 3, -1 }, } },
- /* titan_210l */ { 1, { { 3, -1 }, } },
- /* avlab_1s1p */ { 1, { { 1, 2}, } },
- /* avlab_1s1p_650 */ { 1, { { 1, 2}, } },
- /* avlab_1s1p_850 */ { 1, { { 1, 2}, } },
- /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} },
- /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} },
- /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} },
- /* avlab_2s1p */ { 1, { { 2, 3}, } },
- /* avlab_2s1p_650 */ { 1, { { 2, 3}, } },
- /* avlab_2s1p_850 */ { 1, { { 2, 3}, } },
- /* siig_1s1p_10x */ { 1, { { 3, 4 }, } },
- /* siig_2s1p_10x */ { 1, { { 4, 5 }, } },
- /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } },
- /* siig_1s1p_20x */ { 1, { { 1, 2 }, } },
- /* siig_2s1p_20x */ { 1, { { 2, 3 }, } },
-};
-
-static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = {
- /* PCI cards */
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
- { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
- /* 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},
- { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850},
- { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p},
- { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650},
- { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850},
- { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p},
- { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650},
- { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850},
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
-
- { 0, } /* terminate list */
-};
-MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
-
-struct pci_board_no_ids {
- int flags;
- int num_ports;
- int base_baud;
- int uart_offset;
- int reg_shift;
- int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board,
- int enable);
- int first_uart_offset;
-};
-
-static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
-{
- return pci_siig10x_fn(dev, NULL, enable);
-}
-
-static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable)
-{
- return pci_siig20x_fn(dev, NULL, enable);
-}
-
-static struct pci_board_no_ids pci_boards[] __devinitdata = {
- /*
- * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
- * Offset to get to next UART's registers,
- * Register shift to use for memory-mapped I/O,
- * Initialization function, first UART offset
- */
-
-// Cards not tested are marked n/t
-// If you have one of these cards and it works for you, please tell me..
-
-/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
-/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
-/* 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 },
-/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
-/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
-/* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn },
-/* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn },
-/* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
-/* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
-/* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
-};
-
-struct parport_serial_private {
- int num_ser;
- int line[20];
- struct pci_board_no_ids ser;
- int num_par;
- struct parport *port[PARPORT_MAX];
-};
-
-static int __devinit get_pci_port (struct pci_dev *dev,
- struct pci_board_no_ids *board,
- struct serial_struct *req,
- int idx)
-{
- unsigned long port;
- int base_idx;
- int max_port;
- int offset;
-
- base_idx = SPCI_FL_GET_BASE(board->flags);
- if (board->flags & SPCI_FL_BASE_TABLE)
- base_idx += idx;
-
- if (board->flags & SPCI_FL_REGION_SZ_CAP) {
- max_port = pci_resource_len(dev, base_idx) / 8;
- if (idx >= max_port)
- return 1;
- }
-
- offset = board->first_uart_offset;
-
- /* Timedia/SUNIX uses a mixture of BARs and offsets */
- /* Ugh, this is ugly as all hell --- TYT */
- if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */
- switch(idx) {
- case 0: base_idx=0;
- break;
- case 1: base_idx=0; offset=8;
- break;
- case 2: base_idx=1;
- break;
- case 3: base_idx=1; offset=8;
- break;
- case 4: /* BAR 2*/
- case 5: /* BAR 3 */
- case 6: /* BAR 4*/
- case 7: base_idx=idx-2; /* BAR 5*/
- }
-
- port = pci_resource_start(dev, base_idx) + offset;
-
- if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
- port += idx * (board->uart_offset ? board->uart_offset : 8);
-
- if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) {
- int high_bits_offset = ((sizeof(long)-sizeof(int))*8);
- req->port = port;
- if (high_bits_offset)
- req->port_high = port >> high_bits_offset;
- else
- req->port_high = 0;
- return 0;
- }
- req->io_type = SERIAL_IO_MEM;
- req->iomem_base = ioremap(port, board->uart_offset);
- req->iomem_reg_shift = board->reg_shift;
- req->port = 0;
- return req->iomem_base ? 0 : 1;
-}
-
-/* Register the serial port(s) of a PCI card. */
-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 parport_serial_private *priv = pci_get_drvdata (dev);
- struct serial_struct serial_req;
- int base_baud;
- int k;
- int success = 0;
-
- priv->ser = *board;
- if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
- return 1;
-
- base_baud = board->base_baud;
- if (!base_baud)
- base_baud = BASE_BAUD;
- memset (&serial_req, 0, sizeof (serial_req));
-
- for (k = 0; k < board->num_ports; k++) {
- int line;
- serial_req.irq = dev->irq;
- if (get_pci_port (dev, board, &serial_req, k))
- break;
- serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
- serial_req.baud_base = base_baud;
- line = register_serial (&serial_req);
- if (line < 0) {
- printk (KERN_DEBUG
- "parport_serial: register_serial failed\n");
- continue;
- }
- priv->line[priv->num_ser++] = line;
- success = 1;
- }
-
- return success ? 0 : 1;
-}
-
-/* Register the parallel port(s) of a PCI card. */
-static int __devinit parport_register (struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- 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))
- return -ENODEV;
-
- for (n = 0; n < cards[i].numports; n++) {
- struct parport *port;
- int lo = cards[i].addr[n].lo;
- int hi = cards[i].addr[n].hi;
- unsigned long io_lo, io_hi;
- io_lo = pci_resource_start (dev, lo);
- io_hi = 0;
- if ((hi >= 0) && (hi <= 6))
- io_hi = pci_resource_start (dev, hi);
- else if (hi > 6)
- io_lo += hi; /* Reinterpret the meaning of
- "hi" as an offset (see SYBA
- def.) */
- /* TODO: test if sharing interrupts works */
- printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
- "I/O at %#lx(%#lx)\n",
- parport_serial_pci_tbl[i].vendor,
- parport_serial_pci_tbl[i].device, io_lo, io_hi);
- port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, dev);
- if (port) {
- priv->port[priv->num_par++] = port;
- success = 1;
- }
- }
-
- if (cards[i].postinit_hook)
- cards[i].postinit_hook (dev, !success);
-
- return success ? 0 : 1;
-}
-
-static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- struct parport_serial_private *priv;
- int err;
-
- priv = kmalloc (sizeof *priv, GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->num_ser = priv->num_par = 0;
- pci_set_drvdata (dev, priv);
-
- err = pci_enable_device (dev);
- if (err) {
- pci_set_drvdata (dev, NULL);
- kfree (priv);
- return err;
- }
-
- if (parport_register (dev, id)) {
- pci_set_drvdata (dev, NULL);
- kfree (priv);
- return -ENODEV;
- }
-
- if (serial_register (dev, id)) {
- int i;
- for (i = 0; i < priv->num_par; i++)
- parport_pc_unregister_port (priv->port[i]);
- pci_set_drvdata (dev, NULL);
- kfree (priv);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
-{
- struct parport_serial_private *priv = pci_get_drvdata (dev);
- int i;
-
- // Serial ports
- for (i = 0; i < priv->num_ser; i++) {
- unregister_serial (priv->line[i]);
-
- if (priv->ser.init_fn)
- (priv->ser.init_fn) (dev, &priv->ser, 0);
- }
- pci_set_drvdata (dev, NULL);
-
- // Parallel ports
- for (i = 0; i < priv->num_par; i++)
- parport_pc_unregister_port (priv->port[i]);
-
- kfree (priv);
- return;
-}
-
-static struct pci_driver parport_serial_pci_driver = {
- name: "parport_serial",
- id_table: parport_serial_pci_tbl,
- probe: parport_serial_pci_probe,
- remove: __devexit_p(parport_serial_pci_remove),
-};
-
-
-static int __init parport_serial_init (void)
-{
- return pci_module_init (&parport_serial_pci_driver);
-}
-
-static void __exit parport_serial_exit (void)
-{
- pci_unregister_driver (&parport_serial_pci_driver);
- return;
-}
-
-MODULE_AUTHOR("Tim Waugh <[email protected]>");
-MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
-MODULE_LICENSE("GPL");
-
-module_init(parport_serial_init);
-module_exit(parport_serial_exit);
On Thu, 26 Sep 2002, Marek Michalkiewicz wrote:
> I need this for NM9835 support (working fine here on two machines) -
> I'd like to submit a separate patch for this (so the parport_serial.c
> NM9835-related changes are easy to see, after the file is moved to
> the new place). Please let me know if you see any problems with
> this patch - it certainly looks like a bug fix to me...
Ahh return of the 9835 =) This POS never goes away...
Zwane
--
function.linuxpower.ca
> Ahh return of the 9835 =) This POS never goes away...
Just curions, what does POS mean here? :)
These "ST Lab" 2S1P cards are the only kind of PCI I/O card that I was
able to find here at a reasonable price (about $25), and it took me
quite some time to find a company that actually sells them (in stock,
not only in the price list - but if asked, "maybe in two weeks" for 3
months now...). In general, it is difficult to buy anything non-USB
here at reasonable (not "industrial PC") prices. Without these cards,
I'd have to buy USB hubs and USB/serial converters instead...
The patch fixes a bug for _all_ PCI parallel+serial cards, and does
not add NM9835 support yet (I'd like to submit that next - I would
really like to see it in the standard kernel).
Thanks,
Marek
On Fri, 27 Sep 2002, Marek Michalkiewicz wrote:
> > Ahh return of the 9835 =) This POS never goes away...
>
> Just curions, what does POS mean here? :)
Piece-Of-Shh... ;)
> These "ST Lab" 2S1P cards are the only kind of PCI I/O card that I was
> able to find here at a reasonable price (about $25), and it took me
> quite some time to find a company that actually sells them (in stock,
> not only in the price list - but if asked, "maybe in two weeks" for 3
> months now...). In general, it is difficult to buy anything non-USB
> here at reasonable (not "industrial PC") prices. Without these cards,
> I'd have to buy USB hubs and USB/serial converters instead...
>
> The patch fixes a bug for _all_ PCI parallel+serial cards, and does
> not add NM9835 support yet (I'd like to submit that next - I would
> really like to see it in the standard kernel).
True;
00:0e.0 Communication controller: NetMos Technology 222N-2 I/O Card (2S+1P) (rev 01)
PCI parallel port detected: 9710:9835, I/O at 0xb000(0xa800)
parport0: PC-style at 0xb000 (0xa800) [PCSPP,TRISTATE]
ttyS04 at port 0xb800 (irq = 5) is a 16550A
ttyS05 at port 0xb400 (irq = 5) is a 16550A
I'm running this with shared parport IRQs since i have another PCI device
sharing that IRQ too (its a real mess)
I have been using this setup for a while now.
Zwane
--
function.linuxpower.ca
> Piece-Of-Shh... ;)
Hmm, works fine here so far, though I only have tested the parallel
port in polling mode (that's how it is set up by default).
> 00:0e.0 Communication controller: NetMos Technology 222N-2 I/O Card (2S+1P) (rev 01)
Mine is "ST Lab PCI 2S1P IO Controller Card" - which has no serial
configuration EEPROM (there is an empty place for it on the PCB).
The 9710:9835 numbers are the generic defaults hardwired in the
NM9835 chip, not specific to any board type like "222N-2".
> I have been using this setup for a while now.
I haven't heard anything from the kernel people yet - any chances of
getting these changes into the official 2.4.x source? I can make
a second patch (NetMos support) after the first one is accepted...
Marek
On Sun, 29 Sep 2002, Marek Michalkiewicz wrote:
> I haven't heard anything from the kernel people yet - any chances of
> getting these changes into the official 2.4.x source? I can make
> a second patch (NetMos support) after the first one is accepted...
I submitted both a parport sharing (i am using interrupt driven parport,
which is needed due to both serial ports using the same irq) and netmos
patch a while ago, Tim was concerned about issues encountered
by folks previously wrt the netmos.
Tests run with this setup was copying a cd from a parport cd drive and
doing heavy serial i/o on both serial ports. the md5sum on the resultant
cd image was verified.
Zwane
--
function.linuxpower.ca
> I submitted both a parport sharing (i am using interrupt driven parport,
> which is needed due to both serial ports using the same irq) and netmos
> patch a while ago, Tim was concerned about issues encountered
> by folks previously wrt the netmos.
What are these issues? If they are caused by IRQ sharing between
parallel and serial ports, and parport works fine in polling mode
(it does for me, I've done quite a lot of printing), I'd suggest
to use polling for now, and leave IRQ sharing support for later...
Serial ports are more important for me right now, but 2S1P cards
are easier to find and even cheaper (!) than 2S cards... There is
a disadvantage - extra slot (or holes in the back of the box) needed
for the two DB9 connectors connected to the card with ribbon cables.
The parport_serial / serial link order issue is quite old - is
everyone using modular kernels (not affected by it) these days?
Perhaps all of parport_serial should still be CONFIG_EXPERIMENTAL ;)
Marek
On Sun, 29 Sep 2002, Marek Michalkiewicz wrote:
> What are these issues? If they are caused by IRQ sharing between
> parallel and serial ports, and parport works fine in polling mode
> (it does for me, I've done quite a lot of printing), I'd suggest
> to use polling for now, and leave IRQ sharing support for later...
Tim would know better there since he removed it, but iirc it had something
to do with the BARs used, hmm your card has the same PCI id and is serial
neutered to an extent, what happens if you treat it as if it really does
have both serial ports there? Does it still work without causing other
problems so you can safely ignore it? FYI, Interrupt driven works great
for me.
> The parport_serial / serial link order issue is quite old - is
> everyone using modular kernels (not affected by it) these days?
> Perhaps all of parport_serial should still be CONFIG_EXPERIMENTAL ;)
link order shouldn't affect the decision seeing as it affects all
parport_serial anyway. You might have to wait it out and see what Tim/Ed
have to say but i do have patches for both lying about.
Cheers,
Zwane
--
function.linuxpower.ca
On Thu, Sep 26, 2002 at 10:05:16PM +0200, Marek Michalkiewicz wrote:
> below is a patch that moves parport_serial.c from drivers/parport/
> to drivers/char/ - this fixes the wrong link order when the drivers
> are compiled into the kernel.
What was wrong with the original, much smaller patch that you sent me
previously (below)?
I'm happy to accept whichever patch is the better.
Tim.
*/
2002-08-28 Marek Michalkiewicz <[email protected]> [sent 2002-08-28]
* drivers/char/serial.c (register_serial): Call rs_init() if it
hasn't already been called. For parport_serial.c.
--- linux/drivers/char/serial.c.init_order 2002-08-28 20:55:10.000000000 +0100
+++ linux/drivers/char/serial.c 2002-08-28 21:00:24.000000000 +0100
@@ -254,6 +254,7 @@
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
+static int serial_initialized;
static struct timer_list serial_timer;
@@ -5385,6 +5386,10 @@
int i;
struct serial_state * state;
+ if (serial_initialized)
+ return;
+ serial_initialized++;
+
init_bh(SERIAL_BH, do_serial_bh);
init_timer(&serial_timer);
serial_timer.function = rs_timer;
@@ -5603,6 +5608,11 @@
struct async_struct *info;
unsigned long port;
+ if (!serial_initialized) {
+ printk("register_serial(): calling rs_init()\n");
+ rs_init();
+ }
+
port = req->port;
if (HIGH_BITS_OFFSET)
port += (unsigned long) req->port_high << HIGH_BITS_OFFSET;
On Mon, Sep 30, 2002 at 10:40:12AM +0100, Tim Waugh wrote:
> On Thu, Sep 26, 2002 at 10:05:16PM +0200, Marek Michalkiewicz wrote:
> > below is a patch that moves parport_serial.c from drivers/parport/
> > to drivers/char/ - this fixes the wrong link order when the drivers
> > are compiled into the kernel.
>
> What was wrong with the original, much smaller patch that you sent me
> previously (below)?
>
> I'm happy to accept whichever patch is the better.
Other than it's a gross hack rather than a fix. However, for 2.4, I
think this is probably the best solution without creating a risk of
other init ordering problems. Ed, any comments?
In 2.5, its easier to solve; we just need to make sure serial is
initialised before parport. This is easy, since serial now has its
own drivers/serial subdirectory.
--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
> What was wrong with the original, much smaller patch that you sent me
> previously (below)?
It was a hack (more a proof of concept where the problem was), and
Pavel Janik had some trouble with it (it hung before detecting the PCI
serial ports, while changing the link order worked fine - not sure why,
could this be a kernel stack overflow resulting from calling rs_init()
from within parport code instead of directly from the top level?).
My most recent patch simply moves parport_serial.c to a different
directory - that's why the patch is so big, but it doesn't otherwise
change a single line in that moved file (I split NetMos support to
the next patch, after this one is accepted and possible NetMos bugs
are resolved - works fine here with parport in polling mode, IRQ
sharing with serial ports not tested).
After the parport_serial.c move, the init order would be:
- parport
- serial
- parport_serial (needs both of the above initialized first)
- other char/block/net drivers (some of them might need the parallel
ports, including the PCI ones: lp, paride, plip - so moving all of
parport after char/block/net would be wrong)
> I'm happy to accept whichever patch is the better.
I'd suggest the more recent (larger, but not really...) one.
Thanks,
Marek
> Tim would know better there since he removed it, but iirc it had something
> to do with the BARs used, hmm your card has the same PCI id and is serial
> neutered to an extent, what happens if you treat it as if it really does
> have both serial ports there? Does it still work without causing other
> problems so you can safely ignore it? FYI, Interrupt driven works great
> for me.
Hmm, not sure what you're talking about - I have both serial ports working
fine, sharing one IRQ. Not sure what the regions 3-5 are for though...
If you have a parport IRQ sharing patch to test, you can send it to me.
The card is just a bare NM9835 chip + two GD75232 chips (RS232 drivers),
no configuration EEPROM mounted, so all data is from the NM9835 defaults
and all such cards should work the same way...
00:09.0 Communication controller: Unknown device 9710:9835 (rev 01)
Subsystem: LSI Logic / Symbios Logic (formerly NCR): Unknown device 0012
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 9
Region 0: I/O ports at ac00 [size=8]
Region 1: I/O ports at b000 [size=8]
Region 2: I/O ports at b400 [size=8]
Region 3: I/O ports at b800 [size=8]
Region 4: I/O ports at bc00 [size=8]
Region 5: I/O ports at c000 [size=16]
parport0: PC-style at 0x378 [PCSPP,TRISTATE,EPP]
parport_pc: Via 686A parallel port: io=0x378
...
Serial driver version 5.05c (2001-07-08) with MANY_PORTS SHARE_IRQ SERIAL_PCI ISAPNP enabled
ttyS00 at 0x03f8 (irq = 4) is a 16550A
ttyS01 at 0x02f8 (irq = 3) is a 16550A
PCI parallel port detected: 9710:9835, I/O at 0xb400(0x0)
parport1: PC-style at 0xb400 [PCSPP,TRISTATE,EPP]
ttyS04 at port 0xac00 (irq = 9) is a 16550A
ttyS05 at port 0xb000 (irq = 9) is a 16550A
lp0: using parport0 (polling).
lp0: console ready
lp1: using parport1 (polling).
> link order shouldn't affect the decision seeing as it affects all
> parport_serial anyway. You might have to wait it out and see what Tim/Ed
> have to say but i do have patches for both lying about.
OK, I'll try to be patient ;)
Marek