1 /**
2 @verbatim
3
4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
5
6 ADDI-DATA GmbH
7 Dieselstrasse 3
8 D-77833 Ottersweier
9 Tel: +19(0)7223/9493-0
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data.com
12 info@addi-data.com
13
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.
15
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.
17
18 @endverbatim
19 */
20 /*
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 +-----------------------------------------------------------------------+
34 | UPDATE'S |
35 +-----------------------------------------------------------------------+
36 | Date | Author | Description of updates |
37 +----------+-----------+------------------------------------------------+
38 | | | |
39 | | | |
40 +----------+-----------+------------------------------------------------+
41 */
42
43 #include <linux/delay.h>
44
45 /*
46 * ADDON RELATED ADDITIONS
47 */
48 /* Constant */
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
60
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)
68
69 /* AMCC */
70 #define APCI3120_AMCC_OP_MCSR 0x3C
71 #define APCI3120_AMCC_OP_REG_INTCSR 0x38
72
73 /* for transfer count enable bit */
74 #define AGCSTS_TC_ENABLE 0x10000000
75
76 /* used for test on mixture of BIP/UNI ranges */
77 #define APCI3120_BIPOLAR_RANGES 4
78
79 #define APCI3120_ADDRESS_RANGE 16
80
81 #define APCI3120_DISABLE 0
82 #define APCI3120_ENABLE 1
83
84 #define APCI3120_START 1
85 #define APCI3120_STOP 0
86
87 #define APCI3120_EOC_MODE 1
88 #define APCI3120_EOS_MODE 2
89 #define APCI3120_DMA_MODE 3
90
91 /* DIGITAL INPUT-OUTPUT DEFINE */
92
93 #define APCI3120_DIGITAL_OUTPUT 0x0d
94 #define APCI3120_RD_STATUS 0x02
95 #define APCI3120_RD_FIFO 0x00
96
97 /* digital output insn_write ON /OFF selection */
98 #define APCI3120_SET4DIGITALOUTPUTON 1
99 #define APCI3120_SET4DIGITALOUTPUTOFF 0
100
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
110
111 /* Enable external trigger bit in nWrAddress */
112 #define APCI3120_ENABLE_EXT_TRIGGER 0x8000
113
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)
132
133 /* nWrMode_Select */
134 #define APCI3120_ENABLE_SCAN 0x8
135 #define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN)
136 #define APCI3120_ENABLE_EOS_INT 0x2
137
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)
145
146 /* status register bits */
147 #define APCI3120_EOC 0x8000
148 #define APCI3120_EOS 0x2000
149
150 /* software trigger dummy register */
151 #define APCI3120_START_CONVERSION 0x02
152
153 /* TIMER DEFINE */
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
168
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
173
174 /* $$ BIT FOR MODE IN nCsTimerCtr0 */
175 #define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02
176 #define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03
177
178 #define APCI3120_TIMER_CRT0 0x0d
179 #define APCI3120_TIMER_CRT1 0x0c
180
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)
196
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)
202
203 #define MAX_ANALOGINPUT_CHANNELS 32
204
205 struct str_AnalogReadInformation {
206 /* EOC or EOS */
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];
218 };
219
220 /* ANALOG INPUT RANGE */
221 static const struct comedi_lrange range_apci3120_ai = {
222 8, {
223 BIP_RANGE(10),
224 BIP_RANGE(5),
225 BIP_RANGE(2),
226 BIP_RANGE(1),
227 UNI_RANGE(10),
228 UNI_RANGE(5),
229 UNI_RANGE(2),
230 UNI_RANGE(1)
231 }
232 };
233
234 /* ANALOG OUTPUT RANGE */
235 static const struct comedi_lrange range_apci3120_ao = {
236 2, {
237 BIP_RANGE(10),
238 UNI_RANGE(10)
239 }
240 };
241
242
243 /* FUNCTION DEFINITIONS */
apci3120_ai_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)244 static int apci3120_ai_insn_config(struct comedi_device *dev,
245 struct comedi_subdevice *s,
246 struct comedi_insn *insn,
247 unsigned int *data)
248 {
249 const struct addi_board *this_board = dev->board_ptr;
250 struct addi_private *devpriv = dev->private;
251 unsigned int i;
252
253 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
254 return -1;
255
256 /* Check for Conversion time to be added */
257 devpriv->ui_EocEosConversionTime = data[2];
258
259 if (data[0] == APCI3120_EOS_MODE) {
260
261 /* Test the number of the channel */
262 for (i = 0; i < data[3]; i++) {
263
264 if (CR_CHAN(data[4 + i]) >=
265 this_board->i_NbrAiChannel) {
266 dev_err(dev->class_dev, "bad channel list\n");
267 return -2;
268 }
269 }
270
271 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
272
273 if (data[1])
274 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
275 else
276 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
277 /* Copy channel list and Range List to devpriv */
278 devpriv->ui_AiNbrofChannels = data[3];
279 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
280 devpriv->ui_AiChannelList[i] = data[4 + i];
281
282 } else { /* EOC */
283 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
284 if (data[1])
285 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
286 else
287 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
288 }
289
290 return insn->n;
291 }
292
293 /*
294 * This function will first check channel list is ok or not and then
295 * initialize the sequence RAM with the polarity, Gain,Channel number.
296 * If the last argument of function "check"is 1 then it only checks
297 * the channel list is ok or not.
298 */
apci3120_setup_chan_list(struct comedi_device * dev,struct comedi_subdevice * s,int n_chan,unsigned int * chanlist,char check)299 static int apci3120_setup_chan_list(struct comedi_device *dev,
300 struct comedi_subdevice *s,
301 int n_chan,
302 unsigned int *chanlist,
303 char check)
304 {
305 struct addi_private *devpriv = dev->private;
306 unsigned int i;
307 unsigned int gain;
308 unsigned short us_TmpValue;
309
310 /* correct channel and range number check itself comedi/range.c */
311 if (n_chan < 1) {
312 if (!check)
313 dev_err(dev->class_dev,
314 "range/channel list is empty!\n");
315 return 0;
316 }
317 /* All is ok, so we can setup channel/range list */
318 if (check)
319 return 1;
320
321 /* Code to set the PA and PR...Here it set PA to 0 */
322 devpriv->us_OutputRegister =
323 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
324 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
325 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
326
327 for (i = 0; i < n_chan; i++) {
328 /* store range list to card */
329 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number */
330
331 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
332 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
333 else
334 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar */
335
336 gain = CR_RANGE(chanlist[i]); /* get gain number */
337 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
338 us_TmpValue |= i << 8; /* To select the RAM LOCATION */
339 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
340 }
341 return 1; /* we can serve this with scan logic */
342 }
343
344 /*
345 * Reads analog input in synchronous mode EOC and EOS is selected
346 * as per configured if no conversion time is set uses default
347 * conversion time 10 microsec.
348 */
apci3120_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)349 static int apci3120_ai_insn_read(struct comedi_device *dev,
350 struct comedi_subdevice *s,
351 struct comedi_insn *insn,
352 unsigned int *data)
353 {
354 const struct addi_board *this_board = dev->board_ptr;
355 struct addi_private *devpriv = dev->private;
356 unsigned short us_ConvertTiming, us_TmpValue, i;
357 unsigned char b_Tmp;
358
359 /* fix conversion time to 10 us */
360 if (!devpriv->ui_EocEosConversionTime)
361 us_ConvertTiming = 10;
362 else
363 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
364
365 /* Clear software registers */
366 devpriv->b_TimerSelectMode = 0;
367 devpriv->b_ModeSelectRegister = 0;
368 devpriv->us_OutputRegister = 0;
369
370 if (insn->unused[0] == 222) { /* second insn read */
371 for (i = 0; i < insn->n; i++)
372 data[i] = devpriv->ui_AiReadData[i];
373 } else {
374 devpriv->tsk_Current = current; /* Save the current process task structure */
375
376 /*
377 * Testing if board have the new Quartz and calculate the time value
378 * to set in the timer
379 */
380 us_TmpValue =
381 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
382
383 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
384 if ((us_TmpValue & 0x00B0) == 0x00B0
385 || !strcmp(this_board->pc_DriverName, "apci3001")) {
386 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
387 } else {
388 us_ConvertTiming =
389 ((us_ConvertTiming * 12926) / 10000) - 1;
390 }
391
392 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
393
394 switch (us_TmpValue) {
395
396 case APCI3120_EOC_MODE:
397
398 /*
399 * Testing the interrupt flag and set the EOC bit Clears the FIFO
400 */
401 inw(devpriv->iobase + APCI3120_RESET_FIFO);
402
403 /* Initialize the sequence array */
404 if (!apci3120_setup_chan_list(dev, s, 1,
405 &insn->chanspec, 0))
406 return -EINVAL;
407
408 /* Initialize Timer 0 mode 4 */
409 devpriv->b_TimerSelectMode =
410 (devpriv->
411 b_TimerSelectMode & 0xFC) |
412 APCI3120_TIMER_0_MODE_4;
413 outb(devpriv->b_TimerSelectMode,
414 devpriv->iobase + APCI3120_TIMER_CRT1);
415
416 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
417 devpriv->b_ModeSelectRegister =
418 devpriv->
419 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
420
421 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
422
423 /* Disables the EOS,DMA and enables the EOC interrupt */
424 devpriv->b_ModeSelectRegister =
425 (devpriv->
426 b_ModeSelectRegister &
427 APCI3120_DISABLE_EOS_INT) |
428 APCI3120_ENABLE_EOC_INT;
429 inw(devpriv->iobase);
430
431 } else {
432 devpriv->b_ModeSelectRegister =
433 devpriv->
434 b_ModeSelectRegister &
435 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
436 }
437
438 outb(devpriv->b_ModeSelectRegister,
439 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
440
441 /* Sets gate 0 */
442 devpriv->us_OutputRegister =
443 (devpriv->
444 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
445 APCI3120_ENABLE_TIMER0;
446 outw(devpriv->us_OutputRegister,
447 devpriv->iobase + APCI3120_WR_ADDRESS);
448
449 /* Select Timer 0 */
450 b_Tmp = ((devpriv->
451 b_DigitalOutputRegister) & 0xF0) |
452 APCI3120_SELECT_TIMER_0_WORD;
453 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
454
455 /* Set the conversion time */
456 outw(us_ConvertTiming,
457 devpriv->iobase + APCI3120_TIMER_VALUE);
458
459 us_TmpValue =
460 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
461
462 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
463
464 do {
465 /* Waiting for the end of conversion */
466 us_TmpValue =
467 inw(devpriv->iobase +
468 APCI3120_RD_STATUS);
469 } while ((us_TmpValue & APCI3120_EOC) ==
470 APCI3120_EOC);
471
472 /* Read the result in FIFO and put it in insn data pointer */
473 us_TmpValue = inw(devpriv->iobase + 0);
474 *data = us_TmpValue;
475
476 inw(devpriv->iobase + APCI3120_RESET_FIFO);
477 }
478
479 break;
480
481 case APCI3120_EOS_MODE:
482
483 inw(devpriv->iobase);
484 /* Clears the FIFO */
485 inw(devpriv->iobase + APCI3120_RESET_FIFO);
486 /* clear PA PR and disable timer 0 */
487
488 devpriv->us_OutputRegister =
489 (devpriv->
490 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
491 APCI3120_DISABLE_TIMER0;
492
493 outw(devpriv->us_OutputRegister,
494 devpriv->iobase + APCI3120_WR_ADDRESS);
495
496 if (!apci3120_setup_chan_list(dev, s,
497 devpriv->ui_AiNbrofChannels,
498 devpriv->ui_AiChannelList, 0))
499 return -EINVAL;
500
501 /* Initialize Timer 0 mode 2 */
502 devpriv->b_TimerSelectMode =
503 (devpriv->
504 b_TimerSelectMode & 0xFC) |
505 APCI3120_TIMER_0_MODE_2;
506 outb(devpriv->b_TimerSelectMode,
507 devpriv->iobase + APCI3120_TIMER_CRT1);
508
509 /* Select Timer 0 */
510 b_Tmp = ((devpriv->
511 b_DigitalOutputRegister) & 0xF0) |
512 APCI3120_SELECT_TIMER_0_WORD;
513 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
514
515 /* Set the conversion time */
516 outw(us_ConvertTiming,
517 devpriv->iobase + APCI3120_TIMER_VALUE);
518
519 /* Set the scan bit */
520 devpriv->b_ModeSelectRegister =
521 devpriv->
522 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
523 outb(devpriv->b_ModeSelectRegister,
524 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
525
526 /* If Interrupt function is loaded */
527 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
528 /* Disables the EOC,DMA and enables the EOS interrupt */
529 devpriv->b_ModeSelectRegister =
530 (devpriv->
531 b_ModeSelectRegister &
532 APCI3120_DISABLE_EOC_INT) |
533 APCI3120_ENABLE_EOS_INT;
534 inw(devpriv->iobase);
535
536 } else
537 devpriv->b_ModeSelectRegister =
538 devpriv->
539 b_ModeSelectRegister &
540 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
541
542 outb(devpriv->b_ModeSelectRegister,
543 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
544
545 inw(devpriv->iobase + APCI3120_RD_STATUS);
546
547 /* Sets gate 0 */
548 devpriv->us_OutputRegister =
549 devpriv->
550 us_OutputRegister | APCI3120_ENABLE_TIMER0;
551 outw(devpriv->us_OutputRegister,
552 devpriv->iobase + APCI3120_WR_ADDRESS);
553
554 /* Start conversion */
555 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
556
557 /* Waiting of end of conversion if interrupt is not installed */
558 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
559 /* Waiting the end of conversion */
560 do {
561 us_TmpValue =
562 inw(devpriv->iobase +
563 APCI3120_RD_STATUS);
564 } while ((us_TmpValue & APCI3120_EOS) !=
565 APCI3120_EOS);
566
567 for (i = 0; i < devpriv->ui_AiNbrofChannels;
568 i++) {
569 /* Read the result in FIFO and write them in shared memory */
570 us_TmpValue = inw(devpriv->iobase);
571 data[i] = (unsigned int) us_TmpValue;
572 }
573
574 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults */
575 }
576 break;
577
578 default:
579 dev_err(dev->class_dev, "inputs wrong\n");
580
581 }
582 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable */
583 }
584
585 return insn->n;
586
587 }
588
apci3120_reset(struct comedi_device * dev)589 static int apci3120_reset(struct comedi_device *dev)
590 {
591 struct addi_private *devpriv = dev->private;
592 unsigned int i;
593 unsigned short us_TmpValue;
594
595 devpriv->ai_running = 0;
596 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
597 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
598 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
599
600 /* variables used in timer subdevice */
601 devpriv->b_Timer2Mode = 0;
602 devpriv->b_Timer2Interrupt = 0;
603 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
604
605 /* Disable all interrupts, watchdog for the anolog output */
606 devpriv->b_ModeSelectRegister = 0;
607 outb(devpriv->b_ModeSelectRegister,
608 dev->iobase + APCI3120_WRITE_MODE_SELECT);
609
610 /* Disables all counters, ext trigger and clears PA, PR */
611 devpriv->us_OutputRegister = 0;
612 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
613
614 /*
615 * Code to set the all anolog o/p channel to 0v 8191 is decimal
616 * value for zero(0 v)volt in bipolar mode(default)
617 */
618 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
619 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
620 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
621 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
622
623 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
624 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
625 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
626 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
627
628 udelay(10);
629
630 inw(dev->iobase + 0); /* make a dummy read */
631 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
632 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
633
634 /* code to reset the RAM sequence */
635 for (i = 0; i < 16; i++) {
636 us_TmpValue = i << 8; /* select the location */
637 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
638 }
639 return 0;
640 }
641
apci3120_exttrig_enable(struct comedi_device * dev)642 static int apci3120_exttrig_enable(struct comedi_device *dev)
643 {
644 struct addi_private *devpriv = dev->private;
645
646 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
647 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
648 return 0;
649 }
650
apci3120_exttrig_disable(struct comedi_device * dev)651 static int apci3120_exttrig_disable(struct comedi_device *dev)
652 {
653 struct addi_private *devpriv = dev->private;
654
655 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
656 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
657 return 0;
658 }
659
apci3120_cancel(struct comedi_device * dev,struct comedi_subdevice * s)660 static int apci3120_cancel(struct comedi_device *dev,
661 struct comedi_subdevice *s)
662 {
663 struct addi_private *devpriv = dev->private;
664
665 /* Disable A2P Fifo write and AMWEN signal */
666 outw(0, devpriv->i_IobaseAddon + 4);
667
668 /* Disable Bus Master ADD ON */
669 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
670 outw(0, devpriv->i_IobaseAddon + 2);
671 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
672 outw(0, devpriv->i_IobaseAddon + 2);
673
674 /* Disable BUS Master PCI */
675 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
676
677 /* Disable ext trigger */
678 apci3120_exttrig_disable(dev);
679
680 devpriv->us_OutputRegister = 0;
681 /* stop counters */
682 outw(devpriv->
683 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
684 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
685
686 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
687
688 /* DISABLE_ALL_INTERRUPT */
689 outb(APCI3120_DISABLE_ALL_INTERRUPT,
690 dev->iobase + APCI3120_WRITE_MODE_SELECT);
691 /* Flush FIFO */
692 inb(dev->iobase + APCI3120_RESET_FIFO);
693 inw(dev->iobase + APCI3120_RD_STATUS);
694 devpriv->ui_AiActualScan = 0;
695 s->async->cur_chan = 0;
696 devpriv->ui_DmaActualBuffer = 0;
697
698 devpriv->ai_running = 0;
699 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
700 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
701 apci3120_reset(dev);
702 return 0;
703 }
704
apci3120_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)705 static int apci3120_ai_cmdtest(struct comedi_device *dev,
706 struct comedi_subdevice *s,
707 struct comedi_cmd *cmd)
708 {
709 int err = 0;
710
711 /* Step 1 : check if triggers are trivially valid */
712
713 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
714 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
715 TRIG_TIMER | TRIG_FOLLOW);
716 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
717 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
718 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
719
720 if (err)
721 return 1;
722
723 /* Step 2a : make sure trigger sources are unique */
724
725 err |= cfc_check_trigger_is_unique(cmd->start_src);
726 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
727 err |= cfc_check_trigger_is_unique(cmd->stop_src);
728
729 /* Step 2b : and mutually compatible */
730
731 if (err)
732 return 2;
733
734 /* Step 3: check if arguments are trivially valid */
735
736 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
737
738 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
739 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
740
741 if (cmd->scan_begin_src == TRIG_TIMER) {
742 if (cmd->convert_arg)
743 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
744 10000);
745 } else {
746 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
747 }
748
749 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
750 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
751
752 if (cmd->stop_src == TRIG_COUNT)
753 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
754 else /* TRIG_NONE */
755 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
756
757 if (err)
758 return 3;
759
760 /* step 4: fix up any arguments */
761
762 if (cmd->scan_begin_src == TRIG_TIMER &&
763 cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
764 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
765 err |= -EINVAL;
766 }
767
768 if (err)
769 return 4;
770
771 return 0;
772 }
773
774 /*
775 * This is used for analog input cyclic acquisition.
776 * Performs the command operations.
777 * If DMA is configured does DMA initialization otherwise does the
778 * acquisition with EOS interrupt.
779 */
apci3120_cyclic_ai(int mode,struct comedi_device * dev,struct comedi_subdevice * s)780 static int apci3120_cyclic_ai(int mode,
781 struct comedi_device *dev,
782 struct comedi_subdevice *s)
783 {
784 const struct addi_board *this_board = dev->board_ptr;
785 struct addi_private *devpriv = dev->private;
786 struct comedi_cmd *cmd = &s->async->cmd;
787 unsigned char b_Tmp;
788 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
789 0, dmalen1 = 0, ui_TimerValue2 =
790 0, ui_TimerValue0, ui_ConvertTiming;
791 unsigned short us_TmpValue;
792
793 /* Resets the FIFO */
794 inb(dev->iobase + APCI3120_RESET_FIFO);
795
796 devpriv->ai_running = 1;
797
798 /* clear software registers */
799 devpriv->b_TimerSelectMode = 0;
800 devpriv->us_OutputRegister = 0;
801 devpriv->b_ModeSelectRegister = 0;
802
803 /* Clear Timer Write TC int */
804 outl(APCI3120_CLEAR_WRITE_TC_INT,
805 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
806
807 /* Disables All Timer */
808 /* Sets PR and PA to 0 */
809 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
810 APCI3120_DISABLE_TIMER0 &
811 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
812
813 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
814
815 /* Resets the FIFO */
816 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
817 inb(devpriv->iobase + APCI3120_RESET_FIFO);
818 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
819
820 devpriv->ui_AiActualScan = 0;
821 s->async->cur_chan = 0;
822 devpriv->ui_DmaActualBuffer = 0;
823
824 /* value for timer2 minus -2 has to be done */
825 ui_TimerValue2 = cmd->stop_arg - 2;
826 ui_ConvertTiming = cmd->convert_arg;
827
828 if (mode == 2)
829 ui_DelayTiming = cmd->scan_begin_arg;
830
831 /* Initializes the sequence array */
832 if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
833 cmd->chanlist, 0))
834 return -EINVAL;
835
836 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
837
838 /* EL241003 Begin: add this section to replace floats calculation by integer calculations */
839 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
840 if ((us_TmpValue & 0x00B0) == 0x00B0
841 || !strcmp(this_board->pc_DriverName, "apci3001")) {
842 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
843 ui_TimerValue0 = ui_TimerValue0 / 1000;
844
845 if (mode == 2) {
846 ui_DelayTiming = ui_DelayTiming / 1000;
847 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
848 ui_TimerValue1 = ui_TimerValue1 / 100;
849 }
850 } else {
851 ui_ConvertTiming = ui_ConvertTiming / 1000;
852 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
853 ui_TimerValue0 = ui_TimerValue0 / 10000;
854
855 if (mode == 2) {
856 ui_DelayTiming = ui_DelayTiming / 1000;
857 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
858 ui_TimerValue1 = ui_TimerValue1 / 1000000;
859 }
860 }
861 /* EL241003 End */
862
863 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
864 apci3120_exttrig_enable(dev); /* activate EXT trigger */
865 switch (mode) {
866 case 1:
867 /* init timer0 in mode 2 */
868 devpriv->b_TimerSelectMode =
869 (devpriv->
870 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
871 outb(devpriv->b_TimerSelectMode,
872 dev->iobase + APCI3120_TIMER_CRT1);
873
874 /* Select Timer 0 */
875 b_Tmp = ((devpriv->
876 b_DigitalOutputRegister) & 0xF0) |
877 APCI3120_SELECT_TIMER_0_WORD;
878 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
879 /* Set the conversion time */
880 outw(((unsigned short) ui_TimerValue0),
881 dev->iobase + APCI3120_TIMER_VALUE);
882 break;
883
884 case 2:
885 /* init timer1 in mode 2 */
886 devpriv->b_TimerSelectMode =
887 (devpriv->
888 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
889 outb(devpriv->b_TimerSelectMode,
890 dev->iobase + APCI3120_TIMER_CRT1);
891
892 /* Select Timer 1 */
893 b_Tmp = ((devpriv->
894 b_DigitalOutputRegister) & 0xF0) |
895 APCI3120_SELECT_TIMER_1_WORD;
896 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
897 /* Set the conversion time */
898 outw(((unsigned short) ui_TimerValue1),
899 dev->iobase + APCI3120_TIMER_VALUE);
900
901 /* init timer0 in mode 2 */
902 devpriv->b_TimerSelectMode =
903 (devpriv->
904 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
905 outb(devpriv->b_TimerSelectMode,
906 dev->iobase + APCI3120_TIMER_CRT1);
907
908 /* Select Timer 0 */
909 b_Tmp = ((devpriv->
910 b_DigitalOutputRegister) & 0xF0) |
911 APCI3120_SELECT_TIMER_0_WORD;
912 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
913
914 /* Set the conversion time */
915 outw(((unsigned short) ui_TimerValue0),
916 dev->iobase + APCI3120_TIMER_VALUE);
917 break;
918
919 }
920 /* common for all modes */
921 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
922 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
923 APCI3120_DISABLE_SCAN;
924 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
925
926 outb(devpriv->b_ModeSelectRegister,
927 dev->iobase + APCI3120_WRITE_MODE_SELECT);
928
929 /* If DMA is disabled */
930 if (devpriv->us_UseDma == APCI3120_DISABLE) {
931 /* disable EOC and enable EOS */
932 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
933 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
934
935 devpriv->b_ModeSelectRegister =
936 (devpriv->
937 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
938 APCI3120_ENABLE_EOS_INT;
939 outb(devpriv->b_ModeSelectRegister,
940 dev->iobase + APCI3120_WRITE_MODE_SELECT);
941
942 if (cmd->stop_src == TRIG_COUNT) {
943 /*
944 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
945 * disable it (Set Bit D14 to 0)
946 */
947 devpriv->us_OutputRegister =
948 devpriv->
949 us_OutputRegister & APCI3120_DISABLE_TIMER2;
950 outw(devpriv->us_OutputRegister,
951 dev->iobase + APCI3120_WR_ADDRESS);
952
953 /* DISABLE TIMER intERRUPT */
954 devpriv->b_ModeSelectRegister =
955 devpriv->
956 b_ModeSelectRegister &
957 APCI3120_DISABLE_TIMER_INT & 0xEF;
958 outb(devpriv->b_ModeSelectRegister,
959 dev->iobase + APCI3120_WRITE_MODE_SELECT);
960
961 /* (1) Init timer 2 in mode 0 and write timer value */
962 devpriv->b_TimerSelectMode =
963 (devpriv->
964 b_TimerSelectMode & 0x0F) |
965 APCI3120_TIMER_2_MODE_0;
966 outb(devpriv->b_TimerSelectMode,
967 dev->iobase + APCI3120_TIMER_CRT1);
968
969 /* Writing LOW unsigned short */
970 b_Tmp = ((devpriv->
971 b_DigitalOutputRegister) & 0xF0) |
972 APCI3120_SELECT_TIMER_2_LOW_WORD;
973 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
974 outw(ui_TimerValue2 & 0xffff,
975 dev->iobase + APCI3120_TIMER_VALUE);
976
977 /* Writing HIGH unsigned short */
978 b_Tmp = ((devpriv->
979 b_DigitalOutputRegister) & 0xF0) |
980 APCI3120_SELECT_TIMER_2_HIGH_WORD;
981 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
982 outw((ui_TimerValue2 >> 16) & 0xffff,
983 dev->iobase + APCI3120_TIMER_VALUE);
984
985 /* (2) Reset FC_TIMER BIT Clearing timer status register */
986 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
987 /* enable timer counter and disable watch dog */
988 devpriv->b_ModeSelectRegister =
989 (devpriv->
990 b_ModeSelectRegister |
991 APCI3120_ENABLE_TIMER_COUNTER) &
992 APCI3120_DISABLE_WATCHDOG;
993 /* select EOS clock input for timer 2 */
994 devpriv->b_ModeSelectRegister =
995 devpriv->
996 b_ModeSelectRegister |
997 APCI3120_TIMER2_SELECT_EOS;
998 /* Enable timer2 interrupt */
999 devpriv->b_ModeSelectRegister =
1000 devpriv->
1001 b_ModeSelectRegister |
1002 APCI3120_ENABLE_TIMER_INT;
1003 outb(devpriv->b_ModeSelectRegister,
1004 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1005 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1006 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1007 }
1008 } else {
1009 /* If DMA Enabled */
1010 unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short);
1011
1012 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1013
1014 /* Disables the EOC, EOS interrupt */
1015 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1016 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1017
1018 outb(devpriv->b_ModeSelectRegister,
1019 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1020
1021 dmalen0 = devpriv->ui_DmaBufferSize[0];
1022 dmalen1 = devpriv->ui_DmaBufferSize[1];
1023
1024 if (cmd->stop_src == TRIG_COUNT) {
1025 /*
1026 * Must we fill full first buffer? And must we fill
1027 * full second buffer when first is once filled?
1028 */
1029 if (dmalen0 > (cmd->stop_arg * scan_bytes)) {
1030 dmalen0 = cmd->stop_arg * scan_bytes;
1031 } else if (dmalen1 > (cmd->stop_arg * scan_bytes -
1032 dmalen0))
1033 dmalen1 = cmd->stop_arg * scan_bytes -
1034 dmalen0;
1035 }
1036
1037 if (cmd->flags & CMDF_WAKE_EOS) {
1038 /* don't we want wake up every scan? */
1039 if (dmalen0 > scan_bytes) {
1040 dmalen0 = scan_bytes;
1041 if (cmd->scan_end_arg & 1)
1042 dmalen0 += 2;
1043 }
1044 if (dmalen1 > scan_bytes) {
1045 dmalen1 = scan_bytes;
1046 if (cmd->scan_end_arg & 1)
1047 dmalen1 -= 2;
1048 if (dmalen1 < 4)
1049 dmalen1 = 4;
1050 }
1051 } else { /* isn't output buff smaller that our DMA buff? */
1052 if (dmalen0 > s->async->prealloc_bufsz)
1053 dmalen0 = s->async->prealloc_bufsz;
1054 if (dmalen1 > s->async->prealloc_bufsz)
1055 dmalen1 = s->async->prealloc_bufsz;
1056 }
1057 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1058 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1059
1060 /* Initialize DMA */
1061
1062 /*
1063 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1064 * register 1
1065 */
1066 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1067 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1068
1069 /* changed since 16 bit interface for add on */
1070 /* ENABLE BUS MASTER */
1071 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1072 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1073 devpriv->i_IobaseAddon + 2);
1074
1075 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1076 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1077 devpriv->i_IobaseAddon + 2);
1078
1079 /*
1080 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1081 * driver
1082 */
1083 outw(0x1000, devpriv->i_IobaseAddon + 2);
1084 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1085
1086 /* 2 No change */
1087 /* A2P FIFO MANAGEMENT */
1088 /* A2P fifo reset & transfer control enable */
1089 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1090 APCI3120_AMCC_OP_MCSR);
1091
1092 /*
1093 * 3
1094 * beginning address of dma buf The 32 bit address of dma buffer
1095 * is converted into two 16 bit addresses Can done by using _attach
1096 * and put into into an array array used may be for differnet pages
1097 */
1098
1099 /* DMA Start Address Low */
1100 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1101 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1102 devpriv->i_IobaseAddon + 2);
1103
1104 /* DMA Start Address High */
1105 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1106 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1107 devpriv->i_IobaseAddon + 2);
1108
1109 /*
1110 * 4
1111 * amount of bytes to be transferred set transfer count used ADDON
1112 * MWTC register commented testing
1113 */
1114
1115 /* Nbr of acquisition LOW */
1116 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1117 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1118 devpriv->i_IobaseAddon + 2);
1119
1120 /* Nbr of acquisition HIGH */
1121 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1122 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1123 devpriv->i_IobaseAddon + 2);
1124
1125 /*
1126 * 5
1127 * To configure A2P FIFO testing outl(
1128 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1129 */
1130
1131 /* A2P FIFO RESET */
1132 /*
1133 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1134 * driver
1135 */
1136 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1137 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1138
1139 /*
1140 * 6
1141 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1142 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1143 */
1144
1145 /*
1146 * 7
1147 * initialise end of dma interrupt AINT_WRITE_COMPL =
1148 * ENABLE_WRITE_TC_INT(ADDI)
1149 */
1150 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1151 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1152 APCI3120_ENABLE_WRITE_TC_INT),
1153 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1154
1155 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1156 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1157 outw(3, devpriv->i_IobaseAddon + 4);
1158 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1159
1160 /* A2P FIFO RESET */
1161 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1162 outl(0x04000000UL,
1163 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1164 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1165 }
1166
1167 if (devpriv->us_UseDma == APCI3120_DISABLE &&
1168 cmd->stop_src == TRIG_COUNT) {
1169 /* set gate 2 to start conversion */
1170 devpriv->us_OutputRegister =
1171 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1172 outw(devpriv->us_OutputRegister,
1173 dev->iobase + APCI3120_WR_ADDRESS);
1174 }
1175
1176 switch (mode) {
1177 case 1:
1178 /* set gate 0 to start conversion */
1179 devpriv->us_OutputRegister =
1180 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1181 outw(devpriv->us_OutputRegister,
1182 dev->iobase + APCI3120_WR_ADDRESS);
1183 break;
1184 case 2:
1185 /* set gate 0 and gate 1 */
1186 devpriv->us_OutputRegister =
1187 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1188 devpriv->us_OutputRegister =
1189 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1190 outw(devpriv->us_OutputRegister,
1191 dev->iobase + APCI3120_WR_ADDRESS);
1192 break;
1193
1194 }
1195
1196 return 0;
1197
1198 }
1199
1200 /*
1201 * Does asynchronous acquisition.
1202 * Determines the mode 1 or 2.
1203 */
apci3120_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)1204 static int apci3120_ai_cmd(struct comedi_device *dev,
1205 struct comedi_subdevice *s)
1206 {
1207 struct addi_private *devpriv = dev->private;
1208 struct comedi_cmd *cmd = &s->async->cmd;
1209
1210 /* loading private structure with cmd structure inputs */
1211 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
1212
1213 if (cmd->start_src == TRIG_EXT)
1214 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
1215 else
1216 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1217
1218 if (cmd->scan_begin_src == TRIG_FOLLOW)
1219 return apci3120_cyclic_ai(1, dev, s);
1220 /* TRIG_TIMER */
1221 return apci3120_cyclic_ai(2, dev, s);
1222 }
1223
1224 /*
1225 * This function copies the data from DMA buffer to the Comedi buffer.
1226 */
v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev,struct comedi_subdevice * s,unsigned short * dma_buffer,unsigned int num_samples)1227 static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1228 struct comedi_subdevice *s,
1229 unsigned short *dma_buffer,
1230 unsigned int num_samples)
1231 {
1232 struct addi_private *devpriv = dev->private;
1233 struct comedi_cmd *cmd = &s->async->cmd;
1234
1235 devpriv->ui_AiActualScan +=
1236 (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
1237 s->async->cur_chan += num_samples;
1238 s->async->cur_chan %= cmd->scan_end_arg;
1239
1240 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1241 }
1242
1243 /*
1244 * This is a handler for the DMA interrupt.
1245 * This function copies the data to Comedi Buffer.
1246 * For continuous DMA it reinitializes the DMA operation.
1247 * For single mode DMA it stop the acquisition.
1248 */
apci3120_interrupt_dma(int irq,void * d)1249 static void apci3120_interrupt_dma(int irq, void *d)
1250 {
1251 struct comedi_device *dev = d;
1252 struct addi_private *devpriv = dev->private;
1253 struct comedi_subdevice *s = dev->read_subdev;
1254 struct comedi_cmd *cmd = &s->async->cmd;
1255 unsigned int next_dma_buf, samplesinbuf;
1256 unsigned long low_word, high_word, var;
1257 unsigned int ui_Tmp;
1258
1259 samplesinbuf =
1260 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1261 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1262
1263 if (samplesinbuf <
1264 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1265 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
1266 }
1267 if (samplesinbuf & 1) {
1268 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
1269 apci3120_cancel(dev, s);
1270 return;
1271 }
1272 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1273 if (devpriv->b_DmaDoubleBuffer) {
1274 /* switch DMA buffers if is used double buffering */
1275 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1276
1277 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1278 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1279
1280 /* changed since 16 bit interface for add on */
1281 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1282 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1283 devpriv->i_IobaseAddon + 2);
1284 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1285 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
1286
1287 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1288 low_word = var & 0xffff;
1289 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1290 high_word = var / 65536;
1291
1292 /* DMA Start Address Low */
1293 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1294 outw(low_word, devpriv->i_IobaseAddon + 2);
1295
1296 /* DMA Start Address High */
1297 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1298 outw(high_word, devpriv->i_IobaseAddon + 2);
1299
1300 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1301 low_word = var & 0xffff;
1302 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1303 high_word = var / 65536;
1304
1305 /* Nbr of acquisition LOW */
1306 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1307 outw(low_word, devpriv->i_IobaseAddon + 2);
1308
1309 /* Nbr of acquisition HIGH */
1310 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1311 outw(high_word, devpriv->i_IobaseAddon + 2);
1312
1313 /*
1314 * To configure A2P FIFO
1315 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1316 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1317 */
1318 outw(3, devpriv->i_IobaseAddon + 4);
1319 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1320 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1321 APCI3120_ENABLE_WRITE_TC_INT),
1322 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1323
1324 }
1325 if (samplesinbuf) {
1326 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1327 devpriv->ul_DmaBufferVirtual[devpriv->
1328 ui_DmaActualBuffer], samplesinbuf);
1329
1330 if (!(cmd->flags & CMDF_WAKE_EOS)) {
1331 s->async->events |= COMEDI_CB_EOS;
1332 comedi_event(dev, s);
1333 }
1334 }
1335 if (cmd->stop_src == TRIG_COUNT)
1336 if (devpriv->ui_AiActualScan >= cmd->stop_arg) {
1337 /* all data sampled */
1338 apci3120_cancel(dev, s);
1339 s->async->events |= COMEDI_CB_EOA;
1340 comedi_event(dev, s);
1341 return;
1342 }
1343
1344 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1345 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1346 } else {
1347 /*
1348 * restart DMA if is not used double buffering
1349 * ADDED REINITIALISE THE DMA
1350 */
1351 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1352 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1353
1354 /* changed since 16 bit interface for add on */
1355 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1356 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1357 devpriv->i_IobaseAddon + 2);
1358 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1359 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);
1360 /*
1361 * A2P FIFO MANAGEMENT
1362 * A2P fifo reset & transfer control enable
1363 */
1364 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1365 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1366
1367 var = devpriv->ul_DmaBufferHw[0];
1368 low_word = var & 0xffff;
1369 var = devpriv->ul_DmaBufferHw[0];
1370 high_word = var / 65536;
1371 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1372 outw(low_word, devpriv->i_IobaseAddon + 2);
1373 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1374 outw(high_word, devpriv->i_IobaseAddon + 2);
1375
1376 var = devpriv->ui_DmaBufferUsesize[0];
1377 low_word = var & 0xffff; /* changed */
1378 var = devpriv->ui_DmaBufferUsesize[0];
1379 high_word = var / 65536;
1380 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1381 outw(low_word, devpriv->i_IobaseAddon + 2);
1382 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1383 outw(high_word, devpriv->i_IobaseAddon + 2);
1384
1385 /*
1386 * To configure A2P FIFO
1387 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1388 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1389 */
1390 outw(3, devpriv->i_IobaseAddon + 4);
1391 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1392 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1393 APCI3120_ENABLE_WRITE_TC_INT),
1394 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1395 }
1396 }
1397
1398 /*
1399 * This function handles EOS interrupt.
1400 * This function copies the acquired data(from FIFO) to Comedi buffer.
1401 */
apci3120_interrupt_handle_eos(struct comedi_device * dev)1402 static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
1403 {
1404 struct addi_private *devpriv = dev->private;
1405 struct comedi_subdevice *s = dev->read_subdev;
1406 int n_chan, i;
1407 int err = 1;
1408
1409 n_chan = devpriv->ui_AiNbrofChannels;
1410
1411 for (i = 0; i < n_chan; i++)
1412 err &= comedi_buf_put(s, inw(dev->iobase + 0));
1413
1414 s->async->events |= COMEDI_CB_EOS;
1415
1416 if (err == 0)
1417 s->async->events |= COMEDI_CB_OVERFLOW;
1418
1419 comedi_event(dev, s);
1420
1421 return 0;
1422 }
1423
apci3120_interrupt(int irq,void * d)1424 static void apci3120_interrupt(int irq, void *d)
1425 {
1426 struct comedi_device *dev = d;
1427 struct addi_private *devpriv = dev->private;
1428 struct comedi_subdevice *s = dev->read_subdev;
1429 unsigned short int_daq;
1430 unsigned int int_amcc, ui_Check, i;
1431 unsigned short us_TmpValue;
1432 unsigned char b_DummyRead;
1433
1434 ui_Check = 1;
1435
1436 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1437 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
1438
1439 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1440 dev_err(dev->class_dev, "IRQ from unknown source\n");
1441 return;
1442 }
1443
1444 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1445
1446 int_daq = (int_daq >> 12) & 0xF;
1447
1448 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1449 /* Disable ext trigger */
1450 apci3120_exttrig_disable(dev);
1451 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1452 }
1453 /* clear the timer 2 interrupt */
1454 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1455
1456 if (int_amcc & MASTER_ABORT_INT)
1457 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
1458 if (int_amcc & TARGET_ABORT_INT)
1459 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
1460
1461 /* Ckeck if EOC interrupt */
1462 if (((int_daq & 0x8) == 0)
1463 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1464 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1465
1466 /* Read the AI Value */
1467 devpriv->ui_AiReadData[0] =
1468 (unsigned int) inw(devpriv->iobase + 0);
1469 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1470 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1471 } else {
1472 /* Disable EOC Interrupt */
1473 devpriv->b_ModeSelectRegister =
1474 devpriv->
1475 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1476 outb(devpriv->b_ModeSelectRegister,
1477 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1478
1479 }
1480 }
1481
1482 /* Check If EOS interrupt */
1483 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1484
1485 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
1486
1487 if (devpriv->ai_running) {
1488 ui_Check = 0;
1489 apci3120_interrupt_handle_eos(dev);
1490 devpriv->ui_AiActualScan++;
1491 devpriv->b_ModeSelectRegister =
1492 devpriv->
1493 b_ModeSelectRegister |
1494 APCI3120_ENABLE_EOS_INT;
1495 outb(devpriv->b_ModeSelectRegister,
1496 dev->iobase +
1497 APCI3120_WRITE_MODE_SELECT);
1498 } else {
1499 ui_Check = 0;
1500 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1501 i++) {
1502 us_TmpValue = inw(devpriv->iobase + 0);
1503 devpriv->ui_AiReadData[i] =
1504 (unsigned int) us_TmpValue;
1505 }
1506 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1507 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1508
1509 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1510
1511 }
1512
1513 } else {
1514 devpriv->b_ModeSelectRegister =
1515 devpriv->
1516 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1517 outb(devpriv->b_ModeSelectRegister,
1518 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1519 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1520 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1521 }
1522
1523 }
1524 /* Timer2 interrupt */
1525 if (int_daq & 0x1) {
1526
1527 switch (devpriv->b_Timer2Mode) {
1528 case APCI3120_COUNTER:
1529 devpriv->b_ModeSelectRegister =
1530 devpriv->
1531 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1532 outb(devpriv->b_ModeSelectRegister,
1533 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1534
1535 /* stop timer 2 */
1536 devpriv->us_OutputRegister =
1537 devpriv->
1538 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1539 outw(devpriv->us_OutputRegister,
1540 dev->iobase + APCI3120_WR_ADDRESS);
1541
1542 /* stop timer 0 and timer 1 */
1543 apci3120_cancel(dev, s);
1544
1545 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1546 s->async->events |= COMEDI_CB_EOA;
1547 comedi_event(dev, s);
1548
1549 break;
1550
1551 case APCI3120_TIMER:
1552
1553 /* Send a signal to from kernel to user space */
1554 send_sig(SIGIO, devpriv->tsk_Current, 0);
1555 break;
1556
1557 case APCI3120_WATCHDOG:
1558
1559 /* Send a signal to from kernel to user space */
1560 send_sig(SIGIO, devpriv->tsk_Current, 0);
1561 break;
1562
1563 default:
1564
1565 /* disable Timer Interrupt */
1566 devpriv->b_ModeSelectRegister =
1567 devpriv->
1568 b_ModeSelectRegister &
1569 APCI3120_DISABLE_TIMER_INT;
1570
1571 outb(devpriv->b_ModeSelectRegister,
1572 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1573
1574 }
1575
1576 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1577
1578 }
1579
1580 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1581 if (devpriv->ai_running) {
1582
1583 /* Clear Timer Write TC int */
1584 outl(APCI3120_CLEAR_WRITE_TC_INT,
1585 devpriv->i_IobaseAmcc +
1586 APCI3120_AMCC_OP_REG_INTCSR);
1587
1588 /* Clears the timer status register */
1589 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1590 /* do some data transfer */
1591 apci3120_interrupt_dma(irq, d);
1592 } else {
1593 /* Stops the Timer */
1594 outw(devpriv->
1595 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1596 APCI3120_DISABLE_TIMER1,
1597 dev->iobase + APCI3120_WR_ADDRESS);
1598 }
1599
1600 }
1601 }
1602
1603 /*
1604 * Configure Timer 2
1605 *
1606 * data[0] = TIMER configure as timer
1607 * = WATCHDOG configure as watchdog
1608 * data[1] = Timer constant
1609 * data[2] = Timer2 interrupt (1)enable or(0) disable
1610 */
apci3120_config_insn_timer(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1611 static int apci3120_config_insn_timer(struct comedi_device *dev,
1612 struct comedi_subdevice *s,
1613 struct comedi_insn *insn,
1614 unsigned int *data)
1615 {
1616 const struct addi_board *this_board = dev->board_ptr;
1617 struct addi_private *devpriv = dev->private;
1618 unsigned int ui_Timervalue2;
1619 unsigned short us_TmpValue;
1620 unsigned char b_Tmp;
1621
1622 if (!data[1])
1623 dev_err(dev->class_dev, "No timer constant!\n");
1624
1625 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1626
1627 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1628
1629 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1630
1631 /*
1632 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1633 * is an APCI3001 and calculate the time value to set in the timer
1634 */
1635 if ((us_TmpValue & 0x00B0) == 0x00B0
1636 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1637 /* Calculate the time value to set in the timer */
1638 ui_Timervalue2 = ui_Timervalue2 / 50;
1639 } else {
1640 /* Calculate the time value to set in the timer */
1641 ui_Timervalue2 = ui_Timervalue2 / 70;
1642 }
1643
1644 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1645 devpriv->us_OutputRegister =
1646 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1647 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1648
1649 /* Disable TIMER Interrupt */
1650 devpriv->b_ModeSelectRegister =
1651 devpriv->
1652 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1653
1654 /* Disable Eoc and Eos Interrupts */
1655 devpriv->b_ModeSelectRegister =
1656 devpriv->
1657 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1658 APCI3120_DISABLE_EOS_INT;
1659 outb(devpriv->b_ModeSelectRegister,
1660 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1661 if (data[0] == APCI3120_TIMER) { /* initialize timer */
1662 /* Set the Timer 2 in mode 2(Timer) */
1663 devpriv->b_TimerSelectMode =
1664 (devpriv->
1665 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1666 outb(devpriv->b_TimerSelectMode,
1667 devpriv->iobase + APCI3120_TIMER_CRT1);
1668
1669 /*
1670 * Configure the timer 2 for writing the LOW unsigned short of timer
1671 * is Delay value You must make a b_tmp variable with
1672 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1673 * you can set the digital output and configure the timer 2,and if
1674 * you don't make this, digital output are erase (Set to 0)
1675 */
1676
1677 /* Writing LOW unsigned short */
1678 b_Tmp = ((devpriv->
1679 b_DigitalOutputRegister) & 0xF0) |
1680 APCI3120_SELECT_TIMER_2_LOW_WORD;
1681 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1682 outw(ui_Timervalue2 & 0xffff,
1683 devpriv->iobase + APCI3120_TIMER_VALUE);
1684
1685 /* Writing HIGH unsigned short */
1686 b_Tmp = ((devpriv->
1687 b_DigitalOutputRegister) & 0xF0) |
1688 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1689 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1690 outw((ui_Timervalue2 >> 16) & 0xffff,
1691 devpriv->iobase + APCI3120_TIMER_VALUE);
1692 /* timer2 in Timer mode enabled */
1693 devpriv->b_Timer2Mode = APCI3120_TIMER;
1694
1695 } else { /* Initialize Watch dog */
1696
1697 /* Set the Timer 2 in mode 5(Watchdog) */
1698 devpriv->b_TimerSelectMode =
1699 (devpriv->
1700 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1701 outb(devpriv->b_TimerSelectMode,
1702 devpriv->iobase + APCI3120_TIMER_CRT1);
1703
1704 /*
1705 * Configure the timer 2 for writing the LOW unsigned short of timer
1706 * is Delay value You must make a b_tmp variable with
1707 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1708 * you can set the digital output and configure the timer 2,and if
1709 * you don't make this, digital output are erase (Set to 0)
1710 */
1711
1712 /* Writing LOW unsigned short */
1713 b_Tmp = ((devpriv->
1714 b_DigitalOutputRegister) & 0xF0) |
1715 APCI3120_SELECT_TIMER_2_LOW_WORD;
1716 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1717 outw(ui_Timervalue2 & 0xffff,
1718 devpriv->iobase + APCI3120_TIMER_VALUE);
1719
1720 /* Writing HIGH unsigned short */
1721 b_Tmp = ((devpriv->
1722 b_DigitalOutputRegister) & 0xF0) |
1723 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1724 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1725
1726 outw((ui_Timervalue2 >> 16) & 0xffff,
1727 devpriv->iobase + APCI3120_TIMER_VALUE);
1728 /* watchdog enabled */
1729 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1730
1731 }
1732
1733 return insn->n;
1734
1735 }
1736
1737 /*
1738 * To start and stop the timer
1739 *
1740 * data[0] = 1 (start)
1741 * = 0 (stop)
1742 * = 2 (write new value)
1743 * data[1] = new value
1744 *
1745 * devpriv->b_Timer2Mode = 0 DISABLE
1746 * = 1 Timer
1747 * = 2 Watch dog
1748 */
apci3120_write_insn_timer(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1749 static int apci3120_write_insn_timer(struct comedi_device *dev,
1750 struct comedi_subdevice *s,
1751 struct comedi_insn *insn,
1752 unsigned int *data)
1753 {
1754 const struct addi_board *this_board = dev->board_ptr;
1755 struct addi_private *devpriv = dev->private;
1756 unsigned int ui_Timervalue2 = 0;
1757 unsigned short us_TmpValue;
1758 unsigned char b_Tmp;
1759
1760 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1761 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1762 dev_err(dev->class_dev, "timer2 not configured\n");
1763 return -EINVAL;
1764 }
1765
1766 if (data[0] == 2) { /* write new value */
1767 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1768 dev_err(dev->class_dev,
1769 "timer2 not configured in TIMER MODE\n");
1770 return -EINVAL;
1771 }
1772
1773 if (data[1])
1774 ui_Timervalue2 = data[1];
1775 else
1776 ui_Timervalue2 = 0;
1777 }
1778
1779 switch (data[0]) {
1780 case APCI3120_START:
1781
1782 /* Reset FC_TIMER BIT */
1783 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1784 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1785 /* Enable Timer */
1786 devpriv->b_ModeSelectRegister =
1787 devpriv->b_ModeSelectRegister & 0x0B;
1788 } else { /* start watch dog */
1789 /* Enable WatchDog */
1790 devpriv->b_ModeSelectRegister =
1791 (devpriv->
1792 b_ModeSelectRegister & 0x0B) |
1793 APCI3120_ENABLE_WATCHDOG;
1794 }
1795
1796 /* enable disable interrupt */
1797 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1798
1799 devpriv->b_ModeSelectRegister =
1800 devpriv->
1801 b_ModeSelectRegister |
1802 APCI3120_ENABLE_TIMER_INT;
1803 /* save the task structure to pass info to user */
1804 devpriv->tsk_Current = current;
1805 } else {
1806
1807 devpriv->b_ModeSelectRegister =
1808 devpriv->
1809 b_ModeSelectRegister &
1810 APCI3120_DISABLE_TIMER_INT;
1811 }
1812 outb(devpriv->b_ModeSelectRegister,
1813 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1814
1815 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
1816 /* For Timer mode is Gate2 must be activated timer started */
1817 devpriv->us_OutputRegister =
1818 devpriv->
1819 us_OutputRegister | APCI3120_ENABLE_TIMER2;
1820 outw(devpriv->us_OutputRegister,
1821 devpriv->iobase + APCI3120_WR_ADDRESS);
1822 }
1823
1824 break;
1825
1826 case APCI3120_STOP:
1827 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1828 /* Disable timer */
1829 devpriv->b_ModeSelectRegister =
1830 devpriv->
1831 b_ModeSelectRegister &
1832 APCI3120_DISABLE_TIMER_COUNTER;
1833 } else {
1834 /* Disable WatchDog */
1835 devpriv->b_ModeSelectRegister =
1836 devpriv->
1837 b_ModeSelectRegister &
1838 APCI3120_DISABLE_WATCHDOG;
1839 }
1840 /* Disable timer interrupt */
1841 devpriv->b_ModeSelectRegister =
1842 devpriv->
1843 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
1844
1845 /* Write above states to register */
1846 outb(devpriv->b_ModeSelectRegister,
1847 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1848
1849 /* Reset Gate 2 */
1850 devpriv->us_OutputRegister =
1851 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
1852 outw(devpriv->us_OutputRegister,
1853 devpriv->iobase + APCI3120_WR_ADDRESS);
1854
1855 /* Reset FC_TIMER BIT */
1856 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1857
1858 break;
1859
1860 case 2: /* write new value to Timer */
1861 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1862 dev_err(dev->class_dev,
1863 "timer2 not configured in TIMER MODE\n");
1864 return -EINVAL;
1865 }
1866 us_TmpValue =
1867 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1868
1869 /*
1870 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1871 * is an APCI3001 and calculate the time value to set in the timer
1872 */
1873 if ((us_TmpValue & 0x00B0) == 0x00B0
1874 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1875 /* Calculate the time value to set in the timer */
1876 ui_Timervalue2 = ui_Timervalue2 / 50;
1877 } else {
1878 /* Calculate the time value to set in the timer */
1879 ui_Timervalue2 = ui_Timervalue2 / 70;
1880 }
1881 /* Writing LOW unsigned short */
1882 b_Tmp = ((devpriv->
1883 b_DigitalOutputRegister) & 0xF0) |
1884 APCI3120_SELECT_TIMER_2_LOW_WORD;
1885 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1886
1887 outw(ui_Timervalue2 & 0xffff,
1888 devpriv->iobase + APCI3120_TIMER_VALUE);
1889
1890 /* Writing HIGH unsigned short */
1891 b_Tmp = ((devpriv->
1892 b_DigitalOutputRegister) & 0xF0) |
1893 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1894 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1895
1896 outw((ui_Timervalue2 >> 16) & 0xffff,
1897 devpriv->iobase + APCI3120_TIMER_VALUE);
1898
1899 break;
1900 default:
1901 return -EINVAL; /* Not a valid input */
1902 }
1903
1904 return insn->n;
1905 }
1906
1907 /*
1908 * Read the Timer value
1909 *
1910 * for Timer: data[0]= Timer constant
1911 *
1912 * for watchdog: data[0] = 0 (still running)
1913 * = 1 (run down)
1914 */
apci3120_read_insn_timer(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1915 static int apci3120_read_insn_timer(struct comedi_device *dev,
1916 struct comedi_subdevice *s,
1917 struct comedi_insn *insn,
1918 unsigned int *data)
1919 {
1920 struct addi_private *devpriv = dev->private;
1921 unsigned char b_Tmp;
1922 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
1923
1924 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1925 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1926 dev_err(dev->class_dev, "timer2 not configured\n");
1927 }
1928 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1929
1930 /* Read the LOW unsigned short of Timer 2 register */
1931 b_Tmp = ((devpriv->
1932 b_DigitalOutputRegister) & 0xF0) |
1933 APCI3120_SELECT_TIMER_2_LOW_WORD;
1934 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1935
1936 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
1937
1938 /* Read the HIGH unsigned short of Timer 2 register */
1939 b_Tmp = ((devpriv->
1940 b_DigitalOutputRegister) & 0xF0) |
1941 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1942 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1943
1944 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
1945
1946 /* combining both words */
1947 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
1948
1949 } else { /* Read watch dog status */
1950
1951 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
1952 us_StatusValue =
1953 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
1954 if (us_StatusValue == 1) {
1955 /* RESET FC_TIMER BIT */
1956 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1957 }
1958 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
1959 }
1960 return insn->n;
1961 }
1962
apci3120_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1963 static int apci3120_di_insn_bits(struct comedi_device *dev,
1964 struct comedi_subdevice *s,
1965 struct comedi_insn *insn,
1966 unsigned int *data)
1967 {
1968 struct addi_private *devpriv = dev->private;
1969 unsigned int val;
1970
1971 /* the input channels are bits 11:8 of the status reg */
1972 val = inw(devpriv->iobase + APCI3120_RD_STATUS);
1973 data[1] = (val >> 8) & 0xf;
1974
1975 return insn->n;
1976 }
1977
apci3120_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1978 static int apci3120_do_insn_bits(struct comedi_device *dev,
1979 struct comedi_subdevice *s,
1980 struct comedi_insn *insn,
1981 unsigned int *data)
1982 {
1983 struct addi_private *devpriv = dev->private;
1984
1985 if (comedi_dio_update_state(s, data)) {
1986 /* The do channels are bits 7:4 of the do register */
1987 devpriv->b_DigitalOutputRegister = s->state << 4;
1988
1989 outb(devpriv->b_DigitalOutputRegister,
1990 devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
1991 }
1992
1993 data[1] = s->state;
1994
1995 return insn->n;
1996 }
1997
apci3120_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)1998 static int apci3120_ao_insn_write(struct comedi_device *dev,
1999 struct comedi_subdevice *s,
2000 struct comedi_insn *insn,
2001 unsigned int *data)
2002 {
2003 struct addi_private *devpriv = dev->private;
2004 unsigned int ui_Range, ui_Channel;
2005 unsigned short us_TmpValue;
2006
2007 ui_Range = CR_RANGE(insn->chanspec);
2008 ui_Channel = CR_CHAN(insn->chanspec);
2009
2010 if (ui_Range) { /* if 1 then unipolar */
2011
2012 if (data[0] != 0)
2013 data[0] =
2014 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2015 13) | (data[0] + 8191));
2016 else
2017 data[0] =
2018 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2019 13) | 8192);
2020
2021 } else { /* if 0 then bipolar */
2022 data[0] =
2023 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2024 data[0]);
2025
2026 }
2027
2028 do { /* Waiting of DA_READY BIT */
2029 us_TmpValue =
2030 ((unsigned short) inw(devpriv->iobase +
2031 APCI3120_RD_STATUS)) & 0x0001;
2032 } while (us_TmpValue != 0x0001);
2033
2034 if (ui_Channel <= 3)
2035 /*
2036 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2037 * typecasted to ushort since word write is to be done
2038 */
2039 outw((unsigned short) data[0],
2040 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2041 else
2042 /*
2043 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2044 * typecasted to ushort since word write is to be done
2045 */
2046 outw((unsigned short) data[0],
2047 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2048
2049 return insn->n;
2050 }
2051