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 +----------+-----------+------------------------------------------------+
43 #include <linux/delay.h>
46 * ADDON RELATED ADDITIONS
49 #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00
50 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200
51 #define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L
52 #define APCI3120_AMWEN_ENABLE 0x02
53 #define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01
54 #define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L
55 #define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L
56 #define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L
57 #define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0
58 #define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0
59 #define APCI3120_DISABLE_BUS_MASTER_PCI 0x0
61 /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
62 #define APCI3120_ADD_ON_AGCSTS_LOW 0x3C
63 #define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2)
64 #define APCI3120_ADD_ON_MWAR_LOW 0x24
65 #define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2)
66 #define APCI3120_ADD_ON_MWTC_LOW 0x058
67 #define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2)
70 #define APCI3120_AMCC_OP_MCSR 0x3C
71 #define APCI3120_AMCC_OP_REG_INTCSR 0x38
73 /* for transfer count enable bit */
74 #define AGCSTS_TC_ENABLE 0x10000000
76 /* used for test on mixture of BIP/UNI ranges */
77 #define APCI3120_BIPOLAR_RANGES 4
79 #define APCI3120_ADDRESS_RANGE 16
81 #define APCI3120_DISABLE 0
82 #define APCI3120_ENABLE 1
84 #define APCI3120_START 1
85 #define APCI3120_STOP 0
87 #define APCI3120_EOC_MODE 1
88 #define APCI3120_EOS_MODE 2
89 #define APCI3120_DMA_MODE 3
91 /* DIGITAL INPUT-OUTPUT DEFINE */
93 #define APCI3120_DIGITAL_OUTPUT 0x0d
94 #define APCI3120_RD_STATUS 0x02
95 #define APCI3120_RD_FIFO 0x00
97 /* digital output insn_write ON /OFF selection */
98 #define APCI3120_SET4DIGITALOUTPUTON 1
99 #define APCI3120_SET4DIGITALOUTPUTOFF 0
101 /* analog output SELECT BIT */
102 #define APCI3120_ANALOG_OP_CHANNEL_1 0x0000
103 #define APCI3120_ANALOG_OP_CHANNEL_2 0x4000
104 #define APCI3120_ANALOG_OP_CHANNEL_3 0x8000
105 #define APCI3120_ANALOG_OP_CHANNEL_4 0xc000
106 #define APCI3120_ANALOG_OP_CHANNEL_5 0x0000
107 #define APCI3120_ANALOG_OP_CHANNEL_6 0x4000
108 #define APCI3120_ANALOG_OP_CHANNEL_7 0x8000
109 #define APCI3120_ANALOG_OP_CHANNEL_8 0xc000
111 /* Enable external trigger bit in nWrAddress */
112 #define APCI3120_ENABLE_EXT_TRIGGER 0x8000
114 /* ANALOG OUTPUT AND INPUT DEFINE */
115 #define APCI3120_UNIPOLAR 0x80
116 #define APCI3120_BIPOLAR 0x00
117 #define APCI3120_ANALOG_OUTPUT_1 0x08
118 #define APCI3120_ANALOG_OUTPUT_2 0x0a
119 #define APCI3120_1_GAIN 0x00
120 #define APCI3120_2_GAIN 0x10
121 #define APCI3120_5_GAIN 0x20
122 #define APCI3120_10_GAIN 0x30
123 #define APCI3120_SEQ_RAM_ADDRESS 0x06
124 #define APCI3120_RESET_FIFO 0x0c
125 #define APCI3120_TIMER_0_MODE_2 0x01
126 #define APCI3120_TIMER_0_MODE_4 0x2
127 #define APCI3120_SELECT_TIMER_0_WORD 0x00
128 #define APCI3120_ENABLE_TIMER0 0x1000
129 #define APCI3120_CLEAR_PR 0xf0ff
130 #define APCI3120_CLEAR_PA 0xfff0
131 #define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
134 #define APCI3120_ENABLE_SCAN 0x8
135 #define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN)
136 #define APCI3120_ENABLE_EOS_INT 0x2
138 #define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT)
139 #define APCI3120_ENABLE_EOC_INT 0x1
140 #define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT)
141 #define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER \
142 (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
143 #define APCI3120_DISABLE_ALL_INTERRUPT \
144 (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
146 /* status register bits */
147 #define APCI3120_EOC 0x8000
148 #define APCI3120_EOS 0x2000
150 /* software trigger dummy register */
151 #define APCI3120_START_CONVERSION 0x02
154 #define APCI3120_QUARTZ_A 70
155 #define APCI3120_QUARTZ_B 50
156 #define APCI3120_TIMER 1
157 #define APCI3120_WATCHDOG 2
158 #define APCI3120_TIMER_DISABLE 0
159 #define APCI3120_TIMER_ENABLE 1
160 #define APCI3120_ENABLE_TIMER2 0x4000
161 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
162 #define APCI3120_ENABLE_TIMER_INT 0x04
163 #define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT)
164 #define APCI3120_WRITE_MODE_SELECT 0x0e
165 #define APCI3120_SELECT_TIMER_0_WORD 0x00
166 #define APCI3120_SELECT_TIMER_1_WORD 0x01
167 #define APCI3120_TIMER_1_MODE_2 0x4
169 /* $$ BIT FOR MODE IN nCsTimerCtr1 */
170 #define APCI3120_TIMER_2_MODE_0 0x0
171 #define APCI3120_TIMER_2_MODE_2 0x10
172 #define APCI3120_TIMER_2_MODE_5 0x30
174 /* $$ BIT FOR MODE IN nCsTimerCtr0 */
175 #define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02
176 #define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03
178 #define APCI3120_TIMER_CRT0 0x0d
179 #define APCI3120_TIMER_CRT1 0x0c
181 #define APCI3120_TIMER_VALUE 0x04
182 #define APCI3120_TIMER_STATUS_REGISTER 0x0d
183 #define APCI3120_RD_STATUS 0x02
184 #define APCI3120_WR_ADDRESS 0x00
185 #define APCI3120_ENABLE_WATCHDOG 0x20
186 #define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG)
187 #define APCI3120_ENABLE_TIMER_COUNTER 0x10
188 #define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER)
189 #define APCI3120_FC_TIMER 0x1000
190 #define APCI3120_ENABLE_TIMER0 0x1000
191 #define APCI3120_ENABLE_TIMER1 0x2000
192 #define APCI3120_ENABLE_TIMER2 0x4000
193 #define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0)
194 #define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1)
195 #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2)
197 #define APCI3120_TIMER2_SELECT_EOS 0xc0
198 #define APCI3120_COUNTER 3
199 #define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & \
200 APCI3120_DISABLE_TIMER1 & \
201 APCI3120_DISABLE_TIMER2)
203 #define MAX_ANALOGINPUT_CHANNELS 32
205 struct str_AnalogReadInformation {
207 unsigned char b_Type;
208 /* Interrupt use or not */
209 unsigned char b_InterruptFlag;
210 /* Selection of the conversion time */
211 unsigned int ui_ConvertTiming;
212 /* Number of channel to read */
213 unsigned char b_NbrOfChannel;
214 /* Number of the channel to be read */
215 unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS];
216 /* Gain of each channel */
217 unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS];
220 /* ANALOG INPUT RANGE */
221 static const struct comedi_lrange range_apci3120_ai = {
234 /* ANALOG OUTPUT RANGE */
235 static const struct comedi_lrange range_apci3120_ao = {
243 /* FUNCTION DEFINITIONS */
246 +----------------------------------------------------------------------------+
247 | ANALOG INPUT SUBDEVICE |
248 +----------------------------------------------------------------------------+
251 static int apci3120_ai_insn_config(struct comedi_device *dev,
252 struct comedi_subdevice *s,
253 struct comedi_insn *insn,
256 const struct addi_board *this_board = comedi_board(dev);
257 struct addi_private *devpriv = dev->private;
260 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
263 /* Check for Conversion time to be added ?? */
264 devpriv->ui_EocEosConversionTime = data[2];
266 if (data[0] == APCI3120_EOS_MODE) {
268 /* Test the number of the channel */
269 for (i = 0; i < data[3]; i++) {
271 if (CR_CHAN(data[4 + i]) >=
272 this_board->i_NbrAiChannel) {
273 printk("bad channel list\n");
278 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
281 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
283 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
284 /* Copy channel list and Range List to devpriv */
286 devpriv->ui_AiNbrofChannels = data[3];
287 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
288 devpriv->ui_AiChannelList[i] = data[4 + i];
291 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
293 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
295 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
302 * This function will first check channel list is ok or not and then
303 * initialize the sequence RAM with the polarity, Gain,Channel number.
304 * If the last argument of function "check"is 1 then it only checks
305 * the channel list is ok or not.
307 static int apci3120_setup_chan_list(struct comedi_device *dev,
308 struct comedi_subdevice *s,
310 unsigned int *chanlist,
313 struct addi_private *devpriv = dev->private;
314 unsigned int i; /* , differencial=0, bipolar=0; */
316 unsigned short us_TmpValue;
318 /* correct channel and range number check itself comedi/range.c */
321 comedi_error(dev, "range/channel list is empty!");
324 /* All is ok, so we can setup channel/range list */
328 /* Code to set the PA and PR...Here it set PA to 0.. */
329 devpriv->us_OutputRegister =
330 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
331 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
332 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
334 for (i = 0; i < n_chan; i++) {
335 /* store range list to card */
336 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
338 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
339 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
341 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
343 gain = CR_RANGE(chanlist[i]); /* get gain number */
344 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
345 us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
346 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
348 printk("\n Gain = %i",
349 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
350 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
351 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
353 return 1; /* we can serve this with scan logic */
357 * Reads analog input in synchronous mode EOC and EOS is selected
358 * as per configured if no conversion time is set uses default
359 * conversion time 10 microsec.
361 static int apci3120_ai_insn_read(struct comedi_device *dev,
362 struct comedi_subdevice *s,
363 struct comedi_insn *insn,
366 const struct addi_board *this_board = comedi_board(dev);
367 struct addi_private *devpriv = dev->private;
368 unsigned short us_ConvertTiming, us_TmpValue, i;
371 /* fix conversion time to 10 us */
372 if (!devpriv->ui_EocEosConversionTime) {
373 printk("No timer0 Value using 10 us\n");
374 us_ConvertTiming = 10;
376 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
378 /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
380 /* Clear software registers */
381 devpriv->b_TimerSelectMode = 0;
382 devpriv->b_ModeSelectRegister = 0;
383 devpriv->us_OutputRegister = 0;
384 /* devpriv->b_DigitalOutputRegister=0; */
386 if (insn->unused[0] == 222) { /* second insn read */
387 for (i = 0; i < insn->n; i++)
388 data[i] = devpriv->ui_AiReadData[i];
390 devpriv->tsk_Current = current; /* Save the current process task structure */
392 * Testing if board have the new Quartz and calculate the time value
393 * to set in the timer
397 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
399 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
400 if ((us_TmpValue & 0x00B0) == 0x00B0
401 || !strcmp(this_board->pc_DriverName, "apci3001")) {
402 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
405 ((us_ConvertTiming * 12926) / 10000) - 1;
408 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
410 switch (us_TmpValue) {
412 case APCI3120_EOC_MODE:
415 * Testing the interrupt flag and set the EOC bit Clears the FIFO
417 inw(devpriv->iobase + APCI3120_RESET_FIFO);
419 /* Initialize the sequence array */
420 if (!apci3120_setup_chan_list(dev, s, 1,
424 /* Initialize Timer 0 mode 4 */
425 devpriv->b_TimerSelectMode =
427 b_TimerSelectMode & 0xFC) |
428 APCI3120_TIMER_0_MODE_4;
429 outb(devpriv->b_TimerSelectMode,
430 devpriv->iobase + APCI3120_TIMER_CRT1);
432 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
433 devpriv->b_ModeSelectRegister =
435 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
437 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
439 /* Disables the EOS,DMA and enables the EOC interrupt */
440 devpriv->b_ModeSelectRegister =
442 b_ModeSelectRegister &
443 APCI3120_DISABLE_EOS_INT) |
444 APCI3120_ENABLE_EOC_INT;
445 inw(devpriv->iobase);
448 devpriv->b_ModeSelectRegister =
450 b_ModeSelectRegister &
451 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
454 outb(devpriv->b_ModeSelectRegister,
455 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
458 devpriv->us_OutputRegister =
460 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
461 APCI3120_ENABLE_TIMER0;
462 outw(devpriv->us_OutputRegister,
463 devpriv->iobase + APCI3120_WR_ADDRESS);
467 b_DigitalOutputRegister) & 0xF0) |
468 APCI3120_SELECT_TIMER_0_WORD;
469 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
471 /* Set the conversion time */
472 outw(us_ConvertTiming,
473 devpriv->iobase + APCI3120_TIMER_VALUE);
476 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
478 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
481 /* Waiting for the end of conversion */
483 inw(devpriv->iobase +
485 } while ((us_TmpValue & APCI3120_EOC) ==
488 /* Read the result in FIFO and put it in insn data pointer */
489 us_TmpValue = inw(devpriv->iobase + 0);
492 inw(devpriv->iobase + APCI3120_RESET_FIFO);
497 case APCI3120_EOS_MODE:
499 inw(devpriv->iobase);
500 /* Clears the FIFO */
501 inw(devpriv->iobase + APCI3120_RESET_FIFO);
502 /* clear PA PR and disable timer 0 */
504 devpriv->us_OutputRegister =
506 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
507 APCI3120_DISABLE_TIMER0;
509 outw(devpriv->us_OutputRegister,
510 devpriv->iobase + APCI3120_WR_ADDRESS);
512 if (!apci3120_setup_chan_list(dev, s,
513 devpriv->ui_AiNbrofChannels,
514 devpriv->ui_AiChannelList, 0))
517 /* Initialize Timer 0 mode 2 */
518 devpriv->b_TimerSelectMode =
520 b_TimerSelectMode & 0xFC) |
521 APCI3120_TIMER_0_MODE_2;
522 outb(devpriv->b_TimerSelectMode,
523 devpriv->iobase + APCI3120_TIMER_CRT1);
527 b_DigitalOutputRegister) & 0xF0) |
528 APCI3120_SELECT_TIMER_0_WORD;
529 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
531 /* Set the conversion time */
532 outw(us_ConvertTiming,
533 devpriv->iobase + APCI3120_TIMER_VALUE);
535 /* Set the scan bit */
536 devpriv->b_ModeSelectRegister =
538 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
539 outb(devpriv->b_ModeSelectRegister,
540 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
542 /* If Interrupt function is loaded */
543 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
544 /* Disables the EOC,DMA and enables the EOS interrupt */
545 devpriv->b_ModeSelectRegister =
547 b_ModeSelectRegister &
548 APCI3120_DISABLE_EOC_INT) |
549 APCI3120_ENABLE_EOS_INT;
550 inw(devpriv->iobase);
553 devpriv->b_ModeSelectRegister =
555 b_ModeSelectRegister &
556 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
558 outb(devpriv->b_ModeSelectRegister,
559 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
561 inw(devpriv->iobase + APCI3120_RD_STATUS);
565 devpriv->us_OutputRegister =
567 us_OutputRegister | APCI3120_ENABLE_TIMER0;
568 outw(devpriv->us_OutputRegister,
569 devpriv->iobase + APCI3120_WR_ADDRESS);
571 /* Start conversion */
572 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
574 /* Waiting of end of conversion if interrupt is not installed */
575 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
576 /* Waiting the end of conversion */
579 inw(devpriv->iobase +
581 } while ((us_TmpValue & APCI3120_EOS) !=
584 for (i = 0; i < devpriv->ui_AiNbrofChannels;
586 /* Read the result in FIFO and write them in shared memory */
587 us_TmpValue = inw(devpriv->iobase);
588 data[i] = (unsigned int) us_TmpValue;
591 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
596 printk("inputs wrong\n");
599 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
606 static int apci3120_reset(struct comedi_device *dev)
608 struct addi_private *devpriv = dev->private;
610 unsigned short us_TmpValue;
612 devpriv->ai_running = 0;
613 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
614 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
615 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
617 /* variables used in timer subdevice */
618 devpriv->b_Timer2Mode = 0;
619 devpriv->b_Timer2Interrupt = 0;
620 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
622 /* Disable all interrupts, watchdog for the anolog output */
623 devpriv->b_ModeSelectRegister = 0;
624 outb(devpriv->b_ModeSelectRegister,
625 dev->iobase + APCI3120_WRITE_MODE_SELECT);
627 /* Disables all counters, ext trigger and clears PA, PR */
628 devpriv->us_OutputRegister = 0;
629 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
632 * Code to set the all anolog o/p channel to 0v 8191 is decimal
633 * value for zero(0 v)volt in bipolar mode(default)
635 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
636 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
637 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
638 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
640 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
641 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
642 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
643 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
645 /* Reset digital output to L0W */
647 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
650 inw(dev->iobase + 0); /* make a dummy read */
651 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
652 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
654 /* code to reset the RAM sequence */
655 for (i = 0; i < 16; i++) {
656 us_TmpValue = i << 8; /* select the location */
657 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
662 static int apci3120_exttrig_enable(struct comedi_device *dev)
664 struct addi_private *devpriv = dev->private;
666 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
667 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
671 static int apci3120_exttrig_disable(struct comedi_device *dev)
673 struct addi_private *devpriv = dev->private;
675 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
676 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
680 static int apci3120_cancel(struct comedi_device *dev,
681 struct comedi_subdevice *s)
683 struct addi_private *devpriv = dev->private;
685 /* Disable A2P Fifo write and AMWEN signal */
686 outw(0, devpriv->i_IobaseAddon + 4);
688 /* Disable Bus Master ADD ON */
689 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
690 outw(0, devpriv->i_IobaseAddon + 2);
691 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
692 outw(0, devpriv->i_IobaseAddon + 2);
694 /* Disable BUS Master PCI */
695 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
697 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
698 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
700 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
701 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
703 /* Disable ext trigger */
704 apci3120_exttrig_disable(dev);
706 devpriv->us_OutputRegister = 0;
709 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
710 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
712 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
714 /* DISABLE_ALL_INTERRUPT */
715 outb(APCI3120_DISABLE_ALL_INTERRUPT,
716 dev->iobase + APCI3120_WRITE_MODE_SELECT);
718 inb(dev->iobase + APCI3120_RESET_FIFO);
719 inw(dev->iobase + APCI3120_RD_STATUS);
720 devpriv->ui_AiActualScan = 0;
721 s->async->cur_chan = 0;
722 devpriv->ui_DmaActualBuffer = 0;
724 devpriv->ai_running = 0;
725 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
726 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
731 static int apci3120_ai_cmdtest(struct comedi_device *dev,
732 struct comedi_subdevice *s,
733 struct comedi_cmd *cmd)
737 /* Step 1 : check if triggers are trivially valid */
739 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
740 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
741 TRIG_TIMER | TRIG_FOLLOW);
742 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
743 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
744 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
749 /* Step 2a : make sure trigger sources are unique */
751 err |= cfc_check_trigger_is_unique(cmd->start_src);
752 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
753 err |= cfc_check_trigger_is_unique(cmd->stop_src);
755 /* Step 2b : and mutually compatible */
760 /* Step 3: check if arguments are trivially valid */
762 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
764 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
765 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
767 if (cmd->scan_begin_src == TRIG_TIMER) {
768 if (cmd->convert_arg)
769 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
772 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
775 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
776 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
778 if (cmd->stop_src == TRIG_COUNT)
779 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
781 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
786 /* step 4: fix up any arguments */
788 if (cmd->scan_begin_src == TRIG_TIMER &&
789 cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
790 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
801 * This is used for analog input cyclic acquisition.
802 * Performs the command operations.
803 * If DMA is configured does DMA initialization otherwise does the
804 * acquisition with EOS interrupt.
806 static int apci3120_cyclic_ai(int mode,
807 struct comedi_device *dev,
808 struct comedi_subdevice *s)
810 const struct addi_board *this_board = comedi_board(dev);
811 struct addi_private *devpriv = dev->private;
812 struct comedi_cmd *cmd = &s->async->cmd;
814 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
815 0, dmalen1 = 0, ui_TimerValue2 =
816 0, ui_TimerValue0, ui_ConvertTiming;
817 unsigned short us_TmpValue;
819 /*******************/
820 /* Resets the FIFO */
821 /*******************/
822 inb(dev->iobase + APCI3120_RESET_FIFO);
824 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
825 /* inw(dev->iobase+APCI3120_RD_STATUS); */
826 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
828 devpriv->ai_running = 1;
830 /* clear software registers */
831 devpriv->b_TimerSelectMode = 0;
832 devpriv->us_OutputRegister = 0;
833 devpriv->b_ModeSelectRegister = 0;
834 /* devpriv->b_DigitalOutputRegister=0; */
836 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
838 /****************************/
839 /* Clear Timer Write TC int */
840 /****************************/
841 outl(APCI3120_CLEAR_WRITE_TC_INT,
842 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
844 /************************************/
845 /* Clears the timer status register */
846 /************************************/
848 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
849 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
850 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
851 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
853 /**************************/
854 /* Disables All Timer */
855 /* Sets PR and PA to 0 */
856 /**************************/
857 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
858 APCI3120_DISABLE_TIMER0 &
859 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
861 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
863 /*******************/
864 /* Resets the FIFO */
865 /*******************/
866 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
867 inb(devpriv->iobase + APCI3120_RESET_FIFO);
868 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
870 devpriv->ui_AiActualScan = 0;
871 s->async->cur_chan = 0;
872 devpriv->ui_DmaActualBuffer = 0;
874 /* value for timer2 minus -2 has to be done .....dunno y?? */
875 ui_TimerValue2 = cmd->stop_arg - 2;
876 ui_ConvertTiming = cmd->convert_arg;
879 ui_DelayTiming = cmd->scan_begin_arg;
881 /**********************************/
882 /* Initializes the sequence array */
883 /**********************************/
884 if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
888 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
889 /*** EL241003 : add this section in comment because floats must not be used
890 if((us_TmpValue & 0x00B0)==0x00B0)
892 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
893 ui_TimerValue0=(unsigned int)f_ConvertValue;
896 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
897 ui_TimerValue1 = (unsigned int) f_DelayValue;
902 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
903 ui_TimerValue0=(unsigned int)f_ConvertValue;
906 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
907 ui_TimerValue1 = (unsigned int) f_DelayValue;
910 ***********************************************************************************************/
911 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
912 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
913 if ((us_TmpValue & 0x00B0) == 0x00B0
914 || !strcmp(this_board->pc_DriverName, "apci3001")) {
915 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
916 ui_TimerValue0 = ui_TimerValue0 / 1000;
919 ui_DelayTiming = ui_DelayTiming / 1000;
920 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
921 ui_TimerValue1 = ui_TimerValue1 / 100;
924 ui_ConvertTiming = ui_ConvertTiming / 1000;
925 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
926 ui_TimerValue0 = ui_TimerValue0 / 10000;
929 ui_DelayTiming = ui_DelayTiming / 1000;
930 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
931 ui_TimerValue1 = ui_TimerValue1 / 1000000;
934 /*** EL241003 End ******************************************************************************/
936 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
937 apci3120_exttrig_enable(dev); /* activate EXT trigger */
940 /* init timer0 in mode 2 */
941 devpriv->b_TimerSelectMode =
943 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
944 outb(devpriv->b_TimerSelectMode,
945 dev->iobase + APCI3120_TIMER_CRT1);
949 b_DigitalOutputRegister) & 0xF0) |
950 APCI3120_SELECT_TIMER_0_WORD;
951 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
952 /* Set the conversion time */
953 outw(((unsigned short) ui_TimerValue0),
954 dev->iobase + APCI3120_TIMER_VALUE);
958 /* init timer1 in mode 2 */
959 devpriv->b_TimerSelectMode =
961 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
962 outb(devpriv->b_TimerSelectMode,
963 dev->iobase + APCI3120_TIMER_CRT1);
967 b_DigitalOutputRegister) & 0xF0) |
968 APCI3120_SELECT_TIMER_1_WORD;
969 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
970 /* Set the conversion time */
971 outw(((unsigned short) ui_TimerValue1),
972 dev->iobase + APCI3120_TIMER_VALUE);
974 /* init timer0 in mode 2 */
975 devpriv->b_TimerSelectMode =
977 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
978 outb(devpriv->b_TimerSelectMode,
979 dev->iobase + APCI3120_TIMER_CRT1);
983 b_DigitalOutputRegister) & 0xF0) |
984 APCI3120_SELECT_TIMER_0_WORD;
985 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
987 /* Set the conversion time */
988 outw(((unsigned short) ui_TimerValue0),
989 dev->iobase + APCI3120_TIMER_VALUE);
993 /* ##########common for all modes################# */
995 /***********************/
996 /* Clears the SCAN bit */
997 /***********************/
999 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1000 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
1002 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1003 APCI3120_DISABLE_SCAN;
1004 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1006 outb(devpriv->b_ModeSelectRegister,
1007 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1009 /* If DMA is disabled */
1010 if (devpriv->us_UseDma == APCI3120_DISABLE) {
1011 /* disable EOC and enable EOS */
1012 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
1013 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
1015 devpriv->b_ModeSelectRegister =
1017 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
1018 APCI3120_ENABLE_EOS_INT;
1019 outb(devpriv->b_ModeSelectRegister,
1020 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1022 if (cmd->stop_src == TRIG_COUNT) {
1024 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
1025 * disable it (Set Bit D14 to 0)
1027 devpriv->us_OutputRegister =
1029 us_OutputRegister & APCI3120_DISABLE_TIMER2;
1030 outw(devpriv->us_OutputRegister,
1031 dev->iobase + APCI3120_WR_ADDRESS);
1033 /* DISABLE TIMER intERRUPT */
1034 devpriv->b_ModeSelectRegister =
1036 b_ModeSelectRegister &
1037 APCI3120_DISABLE_TIMER_INT & 0xEF;
1038 outb(devpriv->b_ModeSelectRegister,
1039 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1041 /* (1) Init timer 2 in mode 0 and write timer value */
1042 devpriv->b_TimerSelectMode =
1044 b_TimerSelectMode & 0x0F) |
1045 APCI3120_TIMER_2_MODE_0;
1046 outb(devpriv->b_TimerSelectMode,
1047 dev->iobase + APCI3120_TIMER_CRT1);
1049 /* Writing LOW unsigned short */
1051 b_DigitalOutputRegister) & 0xF0) |
1052 APCI3120_SELECT_TIMER_2_LOW_WORD;
1053 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1054 outw(ui_TimerValue2 & 0xffff,
1055 dev->iobase + APCI3120_TIMER_VALUE);
1057 /* Writing HIGH unsigned short */
1059 b_DigitalOutputRegister) & 0xF0) |
1060 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1061 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1062 outw((ui_TimerValue2 >> 16) & 0xffff,
1063 dev->iobase + APCI3120_TIMER_VALUE);
1065 /* (2) Reset FC_TIMER BIT Clearing timer status register */
1066 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1067 /* enable timer counter and disable watch dog */
1068 devpriv->b_ModeSelectRegister =
1070 b_ModeSelectRegister |
1071 APCI3120_ENABLE_TIMER_COUNTER) &
1072 APCI3120_DISABLE_WATCHDOG;
1073 /* select EOS clock input for timer 2 */
1074 devpriv->b_ModeSelectRegister =
1076 b_ModeSelectRegister |
1077 APCI3120_TIMER2_SELECT_EOS;
1078 /* Enable timer2 interrupt */
1079 devpriv->b_ModeSelectRegister =
1081 b_ModeSelectRegister |
1082 APCI3120_ENABLE_TIMER_INT;
1083 outb(devpriv->b_ModeSelectRegister,
1084 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1085 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1086 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1089 /* If DMA Enabled */
1090 unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short);
1092 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1093 /* inw(dev->iobase+0); reset EOC bit */
1094 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1095 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1097 /************************************/
1098 /* Disables the EOC, EOS interrupt */
1099 /************************************/
1100 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1101 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1103 outb(devpriv->b_ModeSelectRegister,
1104 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1106 dmalen0 = devpriv->ui_DmaBufferSize[0];
1107 dmalen1 = devpriv->ui_DmaBufferSize[1];
1109 if (cmd->stop_src == TRIG_COUNT) {
1111 * Must we fill full first buffer? And must we fill
1112 * full second buffer when first is once filled?
1114 if (dmalen0 > (cmd->stop_arg * scan_bytes)) {
1115 dmalen0 = cmd->stop_arg * scan_bytes;
1116 } else if (dmalen1 > (cmd->stop_arg * scan_bytes -
1118 dmalen1 = cmd->stop_arg * scan_bytes -
1122 if (cmd->flags & TRIG_WAKE_EOS) {
1123 /* don't we want wake up every scan? */
1124 if (dmalen0 > scan_bytes) {
1125 dmalen0 = scan_bytes;
1126 if (cmd->scan_end_arg & 1)
1129 if (dmalen1 > scan_bytes) {
1130 dmalen1 = scan_bytes;
1131 if (cmd->scan_end_arg & 1)
1136 } else { /* isn't output buff smaller that our DMA buff? */
1137 if (dmalen0 > s->async->prealloc_bufsz)
1138 dmalen0 = s->async->prealloc_bufsz;
1139 if (dmalen1 > s->async->prealloc_bufsz)
1140 dmalen1 = s->async->prealloc_bufsz;
1142 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1143 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1145 /* Initialize DMA */
1148 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1151 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1152 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1154 /* changed since 16 bit interface for add on */
1155 /*********************/
1156 /* ENABLE BUS MASTER */
1157 /*********************/
1158 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1159 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1160 devpriv->i_IobaseAddon + 2);
1162 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1163 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1164 devpriv->i_IobaseAddon + 2);
1167 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1170 outw(0x1000, devpriv->i_IobaseAddon + 2);
1171 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1174 /* A2P FIFO MANAGEMENT */
1175 /* A2P fifo reset & transfer control enable */
1177 /***********************/
1178 /* A2P FIFO MANAGEMENT */
1179 /***********************/
1180 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1181 APCI3120_AMCC_OP_MCSR);
1185 * beginning address of dma buf The 32 bit address of dma buffer
1186 * is converted into two 16 bit addresses Can done by using _attach
1187 * and put into into an array array used may be for differnet pages
1190 /* DMA Start Address Low */
1191 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1192 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1193 devpriv->i_IobaseAddon + 2);
1195 /*************************/
1196 /* DMA Start Address High */
1197 /*************************/
1198 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1199 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1200 devpriv->i_IobaseAddon + 2);
1204 * amount of bytes to be transferred set transfer count used ADDON
1205 * MWTC register commented testing
1206 * outl(devpriv->ui_DmaBufferUsesize[0],
1207 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1210 /**************************/
1211 /* Nbr of acquisition LOW */
1212 /**************************/
1213 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1214 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1215 devpriv->i_IobaseAddon + 2);
1217 /***************************/
1218 /* Nbr of acquisition HIGH */
1219 /***************************/
1220 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1221 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1222 devpriv->i_IobaseAddon + 2);
1226 * To configure A2P FIFO testing outl(
1227 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1230 /******************/
1231 /* A2P FIFO RESET */
1232 /******************/
1234 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1237 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1238 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1242 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1243 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1246 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1247 /* outw(3,devpriv->i_IobaseAddon + 4); */
1248 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1252 * initialise end of dma interrupt AINT_WRITE_COMPL =
1253 * ENABLE_WRITE_TC_INT(ADDI)
1255 /***************************************************/
1256 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1257 /***************************************************/
1258 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1259 APCI3120_ENABLE_WRITE_TC_INT),
1260 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1262 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1263 /******************************************/
1264 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1265 /******************************************/
1266 outw(3, devpriv->i_IobaseAddon + 4);
1267 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1269 /******************/
1270 /* A2P FIFO RESET */
1271 /******************/
1272 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1274 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1275 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1278 if (devpriv->us_UseDma == APCI3120_DISABLE &&
1279 cmd->stop_src == TRIG_COUNT) {
1280 /* set gate 2 to start conversion */
1281 devpriv->us_OutputRegister =
1282 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1283 outw(devpriv->us_OutputRegister,
1284 dev->iobase + APCI3120_WR_ADDRESS);
1289 /* set gate 0 to start conversion */
1290 devpriv->us_OutputRegister =
1291 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1292 outw(devpriv->us_OutputRegister,
1293 dev->iobase + APCI3120_WR_ADDRESS);
1296 /* set gate 0 and gate 1 */
1297 devpriv->us_OutputRegister =
1298 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1299 devpriv->us_OutputRegister =
1300 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1301 outw(devpriv->us_OutputRegister,
1302 dev->iobase + APCI3120_WR_ADDRESS);
1312 * Does asynchronous acquisition.
1313 * Determines the mode 1 or 2.
1315 static int apci3120_ai_cmd(struct comedi_device *dev,
1316 struct comedi_subdevice *s)
1318 struct addi_private *devpriv = dev->private;
1319 struct comedi_cmd *cmd = &s->async->cmd;
1321 /* loading private structure with cmd structure inputs */
1322 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
1324 if (cmd->start_src == TRIG_EXT)
1325 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
1327 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1329 if (cmd->scan_begin_src == TRIG_FOLLOW)
1330 return apci3120_cyclic_ai(1, dev, s);
1331 else /* TRIG_TIMER */
1332 return apci3120_cyclic_ai(2, dev, s);
1336 * This function copies the data from DMA buffer to the Comedi buffer.
1338 static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1339 struct comedi_subdevice *s,
1340 unsigned short *dma_buffer,
1341 unsigned int num_samples)
1343 struct addi_private *devpriv = dev->private;
1344 struct comedi_cmd *cmd = &s->async->cmd;
1346 devpriv->ui_AiActualScan +=
1347 (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
1348 s->async->cur_chan += num_samples;
1349 s->async->cur_chan %= cmd->scan_end_arg;
1351 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1355 * This is a handler for the DMA interrupt.
1356 * This function copies the data to Comedi Buffer.
1357 * For continuous DMA it reinitializes the DMA operation.
1358 * For single mode DMA it stop the acquisition.
1360 static void apci3120_interrupt_dma(int irq, void *d)
1362 struct comedi_device *dev = d;
1363 struct addi_private *devpriv = dev->private;
1364 struct comedi_subdevice *s = dev->read_subdev;
1365 struct comedi_cmd *cmd = &s->async->cmd;
1366 unsigned int next_dma_buf, samplesinbuf;
1367 unsigned long low_word, high_word, var;
1368 unsigned int ui_Tmp;
1371 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1372 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1375 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1376 comedi_error(dev, "Interrupted DMA transfer!");
1378 if (samplesinbuf & 1) {
1379 comedi_error(dev, "Odd count of bytes in DMA ring!");
1380 apci3120_cancel(dev, s);
1383 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1384 if (devpriv->b_DmaDoubleBuffer) {
1385 /* switch DMA buffers if is used double buffering */
1386 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1388 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1389 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1391 /* changed since 16 bit interface for add on */
1392 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1393 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1394 devpriv->i_IobaseAddon + 2);
1395 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1396 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1398 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1399 low_word = var & 0xffff;
1400 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1401 high_word = var / 65536;
1403 /* DMA Start Address Low */
1404 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1405 outw(low_word, devpriv->i_IobaseAddon + 2);
1407 /* DMA Start Address High */
1408 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1409 outw(high_word, devpriv->i_IobaseAddon + 2);
1411 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1412 low_word = var & 0xffff;
1413 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1414 high_word = var / 65536;
1416 /* Nbr of acquisition LOW */
1417 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1418 outw(low_word, devpriv->i_IobaseAddon + 2);
1420 /* Nbr of acquisition HIGH */
1421 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1422 outw(high_word, devpriv->i_IobaseAddon + 2);
1425 * To configure A2P FIFO
1426 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1427 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1429 outw(3, devpriv->i_IobaseAddon + 4);
1430 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1431 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1432 APCI3120_ENABLE_WRITE_TC_INT),
1433 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1437 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1438 devpriv->ul_DmaBufferVirtual[devpriv->
1439 ui_DmaActualBuffer], samplesinbuf);
1441 if (!(cmd->flags & TRIG_WAKE_EOS)) {
1442 s->async->events |= COMEDI_CB_EOS;
1443 comedi_event(dev, s);
1446 if (cmd->stop_src == TRIG_COUNT)
1447 if (devpriv->ui_AiActualScan >= cmd->stop_arg) {
1448 /* all data sampled */
1449 apci3120_cancel(dev, s);
1450 s->async->events |= COMEDI_CB_EOA;
1451 comedi_event(dev, s);
1455 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1456 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1459 * restart DMA if is not used double buffering
1460 * ADDED REINITIALISE THE DMA
1462 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1463 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1465 /* changed since 16 bit interface for add on */
1466 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1467 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1468 devpriv->i_IobaseAddon + 2);
1469 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1470 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1472 * A2P FIFO MANAGEMENT
1473 * A2P fifo reset & transfer control enable
1475 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1476 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1478 var = devpriv->ul_DmaBufferHw[0];
1479 low_word = var & 0xffff;
1480 var = devpriv->ul_DmaBufferHw[0];
1481 high_word = var / 65536;
1482 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1483 outw(low_word, devpriv->i_IobaseAddon + 2);
1484 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1485 outw(high_word, devpriv->i_IobaseAddon + 2);
1487 var = devpriv->ui_DmaBufferUsesize[0];
1488 low_word = var & 0xffff; /* changed */
1489 var = devpriv->ui_DmaBufferUsesize[0];
1490 high_word = var / 65536;
1491 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1492 outw(low_word, devpriv->i_IobaseAddon + 2);
1493 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1494 outw(high_word, devpriv->i_IobaseAddon + 2);
1497 * To configure A2P FIFO
1498 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1499 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1501 outw(3, devpriv->i_IobaseAddon + 4);
1502 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1503 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1504 APCI3120_ENABLE_WRITE_TC_INT),
1505 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1510 * This function handles EOS interrupt.
1511 * This function copies the acquired data(from FIFO) to Comedi buffer.
1513 static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
1515 struct addi_private *devpriv = dev->private;
1516 struct comedi_subdevice *s = dev->read_subdev;
1520 n_chan = devpriv->ui_AiNbrofChannels;
1522 for (i = 0; i < n_chan; i++)
1523 err &= comedi_buf_put(s, inw(dev->iobase + 0));
1525 s->async->events |= COMEDI_CB_EOS;
1528 s->async->events |= COMEDI_CB_OVERFLOW;
1530 comedi_event(dev, s);
1535 static void apci3120_interrupt(int irq, void *d)
1537 struct comedi_device *dev = d;
1538 struct addi_private *devpriv = dev->private;
1539 struct comedi_subdevice *s = dev->read_subdev;
1540 unsigned short int_daq;
1541 unsigned int int_amcc, ui_Check, i;
1542 unsigned short us_TmpValue;
1543 unsigned char b_DummyRead;
1547 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1548 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1550 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1551 comedi_error(dev, "IRQ from unknown source");
1555 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1557 int_daq = (int_daq >> 12) & 0xF;
1559 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1560 /* Disable ext trigger */
1561 apci3120_exttrig_disable(dev);
1562 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1564 /* clear the timer 2 interrupt */
1565 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1567 if (int_amcc & MASTER_ABORT_INT)
1568 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1569 if (int_amcc & TARGET_ABORT_INT)
1570 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1572 /* Ckeck if EOC interrupt */
1573 if (((int_daq & 0x8) == 0)
1574 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1575 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1577 /* Read the AI Value */
1579 devpriv->ui_AiReadData[0] =
1580 (unsigned int) inw(devpriv->iobase + 0);
1581 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1582 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1584 /* Disable EOC Interrupt */
1585 devpriv->b_ModeSelectRegister =
1587 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1588 outb(devpriv->b_ModeSelectRegister,
1589 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1594 /* Check If EOS interrupt */
1595 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1597 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
1599 if (devpriv->ai_running) {
1601 apci3120_interrupt_handle_eos(dev);
1602 devpriv->ui_AiActualScan++;
1603 devpriv->b_ModeSelectRegister =
1605 b_ModeSelectRegister |
1606 APCI3120_ENABLE_EOS_INT;
1607 outb(devpriv->b_ModeSelectRegister,
1609 APCI3120_WRITE_MODE_SELECT);
1612 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1614 us_TmpValue = inw(devpriv->iobase + 0);
1615 devpriv->ui_AiReadData[i] =
1616 (unsigned int) us_TmpValue;
1618 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1619 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1621 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1626 devpriv->b_ModeSelectRegister =
1628 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1629 outb(devpriv->b_ModeSelectRegister,
1630 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1631 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1632 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1636 /* Timer2 interrupt */
1637 if (int_daq & 0x1) {
1639 switch (devpriv->b_Timer2Mode) {
1640 case APCI3120_COUNTER:
1641 devpriv->b_ModeSelectRegister =
1643 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1644 outb(devpriv->b_ModeSelectRegister,
1645 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1648 devpriv->us_OutputRegister =
1650 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1651 outw(devpriv->us_OutputRegister,
1652 dev->iobase + APCI3120_WR_ADDRESS);
1654 /* stop timer 0 and timer 1 */
1655 apci3120_cancel(dev, s);
1657 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1658 s->async->events |= COMEDI_CB_EOA;
1659 comedi_event(dev, s);
1663 case APCI3120_TIMER:
1665 /* Send a signal to from kernel to user space */
1666 send_sig(SIGIO, devpriv->tsk_Current, 0);
1669 case APCI3120_WATCHDOG:
1671 /* Send a signal to from kernel to user space */
1672 send_sig(SIGIO, devpriv->tsk_Current, 0);
1677 /* disable Timer Interrupt */
1679 devpriv->b_ModeSelectRegister =
1681 b_ModeSelectRegister &
1682 APCI3120_DISABLE_TIMER_INT;
1684 outb(devpriv->b_ModeSelectRegister,
1685 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1689 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1693 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1694 if (devpriv->ai_running) {
1696 /****************************/
1697 /* Clear Timer Write TC int */
1698 /****************************/
1700 outl(APCI3120_CLEAR_WRITE_TC_INT,
1701 devpriv->i_IobaseAmcc +
1702 APCI3120_AMCC_OP_REG_INTCSR);
1704 /************************************/
1705 /* Clears the timer status register */
1706 /************************************/
1707 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1708 /* do some data transfer */
1709 apci3120_interrupt_dma(irq, d);
1711 /* Stops the Timer */
1713 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1714 APCI3120_DISABLE_TIMER1,
1715 dev->iobase + APCI3120_WR_ADDRESS);
1726 * data[0] = TIMER configure as timer
1727 * = WATCHDOG configure as watchdog
1728 * data[1] = Timer constant
1729 * data[2] = Timer2 interrupt (1)enable or(0) disable
1731 static int apci3120_config_insn_timer(struct comedi_device *dev,
1732 struct comedi_subdevice *s,
1733 struct comedi_insn *insn,
1736 const struct addi_board *this_board = comedi_board(dev);
1737 struct addi_private *devpriv = dev->private;
1738 unsigned int ui_Timervalue2;
1739 unsigned short us_TmpValue;
1740 unsigned char b_Tmp;
1743 comedi_error(dev, "config:No timer constant !");
1745 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1747 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1749 /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
1750 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1753 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1754 * is an APCI3001 and calculate the time value to set in the timer
1756 if ((us_TmpValue & 0x00B0) == 0x00B0
1757 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1758 /* Calculate the time value to set in the timer */
1759 ui_Timervalue2 = ui_Timervalue2 / 50;
1761 /* Calculate the time value to set in the timer */
1762 ui_Timervalue2 = ui_Timervalue2 / 70;
1765 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1766 devpriv->us_OutputRegister =
1767 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1768 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1770 /* Disable TIMER Interrupt */
1771 devpriv->b_ModeSelectRegister =
1773 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1775 /* Disable Eoc and Eos Interrupts */
1776 devpriv->b_ModeSelectRegister =
1778 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1779 APCI3120_DISABLE_EOS_INT;
1780 outb(devpriv->b_ModeSelectRegister,
1781 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1782 if (data[0] == APCI3120_TIMER) { /* initialize timer */
1783 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1784 * APCI3120_ENABLE_TIMER_INT; */
1786 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1788 /* Set the Timer 2 in mode 2(Timer) */
1789 devpriv->b_TimerSelectMode =
1791 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1792 outb(devpriv->b_TimerSelectMode,
1793 devpriv->iobase + APCI3120_TIMER_CRT1);
1796 * Configure the timer 2 for writing the LOW unsigned short of timer
1797 * is Delay value You must make a b_tmp variable with
1798 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1799 * you can set the digital output and configure the timer 2,and if
1800 * you don't make this, digital output are erase (Set to 0)
1803 /* Writing LOW unsigned short */
1805 b_DigitalOutputRegister) & 0xF0) |
1806 APCI3120_SELECT_TIMER_2_LOW_WORD;
1807 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1808 outw(ui_Timervalue2 & 0xffff,
1809 devpriv->iobase + APCI3120_TIMER_VALUE);
1811 /* Writing HIGH unsigned short */
1813 b_DigitalOutputRegister) & 0xF0) |
1814 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1815 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1816 outw((ui_Timervalue2 >> 16) & 0xffff,
1817 devpriv->iobase + APCI3120_TIMER_VALUE);
1818 /* timer2 in Timer mode enabled */
1819 devpriv->b_Timer2Mode = APCI3120_TIMER;
1821 } else { /* Initialize Watch dog */
1823 /* Set the Timer 2 in mode 5(Watchdog) */
1825 devpriv->b_TimerSelectMode =
1827 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1828 outb(devpriv->b_TimerSelectMode,
1829 devpriv->iobase + APCI3120_TIMER_CRT1);
1832 * Configure the timer 2 for writing the LOW unsigned short of timer
1833 * is Delay value You must make a b_tmp variable with
1834 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1835 * you can set the digital output and configure the timer 2,and if
1836 * you don't make this, digital output are erase (Set to 0)
1839 /* Writing LOW unsigned short */
1841 b_DigitalOutputRegister) & 0xF0) |
1842 APCI3120_SELECT_TIMER_2_LOW_WORD;
1843 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1844 outw(ui_Timervalue2 & 0xffff,
1845 devpriv->iobase + APCI3120_TIMER_VALUE);
1847 /* Writing HIGH unsigned short */
1849 b_DigitalOutputRegister) & 0xF0) |
1850 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1851 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1853 outw((ui_Timervalue2 >> 16) & 0xffff,
1854 devpriv->iobase + APCI3120_TIMER_VALUE);
1855 /* watchdog enabled */
1856 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1865 * To start and stop the timer
1867 * data[0] = 1 (start)
1869 * = 2 (write new value)
1870 * data[1] = new value
1872 * devpriv->b_Timer2Mode = 0 DISABLE
1876 static int apci3120_write_insn_timer(struct comedi_device *dev,
1877 struct comedi_subdevice *s,
1878 struct comedi_insn *insn,
1881 const struct addi_board *this_board = comedi_board(dev);
1882 struct addi_private *devpriv = dev->private;
1883 unsigned int ui_Timervalue2 = 0;
1884 unsigned short us_TmpValue;
1885 unsigned char b_Tmp;
1887 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1888 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1889 comedi_error(dev, "\nwrite:timer2 not configured ");
1893 if (data[0] == 2) { /* write new value */
1894 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1896 "write :timer2 not configured in TIMER MODE");
1901 ui_Timervalue2 = data[1];
1906 /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
1909 case APCI3120_START:
1911 /* Reset FC_TIMER BIT */
1912 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1913 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1915 devpriv->b_ModeSelectRegister =
1916 devpriv->b_ModeSelectRegister & 0x0B;
1917 } else { /* start watch dog */
1918 /* Enable WatchDog */
1919 devpriv->b_ModeSelectRegister =
1921 b_ModeSelectRegister & 0x0B) |
1922 APCI3120_ENABLE_WATCHDOG;
1925 /* enable disable interrupt */
1926 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1928 devpriv->b_ModeSelectRegister =
1930 b_ModeSelectRegister |
1931 APCI3120_ENABLE_TIMER_INT;
1932 /* save the task structure to pass info to user */
1933 devpriv->tsk_Current = current;
1936 devpriv->b_ModeSelectRegister =
1938 b_ModeSelectRegister &
1939 APCI3120_DISABLE_TIMER_INT;
1941 outb(devpriv->b_ModeSelectRegister,
1942 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1944 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1945 /* For Timer mode is Gate2 must be activated **timer started */
1946 devpriv->us_OutputRegister =
1948 us_OutputRegister | APCI3120_ENABLE_TIMER2;
1949 outw(devpriv->us_OutputRegister,
1950 devpriv->iobase + APCI3120_WR_ADDRESS);
1956 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1958 devpriv->b_ModeSelectRegister =
1960 b_ModeSelectRegister &
1961 APCI3120_DISABLE_TIMER_COUNTER;
1963 /* Disable WatchDog */
1964 devpriv->b_ModeSelectRegister =
1966 b_ModeSelectRegister &
1967 APCI3120_DISABLE_WATCHDOG;
1969 /* Disable timer interrupt */
1970 devpriv->b_ModeSelectRegister =
1972 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
1974 /* Write above states to register */
1975 outb(devpriv->b_ModeSelectRegister,
1976 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1979 devpriv->us_OutputRegister =
1980 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
1981 outw(devpriv->us_OutputRegister,
1982 devpriv->iobase + APCI3120_WR_ADDRESS);
1984 /* Reset FC_TIMER BIT */
1985 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1988 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
1992 case 2: /* write new value to Timer */
1993 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1995 "write :timer2 not configured in TIMER MODE");
1998 /* ui_Timervalue2=data[1]; // passed as argument */
2000 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2003 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2004 * is an APCI3001 and calculate the time value to set in the timer
2006 if ((us_TmpValue & 0x00B0) == 0x00B0
2007 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2008 /* Calculate the time value to set in the timer */
2009 ui_Timervalue2 = ui_Timervalue2 / 50;
2011 /* Calculate the time value to set in the timer */
2012 ui_Timervalue2 = ui_Timervalue2 / 70;
2014 /* Writing LOW unsigned short */
2016 b_DigitalOutputRegister) & 0xF0) |
2017 APCI3120_SELECT_TIMER_2_LOW_WORD;
2018 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2020 outw(ui_Timervalue2 & 0xffff,
2021 devpriv->iobase + APCI3120_TIMER_VALUE);
2023 /* Writing HIGH unsigned short */
2025 b_DigitalOutputRegister) & 0xF0) |
2026 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2027 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2029 outw((ui_Timervalue2 >> 16) & 0xffff,
2030 devpriv->iobase + APCI3120_TIMER_VALUE);
2034 return -EINVAL; /* Not a valid input */
2041 * Read the Timer value
2043 * for Timer: data[0]= Timer constant
2045 * for watchdog: data[0] = 0 (still running)
2048 static int apci3120_read_insn_timer(struct comedi_device *dev,
2049 struct comedi_subdevice *s,
2050 struct comedi_insn *insn,
2053 struct addi_private *devpriv = dev->private;
2054 unsigned char b_Tmp;
2055 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2057 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2058 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2059 comedi_error(dev, "\nread:timer2 not configured ");
2062 /* this_board->timer_read(dev,data); */
2063 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2065 /* Read the LOW unsigned short of Timer 2 register */
2067 b_DigitalOutputRegister) & 0xF0) |
2068 APCI3120_SELECT_TIMER_2_LOW_WORD;
2069 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2071 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2073 /* Read the HIGH unsigned short of Timer 2 register */
2075 b_DigitalOutputRegister) & 0xF0) |
2076 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2077 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2079 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2081 /* combining both words */
2082 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2084 } else { /* Read watch dog status */
2086 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2088 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2089 if (us_StatusValue == 1) {
2090 /* RESET FC_TIMER BIT */
2091 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2093 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2098 static int apci3120_di_insn_bits(struct comedi_device *dev,
2099 struct comedi_subdevice *s,
2100 struct comedi_insn *insn,
2103 struct addi_private *devpriv = dev->private;
2106 /* the input channels are bits 11:8 of the status reg */
2107 val = inw(devpriv->iobase + APCI3120_RD_STATUS);
2108 data[1] = (val >> 8) & 0xf;
2113 static int apci3120_do_insn_bits(struct comedi_device *dev,
2114 struct comedi_subdevice *s,
2115 struct comedi_insn *insn,
2118 struct addi_private *devpriv = dev->private;
2120 if (comedi_dio_update_state(s, data)) {
2121 /* The do channels are bits 7:4 of the do register */
2122 devpriv->b_DigitalOutputRegister = s->state << 4;
2124 outb(devpriv->b_DigitalOutputRegister,
2125 devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2133 static int apci3120_ao_insn_write(struct comedi_device *dev,
2134 struct comedi_subdevice *s,
2135 struct comedi_insn *insn,
2138 struct addi_private *devpriv = dev->private;
2139 unsigned int ui_Range, ui_Channel;
2140 unsigned short us_TmpValue;
2142 ui_Range = CR_RANGE(insn->chanspec);
2143 ui_Channel = CR_CHAN(insn->chanspec);
2145 /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
2146 if (ui_Range) { /* if 1 then unipolar */
2150 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2151 13) | (data[0] + 8191));
2154 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2157 } else { /* if 0 then bipolar */
2159 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2165 * out put n values at the given channel. printk("\nwaiting for
2168 do { /* Waiting of DA_READY BIT */
2170 ((unsigned short) inw(devpriv->iobase +
2171 APCI3120_RD_STATUS)) & 0x0001;
2172 } while (us_TmpValue != 0x0001);
2174 if (ui_Channel <= 3)
2176 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2177 * typecasted to ushort since word write is to be done
2179 outw((unsigned short) data[0],
2180 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2183 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2184 * typecasted to ushort since word write is to be done
2186 outw((unsigned short) data[0],
2187 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);