amplc_dio200: Eliminate 'has_clk_gat_sce' from 'dio200_subdev_8254'.
[comedi.git] / comedi / drivers / amplc_dio200.c
index f461fc509edc0cfbbf4f32c3f618c277ba42cb10..a17d4a4e3ac25cff7b2eba5f78fc9ef292bc4e47 100644 (file)
@@ -29,8 +29,9 @@ Driver: amplc_dio200
 Description: Amplicon 200 Series Digital I/O
 Author: Ian Abbott <abbotti@mev.co.uk>
 Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
-  PCI215 (pci215), PC218E (pc218e), PC272E (pc272e), PCI272 (pci272)
-Updated: Mon, 05 Nov 2007 14:04:04 +0000
+  PCI215 (pci215 or amplc_dio200), PC218E (pc218e), PC272E (pc272e),
+  PCI272 (pci272 or amplc_dio200)
+Updated: Wed, 22 Oct 2008 13:36:02 +0100
 Status: works
 
 Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
@@ -217,6 +218,7 @@ order they appear in the channel list.
 /* #define PCI_VENDOR_ID_AMPLICON 0x14dc */
 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
 #define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
+#define PCI_DEVICE_ID_INVALID 0xffff
 
 /* 200 series registers */
 #define DIO200_IO_SIZE         0x20
@@ -264,7 +266,8 @@ enum dio200_model {
        pc214e_model,
        pc215e_model, pci215_model,
        pc218e_model,
-       pc272e_model, pci272_model
+       pc272e_model, pci272_model,
+       anypci_model
 };
 
 enum dio200_layout {
@@ -277,6 +280,7 @@ enum dio200_layout {
 
 typedef struct dio200_board_struct {
        const char *name;
+       unsigned short devid;
        enum dio200_bustype bustype;
        enum dio200_model model;
        enum dio200_layout layout;
@@ -301,12 +305,15 @@ static const dio200_board dio200_boards[] = {
              model:    pc215e_model,
              layout:   pc215_layout,
                },
+#ifdef CONFIG_COMEDI_PCI
        {
              name:     "pci215",
+             devid:    PCI_DEVICE_ID_AMPLICON_PCI215,
              bustype:  pci_bustype,
              model:    pci215_model,
              layout:   pc215_layout,
                },
+#endif
        {
              name:     "pc218e",
              bustype:  isa_bustype,
@@ -319,12 +326,23 @@ static const dio200_board dio200_boards[] = {
              model:    pc272e_model,
              layout:   pc272_layout,
                },
+#ifdef CONFIG_COMEDI_PCI
        {
              name:     "pci272",
+             devid:    PCI_DEVICE_ID_AMPLICON_PCI272,
              bustype:  pci_bustype,
              model:    pci272_model,
              layout:   pc272_layout,
                },
+#endif
+#ifdef CONFIG_COMEDI_PCI
+       {
+             name:     DIO200_DRIVER_NAME,
+             devid:    PCI_DEVICE_ID_INVALID,
+             bustype:  pci_bustype,
+             model:    anypci_model,   /* wildcard */
+               },
+#endif
 };
 
 /*
@@ -398,15 +416,17 @@ static const dio200_layout dio200_layouts[] = {
  * PCI driver table.
  */
 
-static struct pci_device_id dio200_pci_table[] __devinitdata = {
+#ifdef CONFIG_COMEDI_PCI
+static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
        {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0, pci215_model},
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0, pci272_model},
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0}
 };
 
 MODULE_DEVICE_TABLE(pci, dio200_pci_table);
+#endif /* CONFIG_COMEDI_PCI */
 
 /*
  * Useful for shorthand access to the particular board structure
@@ -418,7 +438,9 @@ MODULE_DEVICE_TABLE(pci, dio200_pci_table);
    several hardware drivers keep similar information in this structure,
    feel free to suggest moving the variable to the comedi_device struct.  */
 typedef struct {
+#ifdef CONFIG_COMEDI_PCI
        struct pci_dev *pci_dev;        /* PCI device */
+#endif
        int intr_sd;
 } dio200_private;
 
@@ -429,9 +451,9 @@ typedef struct {
        unsigned long clk_sce_iobase;   /* CLK_SCE base address */
        unsigned long gat_sce_iobase;   /* GAT_SCE base address */
        int which;              /* Bit 5 of CLK_SCE or GAT_SCE */
-       int has_clk_gat_sce;
        unsigned clock_src[3];  /* Current clock sources */
        unsigned gate_src[3];   /* Current gate sources */
+       spinlock_t spinlock;
 } dio200_subdev_8254;
 
 typedef struct {
@@ -463,57 +485,56 @@ static comedi_driver driver_amplc_dio200 = {
       num_names:sizeof(dio200_boards) / sizeof(dio200_board),
 };
 
+#ifdef CONFIG_COMEDI_PCI
+COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
+#else
 COMEDI_INITCLEANUP(driver_amplc_dio200);
+#endif
 
 /*
  * This function looks for a PCI device matching the requested board name,
  * bus and slot.
  */
+#ifdef CONFIG_COMEDI_PCI
 static int
 dio200_find_pci(comedi_device * dev, int bus, int slot,
        struct pci_dev **pci_dev_p)
 {
        struct pci_dev *pci_dev = NULL;
-       struct pci_device_id *pci_id;
 
        *pci_dev_p = NULL;
 
-       /* Look for PCI table entry for this model. */
-       for (pci_id = dio200_pci_table; pci_id->vendor != 0; pci_id++) {
-               if (pci_id->driver_data == thisboard->model)
-                       break;
-       }
-       if (pci_id->vendor == 0) {
-               printk(KERN_ERR
-                       "comedi%d: %s: BUG! cannot determine board type!\n",
-                       dev->minor, DIO200_DRIVER_NAME);
-               return -EINVAL;
-       }
-
        /* Look for matching PCI device. */
-       for (pci_dev = pci_get_device(pci_id->vendor, pci_id->device, NULL);
+       for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
                pci_dev != NULL;
-               pci_dev = pci_get_device(pci_id->vendor,
-                       pci_id->device, pci_dev)) {
+               pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
+                       PCI_ANY_ID, pci_dev)) {
                /* If bus/slot specified, check them. */
                if (bus || slot) {
                        if (bus != pci_dev->bus->number
                                || slot != PCI_SLOT(pci_dev->devfn))
                                continue;
                }
-#if 0
-               if (pci_id->subvendor != PCI_ANY_ID) {
-                       if (pci_dev->subsystem_vendor != pci_id->subvendor)
+               if (thisboard->model == anypci_model) {
+                       /* Match any supported model. */
+                       int i;
+
+                       for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) {
+                               if (dio200_boards[i].bustype != pci_bustype)
+                                       continue;
+                               if (pci_dev->device == dio200_boards[i].devid) {
+                                       /* Change board_ptr to matched board. */
+                                       dev->board_ptr = &dio200_boards[i];
+                                       break;
+                               }
+                       }
+                       if (i == ARRAY_SIZE(dio200_boards))
                                continue;
-               }
-               if (pci_id->subdevice != PCI_ANY_ID) {
-                       if (pci_dev->subsystem_device != pci_id->subdevice)
+               } else {
+                       /* Match specific model name. */
+                       if (pci_dev->device != thisboard->devid)
                                continue;
                }
-#endif
-               if (((pci_dev->class ^ pci_id->class) & pci_id->class_mask) !=
-                       0)
-                       continue;
 
                /* Found a match. */
                *pci_dev_p = pci_dev;
@@ -530,6 +551,7 @@ dio200_find_pci(comedi_device * dev, int bus, int slot,
        }
        return -EIO;
 }
+#endif
 
 /*
  * This function checks and requests an I/O region, reporting an error
@@ -1016,8 +1038,14 @@ dio200_subdev_8254_read(comedi_device * dev, comedi_subdevice * s,
 {
        dio200_subdev_8254 *subpriv = s->private;
        int chan = CR_CHAN(insn->chanspec);
+       unsigned long flags;
+
+       if (insn->n == 0)
+               return 0;
 
+       comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
        data[0] = i8254_read(subpriv->iobase, 0, chan);
+       comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
 
        return 1;
 }
@@ -1031,8 +1059,14 @@ dio200_subdev_8254_write(comedi_device * dev, comedi_subdevice * s,
 {
        dio200_subdev_8254 *subpriv = s->private;
        int chan = CR_CHAN(insn->chanspec);
+       unsigned long flags;
 
+       if (insn->n == 0)
+               return 0;
+
+       comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
        i8254_write(subpriv->iobase, 0, chan, data[0]);
+       comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
 
        return 1;
 }
@@ -1041,12 +1075,13 @@ dio200_subdev_8254_write(comedi_device * dev, comedi_subdevice * s,
  * Set gate source for an '8254' counter subdevice channel.
  */
 static int
-dio200_set_gate_src(dio200_subdev_8254 * subpriv, unsigned int counter_number,
-       unsigned int gate_src)
+dio200_subdev_8254_set_gate_src(comedi_device * dev, comedi_subdevice *s,
+       unsigned int counter_number, unsigned int gate_src)
 {
+       dio200_subdev_8254 *subpriv = s->private;
        unsigned char byte;
 
-       if (!subpriv->has_clk_gat_sce)
+       if (!thislayout->has_clk_gat_sce)
                return -1;
        if (counter_number > 2)
                return -1;
@@ -1064,9 +1099,12 @@ dio200_set_gate_src(dio200_subdev_8254 * subpriv, unsigned int counter_number,
  * Get gate source for an '8254' counter subdevice channel.
  */
 static int
-dio200_get_gate_src(dio200_subdev_8254 * subpriv, unsigned int counter_number)
+dio200_subdev_8254_get_gate_src(comedi_device * dev, comedi_subdevice *s,
+       unsigned int counter_number)
 {
-       if (!subpriv->has_clk_gat_sce)
+       dio200_subdev_8254 *subpriv = s->private;
+
+       if (!thislayout->has_clk_gat_sce)
                return -1;
        if (counter_number > 2)
                return -1;
@@ -1078,12 +1116,13 @@ dio200_get_gate_src(dio200_subdev_8254 * subpriv, unsigned int counter_number)
  * Set clock source for an '8254' counter subdevice channel.
  */
 static int
-dio200_set_clock_src(dio200_subdev_8254 * subpriv, unsigned int counter_number,
-       unsigned int clock_src)
+dio200_subdev_8254_set_clock_src(comedi_device * dev, comedi_subdevice *s,
+       unsigned int counter_number, unsigned int clock_src)
 {
+       dio200_subdev_8254 *subpriv = s->private;
        unsigned char byte;
 
-       if (!subpriv->has_clk_gat_sce)
+       if (!thislayout->has_clk_gat_sce)
                return -1;
        if (counter_number > 2)
                return -1;
@@ -1101,12 +1140,13 @@ dio200_set_clock_src(dio200_subdev_8254 * subpriv, unsigned int counter_number,
  * Get clock source for an '8254' counter subdevice channel.
  */
 static int
-dio200_get_clock_src(dio200_subdev_8254 * subpriv, unsigned int counter_number,
-       lsampl_t * period_ns)
+dio200_subdev_8254_get_clock_src(comedi_device * dev, comedi_subdevice *s,
+       unsigned int counter_number, lsampl_t * period_ns)
 {
+       dio200_subdev_8254 *subpriv = s->private;
        unsigned clock_src;
 
-       if (!subpriv->has_clk_gat_sce)
+       if (!thislayout->has_clk_gat_sce)
                return -1;
        if (counter_number > 2)
                return -1;
@@ -1124,45 +1164,52 @@ dio200_subdev_8254_config(comedi_device * dev, comedi_subdevice * s,
        comedi_insn * insn, lsampl_t * data)
 {
        dio200_subdev_8254 *subpriv = s->private;
-       int ret;
+       int ret = 0;
        int chan = CR_CHAN(insn->chanspec);
+       unsigned long flags;
 
+       comedi_spin_lock_irqsave(&subpriv->spinlock, flags);
        switch (data[0]) {
        case INSN_CONFIG_SET_COUNTER_MODE:
                ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
                if (ret < 0)
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        case INSN_CONFIG_8254_READ_STATUS:
                data[1] = i8254_status(subpriv->iobase, 0, chan);
                break;
        case INSN_CONFIG_SET_GATE_SRC:
-               ret = dio200_set_gate_src(subpriv, chan, data[2]);
+               ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
                if (ret < 0)
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        case INSN_CONFIG_GET_GATE_SRC:
-               ret = dio200_get_gate_src(subpriv, chan);
-               if (ret < 0)
-                       return -EINVAL;
+               ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
+               if (ret < 0) {
+                       ret = -EINVAL;
+                       break;
+               }
                data[2] = ret;
                break;
        case INSN_CONFIG_SET_CLOCK_SRC:
-               ret = dio200_set_clock_src(subpriv, chan, data[1]);
+               ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
                if (ret < 0)
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        case INSN_CONFIG_GET_CLOCK_SRC:
-               ret = dio200_get_clock_src(subpriv, chan, &data[2]);
-               if (ret < 0)
-                       return -EINVAL;
+               ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
+               if (ret < 0) {
+                       ret = -EINVAL;
+                       break;
+               }
                data[1] = ret;
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
                break;
        }
-       return insn->n;
+       comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags);
+       return ret < 0 ? ret : insn->n;
 }
 
 /*
@@ -1173,7 +1220,7 @@ dio200_subdev_8254_config(comedi_device * dev, comedi_subdevice * s,
  */
 static int
 dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
-       unsigned long iobase, unsigned offset, int has_clk_gat_sce)
+       unsigned long iobase, unsigned offset)
 {
        dio200_subdev_8254 *subpriv;
        unsigned int chan;
@@ -1194,9 +1241,9 @@ dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
        s->insn_write = dio200_subdev_8254_write;
        s->insn_config = dio200_subdev_8254_config;
 
+       spin_lock_init(&subpriv->spinlock);
        subpriv->iobase = offset + iobase;
-       subpriv->has_clk_gat_sce = has_clk_gat_sce;
-       if (has_clk_gat_sce) {
+       if (thislayout->has_clk_gat_sce) {
                /* Derive CLK_SCE and GAT_SCE register offsets from
                 * 8254 offset. */
                subpriv->clk_sce_iobase =
@@ -1210,11 +1257,11 @@ dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
        for (chan = 0; chan < 3; chan++) {
                i8254_set_mode(subpriv->iobase, 0, chan,
                        I8254_MODE0 | I8254_BINARY);
-               if (subpriv->has_clk_gat_sce) {
+               if (thislayout->has_clk_gat_sce) {
                        /* Gate source 0 is VCC (logic 1). */
-                       dio200_set_gate_src(subpriv, chan, 0);
+                       dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
                        /* Clock source 0 is the dedicated clock input. */
-                       dio200_set_clock_src(subpriv, chan, 0);
+                       dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
                }
        }
 
@@ -1227,7 +1274,7 @@ dio200_subdev_8254_init(comedi_device * dev, comedi_subdevice * s,
 static void
 dio200_subdev_8254_cleanup(comedi_device * dev, comedi_subdevice * s)
 {
-       dio200_subdev_intr *subpriv = s->private;
+       dio200_subdev_8254 *subpriv = s->private;
 
        if (subpriv) {
                kfree(subpriv);
@@ -1243,10 +1290,12 @@ dio200_subdev_8254_cleanup(comedi_device * dev, comedi_subdevice * s)
 static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
 {
        comedi_subdevice *s;
-       struct pci_dev *pci_dev = NULL;
        unsigned long iobase = 0;
        unsigned int irq = 0;
+#ifdef CONFIG_COMEDI_PCI
+       struct pci_dev *pci_dev = NULL;
        int bus = 0, slot = 0;
+#endif
        const dio200_layout *layout;
        int share_irq = 0;
        int sdx;
@@ -1269,6 +1318,7 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
                irq = it->options[1];
                share_irq = 0;
                break;
+#ifdef CONFIG_COMEDI_PCI
        case pci_bustype:
                bus = it->options[0];
                slot = it->options[1];
@@ -1278,6 +1328,7 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
                        return ret;
                devpriv->pci_dev = pci_dev;
                break;
+#endif
        default:
                printk(KERN_ERR
                        "comedi%d: %s: BUG! cannot determine board type!\n",
@@ -1289,6 +1340,7 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
        devpriv->intr_sd = -1;
 
        /* Enable device and reserve I/O spaces. */
+#ifdef CONFIG_COMEDI_PCI
        if (pci_dev) {
                ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
                if (ret < 0) {
@@ -1299,7 +1351,9 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
                }
                iobase = pci_resource_start(pci_dev, 2);
                irq = pci_dev->irq;
-       } else {
+       } else
+#endif
+       {
                ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
                if (ret < 0) {
                        return ret;
@@ -1320,7 +1374,7 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
                case sd_8254:
                        /* counter subdevice (8254) */
                        ret = dio200_subdev_8254_init(dev, s, iobase,
-                               layout->sdinfo[n], layout->has_clk_gat_sce);
+                               layout->sdinfo[n]);
                        if (ret < 0) {
                                return ret;
                        }
@@ -1377,7 +1431,9 @@ static int dio200_attach(comedi_device * dev, comedi_devconfig * it)
        if (thisboard->bustype == isa_bustype) {
                printk("(base %#lx) ", iobase);
        } else {
+#ifdef CONFIG_COMEDI_PCI
                printk("(pci %s) ", pci_name(pci_dev));
+#endif
        }
        if (irq) {
                printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -1429,13 +1485,18 @@ static int dio200_detach(comedi_device * dev)
                }
        }
        if (devpriv) {
+#ifdef CONFIG_COMEDI_PCI
                if (devpriv->pci_dev) {
                        if (dev->iobase) {
                                comedi_pci_disable(devpriv->pci_dev);
                        }
                        pci_dev_put(devpriv->pci_dev);
-               } else if (dev->iobase) {
-                       release_region(dev->iobase, DIO200_IO_SIZE);
+               } else
+#endif
+               {
+                       if (dev->iobase) {
+                               release_region(dev->iobase, DIO200_IO_SIZE);
+                       }
                }
        }
        if (dev->board_name) {