1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include <linux/module.h>
41#include <linux/interrupt.h>
42
43#include "../comedidev.h"
44
45#define AIO_IIRO_16_RELAY_0_7 0x00
46#define AIO_IIRO_16_INPUT_0_7 0x01
47#define AIO_IIRO_16_IRQ 0x02
48#define AIO_IIRO_16_RELAY_8_15 0x04
49#define AIO_IIRO_16_INPUT_8_15 0x05
50#define AIO_IIRO_16_STATUS 0x07
51#define AIO_IIRO_16_STATUS_IRQE BIT(7)
52#define AIO_IIRO_16_STATUS_INPUT_8_15 BIT(1)
53#define AIO_IIRO_16_STATUS_INPUT_0_7 BIT(0)
54
55static unsigned int aio_iiro_16_read_inputs(struct comedi_device *dev)
56{
57 unsigned int val;
58
59 val = inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
60 val |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
61
62 return val;
63}
64
65static irqreturn_t aio_iiro_16_cos(int irq, void *d)
66{
67 struct comedi_device *dev = d;
68 struct comedi_subdevice *s = dev->read_subdev;
69 unsigned int status;
70 unsigned int val;
71
72 status = inb(dev->iobase + AIO_IIRO_16_STATUS);
73 if (!(status & AIO_IIRO_16_STATUS_IRQE))
74 return IRQ_NONE;
75
76 val = aio_iiro_16_read_inputs(dev);
77 val |= (status << 16);
78
79 comedi_buf_write_samples(s, &val, 1);
80 comedi_handle_events(dev, s);
81
82 return IRQ_HANDLED;
83}
84
85static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
86{
87 if (enable)
88 inb(dev->iobase + AIO_IIRO_16_IRQ);
89 else
90 outb(0, dev->iobase + AIO_IIRO_16_IRQ);
91}
92
93static int aio_iiro_16_cos_cancel(struct comedi_device *dev,
94 struct comedi_subdevice *s)
95{
96 aio_iiro_enable_irq(dev, false);
97
98 return 0;
99}
100
101static int aio_iiro_16_cos_cmd(struct comedi_device *dev,
102 struct comedi_subdevice *s)
103{
104 aio_iiro_enable_irq(dev, true);
105
106 return 0;
107}
108
109static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev,
110 struct comedi_subdevice *s,
111 struct comedi_cmd *cmd)
112{
113 int err = 0;
114
115
116
117 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
118 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
119 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
120 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
121 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
122
123 if (err)
124 return 1;
125
126
127
128
129
130
131 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
132 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
133 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
134 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
135 cmd->chanlist_len);
136 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
137
138 if (err)
139 return 3;
140
141
142
143
144
145 return 0;
146}
147
148static int aio_iiro_16_do_insn_bits(struct comedi_device *dev,
149 struct comedi_subdevice *s,
150 struct comedi_insn *insn,
151 unsigned int *data)
152{
153 if (comedi_dio_update_state(s, data)) {
154 outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
155 outb((s->state >> 8) & 0xff,
156 dev->iobase + AIO_IIRO_16_RELAY_8_15);
157 }
158
159 data[1] = s->state;
160
161 return insn->n;
162}
163
164static int aio_iiro_16_di_insn_bits(struct comedi_device *dev,
165 struct comedi_subdevice *s,
166 struct comedi_insn *insn,
167 unsigned int *data)
168{
169 data[1] = aio_iiro_16_read_inputs(dev);
170
171 return insn->n;
172}
173
174static int aio_iiro_16_attach(struct comedi_device *dev,
175 struct comedi_devconfig *it)
176{
177 struct comedi_subdevice *s;
178 int ret;
179
180 ret = comedi_request_region(dev, it->options[0], 0x8);
181 if (ret)
182 return ret;
183
184 aio_iiro_enable_irq(dev, false);
185
186
187
188
189
190 if ((1 << it->options[1]) & 0xdcfc) {
191 ret = request_irq(it->options[1], aio_iiro_16_cos, 0,
192 dev->board_name, dev);
193 if (ret == 0)
194 dev->irq = it->options[1];
195 }
196
197 ret = comedi_alloc_subdevices(dev, 2);
198 if (ret)
199 return ret;
200
201
202 s = &dev->subdevices[0];
203 s->type = COMEDI_SUBD_DO;
204 s->subdev_flags = SDF_WRITABLE;
205 s->n_chan = 16;
206 s->maxdata = 1;
207 s->range_table = &range_digital;
208 s->insn_bits = aio_iiro_16_do_insn_bits;
209
210
211 s->state = inb(dev->iobase + AIO_IIRO_16_RELAY_0_7) |
212 (inb(dev->iobase + AIO_IIRO_16_RELAY_8_15) << 8);
213
214
215 s = &dev->subdevices[1];
216 s->type = COMEDI_SUBD_DI;
217 s->subdev_flags = SDF_READABLE;
218 s->n_chan = 16;
219 s->maxdata = 1;
220 s->range_table = &range_digital;
221 s->insn_bits = aio_iiro_16_di_insn_bits;
222 if (dev->irq) {
223 dev->read_subdev = s;
224 s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL;
225 s->len_chanlist = 1;
226 s->do_cmdtest = aio_iiro_16_cos_cmdtest;
227 s->do_cmd = aio_iiro_16_cos_cmd;
228 s->cancel = aio_iiro_16_cos_cancel;
229 }
230
231 return 0;
232}
233
234static struct comedi_driver aio_iiro_16_driver = {
235 .driver_name = "aio_iiro_16",
236 .module = THIS_MODULE,
237 .attach = aio_iiro_16_attach,
238 .detach = comedi_legacy_detach,
239};
240module_comedi_driver(aio_iiro_16_driver);
241
242MODULE_AUTHOR("Comedi http://www.comedi.org");
243MODULE_DESCRIPTION("Comedi driver for Access I/O Products 104-IIRO-16 board");
244MODULE_LICENSE("GPL");
245