Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+52 −79
Original line number Diff line number Diff line
@@ -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)