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); } }
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); } }