* USA.
*
* Revision history:
- * $Log: sx.c,v $
* Revision 1.33 2000/03/09 10:00:00 pvdl,wolff
* - Fixed module and port counting
* - Fixed signal handling
*
* */
-
-#define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
-#define RCS_REV "$Revision: 1.33 $"
-
+#define SX_VERSION 1.33
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
+#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
#endif
-#ifdef CONFIG_PCI
-static struct pci_device_id sx_pci_tbl[] = {
- { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
-#endif /* CONFIG_PCI */
-
/* Configurable options:
(Don't be too sure that it'll work if you toggle them) */
static struct tty_driver *sx_driver;
+static DEFINE_MUTEX(sx_boards_lock);
static struct sx_board boards[SX_NBOARDS];
static struct sx_port *sx_ports;
static int sx_initialized;
static int sx_maxints = 100;
+#ifdef CONFIG_ISA
+
/* These are the only open spaces in my computer. Yours may have more
or less.... -- REW
duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+#endif
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
Some architectures may need more. */
static int sx_irqmask = -1;
-module_param_array(sx_probe_addrs, int, NULL, 0);
-module_param_array(si_probe_addrs, int, NULL, 0);
module_param(sx_poll, int, 0);
module_param(sx_slowpoll, int, 0);
module_param(sx_maxints, int, 0);
*
*/
-static struct file_operations sx_fw_fops = {
+static const struct file_operations sx_fw_fops = {
.owner = THIS_MODULE,
.ioctl = sx_fw_ioctl,
};
* Small, elegant, clear.
*/
-static irqreturn_t sx_interrupt (int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sx_interrupt (int irq, void *ptr)
{
struct sx_board *board = ptr;
struct sx_port *port;
func_enter ();
- sx_interrupt (0, board, NULL);
+ sx_interrupt (0, board);
init_timer(&board->timer);
}
if (chans) {
- /* board->flags |= SX_BOARD_PRESENT; */
if(board->irq > 0) {
/* fixed irq, probably PCI */
if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
}
-static void printheader(void)
+static void __devinit printheader(void)
{
static int header_printed;
if (!header_printed) {
printk (KERN_INFO "Specialix SX driver "
"(C) 1998/1999 R.E.Wolff@BitWizard.nl \n");
- printk (KERN_INFO "sx: version %s\n", RCS_ID);
+ printk (KERN_INFO "sx: version " __stringify(SX_VERSION) "\n");
header_printed = 1;
}
}
-static int probe_sx (struct sx_board *board)
+static int __devinit probe_sx (struct sx_board *board)
{
struct vpd_prom vpdp;
char *p;
return 0;
sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
- board->flags |= SX_BOARD_PRESENT;
-
func_exit();
return 1;
}
-
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
/* Specialix probes for this card at 32k increments from 640k to 16M.
I consider machines with less than 16M unlikely nowadays, so I'm
card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
-static int probe_si (struct sx_board *board)
+static int __devinit probe_si (struct sx_board *board)
{
int i;
return 0;
sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
- board->flags |= SX_BOARD_PRESENT;
-
func_exit();
return 1;
}
+#endif
-static struct tty_operations sx_ops = {
+static const struct tty_operations sx_ops = {
.break_ctl = sx_break,
.open = sx_open,
.close = gs_close,
sx_driver->init_termios = tty_std_termios;
sx_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver->init_termios.c_ispeed = 9600;
+ sx_driver->init_termios.c_ospeed = 9600;
sx_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(sx_driver, &sx_ops);
return 0;
}
-
-static void * ckmalloc (int size)
-{
- void *p;
-
- p = kmalloc(size, GFP_KERNEL);
- if (p)
- memset(p, 0, size);
- return p;
-}
-
-
static int sx_init_portstructs (int nboards, int nports)
{
struct sx_board *board;
/* Many drivers statically allocate the maximum number of ports
There is no reason not to allocate them dynamically. Is there? -- REW */
- sx_ports = ckmalloc(nports * sizeof (struct sx_port));
+ sx_ports = kcalloc(nports, sizeof(struct sx_port), GFP_KERNEL);
if (!sx_ports)
return -ENOMEM;
return 0;
}
+static unsigned int sx_find_free_board(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < SX_NBOARDS; i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT))
+ break;
+
+ return i;
+}
+
static void __exit sx_release_drivers(void)
{
func_enter();
func_exit();
}
-#ifdef CONFIG_PCI
+static void __devexit sx_remove_card(struct sx_board *board)
+{
+ if (board->flags & SX_BOARD_INITIALIZED) {
+ /* The board should stop messing with us. (actually I mean the
+ interrupt) */
+ sx_reset(board);
+ if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+ free_irq(board->irq, board);
+
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer(&board->timer);
+ iounmap(board->base);
+
+ board->flags &= ~(SX_BOARD_INITIALIZED|SX_BOARD_PRESENT);
+ }
+}
+
+#ifdef CONFIG_EISA
+
+static int __devinit sx_eisa_probe(struct device *dev)
+{
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct sx_board *board;
+ unsigned long eisa_slot = edev->base_addr;
+ unsigned int i;
+ int retval = -EIO;
+
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
+
+ dev_info(dev, "XIO : Signature found in EISA slot %lu, "
+ "Product %d Rev %d (REPORT THIS TO LKLM)\n",
+ eisa_slot >> 12,
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 2),
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 3));
+
+ board->eisa_base = eisa_slot;
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SI_EISA_BOARD;
+
+ board->hw_base = ((inb(eisa_slot + 0xc01) << 8) +
+ inb(eisa_slot + 0xc00)) << 16;
+ board->base2 =
+ board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+
+ sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+ sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
+ board->irq = inb(eisa_slot + 0xc02) >> 4;
+ sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
+
+ if (!probe_si(board))
+ goto err_unmap;
+
+ dev_set_drvdata(dev, board);
+
+ return 0;
+err_unmap:
+ iounmap(board->base);
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+}
+
+static int __devexit sx_eisa_remove(struct device *dev)
+{
+ struct sx_board *board = dev_get_drvdata(dev);
+
+ sx_remove_card(board);
+
+ return 0;
+}
+
+static struct eisa_device_id sx_eisa_tbl[] = {
+ { "SLX" },
+ { "" }
+};
+MODULE_DEVICE_TABLE(eisa, sx_eisa_tbl);
+
+static struct eisa_driver sx_eisadriver = {
+ .id_table = sx_eisa_tbl,
+ .driver = {
+ .name = "sx",
+ .probe = sx_eisa_probe,
+ .remove = __devexit_p(sx_eisa_remove),
+ }
+};
+
+#endif
+
/********************************************************
* Setting bit 17 in the CNTRL register of the PLX 9050 *
* chip forces a retry on writes while a read is pending.*
EEprom. As the bit is read/write for the CPU, we can fix it here,
if we detect that it isn't set correctly. -- REW */
-static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
+static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
{
unsigned int hwbase;
void __iomem *rebase;
}
iounmap(rebase);
}
-#endif
+static int __devinit sx_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct sx_board *board;
+ unsigned int i;
+ int retval = -EIO;
+
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err_flag;
+
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= (pdev->subsystem_vendor == 0x200) ? SX_PCI_BOARD :
+ SX_CFPCI_BOARD;
+
+ /* CF boards use base address 3.... */
+ if (IS_CF_BOARD (board))
+ board->hw_base = pci_resource_start(pdev, 3);
+ else
+ board->hw_base = pci_resource_start(pdev, 2);
+ board->base2 =
+ board->base = ioremap(board->hw_base, WINDOW_LEN (board));
+ if (!board->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err_flag;
+ }
+
+ /* Most of the stuff on the CF board is offset by 0x18000 .... */
+ if (IS_CF_BOARD (board))
+ board->base += 0x18000;
+
+ board->irq = pdev->irq;
+
+ dev_info(&pdev->dev, "Got a specialix card: %p(%d) %x.\n", board->base,
+ board->irq, board->flags);
+
+ if (!probe_sx(board)) {
+ retval = -EIO;
+ goto err_unmap;
+ }
+
+ fix_sx_pci(pdev, board);
+
+ pci_set_drvdata(pdev, board);
+
+ return 0;
+err_unmap:
+ iounmap(board->base2);
+err_flag:
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+}
+
+static void __devexit sx_pci_remove(struct pci_dev *pdev)
+{
+ struct sx_board *board = pci_get_drvdata(pdev);
+
+ sx_remove_card(board);
+}
+
+/* Specialix has a whole bunch of cards with 0x2000 as the device ID. They say
+ its because the standard requires it. So check for SUBVENDOR_ID. */
+static struct pci_device_id sx_pci_tbl[] = {
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0200, .subdevice = PCI_ANY_ID },
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0300, .subdevice = PCI_ANY_ID },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
+
+static struct pci_driver sx_pcidriver = {
+ .name = "sx",
+ .id_table = sx_pci_tbl,
+ .probe = sx_pci_probe,
+ .remove = __devexit_p(sx_pci_remove)
+};
static int __init sx_init(void)
{
- int i;
- int found = 0;
- int eisa_slot;
+#ifdef CONFIG_EISA
+ int retval1;
+#endif
+#ifdef CONFIG_ISA
struct sx_board *board;
-
-#ifdef CONFIG_PCI
- struct pci_dev *pdev = NULL;
- unsigned int tint;
- unsigned short tshort;
+ unsigned int i;
#endif
+ unsigned int found = 0;
+ int retval;
func_enter();
sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug);
printk(KERN_ERR "SX: Unable to register firmware loader driver.\n");
return -EIO;
}
-
-#ifdef CONFIG_PCI
- while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
- PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
- pdev))) {
- if (pci_enable_device(pdev))
- continue;
-
- /* Specialix has a whole bunch of cards with
- 0x2000 as the device ID. They say its because
- the standard requires it. Stupid standard. */
- /* It seems that reading a word doesn't work reliably on 2.0.
- Also, reading a non-aligned dword doesn't work. So we read the
- whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
- ourselves */
- /* I don't know why the define doesn't work, constant 0x2c does --REW */
- pci_read_config_dword (pdev, 0x2c, &tint);
- tshort = (tint >> 16) & 0xffff;
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
- /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */
- if ((tshort != 0x0200) && (tshort != 0x0300)) {
- sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n",
- tshort);
- continue;
- }
- board = &boards[found];
-
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= (tshort == 0x200)?SX_PCI_BOARD:
- SX_CFPCI_BOARD;
-
- /* CF boards use base address 3.... */
- if (IS_CF_BOARD (board))
- board->hw_base = pci_resource_start (pdev, 3);
- else
- board->hw_base = pci_resource_start (pdev, 2);
- board->base2 =
- board->base = ioremap(board->hw_base, WINDOW_LEN (board));
- if (!board->base) {
- printk(KERN_ERR "ioremap failed\n");
- /* XXX handle error */
- }
-
- /* Most of the stuff on the CF board is offset by
- 0x18000 .... */
- if (IS_CF_BOARD (board)) board->base += 0x18000;
-
- board->irq = pdev->irq;
-
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%p(%d) %x.\n",
- tint, boards[found].base, board->irq, board->flags);
-
- if (probe_sx (board)) {
- found++;
- fix_sx_pci (pdev, board);
- } else
- iounmap(board->base2);
- }
-#endif
-
+#ifdef CONFIG_ISA
for (i=0;i<NR_SX_ADDRS;i++) {
board = &boards[found];
board->hw_base = sx_probe_addrs[i];
board->irq = sx_irqmask?-1:0;
if (probe_sx (board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
iounmap(board->base);
board->irq = sx_irqmask ?-1:0;
if (probe_si (board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
iounmap (board->base);
board->irq = sx_irqmask ?-1:0;
if (probe_si (board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
iounmap (board->base);
}
}
+#endif
+#ifdef CONFIG_EISA
+ retval1 = eisa_driver_register(&sx_eisadriver);
+#endif
+ retval = pci_register_driver(&sx_pcidriver);
- sx_dprintk(SX_DEBUG_PROBE, "Probing for EISA cards\n");
- for(eisa_slot=0x1000; eisa_slot<0x10000; eisa_slot+=0x1000)
- {
- if((inb(eisa_slot+0xc80)==0x4d) &&
- (inb(eisa_slot+0xc81)==0x98))
- {
- sx_dprintk(SX_DEBUG_PROBE, "%s : Signature found in EISA slot %d, Product %d Rev %d\n",
- "XIO", (eisa_slot>>12), inb(eisa_slot+0xc82), inb(eisa_slot+0xc83));
-
- board = &boards[found];
- board->eisa_base = eisa_slot;
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI_EISA_BOARD;
-
- board->hw_base = (((inb(0xc01+eisa_slot) << 8) + inb(0xc00+eisa_slot)) << 16);
- board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
-
- sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
- sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
- board->irq = inb(board->eisa_base+0xc02)>>4;
- sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
-
- probe_si(board);
-
- found++;
- }
- }
if (found) {
printk (KERN_INFO "sx: total of %d boards detected.\n", found);
- } else {
+ retval = 0;
+ } else if (retval) {
+#ifdef CONFIG_EISA
+ if (retval1)
+#endif
misc_deregister(&sx_fw_device);
}
func_exit();
- return found?0:-EIO;
+ return retval;
}
struct sx_board *board;
func_enter();
+#ifdef CONFIG_EISA
+ eisa_driver_unregister(&sx_eisadriver);
+#endif
+ pci_unregister_driver(&sx_pcidriver);
for (i = 0; i < SX_NBOARDS; i++) {
board = &boards[i];
if (board->flags & SX_BOARD_INITIALIZED) {
}
}
if (misc_deregister(&sx_fw_device) < 0) {
- printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n");
+ printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
}
sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
if (sx_initialized)