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