Skip to contentSkip to conversation

usb: misc: cypress_cy7c63: check control transfer status

PATCH In review Keshav Verma 3 participants 7 messages Jun 18 – Jul 10 USB

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 usb: misc: cypress_cy7c63: check control transfer status

read_port() currently ignores errors from vendor_command() and always returns the cached port value. This can report stale data when the USB control transfer fails or returns a short response.

Return the underlying error for failed transfers and report -EIO if the device returns fewer bytes than required.

Fixes 9189bfc2df0f ("[PATCH] USB: rename Cypress CY7C63xxx driver to proper name and fix up some tiny things")
---
 drivers/usb/misc/cypress_cy7c63.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/misc/cypress_cy7c63.c +4 -0
index 4a7f955ba85b..8601ee0a1ea3 100644
@@ -177,6 +177,10 @@ static ssize_t read_port(struct device *dev, struct device_attribute *attr,
 	result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
 
 	dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+	if (result < 0)
+		return result;
+	if (result < 2)
+		return -EIO;
 
 	return sprintf(buf, "%d", cyp->port[port_num]);
 }
Signature · 1 line
2.39.5
maintainer
#1 lore raw
Quoted 18 lines · Keshav Verma

read_port() currently ignores errors from vendor_command() and always returns the cached port value. This can report stale data when the USB control transfer fails or returns a short response.

Return the underlying error for failed transfers and report -EIO if the device returns fewer bytes than required.

Fixes 9189bfc2df0f ("[PATCH] USB: rename Cypress CY7C63xxx driver to proper name and fix up some tiny things")
---
 drivers/usb/misc/cypress_cy7c63.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/misc/cypress_cy7c63.c +0 -0
index 4a7f955ba85b..8601ee0a1ea3 100644

drivers/usb/misc/cypress_cy7c63.c static ssize_t read_port(struct device *dev, struct device_attribute *attr, · line 186

Quoted 10 lines
drivers/usb/misc/cypress_cy7c63.c +4 -0
@@ -177,6 +177,10 @@ static ssize_t read_port(struct device *dev, struct device_attribute *attr,
 	result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
 
 	dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+	if (result < 0)
+		return result;
+	if (result < 2)
+		return -EIO;
 
 	return sprintf(buf, "%d", cyp->port[port_num]);
 }

You only changed one call to vendor_command() here, why? Why not fix this all up by changing vendor_command() to use a better function that will give you a sane error value, and then check that?

Start with this patch:

drivers/usb/misc/cytherm.c +4 -6
index d26f460ecdbc..86c4678e23b3 100644
@@ -51,12 +51,10 @@ static int vendor_command(struct usb_device *dev, unsigned char request,
 			  unsigned char value, unsigned char index,
 			  void *buf, int size)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-			       request, 
-			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
-			       value, 
-			       index, buf, size,
-			       USB_CTRL_GET_TIMEOUT);
+	return usb_control_msg_recv(dev, 0, request,
+				    USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+				    value, index, buf, size,
+				    USB_CTRL_GET_TIMEOUT, GFP_KERNEL);
 }
 
 

And go from there!

thanks,

greg k-h

#2 lore raw

Hi Greg,

Thanks for the review.
I'll rework the patch as suggested.

I may be a couple of days before I can send the updated patch, but I'll get a revised version posted as soon as I can.

Thanks,
Keshav

#3 lore raw

read_port() currently ignores errors from vendor_command() and always returns the cached port value. This can report stale data when the USB control transfer fails or returns a short response.

Convert vendor_command() to usb_control_msg_recv(), which returns 0 on success and a negative errno on failure, and propagate transport errors from read_port() instead of returning cached data.

Fixes 9189bfc2df0f ("[PATCH] USB: rename Cypress CY7C63xxx driver to

proper name and fix up some tiny things")

---
v2:
- Use usb_control_msg_recv() in vendor_command().
- Remove the obsolete short-transfer check.

 drivers/usb/misc/cypress_cy7c63.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)
(quoted diff) +0 -0

b/drivers/usb/misc/cypress_cy7c63.c
index 4a7f955ba85b..47cb05c3a870 100644

drivers/usb/misc/cypress_cy7c63.c +1 -2
@@ -69,8 +69,7 @@ struct cypress {
 static int vendor_command(struct cypress *dev, unsigned char request,
                          unsigned char address, unsigned char data)
 {
-       int retval = 0;
-       unsigned int pipe;
+       int retval;
        unsigned char *iobuf;
 
        /* allocate some memory for the i/o buffer*/
@@ -80,17 +79,19 @@ static int vendor_command(struct cypress *dev,

unsigned char request,

                goto error;
        }

- dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
-

-       /* prepare usb control message and send it upstream */
-       pipe = usb_rcvctrlpipe(dev->udev, 0);
-       retval = usb_control_msg(dev->udev, pipe, request,
-                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
-                                address, data, iobuf, CYPRESS_MAX_REQSIZE,
-                                USB_CTRL_GET_TIMEOUT);
-       /* we must not process garbage */
-       if (retval < 2)
+       dev_dbg(&dev->udev->dev, "Sending usb_control_msg_recv (data:
%d)\n", data);
+
+       retval = usb_control_msg_recv(dev->udev, 0, request,
+                               USB_DIR_IN | USB_TYPE_VENDOR |
+                               USB_RECIP_OTHER,
+                               address, data, iobuf,
+                               CYPRESS_MAX_REQSIZE,
+                               USB_CTRL_GET_TIMEOUT,
+                               GFP_KERNEL);
+       if (retval < 0) {
+               dev_err(&dev->udev->dev, "usb_control_msg_recv failed:
%d\n", retval);
                goto err_buf;

+ }

        /* store returned data (more READs to be added) */
        switch (request) {
@@ -177,6 +178,8 @@ static ssize_t read_port(struct device *dev,
struct device_attribute *attr,
        result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);

        dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);

+ if (result < 0)
+ return result;

        return sprintf(buf, "%d", cyp->port[port_num]);

}
--
2.39.5

#4 lore raw
Quoted 7 lines · Keshav Verma

read_port() currently ignores errors from vendor_command() and always returns the cached port value. This can report stale data when the USB control transfer fails or returns a short response.

Convert vendor_command() to usb_control_msg_recv(), which returns 0 on success and a negative errno on failure, and propagate transport errors from read_port() instead of returning cached data.

Hi,

Thank you for making a patch for this issue.
I am sorry, but this approach mixes issues that are real with something that is not a problem.

Review

Quoted 10 lines
Fixes 9189bfc2df0f ("[PATCH] USB: rename Cypress CY7C63xxx driver to

proper name and fix up some tiny things")

---
v2:

(quoted diff) +0 -4
-       retval = usb_control_msg(dev->udev, pipe, request,
-                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
-                                address, data, iobuf, CYPRESS_MAX_REQSIZE,
-                                USB_CTRL_GET_TIMEOUT);

This does return errors.

Review

Quoted 6 lines
(quoted diff) +1 -2
-       /* we must not process garbage */
-       if (retval < 2)
+       dev_dbg(&dev->udev->dev, "Sending usb_control_msg_recv (data:

%d)\n", data);

(quoted diff) +2 -0
+
+       retval = usb_control_msg_recv(dev->udev, 0, request,

There is no point in this change. You just allocate yet another buffer for no gain.

Regards
Oliver

#5 lore raw
Quoted 6 lines · Oliver Neukum

There is no point in this change. You just allocate yet another buffer for no gain.

Regards
Oliver

Hi,

Thanks for the review.

The bug I was trying to address is that read_port() ignores the return value from vendor_command() and can return stale cached data after a failed control transfer.

I updated vendor_command() to use usb_control_msg_recv() based on review feedback on the previous version.

Would you prefer that I keep the existing usb_control_msg() implementation and resend a v3 containing only the stale data fix?

Thanks,
Keshav Verma

maintainer
#6 lore raw
In reply to Oliver Neukum
Quoted 20 lines · Oliver Neukum
Quoted 7 lines · Keshav Verma

read_port() currently ignores errors from vendor_command() and always returns the cached port value. This can report stale data when the USB control transfer fails or returns a short response.

Convert vendor_command() to usb_control_msg_recv(), which returns 0 on success and a negative errno on failure, and propagate transport errors from read_port() instead of returning cached data.

Hi,

Thank you for making a patch for this issue.
I am sorry, but this approach mixes issues that are real with something that is not a problem.

Quoted 5 lines
Fixes 9189bfc2df0f ("[PATCH] USB: rename Cypress CY7C63xxx driver to

proper name and fix up some tiny things")

---
v2:

Quoted 6 lines

Review

Quoted 4 lines
(quoted diff) +0 -4
-       retval = usb_control_msg(dev->udev, pipe, request,
-                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
-                                address, data, iobuf, CYPRESS_MAX_REQSIZE,
-                                USB_CTRL_GET_TIMEOUT);

This does return errors.

Yes, but they are not checked properly, as your patch showed.

Quoted 9 lines

Review

Quoted 6 lines
(quoted diff) +1 -2
-       /* we must not process garbage */
-       if (retval < 2)
+       dev_dbg(&dev->udev->dev, "Sending usb_control_msg_recv (data:

%d)\n", data);

(quoted diff) +2 -0
+
+       retval = usb_control_msg_recv(dev->udev, 0, request,

There is no point in this change. You just allocate yet another buffer for no gain.

That's not an issue, we should be moving all drivers away from usb_control_msg() as it's used wrong so many times (like this one.)

So I think this is the correct thing to be doing here.

thanks,

greg k-h