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