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