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