Skip to content

Commit ad7a370

Browse files
bigguinessgregkh
authored andcommitted
staging: comedi: aio_iiro_16: add command support for change of state detection
This board supports interrupts on change of state of the digital inputs. Add the necessary subdevice support and interrupt handler to allow async commands to detect the change of state. Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ffe1cb9 commit ad7a370

File tree

1 file changed

+111
-5
lines changed

1 file changed

+111
-5
lines changed

drivers/staging/comedi/drivers/aio_iiro_16.c

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,49 @@
2323
*
2424
* Configuration Options:
2525
* [0] - I/O port base address
26+
* [1] - IRQ (optional)
27+
*
28+
* The board supports interrupts on change of state of the digital inputs.
29+
* The sample data returned by the async command indicates which inputs
30+
* changed state:
31+
*
32+
* Bit 7 - IRQ Enable (1) / Disable (0)
33+
* Bit 1 - Input 8-15 Changed State (1 = Changed, 0 = No Change)
34+
* Bit 0 - Input 0-7 Changed State (1 = Changed, 0 = No Change)
2635
*/
2736

2837
#include <linux/module.h>
38+
#include <linux/interrupt.h>
39+
2940
#include "../comedidev.h"
3041

31-
#define AIO_IIRO_16_RELAY_0_7 0x00
32-
#define AIO_IIRO_16_INPUT_0_7 0x01
33-
#define AIO_IIRO_16_IRQ 0x02
34-
#define AIO_IIRO_16_RELAY_8_15 0x04
35-
#define AIO_IIRO_16_INPUT_8_15 0x05
42+
#include "comedi_fc.h"
43+
44+
#define AIO_IIRO_16_RELAY_0_7 0x00
45+
#define AIO_IIRO_16_INPUT_0_7 0x01
46+
#define AIO_IIRO_16_IRQ 0x02
47+
#define AIO_IIRO_16_RELAY_8_15 0x04
48+
#define AIO_IIRO_16_INPUT_8_15 0x05
49+
#define AIO_IIRO_16_STATUS 0x07
50+
#define AIO_IIRO_16_STATUS_IRQE BIT(7)
51+
#define AIO_IIRO_16_STATUS_INPUT_8_15 BIT(1)
52+
#define AIO_IIRO_16_STATUS_INPUT_0_7 BIT(0)
53+
54+
static irqreturn_t aio_iiro_16_cos(int irq, void *d)
55+
{
56+
struct comedi_device *dev = d;
57+
struct comedi_subdevice *s = dev->read_subdev;
58+
unsigned int status;
59+
60+
status = inb(dev->iobase + AIO_IIRO_16_STATUS);
61+
if (!(status & AIO_IIRO_16_STATUS_IRQE))
62+
return IRQ_NONE;
63+
64+
comedi_buf_write_samples(s, &status, 1);
65+
comedi_handle_events(dev, s);
66+
67+
return IRQ_HANDLED;
68+
}
3669

3770
static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
3871
{
@@ -42,6 +75,60 @@ static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
4275
outb(0, dev->iobase + AIO_IIRO_16_IRQ);
4376
}
4477

78+
static int aio_iiro_16_cos_cancel(struct comedi_device *dev,
79+
struct comedi_subdevice *s)
80+
{
81+
aio_iiro_enable_irq(dev, false);
82+
83+
return 0;
84+
}
85+
86+
static int aio_iiro_16_cos_cmd(struct comedi_device *dev,
87+
struct comedi_subdevice *s)
88+
{
89+
aio_iiro_enable_irq(dev, true);
90+
91+
return 0;
92+
}
93+
94+
static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev,
95+
struct comedi_subdevice *s,
96+
struct comedi_cmd *cmd)
97+
{
98+
int err = 0;
99+
100+
/* Step 1 : check if triggers are trivially valid */
101+
102+
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
103+
err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
104+
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
105+
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
106+
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
107+
108+
if (err)
109+
return 1;
110+
111+
/* Step 2a : make sure trigger sources are unique */
112+
/* Step 2b : and mutually compatible */
113+
114+
/* Step 3: check if arguments are trivially valid */
115+
116+
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
117+
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
118+
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
119+
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
120+
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
121+
122+
if (err)
123+
return 3;
124+
125+
/* Step 4: fix up any arguments */
126+
127+
/* Step 5: check channel list if it exists */
128+
129+
return 0;
130+
}
131+
45132
static int aio_iiro_16_do_insn_bits(struct comedi_device *dev,
46133
struct comedi_subdevice *s,
47134
struct comedi_insn *insn,
@@ -82,6 +169,17 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
82169

83170
aio_iiro_enable_irq(dev, false);
84171

172+
/*
173+
* Digital input change of state interrupts are optionally supported
174+
* using IRQ 2-7, 10-12, 14, or 15.
175+
*/
176+
if ((1 << it->options[1]) & 0xdcfc) {
177+
ret = request_irq(it->options[1], aio_iiro_16_cos, 0,
178+
dev->board_name, dev);
179+
if (ret == 0)
180+
dev->irq = it->options[1];
181+
}
182+
85183
ret = comedi_alloc_subdevices(dev, 2);
86184
if (ret)
87185
return ret;
@@ -107,6 +205,14 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
107205
s->maxdata = 1;
108206
s->range_table = &range_digital;
109207
s->insn_bits = aio_iiro_16_di_insn_bits;
208+
if (dev->irq) {
209+
dev->read_subdev = s;
210+
s->subdev_flags |= SDF_CMD_READ;
211+
s->len_chanlist = 1;
212+
s->do_cmdtest = aio_iiro_16_cos_cmdtest;
213+
s->do_cmd = aio_iiro_16_cos_cmd;
214+
s->cancel = aio_iiro_16_cos_cancel;
215+
}
110216

111217
return 0;
112218
}

0 commit comments

Comments
 (0)