staging: comedi: addi_common.h: remove {LO, HI}WORD macros
[cascardo/linux.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 @endverbatim
19 */
20 /*
21   +-----------------------------------------------------------------------+
22   | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
23   +-----------------------------------------------------------------------+
24   | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
25   | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
26   +-----------------------------------------------------------------------+
27   | Project     : APCI-3120       | Compiler   : GCC                      |
28   | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
29   +-------------------------------+---------------------------------------+
30   | Project manager: Eric Stolz   | Date       :  02/12/2002              |
31   +-----------------------------------------------------------------------+
32   | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
33   +-----------------------------------------------------------------------+
34   |                             UPDATE'S                                  |
35   +-----------------------------------------------------------------------+
36   |   Date   |   Author  |          Description of updates                |
37   +----------+-----------+------------------------------------------------+
38   |          |           |                                                |
39   |          |           |                                                |
40   +----------+-----------+------------------------------------------------+
41 */
42
43 #include <linux/delay.h>
44
45 /*
46  * ADDON RELATED ADDITIONS
47  */
48 /* Constant */
49 #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW             0x00
50 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH            0x1200
51 #define APCI3120_A2P_FIFO_MANAGEMENT                    0x04000400L
52 #define APCI3120_AMWEN_ENABLE                           0x02
53 #define APCI3120_A2P_FIFO_WRITE_ENABLE                  0x01
54 #define APCI3120_FIFO_ADVANCE_ON_BYTE_2                 0x20000000L
55 #define APCI3120_ENABLE_WRITE_TC_INT                    0x00004000L
56 #define APCI3120_CLEAR_WRITE_TC_INT                     0x00040000L
57 #define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE       0x0
58 #define APCI3120_DISABLE_BUS_MASTER_ADD_ON              0x0
59 #define APCI3120_DISABLE_BUS_MASTER_PCI                 0x0
60
61 /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
62 #define APCI3120_ADD_ON_AGCSTS_LOW      0x3C
63 #define APCI3120_ADD_ON_AGCSTS_HIGH     (APCI3120_ADD_ON_AGCSTS_LOW + 2)
64 #define APCI3120_ADD_ON_MWAR_LOW        0x24
65 #define APCI3120_ADD_ON_MWAR_HIGH       (APCI3120_ADD_ON_MWAR_LOW + 2)
66 #define APCI3120_ADD_ON_MWTC_LOW        0x058
67 #define APCI3120_ADD_ON_MWTC_HIGH       (APCI3120_ADD_ON_MWTC_LOW + 2)
68
69 /* AMCC */
70 #define APCI3120_AMCC_OP_MCSR           0x3C
71 #define APCI3120_AMCC_OP_REG_INTCSR     0x38
72
73 /* for transfer count enable bit */
74 #define AGCSTS_TC_ENABLE        0x10000000
75
76 /* used for test on mixture of BIP/UNI ranges */
77 #define APCI3120_BIPOLAR_RANGES         4
78
79 #define APCI3120_ADDRESS_RANGE          16
80
81 #define APCI3120_DISABLE                0
82 #define APCI3120_ENABLE                 1
83
84 #define APCI3120_START                  1
85 #define APCI3120_STOP                   0
86
87 #define APCI3120_EOC_MODE               1
88 #define APCI3120_EOS_MODE               2
89 #define APCI3120_DMA_MODE               3
90
91 /* DIGITAL INPUT-OUTPUT DEFINE */
92
93 #define APCI3120_DIGITAL_OUTPUT         0x0d
94 #define APCI3120_RD_STATUS              0x02
95 #define APCI3120_RD_FIFO                0x00
96
97 /* digital output insn_write ON /OFF selection */
98 #define APCI3120_SET4DIGITALOUTPUTON    1
99 #define APCI3120_SET4DIGITALOUTPUTOFF   0
100
101 /* analog output SELECT BIT */
102 #define APCI3120_ANALOG_OP_CHANNEL_1    0x0000
103 #define APCI3120_ANALOG_OP_CHANNEL_2    0x4000
104 #define APCI3120_ANALOG_OP_CHANNEL_3    0x8000
105 #define APCI3120_ANALOG_OP_CHANNEL_4    0xc000
106 #define APCI3120_ANALOG_OP_CHANNEL_5    0x0000
107 #define APCI3120_ANALOG_OP_CHANNEL_6    0x4000
108 #define APCI3120_ANALOG_OP_CHANNEL_7    0x8000
109 #define APCI3120_ANALOG_OP_CHANNEL_8    0xc000
110
111 /* Enable external trigger bit in nWrAddress */
112 #define APCI3120_ENABLE_EXT_TRIGGER     0x8000
113
114 /* ANALOG OUTPUT AND INPUT DEFINE */
115 #define APCI3120_UNIPOLAR               0x80
116 #define APCI3120_BIPOLAR                0x00
117 #define APCI3120_ANALOG_OUTPUT_1        0x08
118 #define APCI3120_ANALOG_OUTPUT_2        0x0a
119 #define APCI3120_1_GAIN                 0x00
120 #define APCI3120_2_GAIN                 0x10
121 #define APCI3120_5_GAIN                 0x20
122 #define APCI3120_10_GAIN                0x30
123 #define APCI3120_SEQ_RAM_ADDRESS        0x06
124 #define APCI3120_RESET_FIFO             0x0c
125 #define APCI3120_TIMER_0_MODE_2         0x01
126 #define APCI3120_TIMER_0_MODE_4         0x2
127 #define APCI3120_SELECT_TIMER_0_WORD    0x00
128 #define APCI3120_ENABLE_TIMER0          0x1000
129 #define APCI3120_CLEAR_PR               0xf0ff
130 #define APCI3120_CLEAR_PA               0xfff0
131 #define APCI3120_CLEAR_PA_PR            (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
132
133 /* nWrMode_Select */
134 #define APCI3120_ENABLE_SCAN            0x8
135 #define APCI3120_DISABLE_SCAN           (~APCI3120_ENABLE_SCAN)
136 #define APCI3120_ENABLE_EOS_INT         0x2
137
138 #define APCI3120_DISABLE_EOS_INT        (~APCI3120_ENABLE_EOS_INT)
139 #define APCI3120_ENABLE_EOC_INT         0x1
140 #define APCI3120_DISABLE_EOC_INT        (~APCI3120_ENABLE_EOC_INT)
141 #define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER    \
142         (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
143 #define APCI3120_DISABLE_ALL_INTERRUPT                  \
144         (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
145
146 /* status register bits */
147 #define APCI3120_EOC                    0x8000
148 #define APCI3120_EOS                    0x2000
149
150 /* software trigger dummy register */
151 #define APCI3120_START_CONVERSION       0x02
152
153 /* TIMER DEFINE */
154 #define APCI3120_QUARTZ_A               70
155 #define APCI3120_QUARTZ_B               50
156 #define APCI3120_TIMER                  1
157 #define APCI3120_WATCHDOG               2
158 #define APCI3120_TIMER_DISABLE          0
159 #define APCI3120_TIMER_ENABLE           1
160 #define APCI3120_ENABLE_TIMER2          0x4000
161 #define APCI3120_DISABLE_TIMER2         (~APCI3120_ENABLE_TIMER2)
162 #define APCI3120_ENABLE_TIMER_INT       0x04
163 #define APCI3120_DISABLE_TIMER_INT      (~APCI3120_ENABLE_TIMER_INT)
164 #define APCI3120_WRITE_MODE_SELECT      0x0e
165 #define APCI3120_SELECT_TIMER_0_WORD    0x00
166 #define APCI3120_SELECT_TIMER_1_WORD    0x01
167 #define APCI3120_TIMER_1_MODE_2         0x4
168
169 /* $$ BIT FOR MODE IN nCsTimerCtr1 */
170 #define APCI3120_TIMER_2_MODE_0         0x0
171 #define APCI3120_TIMER_2_MODE_2         0x10
172 #define APCI3120_TIMER_2_MODE_5         0x30
173
174 /* $$ BIT FOR MODE IN nCsTimerCtr0 */
175 #define APCI3120_SELECT_TIMER_2_LOW_WORD        0x02
176 #define APCI3120_SELECT_TIMER_2_HIGH_WORD       0x03
177
178 #define APCI3120_TIMER_CRT0             0x0d
179 #define APCI3120_TIMER_CRT1             0x0c
180
181 #define APCI3120_TIMER_VALUE            0x04
182 #define APCI3120_TIMER_STATUS_REGISTER  0x0d
183 #define APCI3120_RD_STATUS              0x02
184 #define APCI3120_WR_ADDRESS             0x00
185 #define APCI3120_ENABLE_WATCHDOG        0x20
186 #define APCI3120_DISABLE_WATCHDOG       (~APCI3120_ENABLE_WATCHDOG)
187 #define APCI3120_ENABLE_TIMER_COUNTER   0x10
188 #define APCI3120_DISABLE_TIMER_COUNTER  (~APCI3120_ENABLE_TIMER_COUNTER)
189 #define APCI3120_FC_TIMER               0x1000
190 #define APCI3120_ENABLE_TIMER0          0x1000
191 #define APCI3120_ENABLE_TIMER1          0x2000
192 #define APCI3120_ENABLE_TIMER2          0x4000
193 #define APCI3120_DISABLE_TIMER0         (~APCI3120_ENABLE_TIMER0)
194 #define APCI3120_DISABLE_TIMER1         (~APCI3120_ENABLE_TIMER1)
195 #define APCI3120_DISABLE_TIMER2         (~APCI3120_ENABLE_TIMER2)
196
197 #define APCI3120_TIMER2_SELECT_EOS      0xc0
198 #define APCI3120_COUNTER                3
199 #define APCI3120_DISABLE_ALL_TIMER      (APCI3120_DISABLE_TIMER0 &      \
200                                          APCI3120_DISABLE_TIMER1 &      \
201                                          APCI3120_DISABLE_TIMER2)
202
203 #define MAX_ANALOGINPUT_CHANNELS        32
204
205 struct str_AnalogReadInformation {
206         /* EOC or EOS */
207         unsigned char b_Type;
208         /* Interrupt use or not */
209         unsigned char b_InterruptFlag;
210         /* Selection of the conversion time */
211         unsigned int ui_ConvertTiming;
212         /* Number of channel to read */
213         unsigned char b_NbrOfChannel;
214         /* Number of the channel to be read */
215         unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS];
216         /* Gain of each channel */
217         unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS];
218 };
219
220 /* ANALOG INPUT RANGE */
221 static const struct comedi_lrange range_apci3120_ai = {
222         8, {
223                 BIP_RANGE(10),
224                 BIP_RANGE(5),
225                 BIP_RANGE(2),
226                 BIP_RANGE(1),
227                 UNI_RANGE(10),
228                 UNI_RANGE(5),
229                 UNI_RANGE(2),
230                 UNI_RANGE(1)
231         }
232 };
233
234 /* ANALOG OUTPUT RANGE */
235 static const struct comedi_lrange range_apci3120_ao = {
236         2, {
237                 BIP_RANGE(10),
238                 UNI_RANGE(10)
239         }
240 };
241
242
243 /* FUNCTION DEFINITIONS */
244
245 /*
246 +----------------------------------------------------------------------------+
247 |                           ANALOG INPUT SUBDEVICE                               |
248 +----------------------------------------------------------------------------+
249 */
250
251 static int apci3120_ai_insn_config(struct comedi_device *dev,
252                                    struct comedi_subdevice *s,
253                                    struct comedi_insn *insn,
254                                    unsigned int *data)
255 {
256         const struct addi_board *this_board = comedi_board(dev);
257         struct addi_private *devpriv = dev->private;
258         unsigned int i;
259
260         if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
261                 return -1;
262
263         /*  Check for Conversion time to be added ?? */
264         devpriv->ui_EocEosConversionTime = data[2];
265
266         if (data[0] == APCI3120_EOS_MODE) {
267
268                 /* Test the number of the channel */
269                 for (i = 0; i < data[3]; i++) {
270
271                         if (CR_CHAN(data[4 + i]) >=
272                                 this_board->i_NbrAiChannel) {
273                                 printk("bad channel list\n");
274                                 return -2;
275                         }
276                 }
277
278                 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
279
280                 if (data[1])
281                         devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
282                 else
283                         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
284                 /*  Copy channel list and Range List to devpriv */
285
286                 devpriv->ui_AiNbrofChannels = data[3];
287                 for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
288                         devpriv->ui_AiChannelList[i] = data[4 + i];
289
290         } else {                        /*  EOC */
291                 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
292                 if (data[1])
293                         devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
294                 else
295                         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
296         }
297
298         return insn->n;
299 }
300
301 /*
302  * This function will first check channel list is ok or not and then
303  * initialize the sequence RAM with the polarity, Gain,Channel number.
304  * If the last argument of function "check"is 1 then it only checks
305  * the channel list is ok or not.
306  */
307 static int apci3120_setup_chan_list(struct comedi_device *dev,
308                                     struct comedi_subdevice *s,
309                                     int n_chan,
310                                     unsigned int *chanlist,
311                                     char check)
312 {
313         struct addi_private *devpriv = dev->private;
314         unsigned int i;         /* , differencial=0, bipolar=0; */
315         unsigned int gain;
316         unsigned short us_TmpValue;
317
318         /* correct channel and range number check itself comedi/range.c */
319         if (n_chan < 1) {
320                 if (!check)
321                         comedi_error(dev, "range/channel list is empty!");
322                 return 0;
323         }
324         /*  All is ok, so we can setup channel/range list */
325         if (check)
326                 return 1;
327
328         /* Code  to set the PA and PR...Here it set PA to 0.. */
329         devpriv->us_OutputRegister =
330                 devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
331         devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
332         outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
333
334         for (i = 0; i < n_chan; i++) {
335                 /*  store range list to card */
336                 us_TmpValue = CR_CHAN(chanlist[i]);     /*  get channel number; */
337
338                 if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
339                         us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff);   /*  set bipolar */
340                 else
341                         us_TmpValue |= APCI3120_UNIPOLAR;       /*  enable unipolar...... */
342
343                 gain = CR_RANGE(chanlist[i]);   /*  get gain number */
344                 us_TmpValue |= ((gain & 0x03) << 4);    /* <<4 for G0 and G1 bit in RAM */
345                 us_TmpValue |= i << 8;  /* To select the RAM LOCATION.... */
346                 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
347
348                 printk("\n Gain = %i",
349                         (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
350                 printk("\n Channel = %i", CR_CHAN(chanlist[i]));
351                 printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
352         }
353         return 1;               /*  we can serve this with scan logic */
354 }
355
356 /*
357  * Reads analog input in synchronous mode EOC and EOS is selected
358  * as per configured if no conversion time is set uses default
359  * conversion time 10 microsec.
360  */
361 static int apci3120_ai_insn_read(struct comedi_device *dev,
362                                  struct comedi_subdevice *s,
363                                  struct comedi_insn *insn,
364                                  unsigned int *data)
365 {
366         const struct addi_board *this_board = comedi_board(dev);
367         struct addi_private *devpriv = dev->private;
368         unsigned short us_ConvertTiming, us_TmpValue, i;
369         unsigned char b_Tmp;
370
371         /*  fix conversion time to 10 us */
372         if (!devpriv->ui_EocEosConversionTime) {
373                 printk("No timer0 Value using 10 us\n");
374                 us_ConvertTiming = 10;
375         } else
376                 us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000);  /*  nano to useconds */
377
378         /*  this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
379
380         /*  Clear software registers */
381         devpriv->b_TimerSelectMode = 0;
382         devpriv->b_ModeSelectRegister = 0;
383         devpriv->us_OutputRegister = 0;
384 /* devpriv->b_DigitalOutputRegister=0; */
385
386         if (insn->unused[0] == 222) {   /*  second insn read */
387                 for (i = 0; i < insn->n; i++)
388                         data[i] = devpriv->ui_AiReadData[i];
389         } else {
390                 devpriv->tsk_Current = current; /*  Save the current process task structure */
391 /*
392  * Testing if board have the new Quartz and calculate the time value
393  * to set in the timer
394  */
395
396                 us_TmpValue =
397                         (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
398
399                 /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
400                 if ((us_TmpValue & 0x00B0) == 0x00B0
401                         || !strcmp(this_board->pc_DriverName, "apci3001")) {
402                         us_ConvertTiming = (us_ConvertTiming * 2) - 2;
403                 } else {
404                         us_ConvertTiming =
405                                 ((us_ConvertTiming * 12926) / 10000) - 1;
406                 }
407
408                 us_TmpValue = (unsigned short) devpriv->b_InterruptMode;
409
410                 switch (us_TmpValue) {
411
412                 case APCI3120_EOC_MODE:
413
414 /*
415  * Testing the interrupt flag and set the EOC bit Clears the FIFO
416  */
417                         inw(devpriv->iobase + APCI3120_RESET_FIFO);
418
419                         /*  Initialize the sequence array */
420                         if (!apci3120_setup_chan_list(dev, s, 1,
421                                         &insn->chanspec, 0))
422                                 return -EINVAL;
423
424                         /* Initialize Timer 0 mode 4 */
425                         devpriv->b_TimerSelectMode =
426                                 (devpriv->
427                                 b_TimerSelectMode & 0xFC) |
428                                 APCI3120_TIMER_0_MODE_4;
429                         outb(devpriv->b_TimerSelectMode,
430                                 devpriv->iobase + APCI3120_TIMER_CRT1);
431
432                         /*  Reset the scan bit and Disables the  EOS, DMA, EOC interrupt */
433                         devpriv->b_ModeSelectRegister =
434                                 devpriv->
435                                 b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
436
437                         if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
438
439                                 /* Disables the EOS,DMA and enables the EOC interrupt */
440                                 devpriv->b_ModeSelectRegister =
441                                         (devpriv->
442                                         b_ModeSelectRegister &
443                                         APCI3120_DISABLE_EOS_INT) |
444                                         APCI3120_ENABLE_EOC_INT;
445                                 inw(devpriv->iobase);
446
447                         } else {
448                                 devpriv->b_ModeSelectRegister =
449                                         devpriv->
450                                         b_ModeSelectRegister &
451                                         APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
452                         }
453
454                         outb(devpriv->b_ModeSelectRegister,
455                                 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
456
457                         /*  Sets gate 0 */
458                         devpriv->us_OutputRegister =
459                                 (devpriv->
460                                 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
461                                 APCI3120_ENABLE_TIMER0;
462                         outw(devpriv->us_OutputRegister,
463                                 devpriv->iobase + APCI3120_WR_ADDRESS);
464
465                         /*  Select Timer 0 */
466                         b_Tmp = ((devpriv->
467                                         b_DigitalOutputRegister) & 0xF0) |
468                                 APCI3120_SELECT_TIMER_0_WORD;
469                         outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
470
471                         /* Set the conversion time */
472                         outw(us_ConvertTiming,
473                                 devpriv->iobase + APCI3120_TIMER_VALUE);
474
475                         us_TmpValue =
476                                 (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
477
478                         if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
479
480                                 do {
481                                         /*  Waiting for the end of conversion */
482                                         us_TmpValue =
483                                                 inw(devpriv->iobase +
484                                                 APCI3120_RD_STATUS);
485                                 } while ((us_TmpValue & APCI3120_EOC) ==
486                                         APCI3120_EOC);
487
488                                 /* Read the result in FIFO  and put it in insn data pointer */
489                                 us_TmpValue = inw(devpriv->iobase + 0);
490                                 *data = us_TmpValue;
491
492                                 inw(devpriv->iobase + APCI3120_RESET_FIFO);
493                         }
494
495                         break;
496
497                 case APCI3120_EOS_MODE:
498
499                         inw(devpriv->iobase);
500                         /*  Clears the FIFO */
501                         inw(devpriv->iobase + APCI3120_RESET_FIFO);
502                         /*  clear PA PR  and disable timer 0 */
503
504                         devpriv->us_OutputRegister =
505                                 (devpriv->
506                                 us_OutputRegister & APCI3120_CLEAR_PA_PR) |
507                                 APCI3120_DISABLE_TIMER0;
508
509                         outw(devpriv->us_OutputRegister,
510                                 devpriv->iobase + APCI3120_WR_ADDRESS);
511
512                         if (!apci3120_setup_chan_list(dev, s,
513                                         devpriv->ui_AiNbrofChannels,
514                                         devpriv->ui_AiChannelList, 0))
515                                 return -EINVAL;
516
517                         /* Initialize Timer 0 mode 2 */
518                         devpriv->b_TimerSelectMode =
519                                 (devpriv->
520                                 b_TimerSelectMode & 0xFC) |
521                                 APCI3120_TIMER_0_MODE_2;
522                         outb(devpriv->b_TimerSelectMode,
523                                 devpriv->iobase + APCI3120_TIMER_CRT1);
524
525                         /* Select Timer 0 */
526                         b_Tmp = ((devpriv->
527                                         b_DigitalOutputRegister) & 0xF0) |
528                                 APCI3120_SELECT_TIMER_0_WORD;
529                         outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
530
531                         /* Set the conversion time */
532                         outw(us_ConvertTiming,
533                                 devpriv->iobase + APCI3120_TIMER_VALUE);
534
535                         /* Set the scan bit */
536                         devpriv->b_ModeSelectRegister =
537                                 devpriv->
538                                 b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
539                         outb(devpriv->b_ModeSelectRegister,
540                                 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
541
542                         /* If Interrupt function is loaded */
543                         if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
544                                 /* Disables the EOC,DMA and enables the EOS interrupt */
545                                 devpriv->b_ModeSelectRegister =
546                                         (devpriv->
547                                         b_ModeSelectRegister &
548                                         APCI3120_DISABLE_EOC_INT) |
549                                         APCI3120_ENABLE_EOS_INT;
550                                 inw(devpriv->iobase);
551
552                         } else
553                                 devpriv->b_ModeSelectRegister =
554                                         devpriv->
555                                         b_ModeSelectRegister &
556                                         APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
557
558                         outb(devpriv->b_ModeSelectRegister,
559                                 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
560
561                         inw(devpriv->iobase + APCI3120_RD_STATUS);
562
563                         /* Sets gate 0 */
564
565                         devpriv->us_OutputRegister =
566                                 devpriv->
567                                 us_OutputRegister | APCI3120_ENABLE_TIMER0;
568                         outw(devpriv->us_OutputRegister,
569                                 devpriv->iobase + APCI3120_WR_ADDRESS);
570
571                         /* Start conversion */
572                         outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
573
574                         /* Waiting of end of conversion if interrupt is not installed */
575                         if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
576                                 /* Waiting the end of conversion */
577                                 do {
578                                         us_TmpValue =
579                                                 inw(devpriv->iobase +
580                                                 APCI3120_RD_STATUS);
581                                 } while ((us_TmpValue & APCI3120_EOS) !=
582                                          APCI3120_EOS);
583
584                                 for (i = 0; i < devpriv->ui_AiNbrofChannels;
585                                         i++) {
586                                         /* Read the result in FIFO and write them in shared memory */
587                                         us_TmpValue = inw(devpriv->iobase);
588                                         data[i] = (unsigned int) us_TmpValue;
589                                 }
590
591                                 devpriv->b_InterruptMode = APCI3120_EOC_MODE;   /*  Restore defaults. */
592                         }
593                         break;
594
595                 default:
596                         printk("inputs wrong\n");
597
598                 }
599                 devpriv->ui_EocEosConversionTime = 0;   /*  re initializing the variable; */
600         }
601
602         return insn->n;
603
604 }
605
606 static int apci3120_reset(struct comedi_device *dev)
607 {
608         struct addi_private *devpriv = dev->private;
609         unsigned int i;
610         unsigned short us_TmpValue;
611
612         devpriv->ai_running = 0;
613         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
614         devpriv->b_InterruptMode = APCI3120_EOC_MODE;
615         devpriv->ui_EocEosConversionTime = 0;   /*  set eoc eos conv time to 0 */
616
617         /*  variables used in timer subdevice */
618         devpriv->b_Timer2Mode = 0;
619         devpriv->b_Timer2Interrupt = 0;
620         devpriv->b_ExttrigEnable = 0;   /*  Disable ext trigger */
621
622         /* Disable all interrupts, watchdog for the anolog output */
623         devpriv->b_ModeSelectRegister = 0;
624         outb(devpriv->b_ModeSelectRegister,
625                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
626
627         /*  Disables all counters, ext trigger and clears PA, PR */
628         devpriv->us_OutputRegister = 0;
629         outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
630
631 /*
632  * Code to set the all anolog o/p channel to 0v 8191 is decimal
633  * value for zero(0 v)volt in bipolar mode(default)
634  */
635         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 1 */
636         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 2 */
637         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 3 */
638         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1);      /* channel 4 */
639
640         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 5 */
641         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 6 */
642         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 7 */
643         outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2);      /* channel 8 */
644
645         /*   Reset digital output to L0W */
646
647 /* ES05  outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
648         udelay(10);
649
650         inw(dev->iobase + 0);   /* make a dummy read */
651         inb(dev->iobase + APCI3120_RESET_FIFO); /*  flush FIFO */
652         inw(dev->iobase + APCI3120_RD_STATUS);  /*  flush A/D status register */
653
654         /* code to reset the RAM sequence */
655         for (i = 0; i < 16; i++) {
656                 us_TmpValue = i << 8;   /* select the location */
657                 outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
658         }
659         return 0;
660 }
661
662 static int apci3120_exttrig_enable(struct comedi_device *dev)
663 {
664         struct addi_private *devpriv = dev->private;
665
666         devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
667         outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
668         return 0;
669 }
670
671 static int apci3120_exttrig_disable(struct comedi_device *dev)
672 {
673         struct addi_private *devpriv = dev->private;
674
675         devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
676         outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
677         return 0;
678 }
679
680 static int apci3120_cancel(struct comedi_device *dev,
681                            struct comedi_subdevice *s)
682 {
683         struct addi_private *devpriv = dev->private;
684
685         /*  Disable A2P Fifo write and AMWEN signal */
686         outw(0, devpriv->i_IobaseAddon + 4);
687
688         /* Disable Bus Master ADD ON */
689         outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
690         outw(0, devpriv->i_IobaseAddon + 2);
691         outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
692         outw(0, devpriv->i_IobaseAddon + 2);
693
694         /* Disable BUS Master PCI */
695         outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
696
697         /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
698          * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);  stop amcc irqs */
699
700         /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
701          * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR);  stop DMA */
702
703         /* Disable ext trigger */
704         apci3120_exttrig_disable(dev);
705
706         devpriv->us_OutputRegister = 0;
707         /* stop  counters */
708         outw(devpriv->
709                 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
710                 APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
711
712         outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
713
714         /* DISABLE_ALL_INTERRUPT */
715         outb(APCI3120_DISABLE_ALL_INTERRUPT,
716                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
717         /* Flush FIFO */
718         inb(dev->iobase + APCI3120_RESET_FIFO);
719         inw(dev->iobase + APCI3120_RD_STATUS);
720         devpriv->ui_AiActualScan = 0;
721         s->async->cur_chan = 0;
722         devpriv->ui_DmaActualBuffer = 0;
723
724         devpriv->ai_running = 0;
725         devpriv->b_InterruptMode = APCI3120_EOC_MODE;
726         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
727         apci3120_reset(dev);
728         return 0;
729 }
730
731 static int apci3120_ai_cmdtest(struct comedi_device *dev,
732                                struct comedi_subdevice *s,
733                                struct comedi_cmd *cmd)
734 {
735         int err = 0;
736
737         /* Step 1 : check if triggers are trivially valid */
738
739         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
740         err |= cfc_check_trigger_src(&cmd->scan_begin_src,
741                                         TRIG_TIMER | TRIG_FOLLOW);
742         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
743         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
744         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
745
746         if (err)
747                 return 1;
748
749         /* Step 2a : make sure trigger sources are unique */
750
751         err |= cfc_check_trigger_is_unique(cmd->start_src);
752         err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
753         err |= cfc_check_trigger_is_unique(cmd->stop_src);
754
755         /* Step 2b : and mutually compatible */
756
757         if (err)
758                 return 2;
759
760         /* Step 3: check if arguments are trivially valid */
761
762         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
763
764         if (cmd->scan_begin_src == TRIG_TIMER)  /* Test Delay timing */
765                 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
766
767         if (cmd->scan_begin_src == TRIG_TIMER) {
768                 if (cmd->convert_arg)
769                         err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
770                                                          10000);
771         } else {
772                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
773         }
774
775         err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
776         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
777
778         if (cmd->stop_src == TRIG_COUNT)
779                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
780         else    /*  TRIG_NONE */
781                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
782
783         if (err)
784                 return 3;
785
786         /*  step 4: fix up any arguments */
787
788         if (cmd->scan_begin_src == TRIG_TIMER &&
789             cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
790                 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
791                 err |= -EINVAL;
792         }
793
794         if (err)
795                 return 4;
796
797         return 0;
798 }
799
800 /*
801  * This is used for analog input cyclic acquisition.
802  * Performs the command operations.
803  * If DMA is configured does DMA initialization otherwise does the
804  * acquisition with EOS interrupt.
805  */
806 static int apci3120_cyclic_ai(int mode,
807                               struct comedi_device *dev,
808                               struct comedi_subdevice *s)
809 {
810         const struct addi_board *this_board = comedi_board(dev);
811         struct addi_private *devpriv = dev->private;
812         struct comedi_cmd *cmd = &s->async->cmd;
813         unsigned char b_Tmp;
814         unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
815                 0, dmalen1 = 0, ui_TimerValue2 =
816                 0, ui_TimerValue0, ui_ConvertTiming;
817         unsigned short us_TmpValue;
818
819         /*******************/
820         /* Resets the FIFO */
821         /*******************/
822         inb(dev->iobase + APCI3120_RESET_FIFO);
823
824         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
825         /* inw(dev->iobase+APCI3120_RD_STATUS); */
826         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
827
828         devpriv->ai_running = 1;
829
830         /*  clear software  registers */
831         devpriv->b_TimerSelectMode = 0;
832         devpriv->us_OutputRegister = 0;
833         devpriv->b_ModeSelectRegister = 0;
834         /* devpriv->b_DigitalOutputRegister=0; */
835
836         /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
837
838         /****************************/
839         /* Clear Timer Write TC int */
840         /****************************/
841         outl(APCI3120_CLEAR_WRITE_TC_INT,
842                 devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
843
844         /************************************/
845         /* Clears the timer status register */
846         /************************************/
847
848         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
849         /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
850         /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
851         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
852
853         /**************************/
854         /* Disables All Timer     */
855         /* Sets PR and PA to 0    */
856         /**************************/
857         devpriv->us_OutputRegister = devpriv->us_OutputRegister &
858                 APCI3120_DISABLE_TIMER0 &
859                 APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
860
861         outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
862
863         /*******************/
864         /* Resets the FIFO */
865         /*******************/
866         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
867         inb(devpriv->iobase + APCI3120_RESET_FIFO);
868         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
869
870         devpriv->ui_AiActualScan = 0;
871         s->async->cur_chan = 0;
872         devpriv->ui_DmaActualBuffer = 0;
873
874         /*  value for timer2  minus -2 has to be done .....dunno y?? */
875         ui_TimerValue2 = cmd->stop_arg - 2;
876         ui_ConvertTiming = cmd->convert_arg;
877
878         if (mode == 2)
879                 ui_DelayTiming = cmd->scan_begin_arg;
880
881    /**********************************/
882         /* Initializes the sequence array */
883    /**********************************/
884         if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
885                         cmd->chanlist, 0))
886                 return -EINVAL;
887
888         us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
889 /*** EL241003 : add this section in comment because floats must not be used
890         if((us_TmpValue & 0x00B0)==0x00B0)
891          {
892                 f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
893                 ui_TimerValue0=(unsigned int)f_ConvertValue;
894                 if (mode==2)
895                 {
896                         f_DelayValue     = (((float)ui_DelayTiming * 0.00002) - 2);
897                         ui_TimerValue1  =   (unsigned int) f_DelayValue;
898                 }
899          }
900         else
901          {
902                 f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
903                 ui_TimerValue0=(unsigned int)f_ConvertValue;
904                 if (mode == 2)
905                 {
906                      f_DelayValue     = (((float)ui_DelayTiming * 0.000012926) - 1);
907                      ui_TimerValue1  =   (unsigned int) f_DelayValue;
908                 }
909         }
910 ***********************************************************************************************/
911 /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
912         /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
913         if ((us_TmpValue & 0x00B0) == 0x00B0
914                 || !strcmp(this_board->pc_DriverName, "apci3001")) {
915                 ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
916                 ui_TimerValue0 = ui_TimerValue0 / 1000;
917
918                 if (mode == 2) {
919                         ui_DelayTiming = ui_DelayTiming / 1000;
920                         ui_TimerValue1 = ui_DelayTiming * 2 - 200;
921                         ui_TimerValue1 = ui_TimerValue1 / 100;
922                 }
923         } else {
924                 ui_ConvertTiming = ui_ConvertTiming / 1000;
925                 ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
926                 ui_TimerValue0 = ui_TimerValue0 / 10000;
927
928                 if (mode == 2) {
929                         ui_DelayTiming = ui_DelayTiming / 1000;
930                         ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
931                         ui_TimerValue1 = ui_TimerValue1 / 1000000;
932                 }
933         }
934 /*** EL241003 End ******************************************************************************/
935
936         if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
937                 apci3120_exttrig_enable(dev);   /*  activate EXT trigger */
938         switch (mode) {
939         case 1:
940                 /*  init timer0 in mode 2 */
941                 devpriv->b_TimerSelectMode =
942                         (devpriv->
943                         b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
944                 outb(devpriv->b_TimerSelectMode,
945                         dev->iobase + APCI3120_TIMER_CRT1);
946
947                 /* Select Timer 0 */
948                 b_Tmp = ((devpriv->
949                                 b_DigitalOutputRegister) & 0xF0) |
950                         APCI3120_SELECT_TIMER_0_WORD;
951                 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
952                 /* Set the conversion time */
953                 outw(((unsigned short) ui_TimerValue0),
954                         dev->iobase + APCI3120_TIMER_VALUE);
955                 break;
956
957         case 2:
958                 /*  init timer1 in mode 2 */
959                 devpriv->b_TimerSelectMode =
960                         (devpriv->
961                         b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
962                 outb(devpriv->b_TimerSelectMode,
963                         dev->iobase + APCI3120_TIMER_CRT1);
964
965                 /* Select Timer 1 */
966                 b_Tmp = ((devpriv->
967                                 b_DigitalOutputRegister) & 0xF0) |
968                         APCI3120_SELECT_TIMER_1_WORD;
969                 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
970                 /* Set the conversion time */
971                 outw(((unsigned short) ui_TimerValue1),
972                         dev->iobase + APCI3120_TIMER_VALUE);
973
974                 /*  init timer0 in mode 2 */
975                 devpriv->b_TimerSelectMode =
976                         (devpriv->
977                         b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
978                 outb(devpriv->b_TimerSelectMode,
979                         dev->iobase + APCI3120_TIMER_CRT1);
980
981                 /* Select Timer 0 */
982                 b_Tmp = ((devpriv->
983                                 b_DigitalOutputRegister) & 0xF0) |
984                         APCI3120_SELECT_TIMER_0_WORD;
985                 outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
986
987                 /* Set the conversion time */
988                 outw(((unsigned short) ui_TimerValue0),
989                         dev->iobase + APCI3120_TIMER_VALUE);
990                 break;
991
992         }
993         /*    ##########common for all modes################# */
994
995         /***********************/
996         /* Clears the SCAN bit */
997         /***********************/
998
999         /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1000         /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
1001
1002         devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1003                 APCI3120_DISABLE_SCAN;
1004         /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1005
1006         outb(devpriv->b_ModeSelectRegister,
1007                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1008
1009         /*  If DMA is disabled */
1010         if (devpriv->us_UseDma == APCI3120_DISABLE) {
1011                 /*  disable EOC and enable EOS */
1012                 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
1013                 devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
1014
1015                 devpriv->b_ModeSelectRegister =
1016                         (devpriv->
1017                         b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
1018                         APCI3120_ENABLE_EOS_INT;
1019                 outb(devpriv->b_ModeSelectRegister,
1020                         dev->iobase + APCI3120_WRITE_MODE_SELECT);
1021
1022                 if (cmd->stop_src == TRIG_COUNT) {
1023 /*
1024  * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
1025  * disable it (Set Bit D14 to 0)
1026  */
1027                         devpriv->us_OutputRegister =
1028                                 devpriv->
1029                                 us_OutputRegister & APCI3120_DISABLE_TIMER2;
1030                         outw(devpriv->us_OutputRegister,
1031                                 dev->iobase + APCI3120_WR_ADDRESS);
1032
1033                         /*  DISABLE TIMER intERRUPT */
1034                         devpriv->b_ModeSelectRegister =
1035                                 devpriv->
1036                                 b_ModeSelectRegister &
1037                                 APCI3120_DISABLE_TIMER_INT & 0xEF;
1038                         outb(devpriv->b_ModeSelectRegister,
1039                                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1040
1041                         /* (1) Init timer 2 in mode 0 and write timer value */
1042                         devpriv->b_TimerSelectMode =
1043                                 (devpriv->
1044                                 b_TimerSelectMode & 0x0F) |
1045                                 APCI3120_TIMER_2_MODE_0;
1046                         outb(devpriv->b_TimerSelectMode,
1047                                 dev->iobase + APCI3120_TIMER_CRT1);
1048
1049                         /* Writing LOW unsigned short */
1050                         b_Tmp = ((devpriv->
1051                                         b_DigitalOutputRegister) & 0xF0) |
1052                                 APCI3120_SELECT_TIMER_2_LOW_WORD;
1053                         outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1054                         outw(ui_TimerValue2 & 0xffff,
1055                                 dev->iobase + APCI3120_TIMER_VALUE);
1056
1057                         /* Writing HIGH unsigned short */
1058                         b_Tmp = ((devpriv->
1059                                         b_DigitalOutputRegister) & 0xF0) |
1060                                 APCI3120_SELECT_TIMER_2_HIGH_WORD;
1061                         outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
1062                         outw((ui_TimerValue2 >> 16) & 0xffff,
1063                                 dev->iobase + APCI3120_TIMER_VALUE);
1064
1065                         /* (2) Reset FC_TIMER BIT  Clearing timer status register */
1066                         inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1067                         /*  enable timer counter and disable watch dog */
1068                         devpriv->b_ModeSelectRegister =
1069                                 (devpriv->
1070                                 b_ModeSelectRegister |
1071                                 APCI3120_ENABLE_TIMER_COUNTER) &
1072                                 APCI3120_DISABLE_WATCHDOG;
1073                         /*  select EOS clock input for timer 2 */
1074                         devpriv->b_ModeSelectRegister =
1075                                 devpriv->
1076                                 b_ModeSelectRegister |
1077                                 APCI3120_TIMER2_SELECT_EOS;
1078                         /*  Enable timer2  interrupt */
1079                         devpriv->b_ModeSelectRegister =
1080                                 devpriv->
1081                                 b_ModeSelectRegister |
1082                                 APCI3120_ENABLE_TIMER_INT;
1083                         outb(devpriv->b_ModeSelectRegister,
1084                                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1085                         devpriv->b_Timer2Mode = APCI3120_COUNTER;
1086                         devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
1087                 }
1088         } else {
1089                 /* If DMA Enabled */
1090                 unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short);
1091
1092                 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1093                 /* inw(dev->iobase+0); reset EOC bit */
1094                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1095                 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
1096
1097                 /************************************/
1098                 /* Disables the EOC, EOS interrupt  */
1099                 /************************************/
1100                 devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
1101                         APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
1102
1103                 outb(devpriv->b_ModeSelectRegister,
1104                         dev->iobase + APCI3120_WRITE_MODE_SELECT);
1105
1106                 dmalen0 = devpriv->ui_DmaBufferSize[0];
1107                 dmalen1 = devpriv->ui_DmaBufferSize[1];
1108
1109                 if (cmd->stop_src == TRIG_COUNT) {
1110                         /*
1111                          * Must we fill full first buffer? And must we fill
1112                          * full second buffer when first is once filled?
1113                          */
1114                         if (dmalen0 > (cmd->stop_arg * scan_bytes)) {
1115                                 dmalen0 = cmd->stop_arg * scan_bytes;
1116                         } else if (dmalen1 > (cmd->stop_arg * scan_bytes -
1117                                               dmalen0))
1118                                 dmalen1 = cmd->stop_arg * scan_bytes -
1119                                           dmalen0;
1120                 }
1121
1122                 if (cmd->flags & TRIG_WAKE_EOS) {
1123                         /*  don't we want wake up every scan? */
1124                         if (dmalen0 > scan_bytes) {
1125                                 dmalen0 = scan_bytes;
1126                                 if (cmd->scan_end_arg & 1)
1127                                         dmalen0 += 2;
1128                         }
1129                         if (dmalen1 > scan_bytes) {
1130                                 dmalen1 = scan_bytes;
1131                                 if (cmd->scan_end_arg & 1)
1132                                         dmalen1 -= 2;
1133                                 if (dmalen1 < 4)
1134                                         dmalen1 = 4;
1135                         }
1136                 } else {        /*  isn't output buff smaller that our DMA buff? */
1137                         if (dmalen0 > s->async->prealloc_bufsz)
1138                                 dmalen0 = s->async->prealloc_bufsz;
1139                         if (dmalen1 > s->async->prealloc_bufsz)
1140                                 dmalen1 = s->async->prealloc_bufsz;
1141                 }
1142                 devpriv->ui_DmaBufferUsesize[0] = dmalen0;
1143                 devpriv->ui_DmaBufferUsesize[1] = dmalen1;
1144
1145                 /* Initialize DMA */
1146
1147 /*
1148  * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
1149  * register 1
1150  */
1151                 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1152                 outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
1153
1154                 /*  changed  since 16 bit interface for add on */
1155                 /*********************/
1156                 /* ENABLE BUS MASTER */
1157                 /*********************/
1158                 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1159                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1160                         devpriv->i_IobaseAddon + 2);
1161
1162                 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1163                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
1164                         devpriv->i_IobaseAddon + 2);
1165
1166 /*
1167  * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1168  * driver
1169  */
1170                 outw(0x1000, devpriv->i_IobaseAddon + 2);
1171                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1172
1173                 /* 2 No change */
1174                 /* A2P FIFO MANAGEMENT */
1175                 /* A2P fifo reset & transfer control enable */
1176
1177                 /***********************/
1178                 /* A2P FIFO MANAGEMENT */
1179                 /***********************/
1180                 outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
1181                         APCI3120_AMCC_OP_MCSR);
1182
1183 /*
1184  * 3
1185  * beginning address of dma buf The 32 bit address of dma buffer
1186  * is converted into two 16 bit addresses Can done by using _attach
1187  * and put into into an array array used may be for differnet pages
1188  */
1189
1190                 /*  DMA Start Address Low */
1191                 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1192                 outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
1193                         devpriv->i_IobaseAddon + 2);
1194
1195                 /*************************/
1196                 /* DMA Start Address High */
1197                 /*************************/
1198                 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1199                 outw((devpriv->ul_DmaBufferHw[0] / 65536),
1200                         devpriv->i_IobaseAddon + 2);
1201
1202 /*
1203  * 4
1204  * amount of bytes to be transferred set transfer count used ADDON
1205  * MWTC register commented testing
1206  * outl(devpriv->ui_DmaBufferUsesize[0],
1207  * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
1208  */
1209
1210                 /**************************/
1211                 /* Nbr of acquisition LOW */
1212                 /**************************/
1213                 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1214                 outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
1215                         devpriv->i_IobaseAddon + 2);
1216
1217                 /***************************/
1218                 /* Nbr of acquisition HIGH */
1219                 /***************************/
1220                 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1221                 outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
1222                         devpriv->i_IobaseAddon + 2);
1223
1224 /*
1225  * 5
1226  * To configure A2P FIFO testing outl(
1227  * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
1228  */
1229
1230                 /******************/
1231                 /* A2P FIFO RESET */
1232                 /******************/
1233 /*
1234  * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
1235  * driver
1236  */
1237                 outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1238                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1239
1240 /*
1241  * 6
1242  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
1243  * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1244  */
1245
1246                 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1247                 /* outw(3,devpriv->i_IobaseAddon + 4); */
1248                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1249
1250 /*
1251  * 7
1252  * initialise end of dma interrupt AINT_WRITE_COMPL =
1253  * ENABLE_WRITE_TC_INT(ADDI)
1254  */
1255                 /***************************************************/
1256                 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
1257                 /***************************************************/
1258                 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1259                                 APCI3120_ENABLE_WRITE_TC_INT),
1260                         devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1261
1262                 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1263                 /******************************************/
1264                 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
1265                 /******************************************/
1266                 outw(3, devpriv->i_IobaseAddon + 4);
1267                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1268
1269                 /******************/
1270                 /* A2P FIFO RESET */
1271                 /******************/
1272                 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
1273                 outl(0x04000000UL,
1274                         devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
1275                 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
1276         }
1277
1278         if (devpriv->us_UseDma == APCI3120_DISABLE &&
1279             cmd->stop_src == TRIG_COUNT) {
1280                 /*  set gate 2   to start conversion */
1281                 devpriv->us_OutputRegister =
1282                         devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
1283                 outw(devpriv->us_OutputRegister,
1284                         dev->iobase + APCI3120_WR_ADDRESS);
1285         }
1286
1287         switch (mode) {
1288         case 1:
1289                 /*  set gate 0   to start conversion */
1290                 devpriv->us_OutputRegister =
1291                         devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1292                 outw(devpriv->us_OutputRegister,
1293                         dev->iobase + APCI3120_WR_ADDRESS);
1294                 break;
1295         case 2:
1296                 /*  set  gate 0 and gate 1 */
1297                 devpriv->us_OutputRegister =
1298                         devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
1299                 devpriv->us_OutputRegister =
1300                         devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
1301                 outw(devpriv->us_OutputRegister,
1302                         dev->iobase + APCI3120_WR_ADDRESS);
1303                 break;
1304
1305         }
1306
1307         return 0;
1308
1309 }
1310
1311 /*
1312  * Does asynchronous acquisition.
1313  * Determines the mode 1 or 2.
1314  */
1315 static int apci3120_ai_cmd(struct comedi_device *dev,
1316                            struct comedi_subdevice *s)
1317 {
1318         struct addi_private *devpriv = dev->private;
1319         struct comedi_cmd *cmd = &s->async->cmd;
1320
1321         /* loading private structure with cmd structure inputs */
1322         devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
1323
1324         if (cmd->start_src == TRIG_EXT)
1325                 devpriv->b_ExttrigEnable = APCI3120_ENABLE;
1326         else
1327                 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1328
1329         if (cmd->scan_begin_src == TRIG_FOLLOW)
1330                 return apci3120_cyclic_ai(1, dev, s);
1331         else    /* TRIG_TIMER */
1332                 return apci3120_cyclic_ai(2, dev, s);
1333 }
1334
1335 /*
1336  * This function copies the data from DMA buffer to the Comedi buffer.
1337  */
1338 static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
1339                                                   struct comedi_subdevice *s,
1340                                                   unsigned short *dma_buffer,
1341                                                   unsigned int num_samples)
1342 {
1343         struct addi_private *devpriv = dev->private;
1344         struct comedi_cmd *cmd = &s->async->cmd;
1345
1346         devpriv->ui_AiActualScan +=
1347                 (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
1348         s->async->cur_chan += num_samples;
1349         s->async->cur_chan %= cmd->scan_end_arg;
1350
1351         cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
1352 }
1353
1354 /*
1355  * This is a handler for the DMA interrupt.
1356  * This function copies the data to Comedi Buffer.
1357  * For continuous DMA it reinitializes the DMA operation.
1358  * For single mode DMA it stop the acquisition.
1359  */
1360 static void apci3120_interrupt_dma(int irq, void *d)
1361 {
1362         struct comedi_device *dev = d;
1363         struct addi_private *devpriv = dev->private;
1364         struct comedi_subdevice *s = dev->read_subdev;
1365         struct comedi_cmd *cmd = &s->async->cmd;
1366         unsigned int next_dma_buf, samplesinbuf;
1367         unsigned long low_word, high_word, var;
1368         unsigned int ui_Tmp;
1369
1370         samplesinbuf =
1371                 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
1372                 inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
1373
1374         if (samplesinbuf <
1375                 devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
1376                 comedi_error(dev, "Interrupted DMA transfer!");
1377         }
1378         if (samplesinbuf & 1) {
1379                 comedi_error(dev, "Odd count of bytes in DMA ring!");
1380                 apci3120_cancel(dev, s);
1381                 return;
1382         }
1383         samplesinbuf = samplesinbuf >> 1;       /*  number of received samples */
1384         if (devpriv->b_DmaDoubleBuffer) {
1385                 /*  switch DMA buffers if is used double buffering */
1386                 next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
1387
1388                 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1389                 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1390
1391                 /*  changed  since 16 bit interface for add on */
1392                 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1393                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1394                         devpriv->i_IobaseAddon + 2);
1395                 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1396                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /*  0x1000 is out putted in windows driver */
1397
1398                 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1399                 low_word = var & 0xffff;
1400                 var = devpriv->ul_DmaBufferHw[next_dma_buf];
1401                 high_word = var / 65536;
1402
1403                 /* DMA Start Address Low */
1404                 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1405                 outw(low_word, devpriv->i_IobaseAddon + 2);
1406
1407                 /* DMA Start Address High */
1408                 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1409                 outw(high_word, devpriv->i_IobaseAddon + 2);
1410
1411                 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1412                 low_word = var & 0xffff;
1413                 var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
1414                 high_word = var / 65536;
1415
1416                 /* Nbr of acquisition LOW */
1417                 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1418                 outw(low_word, devpriv->i_IobaseAddon + 2);
1419
1420                 /* Nbr of acquisition HIGH */
1421                 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1422                 outw(high_word, devpriv->i_IobaseAddon + 2);
1423
1424 /*
1425  * To configure A2P FIFO
1426  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1427  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1428  */
1429                 outw(3, devpriv->i_IobaseAddon + 4);
1430                 /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1431                 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1432                                 APCI3120_ENABLE_WRITE_TC_INT),
1433                         devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1434
1435         }
1436         if (samplesinbuf) {
1437                 v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
1438                         devpriv->ul_DmaBufferVirtual[devpriv->
1439                                 ui_DmaActualBuffer], samplesinbuf);
1440
1441                 if (!(cmd->flags & TRIG_WAKE_EOS)) {
1442                         s->async->events |= COMEDI_CB_EOS;
1443                         comedi_event(dev, s);
1444                 }
1445         }
1446         if (cmd->stop_src == TRIG_COUNT)
1447                 if (devpriv->ui_AiActualScan >= cmd->stop_arg) {
1448                         /*  all data sampled */
1449                         apci3120_cancel(dev, s);
1450                         s->async->events |= COMEDI_CB_EOA;
1451                         comedi_event(dev, s);
1452                         return;
1453                 }
1454
1455         if (devpriv->b_DmaDoubleBuffer) {       /*  switch dma buffers */
1456                 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
1457         } else {
1458 /*
1459  * restart DMA if is not used double buffering
1460  * ADDED REINITIALISE THE DMA
1461  */
1462                 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
1463                 outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
1464
1465                 /*  changed  since 16 bit interface for add on */
1466                 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
1467                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
1468                         devpriv->i_IobaseAddon + 2);
1469                 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
1470                 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /*  */
1471 /*
1472  * A2P FIFO MANAGEMENT
1473  * A2P fifo reset & transfer control enable
1474  */
1475                 outl(APCI3120_A2P_FIFO_MANAGEMENT,
1476                         devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
1477
1478                 var = devpriv->ul_DmaBufferHw[0];
1479                 low_word = var & 0xffff;
1480                 var = devpriv->ul_DmaBufferHw[0];
1481                 high_word = var / 65536;
1482                 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
1483                 outw(low_word, devpriv->i_IobaseAddon + 2);
1484                 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
1485                 outw(high_word, devpriv->i_IobaseAddon + 2);
1486
1487                 var = devpriv->ui_DmaBufferUsesize[0];
1488                 low_word = var & 0xffff;        /* changed */
1489                 var = devpriv->ui_DmaBufferUsesize[0];
1490                 high_word = var / 65536;
1491                 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
1492                 outw(low_word, devpriv->i_IobaseAddon + 2);
1493                 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
1494                 outw(high_word, devpriv->i_IobaseAddon + 2);
1495
1496 /*
1497  * To configure A2P FIFO
1498  * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
1499  * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
1500  */
1501                 outw(3, devpriv->i_IobaseAddon + 4);
1502                 /* initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
1503                 outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
1504                                 APCI3120_ENABLE_WRITE_TC_INT),
1505                         devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
1506         }
1507 }
1508
1509 /*
1510  * This function handles EOS interrupt.
1511  * This function copies the acquired data(from FIFO) to Comedi buffer.
1512  */
1513 static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
1514 {
1515         struct addi_private *devpriv = dev->private;
1516         struct comedi_subdevice *s = dev->read_subdev;
1517         int n_chan, i;
1518         int err = 1;
1519
1520         n_chan = devpriv->ui_AiNbrofChannels;
1521
1522         for (i = 0; i < n_chan; i++)
1523                 err &= comedi_buf_put(s, inw(dev->iobase + 0));
1524
1525         s->async->events |= COMEDI_CB_EOS;
1526
1527         if (err == 0)
1528                 s->async->events |= COMEDI_CB_OVERFLOW;
1529
1530         comedi_event(dev, s);
1531
1532         return 0;
1533 }
1534
1535 static void apci3120_interrupt(int irq, void *d)
1536 {
1537         struct comedi_device *dev = d;
1538         struct addi_private *devpriv = dev->private;
1539         struct comedi_subdevice *s = dev->read_subdev;
1540         unsigned short int_daq;
1541         unsigned int int_amcc, ui_Check, i;
1542         unsigned short us_TmpValue;
1543         unsigned char b_DummyRead;
1544
1545         ui_Check = 1;
1546
1547         int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;       /*  get IRQ reasons */
1548         int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);     /*  get AMCC int register */
1549
1550         if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
1551                 comedi_error(dev, "IRQ from unknown source");
1552                 return;
1553         }
1554
1555         outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);        /*  shutdown IRQ reasons in AMCC */
1556
1557         int_daq = (int_daq >> 12) & 0xF;
1558
1559         if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
1560                 /* Disable ext trigger */
1561                 apci3120_exttrig_disable(dev);
1562                 devpriv->b_ExttrigEnable = APCI3120_DISABLE;
1563         }
1564         /* clear the timer 2 interrupt */
1565         inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
1566
1567         if (int_amcc & MASTER_ABORT_INT)
1568                 comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
1569         if (int_amcc & TARGET_ABORT_INT)
1570                 comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
1571
1572         /*  Ckeck if EOC interrupt */
1573         if (((int_daq & 0x8) == 0)
1574                 && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
1575                 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
1576
1577                         /*  Read the AI Value */
1578
1579                         devpriv->ui_AiReadData[0] =
1580                                 (unsigned int) inw(devpriv->iobase + 0);
1581                         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1582                         send_sig(SIGIO, devpriv->tsk_Current, 0);       /*  send signal to the sample */
1583                 } else {
1584                         /* Disable EOC Interrupt */
1585                         devpriv->b_ModeSelectRegister =
1586                                 devpriv->
1587                                 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
1588                         outb(devpriv->b_ModeSelectRegister,
1589                                 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1590
1591                 }
1592         }
1593
1594         /*  Check If EOS interrupt */
1595         if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
1596
1597                 if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {    /*  enable this in without DMA ??? */
1598
1599                         if (devpriv->ai_running) {
1600                                 ui_Check = 0;
1601                                 apci3120_interrupt_handle_eos(dev);
1602                                 devpriv->ui_AiActualScan++;
1603                                 devpriv->b_ModeSelectRegister =
1604                                         devpriv->
1605                                         b_ModeSelectRegister |
1606                                         APCI3120_ENABLE_EOS_INT;
1607                                 outb(devpriv->b_ModeSelectRegister,
1608                                         dev->iobase +
1609                                         APCI3120_WRITE_MODE_SELECT);
1610                         } else {
1611                                 ui_Check = 0;
1612                                 for (i = 0; i < devpriv->ui_AiNbrofChannels;
1613                                         i++) {
1614                                         us_TmpValue = inw(devpriv->iobase + 0);
1615                                         devpriv->ui_AiReadData[i] =
1616                                                 (unsigned int) us_TmpValue;
1617                                 }
1618                                 devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
1619                                 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1620
1621                                 send_sig(SIGIO, devpriv->tsk_Current, 0);       /*  send signal to the sample */
1622
1623                         }
1624
1625                 } else {
1626                         devpriv->b_ModeSelectRegister =
1627                                 devpriv->
1628                                 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1629                         outb(devpriv->b_ModeSelectRegister,
1630                                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1631                         devpriv->b_EocEosInterrupt = APCI3120_DISABLE;  /* Default settings */
1632                         devpriv->b_InterruptMode = APCI3120_EOC_MODE;
1633                 }
1634
1635         }
1636         /* Timer2 interrupt */
1637         if (int_daq & 0x1) {
1638
1639                 switch (devpriv->b_Timer2Mode) {
1640                 case APCI3120_COUNTER:
1641                         devpriv->b_ModeSelectRegister =
1642                                 devpriv->
1643                                 b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
1644                         outb(devpriv->b_ModeSelectRegister,
1645                                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1646
1647                         /*  stop timer 2 */
1648                         devpriv->us_OutputRegister =
1649                                 devpriv->
1650                                 us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
1651                         outw(devpriv->us_OutputRegister,
1652                                 dev->iobase + APCI3120_WR_ADDRESS);
1653
1654                         /* stop timer 0 and timer 1 */
1655                         apci3120_cancel(dev, s);
1656
1657                         /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
1658                         s->async->events |= COMEDI_CB_EOA;
1659                         comedi_event(dev, s);
1660
1661                         break;
1662
1663                 case APCI3120_TIMER:
1664
1665                         /* Send a signal to from kernel to user space */
1666                         send_sig(SIGIO, devpriv->tsk_Current, 0);
1667                         break;
1668
1669                 case APCI3120_WATCHDOG:
1670
1671                         /* Send a signal to from kernel to user space */
1672                         send_sig(SIGIO, devpriv->tsk_Current, 0);
1673                         break;
1674
1675                 default:
1676
1677                         /*  disable Timer Interrupt */
1678
1679                         devpriv->b_ModeSelectRegister =
1680                                 devpriv->
1681                                 b_ModeSelectRegister &
1682                                 APCI3120_DISABLE_TIMER_INT;
1683
1684                         outb(devpriv->b_ModeSelectRegister,
1685                                 dev->iobase + APCI3120_WRITE_MODE_SELECT);
1686
1687                 }
1688
1689                 b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1690
1691         }
1692
1693         if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
1694                 if (devpriv->ai_running) {
1695
1696                         /****************************/
1697                         /* Clear Timer Write TC int */
1698                         /****************************/
1699
1700                         outl(APCI3120_CLEAR_WRITE_TC_INT,
1701                                 devpriv->i_IobaseAmcc +
1702                                 APCI3120_AMCC_OP_REG_INTCSR);
1703
1704                         /************************************/
1705                         /* Clears the timer status register */
1706                         /************************************/
1707                         inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
1708                         /* do some data transfer */
1709                         apci3120_interrupt_dma(irq, d);
1710                 } else {
1711                         /* Stops the Timer */
1712                         outw(devpriv->
1713                                 us_OutputRegister & APCI3120_DISABLE_TIMER0 &
1714                                 APCI3120_DISABLE_TIMER1,
1715                                 dev->iobase + APCI3120_WR_ADDRESS);
1716                 }
1717
1718         }
1719
1720         return;
1721 }
1722
1723 /*
1724  * Configure Timer 2
1725  *
1726  * data[0] = TIMER configure as timer
1727  *         = WATCHDOG configure as watchdog
1728  * data[1] = Timer constant
1729  * data[2] = Timer2 interrupt (1)enable or(0) disable
1730  */
1731 static int apci3120_config_insn_timer(struct comedi_device *dev,
1732                                       struct comedi_subdevice *s,
1733                                       struct comedi_insn *insn,
1734                                       unsigned int *data)
1735 {
1736         const struct addi_board *this_board = comedi_board(dev);
1737         struct addi_private *devpriv = dev->private;
1738         unsigned int ui_Timervalue2;
1739         unsigned short us_TmpValue;
1740         unsigned char b_Tmp;
1741
1742         if (!data[1])
1743                 comedi_error(dev, "config:No timer constant !");
1744
1745         devpriv->b_Timer2Interrupt = (unsigned char) data[2];   /*  save info whether to enable or disable interrupt */
1746
1747         ui_Timervalue2 = data[1] / 1000;        /*  convert nano seconds  to u seconds */
1748
1749         /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
1750         us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
1751
1752 /*
1753  * EL250804: Testing if board APCI3120 have the new Quartz or if it
1754  * is an APCI3001 and calculate the time value to set in the timer
1755  */
1756         if ((us_TmpValue & 0x00B0) == 0x00B0
1757                 || !strcmp(this_board->pc_DriverName, "apci3001")) {
1758                 /* Calculate the time value to set in the timer */
1759                 ui_Timervalue2 = ui_Timervalue2 / 50;
1760         } else {
1761                 /* Calculate the time value to set in the timer */
1762                 ui_Timervalue2 = ui_Timervalue2 / 70;
1763         }
1764
1765         /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */
1766         devpriv->us_OutputRegister =
1767                 devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
1768         outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
1769
1770         /*  Disable TIMER Interrupt */
1771         devpriv->b_ModeSelectRegister =
1772                 devpriv->
1773                 b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
1774
1775         /*  Disable Eoc and Eos Interrupts */
1776         devpriv->b_ModeSelectRegister =
1777                 devpriv->
1778                 b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
1779                 APCI3120_DISABLE_EOS_INT;
1780         outb(devpriv->b_ModeSelectRegister,
1781                 devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1782         if (data[0] == APCI3120_TIMER) {        /* initialize timer */
1783                 /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
1784                  * APCI3120_ENABLE_TIMER_INT; */
1785
1786                 /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
1787
1788                 /* Set the Timer 2 in mode 2(Timer) */
1789                 devpriv->b_TimerSelectMode =
1790                         (devpriv->
1791                         b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
1792                 outb(devpriv->b_TimerSelectMode,
1793                         devpriv->iobase + APCI3120_TIMER_CRT1);
1794
1795 /*
1796  * Configure the timer 2 for writing the LOW unsigned short of timer
1797  * is Delay value You must make a b_tmp variable with
1798  * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1799  * you can set the digital output and configure the timer 2,and if
1800  * you don't make this, digital output are erase (Set to 0)
1801  */
1802
1803                 /* Writing LOW unsigned short */
1804                 b_Tmp = ((devpriv->
1805                                 b_DigitalOutputRegister) & 0xF0) |
1806                         APCI3120_SELECT_TIMER_2_LOW_WORD;
1807                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1808                 outw(ui_Timervalue2 & 0xffff,
1809                         devpriv->iobase + APCI3120_TIMER_VALUE);
1810
1811                 /* Writing HIGH unsigned short */
1812                 b_Tmp = ((devpriv->
1813                                 b_DigitalOutputRegister) & 0xF0) |
1814                         APCI3120_SELECT_TIMER_2_HIGH_WORD;
1815                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1816                 outw((ui_Timervalue2 >> 16) & 0xffff,
1817                         devpriv->iobase + APCI3120_TIMER_VALUE);
1818                 /*  timer2 in Timer mode enabled */
1819                 devpriv->b_Timer2Mode = APCI3120_TIMER;
1820
1821         } else {                        /*  Initialize Watch dog */
1822
1823                 /* Set the Timer 2 in mode 5(Watchdog) */
1824
1825                 devpriv->b_TimerSelectMode =
1826                         (devpriv->
1827                         b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
1828                 outb(devpriv->b_TimerSelectMode,
1829                         devpriv->iobase + APCI3120_TIMER_CRT1);
1830
1831 /*
1832  * Configure the timer 2 for writing the LOW unsigned short of timer
1833  * is Delay value You must make a b_tmp variable with
1834  * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
1835  * you can set the digital output and configure the timer 2,and if
1836  * you don't make this, digital output are erase (Set to 0)
1837  */
1838
1839                 /* Writing LOW unsigned short */
1840                 b_Tmp = ((devpriv->
1841                                 b_DigitalOutputRegister) & 0xF0) |
1842                         APCI3120_SELECT_TIMER_2_LOW_WORD;
1843                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1844                 outw(ui_Timervalue2 & 0xffff,
1845                         devpriv->iobase + APCI3120_TIMER_VALUE);
1846
1847                 /* Writing HIGH unsigned short */
1848                 b_Tmp = ((devpriv->
1849                                 b_DigitalOutputRegister) & 0xF0) |
1850                         APCI3120_SELECT_TIMER_2_HIGH_WORD;
1851                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
1852
1853                 outw((ui_Timervalue2 >> 16) & 0xffff,
1854                         devpriv->iobase + APCI3120_TIMER_VALUE);
1855                 /* watchdog enabled */
1856                 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
1857
1858         }
1859
1860         return insn->n;
1861
1862 }
1863
1864 /*
1865  * To start and stop the timer
1866  *
1867  * data[0] = 1 (start)
1868  *         = 0 (stop)
1869  *         = 2 (write new value)
1870  * data[1] = new value
1871  *
1872  * devpriv->b_Timer2Mode = 0 DISABLE
1873  *                       = 1 Timer
1874  *                       = 2 Watch dog
1875  */
1876 static int apci3120_write_insn_timer(struct comedi_device *dev,
1877                                      struct comedi_subdevice *s,
1878                                      struct comedi_insn *insn,
1879                                      unsigned int *data)
1880 {
1881         const struct addi_board *this_board = comedi_board(dev);
1882         struct addi_private *devpriv = dev->private;
1883         unsigned int ui_Timervalue2 = 0;
1884         unsigned short us_TmpValue;
1885         unsigned char b_Tmp;
1886
1887         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
1888                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
1889                 comedi_error(dev, "\nwrite:timer2  not configured ");
1890                 return -EINVAL;
1891         }
1892
1893         if (data[0] == 2) {     /*  write new value */
1894                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1895                         comedi_error(dev,
1896                                 "write :timer2  not configured  in TIMER MODE");
1897                         return -EINVAL;
1898                 }
1899
1900                 if (data[1])
1901                         ui_Timervalue2 = data[1];
1902                 else
1903                         ui_Timervalue2 = 0;
1904         }
1905
1906         /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
1907
1908         switch (data[0]) {
1909         case APCI3120_START:
1910
1911                 /*  Reset FC_TIMER BIT */
1912                 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1913                 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
1914                         /* Enable Timer */
1915                         devpriv->b_ModeSelectRegister =
1916                                 devpriv->b_ModeSelectRegister & 0x0B;
1917                 } else {                /* start watch dog */
1918                         /* Enable WatchDog */
1919                         devpriv->b_ModeSelectRegister =
1920                                 (devpriv->
1921                                 b_ModeSelectRegister & 0x0B) |
1922                                 APCI3120_ENABLE_WATCHDOG;
1923                 }
1924
1925                 /* enable disable interrupt */
1926                 if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
1927
1928                         devpriv->b_ModeSelectRegister =
1929                                 devpriv->
1930                                 b_ModeSelectRegister |
1931                                 APCI3120_ENABLE_TIMER_INT;
1932                         /*  save the task structure to pass info to user */
1933                         devpriv->tsk_Current = current;
1934                 } else {
1935
1936                         devpriv->b_ModeSelectRegister =
1937                                 devpriv->
1938                                 b_ModeSelectRegister &
1939                                 APCI3120_DISABLE_TIMER_INT;
1940                 }
1941                 outb(devpriv->b_ModeSelectRegister,
1942                         devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1943
1944                 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
1945                         /* For Timer mode is  Gate2 must be activated   **timer started */
1946                         devpriv->us_OutputRegister =
1947                                 devpriv->
1948                                 us_OutputRegister | APCI3120_ENABLE_TIMER2;
1949                         outw(devpriv->us_OutputRegister,
1950                                 devpriv->iobase + APCI3120_WR_ADDRESS);
1951                 }
1952
1953                 break;
1954
1955         case APCI3120_STOP:
1956                 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
1957                         /* Disable timer */
1958                         devpriv->b_ModeSelectRegister =
1959                                 devpriv->
1960                                 b_ModeSelectRegister &
1961                                 APCI3120_DISABLE_TIMER_COUNTER;
1962                 } else {
1963                         /* Disable WatchDog */
1964                         devpriv->b_ModeSelectRegister =
1965                                 devpriv->
1966                                 b_ModeSelectRegister &
1967                                 APCI3120_DISABLE_WATCHDOG;
1968                 }
1969                 /*  Disable timer interrupt */
1970                 devpriv->b_ModeSelectRegister =
1971                         devpriv->
1972                         b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
1973
1974                 /*  Write above states  to register */
1975                 outb(devpriv->b_ModeSelectRegister,
1976                         devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
1977
1978                 /*  Reset Gate 2 */
1979                 devpriv->us_OutputRegister =
1980                         devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
1981                 outw(devpriv->us_OutputRegister,
1982                         devpriv->iobase + APCI3120_WR_ADDRESS);
1983
1984                 /*  Reset FC_TIMER BIT */
1985                 inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
1986
1987                 /* Disable timer */
1988                 /* devpriv->b_Timer2Mode=APCI3120_DISABLE;  */
1989
1990                 break;
1991
1992         case 2:         /* write new value to Timer */
1993                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
1994                         comedi_error(dev,
1995                                 "write :timer2  not configured  in TIMER MODE");
1996                         return -EINVAL;
1997                 }
1998                 /*  ui_Timervalue2=data[1]; // passed as argument */
1999                 us_TmpValue =
2000                         (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
2001
2002 /*
2003  * EL250804: Testing if board APCI3120 have the new Quartz or if it
2004  * is an APCI3001 and calculate the time value to set in the timer
2005  */
2006                 if ((us_TmpValue & 0x00B0) == 0x00B0
2007                         || !strcmp(this_board->pc_DriverName, "apci3001")) {
2008                         /* Calculate the time value to set in the timer */
2009                         ui_Timervalue2 = ui_Timervalue2 / 50;
2010                 } else {
2011                         /* Calculate the time value to set in the timer */
2012                         ui_Timervalue2 = ui_Timervalue2 / 70;
2013                 }
2014                 /* Writing LOW unsigned short */
2015                 b_Tmp = ((devpriv->
2016                                 b_DigitalOutputRegister) & 0xF0) |
2017                         APCI3120_SELECT_TIMER_2_LOW_WORD;
2018                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2019
2020                 outw(ui_Timervalue2 & 0xffff,
2021                         devpriv->iobase + APCI3120_TIMER_VALUE);
2022
2023                 /* Writing HIGH unsigned short */
2024                 b_Tmp = ((devpriv->
2025                                 b_DigitalOutputRegister) & 0xF0) |
2026                         APCI3120_SELECT_TIMER_2_HIGH_WORD;
2027                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2028
2029                 outw((ui_Timervalue2 >> 16) & 0xffff,
2030                         devpriv->iobase + APCI3120_TIMER_VALUE);
2031
2032                 break;
2033         default:
2034                 return -EINVAL; /*  Not a valid input */
2035         }
2036
2037         return insn->n;
2038 }
2039
2040 /*
2041  * Read the Timer value
2042  *
2043  * for Timer: data[0]= Timer constant
2044  *
2045  * for watchdog: data[0] = 0 (still running)
2046  *                       = 1 (run down)
2047  */
2048 static int apci3120_read_insn_timer(struct comedi_device *dev,
2049                                     struct comedi_subdevice *s,
2050                                     struct comedi_insn *insn,
2051                                     unsigned int *data)
2052 {
2053         struct addi_private *devpriv = dev->private;
2054         unsigned char b_Tmp;
2055         unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue;
2056
2057         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
2058                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
2059                 comedi_error(dev, "\nread:timer2  not configured ");
2060         }
2061
2062         /* this_board->timer_read(dev,data); */
2063         if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
2064
2065                 /* Read the LOW unsigned short of Timer 2 register */
2066                 b_Tmp = ((devpriv->
2067                                 b_DigitalOutputRegister) & 0xF0) |
2068                         APCI3120_SELECT_TIMER_2_LOW_WORD;
2069                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2070
2071                 us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2072
2073                 /* Read the HIGH unsigned short of Timer 2 register */
2074                 b_Tmp = ((devpriv->
2075                                 b_DigitalOutputRegister) & 0xF0) |
2076                         APCI3120_SELECT_TIMER_2_HIGH_WORD;
2077                 outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
2078
2079                 us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
2080
2081                 /*  combining both words */
2082                 data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16));
2083
2084         } else {                        /*  Read watch dog status */
2085
2086                 us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
2087                 us_StatusValue =
2088                         ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
2089                 if (us_StatusValue == 1) {
2090                         /*  RESET FC_TIMER BIT */
2091                         inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
2092                 }
2093                 data[0] = us_StatusValue;       /*  when data[0] = 1 then the watch dog has rundown */
2094         }
2095         return insn->n;
2096 }
2097
2098 static int apci3120_di_insn_bits(struct comedi_device *dev,
2099                                  struct comedi_subdevice *s,
2100                                  struct comedi_insn *insn,
2101                                  unsigned int *data)
2102 {
2103         struct addi_private *devpriv = dev->private;
2104         unsigned int val;
2105
2106         /* the input channels are bits 11:8 of the status reg */
2107         val = inw(devpriv->iobase + APCI3120_RD_STATUS);
2108         data[1] = (val >> 8) & 0xf;
2109
2110         return insn->n;
2111 }
2112
2113 static int apci3120_do_insn_bits(struct comedi_device *dev,
2114                                  struct comedi_subdevice *s,
2115                                  struct comedi_insn *insn,
2116                                  unsigned int *data)
2117 {
2118         struct addi_private *devpriv = dev->private;
2119
2120         if (comedi_dio_update_state(s, data)) {
2121                 /* The do channels are bits 7:4 of the do register */
2122                 devpriv->b_DigitalOutputRegister = s->state << 4;
2123
2124                 outb(devpriv->b_DigitalOutputRegister,
2125                      devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
2126         }
2127
2128         data[1] = s->state;
2129
2130         return insn->n;
2131 }
2132
2133 static int apci3120_ao_insn_write(struct comedi_device *dev,
2134                                   struct comedi_subdevice *s,
2135                                   struct comedi_insn *insn,
2136                                   unsigned int *data)
2137 {
2138         struct addi_private *devpriv = dev->private;
2139         unsigned int ui_Range, ui_Channel;
2140         unsigned short us_TmpValue;
2141
2142         ui_Range = CR_RANGE(insn->chanspec);
2143         ui_Channel = CR_CHAN(insn->chanspec);
2144
2145         /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
2146         if (ui_Range) {         /*  if 1 then unipolar */
2147
2148                 if (data[0] != 0)
2149                         data[0] =
2150                                 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2151                                         13) | (data[0] + 8191));
2152                 else
2153                         data[0] =
2154                                 ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
2155                                         13) | 8192);
2156
2157         } else {                        /*  if 0 then   bipolar */
2158                 data[0] =
2159                         ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
2160                         data[0]);
2161
2162         }
2163
2164 /*
2165  * out put n values at the given channel. printk("\nwaiting for
2166  * DA_READY BIT");
2167  */
2168         do {                    /* Waiting of DA_READY BIT */
2169                 us_TmpValue =
2170                         ((unsigned short) inw(devpriv->iobase +
2171                                 APCI3120_RD_STATUS)) & 0x0001;
2172         } while (us_TmpValue != 0x0001);
2173
2174         if (ui_Channel <= 3)
2175 /*
2176  * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
2177  * typecasted to ushort since word write is to be done
2178  */
2179                 outw((unsigned short) data[0],
2180                         devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
2181         else
2182 /*
2183  * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
2184  * typecasted to ushort since word write is to be done
2185  */
2186                 outw((unsigned short) data[0],
2187                         devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
2188
2189         return insn->n;
2190 }