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#include <linux/interrupt.h>
39#include "../comedidev.h"
40
41#include <linux/ioport.h>
42
43#include "8255.h"
44
45
46#define COM_REG_1 0x00
47#define STAT_REG 0x00
48#define COM_REG_2 0x02
49
50#define START_CONVERT_REG 0x08
51#define START_DAQ_REG 0x0A
52#define AD_CLEAR_REG 0x0C
53#define EXT_STROBE_REG 0x0E
54
55#define DAC0_REG 0x10
56#define DAC1_REG 0x12
57#define INT2CLR_REG 0x14
58
59#define MUX_CNTR_REG 0x04
60#define MUX_GAIN_REG 0x06
61#define AD_FIFO_REG 0x16
62#define DMA_TC_INT_CLR_REG 0x16
63
64#define AM9513A_DATA_REG 0x18
65#define AM9513A_COM_REG 0x1A
66#define AM9513A_STAT_REG 0x1A
67
68#define MIO_16_DIG_IN_REG 0x1C
69#define MIO_16_DIG_OUT_REG 0x1C
70
71#define RTSI_SW_SHIFT_REG 0x1E
72#define RTSI_SW_STROBE_REG 0x1F
73
74#define DIO_24_PORTA_REG 0x00
75#define DIO_24_PORTB_REG 0x01
76#define DIO_24_PORTC_REG 0x02
77#define DIO_24_CNFG_REG 0x03
78
79
80#define COMREG1_2SCADC 0x0001
81#define COMREG1_1632CNT 0x0002
82#define COMREG1_SCANEN 0x0008
83#define COMREG1_DAQEN 0x0010
84#define COMREG1_DMAEN 0x0020
85#define COMREG1_CONVINTEN 0x0080
86#define COMREG2_SCN2 0x0010
87#define COMREG2_INTEN 0x0080
88#define COMREG2_DOUTEN0 0x0100
89#define COMREG2_DOUTEN1 0x0200
90
91#define STAT_AD_OVERRUN 0x0100
92#define STAT_AD_OVERFLOW 0x0200
93#define STAT_AD_DAQPROG 0x0800
94#define STAT_AD_CONVAVAIL 0x2000
95#define STAT_AD_DAQSTOPINT 0x4000
96
97#define CLOCK_1_MHZ 0x8B25
98#define CLOCK_100_KHZ 0x8C25
99#define CLOCK_10_KHZ 0x8D25
100#define CLOCK_1_KHZ 0x8E25
101#define CLOCK_100_HZ 0x8F25
102
103#define ATMIO16D_SIZE 32
104#define devpriv ((struct atmio16d_private *)dev->private)
105#define ATMIO16D_TIMEOUT 10
106
107struct atmio16_board_t {
108
109 const char *name;
110 int has_8255;
111};
112
113static const struct atmio16_board_t atmio16_boards[] = {
114 {
115 .name = "atmio16",
116 .has_8255 = 0,
117 },
118 {
119 .name = "atmio16d",
120 .has_8255 = 1,
121 },
122};
123
124#define n_atmio16_boards ARRAY_SIZE(atmio16_boards)
125
126#define boardtype ((const struct atmio16_board_t *)dev->board_ptr)
127
128
129static int atmio16d_attach(struct comedi_device *dev,
130 struct comedi_devconfig *it);
131static int atmio16d_detach(struct comedi_device *dev);
132static irqreturn_t atmio16d_interrupt(int irq, void *d);
133static int atmio16d_ai_cmdtest(struct comedi_device *dev,
134 struct comedi_subdevice *s,
135 struct comedi_cmd *cmd);
136static int atmio16d_ai_cmd(struct comedi_device *dev,
137 struct comedi_subdevice *s);
138static int atmio16d_ai_cancel(struct comedi_device *dev,
139 struct comedi_subdevice *s);
140static void reset_counters(struct comedi_device *dev);
141static void reset_atmio16d(struct comedi_device *dev);
142
143
144static struct comedi_driver driver_atmio16d = {
145 .driver_name = "atmio16",
146 .module = THIS_MODULE,
147 .attach = atmio16d_attach,
148 .detach = atmio16d_detach,
149 .board_name = &atmio16_boards[0].name,
150 .num_names = n_atmio16_boards,
151 .offset = sizeof(struct atmio16_board_t),
152};
153
154static int __init driver_atmio16d_init_module(void)
155{
156 return comedi_driver_register(&driver_atmio16d);
157}
158
159static void __exit driver_atmio16d_cleanup_module(void)
160{
161 comedi_driver_unregister(&driver_atmio16d);
162}
163
164module_init(driver_atmio16d_init_module);
165module_exit(driver_atmio16d_cleanup_module);
166
167
168static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
169 BIP_RANGE
170 (10),
171 BIP_RANGE
172 (1),
173 BIP_RANGE
174 (0.1),
175 BIP_RANGE
176 (0.02)
177 }
178};
179
180static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 4, {
181 BIP_RANGE
182 (5),
183 BIP_RANGE
184 (0.5),
185 BIP_RANGE
186 (0.05),
187 BIP_RANGE
188 (0.01)
189 }
190};
191
192static const struct comedi_lrange range_atmio16d_ai_unipolar = { 4, {
193 UNI_RANGE
194 (10),
195 UNI_RANGE
196 (1),
197 UNI_RANGE
198 (0.1),
199 UNI_RANGE
200 (0.02)
201 }
202};
203
204
205struct atmio16d_private {
206 enum { adc_diff, adc_singleended } adc_mux;
207 enum { adc_bipolar10, adc_bipolar5, adc_unipolar10 } adc_range;
208 enum { adc_2comp, adc_straight } adc_coding;
209 enum { dac_bipolar, dac_unipolar } dac0_range, dac1_range;
210 enum { dac_internal, dac_external } dac0_reference, dac1_reference;
211 enum { dac_2comp, dac_straight } dac0_coding, dac1_coding;
212 const struct comedi_lrange *ao_range_type_list[2];
213 unsigned int ao_readback[2];
214 unsigned int com_reg_1_state;
215 unsigned int com_reg_2_state;
216};
217
218static void reset_counters(struct comedi_device *dev)
219{
220
221 outw(0xFFC2, dev->iobase + AM9513A_COM_REG);
222 outw(0xFF02, dev->iobase + AM9513A_COM_REG);
223 outw(0x4, dev->iobase + AM9513A_DATA_REG);
224 outw(0xFF0A, dev->iobase + AM9513A_COM_REG);
225 outw(0x3, dev->iobase + AM9513A_DATA_REG);
226 outw(0xFF42, dev->iobase + AM9513A_COM_REG);
227 outw(0xFF42, dev->iobase + AM9513A_COM_REG);
228
229 outw(0xFFC4, dev->iobase + AM9513A_COM_REG);
230 outw(0xFF03, dev->iobase + AM9513A_COM_REG);
231 outw(0x4, dev->iobase + AM9513A_DATA_REG);
232 outw(0xFF0B, dev->iobase + AM9513A_COM_REG);
233 outw(0x3, dev->iobase + AM9513A_DATA_REG);
234 outw(0xFF44, dev->iobase + AM9513A_COM_REG);
235 outw(0xFF44, dev->iobase + AM9513A_COM_REG);
236
237 outw(0xFFC8, dev->iobase + AM9513A_COM_REG);
238 outw(0xFF04, dev->iobase + AM9513A_COM_REG);
239 outw(0x4, dev->iobase + AM9513A_DATA_REG);
240 outw(0xFF0C, dev->iobase + AM9513A_COM_REG);
241 outw(0x3, dev->iobase + AM9513A_DATA_REG);
242 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
243 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
244
245 outw(0xFFD0, dev->iobase + AM9513A_COM_REG);
246 outw(0xFF05, dev->iobase + AM9513A_COM_REG);
247 outw(0x4, dev->iobase + AM9513A_DATA_REG);
248 outw(0xFF0D, dev->iobase + AM9513A_COM_REG);
249 outw(0x3, dev->iobase + AM9513A_DATA_REG);
250 outw(0xFF50, dev->iobase + AM9513A_COM_REG);
251 outw(0xFF50, dev->iobase + AM9513A_COM_REG);
252
253 outw(0, dev->iobase + AD_CLEAR_REG);
254}
255
256static void reset_atmio16d(struct comedi_device *dev)
257{
258 int i;
259
260
261 outw(0, dev->iobase + COM_REG_1);
262 outw(0, dev->iobase + COM_REG_2);
263 outw(0, dev->iobase + MUX_GAIN_REG);
264
265 outw(0xFFFF, dev->iobase + AM9513A_COM_REG);
266 outw(0xFFEF, dev->iobase + AM9513A_COM_REG);
267 outw(0xFF17, dev->iobase + AM9513A_COM_REG);
268 outw(0xF000, dev->iobase + AM9513A_DATA_REG);
269 for (i = 1; i <= 5; ++i) {
270 outw(0xFF00 + i, dev->iobase + AM9513A_COM_REG);
271 outw(0x0004, dev->iobase + AM9513A_DATA_REG);
272 outw(0xFF08 + i, dev->iobase + AM9513A_COM_REG);
273 outw(0x3, dev->iobase + AM9513A_DATA_REG);
274 }
275 outw(0xFF5F, dev->iobase + AM9513A_COM_REG);
276
277 outw(0, dev->iobase + AD_CLEAR_REG);
278 outw(0, dev->iobase + INT2CLR_REG);
279
280 devpriv->com_reg_1_state |= 1;
281 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
282 devpriv->adc_coding = adc_straight;
283
284 outw(2048, dev->iobase + DAC0_REG);
285 outw(2048, dev->iobase + DAC1_REG);
286}
287
288static irqreturn_t atmio16d_interrupt(int irq, void *d)
289{
290 struct comedi_device *dev = d;
291 struct comedi_subdevice *s = dev->subdevices + 0;
292
293#ifdef DEBUG1
294 printk(KERN_DEBUG "atmio16d_interrupt!\n");
295#endif
296
297 comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG));
298
299 comedi_event(dev, s);
300 return IRQ_HANDLED;
301}
302
303static int atmio16d_ai_cmdtest(struct comedi_device *dev,
304 struct comedi_subdevice *s,
305 struct comedi_cmd *cmd)
306{
307 int err = 0, tmp;
308#ifdef DEBUG1
309 printk(KERN_DEBUG "atmio16d_ai_cmdtest\n");
310#endif
311
312 tmp = cmd->start_src;
313 cmd->start_src &= TRIG_NOW;
314 if (!cmd->start_src || tmp != cmd->start_src)
315 err++;
316
317 tmp = cmd->scan_begin_src;
318 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER;
319 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
320 err++;
321
322 tmp = cmd->convert_src;
323 cmd->convert_src &= TRIG_TIMER;
324 if (!cmd->convert_src || tmp != cmd->convert_src)
325 err++;
326
327 tmp = cmd->scan_end_src;
328 cmd->scan_end_src &= TRIG_COUNT;
329 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
330 err++;
331
332 tmp = cmd->stop_src;
333 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
334 if (!cmd->stop_src || tmp != cmd->stop_src)
335 err++;
336
337 if (err)
338 return 1;
339
340
341
342 if (cmd->scan_begin_src != TRIG_FOLLOW &&
343 cmd->scan_begin_src != TRIG_EXT &&
344 cmd->scan_begin_src != TRIG_TIMER)
345 err++;
346 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
347 err++;
348
349 if (err)
350 return 2;
351
352
353
354 if (cmd->start_arg != 0) {
355 cmd->start_arg = 0;
356 err++;
357 }
358 if (cmd->scan_begin_src == TRIG_FOLLOW) {
359
360 if (cmd->scan_begin_arg != 0) {
361 cmd->scan_begin_arg = 0;
362 err++;
363 }
364 } else {
365#if 0
366
367
368 if (cmd->scan_begin_arg != 0) {
369 cmd->scan_begin_arg = 0;
370 err++;
371 }
372#endif
373 }
374
375 if (cmd->convert_arg < 10000) {
376 cmd->convert_arg = 10000;
377 err++;
378 }
379#if 0
380 if (cmd->convert_arg > SLOWEST_TIMER) {
381 cmd->convert_arg = SLOWEST_TIMER;
382 err++;
383 }
384#endif
385 if (cmd->scan_end_arg != cmd->chanlist_len) {
386 cmd->scan_end_arg = cmd->chanlist_len;
387 err++;
388 }
389 if (cmd->stop_src == TRIG_COUNT) {
390
391 } else {
392
393 if (cmd->stop_arg != 0) {
394 cmd->stop_arg = 0;
395 err++;
396 }
397 }
398
399 if (err)
400 return 3;
401
402 return 0;
403}
404
405static int atmio16d_ai_cmd(struct comedi_device *dev,
406 struct comedi_subdevice *s)
407{
408 struct comedi_cmd *cmd = &s->async->cmd;
409 unsigned int timer, base_clock;
410 unsigned int sample_count, tmp, chan, gain;
411 int i;
412#ifdef DEBUG1
413 printk(KERN_DEBUG "atmio16d_ai_cmd\n");
414#endif
415
416
417
418 reset_counters(dev);
419 s->async->cur_chan = 0;
420
421
422 if (cmd->chanlist_len < 2) {
423 devpriv->com_reg_1_state &= ~COMREG1_SCANEN;
424 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
425 } else {
426 devpriv->com_reg_1_state |= COMREG1_SCANEN;
427 devpriv->com_reg_2_state |= COMREG2_SCN2;
428 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
429 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
430 }
431
432
433 for (i = 0; i < cmd->chanlist_len; ++i) {
434 chan = CR_CHAN(cmd->chanlist[i]);
435 gain = CR_RANGE(cmd->chanlist[i]);
436 outw(i, dev->iobase + MUX_CNTR_REG);
437 tmp = chan | (gain << 6);
438 if (i == cmd->scan_end_arg - 1)
439 tmp |= 0x0010;
440 outw(tmp, dev->iobase + MUX_GAIN_REG);
441 }
442
443
444
445
446 if (cmd->convert_arg < 65536000) {
447 base_clock = CLOCK_1_MHZ;
448 timer = cmd->convert_arg / 1000;
449 } else if (cmd->convert_arg < 655360000) {
450 base_clock = CLOCK_100_KHZ;
451 timer = cmd->convert_arg / 10000;
452 } else if (cmd->convert_arg <= 0xffffffff ) {
453 base_clock = CLOCK_10_KHZ;
454 timer = cmd->convert_arg / 100000;
455 } else if (cmd->convert_arg <= 0xffffffff ) {
456 base_clock = CLOCK_1_KHZ;
457 timer = cmd->convert_arg / 1000000;
458 }
459 outw(0xFF03, dev->iobase + AM9513A_COM_REG);
460 outw(base_clock, dev->iobase + AM9513A_DATA_REG);
461 outw(0xFF0B, dev->iobase + AM9513A_COM_REG);
462 outw(0x2, dev->iobase + AM9513A_DATA_REG);
463 outw(0xFF44, dev->iobase + AM9513A_COM_REG);
464 outw(0xFFF3, dev->iobase + AM9513A_COM_REG);
465 outw(timer, dev->iobase + AM9513A_DATA_REG);
466 outw(0xFF24, dev->iobase + AM9513A_COM_REG);
467
468
469
470 sample_count = cmd->stop_arg * cmd->scan_end_arg;
471 outw(0xFF04, dev->iobase + AM9513A_COM_REG);
472 outw(0x1025, dev->iobase + AM9513A_DATA_REG);
473 outw(0xFF0C, dev->iobase + AM9513A_COM_REG);
474 if (sample_count < 65536) {
475
476 outw(sample_count, dev->iobase + AM9513A_DATA_REG);
477 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
478 outw(0xFFF4, dev->iobase + AM9513A_COM_REG);
479 outw(0xFF28, dev->iobase + AM9513A_COM_REG);
480 devpriv->com_reg_1_state &= ~COMREG1_1632CNT;
481 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
482 } else {
483
484
485 tmp = sample_count & 0xFFFF;
486 if (tmp)
487 outw(tmp - 1, dev->iobase + AM9513A_DATA_REG);
488 else
489 outw(0xFFFF, dev->iobase + AM9513A_DATA_REG);
490
491 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
492 outw(0, dev->iobase + AM9513A_DATA_REG);
493 outw(0xFF28, dev->iobase + AM9513A_COM_REG);
494 outw(0xFF05, dev->iobase + AM9513A_COM_REG);
495 outw(0x25, dev->iobase + AM9513A_DATA_REG);
496 outw(0xFF0D, dev->iobase + AM9513A_COM_REG);
497 tmp = sample_count & 0xFFFF;
498 if ((tmp == 0) || (tmp == 1)) {
499 outw((sample_count >> 16) & 0xFFFF,
500 dev->iobase + AM9513A_DATA_REG);
501 } else {
502 outw(((sample_count >> 16) & 0xFFFF) + 1,
503 dev->iobase + AM9513A_DATA_REG);
504 }
505 outw(0xFF70, dev->iobase + AM9513A_COM_REG);
506 devpriv->com_reg_1_state |= COMREG1_1632CNT;
507 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
508 }
509
510
511
512
513 if (cmd->chanlist_len > 1) {
514 if (cmd->scan_begin_arg < 65536000) {
515 base_clock = CLOCK_1_MHZ;
516 timer = cmd->scan_begin_arg / 1000;
517 } else if (cmd->scan_begin_arg < 655360000) {
518 base_clock = CLOCK_100_KHZ;
519 timer = cmd->scan_begin_arg / 10000;
520 } else if (cmd->scan_begin_arg < 0xffffffff ) {
521 base_clock = CLOCK_10_KHZ;
522 timer = cmd->scan_begin_arg / 100000;
523 } else if (cmd->scan_begin_arg < 0xffffffff ) {
524 base_clock = CLOCK_1_KHZ;
525 timer = cmd->scan_begin_arg / 1000000;
526 }
527 outw(0xFF02, dev->iobase + AM9513A_COM_REG);
528 outw(base_clock, dev->iobase + AM9513A_DATA_REG);
529 outw(0xFF0A, dev->iobase + AM9513A_COM_REG);
530 outw(0x2, dev->iobase + AM9513A_DATA_REG);
531 outw(0xFF42, dev->iobase + AM9513A_COM_REG);
532 outw(0xFFF2, dev->iobase + AM9513A_COM_REG);
533 outw(timer, dev->iobase + AM9513A_DATA_REG);
534 outw(0xFF22, dev->iobase + AM9513A_COM_REG);
535 }
536
537
538 outw(0, dev->iobase + AD_CLEAR_REG);
539 outw(0, dev->iobase + MUX_CNTR_REG);
540 outw(0, dev->iobase + INT2CLR_REG);
541
542 devpriv->com_reg_1_state |= COMREG1_DAQEN;
543 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
544
545 devpriv->com_reg_1_state |= COMREG1_CONVINTEN;
546 devpriv->com_reg_2_state |= COMREG2_INTEN;
547 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
548 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
549
550 outw(0, dev->iobase + START_DAQ_REG);
551
552 return 0;
553}
554
555
556static int atmio16d_ai_cancel(struct comedi_device *dev,
557 struct comedi_subdevice *s)
558{
559 reset_atmio16d(dev);
560
561 return 0;
562}
563
564
565static int atmio16d_ai_insn_read(struct comedi_device *dev,
566 struct comedi_subdevice *s,
567 struct comedi_insn *insn, unsigned int *data)
568{
569 int i, t;
570 int chan;
571 int gain;
572 int status;
573
574#ifdef DEBUG1
575 printk(KERN_DEBUG "atmio16d_ai_insn_read\n");
576#endif
577 chan = CR_CHAN(insn->chanspec);
578 gain = CR_RANGE(insn->chanspec);
579
580
581
582
583
584
585
586 outw(chan | (gain << 6), dev->iobase + MUX_GAIN_REG);
587
588 for (i = 0; i < insn->n; i++) {
589
590 outw(0, dev->iobase + START_CONVERT_REG);
591
592 for (t = 0; t < ATMIO16D_TIMEOUT; t++) {
593
594 status = inw(dev->iobase + STAT_REG);
595#ifdef DEBUG1
596 printk(KERN_DEBUG "status=%x\n", status);
597#endif
598 if (status & STAT_AD_CONVAVAIL) {
599
600 data[i] = inw(dev->iobase + AD_FIFO_REG);
601
602 if (devpriv->adc_coding == adc_2comp)
603 data[i] ^= 0x800;
604 break;
605 }
606 if (status & STAT_AD_OVERFLOW) {
607 printk(KERN_INFO "atmio16d: a/d FIFO overflow\n");
608 outw(0, dev->iobase + AD_CLEAR_REG);
609
610 return -ETIME;
611 }
612 }
613
614 if (t == ATMIO16D_TIMEOUT) {
615 printk(KERN_INFO "atmio16d: timeout\n");
616
617 return -ETIME;
618 }
619 }
620
621 return i;
622}
623
624static int atmio16d_ao_insn_read(struct comedi_device *dev,
625 struct comedi_subdevice *s,
626 struct comedi_insn *insn, unsigned int *data)
627{
628 int i;
629#ifdef DEBUG1
630 printk(KERN_DEBUG "atmio16d_ao_insn_read\n");
631#endif
632
633 for (i = 0; i < insn->n; i++)
634 data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
635 return i;
636}
637
638static int atmio16d_ao_insn_write(struct comedi_device *dev,
639 struct comedi_subdevice *s,
640 struct comedi_insn *insn, unsigned int *data)
641{
642 int i;
643 int chan;
644 int d;
645#ifdef DEBUG1
646 printk(KERN_DEBUG "atmio16d_ao_insn_write\n");
647#endif
648
649 chan = CR_CHAN(insn->chanspec);
650
651 for (i = 0; i < insn->n; i++) {
652 d = data[i];
653 switch (chan) {
654 case 0:
655 if (devpriv->dac0_coding == dac_2comp)
656 d ^= 0x800;
657 outw(d, dev->iobase + DAC0_REG);
658 break;
659 case 1:
660 if (devpriv->dac1_coding == dac_2comp)
661 d ^= 0x800;
662 outw(d, dev->iobase + DAC1_REG);
663 break;
664 default:
665 return -EINVAL;
666 }
667 devpriv->ao_readback[chan] = data[i];
668 }
669 return i;
670}
671
672static int atmio16d_dio_insn_bits(struct comedi_device *dev,
673 struct comedi_subdevice *s,
674 struct comedi_insn *insn, unsigned int *data)
675{
676 if (insn->n != 2)
677 return -EINVAL;
678
679 if (data[0]) {
680 s->state &= ~data[0];
681 s->state |= (data[0] | data[1]);
682 outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG);
683 }
684 data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG);
685
686 return 2;
687}
688
689static int atmio16d_dio_insn_config(struct comedi_device *dev,
690 struct comedi_subdevice *s,
691 struct comedi_insn *insn,
692 unsigned int *data)
693{
694 int i;
695 int mask;
696
697 for (i = 0; i < insn->n; i++) {
698 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
699 s->io_bits &= ~mask;
700 if (data[i])
701 s->io_bits |= mask;
702 }
703 devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1);
704 if (s->io_bits & 0x0f)
705 devpriv->com_reg_2_state |= COMREG2_DOUTEN0;
706 if (s->io_bits & 0xf0)
707 devpriv->com_reg_2_state |= COMREG2_DOUTEN1;
708 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
709
710 return i;
711}
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745static int atmio16d_attach(struct comedi_device *dev,
746 struct comedi_devconfig *it)
747{
748 unsigned int irq;
749 unsigned long iobase;
750 int ret;
751
752 struct comedi_subdevice *s;
753
754
755 iobase = it->options[0];
756 printk(KERN_INFO "comedi%d: atmio16d: 0x%04lx ", dev->minor, iobase);
757 if (!request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d")) {
758 printk("I/O port conflict\n");
759 return -EIO;
760 }
761 dev->iobase = iobase;
762
763
764 dev->board_name = boardtype->name;
765
766 ret = alloc_subdevices(dev, 4);
767 if (ret < 0)
768 return ret;
769
770 ret = alloc_private(dev, sizeof(struct atmio16d_private));
771 if (ret < 0)
772 return ret;
773
774
775 reset_atmio16d(dev);
776
777
778 irq = it->options[1];
779 if (irq) {
780
781 ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev);
782 if (ret < 0) {
783 printk(KERN_INFO "failed to allocate irq %u\n", irq);
784 return ret;
785 }
786 dev->irq = irq;
787 printk(KERN_INFO "( irq = %u )\n", irq);
788 } else {
789 printk(KERN_INFO "( no irq )");
790 }
791
792
793 devpriv->adc_mux = it->options[5];
794 devpriv->adc_range = it->options[6];
795
796 devpriv->dac0_range = it->options[7];
797 devpriv->dac0_reference = it->options[8];
798 devpriv->dac0_coding = it->options[9];
799 devpriv->dac1_range = it->options[10];
800 devpriv->dac1_reference = it->options[11];
801 devpriv->dac1_coding = it->options[12];
802
803
804 s = dev->subdevices + 0;
805 dev->read_subdev = s;
806
807 s->type = COMEDI_SUBD_AI;
808 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
809 s->n_chan = (devpriv->adc_mux ? 16 : 8);
810 s->len_chanlist = 16;
811 s->insn_read = atmio16d_ai_insn_read;
812 s->do_cmdtest = atmio16d_ai_cmdtest;
813 s->do_cmd = atmio16d_ai_cmd;
814 s->cancel = atmio16d_ai_cancel;
815 s->maxdata = 0xfff;
816 switch (devpriv->adc_range) {
817 case adc_bipolar10:
818 s->range_table = &range_atmio16d_ai_10_bipolar;
819 break;
820 case adc_bipolar5:
821 s->range_table = &range_atmio16d_ai_5_bipolar;
822 break;
823 case adc_unipolar10:
824 s->range_table = &range_atmio16d_ai_unipolar;
825 break;
826 }
827
828
829 s++;
830 s->type = COMEDI_SUBD_AO;
831 s->subdev_flags = SDF_WRITABLE;
832 s->n_chan = 2;
833 s->insn_read = atmio16d_ao_insn_read;
834 s->insn_write = atmio16d_ao_insn_write;
835 s->maxdata = 0xfff;
836 s->range_table_list = devpriv->ao_range_type_list;
837 switch (devpriv->dac0_range) {
838 case dac_bipolar:
839 devpriv->ao_range_type_list[0] = &range_bipolar10;
840 break;
841 case dac_unipolar:
842 devpriv->ao_range_type_list[0] = &range_unipolar10;
843 break;
844 }
845 switch (devpriv->dac1_range) {
846 case dac_bipolar:
847 devpriv->ao_range_type_list[1] = &range_bipolar10;
848 break;
849 case dac_unipolar:
850 devpriv->ao_range_type_list[1] = &range_unipolar10;
851 break;
852 }
853
854
855 s++;
856 s->type = COMEDI_SUBD_DIO;
857 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
858 s->n_chan = 8;
859 s->insn_bits = atmio16d_dio_insn_bits;
860 s->insn_config = atmio16d_dio_insn_config;
861 s->maxdata = 1;
862 s->range_table = &range_digital;
863
864
865 s++;
866 if (boardtype->has_8255)
867 subdev_8255_init(dev, s, NULL, dev->iobase);
868 else
869 s->type = COMEDI_SUBD_UNUSED;
870
871
872#if 0
873 s++;
874
875 s->type = COMEDI_SUBD_TIMER;
876 s->n_chan = 0;
877 s->maxdata = 0
878#endif
879 printk("\n");
880
881 return 0;
882}
883
884static int atmio16d_detach(struct comedi_device *dev)
885{
886 printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor);
887
888 if (dev->subdevices && boardtype->has_8255)
889 subdev_8255_cleanup(dev, dev->subdevices + 3);
890
891 if (dev->irq)
892 free_irq(dev->irq, dev);
893
894 reset_atmio16d(dev);
895
896 if (dev->iobase)
897 release_region(dev->iobase, ATMIO16D_SIZE);
898
899 return 0;
900}
901
902MODULE_AUTHOR("Comedi http://www.comedi.org");
903MODULE_DESCRIPTION("Comedi low-level driver");
904MODULE_LICENSE("GPL");
905