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#include <linux/module.h>
37
38#include "../comedidev.h"
39
40#include "8255.h"
41#include "8253.h"
42#include "das08.h"
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#define DAS08_LSB 0
61#define DAS08_MSB 1
62#define DAS08_TRIG_12BIT 1
63#define DAS08_STATUS 2
64#define DAS08_EOC (1<<7)
65#define DAS08_IRQ (1<<3)
66#define DAS08_IP(x) (((x)>>4)&0x7)
67#define DAS08_CONTROL 2
68#define DAS08_MUX_MASK 0x7
69#define DAS08_MUX(x) ((x) & DAS08_MUX_MASK)
70#define DAS08_INTE (1<<3)
71#define DAS08_DO_MASK 0xf0
72#define DAS08_OP(x) (((x) << 4) & DAS08_DO_MASK)
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90#define DAS08JR_DIO 3
91#define DAS08JR_AO_LSB(x) ((x) ? 6 : 4)
92#define DAS08JR_AO_MSB(x) ((x) ? 7 : 5)
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114#define DAS08AO_GAIN_CONTROL 3
115#define DAS08AO_GAIN_STATUS 3
116
117#define DAS08AO_AO_LSB(x) ((x) ? 0xa : 8)
118#define DAS08AO_AO_MSB(x) ((x) ? 0xb : 9)
119#define DAS08AO_AO_UPDATE 8
120
121
122
123static const struct comedi_lrange range_das08_pgl = { 9, {
124 BIP_RANGE(10),
125 BIP_RANGE(5),
126 BIP_RANGE(2.5),
127 BIP_RANGE(1.25),
128 BIP_RANGE(0.625),
129 UNI_RANGE(10),
130 UNI_RANGE(5),
131 UNI_RANGE(2.5),
132 UNI_RANGE(1.25)
133 }
134};
135
136static const struct comedi_lrange range_das08_pgh = { 12, {
137 BIP_RANGE(10),
138 BIP_RANGE(5),
139 BIP_RANGE(1),
140 BIP_RANGE(0.5),
141 BIP_RANGE(0.1),
142 BIP_RANGE(0.05),
143 BIP_RANGE(0.01),
144 BIP_RANGE(0.005),
145 UNI_RANGE(10),
146 UNI_RANGE(1),
147 UNI_RANGE(0.1),
148 UNI_RANGE(0.01),
149 }
150};
151
152static const struct comedi_lrange range_das08_pgm = { 9, {
153 BIP_RANGE(10),
154 BIP_RANGE(5),
155 BIP_RANGE(0.5),
156 BIP_RANGE(0.05),
157 BIP_RANGE(0.01),
158 UNI_RANGE(10),
159 UNI_RANGE(1),
160 UNI_RANGE(0.1),
161 UNI_RANGE(0.01)
162 }
163};
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179static const struct comedi_lrange *const das08_ai_lranges[] = {
180 &range_unknown,
181 &range_bipolar5,
182 &range_das08_pgh,
183 &range_das08_pgl,
184 &range_das08_pgm,
185};
186
187static const int das08_pgh_gainlist[] = {
188 8, 0, 10, 2, 12, 4, 14, 6, 1, 3, 5, 7
189};
190static const int das08_pgl_gainlist[] = { 8, 0, 2, 4, 6, 1, 3, 5, 7 };
191static const int das08_pgm_gainlist[] = { 8, 0, 10, 12, 14, 9, 11, 13, 15 };
192
193static const int *const das08_gainlists[] = {
194 NULL,
195 NULL,
196 das08_pgh_gainlist,
197 das08_pgl_gainlist,
198 das08_pgm_gainlist,
199};
200
201#define TIMEOUT 100000
202
203static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
204 struct comedi_insn *insn, unsigned int *data)
205{
206 const struct das08_board_struct *thisboard = comedi_board(dev);
207 struct das08_private_struct *devpriv = dev->private;
208 int i, n;
209 int chan;
210 int range;
211 int lsb, msb;
212
213 chan = CR_CHAN(insn->chanspec);
214 range = CR_RANGE(insn->chanspec);
215
216
217 inb(dev->iobase + DAS08_LSB);
218 inb(dev->iobase + DAS08_MSB);
219
220
221
222 spin_lock(&dev->spinlock);
223 devpriv->do_mux_bits &= ~DAS08_MUX_MASK;
224 devpriv->do_mux_bits |= DAS08_MUX(chan);
225 outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL);
226 spin_unlock(&dev->spinlock);
227
228 if (s->range_table->length > 1) {
229
230 range = CR_RANGE(insn->chanspec);
231 outb(devpriv->pg_gainlist[range],
232 dev->iobase + DAS08AO_GAIN_CONTROL);
233 }
234
235 for (n = 0; n < insn->n; n++) {
236
237 if (thisboard->ai_nbits == 16)
238 if (inb(dev->iobase + DAS08_MSB) & 0x80)
239 dev_info(dev->class_dev, "over-range\n");
240
241
242 outb_p(0, dev->iobase + DAS08_TRIG_12BIT);
243
244 for (i = 0; i < TIMEOUT; i++) {
245 if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC))
246 break;
247 }
248 if (i == TIMEOUT) {
249 dev_err(dev->class_dev, "timeout\n");
250 return -ETIME;
251 }
252 msb = inb(dev->iobase + DAS08_MSB);
253 lsb = inb(dev->iobase + DAS08_LSB);
254 if (thisboard->ai_encoding == das08_encode12) {
255 data[n] = (lsb >> 4) | (msb << 4);
256 } else if (thisboard->ai_encoding == das08_pcm_encode12) {
257 data[n] = (msb << 8) + lsb;
258 } else if (thisboard->ai_encoding == das08_encode16) {
259
260 if (msb & 0x80)
261 data[n] = (1 << 15) | lsb | ((msb & 0x7f) << 8);
262 else
263 data[n] = (1 << 15) - (lsb | (msb & 0x7f) << 8);
264 } else {
265 comedi_error(dev, "bug! unknown ai encoding");
266 return -1;
267 }
268 }
269
270 return n;
271}
272
273static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
274 struct comedi_insn *insn, unsigned int *data)
275{
276 data[0] = 0;
277 data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS));
278
279 return insn->n;
280}
281
282static int das08_do_wbits(struct comedi_device *dev,
283 struct comedi_subdevice *s,
284 struct comedi_insn *insn,
285 unsigned int *data)
286{
287 struct das08_private_struct *devpriv = dev->private;
288
289 if (comedi_dio_update_state(s, data)) {
290
291 spin_lock(&dev->spinlock);
292 devpriv->do_mux_bits &= ~DAS08_DO_MASK;
293 devpriv->do_mux_bits |= DAS08_OP(s->state);
294 outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL);
295 spin_unlock(&dev->spinlock);
296 }
297
298 data[1] = s->state;
299
300 return insn->n;
301}
302
303static int das08jr_di_rbits(struct comedi_device *dev,
304 struct comedi_subdevice *s,
305 struct comedi_insn *insn, unsigned int *data)
306{
307 data[0] = 0;
308 data[1] = inb(dev->iobase + DAS08JR_DIO);
309
310 return insn->n;
311}
312
313static int das08jr_do_wbits(struct comedi_device *dev,
314 struct comedi_subdevice *s,
315 struct comedi_insn *insn,
316 unsigned int *data)
317{
318 if (comedi_dio_update_state(s, data))
319 outb(s->state, dev->iobase + DAS08JR_DIO);
320
321 data[1] = s->state;
322
323 return insn->n;
324}
325
326static void das08_ao_set_data(struct comedi_device *dev,
327 unsigned int chan, unsigned int data)
328{
329 const struct das08_board_struct *thisboard = comedi_board(dev);
330 struct das08_private_struct *devpriv = dev->private;
331 unsigned char lsb;
332 unsigned char msb;
333
334 lsb = data & 0xff;
335 msb = (data >> 8) & 0xff;
336 if (thisboard->is_jr) {
337 outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan));
338 outb(msb, dev->iobase + DAS08JR_AO_MSB(chan));
339
340 inb(dev->iobase + DAS08JR_DIO);
341 } else {
342 outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan));
343 outb(msb, dev->iobase + DAS08AO_AO_MSB(chan));
344
345 inb(dev->iobase + DAS08AO_AO_UPDATE);
346 }
347 devpriv->ao_readback[chan] = data;
348}
349
350static void das08_ao_initialize(struct comedi_device *dev,
351 struct comedi_subdevice *s)
352{
353 int n;
354 unsigned int data;
355
356 data = s->maxdata / 2;
357 for (n = 0; n < s->n_chan; n++)
358 das08_ao_set_data(dev, n, data);
359}
360
361static int das08_ao_winsn(struct comedi_device *dev,
362 struct comedi_subdevice *s,
363 struct comedi_insn *insn, unsigned int *data)
364{
365 unsigned int n;
366 unsigned int chan;
367
368 chan = CR_CHAN(insn->chanspec);
369
370 for (n = 0; n < insn->n; n++)
371 das08_ao_set_data(dev, chan, *data);
372
373 return n;
374}
375
376static int das08_ao_rinsn(struct comedi_device *dev,
377 struct comedi_subdevice *s,
378 struct comedi_insn *insn, unsigned int *data)
379{
380 struct das08_private_struct *devpriv = dev->private;
381 unsigned int n;
382 unsigned int chan;
383
384 chan = CR_CHAN(insn->chanspec);
385
386 for (n = 0; n < insn->n; n++)
387 data[n] = devpriv->ao_readback[chan];
388
389 return n;
390}
391
392static void i8254_initialize(struct comedi_device *dev)
393{
394 const struct das08_board_struct *thisboard = comedi_board(dev);
395 unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
396 unsigned int mode = I8254_MODE0 | I8254_BINARY;
397 int i;
398
399 for (i = 0; i < 3; ++i)
400 i8254_set_mode(i8254_iobase, 0, i, mode);
401}
402
403static int das08_counter_read(struct comedi_device *dev,
404 struct comedi_subdevice *s,
405 struct comedi_insn *insn, unsigned int *data)
406{
407 const struct das08_board_struct *thisboard = comedi_board(dev);
408 unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
409 int chan = insn->chanspec;
410
411 data[0] = i8254_read(i8254_iobase, 0, chan);
412 return 1;
413}
414
415static int das08_counter_write(struct comedi_device *dev,
416 struct comedi_subdevice *s,
417 struct comedi_insn *insn, unsigned int *data)
418{
419 const struct das08_board_struct *thisboard = comedi_board(dev);
420 unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
421 int chan = insn->chanspec;
422
423 i8254_write(i8254_iobase, 0, chan, data[0]);
424 return 1;
425}
426
427static int das08_counter_config(struct comedi_device *dev,
428 struct comedi_subdevice *s,
429 struct comedi_insn *insn, unsigned int *data)
430{
431 const struct das08_board_struct *thisboard = comedi_board(dev);
432 unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
433 int chan = insn->chanspec;
434
435 switch (data[0]) {
436 case INSN_CONFIG_SET_COUNTER_MODE:
437 i8254_set_mode(i8254_iobase, 0, chan, data[1]);
438 break;
439 case INSN_CONFIG_8254_READ_STATUS:
440 data[1] = i8254_status(i8254_iobase, 0, chan);
441 break;
442 default:
443 return -EINVAL;
444 break;
445 }
446 return 2;
447}
448
449int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
450{
451 const struct das08_board_struct *thisboard = comedi_board(dev);
452 struct das08_private_struct *devpriv = dev->private;
453 struct comedi_subdevice *s;
454 int ret;
455
456 dev->iobase = iobase;
457
458 dev->board_name = thisboard->name;
459
460 ret = comedi_alloc_subdevices(dev, 6);
461 if (ret)
462 return ret;
463
464 s = &dev->subdevices[0];
465
466 if (thisboard->ai_nbits) {
467 s->type = COMEDI_SUBD_AI;
468
469
470
471
472
473 s->subdev_flags = SDF_READABLE | SDF_GROUND;
474 s->n_chan = 8;
475 s->maxdata = (1 << thisboard->ai_nbits) - 1;
476 s->range_table = das08_ai_lranges[thisboard->ai_pg];
477 s->insn_read = das08_ai_rinsn;
478 devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg];
479 } else {
480 s->type = COMEDI_SUBD_UNUSED;
481 }
482
483 s = &dev->subdevices[1];
484
485 if (thisboard->ao_nbits) {
486 s->type = COMEDI_SUBD_AO;
487 s->subdev_flags = SDF_WRITABLE;
488 s->n_chan = 2;
489 s->maxdata = (1 << thisboard->ao_nbits) - 1;
490 s->range_table = &range_bipolar5;
491 s->insn_write = das08_ao_winsn;
492 s->insn_read = das08_ao_rinsn;
493 das08_ao_initialize(dev, s);
494 } else {
495 s->type = COMEDI_SUBD_UNUSED;
496 }
497
498 s = &dev->subdevices[2];
499
500 if (thisboard->di_nchan) {
501 s->type = COMEDI_SUBD_DI;
502 s->subdev_flags = SDF_READABLE;
503 s->n_chan = thisboard->di_nchan;
504 s->maxdata = 1;
505 s->range_table = &range_digital;
506 s->insn_bits =
507 thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits;
508 } else {
509 s->type = COMEDI_SUBD_UNUSED;
510 }
511
512 s = &dev->subdevices[3];
513
514 if (thisboard->do_nchan) {
515 s->type = COMEDI_SUBD_DO;
516 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
517 s->n_chan = thisboard->do_nchan;
518 s->maxdata = 1;
519 s->range_table = &range_digital;
520 s->insn_bits =
521 thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits;
522 } else {
523 s->type = COMEDI_SUBD_UNUSED;
524 }
525
526 s = &dev->subdevices[4];
527
528 if (thisboard->i8255_offset != 0) {
529 subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase +
530 thisboard->
531 i8255_offset));
532 } else {
533 s->type = COMEDI_SUBD_UNUSED;
534 }
535
536 s = &dev->subdevices[5];
537
538 if (thisboard->i8254_offset != 0) {
539 s->type = COMEDI_SUBD_COUNTER;
540 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
541 s->n_chan = 3;
542 s->maxdata = 0xFFFF;
543 s->insn_read = das08_counter_read;
544 s->insn_write = das08_counter_write;
545 s->insn_config = das08_counter_config;
546 i8254_initialize(dev);
547 } else {
548 s->type = COMEDI_SUBD_UNUSED;
549 }
550
551 return 0;
552}
553EXPORT_SYMBOL_GPL(das08_common_attach);
554
555static int __init das08_init(void)
556{
557 return 0;
558}
559module_init(das08_init);
560
561static void __exit das08_exit(void)
562{
563}
564module_exit(das08_exit);
565
566MODULE_AUTHOR("Comedi http://www.comedi.org");
567MODULE_DESCRIPTION("Comedi low-level driver");
568MODULE_LICENSE("GPL");
569