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