Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/errno.h>
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/usb.h>
0011 #include <linux/usb/ch11.h>
0012 
0013 #define TEST_SE0_NAK_PID            0x0101
0014 #define TEST_J_PID              0x0102
0015 #define TEST_K_PID              0x0103
0016 #define TEST_PACKET_PID             0x0104
0017 #define TEST_HS_HOST_PORT_SUSPEND_RESUME    0x0106
0018 #define TEST_SINGLE_STEP_GET_DEV_DESC       0x0107
0019 #define TEST_SINGLE_STEP_SET_FEATURE        0x0108
0020 
0021 extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
0022                         const struct usb_device_id *id);
0023 
0024 /*
0025  * A list of USB hubs which requires to disable the power
0026  * to the port before starting the testing procedures.
0027  */
0028 static const struct usb_device_id ehset_hub_list[] = {
0029     { USB_DEVICE(0x0424, 0x4502) },
0030     { USB_DEVICE(0x0424, 0x4913) },
0031     { USB_DEVICE(0x0451, 0x8027) },
0032     { }
0033 };
0034 
0035 static int ehset_prepare_port_for_testing(struct usb_device *hub_udev, u16 portnum)
0036 {
0037     int ret = 0;
0038 
0039     /*
0040      * The USB2.0 spec chapter 11.24.2.13 says that the USB port which is
0041      * going under test needs to be put in suspend before sending the
0042      * test command. Most hubs don't enforce this precondition, but there
0043      * are some hubs which needs to disable the power to the port before
0044      * starting the test.
0045      */
0046     if (usb_device_match_id(hub_udev, ehset_hub_list)) {
0047         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
0048                        USB_RT_PORT, USB_PORT_FEAT_ENABLE,
0049                        portnum, NULL, 0, 1000, GFP_KERNEL);
0050         /*
0051          * Wait for the port to be disabled. It's an arbitrary value
0052          * which worked every time.
0053          */
0054         msleep(100);
0055     } else {
0056         /*
0057          * For the hubs which are compliant with the spec,
0058          * put the port in SUSPEND.
0059          */
0060         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0061                        USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
0062                        portnum, NULL, 0, 1000, GFP_KERNEL);
0063     }
0064     return ret;
0065 }
0066 
0067 static int ehset_probe(struct usb_interface *intf,
0068                const struct usb_device_id *id)
0069 {
0070     int ret = -EINVAL;
0071     struct usb_device *dev = interface_to_usbdev(intf);
0072     struct usb_device *hub_udev = dev->parent;
0073     struct usb_device_descriptor buf;
0074     u8 portnum = dev->portnum;
0075     u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
0076 
0077     switch (test_pid) {
0078     case TEST_SE0_NAK_PID:
0079         ret = ehset_prepare_port_for_testing(hub_udev, portnum);
0080         if (!ret)
0081             break;
0082         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0083                        USB_RT_PORT, USB_PORT_FEAT_TEST,
0084                        (USB_TEST_SE0_NAK << 8) | portnum,
0085                        NULL, 0, 1000, GFP_KERNEL);
0086         break;
0087     case TEST_J_PID:
0088         ret = ehset_prepare_port_for_testing(hub_udev, portnum);
0089         if (!ret)
0090             break;
0091         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0092                        USB_RT_PORT, USB_PORT_FEAT_TEST,
0093                        (USB_TEST_J << 8) | portnum, NULL, 0,
0094                        1000, GFP_KERNEL);
0095         break;
0096     case TEST_K_PID:
0097         ret = ehset_prepare_port_for_testing(hub_udev, portnum);
0098         if (!ret)
0099             break;
0100         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0101                        USB_RT_PORT, USB_PORT_FEAT_TEST,
0102                        (USB_TEST_K << 8) | portnum, NULL, 0,
0103                        1000, GFP_KERNEL);
0104         break;
0105     case TEST_PACKET_PID:
0106         ret = ehset_prepare_port_for_testing(hub_udev, portnum);
0107         if (!ret)
0108             break;
0109         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0110                        USB_RT_PORT, USB_PORT_FEAT_TEST,
0111                        (USB_TEST_PACKET << 8) | portnum,
0112                        NULL, 0, 1000, GFP_KERNEL);
0113         break;
0114     case TEST_HS_HOST_PORT_SUSPEND_RESUME:
0115         /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
0116         msleep(15 * 1000);
0117         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0118                        USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
0119                        portnum, NULL, 0, 1000, GFP_KERNEL);
0120         if (ret < 0)
0121             break;
0122 
0123         msleep(15 * 1000);
0124         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
0125                        USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
0126                        portnum, NULL, 0, 1000, GFP_KERNEL);
0127         break;
0128     case TEST_SINGLE_STEP_GET_DEV_DESC:
0129         /* Test: wait for 15secs -> GetDescriptor request */
0130         msleep(15 * 1000);
0131 
0132         ret = usb_control_msg_recv(dev, 0, USB_REQ_GET_DESCRIPTOR,
0133                        USB_DIR_IN, USB_DT_DEVICE << 8, 0,
0134                        &buf, USB_DT_DEVICE_SIZE,
0135                        USB_CTRL_GET_TIMEOUT, GFP_KERNEL);
0136         break;
0137     case TEST_SINGLE_STEP_SET_FEATURE:
0138         /*
0139          * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
0140          *
0141          * Note, this test is only supported on root hubs since the
0142          * SetPortFeature handling can only be done inside the HCD's
0143          * hub_control callback function.
0144          */
0145         if (hub_udev != dev->bus->root_hub) {
0146             dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
0147             break;
0148         }
0149 
0150         ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
0151                        USB_RT_PORT, USB_PORT_FEAT_TEST,
0152                        (6 << 8) | portnum, NULL, 0,
0153                        60 * 1000, GFP_KERNEL);
0154 
0155         break;
0156     default:
0157         dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
0158             __func__, test_pid);
0159     }
0160 
0161     return ret;
0162 }
0163 
0164 static void ehset_disconnect(struct usb_interface *intf)
0165 {
0166 }
0167 
0168 static const struct usb_device_id ehset_id_table[] = {
0169     { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
0170     { USB_DEVICE(0x1a0a, TEST_J_PID) },
0171     { USB_DEVICE(0x1a0a, TEST_K_PID) },
0172     { USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
0173     { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
0174     { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
0175     { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
0176     { }         /* Terminating entry */
0177 };
0178 MODULE_DEVICE_TABLE(usb, ehset_id_table);
0179 
0180 static struct usb_driver ehset_driver = {
0181     .name =     "usb_ehset_test",
0182     .probe =    ehset_probe,
0183     .disconnect =   ehset_disconnect,
0184     .id_table = ehset_id_table,
0185 };
0186 
0187 module_usb_driver(ehset_driver);
0188 
0189 MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
0190 MODULE_LICENSE("GPL v2");