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

Commit d2ddce37 authored by Alexandre Peixoto Ferreira's avatar Alexandre Peixoto Ferreira Committed by Greg Kroah-Hartman
Browse files

USB: usbtmc: usbtmc_read sends multiple TMC header based on rigol_quirk



These patches implement a modification of the USBTMC
protocol to allow operation with Rigol equipment. The usbtmc_read function is
modified so if the quirk is active, the TMC header is sent with the size of
the data as the whole size of the request. If the quirk is inactive, the TMC
request is sent once per bulk transfer and with size limited to the bulk
transfer size. In the case of the quirk, only the first response contains the
TMC header and the others are just data.

Signed-off-by: default avatarAlexandre Peixoto Ferreira <alexandref75@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c2e31483
Loading
Loading
Loading
Loading
+114 −38
Original line number Diff line number Diff line
@@ -455,12 +455,29 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
		goto exit;
	}

	if (data->rigol_quirk) {
		dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);

		retval = send_request_dev_dep_msg_in(data, count);

		if (retval < 0) {
			if (data->auto_abort)
				usbtmc_ioctl_abort_bulk_out(data);
			goto exit;
		}
	}

	/* Loop until we have fetched everything we requested */
	remaining = count;
	this_part = remaining;
	done = 0;

	while (remaining > 0) {
		if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3)
			this_part = USBTMC_SIZE_IOBUFFER - 12 - 3;
		if (!(data->rigol_quirk)) {
			dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);

			if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
				this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3;
			else
				this_part = remaining;

@@ -471,6 +488,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
					usbtmc_ioctl_abort_bulk_out(data);
				goto exit;
			}
		}

		/* Send bulk URB */
		retval = usb_bulk_msg(data->usb_dev,
@@ -479,11 +497,37 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
				      buffer, USBTMC_SIZE_IOBUFFER, &actual,
				      USBTMC_TIMEOUT);

		dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);

		/* Store bTag (in case we need to abort) */
		data->bTag_last_read = data->bTag;

		if (retval < 0) {
			dev_err(dev, "Unable to read data, error %d\n", retval);
			dev_dbg(dev, "Unable to read data, error %d\n", retval);
			if (data->auto_abort)
				usbtmc_ioctl_abort_bulk_in(data);
			goto exit;
		}

		/* Parse header in first packet */
		if ((done == 0) || (!(data->rigol_quirk))) {
			/* Sanity checks for the header */
			if (actual < USBTMC_HEADER_SIZE) {
				dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
				if (data->auto_abort)
					usbtmc_ioctl_abort_bulk_in(data);
				goto exit;
			}

			if (buffer[0] != 2) {
				dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]);
				if (data->auto_abort)
					usbtmc_ioctl_abort_bulk_in(data);
				goto exit;
			}

			if (buffer[1] != data->bTag_last_write) {
				dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write);
				if (data->auto_abort)
					usbtmc_ioctl_abort_bulk_in(data);
				goto exit;
@@ -495,35 +539,67 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
				       (buffer[6] << 16) +
				       (buffer[7] << 24);

		/* Ensure the instrument doesn't lie about it */
		if(n_characters > actual - 12) {
			dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12);
			n_characters = actual - 12;
			if (n_characters > this_part) {
				dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count);
				if (data->auto_abort)
					usbtmc_ioctl_abort_bulk_in(data);
				goto exit;
			}

		/* Ensure the instrument doesn't send more back than requested */
		if(n_characters > this_part) {
			dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
			n_characters = this_part;
			/* Remove the USBTMC header */
			actual -= USBTMC_HEADER_SIZE;

			/* Check if the message is smaller than requested */
			if (data->rigol_quirk) {
				if (remaining > n_characters)
					remaining = n_characters;
				/* Remove padding if it exists */
				if (actual > remaining) 
					actual = remaining;
			}
			else {
				if (this_part > n_characters)
					this_part = n_characters;
				/* Remove padding if it exists */
				if (actual > this_part) 
					actual = this_part;
			}

			dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]);

			remaining -= actual;

			/* Terminate if end-of-message bit received from device */
			if ((buffer[8] &  0x01) && (actual >= n_characters))
				remaining = 0;

			dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);

		/* Bound amount of data received by amount of data requested */
		if (n_characters > this_part)
			n_characters = this_part;

			/* Copy buffer to user space */
		if (copy_to_user(buf + done, &buffer[12], n_characters)) {
			if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) {
				/* There must have been an addressing problem */
				retval = -EFAULT;
				goto exit;
			}
			done += actual;
		}
		else  {
			if (actual > remaining) 
				actual = remaining;

		done += n_characters;
		/* Terminate if end-of-message bit received from device */
		if ((buffer[8] &  0x01) && (actual >= n_characters + 12))
			remaining = 0;
		else
			remaining -= n_characters;
			remaining -= actual;

			dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer);

			/* Copy buffer to user space */
			if (copy_to_user(buf + done, buffer, actual)) {
				/* There must have been an addressing problem */
				retval = -EFAULT;
				goto exit;
			}
			done += actual;
		}
	}

	/* Update file position value */