[PATCH] Char: sx, lock boards struct
[linux-drm-fsl-dcu.git] / drivers / char / sx.c
index cc10af08cb059b7f587586518011613541bf028b..42427f4d2ebd170463665559b352101f265589a2 100644 (file)
@@ -32,7 +32,6 @@
  *      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/kdev_t.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) */
 
@@ -308,6 +298,7 @@ static int sx_init_drivers(void);
 
 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;
@@ -333,6 +324,8 @@ static int sx_slowpoll;
 
 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
@@ -347,13 +340,14 @@ static int si1_probe_addrs[]= { 0xd0000};
 #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);
@@ -1987,7 +1981,6 @@ static int sx_init_board (struct sx_board *board)
        }
 
        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? */
@@ -2045,20 +2038,20 @@ static int sx_init_board (struct sx_board *board)
 }
 
 
-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;
@@ -2122,13 +2115,11 @@ static int probe_sx (struct sx_board *board)
                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
@@ -2136,7 +2127,7 @@ static int probe_sx (struct sx_board *board)
    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;
 
@@ -2218,11 +2209,10 @@ static int probe_si (struct sx_board *board)
                return 0;
        sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
 
-       board->flags |= SX_BOARD_PRESENT;
-
        func_exit();
        return 1;
 }
+#endif
 
 static const struct tty_operations sx_ops = {
        .break_ctl = sx_break,
@@ -2263,6 +2253,8 @@ static int sx_init_drivers(void)
        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);
 
@@ -2276,18 +2268,6 @@ static int sx_init_drivers(void)
        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;
@@ -2300,7 +2280,7 @@ static int sx_init_portstructs (int nboards, int nports)
 
        /* 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;
 
@@ -2366,6 +2346,17 @@ static int sx_init_portstructs (int nboards, int nports)
        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();
@@ -2374,7 +2365,102 @@ static void __exit sx_release_drivers(void)
        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.*
@@ -2386,7 +2472,7 @@ static void __exit sx_release_drivers(void)
    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;
@@ -2405,21 +2491,107 @@ static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
        }
        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);
@@ -2434,66 +2606,7 @@ static int __init sx_init(void)
                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];
@@ -2504,6 +2617,7 @@ static int __init sx_init(void)
                board->irq = sx_irqmask?-1:0;
 
                if (probe_sx (board)) {
+                       board->flags |= SX_BOARD_PRESENT;
                        found++;
                } else {
                        iounmap(board->base);
@@ -2520,6 +2634,7 @@ static int __init sx_init(void)
                board->irq = sx_irqmask ?-1:0;
 
                if (probe_si (board)) {
+                       board->flags |= SX_BOARD_PRESENT;
                        found++;
                } else {
                        iounmap (board->base);
@@ -2535,48 +2650,30 @@ static int __init sx_init(void)
                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;
 }
 
 
@@ -2586,6 +2683,10 @@ static void __exit sx_exit (void)
        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) {