1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#include <linux/module.h>
76#include <linux/delay.h>
77#include <linux/gfp.h>
78#include <linux/interrupt.h>
79#include <linux/io.h>
80
81#include "../comedi_pci.h"
82
83#include "amcc_s5933.h"
84#include "comedi_8254.h"
85
86
87
88
89#define PCI9118_TIMER_BASE 0x00
90#define PCI9118_AI_FIFO_REG 0x10
91#define PCI9118_AO_REG(x) (0x10 + ((x) * 4))
92#define PCI9118_AI_STATUS_REG 0x18
93#define PCI9118_AI_STATUS_NFULL BIT(8)
94#define PCI9118_AI_STATUS_NHFULL BIT(7)
95#define PCI9118_AI_STATUS_NEPTY BIT(6)
96#define PCI9118_AI_STATUS_ACMP BIT(5)
97#define PCI9118_AI_STATUS_DTH BIT(4)
98#define PCI9118_AI_STATUS_BOVER BIT(3)
99#define PCI9118_AI_STATUS_ADOS BIT(2)
100#define PCI9118_AI_STATUS_ADOR BIT(1)
101#define PCI9118_AI_STATUS_ADRDY BIT(0)
102#define PCI9118_AI_CTRL_REG 0x18
103#define PCI9118_AI_CTRL_UNIP BIT(7)
104#define PCI9118_AI_CTRL_DIFF BIT(6)
105#define PCI9118_AI_CTRL_SOFTG BIT(5)
106#define PCI9118_AI_CTRL_EXTG BIT(4)
107#define PCI9118_AI_CTRL_EXTM BIT(3)
108#define PCI9118_AI_CTRL_TMRTR BIT(2)
109#define PCI9118_AI_CTRL_INT BIT(1)
110#define PCI9118_AI_CTRL_DMA BIT(0)
111#define PCI9118_DIO_REG 0x1c
112#define PCI9118_SOFTTRG_REG 0x20
113#define PCI9118_AI_CHANLIST_REG 0x24
114#define PCI9118_AI_CHANLIST_RANGE(x) (((x) & 0x3) << 8)
115#define PCI9118_AI_CHANLIST_CHAN(x) ((x) << 0)
116#define PCI9118_AI_BURST_NUM_REG 0x28
117#define PCI9118_AI_AUTOSCAN_MODE_REG 0x2c
118#define PCI9118_AI_CFG_REG 0x30
119#define PCI9118_AI_CFG_PDTRG BIT(7)
120#define PCI9118_AI_CFG_PETRG BIT(6)
121#define PCI9118_AI_CFG_BSSH BIT(5)
122#define PCI9118_AI_CFG_BM BIT(4)
123#define PCI9118_AI_CFG_BS BIT(3)
124#define PCI9118_AI_CFG_PM BIT(2)
125#define PCI9118_AI_CFG_AM BIT(1)
126#define PCI9118_AI_CFG_START BIT(0)
127#define PCI9118_FIFO_RESET_REG 0x34
128#define PCI9118_INT_CTRL_REG 0x38
129#define PCI9118_INT_CTRL_TIMER BIT(3)
130#define PCI9118_INT_CTRL_ABOUT BIT(2)
131#define PCI9118_INT_CTRL_HFULL BIT(1)
132#define PCI9118_INT_CTRL_DTRG BIT(0)
133
134#define START_AI_EXT 0x01
135#define STOP_AI_EXT 0x02
136#define STOP_AI_INT 0x08
137
138static const struct comedi_lrange pci9118_ai_range = {
139 8, {
140 BIP_RANGE(5),
141 BIP_RANGE(2.5),
142 BIP_RANGE(1.25),
143 BIP_RANGE(0.625),
144 UNI_RANGE(10),
145 UNI_RANGE(5),
146 UNI_RANGE(2.5),
147 UNI_RANGE(1.25)
148 }
149};
150
151static const struct comedi_lrange pci9118hg_ai_range = {
152 8, {
153 BIP_RANGE(5),
154 BIP_RANGE(0.5),
155 BIP_RANGE(0.05),
156 BIP_RANGE(0.005),
157 UNI_RANGE(10),
158 UNI_RANGE(1),
159 UNI_RANGE(0.1),
160 UNI_RANGE(0.01)
161 }
162};
163
164enum pci9118_boardid {
165 BOARD_PCI9118DG,
166 BOARD_PCI9118HG,
167 BOARD_PCI9118HR,
168};
169
170struct pci9118_boardinfo {
171 const char *name;
172 unsigned int ai_is_16bit:1;
173 unsigned int is_hg:1;
174};
175
176static const struct pci9118_boardinfo pci9118_boards[] = {
177 [BOARD_PCI9118DG] = {
178 .name = "pci9118dg",
179 },
180 [BOARD_PCI9118HG] = {
181 .name = "pci9118hg",
182 .is_hg = 1,
183 },
184 [BOARD_PCI9118HR] = {
185 .name = "pci9118hr",
186 .ai_is_16bit = 1,
187 },
188};
189
190struct pci9118_dmabuf {
191 unsigned short *virt;
192 dma_addr_t hw;
193 unsigned int size;
194 unsigned int use_size;
195};
196
197struct pci9118_private {
198 unsigned long iobase_a;
199 unsigned int master:1;
200 unsigned int dma_doublebuf:1;
201 unsigned int ai_neverending:1;
202 unsigned int usedma:1;
203 unsigned int usemux:1;
204 unsigned char ai_ctrl;
205 unsigned char int_ctrl;
206 unsigned char ai_cfg;
207 unsigned int ai_do;
208 unsigned int ai_n_realscanlen;
209
210
211
212 unsigned int ai_act_dmapos;
213 unsigned int ai_add_front;
214
215
216
217 unsigned int ai_add_back;
218
219
220
221 unsigned int ai_flags;
222 char ai12_startstop;
223
224
225
226 unsigned int dma_actbuf;
227 struct pci9118_dmabuf dmabuf[2];
228 int softsshdelay;
229
230
231
232 unsigned char softsshsample;
233
234
235
236 unsigned char softsshhold;
237
238
239
240 unsigned int ai_ns_min;
241};
242
243static void pci9118_amcc_setup_dma(struct comedi_device *dev, unsigned int buf)
244{
245 struct pci9118_private *devpriv = dev->private;
246 struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[buf];
247
248
249 outl(dmabuf->hw, devpriv->iobase_a + AMCC_OP_REG_MWAR);
250 outl(dmabuf->use_size, devpriv->iobase_a + AMCC_OP_REG_MWTC);
251}
252
253static void pci9118_amcc_dma_ena(struct comedi_device *dev, bool enable)
254{
255 struct pci9118_private *devpriv = dev->private;
256 unsigned int mcsr;
257
258 mcsr = inl(devpriv->iobase_a + AMCC_OP_REG_MCSR);
259 if (enable)
260 mcsr |= RESET_A2P_FLAGS | A2P_HI_PRIORITY | EN_A2P_TRANSFERS;
261 else
262 mcsr &= ~EN_A2P_TRANSFERS;
263 outl(mcsr, devpriv->iobase_a + AMCC_OP_REG_MCSR);
264}
265
266static void pci9118_amcc_int_ena(struct comedi_device *dev, bool enable)
267{
268 struct pci9118_private *devpriv = dev->private;
269 unsigned int intcsr;
270
271
272 intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
273 if (enable)
274 intcsr |= 0x1f00;
275 else
276 intcsr &= ~0x1f00;
277 outl(intcsr, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
278}
279
280static void pci9118_ai_reset_fifo(struct comedi_device *dev)
281{
282
283 outl(0, dev->iobase + PCI9118_FIFO_RESET_REG);
284}
285
286static int pci9118_ai_check_chanlist(struct comedi_device *dev,
287 struct comedi_subdevice *s,
288 struct comedi_cmd *cmd)
289{
290 struct pci9118_private *devpriv = dev->private;
291 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
292 unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
293 int i;
294
295
296 if (cmd->chanlist_len == 1)
297 return 0;
298
299 for (i = 1; i < cmd->chanlist_len; i++) {
300 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
301 unsigned int range = CR_RANGE(cmd->chanlist[i]);
302 unsigned int aref = CR_AREF(cmd->chanlist[i]);
303
304 if (aref != aref0) {
305 dev_err(dev->class_dev,
306 "Differential and single ended inputs can't be mixed!\n");
307 return -EINVAL;
308 }
309 if (comedi_range_is_bipolar(s, range) !=
310 comedi_range_is_bipolar(s, range0)) {
311 dev_err(dev->class_dev,
312 "Bipolar and unipolar ranges can't be mixed!\n");
313 return -EINVAL;
314 }
315 if (!devpriv->usemux && aref == AREF_DIFF &&
316 (chan >= (s->n_chan / 2))) {
317 dev_err(dev->class_dev,
318 "AREF_DIFF is only available for the first 8 channels!\n");
319 return -EINVAL;
320 }
321 }
322
323 return 0;
324}
325
326static void pci9118_set_chanlist(struct comedi_device *dev,
327 struct comedi_subdevice *s,
328 int n_chan, unsigned int *chanlist,
329 int frontadd, int backadd)
330{
331 struct pci9118_private *devpriv = dev->private;
332 unsigned int chan0 = CR_CHAN(chanlist[0]);
333 unsigned int range0 = CR_RANGE(chanlist[0]);
334 unsigned int aref0 = CR_AREF(chanlist[0]);
335 unsigned int ssh = 0x00;
336 unsigned int val;
337 int i;
338
339
340
341
342
343
344 devpriv->ai_ctrl = 0;
345 if (comedi_range_is_unipolar(s, range0))
346 devpriv->ai_ctrl |= PCI9118_AI_CTRL_UNIP;
347 if (aref0 == AREF_DIFF)
348 devpriv->ai_ctrl |= PCI9118_AI_CTRL_DIFF;
349 outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
350
351
352 outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
353 outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
354 outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
355
356
357 if (frontadd) {
358 val = PCI9118_AI_CHANLIST_CHAN(chan0) |
359 PCI9118_AI_CHANLIST_RANGE(range0);
360 ssh = devpriv->softsshsample;
361 for (i = 0; i < frontadd; i++) {
362 outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
363 ssh = devpriv->softsshhold;
364 }
365 }
366
367
368 for (i = 0; i < n_chan; i++) {
369 unsigned int chan = CR_CHAN(chanlist[i]);
370 unsigned int range = CR_RANGE(chanlist[i]);
371
372 val = PCI9118_AI_CHANLIST_CHAN(chan) |
373 PCI9118_AI_CHANLIST_RANGE(range);
374 outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
375 }
376
377
378 if (backadd) {
379 val = PCI9118_AI_CHANLIST_CHAN(chan0) |
380 PCI9118_AI_CHANLIST_RANGE(range0);
381 for (i = 0; i < backadd; i++)
382 outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
383 }
384
385 outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
386
387}
388
389static void pci9118_ai_mode4_switch(struct comedi_device *dev,
390 unsigned int next_buf)
391{
392 struct pci9118_private *devpriv = dev->private;
393 struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf];
394
395 devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG |
396 PCI9118_AI_CFG_AM;
397 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
398 comedi_8254_load(dev->pacer, 0, dmabuf->hw >> 1,
399 I8254_MODE0 | I8254_BINARY);
400 devpriv->ai_cfg |= PCI9118_AI_CFG_START;
401 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
402}
403
404static unsigned int pci9118_ai_samples_ready(struct comedi_device *dev,
405 struct comedi_subdevice *s,
406 unsigned int n_raw_samples)
407{
408 struct pci9118_private *devpriv = dev->private;
409 struct comedi_cmd *cmd = &s->async->cmd;
410 unsigned int start_pos = devpriv->ai_add_front;
411 unsigned int stop_pos = start_pos + cmd->chanlist_len;
412 unsigned int span_len = stop_pos + devpriv->ai_add_back;
413 unsigned int dma_pos = devpriv->ai_act_dmapos;
414 unsigned int whole_spans, n_samples, x;
415
416 if (span_len == cmd->chanlist_len)
417 return n_raw_samples;
418
419
420
421
422
423
424
425
426 whole_spans = n_raw_samples / span_len;
427 n_samples = whole_spans * cmd->chanlist_len;
428 n_raw_samples -= whole_spans * span_len;
429
430
431
432
433 while (n_raw_samples) {
434 if (dma_pos < start_pos) {
435
436 x = start_pos - dma_pos;
437 if (x > n_raw_samples)
438 x = n_raw_samples;
439 dma_pos += x;
440 n_raw_samples -= x;
441 if (!n_raw_samples)
442 break;
443 }
444 if (dma_pos < stop_pos) {
445
446 x = stop_pos - dma_pos;
447 if (x > n_raw_samples)
448 x = n_raw_samples;
449 n_samples += x;
450 dma_pos += x;
451 n_raw_samples -= x;
452 }
453
454 start_pos += span_len;
455 stop_pos += span_len;
456 }
457 return n_samples;
458}
459
460static void pci9118_ai_dma_xfer(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 unsigned short *dma_buffer,
463 unsigned int n_raw_samples)
464{
465 struct pci9118_private *devpriv = dev->private;
466 struct comedi_cmd *cmd = &s->async->cmd;
467 unsigned int start_pos = devpriv->ai_add_front;
468 unsigned int stop_pos = start_pos + cmd->chanlist_len;
469 unsigned int span_len = stop_pos + devpriv->ai_add_back;
470 unsigned int dma_pos = devpriv->ai_act_dmapos;
471 unsigned int x;
472
473 if (span_len == cmd->chanlist_len) {
474
475 comedi_buf_write_samples(s, dma_buffer, n_raw_samples);
476 dma_pos += n_raw_samples;
477 } else {
478
479
480
481
482
483 while (n_raw_samples) {
484 if (dma_pos < start_pos) {
485
486 x = start_pos - dma_pos;
487 if (x > n_raw_samples)
488 x = n_raw_samples;
489 dma_pos += x;
490 n_raw_samples -= x;
491 if (!n_raw_samples)
492 break;
493 }
494 if (dma_pos < stop_pos) {
495
496 x = stop_pos - dma_pos;
497 if (x > n_raw_samples)
498 x = n_raw_samples;
499 comedi_buf_write_samples(s, dma_buffer, x);
500 dma_pos += x;
501 n_raw_samples -= x;
502 }
503
504 start_pos += span_len;
505 stop_pos += span_len;
506 }
507 }
508
509 devpriv->ai_act_dmapos = dma_pos % span_len;
510}
511
512static void pci9118_exttrg_enable(struct comedi_device *dev, bool enable)
513{
514 struct pci9118_private *devpriv = dev->private;
515
516 if (enable)
517 devpriv->int_ctrl |= PCI9118_INT_CTRL_DTRG;
518 else
519 devpriv->int_ctrl &= ~PCI9118_INT_CTRL_DTRG;
520 outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
521
522 if (devpriv->int_ctrl)
523 pci9118_amcc_int_ena(dev, true);
524 else
525 pci9118_amcc_int_ena(dev, false);
526}
527
528static void pci9118_calc_divisors(struct comedi_device *dev,
529 struct comedi_subdevice *s,
530 unsigned int *tim1, unsigned int *tim2,
531 unsigned int flags, int chans,
532 unsigned int *div1, unsigned int *div2,
533 unsigned int chnsshfront)
534{
535 struct comedi_8254 *pacer = dev->pacer;
536 struct comedi_cmd *cmd = &s->async->cmd;
537
538 *div1 = *tim2 / pacer->osc_base;
539 *div2 = *tim1 / pacer->osc_base;
540 *div2 = *div2 / *div1;
541 if (*div2 < chans)
542 *div2 = chans;
543
544 *tim2 = *div1 * pacer->osc_base;
545
546 if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
547
548 if (*div2 < (chans + 2))
549 *div2 = chans + 2;
550 }
551
552 *tim1 = *div1 * *div2 * pacer->osc_base;
553}
554
555static void pci9118_start_pacer(struct comedi_device *dev, int mode)
556{
557 if (mode == 1 || mode == 2 || mode == 4)
558 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
559}
560
561static int pci9118_ai_cancel(struct comedi_device *dev,
562 struct comedi_subdevice *s)
563{
564 struct pci9118_private *devpriv = dev->private;
565
566 if (devpriv->usedma)
567 pci9118_amcc_dma_ena(dev, false);
568 pci9118_exttrg_enable(dev, false);
569 comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
570
571 devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
572 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
573
574 devpriv->ai_ctrl = 0;
575 outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
576 outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
577
578 outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
579 outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
580 pci9118_ai_reset_fifo(dev);
581
582 devpriv->int_ctrl = 0;
583 outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
584 pci9118_amcc_int_ena(dev, false);
585
586 devpriv->ai_do = 0;
587 devpriv->usedma = 0;
588
589 devpriv->ai_act_dmapos = 0;
590 s->async->inttrig = NULL;
591 devpriv->ai_neverending = 0;
592 devpriv->dma_actbuf = 0;
593
594 return 0;
595}
596
597static void pci9118_ai_munge(struct comedi_device *dev,
598 struct comedi_subdevice *s, void *data,
599 unsigned int num_bytes,
600 unsigned int start_chan_index)
601{
602 struct pci9118_private *devpriv = dev->private;
603 unsigned short *array = data;
604 unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes);
605 unsigned int i;
606 __be16 *barray = data;
607
608 for (i = 0; i < num_samples; i++) {
609 if (devpriv->usedma)
610 array[i] = be16_to_cpu(barray[i]);
611 if (s->maxdata == 0xffff)
612 array[i] ^= 0x8000;
613 else
614 array[i] = (array[i] >> 4) & 0x0fff;
615 }
616}
617
618static void pci9118_ai_get_onesample(struct comedi_device *dev,
619 struct comedi_subdevice *s)
620{
621 struct pci9118_private *devpriv = dev->private;
622 struct comedi_cmd *cmd = &s->async->cmd;
623 unsigned short sampl;
624
625 sampl = inl(dev->iobase + PCI9118_AI_FIFO_REG);
626
627 comedi_buf_write_samples(s, &sampl, 1);
628
629 if (!devpriv->ai_neverending) {
630 if (s->async->scans_done >= cmd->stop_arg)
631 s->async->events |= COMEDI_CB_EOA;
632 }
633}
634
635static void pci9118_ai_get_dma(struct comedi_device *dev,
636 struct comedi_subdevice *s)
637{
638 struct pci9118_private *devpriv = dev->private;
639 struct comedi_cmd *cmd = &s->async->cmd;
640 struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[devpriv->dma_actbuf];
641 unsigned int n_all = comedi_bytes_to_samples(s, dmabuf->use_size);
642 unsigned int n_valid;
643 bool more_dma;
644
645
646 n_valid = pci9118_ai_samples_ready(dev, s, n_all);
647 more_dma = n_valid < comedi_nsamples_left(s, n_valid + 1);
648
649
650 if (more_dma && devpriv->dma_doublebuf) {
651 devpriv->dma_actbuf = 1 - devpriv->dma_actbuf;
652 pci9118_amcc_setup_dma(dev, devpriv->dma_actbuf);
653 if (devpriv->ai_do == 4)
654 pci9118_ai_mode4_switch(dev, devpriv->dma_actbuf);
655 }
656
657 if (n_all)
658 pci9118_ai_dma_xfer(dev, s, dmabuf->virt, n_all);
659
660 if (!devpriv->ai_neverending) {
661 if (s->async->scans_done >= cmd->stop_arg)
662 s->async->events |= COMEDI_CB_EOA;
663 }
664
665 if (s->async->events & COMEDI_CB_CANCEL_MASK)
666 more_dma = false;
667
668
669 if (more_dma && !devpriv->dma_doublebuf) {
670 pci9118_amcc_setup_dma(dev, 0);
671 if (devpriv->ai_do == 4)
672 pci9118_ai_mode4_switch(dev, 0);
673 }
674}
675
676static irqreturn_t pci9118_interrupt(int irq, void *d)
677{
678 struct comedi_device *dev = d;
679 struct comedi_subdevice *s = dev->read_subdev;
680 struct pci9118_private *devpriv = dev->private;
681 unsigned int intsrc;
682 unsigned int intcsr;
683 unsigned int adstat;
684
685 if (!dev->attached)
686 return IRQ_NONE;
687
688 intsrc = inl(dev->iobase + PCI9118_INT_CTRL_REG) & 0xf;
689 intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
690
691 if (!intsrc && !(intcsr & ANY_S593X_INT))
692 return IRQ_NONE;
693
694 outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
695
696 if (intcsr & MASTER_ABORT_INT) {
697 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
698 s->async->events |= COMEDI_CB_ERROR;
699 goto interrupt_exit;
700 }
701
702 if (intcsr & TARGET_ABORT_INT) {
703 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
704 s->async->events |= COMEDI_CB_ERROR;
705 goto interrupt_exit;
706 }
707
708 adstat = inl(dev->iobase + PCI9118_AI_STATUS_REG);
709 if ((adstat & PCI9118_AI_STATUS_NFULL) == 0) {
710 dev_err(dev->class_dev,
711 "A/D FIFO Full status (Fatal Error!)\n");
712 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
713 goto interrupt_exit;
714 }
715 if (adstat & PCI9118_AI_STATUS_BOVER) {
716 dev_err(dev->class_dev,
717 "A/D Burst Mode Overrun Status (Fatal Error!)\n");
718 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
719 goto interrupt_exit;
720 }
721 if (adstat & PCI9118_AI_STATUS_ADOS) {
722 dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n");
723 s->async->events |= COMEDI_CB_ERROR;
724 goto interrupt_exit;
725 }
726 if (adstat & PCI9118_AI_STATUS_ADOR) {
727 dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n");
728 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
729 goto interrupt_exit;
730 }
731
732 if (!devpriv->ai_do)
733 return IRQ_HANDLED;
734
735 if (devpriv->ai12_startstop) {
736 if ((adstat & PCI9118_AI_STATUS_DTH) &&
737 (intsrc & PCI9118_INT_CTRL_DTRG)) {
738
739 if (devpriv->ai12_startstop & START_AI_EXT) {
740
741 devpriv->ai12_startstop &= ~START_AI_EXT;
742 if (!(devpriv->ai12_startstop & STOP_AI_EXT))
743 pci9118_exttrg_enable(dev, false);
744
745
746 pci9118_start_pacer(dev, devpriv->ai_do);
747 outl(devpriv->ai_ctrl,
748 dev->iobase + PCI9118_AI_CTRL_REG);
749 } else if (devpriv->ai12_startstop & STOP_AI_EXT) {
750
751 devpriv->ai12_startstop &= ~STOP_AI_EXT;
752 pci9118_exttrg_enable(dev, false);
753
754
755 devpriv->ai_neverending = 0;
756 }
757 }
758 }
759
760 if (devpriv->usedma)
761 pci9118_ai_get_dma(dev, s);
762 else
763 pci9118_ai_get_onesample(dev, s);
764
765interrupt_exit:
766 comedi_handle_events(dev, s);
767 return IRQ_HANDLED;
768}
769
770static void pci9118_ai_cmd_start(struct comedi_device *dev)
771{
772 struct pci9118_private *devpriv = dev->private;
773
774 outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
775 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
776 if (devpriv->ai_do != 3) {
777 pci9118_start_pacer(dev, devpriv->ai_do);
778 devpriv->ai_ctrl |= PCI9118_AI_CTRL_SOFTG;
779 }
780 outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
781}
782
783static int pci9118_ai_inttrig(struct comedi_device *dev,
784 struct comedi_subdevice *s,
785 unsigned int trig_num)
786{
787 struct comedi_cmd *cmd = &s->async->cmd;
788
789 if (trig_num != cmd->start_arg)
790 return -EINVAL;
791
792 s->async->inttrig = NULL;
793 pci9118_ai_cmd_start(dev);
794
795 return 1;
796}
797
798static int pci9118_ai_setup_dma(struct comedi_device *dev,
799 struct comedi_subdevice *s)
800{
801 struct pci9118_private *devpriv = dev->private;
802 struct comedi_cmd *cmd = &s->async->cmd;
803 struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
804 struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
805 unsigned int dmalen0 = dmabuf0->size;
806 unsigned int dmalen1 = dmabuf1->size;
807 unsigned int scan_bytes = devpriv->ai_n_realscanlen *
808 comedi_bytes_per_sample(s);
809
810
811 if (dmalen0 > s->async->prealloc_bufsz) {
812
813 dmalen0 = s->async->prealloc_bufsz & ~3L;
814 }
815 if (dmalen1 > s->async->prealloc_bufsz) {
816
817 dmalen1 = s->async->prealloc_bufsz & ~3L;
818 }
819
820
821 if (devpriv->ai_flags & CMDF_WAKE_EOS) {
822 if (dmalen0 < scan_bytes) {
823
824 devpriv->ai_flags &= (~CMDF_WAKE_EOS);
825 dev_info(dev->class_dev,
826 "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
827 dmalen0, scan_bytes);
828 } else {
829
830 dmalen0 = scan_bytes;
831 if (dmalen0 < 4) {
832 dev_info(dev->class_dev,
833 "ERR: DMA0 buf len bug? (%d<4)\n",
834 dmalen0);
835 dmalen0 = 4;
836 }
837 }
838 }
839 if (devpriv->ai_flags & CMDF_WAKE_EOS) {
840 if (dmalen1 < scan_bytes) {
841
842 devpriv->ai_flags &= (~CMDF_WAKE_EOS);
843 dev_info(dev->class_dev,
844 "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
845 dmalen1, scan_bytes);
846 } else {
847
848 dmalen1 = scan_bytes;
849 if (dmalen1 < 4) {
850 dev_info(dev->class_dev,
851 "ERR: DMA1 buf len bug? (%d<4)\n",
852 dmalen1);
853 dmalen1 = 4;
854 }
855 }
856 }
857
858
859 if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) {
860 unsigned int tmp;
861
862
863 tmp = dmalen0;
864 dmalen0 = (dmalen0 / scan_bytes) * scan_bytes;
865 dmalen0 &= ~3L;
866 if (!dmalen0)
867 dmalen0 = tmp;
868 tmp = dmalen1;
869 dmalen1 = (dmalen1 / scan_bytes) * scan_bytes;
870 dmalen1 &= ~3L;
871 if (!dmalen1)
872 dmalen1 = tmp;
873
874
875
876
877 if (!devpriv->ai_neverending) {
878 unsigned long long scanlen;
879
880 scanlen = (unsigned long long)scan_bytes *
881 cmd->stop_arg;
882
883
884 if (dmalen0 > scanlen) {
885 dmalen0 = scanlen;
886 dmalen0 &= ~3L;
887 } else {
888
889 if (dmalen1 > (scanlen - dmalen0)) {
890 dmalen1 = scanlen - dmalen0;
891 dmalen1 &= ~3L;
892 }
893 }
894 }
895 }
896
897
898 devpriv->dma_actbuf = 0;
899 dmabuf0->use_size = dmalen0;
900 dmabuf1->use_size = dmalen1;
901
902 pci9118_amcc_dma_ena(dev, false);
903 pci9118_amcc_setup_dma(dev, 0);
904
905 outl(0x00000000 | AINT_WRITE_COMPL,
906 devpriv->iobase_a + AMCC_OP_REG_INTCSR);
907
908 pci9118_amcc_dma_ena(dev, true);
909 outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS,
910 devpriv->iobase_a + AMCC_OP_REG_INTCSR);
911
912
913 return 0;
914}
915
916static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
917{
918 struct pci9118_private *devpriv = dev->private;
919 struct comedi_8254 *pacer = dev->pacer;
920 struct comedi_cmd *cmd = &s->async->cmd;
921 unsigned int addchans = 0;
922 unsigned int scanlen;
923
924 devpriv->ai12_startstop = 0;
925 devpriv->ai_flags = cmd->flags;
926 devpriv->ai_add_front = 0;
927 devpriv->ai_add_back = 0;
928
929
930 if (cmd->start_src == TRIG_EXT)
931 devpriv->ai12_startstop |= START_AI_EXT;
932 if (cmd->stop_src == TRIG_EXT) {
933 devpriv->ai_neverending = 1;
934 devpriv->ai12_startstop |= STOP_AI_EXT;
935 }
936 if (cmd->stop_src == TRIG_NONE)
937 devpriv->ai_neverending = 1;
938 if (cmd->stop_src == TRIG_COUNT)
939 devpriv->ai_neverending = 0;
940
941
942
943
944
945 devpriv->ai_add_front = 0;
946 devpriv->ai_add_back = 0;
947 if (devpriv->master) {
948 devpriv->usedma = 1;
949 if ((cmd->flags & CMDF_WAKE_EOS) &&
950 (cmd->scan_end_arg == 1)) {
951 if (cmd->convert_src == TRIG_NOW)
952 devpriv->ai_add_back = 1;
953 if (cmd->convert_src == TRIG_TIMER) {
954 devpriv->usedma = 0;
955
956
957
958
959 }
960 }
961 if ((cmd->flags & CMDF_WAKE_EOS) &&
962 (cmd->scan_end_arg & 1) &&
963 (cmd->scan_end_arg > 1)) {
964 if (cmd->scan_begin_src == TRIG_FOLLOW) {
965 devpriv->usedma = 0;
966
967
968
969 } else {
970
971
972
973 devpriv->ai_add_back = 1;
974 }
975 }
976 } else {
977 devpriv->usedma = 0;
978 }
979
980
981
982
983
984 if (cmd->convert_src == TRIG_NOW && devpriv->softsshdelay) {
985 devpriv->ai_add_front = 2;
986 if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) {
987
988 devpriv->ai_add_front++;
989 devpriv->ai_add_back = 0;
990 }
991 if (cmd->convert_arg < devpriv->ai_ns_min)
992 cmd->convert_arg = devpriv->ai_ns_min;
993 addchans = devpriv->softsshdelay / cmd->convert_arg;
994 if (devpriv->softsshdelay % cmd->convert_arg)
995 addchans++;
996 if (addchans > (devpriv->ai_add_front - 1)) {
997
998 devpriv->ai_add_front = addchans + 1;
999 if (devpriv->usedma == 1)
1000 if ((devpriv->ai_add_front +
1001 cmd->chanlist_len +
1002 devpriv->ai_add_back) & 1)
1003 devpriv->ai_add_front++;
1004
1005 }
1006 }
1007
1008 scanlen = devpriv->ai_add_front + cmd->chanlist_len +
1009 devpriv->ai_add_back;
1010
1011
1012
1013
1014 devpriv->ai_n_realscanlen = scanlen *
1015 (cmd->scan_end_arg / cmd->chanlist_len);
1016
1017 if (scanlen > s->len_chanlist) {
1018 dev_err(dev->class_dev,
1019 "range/channel list is too long for actual configuration!\n");
1020 return -EINVAL;
1021 }
1022
1023
1024
1025
1026
1027 pci9118_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist,
1028 devpriv->ai_add_front, devpriv->ai_add_back);
1029
1030
1031 devpriv->ai_do = 0;
1032 if (cmd->scan_begin_src != TRIG_TIMER &&
1033 cmd->convert_src == TRIG_TIMER) {
1034
1035 if (cmd->scan_begin_src == TRIG_EXT)
1036 devpriv->ai_do = 4;
1037 else
1038 devpriv->ai_do = 1;
1039
1040 comedi_8254_cascade_ns_to_timer(pacer, &cmd->convert_arg,
1041 devpriv->ai_flags &
1042 CMDF_ROUND_NEAREST);
1043 comedi_8254_update_divisors(pacer);
1044
1045 devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
1046
1047 if (!devpriv->usedma) {
1048 devpriv->ai_ctrl |= PCI9118_AI_CTRL_INT;
1049 devpriv->int_ctrl |= PCI9118_INT_CTRL_TIMER;
1050 }
1051
1052 if (cmd->scan_begin_src == TRIG_EXT) {
1053 struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[0];
1054
1055 devpriv->ai_cfg |= PCI9118_AI_CFG_AM;
1056 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
1057 comedi_8254_load(pacer, 0, dmabuf->hw >> 1,
1058 I8254_MODE0 | I8254_BINARY);
1059 devpriv->ai_cfg |= PCI9118_AI_CFG_START;
1060 }
1061 }
1062
1063 if (cmd->scan_begin_src == TRIG_TIMER &&
1064 cmd->convert_src != TRIG_EXT) {
1065 if (!devpriv->usedma) {
1066 dev_err(dev->class_dev,
1067 "cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!\n");
1068 return -EIO;
1069 }
1070
1071
1072 devpriv->ai_do = 2;
1073
1074 pci9118_calc_divisors(dev, s,
1075 &cmd->scan_begin_arg, &cmd->convert_arg,
1076 devpriv->ai_flags,
1077 devpriv->ai_n_realscanlen,
1078 &pacer->divisor1,
1079 &pacer->divisor2,
1080 devpriv->ai_add_front);
1081
1082 devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
1083 devpriv->ai_cfg |= PCI9118_AI_CFG_BM | PCI9118_AI_CFG_BS;
1084 if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
1085 devpriv->ai_cfg |= PCI9118_AI_CFG_BSSH;
1086 outl(devpriv->ai_n_realscanlen,
1087 dev->iobase + PCI9118_AI_BURST_NUM_REG);
1088 }
1089
1090 if (cmd->scan_begin_src == TRIG_FOLLOW &&
1091 cmd->convert_src == TRIG_EXT) {
1092
1093 devpriv->ai_do = 3;
1094
1095 devpriv->ai_ctrl |= PCI9118_AI_CTRL_EXTM;
1096 }
1097
1098 if (devpriv->ai_do == 0) {
1099 dev_err(dev->class_dev,
1100 "Unable to determine acqusition mode! BUG in (*do_cmdtest)?\n");
1101 return -EINVAL;
1102 }
1103
1104 if (devpriv->usedma)
1105 devpriv->ai_ctrl |= PCI9118_AI_CTRL_DMA;
1106
1107
1108 devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
1109 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
1110 udelay(1);
1111 pci9118_ai_reset_fifo(dev);
1112
1113
1114 inl(dev->iobase + PCI9118_AI_STATUS_REG);
1115 inl(dev->iobase + PCI9118_INT_CTRL_REG);
1116
1117 devpriv->ai_act_dmapos = 0;
1118
1119 if (devpriv->usedma) {
1120 pci9118_ai_setup_dma(dev, s);
1121
1122 outl(0x02000000 | AINT_WRITE_COMPL,
1123 devpriv->iobase_a + AMCC_OP_REG_INTCSR);
1124 } else {
1125 pci9118_amcc_int_ena(dev, true);
1126 }
1127
1128
1129 if (cmd->start_src == TRIG_NOW)
1130 pci9118_ai_cmd_start(dev);
1131 else if (cmd->start_src == TRIG_INT)
1132 s->async->inttrig = pci9118_ai_inttrig;
1133
1134
1135 if (cmd->start_src == TRIG_EXT || cmd->stop_src == TRIG_EXT)
1136 pci9118_exttrg_enable(dev, true);
1137
1138 return 0;
1139}
1140
1141static int pci9118_ai_cmdtest(struct comedi_device *dev,
1142 struct comedi_subdevice *s,
1143 struct comedi_cmd *cmd)
1144{
1145 struct pci9118_private *devpriv = dev->private;
1146 int err = 0;
1147 unsigned int flags;
1148 unsigned int arg;
1149
1150
1151
1152 err |= comedi_check_trigger_src(&cmd->start_src,
1153 TRIG_NOW | TRIG_EXT | TRIG_INT);
1154
1155 flags = TRIG_FOLLOW;
1156 if (devpriv->master)
1157 flags |= TRIG_TIMER | TRIG_EXT;
1158 err |= comedi_check_trigger_src(&cmd->scan_begin_src, flags);
1159
1160 flags = TRIG_TIMER | TRIG_EXT;
1161 if (devpriv->master)
1162 flags |= TRIG_NOW;
1163 err |= comedi_check_trigger_src(&cmd->convert_src, flags);
1164
1165 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1166 err |= comedi_check_trigger_src(&cmd->stop_src,
1167 TRIG_COUNT | TRIG_NONE | TRIG_EXT);
1168
1169 if (err)
1170 return 1;
1171
1172
1173
1174 err |= comedi_check_trigger_is_unique(cmd->start_src);
1175 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
1176 err |= comedi_check_trigger_is_unique(cmd->convert_src);
1177 err |= comedi_check_trigger_is_unique(cmd->stop_src);
1178
1179
1180
1181 if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
1182 err |= -EINVAL;
1183
1184 if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
1185 (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
1186 err |= -EINVAL;
1187
1188 if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
1189 (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
1190 err |= -EINVAL;
1191
1192 if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
1193 err |= -EINVAL;
1194
1195 if (err)
1196 return 2;
1197
1198
1199
1200 switch (cmd->start_src) {
1201 case TRIG_NOW:
1202 case TRIG_EXT:
1203 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
1204 break;
1205 case TRIG_INT:
1206
1207 break;
1208 }
1209
1210 if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT))
1211 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1212
1213 if ((cmd->scan_begin_src == TRIG_TIMER) &&
1214 (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) {
1215 cmd->scan_begin_src = TRIG_FOLLOW;
1216 cmd->convert_arg = cmd->scan_begin_arg;
1217 cmd->scan_begin_arg = 0;
1218 }
1219
1220 if (cmd->scan_begin_src == TRIG_TIMER) {
1221 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
1222 devpriv->ai_ns_min);
1223 }
1224
1225 if (cmd->scan_begin_src == TRIG_EXT) {
1226 if (cmd->scan_begin_arg) {
1227 cmd->scan_begin_arg = 0;
1228 err |= -EINVAL;
1229 err |= comedi_check_trigger_arg_max(&cmd->scan_end_arg,
1230 65535);
1231 }
1232 }
1233
1234 if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
1235 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
1236 devpriv->ai_ns_min);
1237 }
1238
1239 if (cmd->convert_src == TRIG_EXT)
1240 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
1241
1242 if (cmd->stop_src == TRIG_COUNT)
1243 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
1244 else
1245 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
1246
1247 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
1248
1249 err |= comedi_check_trigger_arg_min(&cmd->scan_end_arg,
1250 cmd->chanlist_len);
1251
1252 if ((cmd->scan_end_arg % cmd->chanlist_len)) {
1253 cmd->scan_end_arg =
1254 cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len);
1255 err |= -EINVAL;
1256 }
1257
1258 if (err)
1259 return 3;
1260
1261
1262
1263 if (cmd->scan_begin_src == TRIG_TIMER) {
1264 arg = cmd->scan_begin_arg;
1265 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
1266 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
1267 }
1268
1269 if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
1270 arg = cmd->convert_arg;
1271 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
1272 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
1273
1274 if (cmd->scan_begin_src == TRIG_TIMER &&
1275 cmd->convert_src == TRIG_NOW) {
1276 if (cmd->convert_arg == 0) {
1277 arg = devpriv->ai_ns_min *
1278 (cmd->scan_end_arg + 2);
1279 } else {
1280 arg = cmd->convert_arg * cmd->chanlist_len;
1281 }
1282 err |= comedi_check_trigger_arg_min(&cmd->
1283 scan_begin_arg,
1284 arg);
1285 }
1286 }
1287
1288 if (err)
1289 return 4;
1290
1291
1292
1293 if (cmd->chanlist)
1294 err |= pci9118_ai_check_chanlist(dev, s, cmd);
1295
1296 if (err)
1297 return 5;
1298
1299 return 0;
1300}
1301
1302static int pci9118_ai_eoc(struct comedi_device *dev,
1303 struct comedi_subdevice *s,
1304 struct comedi_insn *insn,
1305 unsigned long context)
1306{
1307 unsigned int status;
1308
1309 status = inl(dev->iobase + PCI9118_AI_STATUS_REG);
1310 if (status & PCI9118_AI_STATUS_ADRDY)
1311 return 0;
1312 return -EBUSY;
1313}
1314
1315static void pci9118_ai_start_conv(struct comedi_device *dev)
1316{
1317
1318 outl(0, dev->iobase + PCI9118_SOFTTRG_REG);
1319}
1320
1321static int pci9118_ai_insn_read(struct comedi_device *dev,
1322 struct comedi_subdevice *s,
1323 struct comedi_insn *insn,
1324 unsigned int *data)
1325{
1326 struct pci9118_private *devpriv = dev->private;
1327 unsigned int val;
1328 int ret;
1329 int i;
1330
1331
1332
1333
1334
1335 pci9118_set_chanlist(dev, s, 1, &insn->chanspec, 0, 0);
1336
1337
1338 devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
1339 outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
1340
1341 pci9118_ai_reset_fifo(dev);
1342
1343 for (i = 0; i < insn->n; i++) {
1344 pci9118_ai_start_conv(dev);
1345
1346 ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
1347 if (ret)
1348 return ret;
1349
1350 val = inl(dev->iobase + PCI9118_AI_FIFO_REG);
1351 if (s->maxdata == 0xffff)
1352 data[i] = (val & 0xffff) ^ 0x8000;
1353 else
1354 data[i] = (val >> 4) & 0xfff;
1355 }
1356
1357 return insn->n;
1358}
1359
1360static int pci9118_ao_insn_write(struct comedi_device *dev,
1361 struct comedi_subdevice *s,
1362 struct comedi_insn *insn,
1363 unsigned int *data)
1364{
1365 unsigned int chan = CR_CHAN(insn->chanspec);
1366 unsigned int val = s->readback[chan];
1367 int i;
1368
1369 for (i = 0; i < insn->n; i++) {
1370 val = data[i];
1371 outl(val, dev->iobase + PCI9118_AO_REG(chan));
1372 }
1373 s->readback[chan] = val;
1374
1375 return insn->n;
1376}
1377
1378static int pci9118_di_insn_bits(struct comedi_device *dev,
1379 struct comedi_subdevice *s,
1380 struct comedi_insn *insn,
1381 unsigned int *data)
1382{
1383
1384
1385
1386
1387
1388 data[1] = inl(dev->iobase + PCI9118_DIO_REG) & 0xf;
1389
1390 return insn->n;
1391}
1392
1393static int pci9118_do_insn_bits(struct comedi_device *dev,
1394 struct comedi_subdevice *s,
1395 struct comedi_insn *insn,
1396 unsigned int *data)
1397{
1398
1399
1400
1401
1402
1403
1404 if (comedi_dio_update_state(s, data))
1405 outl(s->state, dev->iobase + PCI9118_DIO_REG);
1406
1407 data[1] = s->state;
1408
1409 return insn->n;
1410}
1411
1412static void pci9118_reset(struct comedi_device *dev)
1413{
1414
1415 outl(0, dev->iobase + PCI9118_INT_CTRL_REG);
1416 outl(0, dev->iobase + PCI9118_AI_CTRL_REG);
1417 outl(0, dev->iobase + PCI9118_AI_CFG_REG);
1418 pci9118_ai_reset_fifo(dev);
1419
1420
1421 inl(dev->iobase + PCI9118_INT_CTRL_REG);
1422 inl(dev->iobase + PCI9118_AI_STATUS_REG);
1423
1424
1425 outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
1426 outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
1427 outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
1428
1429
1430 outl(2047, dev->iobase + PCI9118_AO_REG(0));
1431 outl(2047, dev->iobase + PCI9118_AO_REG(1));
1432}
1433
1434static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
1435 struct comedi_devconfig *it)
1436{
1437 struct pci_dev *pcidev = NULL;
1438 int bus = it->options[0];
1439 int slot = it->options[1];
1440
1441 for_each_pci_dev(pcidev) {
1442 if (pcidev->vendor != PCI_VENDOR_ID_AMCC)
1443 continue;
1444 if (pcidev->device != 0x80d9)
1445 continue;
1446 if (bus || slot) {
1447
1448 if (pcidev->bus->number != bus ||
1449 PCI_SLOT(pcidev->devfn) != slot)
1450 continue;
1451 }
1452 return pcidev;
1453 }
1454 dev_err(dev->class_dev,
1455 "no supported board found! (req. bus/slot : %d/%d)\n",
1456 bus, slot);
1457 return NULL;
1458}
1459
1460static void pci9118_alloc_dma(struct comedi_device *dev)
1461{
1462 struct pci9118_private *devpriv = dev->private;
1463 struct pci9118_dmabuf *dmabuf;
1464 int order;
1465 int i;
1466
1467 for (i = 0; i < 2; i++) {
1468 dmabuf = &devpriv->dmabuf[i];
1469 for (order = 2; order >= 0; order--) {
1470 dmabuf->virt =
1471 dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order,
1472 &dmabuf->hw, GFP_KERNEL);
1473 if (dmabuf->virt)
1474 break;
1475 }
1476 if (!dmabuf->virt)
1477 break;
1478 dmabuf->size = PAGE_SIZE << order;
1479
1480 if (i == 0)
1481 devpriv->master = 1;
1482 if (i == 1)
1483 devpriv->dma_doublebuf = 1;
1484 }
1485}
1486
1487static void pci9118_free_dma(struct comedi_device *dev)
1488{
1489 struct pci9118_private *devpriv = dev->private;
1490 struct pci9118_dmabuf *dmabuf;
1491 int i;
1492
1493 if (!devpriv)
1494 return;
1495
1496 for (i = 0; i < 2; i++) {
1497 dmabuf = &devpriv->dmabuf[i];
1498 if (dmabuf->virt) {
1499 dma_free_coherent(dev->hw_dev, dmabuf->size,
1500 dmabuf->virt, dmabuf->hw);
1501 }
1502 }
1503}
1504
1505static int pci9118_common_attach(struct comedi_device *dev,
1506 int ext_mux, int softsshdelay)
1507{
1508 const struct pci9118_boardinfo *board = dev->board_ptr;
1509 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1510 struct pci9118_private *devpriv;
1511 struct comedi_subdevice *s;
1512 int ret;
1513 int i;
1514 u16 u16w;
1515
1516 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1517 if (!devpriv)
1518 return -ENOMEM;
1519
1520 ret = comedi_pci_enable(dev);
1521 if (ret)
1522 return ret;
1523 pci_set_master(pcidev);
1524
1525 devpriv->iobase_a = pci_resource_start(pcidev, 0);
1526 dev->iobase = pci_resource_start(pcidev, 2);
1527
1528 dev->pacer = comedi_8254_init(dev->iobase + PCI9118_TIMER_BASE,
1529 I8254_OSC_BASE_4MHZ, I8254_IO32, 0);
1530 if (!dev->pacer)
1531 return -ENOMEM;
1532
1533 pci9118_reset(dev);
1534
1535 if (pcidev->irq) {
1536 ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
1537 dev->board_name, dev);
1538 if (ret == 0) {
1539 dev->irq = pcidev->irq;
1540
1541 pci9118_alloc_dma(dev);
1542 }
1543 }
1544
1545 if (ext_mux > 0) {
1546 if (ext_mux > 256)
1547 ext_mux = 256;
1548 if (softsshdelay > 0)
1549 if (ext_mux > 128)
1550 ext_mux = 128;
1551 devpriv->usemux = 1;
1552 } else {
1553 devpriv->usemux = 0;
1554 }
1555
1556 if (softsshdelay < 0) {
1557
1558 devpriv->softsshdelay = -softsshdelay;
1559 devpriv->softsshsample = 0x80;
1560 devpriv->softsshhold = 0x00;
1561 } else {
1562 devpriv->softsshdelay = softsshdelay;
1563 devpriv->softsshsample = 0x00;
1564 devpriv->softsshhold = 0x80;
1565 }
1566
1567 pci_read_config_word(pcidev, PCI_COMMAND, &u16w);
1568 pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64);
1569
1570
1571 ret = comedi_alloc_subdevices(dev, 4);
1572 if (ret)
1573 return ret;
1574
1575
1576 s = &dev->subdevices[0];
1577 s->type = COMEDI_SUBD_AI;
1578 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
1579 s->n_chan = (devpriv->usemux) ? ext_mux : 16;
1580 s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff;
1581 s->range_table = board->is_hg ? &pci9118hg_ai_range
1582 : &pci9118_ai_range;
1583 s->insn_read = pci9118_ai_insn_read;
1584 if (dev->irq) {
1585 dev->read_subdev = s;
1586 s->subdev_flags |= SDF_CMD_READ;
1587 s->len_chanlist = 255;
1588 s->do_cmdtest = pci9118_ai_cmdtest;
1589 s->do_cmd = pci9118_ai_cmd;
1590 s->cancel = pci9118_ai_cancel;
1591 s->munge = pci9118_ai_munge;
1592 }
1593
1594 if (s->maxdata == 0xffff) {
1595
1596
1597
1598
1599 devpriv->ai_ns_min = 10000;
1600 } else {
1601
1602
1603
1604
1605 devpriv->ai_ns_min = 3000;
1606 }
1607
1608
1609 s = &dev->subdevices[1];
1610 s->type = COMEDI_SUBD_AO;
1611 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1612 s->n_chan = 2;
1613 s->maxdata = 0x0fff;
1614 s->range_table = &range_bipolar10;
1615 s->insn_write = pci9118_ao_insn_write;
1616
1617 ret = comedi_alloc_subdev_readback(s);
1618 if (ret)
1619 return ret;
1620
1621
1622 for (i = 0; i < s->n_chan; i++)
1623 s->readback[i] = 2047;
1624
1625
1626 s = &dev->subdevices[2];
1627 s->type = COMEDI_SUBD_DI;
1628 s->subdev_flags = SDF_READABLE;
1629 s->n_chan = 4;
1630 s->maxdata = 1;
1631 s->range_table = &range_digital;
1632 s->insn_bits = pci9118_di_insn_bits;
1633
1634
1635 s = &dev->subdevices[3];
1636 s->type = COMEDI_SUBD_DO;
1637 s->subdev_flags = SDF_WRITABLE;
1638 s->n_chan = 4;
1639 s->maxdata = 1;
1640 s->range_table = &range_digital;
1641 s->insn_bits = pci9118_do_insn_bits;
1642
1643
1644 s->state = inl(dev->iobase + PCI9118_DIO_REG) >> 4;
1645
1646 return 0;
1647}
1648
1649static int pci9118_attach(struct comedi_device *dev,
1650 struct comedi_devconfig *it)
1651{
1652 struct pci_dev *pcidev;
1653 int ext_mux, softsshdelay;
1654
1655 ext_mux = it->options[2];
1656 softsshdelay = it->options[4];
1657
1658 pcidev = pci9118_find_pci(dev, it);
1659 if (!pcidev)
1660 return -EIO;
1661 comedi_set_hw_dev(dev, &pcidev->dev);
1662
1663 return pci9118_common_attach(dev, ext_mux, softsshdelay);
1664}
1665
1666static int pci9118_auto_attach(struct comedi_device *dev,
1667 unsigned long context)
1668{
1669 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1670 const struct pci9118_boardinfo *board = NULL;
1671
1672 if (context < ARRAY_SIZE(pci9118_boards))
1673 board = &pci9118_boards[context];
1674 if (!board)
1675 return -ENODEV;
1676 dev->board_ptr = board;
1677 dev->board_name = board->name;
1678
1679
1680
1681
1682
1683 pci_dev_get(pcidev);
1684
1685 return pci9118_common_attach(dev, 0, 0);
1686}
1687
1688static void pci9118_detach(struct comedi_device *dev)
1689{
1690 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1691
1692 if (dev->iobase)
1693 pci9118_reset(dev);
1694 comedi_pci_detach(dev);
1695 pci9118_free_dma(dev);
1696 if (pcidev)
1697 pci_dev_put(pcidev);
1698}
1699
1700static struct comedi_driver adl_pci9118_driver = {
1701 .driver_name = "adl_pci9118",
1702 .module = THIS_MODULE,
1703 .attach = pci9118_attach,
1704 .auto_attach = pci9118_auto_attach,
1705 .detach = pci9118_detach,
1706 .num_names = ARRAY_SIZE(pci9118_boards),
1707 .board_name = &pci9118_boards[0].name,
1708 .offset = sizeof(struct pci9118_boardinfo),
1709};
1710
1711static int adl_pci9118_pci_probe(struct pci_dev *dev,
1712 const struct pci_device_id *id)
1713{
1714 return comedi_pci_auto_config(dev, &adl_pci9118_driver,
1715 id->driver_data);
1716}
1717
1718
1719static const struct pci_device_id adl_pci9118_pci_table[] = {
1720 { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118DG },
1721
1722
1723 { 0 }
1724};
1725MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);
1726
1727static struct pci_driver adl_pci9118_pci_driver = {
1728 .name = "adl_pci9118",
1729 .id_table = adl_pci9118_pci_table,
1730 .probe = adl_pci9118_pci_probe,
1731 .remove = comedi_pci_auto_unconfig,
1732};
1733module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver);
1734
1735MODULE_AUTHOR("Comedi http://www.comedi.org");
1736MODULE_DESCRIPTION("Comedi low-level driver");
1737MODULE_LICENSE("GPL");
1738