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
  30static int acl7225b_do_insn(struct comedi_device *dev,
  31                            struct comedi_subdevice *s,
  32                            struct comedi_insn *insn, unsigned int *data)
  33{
  34        if (data[0]) {
  35                s->state &= ~data[0];
  36                s->state |= (data[0] & data[1]);
  37        }
  38        if (data[0] & 0x00ff)
  39                outb(s->state & 0xff, dev->iobase + (unsigned long)s->private);
  40        if (data[0] & 0xff00)
  41                outb((s->state >> 8),
  42                     dev->iobase + (unsigned long)s->private + 1);
  43
  44        data[1] = s->state;
  45
  46        return insn->n;
  47}
  48
  49static int acl7225b_di_insn(struct comedi_device *dev,
  50                            struct comedi_subdevice *s,
  51                            struct comedi_insn *insn, unsigned int *data)
  52{
  53        data[1] = inb(dev->iobase + (unsigned long)s->private) |
  54            (inb(dev->iobase + (unsigned long)s->private + 1) << 8);
  55
  56        return insn->n;
  57}
  58
  59static int acl7225b_attach(struct comedi_device *dev,
  60                           struct comedi_devconfig *it)
  61{
  62        const struct boardtype *board = comedi_board(dev);
  63        struct comedi_subdevice *s;
  64        int iobase, iorange;
  65        int ret;
  66
  67        iobase = it->options[0];
  68        iorange = board->io_range;
  69        printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor,
  70               board->name, iobase);
  71        if (!request_region(iobase, iorange, "acl7225b")) {
  72                printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n",
  73                        dev->minor);
  74                return -EIO;
  75        }
  76        dev->board_name = board->name;
  77        dev->iobase = iobase;
  78        dev->irq = 0;
  79
  80        ret = comedi_alloc_subdevices(dev, 3);
  81        if (ret)
  82                return ret;
  83
  84        s = dev->subdevices + 0;
  85        /* Relays outputs */
  86        s->type = COMEDI_SUBD_DO;
  87        s->subdev_flags = SDF_WRITABLE;
  88        s->maxdata = 1;
  89        s->n_chan = 16;
  90        s->insn_bits = acl7225b_do_insn;
  91        s->range_table = &range_digital;
  92        s->private = (void *)ACL7225_RIO_LO;
  93
  94        s = dev->subdevices + 1;
  95        /* Relays status */
  96        s->type = COMEDI_SUBD_DI;
  97        s->subdev_flags = SDF_READABLE;
  98        s->maxdata = 1;
  99        s->n_chan = 16;
 100        s->insn_bits = acl7225b_di_insn;
 101        s->range_table = &range_digital;
 102        s->private = (void *)ACL7225_RIO_LO;
 103
 104        s = dev->subdevices + 2;
 105        /* Isolated digital inputs */
 106        s->type = COMEDI_SUBD_DI;
 107        s->subdev_flags = SDF_READABLE;
 108        s->maxdata = 1;
 109        s->n_chan = 16;
 110        s->insn_bits = acl7225b_di_insn;
 111        s->range_table = &range_digital;
 112        s->private = (void *)ACL7225_DI_LO;
 113
 114        return 0;
 115}
 116
 117static void acl7225b_detach(struct comedi_device *dev)
 118{
 119        const struct boardtype *board = comedi_board(dev);
 120
 121        if (dev->iobase)
 122                release_region(dev->iobase, board->io_range);
 123}
 124
 125static const struct boardtype boardtypes[] = {
 126        { "acl7225b", ACL7225_SIZE, },
 127        { "p16r16dio", P16R16DIO_SIZE, },
 128};
 129
 130static struct comedi_driver acl7225b_driver = {
 131        .driver_name    = "acl7225b",
 132        .module         = THIS_MODULE,
 133        .attach         = acl7225b_attach,
 134        .detach         = acl7225b_detach,
 135        .board_name     = &boardtypes[0].name,
 136        .num_names      = ARRAY_SIZE(boardtypes),
 137        .offset         = sizeof(struct boardtype),
 138};
 139module_comedi_driver(acl7225b_driver);
 140
 141MODULE_AUTHOR("Comedi http://www.comedi.org");
 142MODULE_DESCRIPTION("Comedi low-level driver");
 143MODULE_LICENSE("GPL");
 144