Hi
Attached is my port of decision's serial patch to 2.2.16 as promised. I
have removed some bits out of the original patch (available from
decision.com.tw iirc, against some oldish 2.2.x kernel) that I didn't
think were important. What I know about the serial driver borders on
dangerous so YMMV. I've only tested it on the PCCOM8 card but it "works
for me".
No warranties/support/guarantees. I don't plan on using this anymore
as the 4 line patch to the 5.01 serial driver is much nicer IMHO ...
Cheers,
--Craig
diff -urN linux-2.2.16.vanilla/drivers/char/Config.in
linux-2.2.16.decision/drivers/char/Config.in
--- linux-2.2.16.vanilla/drivers/char/Config.in Wed Jul 26 14:12:18 2000
+++ linux-2.2.16.decision/drivers/char/Config.in Wed Jul 26 14:17:38 2000
@@ -19,6 +19,7 @@
bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT
bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6
+ bool ' Support the Decision PCCOM PCI card' CONFIG_DCIPCCOM_PCI
fi
bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
diff -urN linux-2.2.16.vanilla/drivers/char/serial.c
linux-2.2.16.decision/drivers/char/serial.c
--- linux-2.2.16.vanilla/drivers/char/serial.c Wed Jul 26 14:12:18 2000
+++ linux-2.2.16.decision/drivers/char/serial.c Wed Jul 26 14:36:48 2000
@@ -40,6 +40,10 @@
/*
* Serial driver configuration section. Here are the various options:
*
+ * CONFIG_DCIPCCOM_PCI
+ * Enable support for the Decision PCCOM PCI 4/8-Port
+ * cards if CONFIG_PCI is defined
+ *
* CONFIG_HUB6
* Enables support for the venerable Bell Technologies
* HUB6 card.
@@ -63,6 +67,12 @@
*/
#include <linux/config.h>
+#ifndef CONFIG_PCI
+#ifdef CONFIG_DCIPCCOM_PCI
+#undef CONFIG_DCIPCCOM_PCI
+#endif /* CONFIG_DCIPCCOM_PCI */
+#endif /* CONFIG_PCI */
+
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
@@ -94,6 +104,15 @@
#endif
#endif
+#ifdef CONFIG_DCIPCCOM_PCI
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif /* CONFIG_DCIPCCOM_PCI */
+
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
@@ -143,6 +162,10 @@
#include <linux/console.h>
#endif
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif /* CONFIG_PCI */
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -179,6 +202,46 @@
static struct console sercons;
#endif
+#ifdef CONFIG_DCIPCCOM_PCI
+
+/*
+ * Programming Interface
+ */
+#define PCI_PI_SERIAL_XT 0x00
+#define PCI_PI_SERIAL_16450 0x01
+#define PCI_PI_SERIAL_16550 0x02
+#define PCI_PI_SERIAL_16650 0x03
+
+/*
+ * Vendor
+ */
+#define PCI_DECISION 0x6666
+
+/*
+ * Class-, SubClass-, and Vendor-specific
+ */
+#define PCI_DC_SIO_PORT 0x2F
+#define PCI_DC_SIO_2P 0x00
+#define PCI_DC_SIO_4P 0x01
+#define PCI_DC_SIO_8P 0x02
+#define PCI_DC_SIO_16P 0x03
+
+#define PCI_DC_SIO_TYPE 0x2E
+#define PCI_DC_SIO_RS232 0x00
+#define PCI_DC_SIO_RS422 0x01
+#define PCI_DC_SIO_RS485 0x02
+
+/*
+ * Hardware configuration
+ */
+#define PCCOM_PCI_VECT_2P(base) (base + 0x10)
+#define PCCOM_PCI_SWID_2P(base) (base + 0x10)
+#define PCCOM_PCI_VECT_4P(base) (base + 0x20)
+#define PCCOM_PCI_SWID_4P(base) (base + 0x20)
+#define PCCOM_PCI_VECT_8P(base) (base + 0x40)
+#define PCCOM_PCI_SWID_8P(base) (base + 0x80)
+#endif /* CONFIG_DCIPCCOM_PCI */
+
static unsigned detect_uart_irq (struct serial_state * state);
static void autoconfig(struct serial_state * info);
static void change_speed(struct async_struct *info, struct termios *old);
@@ -212,6 +275,16 @@
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_DCIPCCOM_PCI
+#define serial_dcpci_nr_cards 2
+#define serial_dcpci_minor1 44
+#define serial_dcpci_minor2 52
+
+static int serial_dcpci_minor[serial_dcpci_nr_cards] = {
+ serial_dcpci_minor1, serial_dcpci_minor2
+};
+#endif /* CONFIG_DCIPCCOM_PCI */
+
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
@@ -2825,6 +2898,10 @@
static _INLINE_ void show_serial_version(void)
{
printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_DCIPCCOM_PCI
+ printk(" DCI_PCCOM_PCI");
+#define SERIAL_OPT
+#endif /* CONFIG_DCIPCCOM_PCI */
#ifdef CONFIG_HUB6
printk(" HUB-6");
#define SERIAL_OPT
@@ -2853,6 +2930,178 @@
#undef SERIAL_OPT
}
+#ifdef CONFIG_DCIPCCOM_PCI
+
+/*
+ * dci_pci_detect() - Test PCI bus presence and Decision PCCOM PCI.
+ */
+static void
+dci_pci_detect(void)
+{
+#define DCIPCCOM_PCI_PI_MAX 4
+
+ static unsigned char dcipccom_pci_pi[DCIPCCOM_PCI_PI_MAX] = {
+ PCI_PI_SERIAL_XT, PCI_PI_SERIAL_16450,
+ PCI_PI_SERIAL_16550, PCI_PI_SERIAL_16650
+ };
+
+ struct pci_dev *pdev = NULL;
+ int reg, vect;
+ unsigned int class = PCI_CLASS_COMMUNICATION_SERIAL;
+ unsigned short vendor;
+ unsigned int base;
+ unsigned char pi, irq, nport, pcid;
+ unsigned int i, index, card;
+ int rc;
+ struct serial_state *info;
+
+ if (pci_present() == 0) /* PCI bus not present */
+ return;
+
+ for (index = card = 0; card < serial_dcpci_nr_cards; index++) {
+ /*
+ * find sio communication class
+ */
+ for (i = 0; i < DCIPCCOM_PCI_PI_MAX; i++) {
+ pi = dcipccom_pci_pi[i];
+ if ((pdev = pci_find_class((class << 8) | pi, pdev))
+ != NULL)
+ break;
+ }
+ if (i == DCIPCCOM_PCI_PI_MAX) break;
+
+ /*
+ * find decision card
+ */
+ if ((rc = pci_read_config_word(pdev, PCI_VENDOR_ID,
+ &vendor)) != PCIBIOS_SUCCESSFUL)
+ break;
+ if (vendor != PCI_DECISION) continue;
+
+ /*
+ * determine programming interface
+ */
+ if ((rc = pci_read_config_byte(pdev, PCI_CLASS_PROG,
+ &pi)) != PCIBIOS_SUCCESSFUL) break;
+ switch (pi) {
+ case PCI_PI_SERIAL_XT:
+ case PCI_PI_SERIAL_16450:
+ case PCI_PI_SERIAL_16550:
+ case PCI_PI_SERIAL_16650:
+ break;
+ default:
+ continue;
+ }
+
+ /*
+ * NPORT
+ */
+ if ((rc = pci_read_config_byte(pdev, PCI_DC_SIO_PORT,
+ &nport)) != PCIBIOS_SUCCESSFUL) break;
+ switch (nport) {
+ case PCI_DC_SIO_2P:
+ nport = 2;
+ break;
+ case PCI_DC_SIO_4P:
+ nport = 4;
+ break;
+ case PCI_DC_SIO_8P:
+ nport = 8;
+ break;
+ case PCI_DC_SIO_16P:
+ nport = 16;
+ break;
+ default:
+ nport = 0;
+ break;
+ }
+
+#if 0
+ printk("nport = %d\n", nport);
+#endif
+
+ /*
+ * IRQ
+ */
+ if ((rc = pci_read_config_byte(pdev,
+ PCI_INTERRUPT_LINE, &irq)) != PCIBIOS_SUCCESSFUL)
+ break;
+
+#if 0
+ printk("IRQ %d\n", irq);
+#endif
+
+ /*
+ * I/O Base addr
+ */
+ i = 0;
+ for (reg = PCI_BASE_ADDRESS_2; reg <= PCI_BASE_ADDRESS_5;
+ i++, reg += 4) {
+ if ((rc = pci_read_config_dword(pdev, reg,
+ &base)) != PCIBIOS_SUCCESSFUL) return;
+
+ if (!base) continue;
+
+#if 0
+ printk("I/O %d at 0x%x\n", i, base);
+#endif
+
+ if (base & PCI_BASE_ADDRESS_SPACE) {
+ base &= PCI_BASE_ADDRESS_IO_MASK;
+#if 0
+ printk("I/O %d at 0x%x\n", i, base);
+#endif
+ break;
+ }
+ }
+
+ switch (nport) {
+ case 2:
+ vect = PCCOM_PCI_VECT_2P(base);
+ pcid = inb(PCCOM_PCI_SWID_2P(base)) >> 4;
+ break;
+ case 4:
+ vect = PCCOM_PCI_VECT_4P(base);
+ pcid = inb(PCCOM_PCI_SWID_4P(base)) >> 4;
+ break;
+ case 8:
+ vect = PCCOM_PCI_VECT_8P(base);
+ pcid = inb(PCCOM_PCI_SWID_8P(base)) >> 4;
+ break;
+ default:
+ vect = 0;
+ pcid = 0;
+ break;
+ }
+
+#if 0
+ printk("dci_pci_detect(%d): (nport, base, irq) = (%d, %x, %d)\n",
+ card, (unsigned)nport, base, (unsigned)irq);
+#endif
+
+ info = rs_table + serial_dcpci_minor[card];
+ for (i = 0; i < nport; info++, i++) {
+ info->port = base + (i << 3);
+ info->irq = irq;
+#if 0
+ printk("%d --> [%d]\n", i, irq);
+#endif
+ }
+
+#if 0
+ cards[set].nport = nport;
+ cards[set].irq = irq;
+ cards[set].addr = base;
+ cards[set].vect = vect;
+ cards[set].pcid = pcid;
+#endif
+
+ card++;
+ }
+} /* dci_pci_detect() */
+
+#endif /* CONFIG_DCIPCCOM_PCI */
+
/*
* This routine detect the IRQ of a serial port by clearing OUT2 when
* no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
@@ -3179,6 +3428,13 @@
if (tty_register_driver(&callout_driver))
panic("Couldn't register callout driver\n");
+#ifdef CONFIG_DCIPCCOM_PCI
+ /*
+ * detect Decision PCCOM PCI cards
+ */
+ dci_pci_detect();
+#endif /* CONFIG_DCIPCCOM_PCI */
+
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
state->magic = SSTATE_MAGIC;
state->line = i;
diff -urN linux-2.2.16.vanilla/drivers/pci/oldproc.c
linux-2.2.16.decision/drivers/pci/oldproc.c
--- linux-2.2.16.vanilla/drivers/pci/oldproc.c Wed Jul 26 14:12:19 2000
+++ linux-2.2.16.decision/drivers/pci/oldproc.c Wed Jul 26 14:40:08 2000
@@ -517,6 +517,11 @@
DEVICE( S3, S3_SONICVIBES, "SonicVibes"),
DEVICE( DCI, DCI_PCCOM4, "PC COM PCI Bus 4 port serial
Adapter"),
DEVICE( GENROCO, GENROCO_HFP832, "TURBOstor HFP832"),
+#ifdef CONFIG_DCIPCCOM_PCI
+ DEVICE( DECISION, DECISION_PCCOM4,"Decision PCCOM PCI 4-Port"),
+ DEVICE( DECISION, DECISION_PCCOM8,"Decision PCCOM PCI 8-Port"),
+ DEVICE( DECISION, DECISION_PCCOM2,"Decision PCCOM PCI 2-Port"),
+#endif /* CONFIG_DCIPCCOM_PCI */
DEVICE( INTEL, INTEL_82375, "82375EB"),
DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"),
DEVICE( INTEL, INTEL_82378, "82378IB"),
@@ -856,7 +861,7 @@
case PCI_VENDOR_ID_AVANCE: return "Avance";
case PCI_VENDOR_ID_NETVIN: return "NetVin";
case PCI_VENDOR_ID_S3: return "S3 Inc.";
- case PCI_VENDOR_ID_DCI: return "Decision Computer Int.";
+ case PCI_VENDOR_ID_DECISION: return "Decision Computer Int.";
case PCI_VENDOR_ID_GENROCO: return "Genroco";
case PCI_VENDOR_ID_INTEL: return "Intel";
case PCI_VENDOR_ID_KTI: return "KTI";
diff -urN linux-2.2.16.vanilla/include/asm-i386/serial.h
linux-2.2.16.decision/include/asm-i386/serial.h
--- linux-2.2.16.vanilla/include/asm-i386/serial.h Tue May 11 19:35:45 1999
+++ linux-2.2.16.decision/include/asm-i386/serial.h Wed Jul 26 14:42:20 2000
@@ -108,6 +108,51 @@
#define HUB6_SERIAL_PORT_DFNS
#endif
+/*
+ * Decision PCCOM PCI 2/4/8-port cards support
+ *
+ * You can have up to two cards in the system.
+ */
+#if (defined(CONFIG_DCIPCCOM_PCI) && defined(CONFIG_SERIAL_MANY_PORTS))
+
+#ifndef CONFIG_HUB6
+#undef HUB6_SERIAL_PORT_DFNS
+#define HUB6_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
+ { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
+#endif /* CONFIG_HUB6 */
+
+#define DCIPCCOM_PCI_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS44 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS45 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS46 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS47 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS48 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS49 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS50 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS51 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS52 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS53 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS54 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS55 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS56 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS57 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS58 */ \
+ { 0, BASE_BAUD, 0x0, 0, STD_COM_FLAGS }, /* ttyS59 */
+#else
+#define DCIPCCOM_PCI_SERIAL_PORT_DFNS
+#endif
+
#ifdef CONFIG_MCA
#define MCA_SERIAL_PORT_DFNS \
{ 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS }, \
@@ -124,5 +169,6 @@
STD_SERIAL_PORT_DEFNS \
EXTRA_SERIAL_PORT_DEFNS \
HUB6_SERIAL_PORT_DFNS \
+ DCIPCCOM_PCI_SERIAL_PORT_DFNS \
MCA_SERIAL_PORT_DFNS
diff -urN linux-2.2.16.vanilla/include/linux/pci.h
linux-2.2.16.decision/include/linux/pci.h
--- linux-2.2.16.vanilla/include/linux/pci.h Wed Jul 26 14:12:28 2000
+++ linux-2.2.16.decision/include/linux/pci.h Wed Jul 26 14:43:26 2000
@@ -1214,6 +1214,11 @@
#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004
#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005
+#define PCI_VENDOR_ID_DECISION 0x6666
+#define PCI_DEVICE_ID_DECISION_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DECISION_PCCOM8 0x0002
+#define PCI_DEVICE_ID_DECISION_PCCOM2 0x0004
+
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded