Staging: comedi: addi-data: Cleanup redundant tests on unsigned
[linux-2.6-block.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3120.c
CommitLineData
c995fe94
ADG
1/**
2@verbatim
3
4Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
5
356cdbcb
BP
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
c995fe94
ADG
13
14This 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
16This 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
18You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20You shoud also find the complete GPL in the COPYING file accompanying this source code.
21
22@endverbatim
23*/
24/*
25 +-----------------------------------------------------------------------+
26 | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier |
27 +-----------------------------------------------------------------------+
28 | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
29 | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
30 +-----------------------------------------------------------------------+
31 | Project : APCI-3120 | Compiler : GCC |
32 | Module name : hwdrv_apci3120.c| Version : 2.96 |
33 +-------------------------------+---------------------------------------+
34 | Project manager: Eric Stolz | Date : 02/12/2002 |
35 +-----------------------------------------------------------------------+
36 | Description :APCI3120 Module. Hardware abstraction Layer for APCI3120|
37 +-----------------------------------------------------------------------+
38 | UPDATE'S |
39 +-----------------------------------------------------------------------+
40 | Date | Author | Description of updates |
41 +----------+-----------+------------------------------------------------+
42 | | | |
43 | | | |
44 +----------+-----------+------------------------------------------------+
45*/
46
47#include "hwdrv_apci3120.h"
117102b0 48static unsigned int ui_Temp = 0;
c995fe94 49
1efd18f0 50/* FUNCTION DEFINITIONS */
c995fe94
ADG
51
52/*
53+----------------------------------------------------------------------------+
54| ANALOG INPUT SUBDEVICE |
55+----------------------------------------------------------------------------+
56*/
57
58/*
59+----------------------------------------------------------------------------+
71b5f4f1 60| Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
90035c08 61| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
62| |
63+----------------------------------------------------------------------------+
64| Task : Calls card specific function |
65| |
66+----------------------------------------------------------------------------+
71b5f4f1 67| Input Parameters : struct comedi_device *dev |
34c43922 68| struct comedi_subdevice *s |
90035c08 69| struct comedi_insn *insn |
790c5541 70| unsigned int *data |
c995fe94
ADG
71+----------------------------------------------------------------------------+
72| Return Value : |
73| |
74+----------------------------------------------------------------------------+
75*/
76
da91b269
BP
77int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
78 struct comedi_insn *insn, unsigned int *data)
c995fe94 79{
117102b0 80 unsigned int i;
c995fe94
ADG
81
82 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
83 return -1;
84
1efd18f0 85 /* Check for Conversion time to be added ?? */
c995fe94
ADG
86 devpriv->ui_EocEosConversionTime = data[2];
87
88 if (data[0] == APCI3120_EOS_MODE) {
89
1efd18f0 90 /* Test the number of the channel */
c995fe94
ADG
91 for (i = 0; i < data[3]; i++) {
92
93 if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
94 printk("bad channel list\n");
95 return -2;
96 }
97 }
98
99 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
100
101 if (data[1]) {
102 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
103 } else
104 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1efd18f0 105 /* Copy channel list and Range List to devpriv */
c995fe94
ADG
106
107 devpriv->ui_AiNbrofChannels = data[3];
108 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
109 devpriv->ui_AiChannelList[i] = data[4 + i];
110 }
111
1efd18f0 112 } else /* EOC */
c995fe94
ADG
113 {
114 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
115 if (data[1]) {
116 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
117 } else {
118 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
119 }
120 }
121
122 return insn->n;
123}
124
125/*
126+----------------------------------------------------------------------------+
71b5f4f1 127| Function name :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, |
90035c08 128| struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
c995fe94
ADG
129| |
130+----------------------------------------------------------------------------+
131| Task : card specific function |
132| Reads analog input in synchronous mode |
133| EOC and EOS is selected as per configured |
134| if no conversion time is set uses default conversion |
135| time 10 microsec. |
136| |
137+----------------------------------------------------------------------------+
71b5f4f1 138| Input Parameters : struct comedi_device *dev |
34c43922 139| struct comedi_subdevice *s |
90035c08 140| struct comedi_insn *insn |
790c5541 141| unsigned int *data |
c995fe94
ADG
142+----------------------------------------------------------------------------+
143| Return Value : |
144| |
145+----------------------------------------------------------------------------+
146*/
147
da91b269
BP
148int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
149 struct comedi_insn *insn, unsigned int *data)
c995fe94 150{
a9fce7c9 151 unsigned short us_ConvertTiming, us_TmpValue, i;
1783fbfe 152 unsigned char b_Tmp;
c995fe94 153
1efd18f0 154 /* fix convertion time to 10 us */
c995fe94
ADG
155 if (!devpriv->ui_EocEosConversionTime) {
156 printk("No timer0 Value using 10 us\n");
157 us_ConvertTiming = 10;
158 } else
1efd18f0 159 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
c995fe94 160
1efd18f0 161 /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
c995fe94 162
1efd18f0 163 /* Clear software registers */
c995fe94
ADG
164 devpriv->b_TimerSelectMode = 0;
165 devpriv->b_ModeSelectRegister = 0;
166 devpriv->us_OutputRegister = 0;
1efd18f0 167/* devpriv->b_DigitalOutputRegister=0; */
c995fe94 168
1efd18f0 169 if (insn->unused[0] == 222) /* second insn read */
c995fe94
ADG
170 {
171
172 for (i = 0; i < insn->n; i++) {
173 data[i] = devpriv->ui_AiReadData[i];
174 }
175
176 } else {
1efd18f0
BP
177 devpriv->tsk_Current = current; /* Save the current process task structure */
178/*
179 * Testing if board have the new Quartz and calculate the time value
180 * to set in the timer
181 */
c995fe94
ADG
182
183 us_TmpValue =
a9fce7c9 184 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
c995fe94 185
1efd18f0 186 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
c995fe94
ADG
187 if ((us_TmpValue & 0x00B0) == 0x00B0
188 || !strcmp(this_board->pc_DriverName, "apci3001")) {
189 us_ConvertTiming = (us_ConvertTiming * 2) - 2;
190 } else {
191 us_ConvertTiming =
192 ((us_ConvertTiming * 12926) / 10000) - 1;
193 }
194
a9fce7c9 195 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
c995fe94
ADG
196
197 switch (us_TmpValue) {
198
199 case APCI3120_EOC_MODE:
200
1efd18f0
BP
201/*
202 * Testing the interrupt flag and set the EOC bit Clears the FIFO
203 */
c995fe94
ADG
204 inw(devpriv->iobase + APCI3120_RESET_FIFO);
205
1efd18f0 206 /* Initialize the sequence array */
c995fe94 207
1efd18f0 208 /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
c995fe94
ADG
209
210 if (!i_APCI3120_SetupChannelList(dev, s, 1,
211 &insn->chanspec, 0))
212 return -EINVAL;
213
1efd18f0 214 /* Initialize Timer 0 mode 4 */
c995fe94
ADG
215 devpriv->b_TimerSelectMode =
216 (devpriv->
217 b_TimerSelectMode & 0xFC) |
218 APCI3120_TIMER_0_MODE_4;
219 outb(devpriv->b_TimerSelectMode,
220 devpriv->iobase + APCI3120_TIMER_CRT1);
221
1efd18f0 222 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
c995fe94
ADG
223 devpriv->b_ModeSelectRegister =
224 devpriv->
225 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
226
227 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
228
1efd18f0 229 /* Disables the EOS,DMA and enables the EOC interrupt */
c995fe94
ADG
230 devpriv->b_ModeSelectRegister =
231 (devpriv->
232 b_ModeSelectRegister &
233 APCI3120_DISABLE_EOS_INT) |
234 APCI3120_ENABLE_EOC_INT;
235 inw(devpriv->iobase);
236
237 } else {
238 devpriv->b_ModeSelectRegister =
239 devpriv->
240 b_ModeSelectRegister &
241 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
242 }
243
244 outb(devpriv->b_ModeSelectRegister,
245 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
246
1efd18f0 247 /* Sets gate 0 */
c995fe94
ADG
248 devpriv->us_OutputRegister =
249 (devpriv->
250 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
251 APCI3120_ENABLE_TIMER0;
252 outw(devpriv->us_OutputRegister,
253 devpriv->iobase + APCI3120_WR_ADDRESS);
254
1efd18f0 255 /* Select Timer 0 */
c995fe94
ADG
256 b_Tmp = ((devpriv->
257 b_DigitalOutputRegister) & 0xF0) |
258 APCI3120_SELECT_TIMER_0_WORD;
259 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
260
1efd18f0 261 /* Set the convertion time */
c995fe94
ADG
262 outw(us_ConvertTiming,
263 devpriv->iobase + APCI3120_TIMER_VALUE);
264
265 us_TmpValue =
a9fce7c9 266 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
c995fe94
ADG
267
268 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
269
270 do {
1efd18f0 271 /* Waiting for the end of conversion */
c995fe94
ADG
272 us_TmpValue =
273 inw(devpriv->iobase +
274 APCI3120_RD_STATUS);
275 } while ((us_TmpValue & APCI3120_EOC) ==
276 APCI3120_EOC);
277
1efd18f0 278 /* Read the result in FIFO and put it in insn data pointer */
c995fe94
ADG
279 us_TmpValue = inw(devpriv->iobase + 0);
280 *data = us_TmpValue;
281
282 inw(devpriv->iobase + APCI3120_RESET_FIFO);
283 }
284
285 break;
286
287 case APCI3120_EOS_MODE:
288
289 inw(devpriv->iobase);
1efd18f0 290 /* Clears the FIFO */
c995fe94 291 inw(devpriv->iobase + APCI3120_RESET_FIFO);
1efd18f0 292 /* clear PA PR and disable timer 0 */
c995fe94
ADG
293
294 devpriv->us_OutputRegister =
295 (devpriv->
296 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
297 APCI3120_DISABLE_TIMER0;
298
299 outw(devpriv->us_OutputRegister,
300 devpriv->iobase + APCI3120_WR_ADDRESS);
301
302 if (!i_APCI3120_SetupChannelList(dev, s,
303 devpriv->ui_AiNbrofChannels,
304 devpriv->ui_AiChannelList, 0))
305 return -EINVAL;
306
1efd18f0 307 /* Initialize Timer 0 mode 2 */
c995fe94
ADG
308 devpriv->b_TimerSelectMode =
309 (devpriv->
310 b_TimerSelectMode & 0xFC) |
311 APCI3120_TIMER_0_MODE_2;
312 outb(devpriv->b_TimerSelectMode,
313 devpriv->iobase + APCI3120_TIMER_CRT1);
314
1efd18f0 315 /* Select Timer 0 */
c995fe94
ADG
316 b_Tmp = ((devpriv->
317 b_DigitalOutputRegister) & 0xF0) |
318 APCI3120_SELECT_TIMER_0_WORD;
319 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
320
1efd18f0 321 /* Set the convertion time */
c995fe94
ADG
322 outw(us_ConvertTiming,
323 devpriv->iobase + APCI3120_TIMER_VALUE);
324
1efd18f0 325 /* Set the scan bit */
c995fe94
ADG
326 devpriv->b_ModeSelectRegister =
327 devpriv->
328 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
329 outb(devpriv->b_ModeSelectRegister,
330 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
331
1efd18f0 332 /* If Interrupt function is loaded */
c995fe94 333 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1efd18f0 334 /* Disables the EOC,DMA and enables the EOS interrupt */
c995fe94
ADG
335 devpriv->b_ModeSelectRegister =
336 (devpriv->
337 b_ModeSelectRegister &
338 APCI3120_DISABLE_EOC_INT) |
339 APCI3120_ENABLE_EOS_INT;
340 inw(devpriv->iobase);
341
342 } else
343 devpriv->b_ModeSelectRegister =
344 devpriv->
345 b_ModeSelectRegister &
346 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
347
348 outb(devpriv->b_ModeSelectRegister,
349 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
350
351 inw(devpriv->iobase + APCI3120_RD_STATUS);
352
1efd18f0 353 /* Sets gate 0 */
c995fe94
ADG
354
355 devpriv->us_OutputRegister =
356 devpriv->
357 us_OutputRegister | APCI3120_ENABLE_TIMER0;
358 outw(devpriv->us_OutputRegister,
359 devpriv->iobase + APCI3120_WR_ADDRESS);
360
1efd18f0 361 /* Start conversion */
c995fe94
ADG
362 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
363
1efd18f0 364 /* Waiting of end of convertion if interrupt is not installed */
c995fe94 365 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
1efd18f0 366 /* Waiting the end of convertion */
c995fe94
ADG
367 do {
368 us_TmpValue =
369 inw(devpriv->iobase +
370 APCI3120_RD_STATUS);
ff89514f
BP
371 } while ((us_TmpValue & APCI3120_EOS) !=
372 APCI3120_EOS);
c995fe94
ADG
373
374 for (i = 0; i < devpriv->ui_AiNbrofChannels;
375 i++) {
1efd18f0 376 /* Read the result in FIFO and write them in shared memory */
c995fe94 377 us_TmpValue = inw(devpriv->iobase);
117102b0 378 data[i] = (unsigned int) us_TmpValue;
c995fe94
ADG
379 }
380
1efd18f0 381 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
c995fe94
ADG
382 }
383 break;
384
385 default:
386 printk("inputs wrong\n");
387
388 }
1efd18f0 389 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
c995fe94
ADG
390 }
391
392 return insn->n;
393
394}
395
396/*
397+----------------------------------------------------------------------------+
71b5f4f1 398| Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
34c43922 399| struct comedi_subdevice *s)|
c995fe94
ADG
400| |
401+----------------------------------------------------------------------------+
402| Task : Stops Cyclic acquisition |
403| |
404+----------------------------------------------------------------------------+
71b5f4f1 405| Input Parameters : struct comedi_device *dev |
34c43922 406| struct comedi_subdevice *s |
c995fe94
ADG
407| |
408+----------------------------------------------------------------------------+
409| Return Value :0 |
410| |
411+----------------------------------------------------------------------------+
412*/
413
da91b269 414int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s)
c995fe94 415{
1efd18f0 416 /* Disable A2P Fifo write and AMWEN signal */
c995fe94
ADG
417 outw(0, devpriv->i_IobaseAddon + 4);
418
1efd18f0 419 /* Disable Bus Master ADD ON */
c995fe94
ADG
420 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
421 outw(0, devpriv->i_IobaseAddon + 2);
422 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
423 outw(0, devpriv->i_IobaseAddon + 2);
424
1efd18f0 425 /* Disable BUS Master PCI */
c995fe94
ADG
426 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
427
1efd18f0
BP
428 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
429 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
430
431 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
432 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
c995fe94 433
1efd18f0 434 /* Disable ext trigger */
c995fe94
ADG
435 i_APCI3120_ExttrigDisable(dev);
436
437 devpriv->us_OutputRegister = 0;
1efd18f0 438 /* stop counters */
c995fe94
ADG
439 outw(devpriv->
440 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
441 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
442
443 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
444
1efd18f0 445 /* DISABLE_ALL_INTERRUPT */
c995fe94
ADG
446 outb(APCI3120_DISABLE_ALL_INTERRUPT,
447 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1efd18f0 448 /* Flush FIFO */
c995fe94
ADG
449 inb(dev->iobase + APCI3120_RESET_FIFO);
450 inw(dev->iobase + APCI3120_RD_STATUS);
451 devpriv->ui_AiActualScan = 0;
452 devpriv->ui_AiActualScanPosition = 0;
453 s->async->cur_chan = 0;
454 devpriv->ui_AiBufferPtr = 0;
455 devpriv->b_AiContinuous = 0;
456 devpriv->ui_DmaActualBuffer = 0;
457
458 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
459 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
460 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
461 i_APCI3120_Reset(dev);
462 return 0;
463}
464
465/*
466+----------------------------------------------------------------------------+
71b5f4f1 467| Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
ea6d0d4c 468| ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
c995fe94
ADG
469| |
470+----------------------------------------------------------------------------+
471| Task : Test validity for a command for cyclic anlog input |
472| acquisition |
473| |
474+----------------------------------------------------------------------------+
71b5f4f1 475| Input Parameters : struct comedi_device *dev |
34c43922 476| struct comedi_subdevice *s |
ea6d0d4c 477| struct comedi_cmd *cmd |
c995fe94
ADG
478+----------------------------------------------------------------------------+
479| Return Value :0 |
480| |
481+----------------------------------------------------------------------------+
482*/
483
da91b269
BP
484int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
485 struct comedi_cmd *cmd)
c995fe94
ADG
486{
487 int err = 0;
1efd18f0 488 int tmp; /* divisor1,divisor2; */
c995fe94 489
1efd18f0 490 /* step 1: make sure trigger sources are trivially valid */
c995fe94
ADG
491
492 tmp = cmd->start_src;
493 cmd->start_src &= TRIG_NOW | TRIG_EXT;
494 if (!cmd->start_src || tmp != cmd->start_src)
495 err++;
496
497 tmp = cmd->scan_begin_src;
498 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
499 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
500 err++;
501
502 tmp = cmd->convert_src;
503 cmd->convert_src &= TRIG_TIMER;
504 if (!cmd->convert_src || tmp != cmd->convert_src)
505 err++;
506
507 tmp = cmd->scan_end_src;
508 cmd->scan_end_src &= TRIG_COUNT;
509 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
510 err++;
511
512 tmp = cmd->stop_src;
513 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
514 if (!cmd->stop_src || tmp != cmd->stop_src)
515 err++;
516
517 if (err)
518 return 1;
519
1efd18f0 520 /* step 2: make sure trigger sources are unique and mutually compatible */
c995fe94
ADG
521
522 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
523 err++;
524 }
525
526 if (cmd->scan_begin_src != TRIG_TIMER &&
527 cmd->scan_begin_src != TRIG_FOLLOW)
528 err++;
529
530 if (cmd->convert_src != TRIG_TIMER)
531 err++;
532
533 if (cmd->scan_end_src != TRIG_COUNT) {
534 cmd->scan_end_src = TRIG_COUNT;
535 err++;
536 }
537
538 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
539 err++;
540
541 if (err)
542 return 2;
543
1efd18f0 544 /* step 3: make sure arguments are trivially compatible */
c995fe94
ADG
545
546 if (cmd->start_arg != 0) {
547 cmd->start_arg = 0;
548 err++;
549 }
550
1efd18f0 551 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
c995fe94
ADG
552 {
553 if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
554 cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
555 err++;
556 }
557 }
558
1efd18f0 559 if (cmd->convert_src == TRIG_TIMER) /* Test Acquisition timing */
c995fe94
ADG
560 {
561 if (cmd->scan_begin_src == TRIG_TIMER) {
562 if ((cmd->convert_arg)
563 && (cmd->convert_arg <
564 this_board->ui_MinAcquisitiontimeNs)) {
565 cmd->convert_arg =
566 this_board->ui_MinAcquisitiontimeNs;
567 err++;
568 }
569 } else {
570 if (cmd->convert_arg <
571 this_board->ui_MinAcquisitiontimeNs) {
572 cmd->convert_arg =
573 this_board->ui_MinAcquisitiontimeNs;
574 err++;
575
576 }
577 }
578 }
579
580 if (!cmd->chanlist_len) {
581 cmd->chanlist_len = 1;
582 err++;
583 }
584 if (cmd->chanlist_len > this_board->i_AiChannelList) {
585 cmd->chanlist_len = this_board->i_AiChannelList;
586 err++;
587 }
588 if (cmd->stop_src == TRIG_COUNT) {
589 if (!cmd->stop_arg) {
590 cmd->stop_arg = 1;
591 err++;
592 }
1efd18f0 593 } else { /* TRIG_NONE */
c995fe94
ADG
594 if (cmd->stop_arg != 0) {
595 cmd->stop_arg = 0;
596 err++;
597 }
598 }
599
600 if (err)
601 return 3;
602
1efd18f0 603 /* step 4: fix up any arguments */
c995fe94
ADG
604
605 if (cmd->convert_src == TRIG_TIMER) {
606
607 if (cmd->scan_begin_src == TRIG_TIMER &&
608 cmd->scan_begin_arg <
609 cmd->convert_arg * cmd->scan_end_arg) {
610 cmd->scan_begin_arg =
611 cmd->convert_arg * cmd->scan_end_arg;
612 err++;
613 }
614 }
615
616 if (err)
617 return 4;
618
619 return 0;
620}
621
622/*
623+----------------------------------------------------------------------------+
71b5f4f1 624| Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
34c43922 625| struct comedi_subdevice *s) |
c995fe94
ADG
626| |
627+----------------------------------------------------------------------------+
628| Task : Does asynchronous acquisition |
629| Determines the mode 1 or 2. |
630| |
631+----------------------------------------------------------------------------+
71b5f4f1 632| Input Parameters : struct comedi_device *dev |
34c43922 633| struct comedi_subdevice *s |
c995fe94
ADG
634| |
635+----------------------------------------------------------------------------+
636| Return Value : |
637| |
638+----------------------------------------------------------------------------+
639*/
640
da91b269 641int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s)
c995fe94 642{
ea6d0d4c 643 struct comedi_cmd *cmd = &s->async->cmd;
c995fe94 644
1efd18f0 645 /* loading private structure with cmd structure inputs */
c995fe94
ADG
646 devpriv->ui_AiFlags = cmd->flags;
647 devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
648 devpriv->ui_AiScanLength = cmd->scan_end_arg;
649 devpriv->pui_AiChannelList = cmd->chanlist;
650
1efd18f0 651 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
c995fe94 652 devpriv->AiData = s->async->prealloc_buf;
1efd18f0 653 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
c995fe94
ADG
654 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
655
656 if (cmd->stop_src == TRIG_COUNT) {
657 devpriv->ui_AiNbrofScans = cmd->stop_arg;
658 } else {
659 devpriv->ui_AiNbrofScans = 0;
660 }
661
1efd18f0 662 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
c995fe94
ADG
663 devpriv->ui_AiTimer1 = 0;
664 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
1efd18f0
BP
665 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
666 /* stopped using cancel */
c995fe94
ADG
667
668 if (cmd->start_src == TRIG_EXT)
669 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
670 else
671 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
672
673 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1efd18f0 674 /* mode 1 or 3 */
c995fe94 675 if (cmd->convert_src == TRIG_TIMER) {
1efd18f0 676 /* mode 1 */
c995fe94 677
1efd18f0
BP
678 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
679 /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
c995fe94
ADG
680 return i_APCI3120_CyclicAnalogInput(1, dev, s);
681 }
682
683 }
684 if ((cmd->scan_begin_src == TRIG_TIMER)
685 && (cmd->convert_src == TRIG_TIMER)) {
1efd18f0 686 /* mode 2 */
c995fe94 687 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
1efd18f0
BP
688 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
689 /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
c995fe94
ADG
690 return i_APCI3120_CyclicAnalogInput(2, dev, s);
691 }
692 return -1;
693}
694
695/*
696+----------------------------------------------------------------------------+
697| Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
34c43922 698| struct comedi_device * dev,struct comedi_subdevice * s) |
c995fe94
ADG
699+----------------------------------------------------------------------------+
700| Task : This is used for analog input cyclic acquisition |
701| Performs the command operations. |
702| If DMA is configured does DMA initialization |
703| otherwise does the acquisition with EOS interrupt. |
704| |
705+----------------------------------------------------------------------------+
706| Input Parameters : |
707| |
708| |
709+----------------------------------------------------------------------------+
710| Return Value : |
711| |
712+----------------------------------------------------------------------------+
713*/
714
da91b269
BP
715int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
716 struct comedi_subdevice *s)
c995fe94 717{
1783fbfe 718 unsigned char b_Tmp;
117102b0 719 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
c995fe94
ADG
720 0, dmalen1 = 0, ui_TimerValue2 =
721 0, ui_TimerValue0, ui_ConvertTiming;
a9fce7c9 722 unsigned short us_TmpValue;
c995fe94 723
1efd18f0
BP
724 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
725 /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
726 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
727
728 /*******************/
729 /* Resets the FIFO */
730 /*******************/
731 inb(dev->iobase + APCI3120_RESET_FIFO);
732
1efd18f0
BP
733 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
734 /* inw(dev->iobase+APCI3120_RD_STATUS); */
735 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
736
737 /***************************/
738 /* Acquisition initialized */
739 /***************************/
1efd18f0 740 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94 741 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
1efd18f0 742 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94 743
1efd18f0 744 /* clear software registers */
c995fe94
ADG
745 devpriv->b_TimerSelectMode = 0;
746 devpriv->us_OutputRegister = 0;
747 devpriv->b_ModeSelectRegister = 0;
1efd18f0 748 /* devpriv->b_DigitalOutputRegister=0; */
c995fe94 749
1efd18f0 750 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
c995fe94 751
1efd18f0 752 /****************************/
74b894e5 753 /* Clear Timer Write TC int */
1efd18f0 754 /****************************/
c995fe94
ADG
755 outl(APCI3120_CLEAR_WRITE_TC_INT,
756 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
757
1efd18f0 758 /************************************/
c995fe94 759 /* Clears the timer status register */
1efd18f0 760 /************************************/
c995fe94 761
1efd18f0
BP
762 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
763 /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
764 /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
765 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
766
767 /**************************/
c995fe94
ADG
768 /* Disables All Timer */
769 /* Sets PR and PA to 0 */
1efd18f0 770 /**************************/
c995fe94
ADG
771 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
772 APCI3120_DISABLE_TIMER0 &
773 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
774
775 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
776
1efd18f0 777 /*******************/
c995fe94 778 /* Resets the FIFO */
1efd18f0
BP
779 /*******************/
780 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94 781 inb(devpriv->iobase + APCI3120_RESET_FIFO);
1efd18f0 782 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
783
784 devpriv->ui_AiActualScan = 0;
785 devpriv->ui_AiActualScanPosition = 0;
786 s->async->cur_chan = 0;
787 devpriv->ui_AiBufferPtr = 0;
788 devpriv->ui_DmaActualBuffer = 0;
789
1efd18f0 790 /* value for timer2 minus -2 has to be done .....dunno y?? */
c995fe94
ADG
791 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
792 ui_ConvertTiming = devpriv->ui_AiTimer0;
793
794 if (mode == 2)
795 ui_DelayTiming = devpriv->ui_AiTimer1;
796
797 /**********************************/
798 /* Initializes the sequence array */
799 /**********************************/
800 if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
801 devpriv->pui_AiChannelList, 0))
802 return -EINVAL;
803
a9fce7c9 804 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
c995fe94 805/*** EL241003 : add this section in comment because floats must not be used
356cdbcb 806 if((us_TmpValue & 0x00B0)==0x00B0)
c995fe94 807 {
356cdbcb 808 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
117102b0 809 ui_TimerValue0=(unsigned int)f_ConvertValue;
c995fe94
ADG
810 if (mode==2)
811 {
812 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
117102b0 813 ui_TimerValue1 = (unsigned int) f_DelayValue;
c995fe94
ADG
814 }
815 }
356cdbcb 816 else
c995fe94
ADG
817 {
818 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
117102b0 819 ui_TimerValue0=(unsigned int)f_ConvertValue;
c995fe94
ADG
820 if (mode == 2)
821 {
822 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
117102b0 823 ui_TimerValue1 = (unsigned int) f_DelayValue;
c995fe94
ADG
824 }
825 }
826***********************************************************************************************/
827/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
1efd18f0 828 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
c995fe94
ADG
829 if ((us_TmpValue & 0x00B0) == 0x00B0
830 || !strcmp(this_board->pc_DriverName, "apci3001")) {
831 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
832 ui_TimerValue0 = ui_TimerValue0 / 1000;
833
834 if (mode == 2) {
835 ui_DelayTiming = ui_DelayTiming / 1000;
836 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
837 ui_TimerValue1 = ui_TimerValue1 / 100;
838 }
839 } else {
840 ui_ConvertTiming = ui_ConvertTiming / 1000;
841 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
842 ui_TimerValue0 = ui_TimerValue0 / 10000;
843
844 if (mode == 2) {
845 ui_DelayTiming = ui_DelayTiming / 1000;
846 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
847 ui_TimerValue1 = ui_TimerValue1 / 1000000;
848 }
849 }
850/*** EL241003 End ******************************************************************************/
851
852 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1efd18f0 853 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
c995fe94
ADG
854 }
855 switch (mode) {
856 case 1:
1efd18f0 857 /* init timer0 in mode 2 */
c995fe94
ADG
858 devpriv->b_TimerSelectMode =
859 (devpriv->
860 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
861 outb(devpriv->b_TimerSelectMode,
862 dev->iobase + APCI3120_TIMER_CRT1);
863
1efd18f0 864 /* Select Timer 0 */
c995fe94
ADG
865 b_Tmp = ((devpriv->
866 b_DigitalOutputRegister) & 0xF0) |
867 APCI3120_SELECT_TIMER_0_WORD;
868 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1efd18f0 869 /* Set the convertion time */
a9fce7c9 870 outw(((unsigned short) ui_TimerValue0),
c995fe94
ADG
871 dev->iobase + APCI3120_TIMER_VALUE);
872 break;
873
874 case 2:
1efd18f0 875 /* init timer1 in mode 2 */
c995fe94
ADG
876 devpriv->b_TimerSelectMode =
877 (devpriv->
878 b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
879 outb(devpriv->b_TimerSelectMode,
880 dev->iobase + APCI3120_TIMER_CRT1);
881
1efd18f0 882 /* Select Timer 1 */
c995fe94
ADG
883 b_Tmp = ((devpriv->
884 b_DigitalOutputRegister) & 0xF0) |
885 APCI3120_SELECT_TIMER_1_WORD;
886 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1efd18f0 887 /* Set the convertion time */
a9fce7c9 888 outw(((unsigned short) ui_TimerValue1),
c995fe94
ADG
889 dev->iobase + APCI3120_TIMER_VALUE);
890
1efd18f0 891 /* init timer0 in mode 2 */
c995fe94
ADG
892 devpriv->b_TimerSelectMode =
893 (devpriv->
894 b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
895 outb(devpriv->b_TimerSelectMode,
896 dev->iobase + APCI3120_TIMER_CRT1);
897
1efd18f0 898 /* Select Timer 0 */
c995fe94
ADG
899 b_Tmp = ((devpriv->
900 b_DigitalOutputRegister) & 0xF0) |
901 APCI3120_SELECT_TIMER_0_WORD;
902 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
903
1efd18f0 904 /* Set the convertion time */
a9fce7c9 905 outw(((unsigned short) ui_TimerValue0),
c995fe94
ADG
906 dev->iobase + APCI3120_TIMER_VALUE);
907 break;
908
909 }
1efd18f0 910 /* ##########common for all modes################# */
c995fe94
ADG
911
912 /***********************/
913 /* Clears the SCAN bit */
914 /***********************/
1efd18f0
BP
915
916 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
917 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
918
c995fe94
ADG
919 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
920 APCI3120_DISABLE_SCAN;
1efd18f0
BP
921 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
922
c995fe94
ADG
923 outb(devpriv->b_ModeSelectRegister,
924 dev->iobase + APCI3120_WRITE_MODE_SELECT);
925
1efd18f0 926 /* If DMA is disabled */
c995fe94 927 if (devpriv->us_UseDma == APCI3120_DISABLE) {
1efd18f0 928 /* disable EOC and enable EOS */
c995fe94
ADG
929 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
930 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
931
932 devpriv->b_ModeSelectRegister =
933 (devpriv->
934 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
935 APCI3120_ENABLE_EOS_INT;
936 outb(devpriv->b_ModeSelectRegister,
937 dev->iobase + APCI3120_WRITE_MODE_SELECT);
938
939 if (!devpriv->b_AiContinuous) {
1efd18f0
BP
940/*
941 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
942 * disable it (Set Bit D14 to 0)
943 */
c995fe94
ADG
944 devpriv->us_OutputRegister =
945 devpriv->
946 us_OutputRegister & APCI3120_DISABLE_TIMER2;
947 outw(devpriv->us_OutputRegister,
948 dev->iobase + APCI3120_WR_ADDRESS);
949
1efd18f0 950 /* DISABLE TIMER intERRUPT */
c995fe94
ADG
951 devpriv->b_ModeSelectRegister =
952 devpriv->
953 b_ModeSelectRegister &
954 APCI3120_DISABLE_TIMER_INT & 0xEF;
955 outb(devpriv->b_ModeSelectRegister,
956 dev->iobase + APCI3120_WRITE_MODE_SELECT);
957
1efd18f0 958 /* (1) Init timer 2 in mode 0 and write timer value */
c995fe94
ADG
959 devpriv->b_TimerSelectMode =
960 (devpriv->
961 b_TimerSelectMode & 0x0F) |
962 APCI3120_TIMER_2_MODE_0;
963 outb(devpriv->b_TimerSelectMode,
964 dev->iobase + APCI3120_TIMER_CRT1);
965
1efd18f0 966 /* Writing LOW unsigned short */
c995fe94
ADG
967 b_Tmp = ((devpriv->
968 b_DigitalOutputRegister) & 0xF0) |
969 APCI3120_SELECT_TIMER_2_LOW_WORD;
970 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
971 outw(LOWORD(ui_TimerValue2),
972 dev->iobase + APCI3120_TIMER_VALUE);
973
1efd18f0 974 /* Writing HIGH unsigned short */
c995fe94
ADG
975 b_Tmp = ((devpriv->
976 b_DigitalOutputRegister) & 0xF0) |
977 APCI3120_SELECT_TIMER_2_HIGH_WORD;
978 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
979 outw(HIWORD(ui_TimerValue2),
980 dev->iobase + APCI3120_TIMER_VALUE);
981
1efd18f0 982 /* (2) Reset FC_TIMER BIT Clearing timer status register */
c995fe94 983 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1efd18f0 984 /* enable timer counter and disable watch dog */
c995fe94
ADG
985 devpriv->b_ModeSelectRegister =
986 (devpriv->
987 b_ModeSelectRegister |
988 APCI3120_ENABLE_TIMER_COUNTER) &
989 APCI3120_DISABLE_WATCHDOG;
1efd18f0 990 /* select EOS clock input for timer 2 */
c995fe94
ADG
991 devpriv->b_ModeSelectRegister =
992 devpriv->
993 b_ModeSelectRegister |
994 APCI3120_TIMER2_SELECT_EOS;
1efd18f0 995 /* Enable timer2 interrupt */
c995fe94
ADG
996 devpriv->b_ModeSelectRegister =
997 devpriv->
998 b_ModeSelectRegister |
999 APCI3120_ENABLE_TIMER_INT;
1000 outb(devpriv->b_ModeSelectRegister,
1001 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1002 devpriv->b_Timer2Mode = APCI3120_COUNTER;
1003 devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1004 }
1005 } else {
1efd18f0
BP
1006 /* If DMA Enabled */
1007
1008 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1009 /* inw(dev->iobase+0); reset EOC bit */
1010 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
1011 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1012
1efd18f0 1013 /************************************/
c995fe94 1014 /* Disables the EOC, EOS interrupt */
1efd18f0 1015 /************************************/
c995fe94
ADG
1016 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1017 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1018
1019 outb(devpriv->b_ModeSelectRegister,
1020 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1021
1022 dmalen0 = devpriv->ui_DmaBufferSize[0];
1023 dmalen1 = devpriv->ui_DmaBufferSize[1];
1024
1025 if (!devpriv->b_AiContinuous) {
1026
1efd18f0 1027 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
c995fe94
ADG
1028 dmalen0 =
1029 devpriv->ui_AiNbrofScans *
1030 devpriv->ui_AiScanLength * 2;
1efd18f0 1031 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
c995fe94
ADG
1032 dmalen1 =
1033 devpriv->ui_AiNbrofScans *
1034 devpriv->ui_AiScanLength * 2 - dmalen0;
1035 }
1036
1037 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1efd18f0 1038 /* don't we want wake up every scan? */
c995fe94
ADG
1039 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1040 dmalen0 = devpriv->ui_AiScanLength * 2;
1041 if (devpriv->ui_AiScanLength & 1)
1042 dmalen0 += 2;
1043 }
1044 if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
1045 dmalen1 = devpriv->ui_AiScanLength * 2;
1046 if (devpriv->ui_AiScanLength & 1)
1047 dmalen1 -= 2;
1048 if (dmalen1 < 4)
1049 dmalen1 = 4;
1050 }
1efd18f0 1051 } else { /* isn't output buff smaller that our DMA buff? */
c995fe94
ADG
1052 if (dmalen0 > (devpriv->ui_AiDataLength)) {
1053 dmalen0 = devpriv->ui_AiDataLength;
1054 }
1055 if (dmalen1 > (devpriv->ui_AiDataLength)) {
1056 dmalen1 = devpriv->ui_AiDataLength;
1057 }
1058 }
1059 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1060 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1061
1efd18f0 1062 /* Initialize DMA */
c995fe94 1063
1efd18f0
BP
1064/*
1065 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1066 * register 1
1067 */
c995fe94
ADG
1068 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1069 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1070
1efd18f0 1071 /* changed since 16 bit interface for add on */
c995fe94
ADG
1072 /*********************/
1073 /* ENABLE BUS MASTER */
1074 /*********************/
1075 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1076 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1077 devpriv->i_IobaseAddon + 2);
1078
1079 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1080 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1081 devpriv->i_IobaseAddon + 2);
1082
1efd18f0
BP
1083/*
1084 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1085 * driver
1086 */
c995fe94 1087 outw(0x1000, devpriv->i_IobaseAddon + 2);
1efd18f0 1088 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94 1089
1efd18f0 1090 /* 2 No change */
c995fe94 1091 /* A2P FIFO MANAGEMENT */
1efd18f0
BP
1092 /* A2P fifo reset & transfer control enable */
1093
1094 /***********************/
1095 /* A2P FIFO MANAGEMENT */
1096 /***********************/
c995fe94
ADG
1097 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1098 APCI3120_AMCC_OP_MCSR);
1099
1efd18f0
BP
1100/*
1101 * 3
1102 * beginning address of dma buf The 32 bit address of dma buffer
1103 * is converted into two 16 bit addresses Can done by using _attach
1104 * and put into into an array array used may be for differnet pages
1105 */
c995fe94 1106
1efd18f0 1107 /* DMA Start Adress Low */
c995fe94
ADG
1108 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1109 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1110 devpriv->i_IobaseAddon + 2);
1111
1efd18f0 1112 /*************************/
c995fe94 1113 /* DMA Start Adress High */
1efd18f0 1114 /*************************/
c995fe94
ADG
1115 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1116 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1117 devpriv->i_IobaseAddon + 2);
1118
1efd18f0
BP
1119/*
1120 * 4
1121 * amount of bytes to be transfered set transfer count used ADDON
1122 * MWTC register commented testing
1123 * outl(devpriv->ui_DmaBufferUsesize[0],
1124 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1125 */
1126
1127 /**************************/
c995fe94 1128 /* Nbr of acquisition LOW */
1efd18f0 1129 /**************************/
c995fe94
ADG
1130 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1131 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1132 devpriv->i_IobaseAddon + 2);
1133
1efd18f0 1134 /***************************/
c995fe94 1135 /* Nbr of acquisition HIGH */
1efd18f0 1136 /***************************/
c995fe94
ADG
1137 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1138 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1139 devpriv->i_IobaseAddon + 2);
1140
1efd18f0
BP
1141/*
1142 * 5
1143 * To configure A2P FIFO testing outl(
1144 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1145 */
c995fe94
ADG
1146
1147 /******************/
1148 /* A2P FIFO RESET */
1149 /******************/
1efd18f0
BP
1150/*
1151 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1152 * driver
1153 */
c995fe94 1154 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1efd18f0
BP
1155 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1156
1157/*
1158 * 6
1159 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1160 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1161 */
c995fe94 1162
1efd18f0
BP
1163 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1164 /* outw(3,devpriv->i_IobaseAddon + 4); */
1165 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94 1166
1efd18f0
BP
1167/*
1168 * 7
1169 * initialise end of dma interrupt AINT_WRITE_COMPL =
1170 * ENABLE_WRITE_TC_INT(ADDI)
1171 */
c995fe94 1172 /***************************************************/
74b894e5 1173 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
c995fe94
ADG
1174 /***************************************************/
1175 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1176 APCI3120_ENABLE_WRITE_TC_INT),
1177 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1178
1efd18f0 1179 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
1180 /******************************************/
1181 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1182 /******************************************/
1183 outw(3, devpriv->i_IobaseAddon + 4);
1efd18f0 1184 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
1185
1186 /******************/
1187 /* A2P FIFO RESET */
1188 /******************/
1efd18f0 1189 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
1190 outl(0x04000000UL,
1191 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1efd18f0 1192 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
c995fe94
ADG
1193 }
1194
1195 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1196 && !devpriv->b_AiContinuous) {
1efd18f0 1197 /* set gate 2 to start conversion */
c995fe94
ADG
1198 devpriv->us_OutputRegister =
1199 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1200 outw(devpriv->us_OutputRegister,
1201 dev->iobase + APCI3120_WR_ADDRESS);
1202 }
1203
1204 switch (mode) {
1205 case 1:
1efd18f0 1206 /* set gate 0 to start conversion */
c995fe94
ADG
1207 devpriv->us_OutputRegister =
1208 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1209 outw(devpriv->us_OutputRegister,
1210 dev->iobase + APCI3120_WR_ADDRESS);
1211 break;
1212 case 2:
1efd18f0 1213 /* set gate 0 and gate 1 */
c995fe94
ADG
1214 devpriv->us_OutputRegister =
1215 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1216 devpriv->us_OutputRegister =
1217 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1218 outw(devpriv->us_OutputRegister,
1219 dev->iobase + APCI3120_WR_ADDRESS);
1220 break;
1221
1222 }
1223
1224 return 0;
1225
1226}
1227
1228/*
1229+----------------------------------------------------------------------------+
74b894e5 1230| intERNAL FUNCTIONS |
c995fe94
ADG
1231+----------------------------------------------------------------------------+
1232*/
1233
1234/*
1235+----------------------------------------------------------------------------+
71b5f4f1 1236| Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
c995fe94
ADG
1237| |
1238| |
1239+----------------------------------------------------------------------------+
1240| Task : Hardware reset function |
1241| |
1242+----------------------------------------------------------------------------+
71b5f4f1 1243| Input Parameters : struct comedi_device *dev |
c995fe94
ADG
1244| |
1245| |
1246+----------------------------------------------------------------------------+
1247| Return Value : |
1248| |
1249+----------------------------------------------------------------------------+
1250*/
1251
da91b269 1252int i_APCI3120_Reset(struct comedi_device *dev)
c995fe94
ADG
1253{
1254 unsigned int i;
1255 unsigned short us_TmpValue;
1256
1257 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1258 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1259 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1efd18f0 1260 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
c995fe94
ADG
1261 devpriv->b_OutputMemoryStatus = 0;
1262
1efd18f0 1263 /* variables used in timer subdevice */
c995fe94
ADG
1264 devpriv->b_Timer2Mode = 0;
1265 devpriv->b_Timer2Interrupt = 0;
1efd18f0 1266 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
c995fe94
ADG
1267
1268 /* Disable all interrupts, watchdog for the anolog output */
1269 devpriv->b_ModeSelectRegister = 0;
1270 outb(devpriv->b_ModeSelectRegister,
1271 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1272
1efd18f0 1273 /* Disables all counters, ext trigger and clears PA, PR */
c995fe94
ADG
1274 devpriv->us_OutputRegister = 0;
1275 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1276
1efd18f0
BP
1277/*
1278 * Code to set the all anolog o/p channel to 0v 8191 is decimal
1279 * value for zero(0 v)volt in bipolar mode(default)
1280 */
1281 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
1282 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
1283 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
1284 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */
1285
1286 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */
1287 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */
1288 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
1289 outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
1290
1291 /* Reset digital output to L0W */
1292
1293/* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
c995fe94
ADG
1294 udelay(10);
1295
1efd18f0
BP
1296 inw(dev->iobase + 0); /* make a dummy read */
1297 inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */
1298 inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */
c995fe94 1299
1efd18f0 1300 /* code to reset the RAM sequence */
c995fe94 1301 for (i = 0; i < 16; i++) {
1efd18f0 1302 us_TmpValue = i << 8; /* select the location */
c995fe94
ADG
1303 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1304 }
1305 return 0;
1306}
1307
1308/*
1309+----------------------------------------------------------------------------+
71b5f4f1 1310| Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
34c43922 1311| struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
c995fe94
ADG
1312| ,char check) |
1313| |
1314+----------------------------------------------------------------------------+
1315| Task :This function will first check channel list is ok or not|
1316|and then initialize the sequence RAM with the polarity, Gain,Channel number |
1317|If the last argument of function "check"is 1 then it only checks the channel|
1318|list is ok or not. |
1319| |
1320+----------------------------------------------------------------------------+
71b5f4f1 1321| Input Parameters : struct comedi_device * dev |
34c43922 1322| struct comedi_subdevice * s |
c995fe94
ADG
1323| int n_chan |
1324 unsigned int *chanlist
1325 char check
1326+----------------------------------------------------------------------------+
1327| Return Value : |
1328| |
1329+----------------------------------------------------------------------------+
1330*/
1331
da91b269 1332int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s,
c995fe94
ADG
1333 int n_chan, unsigned int *chanlist, char check)
1334{
1efd18f0 1335 unsigned int i; /* , differencial=0, bipolar=0; */
c995fe94
ADG
1336 unsigned int gain;
1337 unsigned short us_TmpValue;
1338
1339 /* correct channel and range number check itself comedi/range.c */
1340 if (n_chan < 1) {
1341 if (!check)
1342 comedi_error(dev, "range/channel list is empty!");
1343 return 0;
1344 }
1efd18f0 1345 /* All is ok, so we can setup channel/range list */
c995fe94
ADG
1346 if (check)
1347 return 1;
1348
1efd18f0 1349 /* Code to set the PA and PR...Here it set PA to 0.. */
c995fe94
ADG
1350 devpriv->us_OutputRegister =
1351 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
1352 devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
1353 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1354
1355 for (i = 0; i < n_chan; i++) {
1efd18f0
BP
1356 /* store range list to card */
1357 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
c995fe94
ADG
1358
1359 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
1efd18f0 1360 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
c995fe94 1361 } else {
1efd18f0 1362 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
c995fe94
ADG
1363 }
1364
1efd18f0
BP
1365 gain = CR_RANGE(chanlist[i]); /* get gain number */
1366 us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
1367 us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
c995fe94
ADG
1368 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1369
1370 printk("\n Gain = %i",
1371 (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
1372 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
1373 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
1374 }
1efd18f0 1375 return 1; /* we can serve this with scan logic */
c995fe94
ADG
1376}
1377
1378/*
1379+----------------------------------------------------------------------------+
71b5f4f1 1380| Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
c995fe94
ADG
1381| |
1382| |
1383+----------------------------------------------------------------------------+
1384| Task : Enable the external trigger |
1385| |
1386+----------------------------------------------------------------------------+
71b5f4f1 1387| Input Parameters : struct comedi_device * dev |
c995fe94
ADG
1388| |
1389| |
1390+----------------------------------------------------------------------------+
1391| Return Value : 0 |
1392| |
1393+----------------------------------------------------------------------------+
1394*/
1395
da91b269 1396int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
c995fe94
ADG
1397{
1398
1399 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1400 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1401 return 0;
1402}
1403
1404/*
1405+----------------------------------------------------------------------------+
71b5f4f1 1406| Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
c995fe94
ADG
1407| |
1408+----------------------------------------------------------------------------+
1409| Task : Disables the external trigger |
1410| |
1411+----------------------------------------------------------------------------+
71b5f4f1 1412| Input Parameters : struct comedi_device * dev |
c995fe94
ADG
1413| |
1414| |
1415+----------------------------------------------------------------------------+
1416| Return Value : 0 |
1417| |
1418+----------------------------------------------------------------------------+
1419*/
1420
da91b269 1421int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
c995fe94
ADG
1422{
1423 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1424 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1425 return 0;
1426}
1427
1428/*
1429+----------------------------------------------------------------------------+
74b894e5 1430| intERRUPT FUNCTIONS |
c995fe94
ADG
1431+----------------------------------------------------------------------------+
1432*/
1433
1434/*
1435+----------------------------------------------------------------------------+
1436| Function name : void v_APCI3120_Interrupt(int irq, void *d) |
1437| |
1438| |
1439+----------------------------------------------------------------------------+
1440| Task :Interrupt handler for APCI3120 |
1441| When interrupt occurs this gets called. |
1442| First it finds which interrupt has been generated and |
1443| handles corresponding interrupt |
1444| |
1445+----------------------------------------------------------------------------+
1446| Input Parameters : int irq |
1447| void *d |
1448| |
1449+----------------------------------------------------------------------------+
1450| Return Value : void |
1451| |
1452+----------------------------------------------------------------------------+
1453*/
1454
1455void v_APCI3120_Interrupt(int irq, void *d)
1456{
71b5f4f1 1457 struct comedi_device *dev = d;
a9fce7c9 1458 unsigned short int_daq;
c995fe94
ADG
1459
1460 unsigned int int_amcc, ui_Check, i;
a9fce7c9 1461 unsigned short us_TmpValue;
1783fbfe 1462 unsigned char b_DummyRead;
c995fe94 1463
34c43922 1464 struct comedi_subdevice *s = dev->subdevices + 0;
c995fe94
ADG
1465 ui_Check = 1;
1466
1efd18f0
BP
1467 int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */
1468 int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */
c995fe94
ADG
1469
1470 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1471 comedi_error(dev, "IRQ from unknow source");
1472 return;
1473 }
1474
1efd18f0 1475 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
c995fe94
ADG
1476
1477 int_daq = (int_daq >> 12) & 0xF;
1478
1479 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1efd18f0 1480 /* Disable ext trigger */
c995fe94
ADG
1481 i_APCI3120_ExttrigDisable(dev);
1482 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1483 }
1efd18f0 1484 /* clear the timer 2 interrupt */
c995fe94
ADG
1485 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1486
1487 if (int_amcc & MASTER_ABORT_INT)
1488 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1489 if (int_amcc & TARGET_ABORT_INT)
1490 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1491
1efd18f0 1492 /* Ckeck if EOC interrupt */
c995fe94
ADG
1493 if (((int_daq & 0x8) == 0)
1494 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1495 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1496
1efd18f0 1497 /* Read the AI Value */
c995fe94
ADG
1498
1499 devpriv->ui_AiReadData[0] =
117102b0 1500 (unsigned int) inw(devpriv->iobase + 0);
c995fe94 1501 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1efd18f0 1502 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
c995fe94 1503 } else {
1efd18f0 1504 /* Disable EOC Interrupt */
c995fe94
ADG
1505 devpriv->b_ModeSelectRegister =
1506 devpriv->
1507 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1508 outb(devpriv->b_ModeSelectRegister,
1509 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1510
1511 }
1512 }
1513
1efd18f0 1514 /* Check If EOS interrupt */
c995fe94
ADG
1515 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1516
1efd18f0 1517 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) /* enable this in without DMA ??? */
c995fe94
ADG
1518 {
1519
1520 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1521 ui_Check = 0;
1522 i_APCI3120_InterruptHandleEos(dev);
1523 devpriv->ui_AiActualScan++;
1524 devpriv->b_ModeSelectRegister =
1525 devpriv->
1526 b_ModeSelectRegister |
1527 APCI3120_ENABLE_EOS_INT;
1528 outb(devpriv->b_ModeSelectRegister,
1529 dev->iobase +
1530 APCI3120_WRITE_MODE_SELECT);
1531 } else {
1532 ui_Check = 0;
1533 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1534 i++) {
1535 us_TmpValue = inw(devpriv->iobase + 0);
1536 devpriv->ui_AiReadData[i] =
117102b0 1537 (unsigned int) us_TmpValue;
c995fe94
ADG
1538 }
1539 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1540 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1541
1efd18f0 1542 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
c995fe94
ADG
1543
1544 }
1545
1546 } else {
1547 devpriv->b_ModeSelectRegister =
1548 devpriv->
1549 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1550 outb(devpriv->b_ModeSelectRegister,
1551 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1efd18f0 1552 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
c995fe94
ADG
1553 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1554 }
1555
1556 }
1efd18f0 1557 /* Timer2 interrupt */
c995fe94
ADG
1558 if (int_daq & 0x1) {
1559
1560 switch (devpriv->b_Timer2Mode) {
1561 case APCI3120_COUNTER:
1562
1563 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1564 devpriv->b_ModeSelectRegister =
1565 devpriv->
1566 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1567 outb(devpriv->b_ModeSelectRegister,
1568 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1569
1efd18f0 1570 /* stop timer 2 */
c995fe94
ADG
1571 devpriv->us_OutputRegister =
1572 devpriv->
1573 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1574 outw(devpriv->us_OutputRegister,
1575 dev->iobase + APCI3120_WR_ADDRESS);
1576
1efd18f0 1577 /* stop timer 0 and timer 1 */
c995fe94
ADG
1578 i_APCI3120_StopCyclicAcquisition(dev, s);
1579 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1580
1efd18f0 1581 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
c995fe94
ADG
1582 s->async->events |= COMEDI_CB_EOA;
1583 comedi_event(dev, s);
1584
1585 break;
1586
1587 case APCI3120_TIMER:
1588
1efd18f0 1589 /* Send a signal to from kernel to user space */
c995fe94
ADG
1590 send_sig(SIGIO, devpriv->tsk_Current, 0);
1591 break;
1592
1593 case APCI3120_WATCHDOG:
1594
1efd18f0 1595 /* Send a signal to from kernel to user space */
c995fe94
ADG
1596 send_sig(SIGIO, devpriv->tsk_Current, 0);
1597 break;
1598
1599 default:
1600
1efd18f0 1601 /* disable Timer Interrupt */
c995fe94
ADG
1602
1603 devpriv->b_ModeSelectRegister =
1604 devpriv->
1605 b_ModeSelectRegister &
1606 APCI3120_DISABLE_TIMER_INT;
1607
1608 outb(devpriv->b_ModeSelectRegister,
1609 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1610
1611 }
1612
1613 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1614
1615 }
1616
1617 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1618 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1619
1620 /****************************/
74b894e5 1621 /* Clear Timer Write TC int */
c995fe94
ADG
1622 /****************************/
1623
1624 outl(APCI3120_CLEAR_WRITE_TC_INT,
1625 devpriv->i_IobaseAmcc +
1626 APCI3120_AMCC_OP_REG_INTCSR);
1627
1628 /************************************/
1629 /* Clears the timer status register */
1630 /************************************/
1631 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1efd18f0 1632 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
c995fe94
ADG
1633 } else {
1634 /* Stops the Timer */
1635 outw(devpriv->
1636 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1637 APCI3120_DISABLE_TIMER1,
1638 dev->iobase + APCI3120_WR_ADDRESS);
1639 }
1640
1641 }
1642
1643 return;
1644}
1645
1646/*
1647+----------------------------------------------------------------------------+
71b5f4f1 1648| Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
c995fe94
ADG
1649| |
1650| |
1651+----------------------------------------------------------------------------+
1652| Task : This function handles EOS interrupt. |
1653| This function copies the acquired data(from FIFO) |
1654| to Comedi buffer. |
1655| |
1656+----------------------------------------------------------------------------+
71b5f4f1 1657| Input Parameters : struct comedi_device *dev |
c995fe94
ADG
1658| |
1659| |
1660+----------------------------------------------------------------------------+
1661| Return Value : 0 |
1662| |
1663+----------------------------------------------------------------------------+
1664*/
1665
1efd18f0 1666
da91b269 1667int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
c995fe94
ADG
1668{
1669 int n_chan, i;
34c43922 1670 struct comedi_subdevice *s = dev->subdevices + 0;
c995fe94
ADG
1671 int err = 1;
1672
1673 n_chan = devpriv->ui_AiNbrofChannels;
1674
1675 s->async->events = 0;
1676
1677 for (i = 0; i < n_chan; i++)
1678 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1679
1680 s->async->events |= COMEDI_CB_EOS;
1681
1682 if (err == 0)
1683 s->async->events |= COMEDI_CB_OVERFLOW;
1684
1685 comedi_event(dev, s);
1686
1687 return 0;
1688}
1689
1690/*
1691+----------------------------------------------------------------------------+
1692| Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
1693| |
1694+----------------------------------------------------------------------------+
1695| Task : This is a handler for the DMA interrupt |
1696| This function copies the data to Comedi Buffer. |
1697| For continuous DMA it reinitializes the DMA operation. |
1698| For single mode DMA it stop the acquisition. |
1699| |
1700+----------------------------------------------------------------------------+
1701| Input Parameters : int irq, void *d |
1702| |
1703+----------------------------------------------------------------------------+
1704| Return Value : void |
1705| |
1706+----------------------------------------------------------------------------+
1707*/
1708
1709void v_APCI3120_InterruptDma(int irq, void *d)
1710{
71b5f4f1 1711 struct comedi_device *dev = d;
34c43922 1712 struct comedi_subdevice *s = dev->subdevices + 0;
c995fe94
ADG
1713 unsigned int next_dma_buf, samplesinbuf;
1714 unsigned long low_word, high_word, var;
1715
117102b0 1716 unsigned int ui_Tmp;
c995fe94
ADG
1717 samplesinbuf =
1718 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1719 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1720
1721 if (samplesinbuf <
1722 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1723 comedi_error(dev, "Interrupted DMA transfer!");
1724 }
1725 if (samplesinbuf & 1) {
1726 comedi_error(dev, "Odd count of bytes in DMA ring!");
1727 i_APCI3120_StopCyclicAcquisition(dev, s);
1728 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1729
1730 return;
1731 }
1efd18f0 1732 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
c995fe94 1733 if (devpriv->b_DmaDoubleBuffer) {
1efd18f0 1734 /* switch DMA buffers if is used double buffering */
c995fe94
ADG
1735 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1736
1737 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1738 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1739
1efd18f0 1740 /* changed since 16 bit interface for add on */
c995fe94
ADG
1741 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1742 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1743 devpriv->i_IobaseAddon + 2);
1744 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1efd18f0 1745 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
c995fe94
ADG
1746
1747 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1748 low_word = var & 0xffff;
1749 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1750 high_word = var / 65536;
1751
1752 /* DMA Start Adress Low */
1753 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1754 outw(low_word, devpriv->i_IobaseAddon + 2);
1755
1756 /* DMA Start Adress High */
1757 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1758 outw(high_word, devpriv->i_IobaseAddon + 2);
1759
1760 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1761 low_word = var & 0xffff;
1762 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1763 high_word = var / 65536;
1764
1765 /* Nbr of acquisition LOW */
1766 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1767 outw(low_word, devpriv->i_IobaseAddon + 2);
1768
1769 /* Nbr of acquisition HIGH */
1770 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1771 outw(high_word, devpriv->i_IobaseAddon + 2);
1772
1efd18f0
BP
1773/*
1774 * To configure A2P FIFO
1775 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1776 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1777 */
c995fe94 1778 outw(3, devpriv->i_IobaseAddon + 4);
1efd18f0 1779 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
c995fe94
ADG
1780 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1781 APCI3120_ENABLE_WRITE_TC_INT),
1782 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1783
1784 }
c995fe94
ADG
1785 if (samplesinbuf) {
1786 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1787 devpriv->ul_DmaBufferVirtual[devpriv->
1788 ui_DmaActualBuffer], samplesinbuf);
1789
1790 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1791 s->async->events |= COMEDI_CB_EOS;
1792 comedi_event(dev, s);
1793 }
1794 }
1795 if (!devpriv->b_AiContinuous)
1796 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1efd18f0 1797 /* all data sampled */
c995fe94
ADG
1798 i_APCI3120_StopCyclicAcquisition(dev, s);
1799 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1800 s->async->events |= COMEDI_CB_EOA;
1801 comedi_event(dev, s);
1802 return;
1803 }
1804
1efd18f0 1805 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
c995fe94
ADG
1806 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1807 } else {
1efd18f0
BP
1808/*
1809 * restart DMA if is not used double buffering
1810 * ADDED REINITIALISE THE DMA
1811 */
c995fe94
ADG
1812 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1813 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1814
1efd18f0 1815 /* changed since 16 bit interface for add on */
c995fe94
ADG
1816 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1817 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1818 devpriv->i_IobaseAddon + 2);
1819 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1efd18f0
BP
1820 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1821/*
1822 * A2P FIFO MANAGEMENT
1823 * A2P fifo reset & transfer control enable
1824 */
c995fe94
ADG
1825 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1826 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1827
1828 var = devpriv->ul_DmaBufferHw[0];
1829 low_word = var & 0xffff;
1830 var = devpriv->ul_DmaBufferHw[0];
1831 high_word = var / 65536;
1832 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1833 outw(low_word, devpriv->i_IobaseAddon + 2);
1834 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1835 outw(high_word, devpriv->i_IobaseAddon + 2);
1836
1837 var = devpriv->ui_DmaBufferUsesize[0];
1efd18f0 1838 low_word = var & 0xffff; /* changed */
c995fe94
ADG
1839 var = devpriv->ui_DmaBufferUsesize[0];
1840 high_word = var / 65536;
1841 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1842 outw(low_word, devpriv->i_IobaseAddon + 2);
1843 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1844 outw(high_word, devpriv->i_IobaseAddon + 2);
1845
1efd18f0
BP
1846/*
1847 * To configure A2P FIFO
1848 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1849 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1850 */
c995fe94 1851 outw(3, devpriv->i_IobaseAddon + 4);
1efd18f0 1852 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
c995fe94
ADG
1853 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1854 APCI3120_ENABLE_WRITE_TC_INT),
1855 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1856 }
1857}
1858
1859/*
1860+----------------------------------------------------------------------------+
1861| Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
34c43922 1862|*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
c995fe94
ADG
1863| |
1864+----------------------------------------------------------------------------+
1865| Task : This function copies the data from DMA buffer to the |
1866| Comedi buffer |
1867| |
1868+----------------------------------------------------------------------------+
71b5f4f1 1869| Input Parameters : struct comedi_device *dev |
34c43922 1870| struct comedi_subdevice *s |
790c5541
BP
1871| short *dma |
1872| short *data,int n |
c995fe94
ADG
1873+----------------------------------------------------------------------------+
1874| Return Value : void |
1875| |
1876+----------------------------------------------------------------------------+
1877*/
1878
da91b269
BP
1879void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1880 struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples)
c995fe94
ADG
1881{
1882 devpriv->ui_AiActualScan +=
1883 (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
1884 s->async->cur_chan += num_samples;
1885 s->async->cur_chan %= devpriv->ui_AiScanLength;
1886
790c5541 1887 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
c995fe94
ADG
1888}
1889
1890/*
1891+----------------------------------------------------------------------------+
1892| TIMER SUBDEVICE |
1893+----------------------------------------------------------------------------+
1894*/
1895
1896/*
1897+----------------------------------------------------------------------------+
71b5f4f1 1898| Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
90035c08 1899| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
1900| |
1901+----------------------------------------------------------------------------+
1902| Task :Configure Timer 2 |
1903| |
1904+----------------------------------------------------------------------------+
71b5f4f1 1905| Input Parameters : struct comedi_device *dev |
34c43922 1906| struct comedi_subdevice *s |
90035c08 1907| struct comedi_insn *insn |
790c5541 1908| unsigned int *data |
c995fe94
ADG
1909| |
1910| data[0]= TIMER configure as timer |
1911| = WATCHDOG configure as watchdog |
1912| data[1] = Timer constant |
1913| data[2] = Timer2 interrupt (1)enable or(0) disable |
1914| |
1915+----------------------------------------------------------------------------+
1916| Return Value : |
1917| |
1918+----------------------------------------------------------------------------+
1919*/
1920
da91b269
BP
1921int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s,
1922 struct comedi_insn *insn, unsigned int *data)
c995fe94
ADG
1923{
1924
117102b0 1925 unsigned int ui_Timervalue2;
a9fce7c9 1926 unsigned short us_TmpValue;
1783fbfe 1927 unsigned char b_Tmp;
c995fe94
ADG
1928
1929 if (!data[1])
1930 comedi_error(dev, "config:No timer constant !");
1931
1efd18f0 1932 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
c995fe94 1933
1efd18f0 1934 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
c995fe94 1935
1efd18f0 1936 /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
a9fce7c9 1937 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
c995fe94 1938
1efd18f0
BP
1939/*
1940 * EL250804: Testing if board APCI3120 have the new Quartz or if it
1941 * is an APCI3001 and calculate the time value to set in the timer
1942 */
c995fe94
ADG
1943 if ((us_TmpValue & 0x00B0) == 0x00B0
1944 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1efd18f0 1945 /* Calculate the time value to set in the timer */
c995fe94
ADG
1946 ui_Timervalue2 = ui_Timervalue2 / 50;
1947 } else {
1efd18f0 1948 /* Calculate the time value to set in the timer */
c995fe94
ADG
1949 ui_Timervalue2 = ui_Timervalue2 / 70;
1950 }
1951
1efd18f0 1952 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
c995fe94
ADG
1953 devpriv->us_OutputRegister =
1954 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1955 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1956
1efd18f0 1957 /* Disable TIMER Interrupt */
c995fe94
ADG
1958 devpriv->b_ModeSelectRegister =
1959 devpriv->
1960 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1961
1efd18f0 1962 /* Disable Eoc and Eos Interrupts */
c995fe94
ADG
1963 devpriv->b_ModeSelectRegister =
1964 devpriv->
1965 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1966 APCI3120_DISABLE_EOS_INT;
1967 outb(devpriv->b_ModeSelectRegister,
1968 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1efd18f0 1969 if (data[0] == APCI3120_TIMER) /* initialize timer */
c995fe94 1970 {
1efd18f0
BP
1971 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1972 * APCI3120_ENABLE_TIMER_INT; */
c995fe94 1973
1efd18f0 1974 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
c995fe94 1975
1efd18f0 1976 /* Set the Timer 2 in mode 2(Timer) */
c995fe94
ADG
1977 devpriv->b_TimerSelectMode =
1978 (devpriv->
1979 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1980 outb(devpriv->b_TimerSelectMode,
1981 devpriv->iobase + APCI3120_TIMER_CRT1);
1982
1efd18f0
BP
1983/*
1984 * Configure the timer 2 for writing the LOW unsigned short of timer
1985 * is Delay value You must make a b_tmp variable with
1986 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1987 * you can set the digital output and configure the timer 2,and if
1988 * you don't make this, digital output are erase (Set to 0)
1989 */
1990
1991 /* Writing LOW unsigned short */
c995fe94
ADG
1992 b_Tmp = ((devpriv->
1993 b_DigitalOutputRegister) & 0xF0) |
1994 APCI3120_SELECT_TIMER_2_LOW_WORD;
1995 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1996 outw(LOWORD(ui_Timervalue2),
1997 devpriv->iobase + APCI3120_TIMER_VALUE);
1998
1efd18f0 1999 /* Writing HIGH unsigned short */
c995fe94
ADG
2000 b_Tmp = ((devpriv->
2001 b_DigitalOutputRegister) & 0xF0) |
2002 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2003 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2004 outw(HIWORD(ui_Timervalue2),
2005 devpriv->iobase + APCI3120_TIMER_VALUE);
1efd18f0 2006 /* timer2 in Timer mode enabled */
c995fe94
ADG
2007 devpriv->b_Timer2Mode = APCI3120_TIMER;
2008
1efd18f0 2009 } else /* Initialize Watch dog */
c995fe94
ADG
2010 {
2011
1efd18f0 2012 /* Set the Timer 2 in mode 5(Watchdog) */
c995fe94
ADG
2013
2014 devpriv->b_TimerSelectMode =
2015 (devpriv->
2016 b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
2017 outb(devpriv->b_TimerSelectMode,
2018 devpriv->iobase + APCI3120_TIMER_CRT1);
2019
1efd18f0
BP
2020/*
2021 * Configure the timer 2 for writing the LOW unsigned short of timer
2022 * is Delay value You must make a b_tmp variable with
2023 * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
2024 * you can set the digital output and configure the timer 2,and if
2025 * you don't make this, digital output are erase (Set to 0)
2026 */
2027
2028 /* Writing LOW unsigned short */
c995fe94
ADG
2029 b_Tmp = ((devpriv->
2030 b_DigitalOutputRegister) & 0xF0) |
2031 APCI3120_SELECT_TIMER_2_LOW_WORD;
2032 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2033 outw(LOWORD(ui_Timervalue2),
2034 devpriv->iobase + APCI3120_TIMER_VALUE);
2035
1efd18f0 2036 /* Writing HIGH unsigned short */
c995fe94
ADG
2037 b_Tmp = ((devpriv->
2038 b_DigitalOutputRegister) & 0xF0) |
2039 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2040 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2041
2042 outw(HIWORD(ui_Timervalue2),
2043 devpriv->iobase + APCI3120_TIMER_VALUE);
1efd18f0 2044 /* watchdog enabled */
c995fe94
ADG
2045 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2046
2047 }
2048
2049 return insn->n;
2050
2051}
2052
2053/*
2054+----------------------------------------------------------------------------+
71b5f4f1 2055| Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
90035c08 2056| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2057| |
2058+----------------------------------------------------------------------------+
2059| Task : To start and stop the timer |
2060+----------------------------------------------------------------------------+
71b5f4f1 2061| Input Parameters : struct comedi_device *dev |
34c43922 2062| struct comedi_subdevice *s |
90035c08 2063| struct comedi_insn *insn |
790c5541 2064| unsigned int *data |
c995fe94
ADG
2065| |
2066| data[0] = 1 (start) |
2067| data[0] = 0 (stop ) |
2068| data[0] = 2 (write new value) |
2069| data[1]= new value |
2070| |
2071| devpriv->b_Timer2Mode = 0 DISABLE |
2072| 1 Timer |
2073| 2 Watch dog |
2074| |
2075+----------------------------------------------------------------------------+
2076| Return Value : |
2077| |
2078+----------------------------------------------------------------------------+
2079*/
2080
da91b269
BP
2081int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2082 struct comedi_insn *insn, unsigned int *data)
c995fe94
ADG
2083{
2084
117102b0 2085 unsigned int ui_Timervalue2 = 0;
a9fce7c9 2086 unsigned short us_TmpValue;
1783fbfe 2087 unsigned char b_Tmp;
c995fe94
ADG
2088
2089 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2090 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2091 comedi_error(dev, "\nwrite:timer2 not configured ");
2092 return -EINVAL;
2093 }
2094
1efd18f0 2095 if (data[0] == 2) /* write new value */
c995fe94
ADG
2096 {
2097 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2098 comedi_error(dev,
2099 "write :timer2 not configured in TIMER MODE");
2100 return -EINVAL;
2101 }
2102
2103 if (data[1])
2104 ui_Timervalue2 = data[1];
2105 else
2106 ui_Timervalue2 = 0;
2107 }
2108
1efd18f0 2109 /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
c995fe94
ADG
2110
2111 switch (data[0]) {
2112 case APCI3120_START:
2113
1efd18f0 2114 /* Reset FC_TIMER BIT */
c995fe94 2115 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1efd18f0 2116 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
c995fe94 2117 {
1efd18f0 2118 /* Enable Timer */
c995fe94
ADG
2119 devpriv->b_ModeSelectRegister =
2120 devpriv->b_ModeSelectRegister & 0x0B;
1efd18f0 2121 } else /* start watch dog */
c995fe94 2122 {
1efd18f0 2123 /* Enable WatchDog */
c995fe94
ADG
2124 devpriv->b_ModeSelectRegister =
2125 (devpriv->
2126 b_ModeSelectRegister & 0x0B) |
2127 APCI3120_ENABLE_WATCHDOG;
2128 }
2129
1efd18f0 2130 /* enable disable interrupt */
c995fe94
ADG
2131 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2132
2133 devpriv->b_ModeSelectRegister =
2134 devpriv->
2135 b_ModeSelectRegister |
2136 APCI3120_ENABLE_TIMER_INT;
1efd18f0 2137 /* save the task structure to pass info to user */
c995fe94
ADG
2138 devpriv->tsk_Current = current;
2139 } else {
2140
2141 devpriv->b_ModeSelectRegister =
2142 devpriv->
2143 b_ModeSelectRegister &
2144 APCI3120_DISABLE_TIMER_INT;
2145 }
2146 outb(devpriv->b_ModeSelectRegister,
2147 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2148
1efd18f0 2149 if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */
c995fe94 2150 {
1efd18f0 2151 /* For Timer mode is Gate2 must be activated **timer started */
c995fe94
ADG
2152 devpriv->us_OutputRegister =
2153 devpriv->
2154 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2155 outw(devpriv->us_OutputRegister,
2156 devpriv->iobase + APCI3120_WR_ADDRESS);
2157 }
2158
2159 break;
2160
2161 case APCI3120_STOP:
2162 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1efd18f0 2163 /* Disable timer */
c995fe94
ADG
2164 devpriv->b_ModeSelectRegister =
2165 devpriv->
2166 b_ModeSelectRegister &
2167 APCI3120_DISABLE_TIMER_COUNTER;
2168 } else {
1efd18f0 2169 /* Disable WatchDog */
c995fe94
ADG
2170 devpriv->b_ModeSelectRegister =
2171 devpriv->
2172 b_ModeSelectRegister &
2173 APCI3120_DISABLE_WATCHDOG;
2174 }
1efd18f0 2175 /* Disable timer interrupt */
c995fe94
ADG
2176 devpriv->b_ModeSelectRegister =
2177 devpriv->
2178 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2179
1efd18f0 2180 /* Write above states to register */
c995fe94
ADG
2181 outb(devpriv->b_ModeSelectRegister,
2182 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2183
1efd18f0 2184 /* Reset Gate 2 */
c995fe94
ADG
2185 devpriv->us_OutputRegister =
2186 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2187 outw(devpriv->us_OutputRegister,
2188 devpriv->iobase + APCI3120_WR_ADDRESS);
2189
1efd18f0 2190 /* Reset FC_TIMER BIT */
c995fe94
ADG
2191 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2192
1efd18f0
BP
2193 /* Disable timer */
2194 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
c995fe94
ADG
2195
2196 break;
2197
1efd18f0 2198 case 2: /* write new value to Timer */
c995fe94
ADG
2199 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2200 comedi_error(dev,
2201 "write :timer2 not configured in TIMER MODE");
2202 return -EINVAL;
2203 }
1efd18f0 2204 /* ui_Timervalue2=data[1]; // passed as argument */
c995fe94 2205 us_TmpValue =
a9fce7c9 2206 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
c995fe94 2207
1efd18f0
BP
2208/*
2209 * EL250804: Testing if board APCI3120 have the new Quartz or if it
2210 * is an APCI3001 and calculate the time value to set in the timer
2211 */
c995fe94
ADG
2212 if ((us_TmpValue & 0x00B0) == 0x00B0
2213 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1efd18f0 2214 /* Calculate the time value to set in the timer */
c995fe94
ADG
2215 ui_Timervalue2 = ui_Timervalue2 / 50;
2216 } else {
1efd18f0 2217 /* Calculate the time value to set in the timer */
c995fe94
ADG
2218 ui_Timervalue2 = ui_Timervalue2 / 70;
2219 }
1efd18f0 2220 /* Writing LOW unsigned short */
c995fe94
ADG
2221 b_Tmp = ((devpriv->
2222 b_DigitalOutputRegister) & 0xF0) |
2223 APCI3120_SELECT_TIMER_2_LOW_WORD;
2224 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2225
2226 outw(LOWORD(ui_Timervalue2),
2227 devpriv->iobase + APCI3120_TIMER_VALUE);
2228
1efd18f0 2229 /* Writing HIGH unsigned short */
c995fe94
ADG
2230 b_Tmp = ((devpriv->
2231 b_DigitalOutputRegister) & 0xF0) |
2232 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2233 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2234
2235 outw(HIWORD(ui_Timervalue2),
2236 devpriv->iobase + APCI3120_TIMER_VALUE);
2237
2238 break;
2239 default:
1efd18f0 2240 return -EINVAL; /* Not a valid input */
c995fe94
ADG
2241 }
2242
2243 return insn->n;
2244}
2245
2246/*
2247+----------------------------------------------------------------------------+
71b5f4f1 2248| Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
90035c08 2249| struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
c995fe94
ADG
2250| |
2251| |
2252+----------------------------------------------------------------------------+
2253| Task : read the Timer value |
2254+----------------------------------------------------------------------------+
71b5f4f1 2255| Input Parameters : struct comedi_device *dev |
34c43922 2256| struct comedi_subdevice *s |
90035c08 2257| struct comedi_insn *insn |
790c5541 2258| unsigned int *data |
c995fe94
ADG
2259| |
2260+----------------------------------------------------------------------------+
2261| Return Value : |
2262| for Timer: data[0]= Timer constant |
2263| |
2264| for watchdog: data[0]=0 (still running) |
2265| data[0]=1 (run down) |
2266| |
2267+----------------------------------------------------------------------------+
2268*/
da91b269
BP
2269int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2270 struct comedi_insn *insn, unsigned int *data)
c995fe94 2271{
1783fbfe 2272 unsigned char b_Tmp;
a9fce7c9 2273 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
c995fe94
ADG
2274
2275 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2276 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2277 comedi_error(dev, "\nread:timer2 not configured ");
2278 }
2279
1efd18f0 2280 /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
c995fe94
ADG
2281 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2282
1efd18f0 2283 /* Read the LOW unsigned short of Timer 2 register */
c995fe94
ADG
2284 b_Tmp = ((devpriv->
2285 b_DigitalOutputRegister) & 0xF0) |
2286 APCI3120_SELECT_TIMER_2_LOW_WORD;
2287 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2288
2289 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2290
1efd18f0 2291 /* Read the HIGH unsigned short of Timer 2 register */
c995fe94
ADG
2292 b_Tmp = ((devpriv->
2293 b_DigitalOutputRegister) & 0xF0) |
2294 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2295 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2296
2297 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2298
1efd18f0 2299 /* combining both words */
117102b0 2300 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
c995fe94 2301
1efd18f0 2302 } else /* Read watch dog status */
c995fe94
ADG
2303 {
2304
2305 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2306 us_StatusValue =
2307 ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2308 if (us_StatusValue == 1) {
1efd18f0 2309 /* RESET FC_TIMER BIT */
c995fe94
ADG
2310 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2311 }
1efd18f0 2312 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
c995fe94
ADG
2313 }
2314 return insn->n;
2315}
2316
2317/*
2318+----------------------------------------------------------------------------+
2319| DIGITAL INPUT SUBDEVICE |
2320+----------------------------------------------------------------------------+
2321*/
2322
2323/*
2324+----------------------------------------------------------------------------+
71b5f4f1 2325| Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
90035c08 2326| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2327| |
2328| |
2329+----------------------------------------------------------------------------+
2330| Task : Reads the value of the specified Digital input channel|
2331| |
2332+----------------------------------------------------------------------------+
71b5f4f1 2333| Input Parameters : struct comedi_device *dev |
34c43922 2334| struct comedi_subdevice *s |
90035c08 2335| struct comedi_insn *insn |
790c5541 2336| unsigned int *data |
c995fe94
ADG
2337+----------------------------------------------------------------------------+
2338| Return Value : |
2339| |
2340+----------------------------------------------------------------------------+
2341*/
2342
34c43922
BP
2343int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2344 struct comedi_subdevice *s,
90035c08 2345 struct comedi_insn *insn,
34c43922 2346 unsigned int *data)
c995fe94 2347{
117102b0 2348 unsigned int ui_Chan, ui_TmpValue;
c995fe94 2349
1efd18f0 2350 ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
c995fe94 2351
1efd18f0 2352 /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
dc8af068 2353 if (ui_Chan <= 3) {
117102b0 2354 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
c995fe94 2355
1efd18f0
BP
2356/*
2357 * since only 1 channel reqd to bring it to last bit it is rotated 8
2358 * +(chan - 1) times then ANDed with 1 for last bit.
2359 */
c995fe94 2360 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
1efd18f0 2361 /* return 0; */
c995fe94 2362 } else {
1efd18f0
BP
2363 /* comedi_error(dev," chan spec wrong"); */
2364 return -EINVAL; /* "sorry channel spec wrong " */
c995fe94
ADG
2365 }
2366 return insn->n;
2367
2368}
2369
2370/*
2371+----------------------------------------------------------------------------+
71b5f4f1 2372| Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
90035c08 2373|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2374| |
2375+----------------------------------------------------------------------------+
2376| Task : Reads the value of the Digital input Port i.e.4channels|
2377| value is returned in data[0] |
2378| |
2379+----------------------------------------------------------------------------+
71b5f4f1 2380| Input Parameters : struct comedi_device *dev |
34c43922 2381| struct comedi_subdevice *s |
90035c08 2382| struct comedi_insn *insn |
790c5541 2383| unsigned int *data |
c995fe94
ADG
2384+----------------------------------------------------------------------------+
2385| Return Value : |
2386| |
2387+----------------------------------------------------------------------------+
2388*/
da91b269
BP
2389int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
2390 struct comedi_insn *insn, unsigned int *data)
c995fe94 2391{
117102b0
BP
2392 unsigned int ui_TmpValue;
2393 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
c995fe94
ADG
2394 /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg
2395 rotated right 8 times to bring them to last four bits
2396 ANDed with oxf for value.
2397 *****/
2398
2399 *data = (ui_TmpValue >> 8) & 0xf;
1efd18f0 2400 /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
c995fe94
ADG
2401 return insn->n;
2402}
2403
2404/*
2405+----------------------------------------------------------------------------+
2406| DIGITAL OUTPUT SUBDEVICE |
2407+----------------------------------------------------------------------------+
2408*/
2409/*
2410+----------------------------------------------------------------------------+
71b5f4f1 2411| Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
90035c08 2412| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2413| |
2414+----------------------------------------------------------------------------+
2415| Task :Configure the output memory ON or OFF |
2416| |
2417+----------------------------------------------------------------------------+
71b5f4f1 2418| Input Parameters :struct comedi_device *dev |
34c43922 2419| struct comedi_subdevice *s |
90035c08 2420| struct comedi_insn *insn |
790c5541 2421| unsigned int *data |
c995fe94
ADG
2422+----------------------------------------------------------------------------+
2423| Return Value : |
2424| |
2425+----------------------------------------------------------------------------+
2426*/
2427
da91b269
BP
2428int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
2429 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
c995fe94
ADG
2430{
2431
2432 if ((data[0] != 0) && (data[0] != 1)) {
2433 comedi_error(dev,
2434 "Not a valid Data !!! ,Data should be 1 or 0\n");
2435 return -EINVAL;
2436 }
2437 if (data[0]) {
2438 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2439
2440 } else {
2441 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2442 devpriv->b_DigitalOutputRegister = 0;
2443 }
2444 if (!devpriv->b_OutputMemoryStatus) {
2445 ui_Temp = 0;
2446
1efd18f0 2447 } /* if(!devpriv->b_OutputMemoryStatus ) */
c995fe94
ADG
2448
2449 return insn->n;
2450}
2451
2452/*
2453+----------------------------------------------------------------------------+
71b5f4f1 2454| Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
90035c08 2455| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2456| |
2457+----------------------------------------------------------------------------+
2458| Task : write diatal output port |
2459| |
2460+----------------------------------------------------------------------------+
71b5f4f1 2461| Input Parameters : struct comedi_device *dev |
34c43922 2462| struct comedi_subdevice *s |
90035c08 2463| struct comedi_insn *insn |
790c5541 2464| unsigned int *data |
356cdbcb
BP
2465| data[0] Value to be written
2466| data[1] :1 Set digital o/p ON
2467| data[1] 2 Set digital o/p OFF with memory ON
c995fe94
ADG
2468+----------------------------------------------------------------------------+
2469| Return Value : |
2470| |
2471+----------------------------------------------------------------------------+
2472*/
2473
da91b269 2474int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,
34c43922 2475 struct comedi_subdevice *s,
90035c08 2476 struct comedi_insn *insn,
34c43922 2477 unsigned int *data)
c995fe94
ADG
2478{
2479 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2480
2481 comedi_error(dev, "Data is not valid !!! \n");
2482 return -EINVAL;
2483 }
2484
2485 switch (data[1]) {
2486 case 1:
2487 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2488 break;
2489
2490 case 2:
2491 data[0] = data[0];
2492 break;
2493 default:
2494 printk("\nThe parameter passed is in error \n");
2495 return -EINVAL;
1efd18f0 2496 } /* switch(data[1]) */
c995fe94
ADG
2497 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2498
2499 devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2500
2501 return insn->n;
2502
2503}
2504
2505/*
2506+----------------------------------------------------------------------------+
71b5f4f1 2507| Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
90035c08 2508|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2509| |
2510+----------------------------------------------------------------------------+
2511| Task : Write digiatl output |
2512| |
2513+----------------------------------------------------------------------------+
71b5f4f1 2514| Input Parameters : struct comedi_device *dev |
34c43922 2515| struct comedi_subdevice *s |
90035c08 2516| struct comedi_insn *insn |
790c5541 2517| unsigned int *data |
c995fe94
ADG
2518 data[0] Value to be written
2519 data[1] :1 Set digital o/p ON
2520 data[1] 2 Set digital o/p OFF with memory ON
2521+----------------------------------------------------------------------------+
2522| Return Value : |
2523| |
2524+----------------------------------------------------------------------------+
2525*/
2526
34c43922
BP
2527int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2528 struct comedi_subdevice *s,
90035c08 2529 struct comedi_insn *insn,
34c43922 2530 unsigned int *data)
c995fe94
ADG
2531{
2532
117102b0 2533 unsigned int ui_Temp1;
c995fe94 2534
1efd18f0 2535 unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
c995fe94
ADG
2536
2537 if ((data[0] != 0) && (data[0] != 1)) {
2538 comedi_error(dev,
2539 "Not a valid Data !!! ,Data should be 1 or 0\n");
2540 return -EINVAL;
2541 }
dc8af068 2542 if (ui_NoOfChannel > this_board->i_NbrDoChannel - 1) {
c995fe94
ADG
2543 comedi_error(dev,
2544 "This board doesn't have specified channel !!! \n");
2545 return -EINVAL;
2546 }
2547
2548 switch (data[1]) {
2549 case 1:
2550 data[0] = (data[0] << ui_NoOfChannel);
1efd18f0 2551/* ES05 data[0]=(data[0]<<4)|ui_Temp; */
c995fe94
ADG
2552 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2553 break;
2554
2555 case 2:
2556 data[0] = ~data[0] & 0x1;
2557 ui_Temp1 = 1;
2558 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
2559 ui_Temp1 = ui_Temp1 << 4;
1efd18f0 2560/* ES05 ui_Temp=ui_Temp|ui_Temp1; */
c995fe94
ADG
2561 devpriv->b_DigitalOutputRegister =
2562 devpriv->b_DigitalOutputRegister | ui_Temp1;
2563
2564 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2565 data[0] = data[0] << 4;
1efd18f0 2566/* ES05 data[0]=data[0]& ui_Temp; */
c995fe94
ADG
2567 data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2568 break;
2569 default:
2570 printk("\nThe parameter passed is in error \n");
2571 return -EINVAL;
1efd18f0 2572 } /* switch(data[1]) */
c995fe94
ADG
2573 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2574
1efd18f0 2575/* ES05 ui_Temp=data[0] & 0xf0; */
c995fe94 2576 devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
dae0dc30 2577 return insn->n;
c995fe94
ADG
2578
2579}
2580
2581/*
2582+----------------------------------------------------------------------------+
2583| ANALOG OUTPUT SUBDEVICE |
2584+----------------------------------------------------------------------------+
2585*/
2586
2587/*
2588+----------------------------------------------------------------------------+
71b5f4f1 2589| Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
90035c08 2590|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
c995fe94
ADG
2591| |
2592+----------------------------------------------------------------------------+
2593| Task : Write analog output |
2594| |
2595+----------------------------------------------------------------------------+
71b5f4f1 2596| Input Parameters : struct comedi_device *dev |
34c43922 2597| struct comedi_subdevice *s |
90035c08 2598| struct comedi_insn *insn |
790c5541 2599| unsigned int *data |
c995fe94
ADG
2600+----------------------------------------------------------------------------+
2601| Return Value : |
2602| |
2603+----------------------------------------------------------------------------+
2604*/
2605
34c43922
BP
2606int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2607 struct comedi_subdevice *s,
90035c08 2608 struct comedi_insn *insn,
34c43922 2609 unsigned int *data)
c995fe94 2610{
117102b0 2611 unsigned int ui_Range, ui_Channel;
a9fce7c9 2612 unsigned short us_TmpValue;
c995fe94
ADG
2613
2614 ui_Range = CR_RANGE(insn->chanspec);
2615 ui_Channel = CR_CHAN(insn->chanspec);
2616
1efd18f0
BP
2617 /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2618 if (ui_Range) /* if 1 then unipolar */
c995fe94
ADG
2619 {
2620
2621 if (data[0] != 0)
2622 data[0] =
2623 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2624 13) | (data[0] + 8191));
2625 else
2626 data[0] =
2627 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2628 13) | 8192);
2629
1efd18f0 2630 } else /* if 0 then bipolar */
c995fe94
ADG
2631 {
2632 data[0] =
2633 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2634 data[0]);
2635
2636 }
2637
1efd18f0 2638/*
5f74ea14 2639 * out put n values at the given channel. printk("\nwaiting for
1efd18f0
BP
2640 * DA_READY BIT");
2641 */
2642 do /* Waiting of DA_READY BIT */
c995fe94
ADG
2643 {
2644 us_TmpValue =
a9fce7c9 2645 ((unsigned short) inw(devpriv->iobase +
c995fe94
ADG
2646 APCI3120_RD_STATUS)) & 0x0001;
2647 } while (us_TmpValue != 0x0001);
2648
2649 if (ui_Channel <= 3)
1efd18f0
BP
2650/*
2651 * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2652 * typecasted to ushort since word write is to be done
2653 */
a9fce7c9 2654 outw((unsigned short) data[0],
c995fe94
ADG
2655 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2656 else
1efd18f0
BP
2657/*
2658 * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2659 * typecasted to ushort since word write is to be done
2660 */
a9fce7c9 2661 outw((unsigned short) data[0],
c995fe94
ADG
2662 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2663
2664 return insn->n;
2665}