aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/pcl730.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/pcl730.c')
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c332
1 files changed, 248 insertions, 84 deletions
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index 2879db75da3e..862e75fd68fd 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -3,135 +3,299 @@
* Driver for Advantech PCL-730 and clones
* José Luis Sánchez
*/
-/*
-Driver: pcl730
-Description: Advantech PCL-730 (& compatibles)
-Author: José Luis Sánchez (jsanchezv@teleline.es)
-Status: untested
-Devices: [Advantech] PCL-730 (pcl730), [ICP] ISO-730 (iso730),
- [Adlink] ACL-7130 (acl7130)
-Interrupts are not supported.
-The ACL-7130 card have an 8254 timer/counter not supported by this driver.
-*/
+/*
+ * Driver: pcl730
+ * Description: Advantech PCL-730 (& compatibles)
+ * Devices: (Advantech) PCL-730 [pcl730]
+ * (ICP) ISO-730 [iso730]
+ * (Adlink) ACL-7130 [acl7130]
+ * (Advantech) PCM-3730 [pcm3730]
+ * (Advantech) PCL-725 [pcl725]
+ * (ICP) P8R8-DIO [p16r16dio]
+ * (Adlink) ACL-7225b [acl7225b]
+ * (ICP) P16R16-DIO [p16r16dio]
+ * (Advantech) PCL-733 [pcl733]
+ * (Advantech) PCL-734 [pcl734]
+ * Author: José Luis Sánchez (jsanchezv@teleline.es)
+ * Status: untested
+ *
+ * Configuration options:
+ * [0] - I/O port base
+ *
+ * Interrupts are not supported.
+ * The ACL-7130 card has an 8254 timer/counter not supported by this driver.
+ */
#include "../comedidev.h"
#include <linux/ioport.h>
-#define PCL730_SIZE 4
-#define ACL7130_SIZE 8
-#define PCL730_IDIO_LO 0 /* Isolated Digital I/O low byte (ID0-ID7) */
-#define PCL730_IDIO_HI 1 /* Isolated Digital I/O high byte (ID8-ID15) */
-#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */
-#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */
+/*
+ * Register map
+ *
+ * The register map varies slightly depending on the board type but
+ * all registers are 8-bit.
+ *
+ * The boardinfo 'io_range' is used to allow comedi to request the
+ * proper range required by the board.
+ *
+ * The comedi_subdevice 'private' data is used to pass the register
+ * offset to the (*insn_bits) functions to read/write the correct
+ * registers.
+ *
+ * The basic register mapping looks like this:
+ *
+ * BASE+0 Isolated outputs 0-7 (write) / inputs 0-7 (read)
+ * BASE+1 Isolated outputs 8-15 (write) / inputs 8-15 (read)
+ * BASE+2 TTL outputs 0-7 (write) / inputs 0-7 (read)
+ * BASE+3 TTL outputs 8-15 (write) / inputs 8-15 (read)
+ *
+ * The pcm3730 board does not have register BASE+1.
+ *
+ * The pcl725 and p8r8dio only have registers BASE+0 and BASE+1:
+ *
+ * BASE+0 Isolated outputs 0-7 (write) (read back on p8r8dio)
+ * BASE+1 Isolated inputs 0-7 (read)
+ *
+ * The acl7225b and p16r16dio boards have this register mapping:
+ *
+ * BASE+0 Isolated outputs 0-7 (write) (read back)
+ * BASE+1 Isolated outputs 8-15 (write) (read back)
+ * BASE+2 Isolated inputs 0-7 (read)
+ * BASE+3 Isolated inputs 8-15 (read)
+ *
+ * The pcl733 and pcl733 boards have this register mapping:
+ *
+ * BASE+0 Isolated outputs 0-7 (write) or inputs 0-7 (read)
+ * BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read)
+ * BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read)
+ * BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read)
+ */
struct pcl730_board {
+ const char *name;
+ unsigned int io_range;
+ unsigned is_pcl725:1;
+ unsigned is_acl7225b:1;
+ unsigned has_readback:1;
+ unsigned has_ttl_io:1;
+ int n_subdevs;
+ int n_iso_out_chan;
+ int n_iso_in_chan;
+ int n_ttl_chan;
+};
- const char *name; /* board name */
- unsigned int io_range; /* len of I/O space */
+static const struct pcl730_board pcl730_boards[] = {
+ {
+ .name = "pcl730",
+ .io_range = 0x04,
+ .has_ttl_io = 1,
+ .n_subdevs = 4,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ .n_ttl_chan = 16,
+ }, {
+ .name = "iso730",
+ .io_range = 0x04,
+ .n_subdevs = 4,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ .n_ttl_chan = 16,
+ }, {
+ .name = "acl7130",
+ .io_range = 0x08,
+ .has_ttl_io = 1,
+ .n_subdevs = 4,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ .n_ttl_chan = 16,
+ }, {
+ .name = "pcm3730",
+ .io_range = 0x04,
+ .has_ttl_io = 1,
+ .n_subdevs = 4,
+ .n_iso_out_chan = 8,
+ .n_iso_in_chan = 8,
+ .n_ttl_chan = 16,
+ }, {
+ .name = "pcl725",
+ .io_range = 0x02,
+ .is_pcl725 = 1,
+ .n_subdevs = 2,
+ .n_iso_out_chan = 8,
+ .n_iso_in_chan = 8,
+ }, {
+ .name = "p8r8dio",
+ .io_range = 0x02,
+ .is_pcl725 = 1,
+ .has_readback = 1,
+ .n_subdevs = 2,
+ .n_iso_out_chan = 8,
+ .n_iso_in_chan = 8,
+ }, {
+ .name = "acl7225b",
+ .io_range = 0x08, /* only 4 are used */
+ .is_acl7225b = 1,
+ .has_readback = 1,
+ .n_subdevs = 2,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ }, {
+ .name = "p16r16dio",
+ .io_range = 0x04,
+ .is_acl7225b = 1,
+ .has_readback = 1,
+ .n_subdevs = 2,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ }, {
+ .name = "pcl733",
+ .io_range = 0x04,
+ .n_subdevs = 1,
+ .n_iso_in_chan = 32,
+ }, {
+ .name = "pcl734",
+ .io_range = 0x04,
+ .n_subdevs = 1,
+ .n_iso_out_chan = 32,
+ },
};
-static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int pcl730_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
+ unsigned long reg = (unsigned long)s->private;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
+
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
+
+ if (mask & 0x00ff)
+ outb(s->state & 0xff, dev->iobase + reg);
+ if ((mask & 0xff00) && (s->n_chan > 8))
+ outb((s->state >> 8) & 0xff, dev->iobase + reg + 1);
+ if ((mask & 0xff0000) && (s->n_chan > 16))
+ outb((s->state >> 16) & 0xff, dev->iobase + reg + 2);
+ if ((mask & 0xff000000) && (s->n_chan > 24))
+ outb((s->state >> 24) & 0xff, dev->iobase + reg + 3);
}
- if (data[0] & 0x00ff)
- outb(s->state & 0xff,
- dev->iobase + ((unsigned long)s->private));
- if (data[0] & 0xff00)
- outb((s->state >> 8),
- dev->iobase + ((unsigned long)s->private) + 1);
data[1] = s->state;
return insn->n;
}
-static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static unsigned int pcl730_get_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- data[1] = inb(dev->iobase + ((unsigned long)s->private)) |
- (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8);
+ unsigned long reg = (unsigned long)s->private;
+ unsigned int val;
+
+ val = inb(dev->iobase + reg);
+ if (s->n_chan > 8)
+ val |= (inb(dev->iobase + reg + 1) << 8);
+ if (s->n_chan > 16)
+ val |= (inb(dev->iobase + reg + 2) << 16);
+ if (s->n_chan > 24)
+ val |= (inb(dev->iobase + reg + 3) << 24);
+
+ return val;
+}
+
+static int pcl730_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = pcl730_get_bits(dev, s);
return insn->n;
}
-static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int pcl730_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
const struct pcl730_board *board = comedi_board(dev);
struct comedi_subdevice *s;
+ int subdev;
int ret;
ret = comedi_request_region(dev, it->options[0], board->io_range);
if (ret)
return ret;
- ret = comedi_alloc_subdevices(dev, 4);
+ ret = comedi_alloc_subdevices(dev, board->n_subdevs);
if (ret)
return ret;
- s = &dev->subdevices[0];
- /* Isolated do */
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = pcl730_do_insn;
- s->range_table = &range_digital;
- s->private = (void *)PCL730_IDIO_LO;
-
- s = &dev->subdevices[1];
- /* Isolated di */
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = pcl730_di_insn;
- s->range_table = &range_digital;
- s->private = (void *)PCL730_IDIO_LO;
-
- s = &dev->subdevices[2];
- /* TTL do */
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = pcl730_do_insn;
- s->range_table = &range_digital;
- s->private = (void *)PCL730_DIO_LO;
-
- s = &dev->subdevices[3];
- /* TTL di */
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = pcl730_di_insn;
- s->range_table = &range_digital;
- s->private = (void *)PCL730_DIO_LO;
-
- printk(KERN_INFO "\n");
+ subdev = 0;
+
+ if (board->n_iso_out_chan) {
+ /* Isolated Digital Outputs */
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = board->n_iso_out_chan;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl730_do_insn_bits;
+ s->private = (void *)0;
+
+ /* get the initial state if supported */
+ if (board->has_readback)
+ s->state = pcl730_get_bits(dev, s);
+ }
+
+ if (board->n_iso_in_chan) {
+ /* Isolated Digital Inputs */
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = board->n_iso_in_chan;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl730_di_insn_bits;
+ s->private = board->is_acl7225b ? (void *)2 :
+ board->is_pcl725 ? (void *)1 : (void *)0;
+ }
+
+ if (board->has_ttl_io) {
+ /* TTL Digital Outputs */
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = board->n_ttl_chan;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl730_do_insn_bits;
+ s->private = (void *)2;
+
+ /* TTL Digital Inputs */
+ s = &dev->subdevices[subdev++];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = board->n_ttl_chan;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl730_di_insn_bits;
+ s->private = (void *)2;
+ }
return 0;
}
-static const struct pcl730_board boardtypes[] = {
- { "pcl730", PCL730_SIZE, },
- { "iso730", PCL730_SIZE, },
- { "acl7130", ACL7130_SIZE, },
-};
-
static struct comedi_driver pcl730_driver = {
.driver_name = "pcl730",
.module = THIS_MODULE,
.attach = pcl730_attach,
.detach = comedi_legacy_detach,
- .board_name = &boardtypes[0].name,
- .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &pcl730_boards[0].name,
+ .num_names = ARRAY_SIZE(pcl730_boards),
.offset = sizeof(struct pcl730_board),
};
module_comedi_driver(pcl730_driver);