linux/drivers/staging/comedi/drivers/acl7225b.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/acl7225b.c
   3 * Driver for Adlink NuDAQ ACL-7225b and clones
   4 * José Luis Sánchez
   5 */
   6/*
   7Driver: acl7225b
   8Description: Adlink NuDAQ ACL-7225b & compatibles
   9Author: José Luis Sánchez (jsanchezv@teleline.es)
  10Status: testing
  11Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
  12*/
  13
  14#include "../comedidev.h"
  15
  16#include <linux/ioport.h>
  17
  18#define ACL7225_SIZE   8        /* Requires 8 ioports, but only 4 are used */
  19#define P16R16DIO_SIZE 4
  20#define ACL7225_RIO_LO 0        /* Relays input/output low byte (R0-R7) */
  21#define ACL7225_RIO_HI 1        /* Relays input/output high byte (R8-R15) */
  22#define ACL7225_DI_LO  2        /* Digital input low byte (DI0-DI7) */
  23#define ACL7225_DI_HI  3        /* Digital input high byte (DI8-DI15) */
  24
  25struct boardtype {
  26        const char *name;       /*  driver name */
  27        int io_range;           /*  len of I/O space */
  28};
  29
  30#define this_board ((const struct boardtype *)dev->board_ptr)
  31
  32static int acl7225b_do_insn(struct comedi_device *dev,
  33                            struct comedi_subdevice *s,
  34                            struct comedi_insn *insn, unsigned int *data)
  35{
  36        if (insn->n != 2)
  37                return -EINVAL;
  38
  39        if (data[0]) {
  40                s->state &= ~data[0];
  41                s->state |= (data[0] & data[1]);
  42        }
  43        if (data[0] & 0x00ff)
  44                outb(s->state & 0xff, dev->iobase + (unsigned long)s->private);
  45        if (data[0] & 0xff00)
  46                outb((s->state >> 8),
  47                     dev->iobase + (unsigned long)s->private + 1);
  48
  49        data[1] = s->state;
  50
  51        return 2;
  52}
  53
  54static int acl7225b_di_insn(struct comedi_device *dev,
  55                            struct comedi_subdevice *s,
  56                            struct comedi_insn *insn, unsigned int *data)
  57{
  58        if (insn->n != 2)
  59                return -EINVAL;
  60
  61        data[1] = inb(dev->iobase + (unsigned long)s->private) |
  62            (inb(dev->iobase + (unsigned long)s->private + 1) << 8);
  63
  64        return 2;
  65}
  66
  67static int acl7225b_attach(struct comedi_device *dev,
  68                           struct comedi_devconfig *it)
  69{
  70        struct comedi_subdevice *s;
  71        int iobase, iorange;
  72
  73        iobase = it->options[0];
  74        iorange = this_board->io_range;
  75        printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor,
  76               this_board->name, iobase);
  77        if (!request_region(iobase, iorange, "acl7225b")) {
  78                printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n",
  79                        dev->minor);
  80                return -EIO;
  81        }
  82        dev->board_name = this_board->name;
  83        dev->iobase = iobase;
  84        dev->irq = 0;
  85
  86        if (alloc_subdevices(dev, 3) < 0)
  87                return -ENOMEM;
  88
  89        s = dev->subdevices + 0;
  90        /* Relays outputs */
  91        s->type = COMEDI_SUBD_DO;
  92        s->subdev_flags = SDF_WRITABLE;
  93        s->maxdata = 1;
  94        s->n_chan = 16;
  95        s->insn_bits = acl7225b_do_insn;
  96        s->range_table = &range_digital;
  97        s->private = (void *)ACL7225_RIO_LO;
  98
  99        s = dev->subdevices + 1;
 100        /* Relays status */
 101        s->type = COMEDI_SUBD_DI;
 102        s->subdev_flags = SDF_READABLE;
 103        s->maxdata = 1;
 104        s->n_chan = 16;
 105        s->insn_bits = acl7225b_di_insn;
 106        s->range_table = &range_digital;
 107        s->private = (void *)ACL7225_RIO_LO;
 108
 109        s = dev->subdevices + 2;
 110        /* Isolated digital inputs */
 111        s->type = COMEDI_SUBD_DI;
 112        s->subdev_flags = SDF_READABLE;
 113        s->maxdata = 1;
 114        s->n_chan = 16;
 115        s->insn_bits = acl7225b_di_insn;
 116        s->range_table = &range_digital;
 117        s->private = (void *)ACL7225_DI_LO;
 118
 119        return 0;
 120}
 121
 122static void acl7225b_detach(struct comedi_device *dev)
 123{
 124        if (dev->iobase)
 125                release_region(dev->iobase, this_board->io_range);
 126}
 127
 128static const struct boardtype boardtypes[] = {
 129        { "acl7225b", ACL7225_SIZE, },
 130        { "p16r16dio", P16R16DIO_SIZE, },
 131};
 132
 133static struct comedi_driver acl7225b_driver = {
 134        .driver_name    = "acl7225b",
 135        .module         = THIS_MODULE,
 136        .attach         = acl7225b_attach,
 137        .detach         = acl7225b_detach,
 138        .board_name     = &boardtypes[0].name,
 139        .num_names      = ARRAY_SIZE(boardtypes),
 140        .offset         = sizeof(struct boardtype),
 141};
 142module_comedi_driver(acl7225b_driver);
 143
 144MODULE_AUTHOR("Comedi http://www.comedi.org");
 145MODULE_DESCRIPTION("Comedi low-level driver");
 146MODULE_LICENSE("GPL");
 147