Commit cbe743f1 authored by Guido Kiener's avatar Guido Kiener Committed by Greg Kroah-Hartman
Browse files

usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN



Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.

Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.

Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.

Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.

Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.

Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.

Signed-off-by: default avatarGuido Kiener <guido.kiener@rohde-schwarz.com>
Reviewed-by: default avatarSteve Bayless <steve_bayless@keysight.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent dfee02ac
Loading
Loading
Loading
Loading
+51 −68
Original line number Diff line number Diff line
@@ -270,18 +270,17 @@ static int usbtmc_release(struct inode *inode, struct file *file)
	return 0;
}

static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
					  u8 tag)
{
	u8 *buffer;
	struct device *dev;
	int rv;
	int n;
	int actual;
	struct usb_host_interface *current_setting;
	int max_size;

	dev = &data->intf->dev;
	buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
	buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;

@@ -289,86 +288,87 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
			     usb_rcvctrlpipe(data->usb_dev, 0),
			     USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
			     data->bTag_last_read, data->bulk_in,
			     buffer, 2, USBTMC_TIMEOUT);
			     tag, data->bulk_in,
			     buffer, 2, USB_CTRL_GET_TIMEOUT);

	if (rv < 0) {
		dev_err(dev, "usb_control_msg returned %d\n", rv);
		goto exit;
	}

	dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
	dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
		buffer[0], buffer[1]);

	if (buffer[0] == USBTMC_STATUS_FAILED) {
		/* No transfer in progress and the Bulk-OUT FIFO is empty. */
		rv = 0;
		goto exit;
	}

	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
		dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
			buffer[0]);
		rv = -EPERM;
	if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
		/* The device returns this status if either:
		 * - There is a transfer in progress, but the specified bTag
		 *   does not match.
		 * - There is no transfer in progress, but the Bulk-OUT FIFO
		 *   is not empty.
		 */
		rv = -ENOMSG;
		goto exit;
	}

	max_size = 0;
	current_setting = data->intf->cur_altsetting;
	for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
		if (current_setting->endpoint[n].desc.bEndpointAddress ==
			data->bulk_in)
			max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);

	if (max_size == 0) {
		dev_err(dev, "Couldn't get wMaxPacketSize\n");
	if (buffer[0] != USBTMC_STATUS_SUCCESS) {
		dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
			buffer[0]);
		rv = -EPERM;
		goto exit;
	}

	dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size);

	n = 0;

	do {
usbtmc_abort_bulk_in_status:
	dev_dbg(dev, "Reading from bulk in EP\n");

	/* Data must be present. So use low timeout 300 ms */
	rv = usb_bulk_msg(data->usb_dev,
			  usb_rcvbulkpipe(data->usb_dev,
					  data->bulk_in),
				  buffer, USBTMC_SIZE_IOBUFFER,
				  &actual, USBTMC_TIMEOUT);
			  buffer, USBTMC_BUFSIZE,
			  &actual, 300);

	print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
			     buffer, actual, true);

	n++;

	if (rv < 0) {
		dev_err(dev, "usb_bulk_msg returned %d\n", rv);
		if (rv != -ETIMEDOUT)
			goto exit;
	}
	} while ((actual == max_size) &&
		 (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));

	if (actual == max_size) {
	if (actual == USBTMC_BUFSIZE)
		goto usbtmc_abort_bulk_in_status;

	if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
		rv = -EPERM;
		goto exit;
	}

	n = 0;

usbtmc_abort_bulk_in_status:
	rv = usb_control_msg(data->usb_dev,
			     usb_rcvctrlpipe(data->usb_dev, 0),
			     USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS,
			     USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
			     0, data->bulk_in, buffer, 0x08,
			     USBTMC_TIMEOUT);
			     USB_CTRL_GET_TIMEOUT);

	if (rv < 0) {
		dev_err(dev, "usb_control_msg returned %d\n", rv);
		goto exit;
	}

	dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
	dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);

	if (buffer[0] == USBTMC_STATUS_SUCCESS) {
		rv = 0;
@@ -376,43 +376,26 @@ usbtmc_abort_bulk_in_status:
	}

	if (buffer[0] != USBTMC_STATUS_PENDING) {
		dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
		rv = -EPERM;
		goto exit;
	}

	if (buffer[1] == 1)
		do {
			dev_dbg(dev, "Reading from bulk in EP\n");

			rv = usb_bulk_msg(data->usb_dev,
					  usb_rcvbulkpipe(data->usb_dev,
							  data->bulk_in),
					  buffer, USBTMC_SIZE_IOBUFFER,
					  &actual, USBTMC_TIMEOUT);

			n++;

			if (rv < 0) {
				dev_err(dev, "usb_bulk_msg returned %d\n", rv);
				goto exit;
			}
		} while ((actual == max_size) &&
			 (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));

	if (actual == max_size) {
		dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
			USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
		dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
		rv = -EPERM;
		goto exit;
	}

	if ((buffer[1] & 1) > 0) {
		/* The device has 1 or more queued packets the Host can read */
		goto usbtmc_abort_bulk_in_status;
	}

	/* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */
	rv = -EAGAIN;
exit:
	kfree(buffer);
	return rv;
}

static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
{
	return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
}

static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)