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