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