staging: comedi: usbduxfast: introduce usbduxfast_ai_handle_urb()
authorH Hartley Sweeten <hsweeten@visionengravers.com>
Tue, 14 Oct 2014 19:14:39 +0000 (12:14 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Oct 2014 07:52:14 +0000 (15:52 +0800)
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 <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Reviewed-by: Bernd Porr <mail@berndporr.me.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/comedi/drivers/usbduxfast.c

index cddc2ba294bb0a1b9c824c1b8a8fdb229228daaa..95c2ec7ed22a1c0b53072bb24b126d75e493b965 100644 (file)
@@ -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)