static int usbduxsigma_ai_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_ai_stop(dev, devpriv->ai_cmd_running); up(&devpriv->sem); return 0; }
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); }
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_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); }