root/drivers/staging/comedi/drivers/aio_iiro_16.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. aio_iiro_16_read_inputs
  2. aio_iiro_16_cos
  3. aio_iiro_enable_irq
  4. aio_iiro_16_cos_cancel
  5. aio_iiro_16_cos_cmd
  6. aio_iiro_16_cos_cmdtest
  7. aio_iiro_16_do_insn_bits
  8. aio_iiro_16_di_insn_bits
  9. aio_iiro_16_attach

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * aio_iiro_16.c
   4  * Comedi driver for Access I/O Products 104-IIRO-16 board
   5  * Copyright (C) 2006 C&C Technologies, Inc.
   6  */
   7 
   8 /*
   9  * Driver: aio_iiro_16
  10  * Description: Access I/O Products PC/104 Isolated Input/Relay Output Board
  11  * Author: Zachary Ware <zach.ware@cctechnol.com>
  12  * Devices: [Access I/O] 104-IIRO-16 (aio_iiro_16)
  13  * Status: experimental
  14  *
  15  * Configuration Options:
  16  *   [0] - I/O port base address
  17  *   [1] - IRQ (optional)
  18  *
  19  * The board supports interrupts on change of state of the digital inputs.
  20  * The sample data returned by the async command indicates which inputs
  21  * changed state and the current state of the inputs:
  22  *
  23  *      Bit 23 - IRQ Enable (1) / Disable (0)
  24  *      Bit 17 - Input 8-15 Changed State (1 = Changed, 0 = No Change)
  25  *      Bit 16 - Input 0-7 Changed State (1 = Changed, 0 = No Change)
  26  *      Bit 15 - Digital input 15
  27  *      ...
  28  *      Bit 0  - Digital input 0
  29  */
  30 
  31 #include <linux/module.h>
  32 #include <linux/interrupt.h>
  33 
  34 #include "../comedidev.h"
  35 
  36 #define AIO_IIRO_16_RELAY_0_7           0x00
  37 #define AIO_IIRO_16_INPUT_0_7           0x01
  38 #define AIO_IIRO_16_IRQ                 0x02
  39 #define AIO_IIRO_16_RELAY_8_15          0x04
  40 #define AIO_IIRO_16_INPUT_8_15          0x05
  41 #define AIO_IIRO_16_STATUS              0x07
  42 #define AIO_IIRO_16_STATUS_IRQE         BIT(7)
  43 #define AIO_IIRO_16_STATUS_INPUT_8_15   BIT(1)
  44 #define AIO_IIRO_16_STATUS_INPUT_0_7    BIT(0)
  45 
  46 static unsigned int aio_iiro_16_read_inputs(struct comedi_device *dev)
  47 {
  48         unsigned int val;
  49 
  50         val = inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
  51         val |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
  52 
  53         return val;
  54 }
  55 
  56 static irqreturn_t aio_iiro_16_cos(int irq, void *d)
  57 {
  58         struct comedi_device *dev = d;
  59         struct comedi_subdevice *s = dev->read_subdev;
  60         unsigned int status;
  61         unsigned int val;
  62 
  63         status = inb(dev->iobase + AIO_IIRO_16_STATUS);
  64         if (!(status & AIO_IIRO_16_STATUS_IRQE))
  65                 return IRQ_NONE;
  66 
  67         val = aio_iiro_16_read_inputs(dev);
  68         val |= (status << 16);
  69 
  70         comedi_buf_write_samples(s, &val, 1);
  71         comedi_handle_events(dev, s);
  72 
  73         return IRQ_HANDLED;
  74 }
  75 
  76 static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
  77 {
  78         if (enable)
  79                 inb(dev->iobase + AIO_IIRO_16_IRQ);
  80         else
  81                 outb(0, dev->iobase + AIO_IIRO_16_IRQ);
  82 }
  83 
  84 static int aio_iiro_16_cos_cancel(struct comedi_device *dev,
  85                                   struct comedi_subdevice *s)
  86 {
  87         aio_iiro_enable_irq(dev, false);
  88 
  89         return 0;
  90 }
  91 
  92 static int aio_iiro_16_cos_cmd(struct comedi_device *dev,
  93                                struct comedi_subdevice *s)
  94 {
  95         aio_iiro_enable_irq(dev, true);
  96 
  97         return 0;
  98 }
  99 
 100 static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev,
 101                                    struct comedi_subdevice *s,
 102                                    struct comedi_cmd *cmd)
 103 {
 104         int err = 0;
 105 
 106         /* Step 1 : check if triggers are trivially valid */
 107 
 108         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
 109         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
 110         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
 111         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 112         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 113 
 114         if (err)
 115                 return 1;
 116 
 117         /* Step 2a : make sure trigger sources are unique */
 118         /* Step 2b : and mutually compatible */
 119 
 120         /* Step 3: check if arguments are trivially valid */
 121 
 122         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
 123         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 124         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
 125         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
 126                                            cmd->chanlist_len);
 127         err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
 128 
 129         if (err)
 130                 return 3;
 131 
 132         /* Step 4: fix up any arguments */
 133 
 134         /* Step 5: check channel list if it exists */
 135 
 136         return 0;
 137 }
 138 
 139 static int aio_iiro_16_do_insn_bits(struct comedi_device *dev,
 140                                     struct comedi_subdevice *s,
 141                                     struct comedi_insn *insn,
 142                                     unsigned int *data)
 143 {
 144         if (comedi_dio_update_state(s, data)) {
 145                 outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
 146                 outb((s->state >> 8) & 0xff,
 147                      dev->iobase + AIO_IIRO_16_RELAY_8_15);
 148         }
 149 
 150         data[1] = s->state;
 151 
 152         return insn->n;
 153 }
 154 
 155 static int aio_iiro_16_di_insn_bits(struct comedi_device *dev,
 156                                     struct comedi_subdevice *s,
 157                                     struct comedi_insn *insn,
 158                                     unsigned int *data)
 159 {
 160         data[1] = aio_iiro_16_read_inputs(dev);
 161 
 162         return insn->n;
 163 }
 164 
 165 static int aio_iiro_16_attach(struct comedi_device *dev,
 166                               struct comedi_devconfig *it)
 167 {
 168         struct comedi_subdevice *s;
 169         int ret;
 170 
 171         ret = comedi_request_region(dev, it->options[0], 0x8);
 172         if (ret)
 173                 return ret;
 174 
 175         aio_iiro_enable_irq(dev, false);
 176 
 177         /*
 178          * Digital input change of state interrupts are optionally supported
 179          * using IRQ 2-7, 10-12, 14, or 15.
 180          */
 181         if ((1 << it->options[1]) & 0xdcfc) {
 182                 ret = request_irq(it->options[1], aio_iiro_16_cos, 0,
 183                                   dev->board_name, dev);
 184                 if (ret == 0)
 185                         dev->irq = it->options[1];
 186         }
 187 
 188         ret = comedi_alloc_subdevices(dev, 2);
 189         if (ret)
 190                 return ret;
 191 
 192         /* Digital Output subdevice */
 193         s = &dev->subdevices[0];
 194         s->type         = COMEDI_SUBD_DO;
 195         s->subdev_flags = SDF_WRITABLE;
 196         s->n_chan       = 16;
 197         s->maxdata      = 1;
 198         s->range_table  = &range_digital;
 199         s->insn_bits    = aio_iiro_16_do_insn_bits;
 200 
 201         /* get the initial state of the relays */
 202         s->state = inb(dev->iobase + AIO_IIRO_16_RELAY_0_7) |
 203                    (inb(dev->iobase + AIO_IIRO_16_RELAY_8_15) << 8);
 204 
 205         /* Digital Input subdevice */
 206         s = &dev->subdevices[1];
 207         s->type         = COMEDI_SUBD_DI;
 208         s->subdev_flags = SDF_READABLE;
 209         s->n_chan       = 16;
 210         s->maxdata      = 1;
 211         s->range_table  = &range_digital;
 212         s->insn_bits    = aio_iiro_16_di_insn_bits;
 213         if (dev->irq) {
 214                 dev->read_subdev = s;
 215                 s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL;
 216                 s->len_chanlist = 1;
 217                 s->do_cmdtest   = aio_iiro_16_cos_cmdtest;
 218                 s->do_cmd       = aio_iiro_16_cos_cmd;
 219                 s->cancel       = aio_iiro_16_cos_cancel;
 220         }
 221 
 222         return 0;
 223 }
 224 
 225 static struct comedi_driver aio_iiro_16_driver = {
 226         .driver_name    = "aio_iiro_16",
 227         .module         = THIS_MODULE,
 228         .attach         = aio_iiro_16_attach,
 229         .detach         = comedi_legacy_detach,
 230 };
 231 module_comedi_driver(aio_iiro_16_driver);
 232 
 233 MODULE_AUTHOR("Comedi http://www.comedi.org");
 234 MODULE_DESCRIPTION("Comedi driver for Access I/O Products 104-IIRO-16 board");
 235 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */