From 7c88f9f48c6fcf31aeda755b723befad642150ca Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 14 Oct 2014 12:14:39 -0700 Subject: [PATCH] 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: H Hartley Sweeten Reviewed-by: Ian Abbott Reviewed-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxfast.c | 131 ++++++++------------ 1 file changed, 52 insertions(+), 79 deletions(-) diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index cddc2ba294bb..95c2ec7ed22a 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -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) -- 2.30.2