patch-2.0.36 linux/drivers/char/specialix.c
Next file: linux/drivers/char/specialix_io8.h
Previous file: linux/drivers/char/random.c
Back to the patch index
Back to the overall index
- Lines: 258
- Date:
Sun Nov 15 10:32:55 1998
- Orig file:
v2.0.35/linux/drivers/char/specialix.c
- Orig date:
Mon Jul 13 13:46:28 1998
diff -u --recursive --new-file v2.0.35/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
@@ -56,10 +56,14 @@
* Changed the specialix=... format to include interrupt.
* Revision 1.7: May 27 1997
* Made many more debug printk's a compile time option.
+ * Revision 1.8: Port to 2.1 kernel. -- Not here.
+ *
+ * Revision 1.9: October 1 1998
+ * Support for the PCI version of the card.
*
*/
-#define VERSION "1.7"
+#define VERSION "1.9"
/*
@@ -84,7 +88,8 @@
#include <linux/delay.h>
#include <linux/tqueue.h>
#include <linux/version.h>
-
+#include <linux/pci.h>
+#include <linux/bios32.h>
/* ************************************************************** */
/* * This section can be removed when 2.0 becomes outdated.... * */
@@ -170,7 +175,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, };
@@ -322,23 +326,28 @@
extern inline int sx_check_io_range(struct specialix_board * bp)
{
- return check_region (bp->base, SX_IO_SPACE);
+ return check_region (bp->base,
+ bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
}
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. Don't use this for anything else than initialization code */
extern inline void sx_long_delay(unsigned long delay)
{
unsigned long i;
@@ -354,6 +363,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;
@@ -481,9 +492,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;
}
@@ -865,7 +881,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
@@ -921,6 +937,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)
@@ -930,14 +965,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;
@@ -953,11 +986,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;
}
@@ -1042,12 +1077,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);
}
}
@@ -2150,7 +2187,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";
@@ -2240,7 +2276,7 @@
void specialix_setup(char *str, int * ints)
{
int i;
-
+
for (i=0;i<SX_NBOARD;i++) {
sx_board[i].base = 0;
}
@@ -2261,8 +2297,12 @@
{
int i;
int found = 0;
+#ifdef CONFIG_PCI
+ int pci_index;
+ unsigned char pci_bus, pci_device_fn;
+#endif
- 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");
@@ -2277,6 +2317,36 @@
if (sx_board[i].base && !sx_probe(&sx_board[i]))
found++;
+#ifdef CONFIG_PCI
+ i=0;
+ pci_index = 0;
+ while ((i < SX_NBOARD) && (pci_index < 0xff)) {
+ unsigned char tbyte;
+ unsigned int tint;
+ if (sx_board[i].flags & SX_BOARD_PRESENT) {
+ i++;
+ continue;
+ }
+ if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_IO8,
+ pci_index, &pci_bus, &pci_device_fn)
+ != PCIBIOS_SUCCESSFUL)
+ break;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &tbyte);
+ sx_board[i].irq = tbyte;
+
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ 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 ++;
+ pci_index++;
+ }
+#endif
+
if (!found) {
sx_release_drivers();
printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");
@@ -2293,7 +2363,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.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov