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#include <linux/module.h>
64#include <linux/delay.h>
65#include <linux/interrupt.h>
66
67#include "../comedi_pci.h"
68
69#include "comedi_8254.h"
70#include "8255.h"
71#include "amcc_s5933.h"
72
73#define AI_BUFFER_SIZE 1024
74#define AO_BUFFER_SIZE 1024
75
76
77
78
79#define PCIDAS_CTRL_REG 0x00
80#define PCIDAS_CTRL_INT(x) (((x) & 0x3) << 0)
81#define PCIDAS_CTRL_INT_NONE PCIDAS_CTRL_INT(0)
82#define PCIDAS_CTRL_INT_EOS PCIDAS_CTRL_INT(1)
83#define PCIDAS_CTRL_INT_FHF PCIDAS_CTRL_INT(2)
84#define PCIDAS_CTRL_INT_FNE PCIDAS_CTRL_INT(3)
85#define PCIDAS_CTRL_INT_MASK PCIDAS_CTRL_INT(3)
86#define PCIDAS_CTRL_INTE BIT(2)
87#define PCIDAS_CTRL_DAHFIE BIT(3)
88#define PCIDAS_CTRL_EOAIE BIT(4)
89#define PCIDAS_CTRL_DAHFI BIT(5)
90#define PCIDAS_CTRL_EOAI BIT(6)
91#define PCIDAS_CTRL_INT_CLR BIT(7)
92#define PCIDAS_CTRL_EOBI BIT(9)
93#define PCIDAS_CTRL_ADHFI BIT(10)
94#define PCIDAS_CTRL_ADNEI BIT(11)
95#define PCIDAS_CTRL_ADNE BIT(12)
96#define PCIDAS_CTRL_DAEMIE BIT(12)
97#define PCIDAS_CTRL_LADFUL BIT(13)
98#define PCIDAS_CTRL_DAEMI BIT(14)
99
100#define PCIDAS_CTRL_AI_INT (PCIDAS_CTRL_EOAI | PCIDAS_CTRL_EOBI | \
101 PCIDAS_CTRL_ADHFI | PCIDAS_CTRL_ADNEI | \
102 PCIDAS_CTRL_LADFUL)
103#define PCIDAS_CTRL_AO_INT (PCIDAS_CTRL_DAHFI | PCIDAS_CTRL_DAEMI)
104
105#define PCIDAS_AI_REG 0x02
106#define PCIDAS_AI_FIRST(x) ((x) & 0xf)
107#define PCIDAS_AI_LAST(x) (((x) & 0xf) << 4)
108#define PCIDAS_AI_CHAN(x) (PCIDAS_AI_FIRST(x) | PCIDAS_AI_LAST(x))
109#define PCIDAS_AI_GAIN(x) (((x) & 0x3) << 8)
110#define PCIDAS_AI_SE BIT(10)
111#define PCIDAS_AI_UNIP BIT(11)
112#define PCIDAS_AI_PACER(x) (((x) & 0x3) << 12)
113#define PCIDAS_AI_PACER_SW PCIDAS_AI_PACER(0)
114#define PCIDAS_AI_PACER_INT PCIDAS_AI_PACER(1)
115#define PCIDAS_AI_PACER_EXTN PCIDAS_AI_PACER(2)
116#define PCIDAS_AI_PACER_EXTP PCIDAS_AI_PACER(3)
117#define PCIDAS_AI_PACER_MASK PCIDAS_AI_PACER(3)
118#define PCIDAS_AI_EOC BIT(14)
119
120#define PCIDAS_TRIG_REG 0x04
121#define PCIDAS_TRIG_SEL(x) (((x) & 0x3) << 0)
122#define PCIDAS_TRIG_SEL_NONE PCIDAS_TRIG_SEL(0)
123#define PCIDAS_TRIG_SEL_SW PCIDAS_TRIG_SEL(1)
124#define PCIDAS_TRIG_SEL_EXT PCIDAS_TRIG_SEL(2)
125#define PCIDAS_TRIG_SEL_ANALOG PCIDAS_TRIG_SEL(3)
126#define PCIDAS_TRIG_SEL_MASK PCIDAS_TRIG_SEL(3)
127#define PCIDAS_TRIG_POL BIT(2)
128#define PCIDAS_TRIG_MODE BIT(3)
129#define PCIDAS_TRIG_EN BIT(4)
130#define PCIDAS_TRIG_BURSTE BIT(5)
131#define PCIDAS_TRIG_CLR BIT(7)
132
133#define PCIDAS_CALIB_REG 0x06
134#define PCIDAS_CALIB_8800_SEL BIT(8)
135#define PCIDAS_CALIB_TRIM_SEL BIT(9)
136#define PCIDAS_CALIB_DAC08_SEL BIT(10)
137#define PCIDAS_CALIB_SRC(x) (((x) & 0x7) << 11)
138#define PCIDAS_CALIB_EN BIT(14)
139#define PCIDAS_CALIB_DATA BIT(15)
140
141#define PCIDAS_AO_REG 0x08
142#define PCIDAS_AO_EMPTY BIT(0)
143#define PCIDAS_AO_DACEN BIT(1)
144#define PCIDAS_AO_START BIT(2)
145#define PCIDAS_AO_PACER(x) (((x) & 0x3) << 3)
146#define PCIDAS_AO_PACER_SW PCIDAS_AO_PACER(0)
147#define PCIDAS_AO_PACER_INT PCIDAS_AO_PACER(1)
148#define PCIDAS_AO_PACER_EXTN PCIDAS_AO_PACER(2)
149#define PCIDAS_AO_PACER_EXTP PCIDAS_AO_PACER(3)
150#define PCIDAS_AO_PACER_MASK PCIDAS_AO_PACER(3)
151#define PCIDAS_AO_CHAN_EN(c) BIT(5 + ((c) & 0x1))
152#define PCIDAS_AO_CHAN_MASK (PCIDAS_AO_CHAN_EN(0) | PCIDAS_AO_CHAN_EN(1))
153#define PCIDAS_AO_UPDATE_BOTH BIT(7)
154#define PCIDAS_AO_RANGE(c, r) (((r) & 0x3) << (8 + 2 * ((c) & 0x1)))
155#define PCIDAS_AO_RANGE_MASK(c) PCIDAS_AO_RANGE((c), 0x3)
156
157
158
159
160#define PCIDAS_AI_DATA_REG 0x00
161#define PCIDAS_AI_FIFO_CLR_REG 0x02
162
163
164
165
166#define PCIDAS_AI_8254_BASE 0x00
167#define PCIDAS_8255_BASE 0x04
168#define PCIDAS_AO_8254_BASE 0x08
169
170
171
172
173#define PCIDAS_AO_DATA_REG(x) (0x00 + ((x) * 2))
174#define PCIDAS_AO_FIFO_REG 0x00
175#define PCIDAS_AO_FIFO_CLR_REG 0x02
176
177
178static const struct comedi_lrange cb_pcidas_ranges = {
179 8, {
180 BIP_RANGE(10),
181 BIP_RANGE(5),
182 BIP_RANGE(2.5),
183 BIP_RANGE(1.25),
184 UNI_RANGE(10),
185 UNI_RANGE(5),
186 UNI_RANGE(2.5),
187 UNI_RANGE(1.25)
188 }
189};
190
191
192static const struct comedi_lrange cb_pcidas_alt_ranges = {
193 8, {
194 BIP_RANGE(10),
195 BIP_RANGE(1),
196 BIP_RANGE(0.1),
197 BIP_RANGE(0.01),
198 UNI_RANGE(10),
199 UNI_RANGE(1),
200 UNI_RANGE(0.1),
201 UNI_RANGE(0.01)
202 }
203};
204
205
206static const struct comedi_lrange cb_pcidas_ao_ranges = {
207 4, {
208 BIP_RANGE(5),
209 BIP_RANGE(10),
210 UNI_RANGE(5),
211 UNI_RANGE(10)
212 }
213};
214
215enum cb_pcidas_boardid {
216 BOARD_PCIDAS1602_16,
217 BOARD_PCIDAS1200,
218 BOARD_PCIDAS1602_12,
219 BOARD_PCIDAS1200_JR,
220 BOARD_PCIDAS1602_16_JR,
221 BOARD_PCIDAS1000,
222 BOARD_PCIDAS1001,
223 BOARD_PCIDAS1002,
224};
225
226struct cb_pcidas_board {
227 const char *name;
228 int ai_speed;
229 int ao_scan_speed;
230 int fifo_size;
231 unsigned int is_16bit;
232 unsigned int use_alt_range:1;
233 unsigned int has_ao:1;
234 unsigned int has_ao_fifo:1;
235 unsigned int has_ad8402:1;
236 unsigned int has_dac08:1;
237 unsigned int is_1602:1;
238};
239
240static const struct cb_pcidas_board cb_pcidas_boards[] = {
241 [BOARD_PCIDAS1602_16] = {
242 .name = "pci-das1602/16",
243 .ai_speed = 5000,
244 .ao_scan_speed = 10000,
245 .fifo_size = 512,
246 .is_16bit = 1,
247 .has_ao = 1,
248 .has_ao_fifo = 1,
249 .has_ad8402 = 1,
250 .has_dac08 = 1,
251 .is_1602 = 1,
252 },
253 [BOARD_PCIDAS1200] = {
254 .name = "pci-das1200",
255 .ai_speed = 3200,
256 .fifo_size = 1024,
257 .has_ao = 1,
258 },
259 [BOARD_PCIDAS1602_12] = {
260 .name = "pci-das1602/12",
261 .ai_speed = 3200,
262 .ao_scan_speed = 4000,
263 .fifo_size = 1024,
264 .has_ao = 1,
265 .has_ao_fifo = 1,
266 .is_1602 = 1,
267 },
268 [BOARD_PCIDAS1200_JR] = {
269 .name = "pci-das1200/jr",
270 .ai_speed = 3200,
271 .fifo_size = 1024,
272 },
273 [BOARD_PCIDAS1602_16_JR] = {
274 .name = "pci-das1602/16/jr",
275 .ai_speed = 5000,
276 .fifo_size = 512,
277 .is_16bit = 1,
278 .has_ad8402 = 1,
279 .has_dac08 = 1,
280 .is_1602 = 1,
281 },
282 [BOARD_PCIDAS1000] = {
283 .name = "pci-das1000",
284 .ai_speed = 4000,
285 .fifo_size = 1024,
286 },
287 [BOARD_PCIDAS1001] = {
288 .name = "pci-das1001",
289 .ai_speed = 6800,
290 .fifo_size = 1024,
291 .use_alt_range = 1,
292 .has_ao = 1,
293 },
294 [BOARD_PCIDAS1002] = {
295 .name = "pci-das1002",
296 .ai_speed = 6800,
297 .fifo_size = 1024,
298 .has_ao = 1,
299 },
300};
301
302struct cb_pcidas_private {
303 struct comedi_8254 *ao_pacer;
304
305 unsigned long amcc;
306 unsigned long pcibar1;
307 unsigned long pcibar2;
308 unsigned long pcibar4;
309
310 unsigned int ctrl;
311 unsigned int amcc_intcsr;
312 unsigned int ao_ctrl;
313
314 unsigned short ai_buffer[AI_BUFFER_SIZE];
315 unsigned short ao_buffer[AO_BUFFER_SIZE];
316 unsigned int calib_src;
317};
318
319static int cb_pcidas_ai_eoc(struct comedi_device *dev,
320 struct comedi_subdevice *s,
321 struct comedi_insn *insn,
322 unsigned long context)
323{
324 struct cb_pcidas_private *devpriv = dev->private;
325 unsigned int status;
326
327 status = inw(devpriv->pcibar1 + PCIDAS_AI_REG);
328 if (status & PCIDAS_AI_EOC)
329 return 0;
330 return -EBUSY;
331}
332
333static int cb_pcidas_ai_insn_read(struct comedi_device *dev,
334 struct comedi_subdevice *s,
335 struct comedi_insn *insn,
336 unsigned int *data)
337{
338 struct cb_pcidas_private *devpriv = dev->private;
339 unsigned int chan = CR_CHAN(insn->chanspec);
340 unsigned int range = CR_RANGE(insn->chanspec);
341 unsigned int aref = CR_AREF(insn->chanspec);
342 unsigned int bits;
343 int ret;
344 int n;
345
346
347 if (insn->chanspec & CR_ALT_SOURCE) {
348 outw(PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src),
349 devpriv->pcibar1 + PCIDAS_CALIB_REG);
350 chan = 0;
351 } else {
352 outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG);
353 }
354
355
356 bits = PCIDAS_AI_CHAN(chan) | PCIDAS_AI_GAIN(range);
357
358 if (comedi_range_is_unipolar(s, range))
359 bits |= PCIDAS_AI_UNIP;
360
361 if (aref != AREF_DIFF)
362 bits |= PCIDAS_AI_SE;
363 outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG);
364
365
366 outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG);
367
368
369 for (n = 0; n < insn->n; n++) {
370
371 outw(0, devpriv->pcibar2 + PCIDAS_AI_DATA_REG);
372
373
374 ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0);
375 if (ret)
376 return ret;
377
378
379 data[n] = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG);
380 }
381
382
383 return n;
384}
385
386static int cb_pcidas_ai_insn_config(struct comedi_device *dev,
387 struct comedi_subdevice *s,
388 struct comedi_insn *insn,
389 unsigned int *data)
390{
391 struct cb_pcidas_private *devpriv = dev->private;
392 int id = data[0];
393 unsigned int source = data[1];
394
395 switch (id) {
396 case INSN_CONFIG_ALT_SOURCE:
397 if (source >= 8) {
398 dev_err(dev->class_dev,
399 "invalid calibration source: %i\n",
400 source);
401 return -EINVAL;
402 }
403 devpriv->calib_src = source;
404 break;
405 default:
406 return -EINVAL;
407 }
408 return insn->n;
409}
410
411
412static int cb_pcidas_ao_nofifo_insn_write(struct comedi_device *dev,
413 struct comedi_subdevice *s,
414 struct comedi_insn *insn,
415 unsigned int *data)
416{
417 struct cb_pcidas_private *devpriv = dev->private;
418 unsigned int chan = CR_CHAN(insn->chanspec);
419 unsigned int range = CR_RANGE(insn->chanspec);
420 unsigned int val = s->readback[chan];
421 unsigned long flags;
422 int i;
423
424
425 spin_lock_irqsave(&dev->spinlock, flags);
426 devpriv->ao_ctrl &= ~(PCIDAS_AO_UPDATE_BOTH |
427 PCIDAS_AO_RANGE_MASK(chan));
428 devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range);
429 outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG);
430 spin_unlock_irqrestore(&dev->spinlock, flags);
431
432 for (i = 0; i < insn->n; i++) {
433 val = data[i];
434 outw(val, devpriv->pcibar4 + PCIDAS_AO_DATA_REG(chan));
435 }
436
437 s->readback[chan] = val;
438
439 return insn->n;
440}
441
442
443static int cb_pcidas_ao_fifo_insn_write(struct comedi_device *dev,
444 struct comedi_subdevice *s,
445 struct comedi_insn *insn,
446 unsigned int *data)
447{
448 struct cb_pcidas_private *devpriv = dev->private;
449 unsigned int chan = CR_CHAN(insn->chanspec);
450 unsigned int range = CR_RANGE(insn->chanspec);
451 unsigned int val = s->readback[chan];
452 unsigned long flags;
453 int i;
454
455
456 outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG);
457
458
459 spin_lock_irqsave(&dev->spinlock, flags);
460 devpriv->ao_ctrl &= ~(PCIDAS_AO_CHAN_MASK | PCIDAS_AO_RANGE_MASK(chan) |
461 PCIDAS_AO_PACER_MASK);
462 devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range) |
463 PCIDAS_AO_CHAN_EN(chan) | PCIDAS_AO_START;
464 outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG);
465 spin_unlock_irqrestore(&dev->spinlock, flags);
466
467 for (i = 0; i < insn->n; i++) {
468 val = data[i];
469 outw(val, devpriv->pcibar4 + PCIDAS_AO_FIFO_REG);
470 }
471
472 s->readback[chan] = val;
473
474 return insn->n;
475}
476
477static int cb_pcidas_eeprom_ready(struct comedi_device *dev,
478 struct comedi_subdevice *s,
479 struct comedi_insn *insn,
480 unsigned long context)
481{
482 struct cb_pcidas_private *devpriv = dev->private;
483 unsigned int status;
484
485 status = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD);
486 if ((status & MCSR_NV_BUSY) == 0)
487 return 0;
488 return -EBUSY;
489}
490
491static int cb_pcidas_eeprom_insn_read(struct comedi_device *dev,
492 struct comedi_subdevice *s,
493 struct comedi_insn *insn,
494 unsigned int *data)
495{
496 struct cb_pcidas_private *devpriv = dev->private;
497 unsigned int chan = CR_CHAN(insn->chanspec);
498 int ret;
499 int i;
500
501 for (i = 0; i < insn->n; i++) {
502
503 ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0);
504 if (ret)
505 return ret;
506
507
508 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
509 devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD);
510 outb(chan & 0xff, devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA);
511 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
512 devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD);
513 outb((chan >> 8) & 0xff,
514 devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA);
515 outb(MCSR_NV_ENABLE | MCSR_NV_READ,
516 devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD);
517
518
519 ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0);
520 if (ret)
521 return ret;
522
523 data[i] = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA);
524 }
525
526 return insn->n;
527}
528
529static void cb_pcidas_calib_write(struct comedi_device *dev,
530 unsigned int val, unsigned int len,
531 bool trimpot)
532{
533 struct cb_pcidas_private *devpriv = dev->private;
534 unsigned int calib_bits;
535 unsigned int bit;
536
537 calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src);
538 if (trimpot) {
539
540 calib_bits |= PCIDAS_CALIB_TRIM_SEL;
541 outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG);
542 }
543
544
545 for (bit = 1 << (len - 1); bit; bit >>= 1) {
546 if (val & bit)
547 calib_bits |= PCIDAS_CALIB_DATA;
548 else
549 calib_bits &= ~PCIDAS_CALIB_DATA;
550 udelay(1);
551 outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG);
552 }
553 udelay(1);
554
555 calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src);
556
557 if (!trimpot) {
558
559 outw(calib_bits | PCIDAS_CALIB_8800_SEL,
560 devpriv->pcibar1 + PCIDAS_CALIB_REG);
561 udelay(1);
562 }
563
564
565 outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG);
566}
567
568static int cb_pcidas_caldac_insn_write(struct comedi_device *dev,
569 struct comedi_subdevice *s,
570 struct comedi_insn *insn,
571 unsigned int *data)
572{
573 unsigned int chan = CR_CHAN(insn->chanspec);
574
575 if (insn->n) {
576 unsigned int val = data[insn->n - 1];
577
578 if (s->readback[chan] != val) {
579
580 cb_pcidas_calib_write(dev, (chan << 8) | val, 11,
581 false);
582 s->readback[chan] = val;
583 }
584 }
585
586 return insn->n;
587}
588
589static void cb_pcidas_dac08_write(struct comedi_device *dev, unsigned int val)
590{
591 struct cb_pcidas_private *devpriv = dev->private;
592
593 val |= PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src);
594
595
596 outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG);
597 udelay(1);
598 outw(val | PCIDAS_CALIB_DAC08_SEL,
599 devpriv->pcibar1 + PCIDAS_CALIB_REG);
600 udelay(1);
601 outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG);
602 udelay(1);
603}
604
605static int cb_pcidas_dac08_insn_write(struct comedi_device *dev,
606 struct comedi_subdevice *s,
607 struct comedi_insn *insn,
608 unsigned int *data)
609{
610 unsigned int chan = CR_CHAN(insn->chanspec);
611
612 if (insn->n) {
613 unsigned int val = data[insn->n - 1];
614
615 if (s->readback[chan] != val) {
616 cb_pcidas_dac08_write(dev, val);
617 s->readback[chan] = val;
618 }
619 }
620
621 return insn->n;
622}
623
624static void cb_pcidas_trimpot_write(struct comedi_device *dev,
625 unsigned int chan, unsigned int val)
626{
627 const struct cb_pcidas_board *board = dev->board_ptr;
628
629 if (board->has_ad8402) {
630
631 cb_pcidas_calib_write(dev, (chan << 8) | val, 10, true);
632 } else {
633
634 cb_pcidas_calib_write(dev, val, 7, true);
635 }
636}
637
638static int cb_pcidas_trimpot_insn_write(struct comedi_device *dev,
639 struct comedi_subdevice *s,
640 struct comedi_insn *insn,
641 unsigned int *data)
642{
643 unsigned int chan = CR_CHAN(insn->chanspec);
644
645 if (insn->n) {
646 unsigned int val = data[insn->n - 1];
647
648 if (s->readback[chan] != val) {
649 cb_pcidas_trimpot_write(dev, chan, val);
650 s->readback[chan] = val;
651 }
652 }
653
654 return insn->n;
655}
656
657static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev,
658 struct comedi_subdevice *s,
659 struct comedi_cmd *cmd)
660{
661 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
662 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
663 int i;
664
665 for (i = 1; i < cmd->chanlist_len; i++) {
666 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
667 unsigned int range = CR_RANGE(cmd->chanlist[i]);
668
669 if (chan != (chan0 + i) % s->n_chan) {
670 dev_dbg(dev->class_dev,
671 "entries in chanlist must be consecutive channels, counting upwards\n");
672 return -EINVAL;
673 }
674
675 if (range != range0) {
676 dev_dbg(dev->class_dev,
677 "entries in chanlist must all have the same gain\n");
678 return -EINVAL;
679 }
680 }
681 return 0;
682}
683
684static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
685 struct comedi_subdevice *s,
686 struct comedi_cmd *cmd)
687{
688 const struct cb_pcidas_board *board = dev->board_ptr;
689 int err = 0;
690 unsigned int arg;
691
692
693
694 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
695 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
696 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
697 err |= comedi_check_trigger_src(&cmd->convert_src,
698 TRIG_TIMER | TRIG_NOW | TRIG_EXT);
699 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
700 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
701
702 if (err)
703 return 1;
704
705
706
707 err |= comedi_check_trigger_is_unique(cmd->start_src);
708 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
709 err |= comedi_check_trigger_is_unique(cmd->convert_src);
710 err |= comedi_check_trigger_is_unique(cmd->stop_src);
711
712
713
714 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
715 err |= -EINVAL;
716 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
717 err |= -EINVAL;
718 if (cmd->start_src == TRIG_EXT &&
719 (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
720 err |= -EINVAL;
721
722 if (err)
723 return 2;
724
725
726
727 switch (cmd->start_src) {
728 case TRIG_NOW:
729 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
730 break;
731 case TRIG_EXT:
732
733 if ((cmd->start_arg
734 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
735 cmd->start_arg &= ~(CR_FLAGS_MASK &
736 ~(CR_EDGE | CR_INVERT));
737 err |= -EINVAL;
738 }
739 if (!board->is_1602 && (cmd->start_arg & CR_INVERT)) {
740 cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
741 err |= -EINVAL;
742 }
743 break;
744 }
745
746 if (cmd->scan_begin_src == TRIG_TIMER) {
747 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
748 board->ai_speed *
749 cmd->chanlist_len);
750 }
751
752 if (cmd->convert_src == TRIG_TIMER) {
753 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
754 board->ai_speed);
755 }
756
757 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
758 cmd->chanlist_len);
759
760 if (cmd->stop_src == TRIG_COUNT)
761 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
762 else
763 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
764
765 if (err)
766 return 3;
767
768
769
770 if (cmd->scan_begin_src == TRIG_TIMER) {
771 arg = cmd->scan_begin_arg;
772 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
773 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
774 }
775 if (cmd->convert_src == TRIG_TIMER) {
776 arg = cmd->convert_arg;
777 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
778 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
779 }
780
781 if (err)
782 return 4;
783
784
785 if (cmd->chanlist && cmd->chanlist_len > 0)
786 err |= cb_pcidas_ai_check_chanlist(dev, s, cmd);
787
788 if (err)
789 return 5;
790
791 return 0;
792}
793
794static int cb_pcidas_ai_cmd(struct comedi_device *dev,
795 struct comedi_subdevice *s)
796{
797 const struct cb_pcidas_board *board = dev->board_ptr;
798 struct cb_pcidas_private *devpriv = dev->private;
799 struct comedi_async *async = s->async;
800 struct comedi_cmd *cmd = &async->cmd;
801 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
802 unsigned int bits;
803 unsigned long flags;
804
805
806 outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG);
807
808 outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG);
809
810 outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG);
811
812
813 bits = PCIDAS_AI_FIRST(CR_CHAN(cmd->chanlist[0])) |
814 PCIDAS_AI_LAST(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
815 PCIDAS_AI_GAIN(range0);
816
817 if (comedi_range_is_unipolar(s, range0))
818 bits |= PCIDAS_AI_UNIP;
819
820 if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
821 bits |= PCIDAS_AI_SE;
822
823 if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
824 bits |= PCIDAS_AI_PACER_EXTP;
825 else
826 bits |= PCIDAS_AI_PACER_INT;
827 outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG);
828
829
830 if (cmd->scan_begin_src == TRIG_TIMER ||
831 cmd->convert_src == TRIG_TIMER) {
832 comedi_8254_update_divisors(dev->pacer);
833 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
834 }
835
836
837 spin_lock_irqsave(&dev->spinlock, flags);
838 devpriv->ctrl |= PCIDAS_CTRL_INTE;
839 devpriv->ctrl &= ~PCIDAS_CTRL_INT_MASK;
840 if (cmd->flags & CMDF_WAKE_EOS) {
841 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
842
843 devpriv->ctrl |= PCIDAS_CTRL_INT_EOS;
844 } else {
845
846 devpriv->ctrl |= PCIDAS_CTRL_INT_FNE;
847 }
848 } else {
849
850 devpriv->ctrl |= PCIDAS_CTRL_INT_FHF;
851 }
852
853
854 outw(devpriv->ctrl |
855 PCIDAS_CTRL_EOAI | PCIDAS_CTRL_INT_CLR | PCIDAS_CTRL_LADFUL,
856 devpriv->pcibar1 + PCIDAS_CTRL_REG);
857 spin_unlock_irqrestore(&dev->spinlock, flags);
858
859
860 bits = 0;
861 if (cmd->start_src == TRIG_NOW) {
862 bits |= PCIDAS_TRIG_SEL_SW;
863 } else {
864 bits |= PCIDAS_TRIG_SEL_EXT | PCIDAS_TRIG_EN | PCIDAS_TRIG_CLR;
865 if (board->is_1602) {
866 if (cmd->start_arg & CR_INVERT)
867 bits |= PCIDAS_TRIG_POL;
868 if (cmd->start_arg & CR_EDGE)
869 bits |= PCIDAS_TRIG_MODE;
870 }
871 }
872 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
873 bits |= PCIDAS_TRIG_BURSTE;
874 outw(bits, devpriv->pcibar1 + PCIDAS_TRIG_REG);
875
876 return 0;
877}
878
879static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev,
880 struct comedi_subdevice *s,
881 struct comedi_cmd *cmd)
882{
883 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
884
885 if (cmd->chanlist_len > 1) {
886 unsigned int chan1 = CR_CHAN(cmd->chanlist[1]);
887
888 if (chan0 != 0 || chan1 != 1) {
889 dev_dbg(dev->class_dev,
890 "channels must be ordered channel 0, channel 1 in chanlist\n");
891 return -EINVAL;
892 }
893 }
894
895 return 0;
896}
897
898static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
899 struct comedi_subdevice *s,
900 struct comedi_cmd *cmd)
901{
902 const struct cb_pcidas_board *board = dev->board_ptr;
903 struct cb_pcidas_private *devpriv = dev->private;
904 int err = 0;
905
906
907
908 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
909 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
910 TRIG_TIMER | TRIG_EXT);
911 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
912 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
913 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
914
915 if (err)
916 return 1;
917
918
919
920 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
921 err |= comedi_check_trigger_is_unique(cmd->stop_src);
922
923
924
925 if (err)
926 return 2;
927
928
929
930 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
931
932 if (cmd->scan_begin_src == TRIG_TIMER) {
933 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
934 board->ao_scan_speed);
935 }
936
937 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
938 cmd->chanlist_len);
939
940 if (cmd->stop_src == TRIG_COUNT)
941 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
942 else
943 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
944
945 if (err)
946 return 3;
947
948
949
950 if (cmd->scan_begin_src == TRIG_TIMER) {
951 unsigned int arg = cmd->scan_begin_arg;
952
953 comedi_8254_cascade_ns_to_timer(devpriv->ao_pacer,
954 &arg, cmd->flags);
955 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
956 }
957
958 if (err)
959 return 4;
960
961
962 if (cmd->chanlist && cmd->chanlist_len > 0)
963 err |= cb_pcidas_ao_check_chanlist(dev, s, cmd);
964
965 if (err)
966 return 5;
967
968 return 0;
969}
970
971static int cb_pcidas_ai_cancel(struct comedi_device *dev,
972 struct comedi_subdevice *s)
973{
974 struct cb_pcidas_private *devpriv = dev->private;
975 unsigned long flags;
976
977 spin_lock_irqsave(&dev->spinlock, flags);
978
979 devpriv->ctrl &= ~(PCIDAS_CTRL_INTE | PCIDAS_CTRL_EOAIE);
980 outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG);
981 spin_unlock_irqrestore(&dev->spinlock, flags);
982
983
984 outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG);
985 outw(PCIDAS_AI_PACER_SW, devpriv->pcibar1 + PCIDAS_AI_REG);
986
987 return 0;
988}
989
990static void cb_pcidas_ao_load_fifo(struct comedi_device *dev,
991 struct comedi_subdevice *s,
992 unsigned int nsamples)
993{
994 struct cb_pcidas_private *devpriv = dev->private;
995 unsigned int nbytes;
996
997 nsamples = comedi_nsamples_left(s, nsamples);
998 nbytes = comedi_buf_read_samples(s, devpriv->ao_buffer, nsamples);
999
1000 nsamples = comedi_bytes_to_samples(s, nbytes);
1001 outsw(devpriv->pcibar4 + PCIDAS_AO_FIFO_REG,
1002 devpriv->ao_buffer, nsamples);
1003}
1004
1005static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1006 struct comedi_subdevice *s,
1007 unsigned int trig_num)
1008{
1009 const struct cb_pcidas_board *board = dev->board_ptr;
1010 struct cb_pcidas_private *devpriv = dev->private;
1011 struct comedi_async *async = s->async;
1012 struct comedi_cmd *cmd = &async->cmd;
1013 unsigned long flags;
1014
1015 if (trig_num != cmd->start_arg)
1016 return -EINVAL;
1017
1018 cb_pcidas_ao_load_fifo(dev, s, board->fifo_size);
1019
1020
1021 spin_lock_irqsave(&dev->spinlock, flags);
1022 devpriv->ctrl |= PCIDAS_CTRL_DAEMIE | PCIDAS_CTRL_DAHFIE;
1023
1024
1025 outw(devpriv->ctrl | PCIDAS_CTRL_DAEMI | PCIDAS_CTRL_DAHFI,
1026 devpriv->pcibar1 + PCIDAS_CTRL_REG);
1027
1028
1029 devpriv->ao_ctrl |= PCIDAS_AO_START | PCIDAS_AO_DACEN | PCIDAS_AO_EMPTY;
1030 outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG);
1031
1032 spin_unlock_irqrestore(&dev->spinlock, flags);
1033
1034 async->inttrig = NULL;
1035
1036 return 0;
1037}
1038
1039static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1040 struct comedi_subdevice *s)
1041{
1042 struct cb_pcidas_private *devpriv = dev->private;
1043 struct comedi_async *async = s->async;
1044 struct comedi_cmd *cmd = &async->cmd;
1045 unsigned int i;
1046 unsigned long flags;
1047
1048
1049 spin_lock_irqsave(&dev->spinlock, flags);
1050 for (i = 0; i < cmd->chanlist_len; i++) {
1051 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
1052 unsigned int range = CR_RANGE(cmd->chanlist[i]);
1053
1054
1055 devpriv->ao_ctrl |= PCIDAS_AO_CHAN_EN(chan);
1056
1057 devpriv->ao_ctrl |= PCIDAS_AO_RANGE(chan, range);
1058 }
1059
1060
1061 outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG);
1062 spin_unlock_irqrestore(&dev->spinlock, flags);
1063
1064
1065 outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG);
1066
1067
1068 if (cmd->scan_begin_src == TRIG_TIMER) {
1069 comedi_8254_update_divisors(devpriv->ao_pacer);
1070 comedi_8254_pacer_enable(devpriv->ao_pacer, 1, 2, true);
1071 }
1072
1073
1074 spin_lock_irqsave(&dev->spinlock, flags);
1075 switch (cmd->scan_begin_src) {
1076 case TRIG_TIMER:
1077 devpriv->ao_ctrl |= PCIDAS_AO_PACER_INT;
1078 break;
1079 case TRIG_EXT:
1080 devpriv->ao_ctrl |= PCIDAS_AO_PACER_EXTP;
1081 break;
1082 default:
1083 spin_unlock_irqrestore(&dev->spinlock, flags);
1084 dev_err(dev->class_dev, "error setting dac pacer source\n");
1085 return -1;
1086 }
1087 spin_unlock_irqrestore(&dev->spinlock, flags);
1088
1089 async->inttrig = cb_pcidas_ao_inttrig;
1090
1091 return 0;
1092}
1093
1094static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1095 struct comedi_subdevice *s)
1096{
1097 struct cb_pcidas_private *devpriv = dev->private;
1098 unsigned long flags;
1099
1100 spin_lock_irqsave(&dev->spinlock, flags);
1101
1102 devpriv->ctrl &= ~(PCIDAS_CTRL_DAHFIE | PCIDAS_CTRL_DAEMIE);
1103 outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG);
1104
1105
1106 devpriv->ao_ctrl &= ~(PCIDAS_AO_DACEN | PCIDAS_AO_PACER_MASK);
1107 outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG);
1108 spin_unlock_irqrestore(&dev->spinlock, flags);
1109
1110 return 0;
1111}
1112
1113static unsigned int cb_pcidas_ao_interrupt(struct comedi_device *dev,
1114 unsigned int status)
1115{
1116 const struct cb_pcidas_board *board = dev->board_ptr;
1117 struct cb_pcidas_private *devpriv = dev->private;
1118 struct comedi_subdevice *s = dev->write_subdev;
1119 struct comedi_async *async = s->async;
1120 struct comedi_cmd *cmd = &async->cmd;
1121 unsigned int irq_clr = 0;
1122
1123 if (status & PCIDAS_CTRL_DAEMI) {
1124 irq_clr |= PCIDAS_CTRL_DAEMI;
1125
1126 if (inw(devpriv->pcibar4 + PCIDAS_AO_REG) & PCIDAS_AO_EMPTY) {
1127 if (cmd->stop_src == TRIG_COUNT &&
1128 async->scans_done >= cmd->stop_arg) {
1129 async->events |= COMEDI_CB_EOA;
1130 } else {
1131 dev_err(dev->class_dev, "dac fifo underflow\n");
1132 async->events |= COMEDI_CB_ERROR;
1133 }
1134 }
1135 } else if (status & PCIDAS_CTRL_DAHFI) {
1136 irq_clr |= PCIDAS_CTRL_DAHFI;
1137
1138 cb_pcidas_ao_load_fifo(dev, s, board->fifo_size / 2);
1139 }
1140
1141 comedi_handle_events(dev, s);
1142
1143 return irq_clr;
1144}
1145
1146static unsigned int cb_pcidas_ai_interrupt(struct comedi_device *dev,
1147 unsigned int status)
1148{
1149 const struct cb_pcidas_board *board = dev->board_ptr;
1150 struct cb_pcidas_private *devpriv = dev->private;
1151 struct comedi_subdevice *s = dev->read_subdev;
1152 struct comedi_async *async = s->async;
1153 struct comedi_cmd *cmd = &async->cmd;
1154 unsigned int irq_clr = 0;
1155
1156 if (status & PCIDAS_CTRL_ADHFI) {
1157 unsigned int num_samples;
1158
1159 irq_clr |= PCIDAS_CTRL_INT_CLR;
1160
1161
1162 num_samples = comedi_nsamples_left(s, board->fifo_size / 2);
1163 insw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG,
1164 devpriv->ai_buffer, num_samples);
1165 comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
1166
1167 if (cmd->stop_src == TRIG_COUNT &&
1168 async->scans_done >= cmd->stop_arg)
1169 async->events |= COMEDI_CB_EOA;
1170 } else if (status & (PCIDAS_CTRL_ADNEI | PCIDAS_CTRL_EOBI)) {
1171 unsigned int i;
1172
1173 irq_clr |= PCIDAS_CTRL_INT_CLR;
1174
1175
1176 for (i = 0; i < 10000; i++) {
1177 unsigned short val;
1178
1179
1180 if ((inw(devpriv->pcibar1 + PCIDAS_CTRL_REG) &
1181 PCIDAS_CTRL_ADNE) == 0)
1182 break;
1183 val = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG);
1184 comedi_buf_write_samples(s, &val, 1);
1185
1186 if (cmd->stop_src == TRIG_COUNT &&
1187 async->scans_done >= cmd->stop_arg) {
1188 async->events |= COMEDI_CB_EOA;
1189 break;
1190 }
1191 }
1192 } else if (status & PCIDAS_CTRL_EOAI) {
1193 irq_clr |= PCIDAS_CTRL_EOAI;
1194
1195 dev_err(dev->class_dev,
1196 "bug! encountered end of acquisition interrupt?\n");
1197 }
1198
1199
1200 if (status & PCIDAS_CTRL_LADFUL) {
1201 irq_clr |= PCIDAS_CTRL_LADFUL;
1202
1203 dev_err(dev->class_dev, "fifo overflow\n");
1204 async->events |= COMEDI_CB_ERROR;
1205 }
1206
1207 comedi_handle_events(dev, s);
1208
1209 return irq_clr;
1210}
1211
1212static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
1213{
1214 struct comedi_device *dev = d;
1215 struct cb_pcidas_private *devpriv = dev->private;
1216 unsigned int irq_clr = 0;
1217 unsigned int amcc_status;
1218 unsigned int status;
1219
1220 if (!dev->attached)
1221 return IRQ_NONE;
1222
1223 amcc_status = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
1224
1225 if ((INTCSR_INTR_ASSERTED & amcc_status) == 0)
1226 return IRQ_NONE;
1227
1228
1229 inl_p(devpriv->amcc + AMCC_OP_REG_IMB4);
1230
1231 outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS,
1232 devpriv->amcc + AMCC_OP_REG_INTCSR);
1233
1234 status = inw(devpriv->pcibar1 + PCIDAS_CTRL_REG);
1235
1236
1237 if (status & PCIDAS_CTRL_AO_INT)
1238 irq_clr |= cb_pcidas_ao_interrupt(dev, status);
1239
1240
1241 if (status & PCIDAS_CTRL_AI_INT)
1242 irq_clr |= cb_pcidas_ai_interrupt(dev, status);
1243
1244 if (irq_clr) {
1245 unsigned long flags;
1246
1247 spin_lock_irqsave(&dev->spinlock, flags);
1248 outw(devpriv->ctrl | irq_clr,
1249 devpriv->pcibar1 + PCIDAS_CTRL_REG);
1250 spin_unlock_irqrestore(&dev->spinlock, flags);
1251 }
1252
1253 return IRQ_HANDLED;
1254}
1255
1256static int cb_pcidas_auto_attach(struct comedi_device *dev,
1257 unsigned long context)
1258{
1259 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1260 const struct cb_pcidas_board *board = NULL;
1261 struct cb_pcidas_private *devpriv;
1262 struct comedi_subdevice *s;
1263 int i;
1264 int ret;
1265
1266 if (context < ARRAY_SIZE(cb_pcidas_boards))
1267 board = &cb_pcidas_boards[context];
1268 if (!board)
1269 return -ENODEV;
1270 dev->board_ptr = board;
1271 dev->board_name = board->name;
1272
1273 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1274 if (!devpriv)
1275 return -ENOMEM;
1276
1277 ret = comedi_pci_enable(dev);
1278 if (ret)
1279 return ret;
1280
1281 devpriv->amcc = pci_resource_start(pcidev, 0);
1282 devpriv->pcibar1 = pci_resource_start(pcidev, 1);
1283 devpriv->pcibar2 = pci_resource_start(pcidev, 2);
1284 dev->iobase = pci_resource_start(pcidev, 3);
1285 if (board->has_ao)
1286 devpriv->pcibar4 = pci_resource_start(pcidev, 4);
1287
1288
1289 outl(INTCSR_INBOX_INTR_STATUS,
1290 devpriv->amcc + AMCC_OP_REG_INTCSR);
1291
1292 ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED,
1293 dev->board_name, dev);
1294 if (ret) {
1295 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
1296 pcidev->irq);
1297 return ret;
1298 }
1299 dev->irq = pcidev->irq;
1300
1301 dev->pacer = comedi_8254_init(dev->iobase + PCIDAS_AI_8254_BASE,
1302 I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
1303 if (!dev->pacer)
1304 return -ENOMEM;
1305
1306 devpriv->ao_pacer = comedi_8254_init(dev->iobase + PCIDAS_AO_8254_BASE,
1307 I8254_OSC_BASE_10MHZ,
1308 I8254_IO8, 0);
1309 if (!devpriv->ao_pacer)
1310 return -ENOMEM;
1311
1312 ret = comedi_alloc_subdevices(dev, 7);
1313 if (ret)
1314 return ret;
1315
1316
1317 s = &dev->subdevices[0];
1318 s->type = COMEDI_SUBD_AI;
1319 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1320 s->n_chan = 16;
1321 s->maxdata = board->is_16bit ? 0xffff : 0x0fff;
1322 s->range_table = board->use_alt_range ? &cb_pcidas_alt_ranges
1323 : &cb_pcidas_ranges;
1324 s->insn_read = cb_pcidas_ai_insn_read;
1325 s->insn_config = cb_pcidas_ai_insn_config;
1326 if (dev->irq) {
1327 dev->read_subdev = s;
1328 s->subdev_flags |= SDF_CMD_READ;
1329 s->len_chanlist = s->n_chan;
1330 s->do_cmd = cb_pcidas_ai_cmd;
1331 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1332 s->cancel = cb_pcidas_ai_cancel;
1333 }
1334
1335
1336 s = &dev->subdevices[1];
1337 if (board->has_ao) {
1338 s->type = COMEDI_SUBD_AO;
1339 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1340 s->n_chan = 2;
1341 s->maxdata = board->is_16bit ? 0xffff : 0x0fff;
1342 s->range_table = &cb_pcidas_ao_ranges;
1343 s->insn_write = (board->has_ao_fifo)
1344 ? cb_pcidas_ao_fifo_insn_write
1345 : cb_pcidas_ao_nofifo_insn_write;
1346
1347 ret = comedi_alloc_subdev_readback(s);
1348 if (ret)
1349 return ret;
1350
1351 if (dev->irq && board->has_ao_fifo) {
1352 dev->write_subdev = s;
1353 s->subdev_flags |= SDF_CMD_WRITE;
1354 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1355 s->do_cmd = cb_pcidas_ao_cmd;
1356 s->cancel = cb_pcidas_ao_cancel;
1357 }
1358 } else {
1359 s->type = COMEDI_SUBD_UNUSED;
1360 }
1361
1362
1363 s = &dev->subdevices[2];
1364 ret = subdev_8255_init(dev, s, NULL, PCIDAS_8255_BASE);
1365 if (ret)
1366 return ret;
1367
1368
1369 s = &dev->subdevices[3];
1370 s->type = COMEDI_SUBD_MEMORY;
1371 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1372 s->n_chan = 256;
1373 s->maxdata = 0xff;
1374 s->insn_read = cb_pcidas_eeprom_insn_read;
1375
1376
1377 s = &dev->subdevices[4];
1378 s->type = COMEDI_SUBD_CALIB;
1379 s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
1380 s->n_chan = 8;
1381 s->maxdata = 0xff;
1382 s->insn_write = cb_pcidas_caldac_insn_write;
1383
1384 ret = comedi_alloc_subdev_readback(s);
1385 if (ret)
1386 return ret;
1387
1388 for (i = 0; i < s->n_chan; i++) {
1389 unsigned int val = s->maxdata / 2;
1390
1391
1392 cb_pcidas_calib_write(dev, (i << 8) | val, 11, false);
1393 s->readback[i] = val;
1394 }
1395
1396
1397 s = &dev->subdevices[5];
1398 s->type = COMEDI_SUBD_CALIB;
1399 s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
1400 if (board->has_ad8402) {
1401
1402
1403
1404
1405
1406 s->n_chan = 2;
1407 s->maxdata = 0xff;
1408 } else {
1409
1410 s->n_chan = 1;
1411 s->maxdata = 0x7f;
1412 }
1413 s->insn_write = cb_pcidas_trimpot_insn_write;
1414
1415 ret = comedi_alloc_subdev_readback(s);
1416 if (ret)
1417 return ret;
1418
1419 for (i = 0; i < s->n_chan; i++) {
1420 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
1421 s->readback[i] = s->maxdata / 2;
1422 }
1423
1424
1425 s = &dev->subdevices[6];
1426 if (board->has_dac08) {
1427 s->type = COMEDI_SUBD_CALIB;
1428 s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
1429 s->n_chan = 1;
1430 s->maxdata = 0xff;
1431 s->insn_write = cb_pcidas_dac08_insn_write;
1432
1433 ret = comedi_alloc_subdev_readback(s);
1434 if (ret)
1435 return ret;
1436
1437 for (i = 0; i < s->n_chan; i++) {
1438 cb_pcidas_dac08_write(dev, s->maxdata / 2);
1439 s->readback[i] = s->maxdata / 2;
1440 }
1441 } else {
1442 s->type = COMEDI_SUBD_UNUSED;
1443 }
1444
1445
1446 inl(devpriv->amcc + AMCC_OP_REG_IMB4);
1447
1448 devpriv->amcc_intcsr = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1449 INTCSR_INBOX_FULL_INT;
1450
1451 outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS,
1452 devpriv->amcc + AMCC_OP_REG_INTCSR);
1453
1454 return 0;
1455}
1456
1457static void cb_pcidas_detach(struct comedi_device *dev)
1458{
1459 struct cb_pcidas_private *devpriv = dev->private;
1460
1461 if (devpriv) {
1462 if (devpriv->amcc)
1463 outl(INTCSR_INBOX_INTR_STATUS,
1464 devpriv->amcc + AMCC_OP_REG_INTCSR);
1465 kfree(devpriv->ao_pacer);
1466 }
1467 comedi_pci_detach(dev);
1468}
1469
1470static struct comedi_driver cb_pcidas_driver = {
1471 .driver_name = "cb_pcidas",
1472 .module = THIS_MODULE,
1473 .auto_attach = cb_pcidas_auto_attach,
1474 .detach = cb_pcidas_detach,
1475};
1476
1477static int cb_pcidas_pci_probe(struct pci_dev *dev,
1478 const struct pci_device_id *id)
1479{
1480 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1481 id->driver_data);
1482}
1483
1484static const struct pci_device_id cb_pcidas_pci_table[] = {
1485 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1486 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1487 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1488 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1489 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1490 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1491 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1492 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
1493 { 0 }
1494};
1495MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
1496
1497static struct pci_driver cb_pcidas_pci_driver = {
1498 .name = "cb_pcidas",
1499 .id_table = cb_pcidas_pci_table,
1500 .probe = cb_pcidas_pci_probe,
1501 .remove = comedi_pci_auto_unconfig,
1502};
1503module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
1504
1505MODULE_AUTHOR("Comedi http://www.comedi.org");
1506MODULE_DESCRIPTION("Comedi driver for MeasurementComputing PCI-DAS series");
1507MODULE_LICENSE("GPL");
1508