linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] usb: misc: ehset: Workaround for "special" hubs
@ 2021-09-10 12:46 Razvan Heghedus
  2021-09-10 12:58 ` Greg Kroah-Hartman
  0 siblings, 1 reply; 2+ messages in thread
From: Razvan Heghedus @ 2021-09-10 12:46 UTC (permalink / raw)
  Cc: Razvan.Heghedus, Greg Kroah-Hartman, Peter Chen, Johan Hovold,
	Anant Thazhemadam, linux-usb, linux-kernel

The USB2.0 spec chapter 11.24.2.13 says that the USB port which is going
under test needs to be put in suspend state before sending the test
command. Many hubs, don't enforce this precondition and they work fine
without this step. But there are some "special" hubs, which requires to
disable the port power before sending the test command.

Because the USB spec mention that the port should be suspended, also
do this step before sending the test command. This could rise the
problem with other hubs which are not compliant with the spec and the
test command will not work if the port is suspend. If such hubs are
found, a similar workaround like the disable part could be implemented
to skip the suspend port command.

Signed-off-by: Razvan Heghedus <Razvan.Heghedus@garmin.com>
---
 drivers/usb/misc/ehset.c | 78 +++++++++++++++++++++++++++++++---------
 1 file changed, 62 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
index f87890f9cd26..169f10efd163 100644
--- a/drivers/usb/misc/ehset.c
+++ b/drivers/usb/misc/ehset.c
@@ -18,6 +18,44 @@
 #define TEST_SINGLE_STEP_GET_DEV_DESC          0x0107
 #define TEST_SINGLE_STEP_SET_FEATURE           0x0108

+/* A list of USB hubs which requires to disable the power
+ * to the port before starting the testing procedures.
+ */
+static const struct usb_device_id ehset_hub_list[] = {
+       {USB_DEVICE(0x0424, 0x4502)},
+       {USB_DEVICE(0x0424, 0x4913)},
+       {USB_DEVICE(0x0451, 0x8027)},
+       {}
+};
+
+static int ehset_prepare_port_for_testing(struct usb_device *hub_udev, u16 portnum)
+{
+       int ret = 0;
+       /* The USB2.0 spec chapter 11.24.2.13 says that the USB port which is
+        * going under test needs to be put in suspend before sending the
+        * test command. Most hubs don't enforce this precondition, but there
+        * are some hubs which needs to disable the power to the port before
+        * starting the test.
+        */
+       if (usb_match_id(to_usb_interface(hub_udev->dev.parent), ehset_hub_list)) {
+               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
+                                          USB_RT_PORT, USB_PORT_FEAT_ENABLE,
+                                          portnum, NULL, 0, 1000, GFP_KERNEL);
+               /* Wait for the port to be disabled. It's an arbitrary value
+                * which worked every time.
+                */
+               msleep(100);
+       } else {
+               /* For the hubs which are compliant with the spec,
+                * put the port in SUSPEND.
+                */
+               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+                                          USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
+                                          portnum, NULL, 0, 1000, GFP_KERNEL);
+       }
+       return ret;
+}
+
 static int ehset_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
 {
@@ -30,28 +68,36 @@ static int ehset_probe(struct usb_interface *intf,

        switch (test_pid) {
        case TEST_SE0_NAK_PID:
-               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-                                          USB_RT_PORT, USB_PORT_FEAT_TEST,
-                                          (USB_TEST_SE0_NAK << 8) | portnum,
-                                          NULL, 0, 1000, GFP_KERNEL);
+               ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+               if (!ret)
+                       ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+                                                  USB_RT_PORT, USB_PORT_FEAT_TEST,
+                                                  (USB_TEST_SE0_NAK << 8) | portnum,
+                                                  NULL, 0, 1000, GFP_KERNEL);
                break;
        case TEST_J_PID:
-               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-                                          USB_RT_PORT, USB_PORT_FEAT_TEST,
-                                          (USB_TEST_J << 8) | portnum, NULL, 0,
-                                          1000, GFP_KERNEL);
+               ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+               if (!ret)
+                       ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+                                                  USB_RT_PORT, USB_PORT_FEAT_TEST,
+                                                  (USB_TEST_J << 8) | portnum, NULL, 0,
+                                                  1000, GFP_KERNEL);
                break;
        case TEST_K_PID:
-               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-                                          USB_RT_PORT, USB_PORT_FEAT_TEST,
-                                          (USB_TEST_K << 8) | portnum, NULL, 0,
-                                          1000, GFP_KERNEL);
+               ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+               if (!ret)
+                       ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+                                                  USB_RT_PORT, USB_PORT_FEAT_TEST,
+                                                  (USB_TEST_K << 8) | portnum, NULL, 0,
+                                                  1000, GFP_KERNEL);
                break;
        case TEST_PACKET_PID:
-               ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-                                          USB_RT_PORT, USB_PORT_FEAT_TEST,
-                                          (USB_TEST_PACKET << 8) | portnum,
-                                          NULL, 0, 1000, GFP_KERNEL);
+               ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+               if (!ret)
+                       ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+                                                  USB_RT_PORT, USB_PORT_FEAT_TEST,
+                                                  (USB_TEST_PACKET << 8) | portnum,
+                                                  NULL, 0, 1000, GFP_KERNEL);
                break;
        case TEST_HS_HOST_PORT_SUSPEND_RESUME:
                /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
--
2.33.0

Handelsregister beim Amtsgericht Würzburg / Commercial Register Würzburg HRB 11347
Geschäftsführer / Managing Directors: Johannes Angenvoort, Mike Wiegers, Andrew Etkind

This Email, including any attachment/s, is confidential and intended only for the individuals or company named above. If you are not the intended recipient, please do not read, copy, use or disclose the contents of this communication to others. Please notify the sender that you have received this e-mail in error, by calling the phone number indicated or by Email, and delete the Email, including any attachment, subsequently. The information contained in this Email may be subject to professional secrecy (e. g. of auditor, tax or legal advisor), other privilege or otherwise be protected by work product immunity or other legal rules. Thank you.

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] usb: misc: ehset: Workaround for "special" hubs
  2021-09-10 12:46 [PATCH] usb: misc: ehset: Workaround for "special" hubs Razvan Heghedus
@ 2021-09-10 12:58 ` Greg Kroah-Hartman
  0 siblings, 0 replies; 2+ messages in thread
From: Greg Kroah-Hartman @ 2021-09-10 12:58 UTC (permalink / raw)
  To: Razvan Heghedus
  Cc: Peter Chen, Johan Hovold, Anant Thazhemadam, linux-usb, linux-kernel

On Fri, Sep 10, 2021 at 03:46:10PM +0300, Razvan Heghedus wrote:
> This Email, including any attachment/s, is confidential and intended only for the individuals or company named above. If you are not the intended recipient, please do not read, copy, use or disclose the contents of this communication to others. Please notify the sender that you have received this e-mail in error, by calling the phone number indicated or by Email, and delete the Email, including any attachment, subsequently. The information contained in this Email may be subject to professional secrecy (e. g. of auditor, tax or legal advisor), other privilege or otherwise be protected by work product immunity or other legal rules. Thank you.

Now deleted as this is not ok to have on a kernel patch :(

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-09-10 13:20 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-10 12:46 [PATCH] usb: misc: ehset: Workaround for "special" hubs Razvan Heghedus
2021-09-10 12:58 ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).