static int usbduxsigma_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct usbduxsigma_private *devpriv = dev->private; down(&devpriv->sem); /* unlink only if it is really running */ usbduxsigma_ao_stop(dev, devpriv->ao_cmd_running); up(&devpriv->sem); return 0; }
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 void usbduxsigma_detach(struct comedi_device *dev) { struct usb_interface *intf = comedi_to_usb_interface(dev); struct usbduxsigma_private *devpriv = dev->private; usb_set_intfdata(intf, NULL); if (!devpriv) return; down(&devpriv->sem); /* force unlink all urbs */ usbduxsigma_ai_stop(dev, 1); usbduxsigma_ao_stop(dev, 1); usbduxsigma_pwm_stop(dev, 1); usbduxsigma_free_usb_buffers(dev); up(&devpriv->sem); }
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); } }