GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3120.c
blob851f71bbf1bff69ef1f8ec322ee8c76ca3aa03f5
1 /**
2 @verbatim
4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
6 ADDI-DATA GmbH
7 Dieselstrasse 3
8 D-77833 Ottersweier
9 Tel: +19(0)7223/9493-0
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data-com
12 info@addi-data.com
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 You should also find the complete GPL in the COPYING file accompanying this source code.
22 @endverbatim
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 +----------+-----------+------------------------------------------------+
47 #include "hwdrv_apci3120.h"
48 static unsigned int ui_Temp;
50 /* FUNCTION DEFINITIONS */
53 +----------------------------------------------------------------------------+
54 | ANALOG INPUT SUBDEVICE |
55 +----------------------------------------------------------------------------+
59 +----------------------------------------------------------------------------+
60 | Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
61 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
62 | |
63 +----------------------------------------------------------------------------+
64 | Task : Calls card specific function |
65 | |
66 +----------------------------------------------------------------------------+
67 | Input Parameters : struct comedi_device *dev |
68 | struct comedi_subdevice *s |
69 | struct comedi_insn *insn |
70 | unsigned int *data |
71 +----------------------------------------------------------------------------+
72 | Return Value : |
73 | |
74 +----------------------------------------------------------------------------+
77 int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
78 struct comedi_insn *insn, unsigned int *data)
80 unsigned int i;
82 if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
83 return -1;
85 /* Check for Conversion time to be added ?? */
86 devpriv->ui_EocEosConversionTime = data[2];
88 if (data[0] == APCI3120_EOS_MODE) {
90 /* Test the number of the channel */
91 for (i = 0; i < data[3]; i++) {
93 if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
94 printk("bad channel list\n");
95 return -2;
99 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
101 if (data[1])
102 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
103 else
104 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
105 /* Copy channel list and Range List to devpriv */
107 devpriv->ui_AiNbrofChannels = data[3];
108 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
109 devpriv->ui_AiChannelList[i] = data[4 + i];
111 } else { /* EOC */
112 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
113 if (data[1])
114 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
115 else
116 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
119 return insn->n;
123 +----------------------------------------------------------------------------+
124 | Function name :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, |
125 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
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. |
134 +----------------------------------------------------------------------------+
135 | Input Parameters : struct comedi_device *dev |
136 | struct comedi_subdevice *s |
137 | struct comedi_insn *insn |
138 | unsigned int *data |
139 +----------------------------------------------------------------------------+
140 | Return Value : |
142 +----------------------------------------------------------------------------+
145 int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
146 struct comedi_insn *insn, unsigned int *data)
148 unsigned short us_ConvertTiming, us_TmpValue, i;
149 unsigned char b_Tmp;
151 /* fix convertion time to 10 us */
152 if (!devpriv->ui_EocEosConversionTime) {
153 printk("No timer0 Value using 10 us\n");
154 us_ConvertTiming = 10;
155 } else
156 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
158 /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
160 /* Clear software registers */
161 devpriv->b_TimerSelectMode = 0;
162 devpriv->b_ModeSelectRegister = 0;
163 devpriv->us_OutputRegister = 0;
164 /* devpriv->b_DigitalOutputRegister=0; */
166 if (insn->unused[0] == 222) { /* second insn read */
167 for (i = 0; i < insn->n; i++)
168 data[i] = devpriv->ui_AiReadData[i];
169 } else {
170 devpriv->tsk_Current = current; /* Save the current process task structure */
172 * Testing if board have the new Quartz and calculate the time value
173 * to set in the timer
176 us_TmpValue =
177 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
179 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
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;
188 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
190 switch (us_TmpValue) {
192 case APCI3120_EOC_MODE:
195 * Testing the interrupt flag and set the EOC bit Clears the FIFO
197 inw(devpriv->iobase + APCI3120_RESET_FIFO);
199 /* Initialize the sequence array */
201 /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
203 if (!i_APCI3120_SetupChannelList(dev, s, 1,
204 &insn->chanspec, 0))
205 return -EINVAL;
207 /* Initialize Timer 0 mode 4 */
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);
215 /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */
216 devpriv->b_ModeSelectRegister =
217 devpriv->
218 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
220 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
222 /* Disables the EOS,DMA and enables the EOC interrupt */
223 devpriv->b_ModeSelectRegister =
224 (devpriv->
225 b_ModeSelectRegister &
226 APCI3120_DISABLE_EOS_INT) |
227 APCI3120_ENABLE_EOC_INT;
228 inw(devpriv->iobase);
230 } else {
231 devpriv->b_ModeSelectRegister =
232 devpriv->
233 b_ModeSelectRegister &
234 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
237 outb(devpriv->b_ModeSelectRegister,
238 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
240 /* Sets gate 0 */
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);
248 /* Select Timer 0 */
249 b_Tmp = ((devpriv->
250 b_DigitalOutputRegister) & 0xF0) |
251 APCI3120_SELECT_TIMER_0_WORD;
252 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
254 /* Set the convertion time */
255 outw(us_ConvertTiming,
256 devpriv->iobase + APCI3120_TIMER_VALUE);
258 us_TmpValue =
259 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
261 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
263 do {
264 /* Waiting for the end of conversion */
265 us_TmpValue =
266 inw(devpriv->iobase +
267 APCI3120_RD_STATUS);
268 } while ((us_TmpValue & APCI3120_EOC) ==
269 APCI3120_EOC);
271 /* Read the result in FIFO and put it in insn data pointer */
272 us_TmpValue = inw(devpriv->iobase + 0);
273 *data = us_TmpValue;
275 inw(devpriv->iobase + APCI3120_RESET_FIFO);
278 break;
280 case APCI3120_EOS_MODE:
282 inw(devpriv->iobase);
283 /* Clears the FIFO */
284 inw(devpriv->iobase + APCI3120_RESET_FIFO);
285 /* clear PA PR and disable timer 0 */
287 devpriv->us_OutputRegister =
288 (devpriv->
289 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
290 APCI3120_DISABLE_TIMER0;
292 outw(devpriv->us_OutputRegister,
293 devpriv->iobase + APCI3120_WR_ADDRESS);
295 if (!i_APCI3120_SetupChannelList(dev, s,
296 devpriv->ui_AiNbrofChannels,
297 devpriv->ui_AiChannelList, 0))
298 return -EINVAL;
300 /* Initialize Timer 0 mode 2 */
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);
308 /* Select Timer 0 */
309 b_Tmp = ((devpriv->
310 b_DigitalOutputRegister) & 0xF0) |
311 APCI3120_SELECT_TIMER_0_WORD;
312 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
314 /* Set the convertion time */
315 outw(us_ConvertTiming,
316 devpriv->iobase + APCI3120_TIMER_VALUE);
318 /* Set the scan bit */
319 devpriv->b_ModeSelectRegister =
320 devpriv->
321 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
322 outb(devpriv->b_ModeSelectRegister,
323 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
325 /* If Interrupt function is loaded */
326 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
327 /* Disables the EOC,DMA and enables the EOS interrupt */
328 devpriv->b_ModeSelectRegister =
329 (devpriv->
330 b_ModeSelectRegister &
331 APCI3120_DISABLE_EOC_INT) |
332 APCI3120_ENABLE_EOS_INT;
333 inw(devpriv->iobase);
335 } else
336 devpriv->b_ModeSelectRegister =
337 devpriv->
338 b_ModeSelectRegister &
339 APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
341 outb(devpriv->b_ModeSelectRegister,
342 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
344 inw(devpriv->iobase + APCI3120_RD_STATUS);
346 /* Sets gate 0 */
348 devpriv->us_OutputRegister =
349 devpriv->
350 us_OutputRegister | APCI3120_ENABLE_TIMER0;
351 outw(devpriv->us_OutputRegister,
352 devpriv->iobase + APCI3120_WR_ADDRESS);
354 /* Start conversion */
355 outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
357 /* Waiting of end of convertion if interrupt is not installed */
358 if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
359 /* Waiting the end of convertion */
360 do {
361 us_TmpValue =
362 inw(devpriv->iobase +
363 APCI3120_RD_STATUS);
364 } while ((us_TmpValue & APCI3120_EOS) !=
365 APCI3120_EOS);
367 for (i = 0; i < devpriv->ui_AiNbrofChannels;
368 i++) {
369 /* Read the result in FIFO and write them in shared memory */
370 us_TmpValue = inw(devpriv->iobase);
371 data[i] = (unsigned int) us_TmpValue;
374 devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
376 break;
378 default:
379 printk("inputs wrong\n");
382 devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
385 return insn->n;
390 +----------------------------------------------------------------------------+
391 | Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
392 | struct comedi_subdevice *s)|
394 +----------------------------------------------------------------------------+
395 | Task : Stops Cyclic acquisition |
397 +----------------------------------------------------------------------------+
398 | Input Parameters : struct comedi_device *dev |
399 | struct comedi_subdevice *s |
401 +----------------------------------------------------------------------------+
402 | Return Value :0 |
404 +----------------------------------------------------------------------------+
407 int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s)
409 /* Disable A2P Fifo write and AMWEN signal */
410 outw(0, devpriv->i_IobaseAddon + 4);
412 /* Disable Bus Master ADD ON */
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);
418 /* Disable BUS Master PCI */
419 outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
421 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
422 * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
424 /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
425 * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
427 /* Disable ext trigger */
428 i_APCI3120_ExttrigDisable(dev);
430 devpriv->us_OutputRegister = 0;
431 /* stop counters */
432 outw(devpriv->
433 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
434 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
436 outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
438 /* DISABLE_ALL_INTERRUPT */
439 outb(APCI3120_DISABLE_ALL_INTERRUPT,
440 dev->iobase + APCI3120_WRITE_MODE_SELECT);
441 /* Flush FIFO */
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;
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;
459 +----------------------------------------------------------------------------+
460 | Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
461 | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) |
463 +----------------------------------------------------------------------------+
464 | Task : Test validity for a command for cyclic anlog input |
465 | acquisition |
467 +----------------------------------------------------------------------------+
468 | Input Parameters : struct comedi_device *dev |
469 | struct comedi_subdevice *s |
470 | struct comedi_cmd *cmd |
471 +----------------------------------------------------------------------------+
472 | Return Value :0 |
474 +----------------------------------------------------------------------------+
477 int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
478 struct comedi_cmd *cmd)
480 int err = 0;
481 int tmp; /* divisor1,divisor2; */
483 /* step 1: make sure trigger sources are trivially valid */
485 tmp = cmd->start_src;
486 cmd->start_src &= TRIG_NOW | TRIG_EXT;
487 if (!cmd->start_src || tmp != cmd->start_src)
488 err++;
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++;
495 tmp = cmd->convert_src;
496 cmd->convert_src &= TRIG_TIMER;
497 if (!cmd->convert_src || tmp != cmd->convert_src)
498 err++;
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++;
505 tmp = cmd->stop_src;
506 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
507 if (!cmd->stop_src || tmp != cmd->stop_src)
508 err++;
510 if (err)
511 return 1;
513 /* step 2: make sure trigger sources are unique and mutually compatible */
515 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
516 err++;
518 if (cmd->scan_begin_src != TRIG_TIMER &&
519 cmd->scan_begin_src != TRIG_FOLLOW)
520 err++;
522 if (cmd->convert_src != TRIG_TIMER)
523 err++;
525 if (cmd->scan_end_src != TRIG_COUNT) {
526 cmd->scan_end_src = TRIG_COUNT;
527 err++;
530 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
531 err++;
533 if (err)
534 return 2;
536 /* step 3: make sure arguments are trivially compatible */
538 if (cmd->start_arg != 0) {
539 cmd->start_arg = 0;
540 err++;
543 if (cmd->scan_begin_src == TRIG_TIMER) { /* Test Delay timing */
544 if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
545 cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
546 err++;
550 if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */
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++;
559 } else {
560 if (cmd->convert_arg <
561 this_board->ui_MinAcquisitiontimeNs) {
562 cmd->convert_arg =
563 this_board->ui_MinAcquisitiontimeNs;
564 err++;
570 if (!cmd->chanlist_len) {
571 cmd->chanlist_len = 1;
572 err++;
574 if (cmd->chanlist_len > this_board->i_AiChannelList) {
575 cmd->chanlist_len = this_board->i_AiChannelList;
576 err++;
578 if (cmd->stop_src == TRIG_COUNT) {
579 if (!cmd->stop_arg) {
580 cmd->stop_arg = 1;
581 err++;
583 } else { /* TRIG_NONE */
584 if (cmd->stop_arg != 0) {
585 cmd->stop_arg = 0;
586 err++;
590 if (err)
591 return 3;
593 /* step 4: fix up any arguments */
595 if (cmd->convert_src == TRIG_TIMER) {
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++;
606 if (err)
607 return 4;
609 return 0;
613 +----------------------------------------------------------------------------+
614 | Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, |
615 | struct comedi_subdevice *s) |
617 +----------------------------------------------------------------------------+
618 | Task : Does asynchronous acquisition |
619 | Determines the mode 1 or 2. |
621 +----------------------------------------------------------------------------+
622 | Input Parameters : struct comedi_device *dev |
623 | struct comedi_subdevice *s |
625 +----------------------------------------------------------------------------+
626 | Return Value : |
628 +----------------------------------------------------------------------------+
631 int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s)
633 struct comedi_cmd *cmd = &s->async->cmd;
635 /* loading private structure with cmd structure inputs */
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;
641 /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */
642 devpriv->AiData = s->async->prealloc_buf;
643 /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
644 devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
646 if (cmd->stop_src == TRIG_COUNT)
647 devpriv->ui_AiNbrofScans = cmd->stop_arg;
648 else
649 devpriv->ui_AiNbrofScans = 0;
651 devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
652 devpriv->ui_AiTimer1 = 0;
653 if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
654 devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
655 /* stopped using cancel */
657 if (cmd->start_src == TRIG_EXT)
658 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
659 else
660 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
662 if (cmd->scan_begin_src == TRIG_FOLLOW) {
663 /* mode 1 or 3 */
664 if (cmd->convert_src == TRIG_TIMER) {
665 /* mode 1 */
667 devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
668 /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
669 return i_APCI3120_CyclicAnalogInput(1, dev, s);
673 if ((cmd->scan_begin_src == TRIG_TIMER)
674 && (cmd->convert_src == TRIG_TIMER)) {
675 /* mode 2 */
676 devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
677 devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
678 /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
679 return i_APCI3120_CyclicAnalogInput(2, dev, s);
681 return -1;
685 +----------------------------------------------------------------------------+
686 | Function name : int i_APCI3120_CyclicAnalogInput(int mode, |
687 | struct comedi_device * dev,struct comedi_subdevice * s) |
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. |
694 +----------------------------------------------------------------------------+
695 | Input Parameters : |
698 +----------------------------------------------------------------------------+
699 | Return Value : |
701 +----------------------------------------------------------------------------+
704 int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
705 struct comedi_subdevice *s)
707 unsigned char b_Tmp;
708 unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
709 0, dmalen1 = 0, ui_TimerValue2 =
710 0, ui_TimerValue0, ui_ConvertTiming;
711 unsigned short us_TmpValue;
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 */
717 /*******************/
718 /* Resets the FIFO */
719 /*******************/
720 inb(dev->iobase + APCI3120_RESET_FIFO);
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 */
726 /***************************/
727 /* Acquisition initialized */
728 /***************************/
729 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
730 devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
731 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
733 /* clear software registers */
734 devpriv->b_TimerSelectMode = 0;
735 devpriv->us_OutputRegister = 0;
736 devpriv->b_ModeSelectRegister = 0;
737 /* devpriv->b_DigitalOutputRegister=0; */
739 /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
741 /****************************/
742 /* Clear Timer Write TC int */
743 /****************************/
744 outl(APCI3120_CLEAR_WRITE_TC_INT,
745 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
747 /************************************/
748 /* Clears the timer status register */
749 /************************************/
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 */
756 /**************************/
757 /* Disables All Timer */
758 /* Sets PR and PA to 0 */
759 /**************************/
760 devpriv->us_OutputRegister = devpriv->us_OutputRegister &
761 APCI3120_DISABLE_TIMER0 &
762 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
764 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
766 /*******************/
767 /* Resets the FIFO */
768 /*******************/
769 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
770 inb(devpriv->iobase + APCI3120_RESET_FIFO);
771 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
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;
779 /* value for timer2 minus -2 has to be done .....dunno y?? */
780 ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
781 ui_ConvertTiming = devpriv->ui_AiTimer0;
783 if (mode == 2)
784 ui_DelayTiming = devpriv->ui_AiTimer1;
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;
793 us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
794 /*** EL241003 : add this section in comment because floats must not be used
795 if((us_TmpValue & 0x00B0)==0x00B0)
797 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
798 ui_TimerValue0=(unsigned int)f_ConvertValue;
799 if (mode==2)
801 f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
802 ui_TimerValue1 = (unsigned int) f_DelayValue;
805 else
807 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
808 ui_TimerValue0=(unsigned int)f_ConvertValue;
809 if (mode == 2)
811 f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
812 ui_TimerValue1 = (unsigned int) f_DelayValue;
815 ***********************************************************************************************/
816 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
817 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
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;
823 if (mode == 2) {
824 ui_DelayTiming = ui_DelayTiming / 1000;
825 ui_TimerValue1 = ui_DelayTiming * 2 - 200;
826 ui_TimerValue1 = ui_TimerValue1 / 100;
828 } else {
829 ui_ConvertTiming = ui_ConvertTiming / 1000;
830 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
831 ui_TimerValue0 = ui_TimerValue0 / 10000;
833 if (mode == 2) {
834 ui_DelayTiming = ui_DelayTiming / 1000;
835 ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
836 ui_TimerValue1 = ui_TimerValue1 / 1000000;
839 /*** EL241003 End ******************************************************************************/
841 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
842 i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
843 switch (mode) {
844 case 1:
845 /* init timer0 in mode 2 */
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);
852 /* Select Timer 0 */
853 b_Tmp = ((devpriv->
854 b_DigitalOutputRegister) & 0xF0) |
855 APCI3120_SELECT_TIMER_0_WORD;
856 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
857 /* Set the convertion time */
858 outw(((unsigned short) ui_TimerValue0),
859 dev->iobase + APCI3120_TIMER_VALUE);
860 break;
862 case 2:
863 /* init timer1 in mode 2 */
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);
870 /* Select Timer 1 */
871 b_Tmp = ((devpriv->
872 b_DigitalOutputRegister) & 0xF0) |
873 APCI3120_SELECT_TIMER_1_WORD;
874 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
875 /* Set the convertion time */
876 outw(((unsigned short) ui_TimerValue1),
877 dev->iobase + APCI3120_TIMER_VALUE);
879 /* init timer0 in mode 2 */
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);
886 /* Select Timer 0 */
887 b_Tmp = ((devpriv->
888 b_DigitalOutputRegister) & 0xF0) |
889 APCI3120_SELECT_TIMER_0_WORD;
890 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
892 /* Set the convertion time */
893 outw(((unsigned short) ui_TimerValue0),
894 dev->iobase + APCI3120_TIMER_VALUE);
895 break;
898 /* ##########common for all modes################# */
900 /***********************/
901 /* Clears the SCAN bit */
902 /***********************/
904 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
905 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
907 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
908 APCI3120_DISABLE_SCAN;
909 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
911 outb(devpriv->b_ModeSelectRegister,
912 dev->iobase + APCI3120_WRITE_MODE_SELECT);
914 /* If DMA is disabled */
915 if (devpriv->us_UseDma == APCI3120_DISABLE) {
916 /* disable EOC and enable EOS */
917 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
918 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
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);
927 if (!devpriv->b_AiContinuous) {
929 * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
930 * disable it (Set Bit D14 to 0)
932 devpriv->us_OutputRegister =
933 devpriv->
934 us_OutputRegister & APCI3120_DISABLE_TIMER2;
935 outw(devpriv->us_OutputRegister,
936 dev->iobase + APCI3120_WR_ADDRESS);
938 /* DISABLE TIMER intERRUPT */
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);
946 /* (1) Init timer 2 in mode 0 and write timer value */
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);
954 /* Writing LOW unsigned short */
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);
962 /* Writing HIGH unsigned short */
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);
970 /* (2) Reset FC_TIMER BIT Clearing timer status register */
971 inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
972 /* enable timer counter and disable watch dog */
973 devpriv->b_ModeSelectRegister =
974 (devpriv->
975 b_ModeSelectRegister |
976 APCI3120_ENABLE_TIMER_COUNTER) &
977 APCI3120_DISABLE_WATCHDOG;
978 /* select EOS clock input for timer 2 */
979 devpriv->b_ModeSelectRegister =
980 devpriv->
981 b_ModeSelectRegister |
982 APCI3120_TIMER2_SELECT_EOS;
983 /* Enable timer2 interrupt */
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;
993 } else {
994 /* If DMA Enabled */
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 */
999 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1001 /************************************/
1002 /* Disables the EOC, EOS interrupt */
1003 /************************************/
1004 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1005 APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1007 outb(devpriv->b_ModeSelectRegister,
1008 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1010 dmalen0 = devpriv->ui_DmaBufferSize[0];
1011 dmalen1 = devpriv->ui_DmaBufferSize[1];
1013 if (!devpriv->b_AiContinuous) {
1015 if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
1016 dmalen0 =
1017 devpriv->ui_AiNbrofScans *
1018 devpriv->ui_AiScanLength * 2;
1019 } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
1020 dmalen1 =
1021 devpriv->ui_AiNbrofScans *
1022 devpriv->ui_AiScanLength * 2 - dmalen0;
1025 if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
1026 /* don't we want wake up every scan? */
1027 if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
1028 dmalen0 = devpriv->ui_AiScanLength * 2;
1029 if (devpriv->ui_AiScanLength & 1)
1030 dmalen0 += 2;
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;
1039 } else { /* isn't output buff smaller that our DMA buff? */
1040 if (dmalen0 > (devpriv->ui_AiDataLength))
1041 dmalen0 = devpriv->ui_AiDataLength;
1042 if (dmalen1 > (devpriv->ui_AiDataLength))
1043 dmalen1 = devpriv->ui_AiDataLength;
1045 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1046 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1048 /* Initialize DMA */
1051 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1052 * register 1
1054 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1055 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1057 /* changed since 16 bit interface for add on */
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);
1065 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1066 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1067 devpriv->i_IobaseAddon + 2);
1070 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1071 * driver
1073 outw(0x1000, devpriv->i_IobaseAddon + 2);
1074 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1076 /* 2 No change */
1077 /* A2P FIFO MANAGEMENT */
1078 /* A2P fifo reset & transfer control enable */
1080 /***********************/
1081 /* A2P FIFO MANAGEMENT */
1082 /***********************/
1083 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1084 APCI3120_AMCC_OP_MCSR);
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
1093 /* DMA Start Address Low */
1094 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1095 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1096 devpriv->i_IobaseAddon + 2);
1098 /*************************/
1099 /* DMA Start Address High */
1100 /*************************/
1101 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1102 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1103 devpriv->i_IobaseAddon + 2);
1107 * amount of bytes to be transfered set transfer count used ADDON
1108 * MWTC register commented testing
1109 * outl(devpriv->ui_DmaBufferUsesize[0],
1110 * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1113 /**************************/
1114 /* Nbr of acquisition LOW */
1115 /**************************/
1116 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1117 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1118 devpriv->i_IobaseAddon + 2);
1120 /***************************/
1121 /* Nbr of acquisition HIGH */
1122 /***************************/
1123 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1124 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1125 devpriv->i_IobaseAddon + 2);
1129 * To configure A2P FIFO testing outl(
1130 * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1133 /******************/
1134 /* A2P FIFO RESET */
1135 /******************/
1137 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1138 * driver
1140 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1141 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1145 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1146 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
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 */
1155 * initialise end of dma interrupt AINT_WRITE_COMPL =
1156 * ENABLE_WRITE_TC_INT(ADDI)
1158 /***************************************************/
1159 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1160 /***************************************************/
1161 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1162 APCI3120_ENABLE_WRITE_TC_INT),
1163 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1165 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1166 /******************************************/
1167 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1168 /******************************************/
1169 outw(3, devpriv->i_IobaseAddon + 4);
1170 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1172 /******************/
1173 /* A2P FIFO RESET */
1174 /******************/
1175 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1176 outl(0x04000000UL,
1177 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1178 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1181 if ((devpriv->us_UseDma == APCI3120_DISABLE)
1182 && !devpriv->b_AiContinuous) {
1183 /* set gate 2 to start conversion */
1184 devpriv->us_OutputRegister =
1185 devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1186 outw(devpriv->us_OutputRegister,
1187 dev->iobase + APCI3120_WR_ADDRESS);
1190 switch (mode) {
1191 case 1:
1192 /* set gate 0 to start conversion */
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:
1199 /* set gate 0 and gate 1 */
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;
1210 return 0;
1215 +----------------------------------------------------------------------------+
1216 | intERNAL FUNCTIONS |
1217 +----------------------------------------------------------------------------+
1221 +----------------------------------------------------------------------------+
1222 | Function name : int i_APCI3120_Reset(struct comedi_device *dev) |
1225 +----------------------------------------------------------------------------+
1226 | Task : Hardware reset function |
1228 +----------------------------------------------------------------------------+
1229 | Input Parameters : struct comedi_device *dev |
1232 +----------------------------------------------------------------------------+
1233 | Return Value : |
1235 +----------------------------------------------------------------------------+
1238 int i_APCI3120_Reset(struct comedi_device *dev)
1240 unsigned int i;
1241 unsigned short us_TmpValue;
1243 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1244 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1245 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1246 devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
1247 devpriv->b_OutputMemoryStatus = 0;
1249 /* variables used in timer subdevice */
1250 devpriv->b_Timer2Mode = 0;
1251 devpriv->b_Timer2Interrupt = 0;
1252 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
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);
1259 /* Disables all counters, ext trigger and clears PA, PR */
1260 devpriv->us_OutputRegister = 0;
1261 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
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)
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 */
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 */
1277 /* Reset digital output to L0W */
1279 /* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
1280 udelay(10);
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 */
1286 /* code to reset the RAM sequence */
1287 for (i = 0; i < 16; i++) {
1288 us_TmpValue = i << 8; /* select the location */
1289 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
1291 return 0;
1295 +----------------------------------------------------------------------------+
1296 | Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, |
1297 | struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
1298 | ,char check) |
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. |
1306 +----------------------------------------------------------------------------+
1307 | Input Parameters : struct comedi_device * dev |
1308 | struct comedi_subdevice * s |
1309 | int n_chan |
1310 unsigned int *chanlist
1311 char check
1312 +----------------------------------------------------------------------------+
1313 | Return Value : |
1315 +----------------------------------------------------------------------------+
1318 int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s,
1319 int n_chan, unsigned int *chanlist, char check)
1321 unsigned int i; /* , differencial=0, bipolar=0; */
1322 unsigned int gain;
1323 unsigned short us_TmpValue;
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;
1331 /* All is ok, so we can setup channel/range list */
1332 if (check)
1333 return 1;
1335 /* Code to set the PA and PR...Here it set PA to 0.. */
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);
1341 for (i = 0; i < n_chan; i++) {
1342 /* store range list to card */
1343 us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
1345 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
1346 us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
1347 else
1348 us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
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.... */
1353 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
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);
1360 return 1; /* we can serve this with scan logic */
1364 +----------------------------------------------------------------------------+
1365 | Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) |
1368 +----------------------------------------------------------------------------+
1369 | Task : Enable the external trigger |
1371 +----------------------------------------------------------------------------+
1372 | Input Parameters : struct comedi_device * dev |
1375 +----------------------------------------------------------------------------+
1376 | Return Value : 0 |
1378 +----------------------------------------------------------------------------+
1381 int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
1384 devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
1385 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1386 return 0;
1390 +----------------------------------------------------------------------------+
1391 | Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) |
1393 +----------------------------------------------------------------------------+
1394 | Task : Disables the external trigger |
1396 +----------------------------------------------------------------------------+
1397 | Input Parameters : struct comedi_device * dev |
1400 +----------------------------------------------------------------------------+
1401 | Return Value : 0 |
1403 +----------------------------------------------------------------------------+
1406 int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
1408 devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
1409 outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
1410 return 0;
1414 +----------------------------------------------------------------------------+
1415 | intERRUPT FUNCTIONS |
1416 +----------------------------------------------------------------------------+
1420 +----------------------------------------------------------------------------+
1421 | Function name : void v_APCI3120_Interrupt(int irq, void *d) |
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 |
1430 +----------------------------------------------------------------------------+
1431 | Input Parameters : int irq |
1432 | void *d |
1434 +----------------------------------------------------------------------------+
1435 | Return Value : void |
1437 +----------------------------------------------------------------------------+
1440 void v_APCI3120_Interrupt(int irq, void *d)
1442 struct comedi_device *dev = d;
1443 unsigned short int_daq;
1445 unsigned int int_amcc, ui_Check, i;
1446 unsigned short us_TmpValue;
1447 unsigned char b_DummyRead;
1449 struct comedi_subdevice *s = dev->subdevices + 0;
1450 ui_Check = 1;
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 */
1455 if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1456 comedi_error(dev, "IRQ from unknown source");
1457 return;
1460 outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */
1462 int_daq = (int_daq >> 12) & 0xF;
1464 if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1465 /* Disable ext trigger */
1466 i_APCI3120_ExttrigDisable(dev);
1467 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1469 /* clear the timer 2 interrupt */
1470 inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
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!");
1477 /* Ckeck if EOC interrupt */
1478 if (((int_daq & 0x8) == 0)
1479 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1480 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1482 /* Read the AI Value */
1484 devpriv->ui_AiReadData[0] =
1485 (unsigned int) inw(devpriv->iobase + 0);
1486 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1487 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
1488 } else {
1489 /* Disable EOC Interrupt */
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);
1499 /* Check If EOS interrupt */
1500 if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1502 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
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] =
1521 (unsigned int) us_TmpValue;
1523 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1524 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1526 send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
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);
1536 devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */
1537 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1541 /* Timer2 interrupt */
1542 if (int_daq & 0x1) {
1544 switch (devpriv->b_Timer2Mode) {
1545 case APCI3120_COUNTER:
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);
1554 /* stop timer 2 */
1555 devpriv->us_OutputRegister =
1556 devpriv->
1557 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1558 outw(devpriv->us_OutputRegister,
1559 dev->iobase + APCI3120_WR_ADDRESS);
1561 /* stop timer 0 and timer 1 */
1562 i_APCI3120_StopCyclicAcquisition(dev, s);
1563 devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
1565 /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1566 s->async->events |= COMEDI_CB_EOA;
1567 comedi_event(dev, s);
1569 break;
1571 case APCI3120_TIMER:
1573 /* Send a signal to from kernel to user space */
1574 send_sig(SIGIO, devpriv->tsk_Current, 0);
1575 break;
1577 case APCI3120_WATCHDOG:
1579 /* Send a signal to from kernel to user space */
1580 send_sig(SIGIO, devpriv->tsk_Current, 0);
1581 break;
1583 default:
1585 /* disable Timer Interrupt */
1587 devpriv->b_ModeSelectRegister =
1588 devpriv->
1589 b_ModeSelectRegister &
1590 APCI3120_DISABLE_TIMER_INT;
1592 outb(devpriv->b_ModeSelectRegister,
1593 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1597 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1601 if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1602 if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
1604 /****************************/
1605 /* Clear Timer Write TC int */
1606 /****************************/
1608 outl(APCI3120_CLEAR_WRITE_TC_INT,
1609 devpriv->i_IobaseAmcc +
1610 APCI3120_AMCC_OP_REG_INTCSR);
1612 /************************************/
1613 /* Clears the timer status register */
1614 /************************************/
1615 inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1616 v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
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);
1627 return;
1631 +----------------------------------------------------------------------------+
1632 | Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) |
1635 +----------------------------------------------------------------------------+
1636 | Task : This function handles EOS interrupt. |
1637 | This function copies the acquired data(from FIFO) |
1638 | to Comedi buffer. |
1640 +----------------------------------------------------------------------------+
1641 | Input Parameters : struct comedi_device *dev |
1644 +----------------------------------------------------------------------------+
1645 | Return Value : 0 |
1647 +----------------------------------------------------------------------------+
1651 int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
1653 int n_chan, i;
1654 struct comedi_subdevice *s = dev->subdevices + 0;
1655 int err = 1;
1657 n_chan = devpriv->ui_AiNbrofChannels;
1659 s->async->events = 0;
1661 for (i = 0; i < n_chan; i++)
1662 err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
1664 s->async->events |= COMEDI_CB_EOS;
1666 if (err == 0)
1667 s->async->events |= COMEDI_CB_OVERFLOW;
1669 comedi_event(dev, s);
1671 return 0;
1675 +----------------------------------------------------------------------------+
1676 | Function name : void v_APCI3120_InterruptDma(int irq, void *d) |
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. |
1684 +----------------------------------------------------------------------------+
1685 | Input Parameters : int irq, void *d |
1687 +----------------------------------------------------------------------------+
1688 | Return Value : void |
1690 +----------------------------------------------------------------------------+
1693 void v_APCI3120_InterruptDma(int irq, void *d)
1695 struct comedi_device *dev = d;
1696 struct comedi_subdevice *s = dev->subdevices + 0;
1697 unsigned int next_dma_buf, samplesinbuf;
1698 unsigned long low_word, high_word, var;
1700 unsigned int ui_Tmp;
1701 samplesinbuf =
1702 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1703 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1705 if (samplesinbuf <
1706 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1707 comedi_error(dev, "Interrupted DMA transfer!");
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;
1714 return;
1716 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
1717 if (devpriv->b_DmaDoubleBuffer) {
1718 /* switch DMA buffers if is used double buffering */
1719 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1721 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1722 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1724 /* changed since 16 bit interface for add on */
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);
1729 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */
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;
1736 /* DMA Start Address Low */
1737 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1738 outw(low_word, devpriv->i_IobaseAddon + 2);
1740 /* DMA Start Address High */
1741 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1742 outw(high_word, devpriv->i_IobaseAddon + 2);
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;
1749 /* Nbr of acquisition LOW */
1750 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1751 outw(low_word, devpriv->i_IobaseAddon + 2);
1753 /* Nbr of acquisition HIGH */
1754 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1755 outw(high_word, devpriv->i_IobaseAddon + 2);
1758 * To configure A2P FIFO
1759 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1760 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1762 outw(3, devpriv->i_IobaseAddon + 4);
1763 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1764 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1765 APCI3120_ENABLE_WRITE_TC_INT),
1766 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1769 if (samplesinbuf) {
1770 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1771 devpriv->ul_DmaBufferVirtual[devpriv->
1772 ui_DmaActualBuffer], samplesinbuf);
1774 if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
1775 s->async->events |= COMEDI_CB_EOS;
1776 comedi_event(dev, s);
1779 if (!devpriv->b_AiContinuous)
1780 if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
1781 /* all data sampled */
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;
1789 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
1790 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1791 } else {
1793 * restart DMA if is not used double buffering
1794 * ADDED REINITIALISE THE DMA
1796 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1797 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1799 /* changed since 16 bit interface for add on */
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);
1804 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
1806 * A2P FIFO MANAGEMENT
1807 * A2P fifo reset & transfer control enable
1809 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1810 devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
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);
1821 var = devpriv->ui_DmaBufferUsesize[0];
1822 low_word = var & 0xffff; /* changed */
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);
1831 * To configure A2P FIFO
1832 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1833 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1835 outw(3, devpriv->i_IobaseAddon + 4);
1836 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1837 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1838 APCI3120_ENABLE_WRITE_TC_INT),
1839 devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1844 +----------------------------------------------------------------------------+
1845 | Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
1846 |*dev,struct comedi_subdevice *s,short *dma,short *data,int n) |
1848 +----------------------------------------------------------------------------+
1849 | Task : This function copies the data from DMA buffer to the |
1850 | Comedi buffer |
1852 +----------------------------------------------------------------------------+
1853 | Input Parameters : struct comedi_device *dev |
1854 | struct comedi_subdevice *s |
1855 | short *dma |
1856 | short *data,int n |
1857 +----------------------------------------------------------------------------+
1858 | Return Value : void |
1860 +----------------------------------------------------------------------------+
1863 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1864 struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples)
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;
1871 cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1875 +----------------------------------------------------------------------------+
1876 | TIMER SUBDEVICE |
1877 +----------------------------------------------------------------------------+
1881 +----------------------------------------------------------------------------+
1882 | Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, |
1883 | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
1885 +----------------------------------------------------------------------------+
1886 | Task :Configure Timer 2 |
1888 +----------------------------------------------------------------------------+
1889 | Input Parameters : struct comedi_device *dev |
1890 | struct comedi_subdevice *s |
1891 | struct comedi_insn *insn |
1892 | unsigned int *data |
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 |
1899 +----------------------------------------------------------------------------+
1900 | Return Value : |
1902 +----------------------------------------------------------------------------+
1905 int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s,
1906 struct comedi_insn *insn, unsigned int *data)
1909 unsigned int ui_Timervalue2;
1910 unsigned short us_TmpValue;
1911 unsigned char b_Tmp;
1913 if (!data[1])
1914 comedi_error(dev, "config:No timer constant !");
1916 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
1918 ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
1920 /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
1921 us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
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
1927 if ((us_TmpValue & 0x00B0) == 0x00B0
1928 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1929 /* Calculate the time value to set in the timer */
1930 ui_Timervalue2 = ui_Timervalue2 / 50;
1931 } else {
1932 /* Calculate the time value to set in the timer */
1933 ui_Timervalue2 = ui_Timervalue2 / 70;
1936 /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1937 devpriv->us_OutputRegister =
1938 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1939 outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1941 /* Disable TIMER Interrupt */
1942 devpriv->b_ModeSelectRegister =
1943 devpriv->
1944 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1946 /* Disable Eoc and Eos Interrupts */
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);
1953 if (data[0] == APCI3120_TIMER) { /* initialize timer */
1954 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1955 * APCI3120_ENABLE_TIMER_INT; */
1957 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1959 /* Set the Timer 2 in mode 2(Timer) */
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);
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)
1974 /* Writing LOW unsigned short */
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);
1982 /* Writing HIGH unsigned short */
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);
1989 /* timer2 in Timer mode enabled */
1990 devpriv->b_Timer2Mode = APCI3120_TIMER;
1992 } else { /* Initialize Watch dog */
1994 /* Set the Timer 2 in mode 5(Watchdog) */
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);
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)
2010 /* Writing LOW unsigned short */
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);
2018 /* Writing HIGH unsigned short */
2019 b_Tmp = ((devpriv->
2020 b_DigitalOutputRegister) & 0xF0) |
2021 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2022 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2024 outw(HIWORD(ui_Timervalue2),
2025 devpriv->iobase + APCI3120_TIMER_VALUE);
2026 /* watchdog enabled */
2027 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
2031 return insn->n;
2036 +----------------------------------------------------------------------------+
2037 | Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, |
2038 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2040 +----------------------------------------------------------------------------+
2041 | Task : To start and stop the timer |
2042 +----------------------------------------------------------------------------+
2043 | Input Parameters : struct comedi_device *dev |
2044 | struct comedi_subdevice *s |
2045 | struct comedi_insn *insn |
2046 | unsigned int *data |
2048 | data[0] = 1 (start) |
2049 | data[0] = 0 (stop ) |
2050 | data[0] = 2 (write new value) |
2051 | data[1]= new value |
2053 | devpriv->b_Timer2Mode = 0 DISABLE |
2054 | 1 Timer |
2055 | 2 Watch dog |
2057 +----------------------------------------------------------------------------+
2058 | Return Value : |
2060 +----------------------------------------------------------------------------+
2063 int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2064 struct comedi_insn *insn, unsigned int *data)
2067 unsigned int ui_Timervalue2 = 0;
2068 unsigned short us_TmpValue;
2069 unsigned char b_Tmp;
2071 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2072 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2073 comedi_error(dev, "\nwrite:timer2 not configured ");
2074 return -EINVAL;
2077 if (data[0] == 2) { /* write new value */
2078 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2079 comedi_error(dev,
2080 "write :timer2 not configured in TIMER MODE");
2081 return -EINVAL;
2084 if (data[1])
2085 ui_Timervalue2 = data[1];
2086 else
2087 ui_Timervalue2 = 0;
2090 /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
2092 switch (data[0]) {
2093 case APCI3120_START:
2095 /* Reset FC_TIMER BIT */
2096 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2097 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
2098 /* Enable Timer */
2099 devpriv->b_ModeSelectRegister =
2100 devpriv->b_ModeSelectRegister & 0x0B;
2101 } else { /* start watch dog */
2102 /* Enable WatchDog */
2103 devpriv->b_ModeSelectRegister =
2104 (devpriv->
2105 b_ModeSelectRegister & 0x0B) |
2106 APCI3120_ENABLE_WATCHDOG;
2109 /* enable disable interrupt */
2110 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
2112 devpriv->b_ModeSelectRegister =
2113 devpriv->
2114 b_ModeSelectRegister |
2115 APCI3120_ENABLE_TIMER_INT;
2116 /* save the task structure to pass info to user */
2117 devpriv->tsk_Current = current;
2118 } else {
2120 devpriv->b_ModeSelectRegister =
2121 devpriv->
2122 b_ModeSelectRegister &
2123 APCI3120_DISABLE_TIMER_INT;
2125 outb(devpriv->b_ModeSelectRegister,
2126 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2128 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
2129 /* For Timer mode is Gate2 must be activated **timer started */
2130 devpriv->us_OutputRegister =
2131 devpriv->
2132 us_OutputRegister | APCI3120_ENABLE_TIMER2;
2133 outw(devpriv->us_OutputRegister,
2134 devpriv->iobase + APCI3120_WR_ADDRESS);
2137 break;
2139 case APCI3120_STOP:
2140 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2141 /* Disable timer */
2142 devpriv->b_ModeSelectRegister =
2143 devpriv->
2144 b_ModeSelectRegister &
2145 APCI3120_DISABLE_TIMER_COUNTER;
2146 } else {
2147 /* Disable WatchDog */
2148 devpriv->b_ModeSelectRegister =
2149 devpriv->
2150 b_ModeSelectRegister &
2151 APCI3120_DISABLE_WATCHDOG;
2153 /* Disable timer interrupt */
2154 devpriv->b_ModeSelectRegister =
2155 devpriv->
2156 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
2158 /* Write above states to register */
2159 outb(devpriv->b_ModeSelectRegister,
2160 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
2162 /* Reset Gate 2 */
2163 devpriv->us_OutputRegister =
2164 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
2165 outw(devpriv->us_OutputRegister,
2166 devpriv->iobase + APCI3120_WR_ADDRESS);
2168 /* Reset FC_TIMER BIT */
2169 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2171 /* Disable timer */
2172 /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
2174 break;
2176 case 2: /* write new value to Timer */
2177 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
2178 comedi_error(dev,
2179 "write :timer2 not configured in TIMER MODE");
2180 return -EINVAL;
2182 /* ui_Timervalue2=data[1]; // passed as argument */
2183 us_TmpValue =
2184 (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
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
2190 if ((us_TmpValue & 0x00B0) == 0x00B0
2191 || !strcmp(this_board->pc_DriverName, "apci3001")) {
2192 /* Calculate the time value to set in the timer */
2193 ui_Timervalue2 = ui_Timervalue2 / 50;
2194 } else {
2195 /* Calculate the time value to set in the timer */
2196 ui_Timervalue2 = ui_Timervalue2 / 70;
2198 /* Writing LOW unsigned short */
2199 b_Tmp = ((devpriv->
2200 b_DigitalOutputRegister) & 0xF0) |
2201 APCI3120_SELECT_TIMER_2_LOW_WORD;
2202 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2204 outw(LOWORD(ui_Timervalue2),
2205 devpriv->iobase + APCI3120_TIMER_VALUE);
2207 /* Writing HIGH unsigned short */
2208 b_Tmp = ((devpriv->
2209 b_DigitalOutputRegister) & 0xF0) |
2210 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2211 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2213 outw(HIWORD(ui_Timervalue2),
2214 devpriv->iobase + APCI3120_TIMER_VALUE);
2216 break;
2217 default:
2218 return -EINVAL; /* Not a valid input */
2221 return insn->n;
2225 +----------------------------------------------------------------------------+
2226 | Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, |
2227 | struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) |
2230 +----------------------------------------------------------------------------+
2231 | Task : read the Timer value |
2232 +----------------------------------------------------------------------------+
2233 | Input Parameters : struct comedi_device *dev |
2234 | struct comedi_subdevice *s |
2235 | struct comedi_insn *insn |
2236 | unsigned int *data |
2238 +----------------------------------------------------------------------------+
2239 | Return Value : |
2240 | for Timer: data[0]= Timer constant |
2242 | for watchdog: data[0]=0 (still running) |
2243 | data[0]=1 (run down) |
2245 +----------------------------------------------------------------------------+
2247 int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s,
2248 struct comedi_insn *insn, unsigned int *data)
2250 unsigned char b_Tmp;
2251 unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2253 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2254 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2255 comedi_error(dev, "\nread:timer2 not configured ");
2258 /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
2259 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2261 /* Read the LOW unsigned short of Timer 2 register */
2262 b_Tmp = ((devpriv->
2263 b_DigitalOutputRegister) & 0xF0) |
2264 APCI3120_SELECT_TIMER_2_LOW_WORD;
2265 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2267 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2269 /* Read the HIGH unsigned short of Timer 2 register */
2270 b_Tmp = ((devpriv->
2271 b_DigitalOutputRegister) & 0xF0) |
2272 APCI3120_SELECT_TIMER_2_HIGH_WORD;
2273 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2275 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2277 /* combining both words */
2278 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2280 } else { /* Read watch dog status */
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) {
2286 /* RESET FC_TIMER BIT */
2287 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2289 data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */
2291 return insn->n;
2295 +----------------------------------------------------------------------------+
2296 | DIGITAL INPUT SUBDEVICE |
2297 +----------------------------------------------------------------------------+
2301 +----------------------------------------------------------------------------+
2302 | Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, |
2303 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2306 +----------------------------------------------------------------------------+
2307 | Task : Reads the value of the specified Digital input channel|
2309 +----------------------------------------------------------------------------+
2310 | Input Parameters : struct comedi_device *dev |
2311 | struct comedi_subdevice *s |
2312 | struct comedi_insn *insn |
2313 | unsigned int *data |
2314 +----------------------------------------------------------------------------+
2315 | Return Value : |
2317 +----------------------------------------------------------------------------+
2320 int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
2321 struct comedi_subdevice *s,
2322 struct comedi_insn *insn,
2323 unsigned int *data)
2325 unsigned int ui_Chan, ui_TmpValue;
2327 ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
2329 /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
2330 if (ui_Chan <= 3) {
2331 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
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.
2337 *data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
2338 /* return 0; */
2339 } else {
2340 /* comedi_error(dev," chan spec wrong"); */
2341 return -EINVAL; /* "sorry channel spec wrong " */
2343 return insn->n;
2348 +----------------------------------------------------------------------------+
2349 | Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
2350 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2352 +----------------------------------------------------------------------------+
2353 | Task : Reads the value of the Digital input Port i.e.4channels|
2354 | value is returned in data[0] |
2356 +----------------------------------------------------------------------------+
2357 | Input Parameters : struct comedi_device *dev |
2358 | struct comedi_subdevice *s |
2359 | struct comedi_insn *insn |
2360 | unsigned int *data |
2361 +----------------------------------------------------------------------------+
2362 | Return Value : |
2364 +----------------------------------------------------------------------------+
2366 int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
2367 struct comedi_insn *insn, unsigned int *data)
2369 unsigned int ui_TmpValue;
2370 ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
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 *****/
2376 *data = (ui_TmpValue >> 8) & 0xf;
2377 /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
2378 return insn->n;
2382 +----------------------------------------------------------------------------+
2383 | DIGITAL OUTPUT SUBDEVICE |
2384 +----------------------------------------------------------------------------+
2387 +----------------------------------------------------------------------------+
2388 | Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device |
2389 | *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2391 +----------------------------------------------------------------------------+
2392 | Task :Configure the output memory ON or OFF |
2394 +----------------------------------------------------------------------------+
2395 | Input Parameters :struct comedi_device *dev |
2396 | struct comedi_subdevice *s |
2397 | struct comedi_insn *insn |
2398 | unsigned int *data |
2399 +----------------------------------------------------------------------------+
2400 | Return Value : |
2402 +----------------------------------------------------------------------------+
2405 int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
2406 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
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;
2414 if (data[0]) {
2415 devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
2417 } else {
2418 devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
2419 devpriv->b_DigitalOutputRegister = 0;
2421 if (!devpriv->b_OutputMemoryStatus)
2422 ui_Temp = 0;
2423 /* if(!devpriv->b_OutputMemoryStatus ) */
2425 return insn->n;
2429 +----------------------------------------------------------------------------+
2430 | Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, |
2431 | struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2433 +----------------------------------------------------------------------------+
2434 | Task : write diatal output port |
2436 +----------------------------------------------------------------------------+
2437 | Input Parameters : struct comedi_device *dev |
2438 | struct comedi_subdevice *s |
2439 | struct comedi_insn *insn |
2440 | unsigned int *data |
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
2444 +----------------------------------------------------------------------------+
2445 | Return Value : |
2447 +----------------------------------------------------------------------------+
2450 int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,
2451 struct comedi_subdevice *s,
2452 struct comedi_insn *insn,
2453 unsigned int *data)
2455 if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
2457 comedi_error(dev, "Data is not valid !!! \n");
2458 return -EINVAL;
2461 switch (data[1]) {
2462 case 1:
2463 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2464 break;
2466 case 2:
2467 data[0] = data[0];
2468 break;
2469 default:
2470 printk("\nThe parameter passed is in error \n");
2471 return -EINVAL;
2472 } /* switch(data[1]) */
2473 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2475 devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
2477 return insn->n;
2482 +----------------------------------------------------------------------------+
2483 | Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
2484 |struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
2486 +----------------------------------------------------------------------------+
2487 | Task : Write digiatl output |
2489 +----------------------------------------------------------------------------+
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
2497 +----------------------------------------------------------------------------+
2498 | Return Value : |
2500 +----------------------------------------------------------------------------+
2503 int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
2504 struct comedi_subdevice *s,
2505 struct comedi_insn *insn,
2506 unsigned int *data)
2509 unsigned int ui_Temp1;
2511 unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
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;
2518 if (ui_NoOfChannel > this_board->i_NbrDoChannel - 1) {
2519 comedi_error(dev,
2520 "This board doesn't have specified channel !!! \n");
2521 return -EINVAL;
2524 switch (data[1]) {
2525 case 1:
2526 data[0] = (data[0] << ui_NoOfChannel);
2527 /* ES05 data[0]=(data[0]<<4)|ui_Temp; */
2528 data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
2529 break;
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;
2536 /* ES05 ui_Temp=ui_Temp|ui_Temp1; */
2537 devpriv->b_DigitalOutputRegister =
2538 devpriv->b_DigitalOutputRegister | ui_Temp1;
2540 data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
2541 data[0] = data[0] << 4;
2542 /* ES05 data[0]=data[0]& ui_Temp; */
2543 data[0] = data[0] & devpriv->b_DigitalOutputRegister;
2544 break;
2545 default:
2546 printk("\nThe parameter passed is in error \n");
2547 return -EINVAL;
2548 } /* switch(data[1]) */
2549 outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2551 /* ES05 ui_Temp=data[0] & 0xf0; */
2552 devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
2553 return insn->n;
2558 +----------------------------------------------------------------------------+
2559 | ANALOG OUTPUT SUBDEVICE |
2560 +----------------------------------------------------------------------------+
2564 +----------------------------------------------------------------------------+
2565 | Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
2566 |struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) |
2568 +----------------------------------------------------------------------------+
2569 | Task : Write analog output |
2571 +----------------------------------------------------------------------------+
2572 | Input Parameters : struct comedi_device *dev |
2573 | struct comedi_subdevice *s |
2574 | struct comedi_insn *insn |
2575 | unsigned int *data |
2576 +----------------------------------------------------------------------------+
2577 | Return Value : |
2579 +----------------------------------------------------------------------------+
2582 int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
2583 struct comedi_subdevice *s,
2584 struct comedi_insn *insn,
2585 unsigned int *data)
2587 unsigned int ui_Range, ui_Channel;
2588 unsigned short us_TmpValue;
2590 ui_Range = CR_RANGE(insn->chanspec);
2591 ui_Channel = CR_CHAN(insn->chanspec);
2593 /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
2594 if (ui_Range) { /* if 1 then unipolar */
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);
2605 } else { /* if 0 then bipolar */
2606 data[0] =
2607 ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2608 data[0]);
2613 * out put n values at the given channel. printk("\nwaiting for
2614 * DA_READY BIT");
2616 do { /* Waiting of DA_READY BIT */
2617 us_TmpValue =
2618 ((unsigned short) inw(devpriv->iobase +
2619 APCI3120_RD_STATUS)) & 0x0001;
2620 } while (us_TmpValue != 0x0001);
2622 if (ui_Channel <= 3)
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
2627 outw((unsigned short) data[0],
2628 devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2629 else
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
2634 outw((unsigned short) data[0],
2635 devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2637 return insn->n;