Commit 7c88f9f4 authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: usbduxfast: introduce usbduxfast_ai_handle_urb()

Factor the urb handling and resubmit out of the completion handler and
tidy it up. This allows a common exit path to be used in the completion
handler to stop the async command and handle the events.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Reviewed-by: default avatarBernd Porr <mail@berndporr.me.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 41ca22a8
......@@ -236,114 +236,87 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev,
return ret;
}
/*
* analogue IN
* interrupt service routine
*/
static void usbduxfast_ai_handle_urb(struct comedi_device *dev,
struct comedi_subdevice *s,
struct urb *urb)
{
struct usbduxfast_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
int ret;
if (devpriv->ignore) {
devpriv->ignore--;
} else {
unsigned int nbytes = urb->actual_length;
if (cmd->stop_src == TRIG_COUNT) {
unsigned int nsamples = nbytes / bytes_per_sample(s);
if (devpriv->ai_sample_count < nsamples) {
nsamples = devpriv->ai_sample_count;
async->events |= COMEDI_CB_EOA;
}
devpriv->ai_sample_count -= nsamples;
nbytes = nsamples * bytes_per_sample(s);
}
cfc_write_array_to_buffer(s, urb->transfer_buffer, nbytes);
}
/* if command is still running, resubmit urb for BULK transfer */
if (!(async->events & COMEDI_CB_CANCEL_MASK)) {
urb->dev = comedi_to_usb_dev(dev);
urb->status = 0;
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
dev_err(dev->class_dev, "urb resubm failed: %d", ret);
async->events |= COMEDI_CB_ERROR;
}
}
}
static void usbduxfast_ai_interrupt(struct urb *urb)
{
struct comedi_device *dev = urb->context;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
struct usb_device *usb = comedi_to_usb_dev(dev);
struct usbduxfast_private *devpriv = dev->private;
int n, err;
/* 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
*/
/* exit if not running a command, do not resubmit urb */
if (!devpriv->ai_cmd_running)
return;
}
/* first we test if something unusual has just happened */
switch (urb->status) {
case 0:
usbduxfast_ai_handle_urb(dev, s, urb);
break;
/*
* happens after an unlink command or when the device
* is plugged out
*/
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -ECONNABORTED:
/* tell this comedi */
async->events |= COMEDI_CB_EOA;
/* after an unlink command, unplug, ... etc */
async->events |= COMEDI_CB_ERROR;
comedi_event(dev, s);
/* stop the transfer w/o unlink */
usbduxfast_ai_stop(dev, 0);
return;
break;
default:
/* a real error */
dev_err(dev->class_dev,
"non-zero urb status received in ai intr context: %d\n",
urb->status);
async->events |= COMEDI_CB_EOA;
async->events |= COMEDI_CB_ERROR;
comedi_event(dev, s);
usbduxfast_ai_stop(dev, 0);
return;
}
if (!devpriv->ignore) {
if (cmd->stop_src == TRIG_COUNT) {
/* not continuous, fixed number of samples */
n = urb->actual_length / sizeof(uint16_t);
if (unlikely(devpriv->ai_sample_count < n)) {
unsigned int num_bytes;
/* partial sample received */
num_bytes = devpriv->ai_sample_count *
sizeof(uint16_t);
cfc_write_array_to_buffer(s,
urb->transfer_buffer,
num_bytes);
usbduxfast_ai_stop(dev, 0);
/* tell comedi that the acquistion is over */
async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
return;
}
devpriv->ai_sample_count -= n;
}
/* write the full buffer to comedi */
err = cfc_write_array_to_buffer(s, urb->transfer_buffer,
urb->actual_length);
if (unlikely(err == 0)) {
/* buffer overflow */
usbduxfast_ai_stop(dev, 0);
return;
}
/* tell comedi that data is there */
comedi_event(dev, s);
} else {
/* ignore this packet */
devpriv->ignore--;
break;
}
/*
* command is still running
* resubmit urb for BULK transfer
* comedi_handle_events() cannot be used in this driver. The (*cancel)
* operation would unlink the urb.
*/
urb->dev = usb;
urb->status = 0;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
dev_err(dev->class_dev,
"urb resubm failed: %d", err);
async->events |= COMEDI_CB_EOA;
async->events |= COMEDI_CB_ERROR;
comedi_event(dev, s);
if (async->events & COMEDI_CB_CANCEL_MASK)
usbduxfast_ai_stop(dev, 0);
}
comedi_event(dev, s);
}
static int usbduxfast_submit_urb(struct comedi_device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment