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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67#include <linux/module.h>
68#include <linux/interrupt.h>
69
70#include "../comedidev.h"
71
72
73
74
75#define PARPORT_DATA_REG 0x00
76#define PARPORT_STATUS_REG 0x01
77#define PARPORT_CTRL_REG 0x02
78#define PARPORT_CTRL_IRQ_ENA BIT(4)
79#define PARPORT_CTRL_BIDIR_ENA BIT(5)
80
81static int parport_data_reg_insn_bits(struct comedi_device *dev,
82 struct comedi_subdevice *s,
83 struct comedi_insn *insn,
84 unsigned int *data)
85{
86 if (comedi_dio_update_state(s, data))
87 outb(s->state, dev->iobase + PARPORT_DATA_REG);
88
89 data[1] = inb(dev->iobase + PARPORT_DATA_REG);
90
91 return insn->n;
92}
93
94static int parport_data_reg_insn_config(struct comedi_device *dev,
95 struct comedi_subdevice *s,
96 struct comedi_insn *insn,
97 unsigned int *data)
98{
99 unsigned int ctrl;
100 int ret;
101
102 ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
103 if (ret)
104 return ret;
105
106 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
107 if (s->io_bits)
108 ctrl &= ~PARPORT_CTRL_BIDIR_ENA;
109 else
110 ctrl |= PARPORT_CTRL_BIDIR_ENA;
111 outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
112
113 return insn->n;
114}
115
116static int parport_status_reg_insn_bits(struct comedi_device *dev,
117 struct comedi_subdevice *s,
118 struct comedi_insn *insn,
119 unsigned int *data)
120{
121 data[1] = inb(dev->iobase + PARPORT_STATUS_REG) >> 3;
122
123 return insn->n;
124}
125
126static int parport_ctrl_reg_insn_bits(struct comedi_device *dev,
127 struct comedi_subdevice *s,
128 struct comedi_insn *insn,
129 unsigned int *data)
130{
131 unsigned int ctrl;
132
133 if (comedi_dio_update_state(s, data)) {
134 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
135 ctrl &= (PARPORT_CTRL_IRQ_ENA | PARPORT_CTRL_BIDIR_ENA);
136 ctrl |= s->state;
137 outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
138 }
139
140 data[1] = s->state;
141
142 return insn->n;
143}
144
145static int parport_intr_insn_bits(struct comedi_device *dev,
146 struct comedi_subdevice *s,
147 struct comedi_insn *insn,
148 unsigned int *data)
149{
150 data[1] = 0;
151 return insn->n;
152}
153
154static int parport_intr_cmdtest(struct comedi_device *dev,
155 struct comedi_subdevice *s,
156 struct comedi_cmd *cmd)
157{
158 int err = 0;
159
160
161
162 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
163 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
164 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
165 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
166 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
167
168 if (err)
169 return 1;
170
171
172
173
174
175
176 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
177 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
178 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
179 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
180 cmd->chanlist_len);
181 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
182
183 if (err)
184 return 3;
185
186
187
188
189
190 return 0;
191}
192
193static int parport_intr_cmd(struct comedi_device *dev,
194 struct comedi_subdevice *s)
195{
196 unsigned int ctrl;
197
198 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
199 ctrl |= PARPORT_CTRL_IRQ_ENA;
200 outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
201
202 return 0;
203}
204
205static int parport_intr_cancel(struct comedi_device *dev,
206 struct comedi_subdevice *s)
207{
208 unsigned int ctrl;
209
210 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
211 ctrl &= ~PARPORT_CTRL_IRQ_ENA;
212 outb(ctrl, dev->iobase + PARPORT_CTRL_REG);
213
214 return 0;
215}
216
217static irqreturn_t parport_interrupt(int irq, void *d)
218{
219 struct comedi_device *dev = d;
220 struct comedi_subdevice *s = dev->read_subdev;
221 unsigned int ctrl;
222
223 ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
224 if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
225 return IRQ_NONE;
226
227 comedi_buf_write_samples(s, &s->state, 1);
228 comedi_handle_events(dev, s);
229
230 return IRQ_HANDLED;
231}
232
233static int parport_attach(struct comedi_device *dev,
234 struct comedi_devconfig *it)
235{
236 struct comedi_subdevice *s;
237 int ret;
238
239 ret = comedi_request_region(dev, it->options[0], 0x03);
240 if (ret)
241 return ret;
242
243 if (it->options[1]) {
244 ret = request_irq(it->options[1], parport_interrupt, 0,
245 dev->board_name, dev);
246 if (ret == 0)
247 dev->irq = it->options[1];
248 }
249
250 ret = comedi_alloc_subdevices(dev, dev->irq ? 4 : 3);
251 if (ret)
252 return ret;
253
254
255 s = &dev->subdevices[0];
256 s->type = COMEDI_SUBD_DIO;
257 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
258 s->n_chan = 8;
259 s->maxdata = 1;
260 s->range_table = &range_digital;
261 s->insn_bits = parport_data_reg_insn_bits;
262 s->insn_config = parport_data_reg_insn_config;
263
264
265 s = &dev->subdevices[1];
266 s->type = COMEDI_SUBD_DI;
267 s->subdev_flags = SDF_READABLE;
268 s->n_chan = 5;
269 s->maxdata = 1;
270 s->range_table = &range_digital;
271 s->insn_bits = parport_status_reg_insn_bits;
272
273
274 s = &dev->subdevices[2];
275 s->type = COMEDI_SUBD_DO;
276 s->subdev_flags = SDF_WRITABLE;
277 s->n_chan = 4;
278 s->maxdata = 1;
279 s->range_table = &range_digital;
280 s->insn_bits = parport_ctrl_reg_insn_bits;
281
282 if (dev->irq) {
283
284 s = &dev->subdevices[3];
285 dev->read_subdev = s;
286 s->type = COMEDI_SUBD_DI;
287 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
288 s->n_chan = 1;
289 s->maxdata = 1;
290 s->range_table = &range_digital;
291 s->insn_bits = parport_intr_insn_bits;
292 s->len_chanlist = 1;
293 s->do_cmdtest = parport_intr_cmdtest;
294 s->do_cmd = parport_intr_cmd;
295 s->cancel = parport_intr_cancel;
296 }
297
298 outb(0, dev->iobase + PARPORT_DATA_REG);
299 outb(0, dev->iobase + PARPORT_CTRL_REG);
300
301 return 0;
302}
303
304static struct comedi_driver parport_driver = {
305 .driver_name = "comedi_parport",
306 .module = THIS_MODULE,
307 .attach = parport_attach,
308 .detach = comedi_legacy_detach,
309};
310module_comedi_driver(parport_driver);
311
312MODULE_AUTHOR("Comedi http://www.comedi.org");
313MODULE_DESCRIPTION("Comedi: Standard parallel port driver");
314MODULE_LICENSE("GPL");
315