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