2 * This is a handler for the DMA interrupt.
3 * This function copies the data to Comedi Buffer.
4 * For continuous DMA it reinitializes the DMA operation.
5 * For single mode DMA it stop the acquisition.
7 static void apci3120_interrupt_dma(int irq, void *d)
9 struct comedi_device *dev = d;
10 struct apci3120_private *devpriv = dev->private;
11 struct comedi_subdevice *s = dev->read_subdev;
12 struct comedi_async *async = s->async;
13 struct comedi_cmd *cmd = &async->cmd;
14 struct apci3120_dmabuf *dmabuf;
15 unsigned int samplesinbuf;
17 dmabuf = &devpriv->dmabuf[devpriv->cur_dmabuf];
19 samplesinbuf = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC);
21 if (samplesinbuf < dmabuf->use_size)
22 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
23 if (samplesinbuf & 1) {
24 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
25 async->events |= COMEDI_CB_ERROR;
28 samplesinbuf = samplesinbuf >> 1; /* number of received samples */
30 if (devpriv->use_double_buffer) {
31 struct apci3120_dmabuf *next_dmabuf;
33 next_dmabuf = &devpriv->dmabuf[!devpriv->cur_dmabuf];
35 /* start DMA on next buffer */
36 apci3120_init_dma(dev, next_dmabuf);
40 comedi_buf_write_samples(s, dmabuf->virt, samplesinbuf);
42 if (!(cmd->flags & CMDF_WAKE_EOS))
43 async->events |= COMEDI_CB_EOS;
46 if ((async->events & COMEDI_CB_CANCEL_MASK) ||
47 (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg))
50 if (devpriv->use_double_buffer) {
51 /* switch dma buffers for next interrupt */
52 devpriv->cur_dmabuf = !devpriv->cur_dmabuf;
54 /* restart DMA if is not using double buffering */
55 apci3120_init_dma(dev, dmabuf);
59 static irqreturn_t apci3120_interrupt(int irq, void *d)
61 struct comedi_device *dev = d;
62 struct apci3120_private *devpriv = dev->private;
63 struct comedi_subdevice *s = dev->read_subdev;
64 struct comedi_async *async = s->async;
65 struct comedi_cmd *cmd = &async->cmd;
67 unsigned int int_amcc;
69 status = inw(dev->iobase + APCI3120_STATUS_REG);
70 int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
72 if (!(status & APCI3120_STATUS_INT_MASK) &&
73 !(int_amcc & ANY_S593X_INT)) {
74 dev_err(dev->class_dev, "IRQ from unknown source\n");
78 outl(int_amcc | AINT_INT_MASK, devpriv->amcc + AMCC_OP_REG_INTCSR);
80 if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG)
81 apci3120_exttrig_enable(dev, false);
83 if (int_amcc & MASTER_ABORT_INT)
84 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
85 if (int_amcc & TARGET_ABORT_INT)
86 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
88 if ((status & APCI3120_STATUS_EOC_INT) == 0 &&
89 (devpriv->mode & APCI3120_MODE_EOC_IRQ_ENA)) {
90 /* nothing to do... EOC mode is not currently used */
93 if ((status & APCI3120_STATUS_EOS_INT) &&
94 (devpriv->mode & APCI3120_MODE_EOS_IRQ_ENA)) {
98 for (i = 0; i < cmd->chanlist_len; i++) {
99 val = inw(dev->iobase + APCI3120_AI_FIFO_REG);
100 comedi_buf_write_samples(s, &val, 1);
103 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
104 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
107 if (status & APCI3120_STATUS_TIMER2_INT) {
110 * timer2 interrupts are not enabled in the driver
112 apci3120_clr_timer2_interrupt(dev);
115 if (status & APCI3120_STATUS_AMCC_INT) {
116 /* AMCC- Clear write complete interrupt (DMA) */
117 outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR);
119 /* do some data transfer */
120 apci3120_interrupt_dma(irq, d);
123 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
124 async->events |= COMEDI_CB_EOA;
126 comedi_handle_events(dev, s);