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