[PATCH] ISA Plug-n-Play support for 2.3.28

Andrey Panin (pazke@orbita.don.sitek.net)
Tue, 16 Nov 1999 09:52:53 +0300


Hi all !

This patch provides ISA Plug-n-Play support for the serial driver.
It was tested with 'Rockwell 56K ACF II Fax+Data+Voice Modem'
made by ELine Communications.
Other PNP vendor/device ID's are WANTED.

This patch also fixes compilation warning: SERIAL_SHARE_IRQ redefined
and harmless misplaced #endif in serialP.h

BTW does anyone own PNP multiport serial card ?

Andrey

--- /siig/serial.c Tue Nov 9 18:10:13 1999
+++ /linux/drivers/char/serial.c Sun Nov 14 14:20:01 1999
@@ -41,6 +41,9 @@
*
* 10/99: Added support for the SIIG PCI serial cards.
* Andrey Panin <pazke@mail.tp.ru>
+ *
+ * 11/99: ISA Plug-n-Play support added.
+ * Andrey Panin <pazke@mail.tp.ru>
*
* This module exports the following rs232 io functions:
*
@@ -91,8 +94,14 @@

#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072))
#define ENABLE_SERIAL_PCI
+#ifndef CONFIG_SERIAL_SHARE_IRQ
#define CONFIG_SERIAL_SHARE_IRQ
#endif
+#endif
+
+#ifdef CONFIG_ISAPNP
+#define ENABLE_SERIAL_PNP
+#endif

/* Set of debugging defines */

@@ -193,6 +202,10 @@
#include <linux/pci.h>
#endif

+#ifdef ENABLE_SERIAL_PNP
+#include <linux/isapnp.h>
+#endif
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -273,7 +286,7 @@

#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))

-#ifdef ENABLE_SERIAL_PCI
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
#define NR_PCI_BOARDS 8
static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
static int serial_pci_board_idx = 0;
@@ -3191,6 +3204,10 @@
#endif
#define SERIAL_OPT
#endif
+#ifdef ENABLE_SERIAL_PNP
+ printk(" ISAPNP");
+#define SERIAL_OPT
+#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
#else
@@ -4051,6 +4068,177 @@

#endif /* ENABLE_SERIAL_PCI */

+#ifdef ENABLE_SERIAL_PNP
+
+static struct pci_board pnp_devices[] = {
+ { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+ SPCI_FL_BASE0, 1, 115200 },
+ { 0, }
+};
+
+static struct pci_board compatible_devices[] = {
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0,
+ SPCI_FL_BASE0, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
+ SPCI_FL_BASE0, 1, 115200 },
+ { 0, }
+};
+
+
+static void printk_pnp_dev_id(unsigned short vendor, unsigned short device)
+{
+ printk("%c%c%c%x%x%x%x",
+ 'A' + ((vendor >> 2) & 0x3f) - 1,
+ 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+ 'A' + ((vendor >> 8) & 0x1f) - 1,
+ (device >> 4) & 0x0f,
+ device & 0x0f,
+ (device >> 12) & 0x0f,
+ (device >> 8) & 0x0f);
+}
+
+static void handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static inline void request_irqs(void)
+{
+ int i;
+ for (i = 0; i < NR_PORTS; i++
)
+
if (rs_table[i].type != PORT_UNKNOWN)
+ request_irq(rs_table[i].irq, handler,
+ SA_INTERRUPT, "serial", NULL);
+}
+
+static void free_irqs(void)
+{
+ int i;
+ for (i = 0; i < NR_PORTS; i++
)
+
if (rs_table[i].type != PORT_UNKNOWN)
+ free_irq(rs_table[i].irq, NULL);
+}
+
+/* Code in this function is mainly stolen from probe_serial_pci() */
+static void probe_serial_pnp(void)
+{
+ int k, line;
+ struct pci_dev *dev = NULL;
+ struct pci_board *board;
+ struct serial_struct fake_state;
+ int uart_offset, base_baud, base_idx, base_irq;
+ unsigned long port;
+
+#ifdef SERIAL_DEBUG_PNP
+ printk("Entered probe_serial_pnp()\n");
+#endif
+ if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+ printk("Leaving probe_serial_pnp() (no isapnp)\n");
+#endif
+ return;
+ }
+
+ for(dev = isapnp_devices; dev; dev = dev->next) {
+ for (board = pnp_devices; 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;
+ break;
+ }
+
+ if (board->vendor == 0) {
+ /* Device not found, trying compatible device ID's */
+ for (k = 0; k < DEVICE_COUNT_COMPATIBLE; k++) {
+ if (dev->vendor_compatible[k] == 0)
+ continue;
+
+ for (board = compatible_devices; board->vendor; board++) {
+ if (board->vendor != dev->vendor)
+ continue;
+ if (board->device != dev->device)
+ continue;
+#ifdef SERIAL_DEBUG_PNP
+ printk("SERIAL: PNP device '");
+ printk_pnp_dev_id(dev->vendor, dev->device);
+ printk("' unknown, using compatible device '");
+ printk_pnp_dev_id(board->vendor, board->device);
+ printk("'\n");
+#endif
+ break;
+ }
+ }
+ }
+
+ if (board->vendor == 0)
+ continue;
+
+ request_irqs();
+
+ if (dev->prepare(dev) < 0) {
+ printk("SERIAL: PNP device '");
+ printk_pnp_dev_id(board->vendor, board->device);
+ printk("' prepare failed\n");
+ free_irqs();
+ continue;
+ }
+
+ if (dev->activate(dev) < 0) {
+ printk("SERIAL: PNP device '");
+ printk_pnp_dev_id(board->vendor, board->device);
+ printk("' activate failed\n");
+ free_irqs();
+ continue;
+ }
+
+ free_irqs();
+
+ if (board->init_fn)
+ (board->init_fn)(dev, board, 1);
+
+ serial_pci_board[serial_pci_board_idx].board = board;
+ serial_pci_board[serial_pci_board_idx].dev = dev;
+ serial_pci_board_idx++;
+
+ base_idx = board->flags & SPCI_FL_BASE_MASK;
+ base_irq = PNP_IRQ_BASE(board->flags);
+ port = PCI_BASE_ADDRESS(dev, base_idx);
+
+ uart_offset = board->uart_offset;
+ if (!uart_offset)
+ uart_offset = 8;
+ base_baud = board->base_baud;
+ if (!base_baud)
+ base_baud = BASE_BAUD;
+
+ memset(&fake_state, 0, sizeof(fake_state));
+
+ for (k=0; k < board->num_ports; k++) {
+ if (board->flags & SPCI_FL_BASE_TABLE)
+ port = PCI_BASE_ADDRESS(dev, base_idx++);
+ fake_state.port = port;
+ port += uart_offset;
+ fake_state.irq = dev->irq_resource[base_irq].start;
+ if (board->flags & SPNP_FL_IRQ_TABLE)
+ base_irq++;
+ fake_state.flags = ASYNC_SKIP_TEST;
+ line = register_serial(&fake_state);
+ if (line < 0)
+ break;
+ rs_table[line].baud_base = base_baud;
+ }
+ }
+
+#ifdef SERIAL_DEBUG_PNP
+ printk("Leaving probe_serial_pnp() (probe finished)\n");
+#endif
+ return;
+}
+
+#endif /* ENABLE_SERIAL_PNP */
+
/*
* The serial driver boot-time initialization code!
*/
@@ -4194,6 +4382,9 @@
#ifdef ENABLE_SERIAL_PCI
probe_serial_pci();
#endif
+#ifdef ENABLE_SERIAL_PNP
+ probe_serial_pnp();
+#endif
return 0;
}

@@ -4314,12 +4505,17 @@
iounmap(rs_table[i].iomem_base);
#endif
}
-#ifdef ENABLE_SERIAL_PCI
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
for (i=0; i < serial_pci_board_idx; i++) {
struct pci_board_inst *brd = &serial_pci_board[i];

if (brd->board->init_fn)
(brd->board->init_fn)(brd->dev, brd->board, 0);
+
+#ifdef ENABLE_SERIAL_PNP
+ if (brd->dev->deactivate)
+ brd->dev->deactivate(brd->dev);
+#endif
}
#endif
if (tmp_buf) {
--- /usr/src/linux/include/linux/serialP.h Wed Nov 3 18:44:47 1999
+++ /linux/include/linux/serialP.h Sun Nov 14 16:25:45 1999
@@ -159,7 +159,6 @@
#ifndef PCI_ANY_ID
#define PCI_ANY_ID (~0)
#endif
-#endif

#define SPCI_FL_BASE_MASK 0x0007
#define SPCI_FL_BASE0 0x0000
@@ -170,4 +169,19 @@
#define SPCI_FL_IOMEM 0x0008 /* Use I/O mapped memory */
#define SPCI_FL_BASE_TABLE 0x0010 /* Use base address table for UART */

-#endif /* _LINUX_SERIAL_H */
+#endif
+
+#ifdef CONFIG_ISAPNP
+
+#define SPNP_FL_IRQ_TABLE 0x0020 /* Use irq table */
+#define SPNP_FL_IRQ_MASK (7 << 6)
+#define SPCI_FL_IRQBASE0 0x0000
+#define SPCI_FL_IRQBASE1 (0x0001 << 6)
+#define SPCI_FL_IRQBASE2 (0x0002 << 6)
+#define SPCI_FL_IRQBASE3 (0x0003 << 6)
+#define SPCI_FL_IRQBASE4 (0x0004 << 6)
+#define PNP_IRQ_BASE(x) ((x & SPNP_FL_IRQ_MASK) >> 6)
+
+#endif
+
+#endif /* _LINUX_SERIALP_H */
--- /usr/src/linux/drivers/pnp/isapnp.c Tue Sep 7 21:14:37 1999
+++ /linux/drivers/pnp/isapnp.c Sun Nov 14 16:38:28 1999
@@ -2070,6 +2070,8 @@

#endif /* CONFIG_PCI */

+EXPORT_SYMBOL(isapnp_cards);
+EXPORT_SYMBOL(isapnp_devices);
EXPORT_SYMBOL(isapnp_present);
EXPORT_SYMBOL(isapnp_cfg_begin);
EXPORT_SYMBOL(isapnp_cfg_end);
--- /usr/src/linux/include/linux/isapnp.h Fri Sep 10 05:13:45 1999
+++ /linux/include/linux/isapnp.h Sun Nov 14 16:37:58 1999
@@ -120,6 +120,9 @@
struct isapnp_resources *next; /* next resource */
};

+extern struct pci_bus *isapnp_cards; /* ISA PnP cards */
+extern struct pci_dev *isapnp_devices; /* ISA PnP devices */
+
#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) &&
defined(MODULE))

/* lowlevel configuration */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/