Specialix IO8+/PCI support.

Rogier Wolff (R.E.Wolff@BitWizard.nl)
Tue, 3 Nov 1998 12:43:53 +0100 (MET)


Hi Linus,

Could you include the specialix IO8+/PCI patch into 2.1.xxx? It now has
had the official approval from Specialix. It adds support for the PCI
version of the specialix IO8+ card.

(If the below doesn't patch in OK due to mail-mangling, you can tell
me, and I'll gzip/uuencode it for you (but this way you can read it
immediately without unpacking) or you can get it yourself from
ftp://ftp.bitwizard.nl/specialix/specialix-2.1.124-1.10.patch
)

So far, you dropped this once without feedback. Resend timer set for
november fifth.

Thanks,

Roger Wolff.

--------------------------------------------------------------------

diff -ur linux-2.1.124.clean/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.1.124.clean/Documentation/Configure.help Sun Oct 4 19:21:45 1998
+++ linux/Documentation/Configure.help Sat Oct 31 13:20:30 1998
@@ -7158,10 +7158,10 @@

Specialix IO8+ card support
CONFIG_SPECIALIX
- This is a driver for the Specialix IO8+ multiport card which gives
- you many serial ports. You would need something like this to
- connect more than two modems to your Linux box, for instance in
- order to become a BBS.
+ This is a driver for the Specialix IO8+ multiport card (both the
+ ISA and the PCI version) which gives you many serial ports. You
+ would need something like this to connect more than two modems to
+ your Linux box, for instance in order to become a BBS.

If you have a card like that, say Y here and read the file
Documentation/specialix.txt. Also it's possible to say M here and
diff -ur linux-2.1.124.clean/Documentation/specialix.txt linux/Documentation/specialix.txt
--- linux-2.1.124.clean/Documentation/specialix.txt Tue Apr 28 23:22:04 1998
+++ linux/Documentation/specialix.txt Thu Oct 15 10:57:21 1998
@@ -17,7 +17,10 @@
written by Dmitry Gorodchanin. The specialix IO8+ card
programming information was obtained from the CL-CD1865 Data
Book, and Specialix document number 6200059: IO8+ Hardware
- Functional Specification.
+ Functional Specification, augmented by document number 6200088:
+ Merak Hardware Functional Specification. (IO8+/PCI is also
+ called Merak)
+

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -67,6 +70,9 @@
other computer runs just fine with the Specialix card at 0x100....
The card occupies 4 addresses, but actually only two are really used.

+The PCI version doesn't have any dip switches. The BIOS assigns
+an IO address.
+
The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260. If
that causes trouble for you, please report that. I'll remove
autoprobing then.
@@ -75,6 +81,9 @@
change any jumpers to change the IRQ. Just use a command line
argument (irq=xx) to the insmod program to set the interrupt.

+The BIOS assigns the IRQ on the PCI version. You have no say in what
+IRQ to use in that case.
+
If your specialix cards are not at the default locations, you can use
the kernel command line argument "specialix=io0,irq0,io1,irq1...".
Here "io0" is the io address for the first card, and "irq0" is the
@@ -99,6 +108,32 @@

in your /etc/lilo.conf file if you use lilo.

+The Specialix driver is slightly odd: It allows you to have the second
+or third card detected without having a first card. This has
+advantages and disadvantages. A slot that isn't filled by an ISA card,
+might be filled if a PCI card is detected. Thus if you have an ISA
+card at 0x250 and a PCI card, you would get:
+
+sx0: specialix IO8+ Board at 0x100 not found.
+sx1: specialix IO8+ Board at 0x180 not found.
+sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B.
+sx3: specialix IO8+ Board at 0x260 not found.
+sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+This would happen if you don't give any probe hints to the driver.
+If you would specify:
+
+ specialix=0x250,11
+
+you'd get the following messages:
+
+sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B.
+sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B.
+
+ISA probing is aborted after the IO address you gave is exhausted, and
+the PCI card is now detected as the second card. The ISA card is now
+also forced to IRQ11....
+

Baud rates
==========
@@ -118,20 +153,26 @@
If you near the "limit" you will first start to see a graceful
degradation in that the chip cannot keep the transmitter busy at all
times. However with a central clock this slow, you can also get it to
-miss incoming characters.
+miss incoming characters. The driver will print a warning message when
+you are outside the official specs. The messages usually show up in
+the file /var/log/messages .

The specialix card cannot reliably do 115k2. If you use it, you have
to do "extensive testing" (*) to verify if it actually works.

When "mgetty" communicates with my modem at 115k2 it reports:
got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a]
- ^^^^ ^^^^ ^^^^
+ ^^^^ ^^^^ ^^^^

The three characters that have the "^^^" under them have suffered a
bit error in the highest bit. In conclusion: I've tested it, and found
that it simply DOESN'T work for me. I also suspect that this is also
caused by the baud rate being just a little bit out of tune.

+I upgraded the crystal to 66Mhz on one of my Specialix cards. Works
+great! Contact me for details. (Voids warranty, requires a steady hand
+and more such restrictions....)
+

(*) Cirrus logic CD1864 databook, page 40.

@@ -248,7 +289,7 @@
Ports and devices
=================

-Port 0 is the one furthest from the ISA connector.
+Port 0 is the one furthest from the card-edge connector.

Devices:

@@ -265,10 +306,20 @@
done
echo ""

+If your system doesn't come with these devices preinstalled, bug your
+linux-vendor about this. They have had ample time to get this
+implemented by now.

You cannot have more than 4 boards in one computer. The card only
supports 4 different interrupts. If you really want this, contact me
about this and I'll give you a few tips (requires soldering iron)....
+
+If you have enough PCI slots, you can probably use more than 4 PCI
+versions of the card though....
+
+The PCI version of the card cannot adhere to the mechanical part of
+the PCI spec because the 8 serial connectors are simply too large. If
+it doesn't fit in your computer, bring back the card.


------------------------------------------------------------------------
diff -ur linux-2.1.124.clean/drivers/char/specialix.c linux/drivers/char/specialix.c
--- linux-2.1.124.clean/drivers/char/specialix.c Wed May 6 19:56:03 1998
+++ linux/drivers/char/specialix.c Tue Nov 3 11:54:03 1998
@@ -58,10 +58,15 @@
* Made many more debug printk's a compile time option.
* Revision 1.8: Jul 1 1997
* port to linux-2.1.43 kernel.
+ * Revision 1.9: Oct 9 1998
+ * Added stuff for the IO8+/PCI version. .
+ * Revision 1.10: Nov 3 1998
+ * Now also check for the subsystem ID: prevents detecting
+ * SX cards as if they are IO8+/PCI.
*
*/

-#define VERSION "1.8"
+#define VERSION "1.10"


/*
@@ -87,6 +92,7 @@
#include <linux/delay.h>
#include <linux/tqueue.h>
#include <linux/version.h>
+#include <linux/pci.h>


/* ************************************************************** */
@@ -173,7 +179,6 @@
#define SPECIALIX_TYPE_NORMAL 1
#define SPECIALIX_TYPE_CALLOUT 2

-static struct specialix_board * IRQ_to_board[16] = { NULL, } ;
static struct tty_driver specialix_driver, specialix_callout_driver;
static int specialix_refcount = 0;
static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT] = { NULL, };
@@ -331,17 +336,22 @@

extern inline void sx_request_io_range(struct specialix_board * bp)
{
- request_region(bp->base, SX_IO_SPACE, "specialix IO8+" );
+ request_region(bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE,
+ "specialix IO8+" );
}


extern inline void sx_release_io_range(struct specialix_board * bp)
{
- release_region(bp->base, SX_IO_SPACE);
+ release_region(bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
}


/* Must be called with enabled interrupts */
+/* Ugly. Very ugly. Don't use this for anything else than initialization
+ code */
extern inline void sx_long_delay(unsigned long delay)
{
unsigned long i;
@@ -357,6 +367,8 @@
int virq;
int i;

+ if (bp->flags & SX_BOARD_IS_PCI)
+ return 1;
switch (bp->irq) {
/* In the same order as in the docs... */
case 15: virq = 0;break;
@@ -484,9 +496,14 @@
printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
board_No(bp), val1, val2);
#endif
- if (val1 != 0xb2) {
- printk(KERN_INFO "sx%d: specialix IO8+ ID at 0x%03x not found.\n",
- board_No(bp), bp->base);
+ /* They managed to switch the bit order between the docs and
+ the IO8+ card. The new PCI card now conforms to old docs.
+ They changed the PCI docs to reflect the situation on the
+ old card. */
+ val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
+ if (val1 != val2) {
+ printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
+ board_No(bp), val2, bp->base, val1);
return 1;
}

@@ -868,7 +885,7 @@
unsigned long loop = 0;
int saved_reg;

- bp = IRQ_to_board[irq];
+ bp = dev_id;

if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
#ifdef SPECIALIX_DEBUG
@@ -924,6 +941,25 @@
* Routines for open & close processing.
*/

+void turn_ints_off (struct specialix_board *bp)
+{
+ if (bp->flags & SX_BOARD_IS_PCI) {
+ /* This was intended for enabeling the interrupt on the
+ * PCI card. However it seems that it's already enabled
+ * and as PCI interrupts can be shared, there is no real
+ * reason to have to turn it off. */
+ }
+ (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+}
+
+void turn_ints_on (struct specialix_board *bp)
+{
+ if (bp->flags & SX_BOARD_IS_PCI) {
+ /* play with the PCI chip. See comment above. */
+ }
+ (void) sx_in (bp, 0); /* Turn ON interrupts. */
+}
+

/* Called with disabled interrupts */
extern inline int sx_setup_board(struct specialix_board * bp)
@@ -933,14 +969,12 @@
if (bp->flags & SX_BOARD_ACTIVE)
return 0;

- error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", NULL);
+ error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);

if (error)
return error;

- IRQ_to_board[bp->irq] = bp;
- (void) sx_in (bp, 0); /* Turn ON interrupts. */
-
+ turn_ints_on (bp);
bp->flags |= SX_BOARD_ACTIVE;

MOD_INC_USE_COUNT;
@@ -956,11 +990,13 @@

bp->flags &= ~SX_BOARD_ACTIVE;

- free_irq(bp->irq, NULL);
- (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+#if SPECIALIX_DEBUG > 2
+ printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp));
+#endif
+ free_irq(bp->irq, bp);
+
+ turn_ints_off (bp);

- IRQ_to_board[bp->irq] = NULL;
-
MOD_DEC_USE_COUNT;
}

@@ -1045,12 +1081,14 @@
/* Page 48 of version 2.0 of the CL-CD1865 databook */
if (tmp >= 12) {
printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
- "Performance degradation is possible.\n",
+ "Performance degradation is possible.\n"
+ "Read specialix.txt for more info.\n",
port_No (port), tmp);
} else {
printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
"Warning: overstressing Cirrus chip. "
- "This might not work.\n",
+ "This might not work.\n"
+ "Read specialix.txt for more info.\n",
port_No (port), tmp);
}
}
@@ -2153,7 +2191,6 @@
return 1;
}
init_bh(SPECIALIX_BH, do_specialix_bh);
- memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
memset(&specialix_driver, 0, sizeof(specialix_driver));
specialix_driver.magic = TTY_DRIVER_MAGIC;
specialix_driver.name = "ttyW";
@@ -2265,7 +2302,7 @@
int i;
int found = 0;

- printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997.\n");
+ printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
#ifdef CONFIG_SPECIALIX_RTSCTS
printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
@@ -2280,6 +2317,42 @@
if (sx_board[i].base && !sx_probe(&sx_board[i]))
found++;

+#ifdef CONFIG_PCI
+ if (pci_present()) {
+ struct pci_dev *pdev = NULL;
+ unsigned int tint;
+ unsigned short tshort;
+
+ i=0;
+ while (i <= SX_NBOARD) {
+ if (sx_board[i].flags & SX_BOARD_PRESENT) {
+ i++;
+ continue;
+ }
+ pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ pdev);
+ if (!pdev) break;
+
+ /* Specialix has a whole bunch of cards with
+ 0x2000 as the device ID. They say its because
+ the standard requires it. Stupid standard. */
+ pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &tshort);
+ if (tshort != 0xb008) continue;
+
+ sx_board[i].irq = pdev->irq;
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);
+ /* Mask out the fact that it's IO-space */
+ sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK;
+
+ sx_board[i].flags |= SX_BOARD_IS_PCI;
+ if (!sx_probe(&sx_board[i]))
+ found ++;
+ }
+ }
+#endif
+
if (!found) {
sx_release_drivers();
printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
@@ -2296,7 +2369,8 @@

/*
* You can setup up to 4 boards.
- * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
+ * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
+ * You should specify the IRQs too in that case "irq=....,...".
*
* More than 4 boards in one computer is not possible, as the card can
* only use 4 different interrupts.
diff -ur linux-2.1.124.clean/drivers/char/specialix_io8.h linux/drivers/char/specialix_io8.h
--- linux-2.1.124.clean/drivers/char/specialix_io8.h Sun Oct 18 17:40:43 1998
+++ linux/drivers/char/specialix_io8.h Thu Oct 15 11:51:54 1998
@@ -43,9 +43,16 @@

#ifdef __KERNEL__

-#define SX_NBOARD 4
+/* You can have max 4 ISA cards in one PC, and I recommend not much
+more than a few PCI versions of the card. */
+
+#define SX_NBOARD 8
+
/* NOTE: Specialix decoder recognizes 4 addresses, but only two are used.... */
#define SX_IO_SPACE 4
+/* The PCI version decodes 8 addresses, but still only 2 are used. */
+#define SX_PCI_IO_SPACE 8
+
/* eight ports per board. */
#define SX_NPORT 8
#define SX_BOARD(line) ((line) / SX_NPORT)
@@ -93,6 +100,7 @@

#define SX_BOARD_PRESENT 0x00000001
#define SX_BOARD_ACTIVE 0x00000002
+#define SX_BOARD_IS_PCI 0x00000004


struct specialix_port {
diff -ur linux-2.1.124.clean/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- linux-2.1.124.clean/drivers/pci/oldproc.c Wed Sep 16 22:25:57 1998
+++ linux/drivers/pci/oldproc.c Tue Nov 3 11:46:43 1998
@@ -399,6 +399,7 @@
DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"),
DEVICE( NP, NP_PCI_FDDI, "NP-PCI"),
DEVICE( ATT, ATT_L56XMF, "L56xMF"),
+ DEVICE( SPECIALIX, SPECIALIX_SX_XIO_IO8, "SX/XIO/IO8+"),
DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"),
DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"),
DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"),
diff -ur linux-2.1.124.clean/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.1.124.clean/include/linux/pci.h Sun Oct 18 17:03:53 1998
+++ linux/include/linux/pci.h Tue Nov 3 11:45:11 1998
@@ -841,6 +841,7 @@
#define PCI_DEVICE_ID_ATT_L56XMF 0x0440

#define PCI_VENDOR_ID_SPECIALIX 0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000
#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000

-- 
| Most people would die sooner than think....  |    R.E.Wolff@BitWizard.nl 
| in fact, most do.  -- Bertrand Russsell      |     phone: +31-15-2137555 
We write Linux device drivers for any device you may have! fax: ..-2138217

- 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/