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