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.
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 You should also find the complete GPL in the COPYING file accompanying this source code.
25 +-----------------------------------------------------------------------+
26 | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
27 +-----------------------------------------------------------------------+
28 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
29 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
30 +-----------------------------------------------------------------------+
31 | Project : APCI-3120 | Compiler : GCC |
32 | Module name : hwdrv_apci3120.c| Version : 2.96 |
33 +-------------------------------+---------------------------------------+
34 | Project manager: Eric Stolz | Date : 02/12/2002 |
35 +-----------------------------------------------------------------------+
36 | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
37 +-----------------------------------------------------------------------+
39 +-----------------------------------------------------------------------+
40 | Date | Author | Description of updates |
41 +----------+-----------+------------------------------------------------+
44 +----------+-----------+------------------------------------------------+
48 * ADDON RELATED ADDITIONS
51 #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00
52 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200
53 #define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L
54 #define APCI3120_AMWEN_ENABLE 0x02
55 #define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01
56 #define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L
57 #define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L
58 #define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L
59 #define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0
60 #define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0
61 #define APCI3120_DISABLE_BUS_MASTER_PCI 0x0
63 /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
64 #define APCI3120_ADD_ON_AGCSTS_LOW 0x3C
65 #define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2)
66 #define APCI3120_ADD_ON_MWAR_LOW 0x24
67 #define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2)
68 #define APCI3120_ADD_ON_MWTC_LOW 0x058
69 #define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2)
72 #define APCI3120_AMCC_OP_MCSR 0x3C
73 #define APCI3120_AMCC_OP_REG_INTCSR 0x38
75 /* for transfer count enable bit */
76 #define AGCSTS_TC_ENABLE 0x10000000
78 /* used for test on mixture of BIP/UNI ranges */
79 #define APCI3120_BIPOLAR_RANGES 4
81 #define APCI3120_ADDRESS_RANGE 16
83 #define APCI3120_DISABLE 0
84 #define APCI3120_ENABLE 1
86 #define APCI3120_START 1
87 #define APCI3120_STOP 0
89 #define APCI3120_EOC_MODE 1
90 #define APCI3120_EOS_MODE 2
91 #define APCI3120_DMA_MODE 3
93 /* DIGITAL INPUT-OUTPUT DEFINE */
95 #define APCI3120_DIGITAL_OUTPUT 0x0d
96 #define APCI3120_RD_STATUS 0x02
97 #define APCI3120_RD_FIFO 0x00
99 /* digital output insn_write ON /OFF selection */
100 #define APCI3120_SET4DIGITALOUTPUTON 1
101 #define APCI3120_SET4DIGITALOUTPUTOFF 0
103 /* analog output SELECT BIT */
104 #define APCI3120_ANALOG_OP_CHANNEL_1 0x0000
105 #define APCI3120_ANALOG_OP_CHANNEL_2 0x4000
106 #define APCI3120_ANALOG_OP_CHANNEL_3 0x8000
107 #define APCI3120_ANALOG_OP_CHANNEL_4 0xc000
108 #define APCI3120_ANALOG_OP_CHANNEL_5 0x0000
109 #define APCI3120_ANALOG_OP_CHANNEL_6 0x4000
110 #define APCI3120_ANALOG_OP_CHANNEL_7 0x8000
111 #define APCI3120_ANALOG_OP_CHANNEL_8 0xc000
113 /* Enable external trigger bit in nWrAddress */
114 #define APCI3120_ENABLE_EXT_TRIGGER 0x8000
116 /* ANALOG OUTPUT AND INPUT DEFINE */
117 #define APCI3120_UNIPOLAR 0x80
118 #define APCI3120_BIPOLAR 0x00
119 #define APCI3120_ANALOG_OUTPUT_1 0x08
120 #define APCI3120_ANALOG_OUTPUT_2 0x0a
121 #define APCI3120_1_GAIN 0x00
122 #define APCI3120_2_GAIN 0x10
123 #define APCI3120_5_GAIN 0x20
124 #define APCI3120_10_GAIN 0x30
125 #define APCI3120_SEQ_RAM_ADDRESS 0x06
126 #define APCI3120_RESET_FIFO 0x0c
127 #define APCI3120_TIMER_0_MODE_2 0x01
128 #define APCI3120_TIMER_0_MODE_4 0x2
129 #define APCI3120_SELECT_TIMER_0_WORD 0x00
130 #define APCI3120_ENABLE_TIMER0 0x1000
131 #define APCI3120_CLEAR_PR 0xf0ff
132 #define APCI3120_CLEAR_PA 0xfff0
133 #define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
136 #define APCI3120_ENABLE_SCAN 0x8
137 #define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN)
138 #define APCI3120_ENABLE_EOS_INT 0x2
140 #define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT)
141 #define APCI3120_ENABLE_EOC_INT 0x1
142 #define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT)
143 #define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER \
144 (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
145 #define APCI3120_DISABLE_ALL_INTERRUPT \
146 (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
148 /* status register bits */
149 #define APCI3120_EOC 0x8000
150 #define APCI3120_EOS 0x2000
152 /* software trigger dummy register */
153 #define APCI3120_START_CONVERSION 0x02
156 #define APCI3120_QUARTZ_A 70
157 #define APCI3120_QUARTZ_B 50
158 #define APCI3120_TIMER 1
159 #define APCI3120_WATCHDOG 2
160 #define APCI3120_TIMER_DISABLE 0
161 #define APCI3120_TIMER_ENABLE 1
162 #define APCI3120_ENABLE_TIMER2 0x4000
163 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
164 #define APCI3120_ENABLE_TIMER_INT 0x04
165 #define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT)
166 #define APCI3120_WRITE_MODE_SELECT 0x0e
167 #define APCI3120_SELECT_TIMER_0_WORD 0x00
168 #define APCI3120_SELECT_TIMER_1_WORD 0x01
169 #define APCI3120_TIMER_1_MODE_2 0x4
171 /* $$ BIT FOR MODE IN nCsTimerCtr1 */
172 #define APCI3120_TIMER_2_MODE_0 0x0
173 #define APCI3120_TIMER_2_MODE_2 0x10
174 #define APCI3120_TIMER_2_MODE_5 0x30
176 /* $$ BIT FOR MODE IN nCsTimerCtr0 */
177 #define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02
178 #define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03
180 #define APCI3120_TIMER_CRT0 0x0d
181 #define APCI3120_TIMER_CRT1 0x0c
183 #define APCI3120_TIMER_VALUE 0x04
184 #define APCI3120_TIMER_STATUS_REGISTER 0x0d
185 #define APCI3120_RD_STATUS 0x02
186 #define APCI3120_WR_ADDRESS 0x00
187 #define APCI3120_ENABLE_WATCHDOG 0x20
188 #define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG)
189 #define APCI3120_ENABLE_TIMER_COUNTER 0x10
190 #define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER)
191 #define APCI3120_FC_TIMER 0x1000
192 #define APCI3120_ENABLE_TIMER0 0x1000
193 #define APCI3120_ENABLE_TIMER1 0x2000
194 #define APCI3120_ENABLE_TIMER2 0x4000
195 #define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0)
196 #define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1)
197 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
199 #define APCI3120_TIMER2_SELECT_EOS 0xc0
200 #define APCI3120_COUNTER 3
201 #define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & \
202 APCI3120_DISABLE_TIMER1 & \
203 APCI3120_DISABLE_TIMER2)
205 #define MAX_ANALOGINPUT_CHANNELS 32
207 struct str_AnalogReadInformation {
209 unsigned char b_Type;
210 /* Interrupt use or not */
211 unsigned char b_InterruptFlag;
212 /* Selection of the conversion time */
213 unsigned int ui_ConvertTiming;
214 /* Number of channel to read */
215 unsigned char b_NbrOfChannel;
216 /* Number of the channel to be read */
217 unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS];
218 /* Gain of each channel */
219 unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS];
222 /* ANALOG INPUT RANGE */
223 static const struct comedi_lrange range_apci3120_ai = {
236 /* ANALOG OUTPUT RANGE */
237 static const struct comedi_lrange range_apci3120_ao = {
245 /* FUNCTION DEFINITIONS */
248 +----------------------------------------------------------------------------+
249 | ANALOG INPUT SUBDEVICE |
250 +----------------------------------------------------------------------------+
253 static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,
254 struct comedi_subdevice *s,
255 struct comedi_insn *insn,
258 const struct addi_board *this_board = comedi_board(dev);
259 struct addi_private *devpriv = dev->private;
262 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
265 /* Check for Conversion time to be added ?? */
266 devpriv->ui_EocEosConversionTime = data[2];
268 if (data[0] == APCI3120_EOS_MODE) {
270 /* Test the number of the channel */
271 for (i = 0; i < data[3]; i++) {
273 if (CR_CHAN(data[4 + i]) >=
274 this_board->i_NbrAiChannel) {
275 printk("bad channel list\n");
280 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
283 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
285 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
286 /* Copy channel list and Range List to devpriv */
288 devpriv->ui_AiNbrofChannels = data[3];
289 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
290 devpriv->ui_AiChannelList[i] = data[4 + i];
293 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
295 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
297 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
304 * This function will first check channel list is ok or not and then
305 * initialize the sequence RAM with the polarity, Gain,Channel number.
306 * If the last argument of function "check"is 1 then it only checks
307 * the channel list is ok or not.
309 static int i_APCI3120_SetupChannelList(struct comedi_device *dev,
310 struct comedi_subdevice *s,
312 unsigned int *chanlist,
315 struct addi_private *devpriv = dev->private;
316 unsigned int i; /* , differencial=0, bipolar=0; */
318 unsigned short us_TmpValue;
320 /* correct channel and range number check itself comedi/range.c */
323 comedi_error(dev, "range/channel list is empty!");
326 /* All is ok, so we can setup channel/range list */
330 /* Code to set the PA and PR...Here it set PA to 0.. */
331 devpriv->us_OutputRegister =
332 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
333 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
334 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
336 for (i = 0; i < n_chan; i++) {
337 /* store range list to card */
338 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
340 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
341 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
343 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
345 gain = CR_RANGE(chanlist[i]); /* get gain number */
346 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
347 us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
348 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
350 printk("\n Gain = %i",
351 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
352 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
353 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
355 return 1; /* we can serve this with scan logic */
359 * Reads analog input in synchronous mode EOC and EOS is selected
360 * as per configured if no conversion time is set uses default
361 * conversion time 10 microsec.
363 static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
364 struct comedi_subdevice *s,
365 struct comedi_insn *insn,
368 const struct addi_board *this_board = comedi_board(dev);
369 struct addi_private *devpriv = dev->private;
370 unsigned short us_ConvertTiming, us_TmpValue, i;
373 /* fix conversion time to 10 us */
374 if (!devpriv->ui_EocEosConversionTime) {
375 printk("No timer0 Value using 10 us\n");
376 us_ConvertTiming = 10;
378 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
380 /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
382 /* Clear software registers */
383 devpriv->b_TimerSelectMode = 0;
384 devpriv->b_ModeSelectRegister = 0;
385 devpriv->us_OutputRegister = 0;
386 /* devpriv->b_DigitalOutputRegister=0; */
388 if (insn->unused[0] == 222) { /* second insn read */
389 for (i = 0; i < insn->n; i++)
390 data[i] = devpriv->ui_AiReadData[i];
392 devpriv->tsk_Current = current; /* Save the current process task structure */
394 * Testing if board have the new Quartz and calculate the time value
395 * to set in the timer
399 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
401 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
402 if ((us_TmpValue & 0x00B0) == 0x00B0
403 || !strcmp(this_board->pc_DriverName, "apci3001")) {
404 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
407 ((us_ConvertTiming * 12926) / 10000) - 1;
410 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
412 switch (us_TmpValue) {
414 case APCI3120_EOC_MODE:
417 * Testing the interrupt flag and set the EOC bit Clears the FIFO
419 inw(devpriv->iobase + APCI3120_RESET_FIFO);
421 /* Initialize the sequence array */
423 /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
425 if (!i_APCI3120_SetupChannelList(dev, s, 1,
429 /* Initialize Timer 0 mode 4 */
430 devpriv->b_TimerSelectMode =
432 b_TimerSelectMode & 0xFC) |
433 APCI3120_TIMER_0_MODE_4;
434 outb(devpriv->b_TimerSelectMode,
435 devpriv->iobase + APCI3120_TIMER_CRT1);
437 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
438 devpriv->b_ModeSelectRegister =
440 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
442 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
444 /* Disables the EOS,DMA and enables the EOC interrupt */
445 devpriv->b_ModeSelectRegister =
447 b_ModeSelectRegister &
448 APCI3120_DISABLE_EOS_INT) |
449 APCI3120_ENABLE_EOC_INT;
450 inw(devpriv->iobase);
453 devpriv->b_ModeSelectRegister =
455 b_ModeSelectRegister &
456 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
459 outb(devpriv->b_ModeSelectRegister,
460 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
463 devpriv->us_OutputRegister =
465 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
466 APCI3120_ENABLE_TIMER0;
467 outw(devpriv->us_OutputRegister,
468 devpriv->iobase + APCI3120_WR_ADDRESS);
472 b_DigitalOutputRegister) & 0xF0) |
473 APCI3120_SELECT_TIMER_0_WORD;
474 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
476 /* Set the conversion time */
477 outw(us_ConvertTiming,
478 devpriv->iobase + APCI3120_TIMER_VALUE);
481 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
483 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
486 /* Waiting for the end of conversion */
488 inw(devpriv->iobase +
490 } while ((us_TmpValue & APCI3120_EOC) ==
493 /* Read the result in FIFO and put it in insn data pointer */
494 us_TmpValue = inw(devpriv->iobase + 0);
497 inw(devpriv->iobase + APCI3120_RESET_FIFO);
502 case APCI3120_EOS_MODE:
504 inw(devpriv->iobase);
505 /* Clears the FIFO */
506 inw(devpriv->iobase + APCI3120_RESET_FIFO);
507 /* clear PA PR and disable timer 0 */
509 devpriv->us_OutputRegister =
511 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
512 APCI3120_DISABLE_TIMER0;
514 outw(devpriv->us_OutputRegister,
515 devpriv->iobase + APCI3120_WR_ADDRESS);
517 if (!i_APCI3120_SetupChannelList(dev, s,
518 devpriv->ui_AiNbrofChannels,
519 devpriv->ui_AiChannelList, 0))
522 /* Initialize Timer 0 mode 2 */
523 devpriv->b_TimerSelectMode =
525 b_TimerSelectMode & 0xFC) |
526 APCI3120_TIMER_0_MODE_2;
527 outb(devpriv->b_TimerSelectMode,
528 devpriv->iobase + APCI3120_TIMER_CRT1);
532 b_DigitalOutputRegister) & 0xF0) |
533 APCI3120_SELECT_TIMER_0_WORD;
534 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
536 /* Set the conversion time */
537 outw(us_ConvertTiming,
538 devpriv->iobase + APCI3120_TIMER_VALUE);
540 /* Set the scan bit */
541 devpriv->b_ModeSelectRegister =
543 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
544 outb(devpriv->b_ModeSelectRegister,
545 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
547 /* If Interrupt function is loaded */
548 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
549 /* Disables the EOC,DMA and enables the EOS interrupt */
550 devpriv->b_ModeSelectRegister =
552 b_ModeSelectRegister &
553 APCI3120_DISABLE_EOC_INT) |
554 APCI3120_ENABLE_EOS_INT;
555 inw(devpriv->iobase);
558 devpriv->b_ModeSelectRegister =
560 b_ModeSelectRegister &
561 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
563 outb(devpriv->b_ModeSelectRegister,
564 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
566 inw(devpriv->iobase + APCI3120_RD_STATUS);
570 devpriv->us_OutputRegister =
572 us_OutputRegister | APCI3120_ENABLE_TIMER0;
573 outw(devpriv->us_OutputRegister,
574 devpriv->iobase + APCI3120_WR_ADDRESS);
576 /* Start conversion */
577 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
579 /* Waiting of end of conversion if interrupt is not installed */
580 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
581 /* Waiting the end of conversion */
584 inw(devpriv->iobase +
586 } while ((us_TmpValue & APCI3120_EOS) !=
589 for (i = 0; i < devpriv->ui_AiNbrofChannels;
591 /* Read the result in FIFO and write them in shared memory */
592 us_TmpValue = inw(devpriv->iobase);
593 data[i] = (unsigned int) us_TmpValue;
596 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
601 printk("inputs wrong\n");
604 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
611 static int i_APCI3120_Reset(struct comedi_device *dev)
613 struct addi_private *devpriv = dev->private;
615 unsigned short us_TmpValue;
617 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
618 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
619 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
620 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
621 devpriv->b_OutputMemoryStatus = 0;
623 /* variables used in timer subdevice */
624 devpriv->b_Timer2Mode = 0;
625 devpriv->b_Timer2Interrupt = 0;
626 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
628 /* Disable all interrupts, watchdog for the anolog output */
629 devpriv->b_ModeSelectRegister = 0;
630 outb(devpriv->b_ModeSelectRegister,
631 dev->iobase + APCI3120_WRITE_MODE_SELECT);
633 /* Disables all counters, ext trigger and clears PA, PR */
634 devpriv->us_OutputRegister = 0;
635 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
638 * Code to set the all anolog o/p channel to 0v 8191 is decimal
639 * value for zero(0 v)volt in bipolar mode(default)
641 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
642 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
643 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
644 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
646 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
647 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
648 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
649 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
651 /* Reset digital output to L0W */
653 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
656 inw(dev->iobase + 0); /* make a dummy read */
657 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
658 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
660 /* code to reset the RAM sequence */
661 for (i = 0; i < 16; i++) {
662 us_TmpValue = i << 8; /* select the location */
663 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
668 static int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
670 struct addi_private *devpriv = dev->private;
672 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
673 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
677 static int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
679 struct addi_private *devpriv = dev->private;
681 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
682 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
686 static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
687 struct comedi_subdevice *s)
689 struct addi_private *devpriv = dev->private;
691 /* Disable A2P Fifo write and AMWEN signal */
692 outw(0, devpriv->i_IobaseAddon + 4);
694 /* Disable Bus Master ADD ON */
695 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
696 outw(0, devpriv->i_IobaseAddon + 2);
697 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
698 outw(0, devpriv->i_IobaseAddon + 2);
700 /* Disable BUS Master PCI */
701 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
703 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
704 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
706 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
707 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
709 /* Disable ext trigger */
710 i_APCI3120_ExttrigDisable(dev);
712 devpriv->us_OutputRegister = 0;
715 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
716 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
718 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
720 /* DISABLE_ALL_INTERRUPT */
721 outb(APCI3120_DISABLE_ALL_INTERRUPT,
722 dev->iobase + APCI3120_WRITE_MODE_SELECT);
724 inb(dev->iobase + APCI3120_RESET_FIFO);
725 inw(dev->iobase + APCI3120_RD_STATUS);
726 devpriv->ui_AiActualScan = 0;
727 devpriv->ui_AiActualScanPosition = 0;
728 s->async->cur_chan = 0;
729 devpriv->ui_AiBufferPtr = 0;
730 devpriv->b_AiContinuous = 0;
731 devpriv->ui_DmaActualBuffer = 0;
733 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
734 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
735 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
736 i_APCI3120_Reset(dev);
740 static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
741 struct comedi_subdevice *s,
742 struct comedi_cmd *cmd)
744 const struct addi_board *this_board = comedi_board(dev);
747 /* Step 1 : check if triggers are trivially valid */
749 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
750 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
751 TRIG_TIMER | TRIG_FOLLOW);
752 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
753 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
754 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
759 /* Step 2a : make sure trigger sources are unique */
761 err |= cfc_check_trigger_is_unique(cmd->start_src);
762 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
763 err |= cfc_check_trigger_is_unique(cmd->stop_src);
765 /* Step 2b : and mutually compatible */
770 /* Step 3: check if arguments are trivially valid */
772 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
774 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
775 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
777 if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */
778 if (cmd->scan_begin_src == TRIG_TIMER) {
779 if (cmd->convert_arg)
780 err |= cfc_check_trigger_arg_min(
781 &cmd->convert_arg, 10000);
783 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
788 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
789 err |= cfc_check_trigger_arg_max(&cmd->chanlist_len,
790 this_board->i_AiChannelList);
792 if (cmd->stop_src == TRIG_COUNT)
793 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
795 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
800 /* step 4: fix up any arguments */
802 if (cmd->convert_src == TRIG_TIMER) {
804 if (cmd->scan_begin_src == TRIG_TIMER &&
805 cmd->scan_begin_arg <
806 cmd->convert_arg * cmd->scan_end_arg) {
807 cmd->scan_begin_arg =
808 cmd->convert_arg * cmd->scan_end_arg;
820 * This is used for analog input cyclic acquisition.
821 * Performs the command operations.
822 * If DMA is configured does DMA initialization otherwise does the
823 * acquisition with EOS interrupt.
825 static int i_APCI3120_CyclicAnalogInput(int mode,
826 struct comedi_device *dev,
827 struct comedi_subdevice *s)
829 const struct addi_board *this_board = comedi_board(dev);
830 struct addi_private *devpriv = dev->private;
832 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
833 0, dmalen1 = 0, ui_TimerValue2 =
834 0, ui_TimerValue0, ui_ConvertTiming;
835 unsigned short us_TmpValue;
837 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
838 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
839 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
841 /*******************/
842 /* Resets the FIFO */
843 /*******************/
844 inb(dev->iobase + APCI3120_RESET_FIFO);
846 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
847 /* inw(dev->iobase+APCI3120_RD_STATUS); */
848 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
850 /***************************/
851 /* Acquisition initialized */
852 /***************************/
853 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
854 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
855 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
857 /* clear software registers */
858 devpriv->b_TimerSelectMode = 0;
859 devpriv->us_OutputRegister = 0;
860 devpriv->b_ModeSelectRegister = 0;
861 /* devpriv->b_DigitalOutputRegister=0; */
863 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
865 /****************************/
866 /* Clear Timer Write TC int */
867 /****************************/
868 outl(APCI3120_CLEAR_WRITE_TC_INT,
869 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
871 /************************************/
872 /* Clears the timer status register */
873 /************************************/
875 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
876 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
877 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
878 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
880 /**************************/
881 /* Disables All Timer */
882 /* Sets PR and PA to 0 */
883 /**************************/
884 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
885 APCI3120_DISABLE_TIMER0 &
886 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
888 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
890 /*******************/
891 /* Resets the FIFO */
892 /*******************/
893 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
894 inb(devpriv->iobase + APCI3120_RESET_FIFO);
895 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
897 devpriv->ui_AiActualScan = 0;
898 devpriv->ui_AiActualScanPosition = 0;
899 s->async->cur_chan = 0;
900 devpriv->ui_AiBufferPtr = 0;
901 devpriv->ui_DmaActualBuffer = 0;
903 /* value for timer2 minus -2 has to be done .....dunno y?? */
904 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
905 ui_ConvertTiming = devpriv->ui_AiTimer0;
908 ui_DelayTiming = devpriv->ui_AiTimer1;
910 /**********************************/
911 /* Initializes the sequence array */
912 /**********************************/
913 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
914 devpriv->pui_AiChannelList, 0))
917 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
918 /*** EL241003 : add this section in comment because floats must not be used
919 if((us_TmpValue & 0x00B0)==0x00B0)
921 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
922 ui_TimerValue0=(unsigned int)f_ConvertValue;
925 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
926 ui_TimerValue1 = (unsigned int) f_DelayValue;
931 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
932 ui_TimerValue0=(unsigned int)f_ConvertValue;
935 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
936 ui_TimerValue1 = (unsigned int) f_DelayValue;
939 ***********************************************************************************************/
940 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
941 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
942 if ((us_TmpValue & 0x00B0) == 0x00B0
943 || !strcmp(this_board->pc_DriverName, "apci3001")) {
944 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
945 ui_TimerValue0 = ui_TimerValue0 / 1000;
948 ui_DelayTiming = ui_DelayTiming / 1000;
949 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
950 ui_TimerValue1 = ui_TimerValue1 / 100;
953 ui_ConvertTiming = ui_ConvertTiming / 1000;
954 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
955 ui_TimerValue0 = ui_TimerValue0 / 10000;
958 ui_DelayTiming = ui_DelayTiming / 1000;
959 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
960 ui_TimerValue1 = ui_TimerValue1 / 1000000;
963 /*** EL241003 End ******************************************************************************/
965 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
966 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
969 /* init timer0 in mode 2 */
970 devpriv->b_TimerSelectMode =
972 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
973 outb(devpriv->b_TimerSelectMode,
974 dev->iobase + APCI3120_TIMER_CRT1);
978 b_DigitalOutputRegister) & 0xF0) |
979 APCI3120_SELECT_TIMER_0_WORD;
980 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
981 /* Set the conversion time */
982 outw(((unsigned short) ui_TimerValue0),
983 dev->iobase + APCI3120_TIMER_VALUE);
987 /* init timer1 in mode 2 */
988 devpriv->b_TimerSelectMode =
990 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
991 outb(devpriv->b_TimerSelectMode,
992 dev->iobase + APCI3120_TIMER_CRT1);
996 b_DigitalOutputRegister) & 0xF0) |
997 APCI3120_SELECT_TIMER_1_WORD;
998 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
999 /* Set the conversion time */
1000 outw(((unsigned short) ui_TimerValue1),
1001 dev->iobase + APCI3120_TIMER_VALUE);
1003 /* init timer0 in mode 2 */
1004 devpriv->b_TimerSelectMode =
1006 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
1007 outb(devpriv->b_TimerSelectMode,
1008 dev->iobase + APCI3120_TIMER_CRT1);
1010 /* Select Timer 0 */
1012 b_DigitalOutputRegister) & 0xF0) |
1013 APCI3120_SELECT_TIMER_0_WORD;
1014 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1016 /* Set the conversion time */
1017 outw(((unsigned short) ui_TimerValue0),
1018 dev->iobase + APCI3120_TIMER_VALUE);
1022 /* ##########common for all modes################# */
1024 /***********************/
1025 /* Clears the SCAN bit */
1026 /***********************/
1028 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1029 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
1031 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1032 APCI3120_DISABLE_SCAN;
1033 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1035 outb(devpriv->b_ModeSelectRegister,
1036 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1038 /* If DMA is disabled */
1039 if (devpriv->us_UseDma == APCI3120_DISABLE) {
1040 /* disable EOC and enable EOS */
1041 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
1042 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
1044 devpriv->b_ModeSelectRegister =
1046 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
1047 APCI3120_ENABLE_EOS_INT;
1048 outb(devpriv->b_ModeSelectRegister,
1049 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1051 if (!devpriv->b_AiContinuous) {
1053 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
1054 * disable it (Set Bit D14 to 0)
1056 devpriv->us_OutputRegister =
1058 us_OutputRegister & APCI3120_DISABLE_TIMER2;
1059 outw(devpriv->us_OutputRegister,
1060 dev->iobase + APCI3120_WR_ADDRESS);
1062 /* DISABLE TIMER intERRUPT */
1063 devpriv->b_ModeSelectRegister =
1065 b_ModeSelectRegister &
1066 APCI3120_DISABLE_TIMER_INT & 0xEF;
1067 outb(devpriv->b_ModeSelectRegister,
1068 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1070 /* (1) Init timer 2 in mode 0 and write timer value */
1071 devpriv->b_TimerSelectMode =
1073 b_TimerSelectMode & 0x0F) |
1074 APCI3120_TIMER_2_MODE_0;
1075 outb(devpriv->b_TimerSelectMode,
1076 dev->iobase + APCI3120_TIMER_CRT1);
1078 /* Writing LOW unsigned short */
1080 b_DigitalOutputRegister) & 0xF0) |
1081 APCI3120_SELECT_TIMER_2_LOW_WORD;
1082 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1083 outw(LOWORD(ui_TimerValue2),
1084 dev->iobase + APCI3120_TIMER_VALUE);
1086 /* Writing HIGH unsigned short */
1088 b_DigitalOutputRegister) & 0xF0) |
1089 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1090 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1091 outw(HIWORD(ui_TimerValue2),
1092 dev->iobase + APCI3120_TIMER_VALUE);
1094 /* (2) Reset FC_TIMER BIT Clearing timer status register */
1095 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1096 /* enable timer counter and disable watch dog */
1097 devpriv->b_ModeSelectRegister =
1099 b_ModeSelectRegister |
1100 APCI3120_ENABLE_TIMER_COUNTER) &
1101 APCI3120_DISABLE_WATCHDOG;
1102 /* select EOS clock input for timer 2 */
1103 devpriv->b_ModeSelectRegister =
1105 b_ModeSelectRegister |
1106 APCI3120_TIMER2_SELECT_EOS;
1107 /* Enable timer2 interrupt */
1108 devpriv->b_ModeSelectRegister =
1110 b_ModeSelectRegister |
1111 APCI3120_ENABLE_TIMER_INT;
1112 outb(devpriv->b_ModeSelectRegister,
1113 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1114 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1115 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1118 /* If DMA Enabled */
1120 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1121 /* inw(dev->iobase+0); reset EOC bit */
1122 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1123 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1125 /************************************/
1126 /* Disables the EOC, EOS interrupt */
1127 /************************************/
1128 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1129 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1131 outb(devpriv->b_ModeSelectRegister,
1132 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1134 dmalen0 = devpriv->ui_DmaBufferSize[0];
1135 dmalen1 = devpriv->ui_DmaBufferSize[1];
1137 if (!devpriv->b_AiContinuous) {
1139 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
1141 devpriv->ui_AiNbrofScans *
1142 devpriv->ui_AiScanLength * 2;
1143 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
1145 devpriv->ui_AiNbrofScans *
1146 devpriv->ui_AiScanLength * 2 - dmalen0;
1149 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1150 /* don't we want wake up every scan? */
1151 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1152 dmalen0 = devpriv->ui_AiScanLength * 2;
1153 if (devpriv->ui_AiScanLength & 1)
1156 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1157 dmalen1 = devpriv->ui_AiScanLength * 2;
1158 if (devpriv->ui_AiScanLength & 1)
1163 } else { /* isn't output buff smaller that our DMA buff? */
1164 if (dmalen0 > (devpriv->ui_AiDataLength))
1165 dmalen0 = devpriv->ui_AiDataLength;
1166 if (dmalen1 > (devpriv->ui_AiDataLength))
1167 dmalen1 = devpriv->ui_AiDataLength;
1169 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1170 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1172 /* Initialize DMA */
1175 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1178 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1179 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1181 /* changed since 16 bit interface for add on */
1182 /*********************/
1183 /* ENABLE BUS MASTER */
1184 /*********************/
1185 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1186 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1187 devpriv->i_IobaseAddon + 2);
1189 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1190 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1191 devpriv->i_IobaseAddon + 2);
1194 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1197 outw(0x1000, devpriv->i_IobaseAddon + 2);
1198 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1201 /* A2P FIFO MANAGEMENT */
1202 /* A2P fifo reset & transfer control enable */
1204 /***********************/
1205 /* A2P FIFO MANAGEMENT */
1206 /***********************/
1207 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1208 APCI3120_AMCC_OP_MCSR);
1212 * beginning address of dma buf The 32 bit address of dma buffer
1213 * is converted into two 16 bit addresses Can done by using _attach
1214 * and put into into an array array used may be for differnet pages
1217 /* DMA Start Address Low */
1218 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1219 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1220 devpriv->i_IobaseAddon + 2);
1222 /*************************/
1223 /* DMA Start Address High */
1224 /*************************/
1225 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1226 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1227 devpriv->i_IobaseAddon + 2);
1231 * amount of bytes to be transferred set transfer count used ADDON
1232 * MWTC register commented testing
1233 * outl(devpriv->ui_DmaBufferUsesize[0],
1234 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1237 /**************************/
1238 /* Nbr of acquisition LOW */
1239 /**************************/
1240 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1241 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1242 devpriv->i_IobaseAddon + 2);
1244 /***************************/
1245 /* Nbr of acquisition HIGH */
1246 /***************************/
1247 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1248 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1249 devpriv->i_IobaseAddon + 2);
1253 * To configure A2P FIFO testing outl(
1254 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1257 /******************/
1258 /* A2P FIFO RESET */
1259 /******************/
1261 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1264 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1265 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1269 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1270 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1273 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1274 /* outw(3,devpriv->i_IobaseAddon + 4); */
1275 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1279 * initialise end of dma interrupt AINT_WRITE_COMPL =
1280 * ENABLE_WRITE_TC_INT(ADDI)
1282 /***************************************************/
1283 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1284 /***************************************************/
1285 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1286 APCI3120_ENABLE_WRITE_TC_INT),
1287 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1289 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1290 /******************************************/
1291 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1292 /******************************************/
1293 outw(3, devpriv->i_IobaseAddon + 4);
1294 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1296 /******************/
1297 /* A2P FIFO RESET */
1298 /******************/
1299 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1301 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1302 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1305 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1306 && !devpriv->b_AiContinuous) {
1307 /* set gate 2 to start conversion */
1308 devpriv->us_OutputRegister =
1309 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1310 outw(devpriv->us_OutputRegister,
1311 dev->iobase + APCI3120_WR_ADDRESS);
1316 /* set gate 0 to start conversion */
1317 devpriv->us_OutputRegister =
1318 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1319 outw(devpriv->us_OutputRegister,
1320 dev->iobase + APCI3120_WR_ADDRESS);
1323 /* set gate 0 and gate 1 */
1324 devpriv->us_OutputRegister =
1325 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1326 devpriv->us_OutputRegister =
1327 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1328 outw(devpriv->us_OutputRegister,
1329 dev->iobase + APCI3120_WR_ADDRESS);
1339 * Does asynchronous acquisition.
1340 * Determines the mode 1 or 2.
1342 static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,
1343 struct comedi_subdevice *s)
1345 struct addi_private *devpriv = dev->private;
1346 struct comedi_cmd *cmd = &s->async->cmd;
1348 /* loading private structure with cmd structure inputs */
1349 devpriv->ui_AiFlags = cmd->flags;
1350 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
1351 devpriv->ui_AiScanLength = cmd->scan_end_arg;
1352 devpriv->pui_AiChannelList = cmd->chanlist;
1354 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
1355 devpriv->AiData = s->async->prealloc_buf;
1356 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
1357 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
1359 if (cmd->stop_src == TRIG_COUNT)
1360 devpriv->ui_AiNbrofScans = cmd->stop_arg;
1362 devpriv->ui_AiNbrofScans = 0;
1364 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
1365 devpriv->ui_AiTimer1 = 0;
1366 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
1367 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
1368 /* stopped using cancel */
1370 if (cmd->start_src == TRIG_EXT)
1371 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
1373 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1375 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1377 if (cmd->convert_src == TRIG_TIMER) {
1380 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
1381 /* return this_board->ai_cmd(1,dev,s); */
1382 return i_APCI3120_CyclicAnalogInput(1, dev, s);
1386 if ((cmd->scan_begin_src == TRIG_TIMER)
1387 && (cmd->convert_src == TRIG_TIMER)) {
1389 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
1390 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
1391 /* return this_board->ai_cmd(2,dev,s); */
1392 return i_APCI3120_CyclicAnalogInput(2, dev, s);
1398 * This function copies the data from DMA buffer to the Comedi buffer.
1400 static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1401 struct comedi_subdevice *s,
1403 unsigned int num_samples)
1405 struct addi_private *devpriv = dev->private;
1407 devpriv->ui_AiActualScan +=
1408 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1409 s->async->cur_chan += num_samples;
1410 s->async->cur_chan %= devpriv->ui_AiScanLength;
1412 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1416 * This is a handler for the DMA interrupt.
1417 * This function copies the data to Comedi Buffer.
1418 * For continuous DMA it reinitializes the DMA operation.
1419 * For single mode DMA it stop the acquisition.
1421 static void v_APCI3120_InterruptDma(int irq, void *d)
1423 struct comedi_device *dev = d;
1424 struct addi_private *devpriv = dev->private;
1425 struct comedi_subdevice *s = &dev->subdevices[0];
1426 unsigned int next_dma_buf, samplesinbuf;
1427 unsigned long low_word, high_word, var;
1428 unsigned int ui_Tmp;
1431 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1432 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1435 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1436 comedi_error(dev, "Interrupted DMA transfer!");
1438 if (samplesinbuf & 1) {
1439 comedi_error(dev, "Odd count of bytes in DMA ring!");
1440 i_APCI3120_StopCyclicAcquisition(dev, s);
1441 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1445 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1446 if (devpriv->b_DmaDoubleBuffer) {
1447 /* switch DMA buffers if is used double buffering */
1448 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1450 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1451 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1453 /* changed since 16 bit interface for add on */
1454 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1455 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1456 devpriv->i_IobaseAddon + 2);
1457 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1458 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1460 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1461 low_word = var & 0xffff;
1462 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1463 high_word = var / 65536;
1465 /* DMA Start Address Low */
1466 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1467 outw(low_word, devpriv->i_IobaseAddon + 2);
1469 /* DMA Start Address High */
1470 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1471 outw(high_word, devpriv->i_IobaseAddon + 2);
1473 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1474 low_word = var & 0xffff;
1475 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1476 high_word = var / 65536;
1478 /* Nbr of acquisition LOW */
1479 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1480 outw(low_word, devpriv->i_IobaseAddon + 2);
1482 /* Nbr of acquisition HIGH */
1483 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1484 outw(high_word, devpriv->i_IobaseAddon + 2);
1487 * To configure A2P FIFO
1488 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1489 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1491 outw(3, devpriv->i_IobaseAddon + 4);
1492 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1493 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1494 APCI3120_ENABLE_WRITE_TC_INT),
1495 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1499 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1500 devpriv->ul_DmaBufferVirtual[devpriv->
1501 ui_DmaActualBuffer], samplesinbuf);
1503 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1504 s->async->events |= COMEDI_CB_EOS;
1505 comedi_event(dev, s);
1508 if (!devpriv->b_AiContinuous)
1509 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1510 /* all data sampled */
1511 i_APCI3120_StopCyclicAcquisition(dev, s);
1512 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1513 s->async->events |= COMEDI_CB_EOA;
1514 comedi_event(dev, s);
1518 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1519 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1522 * restart DMA if is not used double buffering
1523 * ADDED REINITIALISE THE DMA
1525 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1526 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1528 /* changed since 16 bit interface for add on */
1529 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1530 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1531 devpriv->i_IobaseAddon + 2);
1532 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1533 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1535 * A2P FIFO MANAGEMENT
1536 * A2P fifo reset & transfer control enable
1538 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1539 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1541 var = devpriv->ul_DmaBufferHw[0];
1542 low_word = var & 0xffff;
1543 var = devpriv->ul_DmaBufferHw[0];
1544 high_word = var / 65536;
1545 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1546 outw(low_word, devpriv->i_IobaseAddon + 2);
1547 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1548 outw(high_word, devpriv->i_IobaseAddon + 2);
1550 var = devpriv->ui_DmaBufferUsesize[0];
1551 low_word = var & 0xffff; /* changed */
1552 var = devpriv->ui_DmaBufferUsesize[0];
1553 high_word = var / 65536;
1554 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1555 outw(low_word, devpriv->i_IobaseAddon + 2);
1556 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1557 outw(high_word, devpriv->i_IobaseAddon + 2);
1560 * To configure A2P FIFO
1561 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1562 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1564 outw(3, devpriv->i_IobaseAddon + 4);
1565 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1566 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1567 APCI3120_ENABLE_WRITE_TC_INT),
1568 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1573 * This function handles EOS interrupt.
1574 * This function copies the acquired data(from FIFO) to Comedi buffer.
1576 static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1578 struct addi_private *devpriv = dev->private;
1580 struct comedi_subdevice *s = &dev->subdevices[0];
1583 n_chan = devpriv->ui_AiNbrofChannels;
1585 s->async->events = 0;
1587 for (i = 0; i < n_chan; i++)
1588 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1590 s->async->events |= COMEDI_CB_EOS;
1593 s->async->events |= COMEDI_CB_OVERFLOW;
1595 comedi_event(dev, s);
1600 static void v_APCI3120_Interrupt(int irq, void *d)
1602 struct comedi_device *dev = d;
1603 struct addi_private *devpriv = dev->private;
1604 unsigned short int_daq;
1605 unsigned int int_amcc, ui_Check, i;
1606 unsigned short us_TmpValue;
1607 unsigned char b_DummyRead;
1608 struct comedi_subdevice *s = &dev->subdevices[0];
1612 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1613 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1615 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1616 comedi_error(dev, "IRQ from unknown source");
1620 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1622 int_daq = (int_daq >> 12) & 0xF;
1624 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1625 /* Disable ext trigger */
1626 i_APCI3120_ExttrigDisable(dev);
1627 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1629 /* clear the timer 2 interrupt */
1630 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1632 if (int_amcc & MASTER_ABORT_INT)
1633 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1634 if (int_amcc & TARGET_ABORT_INT)
1635 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1637 /* Ckeck if EOC interrupt */
1638 if (((int_daq & 0x8) == 0)
1639 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1640 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1642 /* Read the AI Value */
1644 devpriv->ui_AiReadData[0] =
1645 (unsigned int) inw(devpriv->iobase + 0);
1646 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1647 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1649 /* Disable EOC Interrupt */
1650 devpriv->b_ModeSelectRegister =
1652 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1653 outb(devpriv->b_ModeSelectRegister,
1654 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1659 /* Check If EOS interrupt */
1660 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1662 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
1664 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1666 i_APCI3120_InterruptHandleEos(dev);
1667 devpriv->ui_AiActualScan++;
1668 devpriv->b_ModeSelectRegister =
1670 b_ModeSelectRegister |
1671 APCI3120_ENABLE_EOS_INT;
1672 outb(devpriv->b_ModeSelectRegister,
1674 APCI3120_WRITE_MODE_SELECT);
1677 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1679 us_TmpValue = inw(devpriv->iobase + 0);
1680 devpriv->ui_AiReadData[i] =
1681 (unsigned int) us_TmpValue;
1683 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1684 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1686 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1691 devpriv->b_ModeSelectRegister =
1693 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1694 outb(devpriv->b_ModeSelectRegister,
1695 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1696 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1697 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1701 /* Timer2 interrupt */
1702 if (int_daq & 0x1) {
1704 switch (devpriv->b_Timer2Mode) {
1705 case APCI3120_COUNTER:
1707 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1708 devpriv->b_ModeSelectRegister =
1710 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1711 outb(devpriv->b_ModeSelectRegister,
1712 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1715 devpriv->us_OutputRegister =
1717 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1718 outw(devpriv->us_OutputRegister,
1719 dev->iobase + APCI3120_WR_ADDRESS);
1721 /* stop timer 0 and timer 1 */
1722 i_APCI3120_StopCyclicAcquisition(dev, s);
1723 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1725 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1726 s->async->events |= COMEDI_CB_EOA;
1727 comedi_event(dev, s);
1731 case APCI3120_TIMER:
1733 /* Send a signal to from kernel to user space */
1734 send_sig(SIGIO, devpriv->tsk_Current, 0);
1737 case APCI3120_WATCHDOG:
1739 /* Send a signal to from kernel to user space */
1740 send_sig(SIGIO, devpriv->tsk_Current, 0);
1745 /* disable Timer Interrupt */
1747 devpriv->b_ModeSelectRegister =
1749 b_ModeSelectRegister &
1750 APCI3120_DISABLE_TIMER_INT;
1752 outb(devpriv->b_ModeSelectRegister,
1753 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1757 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1761 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1762 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1764 /****************************/
1765 /* Clear Timer Write TC int */
1766 /****************************/
1768 outl(APCI3120_CLEAR_WRITE_TC_INT,
1769 devpriv->i_IobaseAmcc +
1770 APCI3120_AMCC_OP_REG_INTCSR);
1772 /************************************/
1773 /* Clears the timer status register */
1774 /************************************/
1775 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1776 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
1778 /* Stops the Timer */
1780 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1781 APCI3120_DISABLE_TIMER1,
1782 dev->iobase + APCI3120_WR_ADDRESS);
1793 * data[0] = TIMER configure as timer
1794 * = WATCHDOG configure as watchdog
1795 * data[1] = Timer constant
1796 * data[2] = Timer2 interrupt (1)enable or(0) disable
1798 static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
1799 struct comedi_subdevice *s,
1800 struct comedi_insn *insn,
1803 const struct addi_board *this_board = comedi_board(dev);
1804 struct addi_private *devpriv = dev->private;
1805 unsigned int ui_Timervalue2;
1806 unsigned short us_TmpValue;
1807 unsigned char b_Tmp;
1810 comedi_error(dev, "config:No timer constant !");
1812 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1814 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1816 /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
1817 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1820 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1821 * is an APCI3001 and calculate the time value to set in the timer
1823 if ((us_TmpValue & 0x00B0) == 0x00B0
1824 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1825 /* Calculate the time value to set in the timer */
1826 ui_Timervalue2 = ui_Timervalue2 / 50;
1828 /* Calculate the time value to set in the timer */
1829 ui_Timervalue2 = ui_Timervalue2 / 70;
1832 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1833 devpriv->us_OutputRegister =
1834 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1835 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1837 /* Disable TIMER Interrupt */
1838 devpriv->b_ModeSelectRegister =
1840 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1842 /* Disable Eoc and Eos Interrupts */
1843 devpriv->b_ModeSelectRegister =
1845 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1846 APCI3120_DISABLE_EOS_INT;
1847 outb(devpriv->b_ModeSelectRegister,
1848 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1849 if (data[0] == APCI3120_TIMER) { /* initialize timer */
1850 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1851 * APCI3120_ENABLE_TIMER_INT; */
1853 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1855 /* Set the Timer 2 in mode 2(Timer) */
1856 devpriv->b_TimerSelectMode =
1858 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1859 outb(devpriv->b_TimerSelectMode,
1860 devpriv->iobase + APCI3120_TIMER_CRT1);
1863 * Configure the timer 2 for writing the LOW unsigned short of timer
1864 * is Delay value You must make a b_tmp variable with
1865 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1866 * you can set the digital output and configure the timer 2,and if
1867 * you don't make this, digital output are erase (Set to 0)
1870 /* Writing LOW unsigned short */
1872 b_DigitalOutputRegister) & 0xF0) |
1873 APCI3120_SELECT_TIMER_2_LOW_WORD;
1874 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1875 outw(LOWORD(ui_Timervalue2),
1876 devpriv->iobase + APCI3120_TIMER_VALUE);
1878 /* Writing HIGH unsigned short */
1880 b_DigitalOutputRegister) & 0xF0) |
1881 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1882 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1883 outw(HIWORD(ui_Timervalue2),
1884 devpriv->iobase + APCI3120_TIMER_VALUE);
1885 /* timer2 in Timer mode enabled */
1886 devpriv->b_Timer2Mode = APCI3120_TIMER;
1888 } else { /* Initialize Watch dog */
1890 /* Set the Timer 2 in mode 5(Watchdog) */
1892 devpriv->b_TimerSelectMode =
1894 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1895 outb(devpriv->b_TimerSelectMode,
1896 devpriv->iobase + APCI3120_TIMER_CRT1);
1899 * Configure the timer 2 for writing the LOW unsigned short of timer
1900 * is Delay value You must make a b_tmp variable with
1901 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1902 * you can set the digital output and configure the timer 2,and if
1903 * you don't make this, digital output are erase (Set to 0)
1906 /* Writing LOW unsigned short */
1908 b_DigitalOutputRegister) & 0xF0) |
1909 APCI3120_SELECT_TIMER_2_LOW_WORD;
1910 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1911 outw(LOWORD(ui_Timervalue2),
1912 devpriv->iobase + APCI3120_TIMER_VALUE);
1914 /* Writing HIGH unsigned short */
1916 b_DigitalOutputRegister) & 0xF0) |
1917 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1918 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1920 outw(HIWORD(ui_Timervalue2),
1921 devpriv->iobase + APCI3120_TIMER_VALUE);
1922 /* watchdog enabled */
1923 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1932 * To start and stop the timer
1934 * data[0] = 1 (start)
1936 * = 2 (write new value)
1937 * data[1] = new value
1939 * devpriv->b_Timer2Mode = 0 DISABLE
1943 static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
1944 struct comedi_subdevice *s,
1945 struct comedi_insn *insn,
1948 const struct addi_board *this_board = comedi_board(dev);
1949 struct addi_private *devpriv = dev->private;
1950 unsigned int ui_Timervalue2 = 0;
1951 unsigned short us_TmpValue;
1952 unsigned char b_Tmp;
1954 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1955 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1956 comedi_error(dev, "\nwrite:timer2 not configured ");
1960 if (data[0] == 2) { /* write new value */
1961 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1963 "write :timer2 not configured in TIMER MODE");
1968 ui_Timervalue2 = data[1];
1973 /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
1976 case APCI3120_START:
1978 /* Reset FC_TIMER BIT */
1979 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1980 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1982 devpriv->b_ModeSelectRegister =
1983 devpriv->b_ModeSelectRegister & 0x0B;
1984 } else { /* start watch dog */
1985 /* Enable WatchDog */
1986 devpriv->b_ModeSelectRegister =
1988 b_ModeSelectRegister & 0x0B) |
1989 APCI3120_ENABLE_WATCHDOG;
1992 /* enable disable interrupt */
1993 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1995 devpriv->b_ModeSelectRegister =
1997 b_ModeSelectRegister |
1998 APCI3120_ENABLE_TIMER_INT;
1999 /* save the task structure to pass info to user */
2000 devpriv->tsk_Current = current;
2003 devpriv->b_ModeSelectRegister =
2005 b_ModeSelectRegister &
2006 APCI3120_DISABLE_TIMER_INT;
2008 outb(devpriv->b_ModeSelectRegister,
2009 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2011 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
2012 /* For Timer mode is Gate2 must be activated **timer started */
2013 devpriv->us_OutputRegister =
2015 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2016 outw(devpriv->us_OutputRegister,
2017 devpriv->iobase + APCI3120_WR_ADDRESS);
2023 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2025 devpriv->b_ModeSelectRegister =
2027 b_ModeSelectRegister &
2028 APCI3120_DISABLE_TIMER_COUNTER;
2030 /* Disable WatchDog */
2031 devpriv->b_ModeSelectRegister =
2033 b_ModeSelectRegister &
2034 APCI3120_DISABLE_WATCHDOG;
2036 /* Disable timer interrupt */
2037 devpriv->b_ModeSelectRegister =
2039 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2041 /* Write above states to register */
2042 outb(devpriv->b_ModeSelectRegister,
2043 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2046 devpriv->us_OutputRegister =
2047 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2048 outw(devpriv->us_OutputRegister,
2049 devpriv->iobase + APCI3120_WR_ADDRESS);
2051 /* Reset FC_TIMER BIT */
2052 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2055 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2059 case 2: /* write new value to Timer */
2060 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2062 "write :timer2 not configured in TIMER MODE");
2065 /* ui_Timervalue2=data[1]; // passed as argument */
2067 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2070 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2071 * is an APCI3001 and calculate the time value to set in the timer
2073 if ((us_TmpValue & 0x00B0) == 0x00B0
2074 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2075 /* Calculate the time value to set in the timer */
2076 ui_Timervalue2 = ui_Timervalue2 / 50;
2078 /* Calculate the time value to set in the timer */
2079 ui_Timervalue2 = ui_Timervalue2 / 70;
2081 /* Writing LOW unsigned short */
2083 b_DigitalOutputRegister) & 0xF0) |
2084 APCI3120_SELECT_TIMER_2_LOW_WORD;
2085 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2087 outw(LOWORD(ui_Timervalue2),
2088 devpriv->iobase + APCI3120_TIMER_VALUE);
2090 /* Writing HIGH unsigned short */
2092 b_DigitalOutputRegister) & 0xF0) |
2093 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2094 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2096 outw(HIWORD(ui_Timervalue2),
2097 devpriv->iobase + APCI3120_TIMER_VALUE);
2101 return -EINVAL; /* Not a valid input */
2108 * Read the Timer value
2110 * for Timer: data[0]= Timer constant
2112 * for watchdog: data[0] = 0 (still running)
2115 static int i_APCI3120_InsnReadTimer(struct comedi_device *dev,
2116 struct comedi_subdevice *s,
2117 struct comedi_insn *insn,
2120 struct addi_private *devpriv = dev->private;
2121 unsigned char b_Tmp;
2122 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2124 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2125 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2126 comedi_error(dev, "\nread:timer2 not configured ");
2129 /* this_board->timer_read(dev,data); */
2130 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2132 /* Read the LOW unsigned short of Timer 2 register */
2134 b_DigitalOutputRegister) & 0xF0) |
2135 APCI3120_SELECT_TIMER_2_LOW_WORD;
2136 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2138 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2140 /* Read the HIGH unsigned short of Timer 2 register */
2142 b_DigitalOutputRegister) & 0xF0) |
2143 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2144 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2146 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2148 /* combining both words */
2149 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2151 } else { /* Read watch dog status */
2153 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2155 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2156 if (us_StatusValue == 1) {
2157 /* RESET FC_TIMER BIT */
2158 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2160 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2165 static int apci3120_di_insn_bits(struct comedi_device *dev,
2166 struct comedi_subdevice *s,
2167 struct comedi_insn *insn,
2170 struct addi_private *devpriv = dev->private;
2173 /* the input channels are bits 11:8 of the status reg */
2174 val = inw(devpriv->iobase + APCI3120_RD_STATUS);
2175 data[1] = (val >> 8) & 0xf;
2180 static int apci3120_do_insn_bits(struct comedi_device *dev,
2181 struct comedi_subdevice *s,
2182 struct comedi_insn *insn,
2185 struct addi_private *devpriv = dev->private;
2186 unsigned int mask = data[0];
2187 unsigned int bits = data[1];
2190 /* The do channels are bits 7:4 of the do register */
2191 val = devpriv->b_DigitalOutputRegister >> 4;
2194 val |= (bits & mask);
2195 devpriv->b_DigitalOutputRegister = val << 4;
2197 outb(val << 4, devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2205 static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2206 struct comedi_subdevice *s,
2207 struct comedi_insn *insn,
2210 struct addi_private *devpriv = dev->private;
2211 unsigned int ui_Range, ui_Channel;
2212 unsigned short us_TmpValue;
2214 ui_Range = CR_RANGE(insn->chanspec);
2215 ui_Channel = CR_CHAN(insn->chanspec);
2217 /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
2218 if (ui_Range) { /* if 1 then unipolar */
2222 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2223 13) | (data[0] + 8191));
2226 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2229 } else { /* if 0 then bipolar */
2231 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2237 * out put n values at the given channel. printk("\nwaiting for
2240 do { /* Waiting of DA_READY BIT */
2242 ((unsigned short) inw(devpriv->iobase +
2243 APCI3120_RD_STATUS)) & 0x0001;
2244 } while (us_TmpValue != 0x0001);
2246 if (ui_Channel <= 3)
2248 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2249 * typecasted to ushort since word write is to be done
2251 outw((unsigned short) data[0],
2252 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2255 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2256 * typecasted to ushort since word write is to be done
2258 outw((unsigned short) data[0],
2259 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);