4 Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
10 Fax: +49(0)7223/9493-92
11 http://www.addi-data.com
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.
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.
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 +-----------------------------------------------------------------------+
35 +-----------------------------------------------------------------------+
36 | Date | Author | Description of updates |
37 +----------+-----------+------------------------------------------------+
40 +----------+-----------+------------------------------------------------+
44 * ADDON RELATED ADDITIONS
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
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)
68 #define APCI3120_AMCC_OP_MCSR 0x3C
69 #define APCI3120_AMCC_OP_REG_INTCSR 0x38
71 /* for transfer count enable bit */
72 #define AGCSTS_TC_ENABLE 0x10000000
74 #define APCI3120_START 1
75 #define APCI3120_STOP 0
77 #define APCI3120_EOC_MODE 1
78 #define APCI3120_EOS_MODE 2
79 #define APCI3120_DMA_MODE 3
81 #define APCI3120_RD_FIFO 0x00
83 /* software trigger dummy register */
84 #define APCI3120_START_CONVERSION 0x02
87 #define APCI3120_QUARTZ_A 70
88 #define APCI3120_QUARTZ_B 50
89 #define APCI3120_TIMER 1
90 #define APCI3120_WATCHDOG 2
91 #define APCI3120_TIMER_DISABLE 0
92 #define APCI3120_TIMER_ENABLE 1
94 #define APCI3120_COUNTER 3
96 static int apci3120_reset(struct comedi_device *dev)
98 struct apci3120_private *devpriv = dev->private;
100 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
102 /* variables used in timer subdevice */
103 devpriv->b_Timer2Mode = 0;
104 devpriv->b_Timer2Interrupt = 0;
105 devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */
107 /* Disable all interrupts, watchdog for the anolog output */
109 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
111 /* disable all counters, ext trigger, and reset scan */
113 outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
115 inw(dev->iobase + APCI3120_STATUS_REG);
120 static int apci3120_cancel(struct comedi_device *dev,
121 struct comedi_subdevice *s)
123 struct apci3120_private *devpriv = dev->private;
125 /* Disable A2P Fifo write and AMWEN signal */
126 outw(0, devpriv->addon + 4);
128 /* Disable Bus Master ADD ON */
129 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
130 outw(0, devpriv->addon + 2);
131 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
132 outw(0, devpriv->addon + 2);
134 /* Disable BUS Master PCI */
135 outl(0, devpriv->amcc + AMCC_OP_REG_MCSR);
137 /* disable all counters, ext trigger, and reset scan */
139 outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
141 /* DISABLE_ALL_INTERRUPT */
143 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
145 inw(dev->iobase + APCI3120_STATUS_REG);
146 devpriv->ui_DmaActualBuffer = 0;
148 devpriv->b_InterruptMode = APCI3120_EOC_MODE;
153 static int apci3120_ai_cmdtest(struct comedi_device *dev,
154 struct comedi_subdevice *s,
155 struct comedi_cmd *cmd)
159 /* Step 1 : check if triggers are trivially valid */
161 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
162 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
163 TRIG_TIMER | TRIG_FOLLOW);
164 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
165 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
166 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
171 /* Step 2a : make sure trigger sources are unique */
173 err |= cfc_check_trigger_is_unique(cmd->start_src);
174 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
175 err |= cfc_check_trigger_is_unique(cmd->stop_src);
177 /* Step 2b : and mutually compatible */
182 /* Step 3: check if arguments are trivially valid */
184 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
186 if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
187 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
189 if (cmd->scan_begin_src == TRIG_TIMER) {
190 if (cmd->convert_arg)
191 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
194 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
197 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
198 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
200 if (cmd->stop_src == TRIG_COUNT)
201 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
203 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
208 /* step 4: fix up any arguments */
210 if (cmd->scan_begin_src == TRIG_TIMER &&
211 cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
212 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
222 static void apci3120_setup_dma(struct comedi_device *dev,
223 struct comedi_subdevice *s)
225 struct apci3120_private *devpriv = dev->private;
226 struct comedi_cmd *cmd = &s->async->cmd;
227 struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
228 struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
229 unsigned int dmalen0 = dmabuf0->size;
230 unsigned int dmalen1 = dmabuf1->size;
231 unsigned int scan_bytes;
233 scan_bytes = comedi_samples_to_bytes(s, cmd->scan_end_arg);
235 if (cmd->stop_src == TRIG_COUNT) {
237 * Must we fill full first buffer? And must we fill
238 * full second buffer when first is once filled?
240 if (dmalen0 > (cmd->stop_arg * scan_bytes))
241 dmalen0 = cmd->stop_arg * scan_bytes;
242 else if (dmalen1 > (cmd->stop_arg * scan_bytes - dmalen0))
243 dmalen1 = cmd->stop_arg * scan_bytes - dmalen0;
246 if (cmd->flags & CMDF_WAKE_EOS) {
247 /* don't we want wake up every scan? */
248 if (dmalen0 > scan_bytes) {
249 dmalen0 = scan_bytes;
250 if (cmd->scan_end_arg & 1)
253 if (dmalen1 > scan_bytes) {
254 dmalen1 = scan_bytes;
255 if (cmd->scan_end_arg & 1)
261 /* isn't output buff smaller that our DMA buff? */
262 if (dmalen0 > s->async->prealloc_bufsz)
263 dmalen0 = s->async->prealloc_bufsz;
264 if (dmalen1 > s->async->prealloc_bufsz)
265 dmalen1 = s->async->prealloc_bufsz;
267 dmabuf0->use_size = dmalen0;
268 dmabuf1->use_size = dmalen1;
273 * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
276 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
277 devpriv->amcc + AMCC_OP_REG_AGCSTS);
279 /* changed since 16 bit interface for add on */
280 /* ENABLE BUS MASTER */
281 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
282 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
284 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
285 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
288 * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
291 outw(0x1000, devpriv->addon + 2);
292 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
295 /* A2P FIFO MANAGEMENT */
296 /* A2P fifo reset & transfer control enable */
297 outl(APCI3120_A2P_FIFO_MANAGEMENT,
298 devpriv->amcc + APCI3120_AMCC_OP_MCSR);
302 * beginning address of dma buf The 32 bit address of dma buffer
303 * is converted into two 16 bit addresses Can done by using _attach
304 * and put into into an array array used may be for differnet pages
307 /* DMA Start Address Low */
308 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
309 outw(dmabuf0->hw & 0xffff, devpriv->addon + 2);
311 /* DMA Start Address High */
312 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
313 outw((dmabuf0->hw >> 16) & 0xffff, devpriv->addon + 2);
317 * amount of bytes to be transferred set transfer count used ADDON
318 * MWTC register commented testing
321 /* Nbr of acquisition LOW */
322 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
323 outw(dmabuf0->use_size & 0xffff, devpriv->addon + 2);
325 /* Nbr of acquisition HIGH */
326 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
327 outw((dmabuf0->use_size >> 16) & 0xffff, devpriv->addon + 2);
331 * To configure A2P FIFO testing outl(
332 * FIFO_ADVANCE_ON_BYTE_2, devpriv->amcc + AMCC_OP_REG_INTCSR);
337 * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
340 outl(0x04000000UL, devpriv->amcc + AMCC_OP_REG_MCSR);
341 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
345 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
346 * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
351 * initialise end of dma interrupt AINT_WRITE_COMPL =
352 * ENABLE_WRITE_TC_INT(ADDI)
354 /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
355 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT,
356 devpriv->amcc + AMCC_OP_REG_INTCSR);
358 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
359 /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
360 outw(3, devpriv->addon + 4);
361 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
364 /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
365 outl(0x04000000UL, devpriv->amcc + APCI3120_AMCC_OP_MCSR);
366 /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
369 static int apci3120_ai_cmd(struct comedi_device *dev,
370 struct comedi_subdevice *s)
372 struct apci3120_private *devpriv = dev->private;
373 struct comedi_cmd *cmd = &s->async->cmd;
374 unsigned int divisor;
376 /* set default mode bits */
377 devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
378 APCI3120_MODE_TIMER2_AS_TIMER;
380 /* Clear Timer Write TC int */
381 outl(APCI3120_CLEAR_WRITE_TC_INT,
382 devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
384 devpriv->ui_DmaActualBuffer = 0;
386 /* load chanlist for command scan */
387 apci3120_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist);
389 if (cmd->start_src == TRIG_EXT) {
390 devpriv->b_ExttrigEnable = 1;
391 apci3120_exttrig_enable(dev, true);
393 devpriv->b_ExttrigEnable = 0;
396 if (cmd->scan_begin_src == TRIG_TIMER) {
398 * Timer 1 is used in MODE2 (rate generator) to set the
399 * start time for each scan.
401 divisor = apci3120_ns_to_timer(dev, 1, cmd->scan_begin_arg,
403 apci3120_timer_set_mode(dev, 1, APCI3120_TIMER_MODE2);
404 apci3120_timer_write(dev, 1, divisor);
408 * Timer 0 is used in MODE2 (rate generator) to set the conversion
409 * time for each acquisition.
411 divisor = apci3120_ns_to_timer(dev, 0, cmd->convert_arg, cmd->flags);
412 apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE2);
413 apci3120_timer_write(dev, 0, divisor);
415 if (devpriv->us_UseDma) {
416 devpriv->b_InterruptMode = APCI3120_DMA_MODE;
417 apci3120_setup_dma(dev, s);
419 devpriv->b_InterruptMode = APCI3120_EOS_MODE;
421 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
423 if (cmd->stop_src == TRIG_COUNT) {
425 * Timer 2 is used in MODE0 (hardware retriggerable
426 * one-shot) to count the number of scans.
428 * NOTE: not sure about the -2 value
430 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE0);
431 apci3120_timer_write(dev, 2, cmd->stop_arg - 2);
433 apci3120_clr_timer2_interrupt(dev);
435 apci3120_timer_enable(dev, 2, true);
437 /* configure Timer 2 For counting EOS */
438 devpriv->mode |= APCI3120_MODE_TIMER2_AS_COUNTER |
439 APCI3120_MODE_TIMER2_CLK_EOS |
440 APCI3120_MODE_TIMER2_IRQ_ENA;
442 devpriv->b_Timer2Mode = APCI3120_COUNTER;
443 devpriv->b_Timer2Interrupt = 1;
447 /* set mode to enable acquisition */
448 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
450 if (cmd->scan_begin_src == TRIG_TIMER)
451 apci3120_timer_enable(dev, 1, true);
452 apci3120_timer_enable(dev, 0, true);
458 * This is a handler for the DMA interrupt.
459 * This function copies the data to Comedi Buffer.
460 * For continuous DMA it reinitializes the DMA operation.
461 * For single mode DMA it stop the acquisition.
463 static void apci3120_interrupt_dma(int irq, void *d)
465 struct comedi_device *dev = d;
466 struct apci3120_private *devpriv = dev->private;
467 struct comedi_subdevice *s = dev->read_subdev;
468 struct comedi_cmd *cmd = &s->async->cmd;
469 struct apci3120_dmabuf *dmabuf;
470 unsigned int samplesinbuf;
473 dmabuf = &devpriv->dmabuf[devpriv->ui_DmaActualBuffer];
475 samplesinbuf = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC);
477 if (samplesinbuf < dmabuf->use_size)
478 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
479 if (samplesinbuf & 1) {
480 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
481 apci3120_cancel(dev, s);
484 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
485 if (devpriv->b_DmaDoubleBuffer) {
486 /* switch DMA buffers if is used double buffering */
487 struct apci3120_dmabuf *next_dmabuf;
489 next_dmabuf = &devpriv->dmabuf[1 - devpriv->ui_DmaActualBuffer];
491 ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
492 outl(ui_Tmp, devpriv->amcc + AMCC_OP_REG_AGCSTS);
494 /* changed since 16 bit interface for add on */
495 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
496 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
497 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
498 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2); /* 0x1000 is out putted in windows driver */
500 /* DMA Start Address Low */
501 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
502 outw(next_dmabuf->hw & 0xffff, devpriv->addon + 2);
504 /* DMA Start Address High */
505 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
506 outw((next_dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
508 /* Nbr of acquisition LOW */
509 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
510 outw(next_dmabuf->use_size & 0xffff, devpriv->addon + 2);
512 /* Nbr of acquisition HIGH */
513 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
514 outw((next_dmabuf->use_size > 16) & 0xffff, devpriv->addon + 2);
517 * To configure A2P FIFO
518 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
519 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
521 outw(3, devpriv->addon + 4);
522 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
523 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
524 APCI3120_ENABLE_WRITE_TC_INT,
525 devpriv->amcc + AMCC_OP_REG_INTCSR);
529 comedi_buf_write_samples(s, dmabuf->virt, samplesinbuf);
531 if (!(cmd->flags & CMDF_WAKE_EOS))
532 s->async->events |= COMEDI_CB_EOS;
534 if (cmd->stop_src == TRIG_COUNT &&
535 s->async->scans_done >= cmd->stop_arg) {
536 s->async->events |= COMEDI_CB_EOA;
540 if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
541 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
544 * restart DMA if is not used double buffering
545 * ADDED REINITIALISE THE DMA
547 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
548 devpriv->amcc + AMCC_OP_REG_AGCSTS);
550 /* changed since 16 bit interface for add on */
551 outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->addon + 0);
552 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->addon + 2);
553 outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->addon + 0);
554 outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->addon + 2);
556 * A2P FIFO MANAGEMENT
557 * A2P fifo reset & transfer control enable
559 outl(APCI3120_A2P_FIFO_MANAGEMENT,
560 devpriv->amcc + AMCC_OP_REG_MCSR);
562 outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->addon + 0);
563 outw(dmabuf->hw & 0xffff, devpriv->addon + 2);
564 outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->addon + 0);
565 outw((dmabuf->hw >> 16) & 0xffff, devpriv->addon + 2);
567 outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->addon + 0);
568 outw(dmabuf->use_size & 0xffff, devpriv->addon + 2);
569 outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->addon + 0);
570 outw((dmabuf->use_size >> 16) & 0xffff, devpriv->addon + 2);
573 * To configure A2P FIFO
574 * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
575 * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
577 outw(3, devpriv->addon + 4);
578 /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
579 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
580 APCI3120_ENABLE_WRITE_TC_INT,
581 devpriv->amcc + AMCC_OP_REG_INTCSR);
585 static irqreturn_t apci3120_interrupt(int irq, void *d)
587 struct comedi_device *dev = d;
588 struct apci3120_private *devpriv = dev->private;
589 struct comedi_subdevice *s = dev->read_subdev;
590 struct comedi_cmd *cmd = &s->async->cmd;
592 unsigned int int_amcc;
594 status = inw(dev->iobase + APCI3120_STATUS_REG);
595 int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
597 if (!(status & APCI3120_STATUS_INT_MASK) &&
598 !(int_amcc & ANY_S593X_INT)) {
599 dev_err(dev->class_dev, "IRQ from unknown source\n");
603 outl(int_amcc | 0x00ff0000, devpriv->amcc + AMCC_OP_REG_INTCSR);
605 if (devpriv->b_ExttrigEnable) {
606 apci3120_exttrig_enable(dev, false);
607 devpriv->b_ExttrigEnable = 0;
610 apci3120_clr_timer2_interrupt(dev);
612 if (int_amcc & MASTER_ABORT_INT)
613 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
614 if (int_amcc & TARGET_ABORT_INT)
615 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
617 if ((status & APCI3120_STATUS_EOC_INT) == 0 &&
618 devpriv->b_InterruptMode == APCI3120_EOC_MODE) {
619 /* nothing to do... EOC mode is not currently used */
622 if ((status & APCI3120_STATUS_EOS_INT) &&
623 devpriv->b_InterruptMode == APCI3120_EOS_MODE) {
627 for (i = 0; i < cmd->chanlist_len; i++) {
628 val = inw(dev->iobase + 0);
629 comedi_buf_write_samples(s, &val, 1);
632 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
633 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
636 if (status & APCI3120_STATUS_TIMER2_INT) {
637 switch (devpriv->b_Timer2Mode) {
638 case APCI3120_COUNTER:
639 devpriv->mode &= ~APCI3120_MODE_EOS_IRQ_ENA;
640 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
642 s->async->events |= COMEDI_CB_EOA;
647 /* Send a signal to from kernel to user space */
648 send_sig(SIGIO, devpriv->tsk_Current, 0);
651 case APCI3120_WATCHDOG:
653 /* Send a signal to from kernel to user space */
654 send_sig(SIGIO, devpriv->tsk_Current, 0);
658 /* disable Timer Interrupt */
659 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
660 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
663 apci3120_clr_timer2_interrupt(dev);
666 if ((status & APCI3120_STATUS_AMCC_INT) &&
667 devpriv->b_InterruptMode == APCI3120_DMA_MODE) {
668 /* Clear Timer Write TC int */
669 outl(APCI3120_CLEAR_WRITE_TC_INT,
670 devpriv->amcc + APCI3120_AMCC_OP_REG_INTCSR);
672 apci3120_clr_timer2_interrupt(dev);
674 /* do some data transfer */
675 apci3120_interrupt_dma(irq, d);
677 comedi_handle_events(dev, s);
685 * data[0] = TIMER configure as timer
686 * = WATCHDOG configure as watchdog
687 * data[1] = Timer constant
688 * data[2] = Timer2 interrupt (1)enable or(0) disable
690 static int apci3120_config_insn_timer(struct comedi_device *dev,
691 struct comedi_subdevice *s,
692 struct comedi_insn *insn,
695 struct apci3120_private *devpriv = dev->private;
696 unsigned int divisor;
699 dev_err(dev->class_dev, "No timer constant!\n");
701 devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */
703 divisor = apci3120_ns_to_timer(dev, 2, data[1], CMDF_ROUND_DOWN);
705 apci3120_timer_enable(dev, 2, false);
707 /* disable timer 2 interrupt and reset operation mode (timer) */
708 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
709 ~APCI3120_MODE_TIMER2_AS_MASK;
711 /* Disable Eoc and Eos Interrupts */
712 devpriv->mode &= ~APCI3120_MODE_EOC_IRQ_ENA &
713 ~APCI3120_MODE_EOS_IRQ_ENA;
714 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
716 if (data[0] == APCI3120_TIMER) { /* initialize timer */
717 /* Set the Timer 2 in mode 2(Timer) */
718 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE2);
720 /* Set timer 2 delay */
721 apci3120_timer_write(dev, 2, divisor);
723 /* timer2 in Timer mode enabled */
724 devpriv->b_Timer2Mode = APCI3120_TIMER;
725 } else { /* Initialize Watch dog */
726 /* Set the Timer 2 in mode 5(Watchdog) */
727 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE5);
729 /* Set timer 2 delay */
730 apci3120_timer_write(dev, 2, divisor);
732 /* watchdog enabled */
733 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
742 * To start and stop the timer
744 * data[0] = 1 (start)
746 * = 2 (write new value)
747 * data[1] = new value
749 * devpriv->b_Timer2Mode = 0 DISABLE
753 static int apci3120_write_insn_timer(struct comedi_device *dev,
754 struct comedi_subdevice *s,
755 struct comedi_insn *insn,
758 struct apci3120_private *devpriv = dev->private;
759 unsigned int divisor;
761 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
762 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
763 dev_err(dev->class_dev, "timer2 not configured\n");
767 if (data[0] == 2) { /* write new value */
768 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
769 dev_err(dev->class_dev,
770 "timer2 not configured in TIMER MODE\n");
777 apci3120_clr_timer2_interrupt(dev);
779 if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
781 devpriv->mode &= 0x0b;
782 devpriv->mode |= APCI3120_MODE_TIMER2_AS_TIMER;
783 } else { /* start watch dog */
784 /* Enable WatchDog */
785 devpriv->mode &= 0x0b;
786 devpriv->mode |= APCI3120_MODE_TIMER2_AS_WDOG;
789 /* enable disable interrupt */
790 if (devpriv->b_Timer2Interrupt) {
791 devpriv->mode |= APCI3120_MODE_TIMER2_IRQ_ENA;
793 /* save the task structure to pass info to user */
794 devpriv->tsk_Current = current;
796 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
798 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
801 if (devpriv->b_Timer2Mode == APCI3120_TIMER)
802 apci3120_timer_enable(dev, 2, true);
806 /* disable timer 2 interrupt and reset operation mode (timer) */
807 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
808 ~APCI3120_MODE_TIMER2_AS_MASK;
809 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
811 apci3120_timer_enable(dev, 2, false);
813 apci3120_clr_timer2_interrupt(dev);
816 case 2: /* write new value to Timer */
817 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
818 dev_err(dev->class_dev,
819 "timer2 not configured in TIMER MODE\n");
823 divisor = apci3120_ns_to_timer(dev, 2, data[1],
826 /* Set timer 2 delay */
827 apci3120_timer_write(dev, 2, divisor);
830 return -EINVAL; /* Not a valid input */
837 * Read the Timer value
839 * for Timer: data[0]= Timer constant
841 * for watchdog: data[0] = 0 (still running)
844 static int apci3120_read_insn_timer(struct comedi_device *dev,
845 struct comedi_subdevice *s,
846 struct comedi_insn *insn,
849 struct apci3120_private *devpriv = dev->private;
852 if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
853 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
854 dev_err(dev->class_dev, "timer2 not configured\n");
856 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
857 data[0] = apci3120_timer_read(dev, 2);
859 /* Read watch dog status */
860 status = inw(dev->iobase + APCI3120_STATUS_REG);
861 if (status & APCI3120_STATUS_TIMER2_INT) {
862 apci3120_clr_timer2_interrupt(dev);