4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data.com
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 +-----------------------------------------------------------------------+
22 | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
23 +-----------------------------------------------------------------------+
24 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
25 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
26 +-----------------------------------------------------------------------+
27 | Project : APCI-3120 | Compiler : GCC |
28 | Module name : hwdrv_apci3120.c| Version : 2.96 |
29 +-------------------------------+---------------------------------------+
30 | Project manager: Eric Stolz | Date : 02/12/2002 |
31 +-----------------------------------------------------------------------+
32 | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
33 +-----------------------------------------------------------------------+
35 +-----------------------------------------------------------------------+
36 | Date | Author | Description of updates |
37 +----------+-----------+------------------------------------------------+
40 +----------+-----------+------------------------------------------------+
44 * ADDON RELATED ADDITIONS
47 #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00
48 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200
49 #define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L
50 #define APCI3120_AMWEN_ENABLE 0x02
51 #define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01
52 #define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L
53 #define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L
54 #define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L
55 #define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0
56 #define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0
57 #define APCI3120_DISABLE_BUS_MASTER_PCI 0x0
59 /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
60 #define APCI3120_ADD_ON_AGCSTS_LOW 0x3C
61 #define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2)
62 #define APCI3120_ADD_ON_MWAR_LOW 0x24
63 #define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2)
64 #define APCI3120_ADD_ON_MWTC_LOW 0x058
65 #define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2)
68 #define APCI3120_AMCC_OP_MCSR 0x3C
69 #define APCI3120_AMCC_OP_REG_INTCSR 0x38
71 /* for transfer count enable bit */
72 #define AGCSTS_TC_ENABLE 0x10000000
74 /* used for test on mixture of BIP/UNI ranges */
75 #define APCI3120_BIPOLAR_RANGES 4
77 #define APCI3120_ADDRESS_RANGE 16
79 #define APCI3120_DISABLE 0
80 #define APCI3120_ENABLE 1
82 #define APCI3120_START 1
83 #define APCI3120_STOP 0
85 #define APCI3120_EOC_MODE 1
86 #define APCI3120_EOS_MODE 2
87 #define APCI3120_DMA_MODE 3
89 /* DIGITAL INPUT-OUTPUT DEFINE */
91 #define APCI3120_DIGITAL_OUTPUT 0x0d
92 #define APCI3120_RD_STATUS 0x02
93 #define APCI3120_RD_FIFO 0x00
95 /* digital output insn_write ON /OFF selection */
96 #define APCI3120_SET4DIGITALOUTPUTON 1
97 #define APCI3120_SET4DIGITALOUTPUTOFF 0
99 /* Enable external trigger bit in nWrAddress */
100 #define APCI3120_ENABLE_EXT_TRIGGER 0x8000
102 /* ANALOG OUTPUT AND INPUT DEFINE */
103 #define APCI3120_UNIPOLAR 0x80
104 #define APCI3120_BIPOLAR 0x00
105 #define APCI3120_1_GAIN 0x00
106 #define APCI3120_2_GAIN 0x10
107 #define APCI3120_5_GAIN 0x20
108 #define APCI3120_10_GAIN 0x30
109 #define APCI3120_SEQ_RAM_ADDRESS 0x06
110 #define APCI3120_RESET_FIFO 0x0c
111 #define APCI3120_TIMER_0_MODE_2 0x01
112 #define APCI3120_TIMER_0_MODE_4 0x2
113 #define APCI3120_SELECT_TIMER_0_WORD 0x00
114 #define APCI3120_ENABLE_TIMER0 0x1000
115 #define APCI3120_CLEAR_PR 0xf0ff
116 #define APCI3120_CLEAR_PA 0xfff0
117 #define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
120 #define APCI3120_ENABLE_SCAN 0x8
121 #define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN)
122 #define APCI3120_ENABLE_EOS_INT 0x2
124 #define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT)
125 #define APCI3120_ENABLE_EOC_INT 0x1
126 #define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT)
127 #define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER \
128 (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
129 #define APCI3120_DISABLE_ALL_INTERRUPT \
130 (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
132 /* status register bits */
133 #define APCI3120_EOC 0x8000
134 #define APCI3120_EOS 0x2000
136 /* software trigger dummy register */
137 #define APCI3120_START_CONVERSION 0x02
140 #define APCI3120_QUARTZ_A 70
141 #define APCI3120_QUARTZ_B 50
142 #define APCI3120_TIMER 1
143 #define APCI3120_WATCHDOG 2
144 #define APCI3120_TIMER_DISABLE 0
145 #define APCI3120_TIMER_ENABLE 1
146 #define APCI3120_ENABLE_TIMER2 0x4000
147 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
148 #define APCI3120_ENABLE_TIMER_INT 0x04
149 #define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT)
150 #define APCI3120_WRITE_MODE_SELECT 0x0e
151 #define APCI3120_SELECT_TIMER_0_WORD 0x00
152 #define APCI3120_SELECT_TIMER_1_WORD 0x01
153 #define APCI3120_TIMER_1_MODE_2 0x4
155 /* $$ BIT FOR MODE IN nCsTimerCtr1 */
156 #define APCI3120_TIMER_2_MODE_0 0x0
157 #define APCI3120_TIMER_2_MODE_2 0x10
158 #define APCI3120_TIMER_2_MODE_5 0x30
160 /* $$ BIT FOR MODE IN nCsTimerCtr0 */
161 #define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02
162 #define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03
164 #define APCI3120_TIMER_CRT0 0x0d
165 #define APCI3120_TIMER_CRT1 0x0c
167 #define APCI3120_TIMER_VALUE 0x04
168 #define APCI3120_TIMER_STATUS_REGISTER 0x0d
169 #define APCI3120_RD_STATUS 0x02
170 #define APCI3120_WR_ADDRESS 0x00
171 #define APCI3120_ENABLE_WATCHDOG 0x20
172 #define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG)
173 #define APCI3120_ENABLE_TIMER_COUNTER 0x10
174 #define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER)
175 #define APCI3120_FC_TIMER 0x1000
176 #define APCI3120_ENABLE_TIMER0 0x1000
177 #define APCI3120_ENABLE_TIMER1 0x2000
178 #define APCI3120_ENABLE_TIMER2 0x4000
179 #define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0)
180 #define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1)
181 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
183 #define APCI3120_TIMER2_SELECT_EOS 0xc0
184 #define APCI3120_COUNTER 3
185 #define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & \
186 APCI3120_DISABLE_TIMER1 & \
187 APCI3120_DISABLE_TIMER2)
189 /* ANALOG INPUT RANGE */
190 static const struct comedi_lrange range_apci3120_ai = {
203 static int apci3120_ai_insn_config(struct comedi_device *dev,
204 struct comedi_subdevice *s,
205 struct comedi_insn *insn,
208 struct apci3120_private *devpriv = dev->private;
211 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
214 /* Check for Conversion time to be added */
215 devpriv->ui_EocEosConversionTime = data[2];
217 if (data[0] == APCI3120_EOS_MODE) {
219 /* Test the number of the channel */
220 for (i = 0; i < data[3]; i++) {
222 if (CR_CHAN(data[4 + i]) >= s->n_chan) {
223 dev_err(dev->class_dev, "bad channel list\n");
228 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
231 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
233 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
234 /* Copy channel list and Range List to devpriv */
235 devpriv->ui_AiNbrofChannels = data[3];
236 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
237 devpriv->ui_AiChannelList[i] = data[4 + i];
240 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
242 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
244 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
251 * This function will first check channel list is ok or not and then
252 * initialize the sequence RAM with the polarity, Gain,Channel number.
253 * If the last argument of function "check"is 1 then it only checks
254 * the channel list is ok or not.
256 static int apci3120_setup_chan_list(struct comedi_device *dev,
257 struct comedi_subdevice *s,
259 unsigned int *chanlist,
262 struct apci3120_private *devpriv = dev->private;
265 unsigned short us_TmpValue;
267 /* correct channel and range number check itself comedi/range.c */
270 dev_err(dev->class_dev,
271 "range/channel list is empty!\n");
274 /* All is ok, so we can setup channel/range list */
278 /* Code to set the PA and PR...Here it set PA to 0 */
279 devpriv->us_OutputRegister =
280 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
281 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
282 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
284 for (i = 0; i < n_chan; i++) {
285 /* store range list to card */
286 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number */
288 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
289 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
291 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar */
293 gain = CR_RANGE(chanlist[i]); /* get gain number */
294 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
295 us_TmpValue |= i << 8; /* To select the RAM LOCATION */
296 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
298 return 1; /* we can serve this with scan logic */
302 * Reads analog input in synchronous mode EOC and EOS is selected
303 * as per configured if no conversion time is set uses default
304 * conversion time 10 microsec.
306 static int apci3120_ai_insn_read(struct comedi_device *dev,
307 struct comedi_subdevice *s,
308 struct comedi_insn *insn,
311 struct apci3120_private *devpriv = dev->private;
312 unsigned short us_ConvertTiming, us_TmpValue, i;
315 /* fix conversion time to 10 us */
316 if (!devpriv->ui_EocEosConversionTime)
317 us_ConvertTiming = 10;
319 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
321 /* Clear software registers */
322 devpriv->b_TimerSelectMode = 0;
323 devpriv->b_ModeSelectRegister = 0;
324 devpriv->us_OutputRegister = 0;
326 if (insn->unused[0] == 222) { /* second insn read */
327 for (i = 0; i < insn->n; i++)
328 data[i] = devpriv->ui_AiReadData[i];
330 devpriv->tsk_Current = current; /* Save the current process task structure */
333 * Testing if board have the new Quartz and calculate the time value
334 * to set in the timer
336 us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
338 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
339 if ((us_TmpValue & 0x00B0) == 0x00B0
340 || !strcmp(dev->board_name, "apci3001")) {
341 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
344 ((us_ConvertTiming * 12926) / 10000) - 1;
347 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
349 switch (us_TmpValue) {
351 case APCI3120_EOC_MODE:
354 * Testing the interrupt flag and set the EOC bit Clears the FIFO
356 inw(dev->iobase + APCI3120_RESET_FIFO);
358 /* Initialize the sequence array */
359 if (!apci3120_setup_chan_list(dev, s, 1,
363 /* Initialize Timer 0 mode 4 */
364 devpriv->b_TimerSelectMode =
366 b_TimerSelectMode & 0xFC) |
367 APCI3120_TIMER_0_MODE_4;
368 outb(devpriv->b_TimerSelectMode,
369 dev->iobase + APCI3120_TIMER_CRT1);
371 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
372 devpriv->b_ModeSelectRegister =
374 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
376 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
378 /* Disables the EOS,DMA and enables the EOC interrupt */
379 devpriv->b_ModeSelectRegister =
381 b_ModeSelectRegister &
382 APCI3120_DISABLE_EOS_INT) |
383 APCI3120_ENABLE_EOC_INT;
384 inw(dev->iobase + 0);
387 devpriv->b_ModeSelectRegister =
389 b_ModeSelectRegister &
390 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
393 outb(devpriv->b_ModeSelectRegister,
394 dev->iobase + APCI3120_WRITE_MODE_SELECT);
397 devpriv->us_OutputRegister =
399 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
400 APCI3120_ENABLE_TIMER0;
401 outw(devpriv->us_OutputRegister,
402 dev->iobase + APCI3120_WR_ADDRESS);
406 b_DigitalOutputRegister) & 0xF0) |
407 APCI3120_SELECT_TIMER_0_WORD;
408 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
410 /* Set the conversion time */
411 outw(us_ConvertTiming,
412 dev->iobase + APCI3120_TIMER_VALUE);
415 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
417 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
420 /* Waiting for the end of conversion */
421 us_TmpValue = inw(dev->iobase +
423 } while ((us_TmpValue & APCI3120_EOC) ==
426 /* Read the result in FIFO and put it in insn data pointer */
427 us_TmpValue = inw(dev->iobase + 0);
430 inw(dev->iobase + APCI3120_RESET_FIFO);
435 case APCI3120_EOS_MODE:
437 inw(dev->iobase + 0);
438 /* Clears the FIFO */
439 inw(dev->iobase + APCI3120_RESET_FIFO);
440 /* clear PA PR and disable timer 0 */
442 devpriv->us_OutputRegister =
444 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
445 APCI3120_DISABLE_TIMER0;
447 outw(devpriv->us_OutputRegister,
448 dev->iobase + APCI3120_WR_ADDRESS);
450 if (!apci3120_setup_chan_list(dev, s,
451 devpriv->ui_AiNbrofChannels,
452 devpriv->ui_AiChannelList, 0))
455 /* Initialize Timer 0 mode 2 */
456 devpriv->b_TimerSelectMode =
458 b_TimerSelectMode & 0xFC) |
459 APCI3120_TIMER_0_MODE_2;
460 outb(devpriv->b_TimerSelectMode,
461 dev->iobase + APCI3120_TIMER_CRT1);
465 b_DigitalOutputRegister) & 0xF0) |
466 APCI3120_SELECT_TIMER_0_WORD;
467 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
469 /* Set the conversion time */
470 outw(us_ConvertTiming,
471 dev->iobase + APCI3120_TIMER_VALUE);
473 /* Set the scan bit */
474 devpriv->b_ModeSelectRegister =
476 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
477 outb(devpriv->b_ModeSelectRegister,
478 dev->iobase + APCI3120_WRITE_MODE_SELECT);
480 /* If Interrupt function is loaded */
481 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
482 /* Disables the EOC,DMA and enables the EOS interrupt */
483 devpriv->b_ModeSelectRegister =
485 b_ModeSelectRegister &
486 APCI3120_DISABLE_EOC_INT) |
487 APCI3120_ENABLE_EOS_INT;
488 inw(dev->iobase + 0);
491 devpriv->b_ModeSelectRegister =
493 b_ModeSelectRegister &
494 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
496 outb(devpriv->b_ModeSelectRegister,
497 dev->iobase + APCI3120_WRITE_MODE_SELECT);
499 inw(dev->iobase + APCI3120_RD_STATUS);
502 devpriv->us_OutputRegister =
504 us_OutputRegister | APCI3120_ENABLE_TIMER0;
505 outw(devpriv->us_OutputRegister,
506 dev->iobase + APCI3120_WR_ADDRESS);
508 /* Start conversion */
509 outw(0, dev->iobase + APCI3120_START_CONVERSION);
511 /* Waiting of end of conversion if interrupt is not installed */
512 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
513 /* Waiting the end of conversion */
515 us_TmpValue = inw(dev->iobase +
517 } while ((us_TmpValue & APCI3120_EOS) !=
520 for (i = 0; i < devpriv->ui_AiNbrofChannels;
522 /* Read the result in FIFO and write them in shared memory */
523 us_TmpValue = inw(dev->iobase);
524 data[i] = (unsigned int) us_TmpValue;
527 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults */
532 dev_err(dev->class_dev, "inputs wrong\n");
535 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable */
542 static int apci3120_reset(struct comedi_device *dev)
544 struct apci3120_private *devpriv = dev->private;
546 unsigned short us_TmpValue;
548 devpriv->ai_running = 0;
549 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
550 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
551 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
553 /* variables used in timer subdevice */
554 devpriv->b_Timer2Mode = 0;
555 devpriv->b_Timer2Interrupt = 0;
556 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
558 /* Disable all interrupts, watchdog for the anolog output */
559 devpriv->b_ModeSelectRegister = 0;
560 outb(devpriv->b_ModeSelectRegister,
561 dev->iobase + APCI3120_WRITE_MODE_SELECT);
563 /* Disables all counters, ext trigger and clears PA, PR */
564 devpriv->us_OutputRegister = 0;
565 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
567 inw(dev->iobase + 0); /* make a dummy read */
568 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
569 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
571 /* code to reset the RAM sequence */
572 for (i = 0; i < 16; i++) {
573 us_TmpValue = i << 8; /* select the location */
574 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
579 static int apci3120_exttrig_enable(struct comedi_device *dev)
581 struct apci3120_private *devpriv = dev->private;
583 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
584 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
588 static int apci3120_exttrig_disable(struct comedi_device *dev)
590 struct apci3120_private *devpriv = dev->private;
592 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
593 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
597 static int apci3120_cancel(struct comedi_device *dev,
598 struct comedi_subdevice *s)
600 struct apci3120_private *devpriv = dev->private;
602 /* Disable A2P Fifo write and AMWEN signal */
603 outw(0, devpriv->addon + 4);
605 /* Disable Bus Master ADD ON */
606 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
607 outw(0, devpriv->addon + 2);
608 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
609 outw(0, devpriv->addon + 2);
611 /* Disable BUS Master PCI */
612 outl(0, devpriv->amcc + AMCC_OP_REG_MCSR);
614 /* Disable ext trigger */
615 apci3120_exttrig_disable(dev);
617 devpriv->us_OutputRegister = 0;
620 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
621 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
623 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
625 /* DISABLE_ALL_INTERRUPT */
626 outb(APCI3120_DISABLE_ALL_INTERRUPT,
627 dev->iobase + APCI3120_WRITE_MODE_SELECT);
629 inb(dev->iobase + APCI3120_RESET_FIFO);
630 inw(dev->iobase + APCI3120_RD_STATUS);
631 devpriv->ui_AiActualScan = 0;
632 s->async->cur_chan = 0;
633 devpriv->ui_DmaActualBuffer = 0;
635 devpriv->ai_running = 0;
636 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
637 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
642 static int apci3120_ai_cmdtest(struct comedi_device *dev,
643 struct comedi_subdevice *s,
644 struct comedi_cmd *cmd)
648 /* Step 1 : check if triggers are trivially valid */
650 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
651 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
652 TRIG_TIMER | TRIG_FOLLOW);
653 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
654 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
655 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
660 /* Step 2a : make sure trigger sources are unique */
662 err |= cfc_check_trigger_is_unique(cmd->start_src);
663 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
664 err |= cfc_check_trigger_is_unique(cmd->stop_src);
666 /* Step 2b : and mutually compatible */
671 /* Step 3: check if arguments are trivially valid */
673 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
675 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
676 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
678 if (cmd->scan_begin_src == TRIG_TIMER) {
679 if (cmd->convert_arg)
680 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
683 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
686 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
687 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
689 if (cmd->stop_src == TRIG_COUNT)
690 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
692 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
697 /* step 4: fix up any arguments */
699 if (cmd->scan_begin_src == TRIG_TIMER &&
700 cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
701 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
712 * This is used for analog input cyclic acquisition.
713 * Performs the command operations.
714 * If DMA is configured does DMA initialization otherwise does the
715 * acquisition with EOS interrupt.
717 static int apci3120_cyclic_ai(int mode,
718 struct comedi_device *dev,
719 struct comedi_subdevice *s)
721 struct apci3120_private *devpriv = dev->private;
722 struct comedi_cmd *cmd = &s->async->cmd;
724 unsigned int ui_DelayTiming = 0;
725 unsigned int ui_TimerValue1 = 0;
726 unsigned int dmalen0 = 0;
727 unsigned int dmalen1 = 0;
728 unsigned int ui_TimerValue2 = 0;
729 unsigned int ui_TimerValue0;
730 unsigned int ui_ConvertTiming;
731 unsigned short us_TmpValue;
733 /* Resets the FIFO */
734 inb(dev->iobase + APCI3120_RESET_FIFO);
736 devpriv->ai_running = 1;
738 /* clear software registers */
739 devpriv->b_TimerSelectMode = 0;
740 devpriv->us_OutputRegister = 0;
741 devpriv->b_ModeSelectRegister = 0;
743 /* Clear Timer Write TC int */
744 outl(APCI3120_CLEAR_WRITE_TC_INT,
745 devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
747 /* Disables All Timer */
748 /* Sets PR and PA to 0 */
749 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
750 APCI3120_DISABLE_TIMER0 &
751 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
753 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
755 /* Resets the FIFO */
756 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
757 inb(dev->iobase + APCI3120_RESET_FIFO);
758 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
760 devpriv->ui_AiActualScan = 0;
761 s->async->cur_chan = 0;
762 devpriv->ui_DmaActualBuffer = 0;
764 /* value for timer2 minus -2 has to be done */
765 ui_TimerValue2 = cmd->stop_arg - 2;
766 ui_ConvertTiming = cmd->convert_arg;
769 ui_DelayTiming = cmd->scan_begin_arg;
771 /* Initializes the sequence array */
772 if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
776 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
778 /* EL241003 Begin: add this section to replace floats calculation by integer calculations */
779 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
780 if ((us_TmpValue & 0x00B0) == 0x00B0
781 || !strcmp(dev->board_name, "apci3001")) {
782 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
783 ui_TimerValue0 = ui_TimerValue0 / 1000;
786 ui_DelayTiming = ui_DelayTiming / 1000;
787 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
788 ui_TimerValue1 = ui_TimerValue1 / 100;
791 ui_ConvertTiming = ui_ConvertTiming / 1000;
792 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
793 ui_TimerValue0 = ui_TimerValue0 / 10000;
796 ui_DelayTiming = ui_DelayTiming / 1000;
797 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
798 ui_TimerValue1 = ui_TimerValue1 / 1000000;
803 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
804 apci3120_exttrig_enable(dev); /* activate EXT trigger */
807 /* init timer0 in mode 2 */
808 devpriv->b_TimerSelectMode =
810 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
811 outb(devpriv->b_TimerSelectMode,
812 dev->iobase + APCI3120_TIMER_CRT1);
816 b_DigitalOutputRegister) & 0xF0) |
817 APCI3120_SELECT_TIMER_0_WORD;
818 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
819 /* Set the conversion time */
820 outw(((unsigned short) ui_TimerValue0),
821 dev->iobase + APCI3120_TIMER_VALUE);
825 /* init timer1 in mode 2 */
826 devpriv->b_TimerSelectMode =
828 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
829 outb(devpriv->b_TimerSelectMode,
830 dev->iobase + APCI3120_TIMER_CRT1);
834 b_DigitalOutputRegister) & 0xF0) |
835 APCI3120_SELECT_TIMER_1_WORD;
836 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
837 /* Set the conversion time */
838 outw(((unsigned short) ui_TimerValue1),
839 dev->iobase + APCI3120_TIMER_VALUE);
841 /* init timer0 in mode 2 */
842 devpriv->b_TimerSelectMode =
844 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
845 outb(devpriv->b_TimerSelectMode,
846 dev->iobase + APCI3120_TIMER_CRT1);
850 b_DigitalOutputRegister) & 0xF0) |
851 APCI3120_SELECT_TIMER_0_WORD;
852 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
854 /* Set the conversion time */
855 outw(((unsigned short) ui_TimerValue0),
856 dev->iobase + APCI3120_TIMER_VALUE);
860 /* common for all modes */
861 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
862 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
863 APCI3120_DISABLE_SCAN;
864 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
866 outb(devpriv->b_ModeSelectRegister,
867 dev->iobase + APCI3120_WRITE_MODE_SELECT);
869 /* If DMA is disabled */
870 if (devpriv->us_UseDma == APCI3120_DISABLE) {
871 /* disable EOC and enable EOS */
872 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
873 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
875 devpriv->b_ModeSelectRegister =
877 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
878 APCI3120_ENABLE_EOS_INT;
879 outb(devpriv->b_ModeSelectRegister,
880 dev->iobase + APCI3120_WRITE_MODE_SELECT);
882 if (cmd->stop_src == TRIG_COUNT) {
884 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
885 * disable it (Set Bit D14 to 0)
887 devpriv->us_OutputRegister =
889 us_OutputRegister & APCI3120_DISABLE_TIMER2;
890 outw(devpriv->us_OutputRegister,
891 dev->iobase + APCI3120_WR_ADDRESS);
893 /* DISABLE TIMER intERRUPT */
894 devpriv->b_ModeSelectRegister =
896 b_ModeSelectRegister &
897 APCI3120_DISABLE_TIMER_INT & 0xEF;
898 outb(devpriv->b_ModeSelectRegister,
899 dev->iobase + APCI3120_WRITE_MODE_SELECT);
901 /* (1) Init timer 2 in mode 0 and write timer value */
902 devpriv->b_TimerSelectMode =
904 b_TimerSelectMode & 0x0F) |
905 APCI3120_TIMER_2_MODE_0;
906 outb(devpriv->b_TimerSelectMode,
907 dev->iobase + APCI3120_TIMER_CRT1);
909 /* Writing LOW unsigned short */
911 b_DigitalOutputRegister) & 0xF0) |
912 APCI3120_SELECT_TIMER_2_LOW_WORD;
913 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
914 outw(ui_TimerValue2 & 0xffff,
915 dev->iobase + APCI3120_TIMER_VALUE);
917 /* Writing HIGH unsigned short */
919 b_DigitalOutputRegister) & 0xF0) |
920 APCI3120_SELECT_TIMER_2_HIGH_WORD;
921 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
922 outw((ui_TimerValue2 >> 16) & 0xffff,
923 dev->iobase + APCI3120_TIMER_VALUE);
925 /* (2) Reset FC_TIMER BIT Clearing timer status register */
926 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
927 /* enable timer counter and disable watch dog */
928 devpriv->b_ModeSelectRegister =
930 b_ModeSelectRegister |
931 APCI3120_ENABLE_TIMER_COUNTER) &
932 APCI3120_DISABLE_WATCHDOG;
933 /* select EOS clock input for timer 2 */
934 devpriv->b_ModeSelectRegister =
936 b_ModeSelectRegister |
937 APCI3120_TIMER2_SELECT_EOS;
938 /* Enable timer2 interrupt */
939 devpriv->b_ModeSelectRegister =
941 b_ModeSelectRegister |
942 APCI3120_ENABLE_TIMER_INT;
943 outb(devpriv->b_ModeSelectRegister,
944 dev->iobase + APCI3120_WRITE_MODE_SELECT);
945 devpriv->b_Timer2Mode = APCI3120_COUNTER;
946 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
950 struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
951 struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
952 unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short);
954 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
956 /* Disables the EOC, EOS interrupt */
957 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
958 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
960 outb(devpriv->b_ModeSelectRegister,
961 dev->iobase + APCI3120_WRITE_MODE_SELECT);
963 dmalen0 = dmabuf0->size;
964 dmalen1 = dmabuf1->size;
966 if (cmd->stop_src == TRIG_COUNT) {
968 * Must we fill full first buffer? And must we fill
969 * full second buffer when first is once filled?
971 if (dmalen0 > (cmd->stop_arg * scan_bytes)) {
972 dmalen0 = cmd->stop_arg * scan_bytes;
973 } else if (dmalen1 > (cmd->stop_arg * scan_bytes -
975 dmalen1 = cmd->stop_arg * scan_bytes -
979 if (cmd->flags & CMDF_WAKE_EOS) {
980 /* don't we want wake up every scan? */
981 if (dmalen0 > scan_bytes) {
982 dmalen0 = scan_bytes;
983 if (cmd->scan_end_arg & 1)
986 if (dmalen1 > scan_bytes) {
987 dmalen1 = scan_bytes;
988 if (cmd->scan_end_arg & 1)
993 } else { /* isn't output buff smaller that our DMA buff? */
994 if (dmalen0 > s->async->prealloc_bufsz)
995 dmalen0 = s->async->prealloc_bufsz;
996 if (dmalen1 > s->async->prealloc_bufsz)
997 dmalen1 = s->async->prealloc_bufsz;
999 dmabuf0->use_size = dmalen0;
1000 dmabuf1->use_size = dmalen1;
1002 /* Initialize DMA */
1005 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1008 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
1009 devpriv->amcc + AMCC_OP_REG_AGCSTS);
1011 /* changed since 16 bit interface for add on */
1012 /* ENABLE BUS MASTER */
1013 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
1014 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
1016 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
1017 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
1020 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1023 outw(0x1000, devpriv->addon + 2);
1024 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1027 /* A2P FIFO MANAGEMENT */
1028 /* A2P fifo reset & transfer control enable */
1029 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1030 devpriv->amcc + APCI3120_AMCC_OP_MCSR);
1034 * beginning address of dma buf The 32 bit address of dma buffer
1035 * is converted into two 16 bit addresses Can done by using _attach
1036 * and put into into an array array used may be for differnet pages
1039 /* DMA Start Address Low */
1040 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
1041 outw(dmabuf0->hw & 0xffff, devpriv->addon + 2);
1043 /* DMA Start Address High */
1044 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
1045 outw((dmabuf0->hw >> 16) & 0xffff, devpriv->addon + 2);
1049 * amount of bytes to be transferred set transfer count used ADDON
1050 * MWTC register commented testing
1053 /* Nbr of acquisition LOW */
1054 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
1055 outw(dmabuf0->use_size & 0xffff, devpriv->addon + 2);
1057 /* Nbr of acquisition HIGH */
1058 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
1059 outw((dmabuf0->use_size >> 16) & 0xffff, devpriv->addon + 2);
1063 * To configure A2P FIFO testing outl(
1064 * FIFO_ADVANCE_ON_BYTE_2, devpriv->amcc + AMCC_OP_REG_INTCSR);
1067 /* A2P FIFO RESET */
1069 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1072 outl(0x04000000UL, devpriv->amcc + AMCC_OP_REG_MCSR);
1073 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1077 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1078 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1083 * initialise end of dma interrupt AINT_WRITE_COMPL =
1084 * ENABLE_WRITE_TC_INT(ADDI)
1086 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1087 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1088 APCI3120_ENABLE_WRITE_TC_INT),
1089 devpriv->amcc + AMCC_OP_REG_INTCSR);
1091 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1092 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1093 outw(3, devpriv->addon + 4);
1094 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1096 /* A2P FIFO RESET */
1097 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1098 outl(0x04000000UL, devpriv->amcc + APCI3120_AMCC_OP_MCSR);
1099 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1102 if (devpriv->us_UseDma == APCI3120_DISABLE &&
1103 cmd->stop_src == TRIG_COUNT) {
1104 /* set gate 2 to start conversion */
1105 devpriv->us_OutputRegister =
1106 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1107 outw(devpriv->us_OutputRegister,
1108 dev->iobase + APCI3120_WR_ADDRESS);
1113 /* set gate 0 to start conversion */
1114 devpriv->us_OutputRegister =
1115 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1116 outw(devpriv->us_OutputRegister,
1117 dev->iobase + APCI3120_WR_ADDRESS);
1120 /* set gate 0 and gate 1 */
1121 devpriv->us_OutputRegister =
1122 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1123 devpriv->us_OutputRegister =
1124 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1125 outw(devpriv->us_OutputRegister,
1126 dev->iobase + APCI3120_WR_ADDRESS);
1136 * Does asynchronous acquisition.
1137 * Determines the mode 1 or 2.
1139 static int apci3120_ai_cmd(struct comedi_device *dev,
1140 struct comedi_subdevice *s)
1142 struct apci3120_private *devpriv = dev->private;
1143 struct comedi_cmd *cmd = &s->async->cmd;
1145 /* loading private structure with cmd structure inputs */
1146 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
1148 if (cmd->start_src == TRIG_EXT)
1149 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
1151 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1153 if (cmd->scan_begin_src == TRIG_FOLLOW)
1154 return apci3120_cyclic_ai(1, dev, s);
1156 return apci3120_cyclic_ai(2, dev, s);
1160 * This function copies the data from DMA buffer to the Comedi buffer.
1162 static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1163 struct comedi_subdevice *s,
1164 unsigned short *dma_buffer,
1165 unsigned int num_samples)
1167 struct apci3120_private *devpriv = dev->private;
1168 struct comedi_cmd *cmd = &s->async->cmd;
1170 devpriv->ui_AiActualScan +=
1171 (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
1172 s->async->cur_chan += num_samples;
1173 s->async->cur_chan %= cmd->scan_end_arg;
1175 comedi_buf_write_samples(s, dma_buffer, num_samples);
1179 * This is a handler for the DMA interrupt.
1180 * This function copies the data to Comedi Buffer.
1181 * For continuous DMA it reinitializes the DMA operation.
1182 * For single mode DMA it stop the acquisition.
1184 static void apci3120_interrupt_dma(int irq, void *d)
1186 struct comedi_device *dev = d;
1187 struct apci3120_private *devpriv = dev->private;
1188 struct comedi_subdevice *s = dev->read_subdev;
1189 struct comedi_cmd *cmd = &s->async->cmd;
1190 struct apci3120_dmabuf *dmabuf;
1191 unsigned int samplesinbuf;
1192 unsigned int ui_Tmp;
1194 dmabuf = &devpriv->dmabuf[devpriv->ui_DmaActualBuffer];
1196 samplesinbuf = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC);
1198 if (samplesinbuf < dmabuf->use_size)
1199 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
1200 if (samplesinbuf & 1) {
1201 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
1202 apci3120_cancel(dev, s);
1205 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1206 if (devpriv->b_DmaDoubleBuffer) {
1207 /* switch DMA buffers if is used double buffering */
1208 struct apci3120_dmabuf *next_dmabuf;
1210 next_dmabuf = &devpriv->dmabuf[1 - devpriv->ui_DmaActualBuffer];
1212 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1213 outl(ui_Tmp, devpriv->amcc + AMCC_OP_REG_AGCSTS);
1215 /* changed since 16 bit interface for add on */
1216 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
1217 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
1218 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
1219 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2); /* 0x1000 is out putted in windows driver */
1221 /* DMA Start Address Low */
1222 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
1223 outw(next_dmabuf->hw & 0xffff, devpriv->addon + 2);
1225 /* DMA Start Address High */
1226 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
1227 outw((next_dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
1229 /* Nbr of acquisition LOW */
1230 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
1231 outw(next_dmabuf->use_size & 0xffff, devpriv->addon + 2);
1233 /* Nbr of acquisition HIGH */
1234 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
1235 outw((next_dmabuf->use_size > 16) & 0xffff, devpriv->addon + 2);
1238 * To configure A2P FIFO
1239 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1240 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1242 outw(3, devpriv->addon + 4);
1243 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1244 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1245 APCI3120_ENABLE_WRITE_TC_INT,
1246 devpriv->amcc + AMCC_OP_REG_INTCSR);
1250 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, dmabuf->virt,
1253 if (!(cmd->flags & CMDF_WAKE_EOS))
1254 s->async->events |= COMEDI_CB_EOS;
1256 if (cmd->stop_src == TRIG_COUNT)
1257 if (devpriv->ui_AiActualScan >= cmd->stop_arg) {
1258 /* all data sampled */
1259 s->async->events |= COMEDI_CB_EOA;
1263 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1264 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1267 * restart DMA if is not used double buffering
1268 * ADDED REINITIALISE THE DMA
1270 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
1271 devpriv->amcc + AMCC_OP_REG_AGCSTS);
1273 /* changed since 16 bit interface for add on */
1274 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
1275 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
1276 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
1277 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
1279 * A2P FIFO MANAGEMENT
1280 * A2P fifo reset & transfer control enable
1282 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1283 devpriv->amcc + AMCC_OP_REG_MCSR);
1285 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
1286 outw(dmabuf->hw & 0xffff, devpriv->addon + 2);
1287 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
1288 outw((dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
1290 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
1291 outw(dmabuf->use_size & 0xffff, devpriv->addon + 2);
1292 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
1293 outw((dmabuf->use_size >> 16) & 0xffff, devpriv->addon + 2);
1296 * To configure A2P FIFO
1297 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1298 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1300 outw(3, devpriv->addon + 4);
1301 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1302 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1303 APCI3120_ENABLE_WRITE_TC_INT,
1304 devpriv->amcc + AMCC_OP_REG_INTCSR);
1309 * This function handles EOS interrupt.
1310 * This function copies the acquired data(from FIFO) to Comedi buffer.
1312 static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
1314 struct apci3120_private *devpriv = dev->private;
1315 struct comedi_subdevice *s = dev->read_subdev;
1319 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
1320 val = inw(dev->iobase + 0);
1321 comedi_buf_write_samples(s, &val, 1);
1327 static irqreturn_t apci3120_interrupt(int irq, void *d)
1329 struct comedi_device *dev = d;
1330 struct apci3120_private *devpriv = dev->private;
1331 struct comedi_subdevice *s = dev->read_subdev;
1332 unsigned short int_daq;
1333 unsigned int int_amcc, ui_Check, i;
1334 unsigned short us_TmpValue;
1335 unsigned char b_DummyRead;
1339 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1340 int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
1342 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1343 dev_err(dev->class_dev, "IRQ from unknown source\n");
1347 outl(int_amcc | 0x00ff0000, devpriv->amcc + AMCC_OP_REG_INTCSR);
1349 int_daq = (int_daq >> 12) & 0xF;
1351 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1352 /* Disable ext trigger */
1353 apci3120_exttrig_disable(dev);
1354 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1356 /* clear the timer 2 interrupt */
1357 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1359 if (int_amcc & MASTER_ABORT_INT)
1360 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
1361 if (int_amcc & TARGET_ABORT_INT)
1362 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
1364 /* Ckeck if EOC interrupt */
1365 if (((int_daq & 0x8) == 0)
1366 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1367 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1369 /* Read the AI Value */
1370 devpriv->ui_AiReadData[0] = inw(dev->iobase + 0);
1371 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1372 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1374 /* Disable EOC Interrupt */
1375 devpriv->b_ModeSelectRegister =
1377 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1378 outb(devpriv->b_ModeSelectRegister,
1379 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1383 /* Check If EOS interrupt */
1384 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1386 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
1388 if (devpriv->ai_running) {
1390 apci3120_interrupt_handle_eos(dev);
1391 devpriv->ui_AiActualScan++;
1392 devpriv->b_ModeSelectRegister =
1394 b_ModeSelectRegister |
1395 APCI3120_ENABLE_EOS_INT;
1396 outb(devpriv->b_ModeSelectRegister,
1398 APCI3120_WRITE_MODE_SELECT);
1401 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1403 us_TmpValue = inw(dev->iobase + 0);
1404 devpriv->ui_AiReadData[i] =
1405 (unsigned int) us_TmpValue;
1407 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1408 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1410 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1415 devpriv->b_ModeSelectRegister =
1417 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1418 outb(devpriv->b_ModeSelectRegister,
1419 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1420 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1421 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1425 /* Timer2 interrupt */
1426 if (int_daq & 0x1) {
1428 switch (devpriv->b_Timer2Mode) {
1429 case APCI3120_COUNTER:
1430 devpriv->b_ModeSelectRegister =
1432 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1433 outb(devpriv->b_ModeSelectRegister,
1434 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1437 devpriv->us_OutputRegister =
1439 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1440 outw(devpriv->us_OutputRegister,
1441 dev->iobase + APCI3120_WR_ADDRESS);
1443 s->async->events |= COMEDI_CB_EOA;
1446 case APCI3120_TIMER:
1448 /* Send a signal to from kernel to user space */
1449 send_sig(SIGIO, devpriv->tsk_Current, 0);
1452 case APCI3120_WATCHDOG:
1454 /* Send a signal to from kernel to user space */
1455 send_sig(SIGIO, devpriv->tsk_Current, 0);
1460 /* disable Timer Interrupt */
1461 devpriv->b_ModeSelectRegister =
1463 b_ModeSelectRegister &
1464 APCI3120_DISABLE_TIMER_INT;
1466 outb(devpriv->b_ModeSelectRegister,
1467 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1471 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1475 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1476 if (devpriv->ai_running) {
1478 /* Clear Timer Write TC int */
1479 outl(APCI3120_CLEAR_WRITE_TC_INT,
1480 devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
1482 /* Clears the timer status register */
1483 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1484 /* do some data transfer */
1485 apci3120_interrupt_dma(irq, d);
1487 /* Stops the Timer */
1489 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1490 APCI3120_DISABLE_TIMER1,
1491 dev->iobase + APCI3120_WR_ADDRESS);
1495 comedi_handle_events(dev, s);
1503 * data[0] = TIMER configure as timer
1504 * = WATCHDOG configure as watchdog
1505 * data[1] = Timer constant
1506 * data[2] = Timer2 interrupt (1)enable or(0) disable
1508 static int apci3120_config_insn_timer(struct comedi_device *dev,
1509 struct comedi_subdevice *s,
1510 struct comedi_insn *insn,
1513 struct apci3120_private *devpriv = dev->private;
1514 unsigned int ui_Timervalue2;
1515 unsigned short us_TmpValue;
1516 unsigned char b_Tmp;
1519 dev_err(dev->class_dev, "No timer constant!\n");
1521 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1523 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1525 us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
1528 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1529 * is an APCI3001 and calculate the time value to set in the timer
1531 if ((us_TmpValue & 0x00B0) == 0x00B0
1532 || !strcmp(dev->board_name, "apci3001")) {
1533 /* Calculate the time value to set in the timer */
1534 ui_Timervalue2 = ui_Timervalue2 / 50;
1536 /* Calculate the time value to set in the timer */
1537 ui_Timervalue2 = ui_Timervalue2 / 70;
1540 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1541 devpriv->us_OutputRegister =
1542 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1543 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1545 /* Disable TIMER Interrupt */
1546 devpriv->b_ModeSelectRegister =
1548 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1550 /* Disable Eoc and Eos Interrupts */
1551 devpriv->b_ModeSelectRegister =
1553 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1554 APCI3120_DISABLE_EOS_INT;
1555 outb(devpriv->b_ModeSelectRegister,
1556 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1557 if (data[0] == APCI3120_TIMER) { /* initialize timer */
1558 /* Set the Timer 2 in mode 2(Timer) */
1559 devpriv->b_TimerSelectMode =
1561 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1562 outb(devpriv->b_TimerSelectMode,
1563 dev->iobase + APCI3120_TIMER_CRT1);
1566 * Configure the timer 2 for writing the LOW unsigned short of timer
1567 * is Delay value You must make a b_tmp variable with
1568 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1569 * you can set the digital output and configure the timer 2,and if
1570 * you don't make this, digital output are erase (Set to 0)
1573 /* Writing LOW unsigned short */
1575 b_DigitalOutputRegister) & 0xF0) |
1576 APCI3120_SELECT_TIMER_2_LOW_WORD;
1577 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1578 outw(ui_Timervalue2 & 0xffff,
1579 dev->iobase + APCI3120_TIMER_VALUE);
1581 /* Writing HIGH unsigned short */
1583 b_DigitalOutputRegister) & 0xF0) |
1584 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1585 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1586 outw((ui_Timervalue2 >> 16) & 0xffff,
1587 dev->iobase + APCI3120_TIMER_VALUE);
1588 /* timer2 in Timer mode enabled */
1589 devpriv->b_Timer2Mode = APCI3120_TIMER;
1591 } else { /* Initialize Watch dog */
1593 /* Set the Timer 2 in mode 5(Watchdog) */
1594 devpriv->b_TimerSelectMode =
1596 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1597 outb(devpriv->b_TimerSelectMode,
1598 dev->iobase + APCI3120_TIMER_CRT1);
1601 * Configure the timer 2 for writing the LOW unsigned short of timer
1602 * is Delay value You must make a b_tmp variable with
1603 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1604 * you can set the digital output and configure the timer 2,and if
1605 * you don't make this, digital output are erase (Set to 0)
1608 /* Writing LOW unsigned short */
1610 b_DigitalOutputRegister) & 0xF0) |
1611 APCI3120_SELECT_TIMER_2_LOW_WORD;
1612 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1613 outw(ui_Timervalue2 & 0xffff,
1614 dev->iobase + APCI3120_TIMER_VALUE);
1616 /* Writing HIGH unsigned short */
1618 b_DigitalOutputRegister) & 0xF0) |
1619 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1620 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1622 outw((ui_Timervalue2 >> 16) & 0xffff,
1623 dev->iobase + APCI3120_TIMER_VALUE);
1624 /* watchdog enabled */
1625 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1634 * To start and stop the timer
1636 * data[0] = 1 (start)
1638 * = 2 (write new value)
1639 * data[1] = new value
1641 * devpriv->b_Timer2Mode = 0 DISABLE
1645 static int apci3120_write_insn_timer(struct comedi_device *dev,
1646 struct comedi_subdevice *s,
1647 struct comedi_insn *insn,
1650 struct apci3120_private *devpriv = dev->private;
1651 unsigned int ui_Timervalue2 = 0;
1652 unsigned short us_TmpValue;
1653 unsigned char b_Tmp;
1655 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1656 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1657 dev_err(dev->class_dev, "timer2 not configured\n");
1661 if (data[0] == 2) { /* write new value */
1662 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1663 dev_err(dev->class_dev,
1664 "timer2 not configured in TIMER MODE\n");
1669 ui_Timervalue2 = data[1];
1675 case APCI3120_START:
1677 /* Reset FC_TIMER BIT */
1678 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1679 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1681 devpriv->b_ModeSelectRegister =
1682 devpriv->b_ModeSelectRegister & 0x0B;
1683 } else { /* start watch dog */
1684 /* Enable WatchDog */
1685 devpriv->b_ModeSelectRegister =
1687 b_ModeSelectRegister & 0x0B) |
1688 APCI3120_ENABLE_WATCHDOG;
1691 /* enable disable interrupt */
1692 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1694 devpriv->b_ModeSelectRegister =
1696 b_ModeSelectRegister |
1697 APCI3120_ENABLE_TIMER_INT;
1698 /* save the task structure to pass info to user */
1699 devpriv->tsk_Current = current;
1702 devpriv->b_ModeSelectRegister =
1704 b_ModeSelectRegister &
1705 APCI3120_DISABLE_TIMER_INT;
1707 outb(devpriv->b_ModeSelectRegister,
1708 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1710 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1711 /* For Timer mode is Gate2 must be activated timer started */
1712 devpriv->us_OutputRegister =
1714 us_OutputRegister | APCI3120_ENABLE_TIMER2;
1715 outw(devpriv->us_OutputRegister,
1716 dev->iobase + APCI3120_WR_ADDRESS);
1722 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1724 devpriv->b_ModeSelectRegister =
1726 b_ModeSelectRegister &
1727 APCI3120_DISABLE_TIMER_COUNTER;
1729 /* Disable WatchDog */
1730 devpriv->b_ModeSelectRegister =
1732 b_ModeSelectRegister &
1733 APCI3120_DISABLE_WATCHDOG;
1735 /* Disable timer interrupt */
1736 devpriv->b_ModeSelectRegister =
1738 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
1740 /* Write above states to register */
1741 outb(devpriv->b_ModeSelectRegister,
1742 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1745 devpriv->us_OutputRegister =
1746 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
1747 outw(devpriv->us_OutputRegister,
1748 dev->iobase + APCI3120_WR_ADDRESS);
1750 /* Reset FC_TIMER BIT */
1751 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1755 case 2: /* write new value to Timer */
1756 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1757 dev_err(dev->class_dev,
1758 "timer2 not configured in TIMER MODE\n");
1761 us_TmpValue = inw(dev->iobase + APCI3120_RD_STATUS);
1764 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1765 * is an APCI3001 and calculate the time value to set in the timer
1767 if ((us_TmpValue & 0x00B0) == 0x00B0
1768 || !strcmp(dev->board_name, "apci3001")) {
1769 /* Calculate the time value to set in the timer */
1770 ui_Timervalue2 = ui_Timervalue2 / 50;
1772 /* Calculate the time value to set in the timer */
1773 ui_Timervalue2 = ui_Timervalue2 / 70;
1775 /* Writing LOW unsigned short */
1777 b_DigitalOutputRegister) & 0xF0) |
1778 APCI3120_SELECT_TIMER_2_LOW_WORD;
1779 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1781 outw(ui_Timervalue2 & 0xffff,
1782 dev->iobase + APCI3120_TIMER_VALUE);
1784 /* Writing HIGH unsigned short */
1786 b_DigitalOutputRegister) & 0xF0) |
1787 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1788 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1790 outw((ui_Timervalue2 >> 16) & 0xffff,
1791 dev->iobase + APCI3120_TIMER_VALUE);
1795 return -EINVAL; /* Not a valid input */
1802 * Read the Timer value
1804 * for Timer: data[0]= Timer constant
1806 * for watchdog: data[0] = 0 (still running)
1809 static int apci3120_read_insn_timer(struct comedi_device *dev,
1810 struct comedi_subdevice *s,
1811 struct comedi_insn *insn,
1814 struct apci3120_private *devpriv = dev->private;
1815 unsigned char b_Tmp;
1816 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
1818 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1819 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1820 dev_err(dev->class_dev, "timer2 not configured\n");
1822 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1824 /* Read the LOW unsigned short of Timer 2 register */
1826 b_DigitalOutputRegister) & 0xF0) |
1827 APCI3120_SELECT_TIMER_2_LOW_WORD;
1828 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1830 us_TmpValue = inw(dev->iobase + APCI3120_TIMER_VALUE);
1832 /* Read the HIGH unsigned short of Timer 2 register */
1834 b_DigitalOutputRegister) & 0xF0) |
1835 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1836 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1838 us_TmpValue_2 = inw(dev->iobase + APCI3120_TIMER_VALUE);
1840 /* combining both words */
1841 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
1843 } else { /* Read watch dog status */
1845 us_StatusValue = inw(dev->iobase + APCI3120_RD_STATUS);
1847 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
1848 if (us_StatusValue == 1) {
1849 /* RESET FC_TIMER BIT */
1850 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1852 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
1857 static int apci3120_di_insn_bits(struct comedi_device *dev,
1858 struct comedi_subdevice *s,
1859 struct comedi_insn *insn,
1864 /* the input channels are bits 11:8 of the status reg */
1865 val = inw(dev->iobase + APCI3120_RD_STATUS);
1866 data[1] = (val >> 8) & 0xf;
1871 static int apci3120_do_insn_bits(struct comedi_device *dev,
1872 struct comedi_subdevice *s,
1873 struct comedi_insn *insn,
1876 struct apci3120_private *devpriv = dev->private;
1878 if (comedi_dio_update_state(s, data)) {
1879 /* The do channels are bits 7:4 of the do register */
1880 devpriv->b_DigitalOutputRegister = s->state << 4;
1882 outb(devpriv->b_DigitalOutputRegister,
1883 dev->iobase + APCI3120_DIGITAL_OUTPUT);
1891 static int apci3120_ao_ready(struct comedi_device *dev,
1892 struct comedi_subdevice *s,
1893 struct comedi_insn *insn,
1894 unsigned long context)
1896 unsigned int status;
1898 status = inw(dev->iobase + APCI3120_RD_STATUS);
1899 if (status & 0x0001) /* waiting for DA_READY */
1904 static int apci3120_ao_insn_write(struct comedi_device *dev,
1905 struct comedi_subdevice *s,
1906 struct comedi_insn *insn,
1909 unsigned int chan = CR_CHAN(insn->chanspec);
1912 for (i = 0; i < insn->n; i++) {
1913 unsigned int val = data[i];
1916 ret = comedi_timeout(dev, s, insn, apci3120_ao_ready, 0);
1920 outw(APCI3120_AO_MUX(chan) | APCI3120_AO_DATA(val),
1921 dev->iobase + APCI3120_AO_REG(chan));
1923 s->readback[chan] = val;