static irqreturn_t apci1032_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct apci1032_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsigned int ctrl; /* check interrupt is from this device */ if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) & INTCSR_INTR_ASSERTED) == 0) return IRQ_NONE; /* check interrupt is enabled */ ctrl = inl(dev->iobase + APCI1032_CTRL_REG); if ((ctrl & APCI1032_CTRL_INT_ENA) == 0) return IRQ_HANDLED; /* disable the interrupt */ outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG); s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff; comedi_buf_put(s, s->state); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); /* enable the interrupt */ outl(ctrl, dev->iobase + APCI1032_CTRL_REG); return IRQ_HANDLED; }
static irqreturn_t pcl711_interrupt(int irq, void *d) { int lo, hi; int data; struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 0; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } hi = inb(dev->iobase + PCL711_AD_HI); lo = inb(dev->iobase + PCL711_AD_LO); outb(0, dev->iobase + PCL711_CLRINTR); data = (hi << 8) | lo; /* FIXME! Nothing else sets ntrig! */ if (!(--devpriv->ntrig)) { if (this_board->is_8112) outb(1, dev->iobase + PCL711_MODE); else outb(0, dev->iobase + PCL711_MODE); s->async->events |= COMEDI_CB_EOA; } comedi_event(dev, s); return IRQ_HANDLED; }
/* * 'do_cmd' function for an 'INTERRUPT' subdevice. */ static int dio200_subdev_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; struct dio200_subdev_intr *subpriv = s->private; unsigned long flags; int event = 0; spin_lock_irqsave(&subpriv->spinlock, flags); subpriv->active = true; /* Set up end of acquisition. */ if (cmd->stop_src == TRIG_COUNT) subpriv->stopcount = cmd->stop_arg; else /* TRIG_NONE */ subpriv->stopcount = 0; if (cmd->start_src == TRIG_INT) s->async->inttrig = dio200_inttrig_start_intr; else /* TRIG_NOW */ event = dio200_start_intr(dev, s); spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) comedi_event(dev, s); return 0; }
void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s) { if (s-> async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { ni_pcidio_cancel(dev, s); } comedi_event(dev, s); }
static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = &dev->subdevices[0]; comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG)); comedi_event(dev, s); return IRQ_HANDLED; }
static void usbduxsigma_ai_urb_complete(struct urb *urb) { struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; /* exit if not running a command, do not resubmit urb */ if (!devpriv->ai_cmd_running) return; switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); usbduxsigma_ai_handle_urb(dev, s, urb); break; case -EILSEQ: /* * error in the ISOchronous data * we don't copy the data into the transfer buffer * and recycle the last data byte */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); usbduxsigma_ai_handle_urb(dev, s, urb); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ async->events |= COMEDI_CB_ERROR; break; default: /* a real error */ dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", __func__, urb->status); async->events |= COMEDI_CB_ERROR; break; } /* * comedi_handle_events() cannot be used in this driver. The (*cancel) * operation would unlink the urb. */ if (async->events & COMEDI_CB_CANCEL_MASK) usbduxsigma_ai_stop(dev, 0); comedi_event(dev, s); }
unsigned int cfc_handle_events(comedi_device *dev, comedi_subdevice *subd) { unsigned int events = subd->async->events; if (events == 0) return events; if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) subd->cancel(dev, subd); comedi_event(dev, subd); return events; }
static void usbduxsigma_ao_urb_complete(struct urb *urb) { struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; /* exit if not running a command, do not resubmit urb */ if (!devpriv->ao_cmd_running) return; switch (urb->status) { case 0: usbduxsigma_ao_handle_urb(dev, s, urb); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ async->events |= COMEDI_CB_ERROR; break; default: /* a real error */ dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", __func__, urb->status); async->events |= COMEDI_CB_ERROR; break; } /* * comedi_handle_events() cannot be used in this driver. The (*cancel) * operation would unlink the urb. */ if (async->events & COMEDI_CB_CANCEL_MASK) usbduxsigma_ao_stop(dev, 0); comedi_event(dev, s); }
static irqreturn_t dt2811_interrupt(int irq, void *d) { int lo, hi; int data; struct comedi_device *dev = d; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } lo = inb(dev->iobase + DT2811_ADDATLO); hi = inb(dev->iobase + DT2811_ADDATHI); data = lo + (hi << 8); if (!(--devpriv->ntrig)) { /* how to turn off acquisition */ s->async->events |= COMEDI_SB_EOA; } comedi_event(dev, s); return IRQ_HANDLED; }
static int dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { struct dio200_subdev_intr *subpriv = s->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; if (trig_num != cmd->start_arg) return -EINVAL; spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = NULL; if (subpriv->active) event = dio200_start_intr(dev, s); spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) comedi_event(dev, s); return 1; }
static void usbduxsub_ao_isoc_irq(struct urb *urb) { struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->write_subdev; struct usbdux_private *devpriv = dev->private; int8_t *datap; int len; int ret; int i; switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* after an unlink command, unplug, ... etc */ /* no unlink needed here. Already shutting down. */ if (devpriv->ao_cmd_running) { s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); usbdux_ao_stop(dev, 0); } return; default: /* a real error */ if (devpriv->ao_cmd_running) { dev_err(dev->class_dev, "Non-zero urb status received in ao intr context: %d\n", urb->status); s->async->events |= COMEDI_CB_ERROR; s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); /* we do an unlink if we are in the high speed mode */ usbdux_ao_stop(dev, 0); } return; } /* are we actually running? */ if (!devpriv->ao_cmd_running) return; /* normal operation: executing a command in this subdevice */ devpriv->ao_counter--; if ((int)devpriv->ao_counter <= 0) { /* timer zero */ devpriv->ao_counter = devpriv->ao_timer; /* handle non continous acquisition */ if (!devpriv->ao_continous) { /* fixed number of samples */ devpriv->ao_sample_count--; if (devpriv->ao_sample_count < 0) { /* all samples transmitted */ usbdux_ao_stop(dev, 0); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); /* no resubmit of the urb */ return; } } /* transmit data to the USB bus */ datap = urb->transfer_buffer; len = s->async->cmd.chanlist_len; *datap++ = len; for (i = 0; i < s->async->cmd.chanlist_len; i++) { unsigned int chan = devpriv->ao_chanlist[i]; short val; ret = comedi_buf_get(s->async, &val); if (ret < 0) { dev_err(dev->class_dev, "buffer underflow\n"); s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_OVERFLOW); } /* pointer to the DA */ *datap++ = val & 0xff; *datap++ = (val >> 8) & 0xff; *datap++ = chan << 6; devpriv->ao_readback[chan] = val; s->async->events |= COMEDI_CB_BLOCK; comedi_event(dev, s); } }
/* analogue IN - interrupt service routine */ static void usbduxsub_ai_isoc_irq(struct urb *urb) { struct comedi_device *dev = urb->context; struct comedi_subdevice *s = dev->read_subdev; struct usbdux_private *devpriv = dev->private; int i, err, n; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* error in the ISOchronous data */ /* we don't copy the data into the transfer buffer */ /* and recycle the last data byte */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ if (devpriv->ai_cmd_running) { s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* stop the transfer w/o unlink */ usbdux_ai_stop(dev, 0); } return; default: /* a real error on the bus */ /* pass error to comedi if we are really running a command */ if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, "Non-zero urb status received in ai intr context: %d\n", urb->status); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* don't do an unlink here */ usbdux_ai_stop(dev, 0); } return; } /* * at this point we are reasonably sure that nothing dodgy has happened * are we running a command? */ if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command, do not continue execution if no * asynchronous command is running in particular not resubmit */ return; } urb->dev = comedi_to_usb_dev(dev); /* resubmit the urb */ err = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err < 0)) { dev_err(dev->class_dev, "urb resubmit failed in int-context! err=%d\n", err); if (err == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; comedi_event(dev, s); /* don't do an unlink here */ usbdux_ai_stop(dev, 0); return; } devpriv->ai_counter--; if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ devpriv->ai_counter = devpriv->ai_timer; /* test, if we transmit only a fixed number of samples */ if (!devpriv->ai_continous) { /* not continuous, fixed number of samples */ devpriv->ai_sample_count--; /* all samples received? */ if (devpriv->ai_sample_count < 0) { /* prevent a resubmit next time */ usbdux_ai_stop(dev, 0); /* say comedi that the acquistion is over */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; } } /* get the data from the USB bus and hand it over to comedi */ n = s->async->cmd.chanlist_len; for (i = 0; i < n; i++) { unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]); int16_t val = le16_to_cpu(devpriv->in_buf[i]); /* bipolar data is two's-complement */ if (comedi_range_is_bipolar(s, range)) val ^= ((s->maxdata + 1) >> 1); /* transfer data */ err = comedi_buf_put(s->async, val); if (unlikely(err == 0)) { /* buffer overflow */ usbdux_ai_stop(dev, 0); return; } } /* tell comedi that data is there */ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); }
static void usbduxsigma_ao_urb_complete(struct urb *urb) { struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; struct comedi_cmd *cmd = &s->async->cmd; uint8_t *datap; int ret; int i; switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ if (devpriv->ao_cmd_running) { usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); } return; default: /* a real error */ if (devpriv->ao_cmd_running) { dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", __func__, urb->status); usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ s->async->events |= (COMEDI_CB_ERROR | COMEDI_CB_EOA); comedi_event(dev, s); } return; } if (!devpriv->ao_cmd_running) return; devpriv->ao_counter--; if ((int)devpriv->ao_counter <= 0) { /* timer zero, transfer from comedi */ devpriv->ao_counter = devpriv->ao_timer; if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ devpriv->ao_sample_count--; if (devpriv->ao_sample_count < 0) { usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ /* acquistion is over, tell comedi */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; } } /* transmit data to the USB bus */ datap = urb->transfer_buffer; *datap++ = cmd->chanlist_len; for (i = 0; i < cmd->chanlist_len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); unsigned short val; ret = comedi_buf_get(s, &val); if (ret < 0) { dev_err(dev->class_dev, "buffer underflow\n"); s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_OVERFLOW); } *datap++ = val; *datap++ = chan; s->readback[chan] = val; s->async->events |= COMEDI_CB_BLOCK; comedi_event(dev, s); } } urb->transfer_buffer_length = SIZEOUTBUF; urb->dev = comedi_to_usb_dev(dev); urb->status = 0; if (devpriv->high_speed) urb->interval = 8; /* uframes */ else urb->interval = 1; /* frames */ urb->number_of_packets = 1; urb->iso_frame_desc[0].offset = 0; urb->iso_frame_desc[0].length = SIZEOUTBUF; urb->iso_frame_desc[0].status = 0; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", __func__, ret); if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler\n"); usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); comedi_event(dev, s); } }
static void usbduxsigma_ai_urb_complete(struct urb *urb) { struct comedi_device *dev = urb->context; struct usbduxsigma_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_cmd *cmd = &s->async->cmd; unsigned int dio_state; uint32_t val; int ret; int i; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* * error in the ISOchronous data * we don't copy the data into the transfer buffer * and recycle the last data byte */ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ if (devpriv->ai_cmd_running) { usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ /* we are still running a command, tell comedi */ s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); comedi_event(dev, s); } return; default: /* * a real error on the bus * pass error to comedi if we are really running a command */ if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, "%s: non-zero urb status (%d)\n", __func__, urb->status); usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); comedi_event(dev, s); } return; } if (unlikely(!devpriv->ai_cmd_running)) return; urb->dev = comedi_to_usb_dev(dev); ret = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(ret < 0)) { dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", __func__, ret); if (ret == -EL2NSYNC) dev_err(dev->class_dev, "buggy USB host controller or bug in IRQ handler\n"); usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); comedi_event(dev, s); return; } /* get the state of the dio pins to allow external trigger */ dio_state = be32_to_cpu(devpriv->in_buf[0]); devpriv->ai_counter--; if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ devpriv->ai_counter = devpriv->ai_timer; if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ devpriv->ai_sample_count--; if (devpriv->ai_sample_count < 0) { usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ /* acquistion is over, tell comedi */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); return; } } /* get the data from the USB bus and hand it over to comedi */ for (i = 0; i < cmd->chanlist_len; i++) { /* transfer data, note first byte is the DIO state */ val = be32_to_cpu(devpriv->in_buf[i+1]); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ ret = cfc_write_array_to_buffer(s, &val, sizeof(uint32_t)); if (unlikely(ret == 0)) { /* buffer overflow */ usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ return; } } /* tell comedi that data is there */ s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); comedi_event(dev, s); }
/* * This is called from the interrupt service routine to handle a read * scan on an 'INTERRUPT' subdevice. */ static int dio200_handle_read_intr(struct comedi_device *dev, struct comedi_subdevice *s) { const struct dio200_layout *layout = dio200_dev_layout(dev); struct dio200_subdev_intr *subpriv = s->private; unsigned triggered; unsigned intstat; unsigned cur_enabled; unsigned int oldevents; unsigned long flags; triggered = 0; spin_lock_irqsave(&subpriv->spinlock, flags); oldevents = s->async->events; if (layout->has_int_sce) { /* * Collect interrupt sources that have triggered and disable * them temporarily. Loop around until no extra interrupt * sources have triggered, at which point, the valid part of * the interrupt status register will read zero, clearing the * cause of the interrupt. * * Mask off interrupt sources already seen to avoid infinite * loop in case of misconfiguration. */ cur_enabled = subpriv->enabled_isns; while ((intstat = (dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns & ~triggered)) != 0) { triggered |= intstat; cur_enabled &= ~triggered; dio200_write8(dev, subpriv->ofs, cur_enabled); } } else { /* * No interrupt status register. Assume the single interrupt * source has triggered. */ triggered = subpriv->enabled_isns; } if (triggered) { /* * Some interrupt sources have triggered and have been * temporarily disabled to clear the cause of the interrupt. * * Reenable them NOW to minimize the time they are disabled. */ cur_enabled = subpriv->enabled_isns; if (layout->has_int_sce) dio200_write8(dev, subpriv->ofs, cur_enabled); if (subpriv->active) { /* * The command is still active. * * Ignore interrupt sources that the command isn't * interested in (just in case there's a race * condition). */ if (triggered & subpriv->enabled_isns) /* Collect scan data. */ dio200_read_scan_intr(dev, s, triggered); } } spin_unlock_irqrestore(&subpriv->spinlock, flags); if (oldevents != s->async->events) comedi_event(dev, s); return (triggered != 0); }