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