1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
6 #include <linux/kernel.h>
7 #include <linux/errno.h>
8 #include <linux/module.h>
9 #include <linux/slab.h>
10 #include <linux/usb.h>
11 #include <linux/usb/ch11.h>
13 #define TEST_SE0_NAK_PID 0x0101
14 #define TEST_J_PID 0x0102
15 #define TEST_K_PID 0x0103
16 #define TEST_PACKET_PID 0x0104
17 #define TEST_HS_HOST_PORT_SUSPEND_RESUME 0x0106
18 #define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107
19 #define TEST_SINGLE_STEP_SET_FEATURE 0x0108
21 extern const struct usb_device_id
*usb_device_match_id(struct usb_device
*udev
,
22 const struct usb_device_id
*id
);
25 * A list of USB hubs which requires to disable the power
26 * to the port before starting the testing procedures.
28 static const struct usb_device_id ehset_hub_list
[] = {
29 { USB_DEVICE(0x0424, 0x4502) },
30 { USB_DEVICE(0x0424, 0x4913) },
31 { USB_DEVICE(0x0451, 0x8027) },
35 static int ehset_prepare_port_for_testing(struct usb_device
*hub_udev
, u16 portnum
)
40 * The USB2.0 spec chapter 11.24.2.13 says that the USB port which is
41 * going under test needs to be put in suspend before sending the
42 * test command. Most hubs don't enforce this precondition, but there
43 * are some hubs which needs to disable the power to the port before
46 if (usb_device_match_id(hub_udev
, ehset_hub_list
)) {
47 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_CLEAR_FEATURE
,
48 USB_RT_PORT
, USB_PORT_FEAT_ENABLE
,
49 portnum
, NULL
, 0, 1000, GFP_KERNEL
);
51 * Wait for the port to be disabled. It's an arbitrary value
52 * which worked every time.
57 * For the hubs which are compliant with the spec,
58 * put the port in SUSPEND.
60 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
61 USB_RT_PORT
, USB_PORT_FEAT_SUSPEND
,
62 portnum
, NULL
, 0, 1000, GFP_KERNEL
);
67 static int ehset_probe(struct usb_interface
*intf
,
68 const struct usb_device_id
*id
)
71 struct usb_device
*dev
= interface_to_usbdev(intf
);
72 struct usb_device
*hub_udev
= dev
->parent
;
73 struct usb_device_descriptor buf
;
74 u8 portnum
= dev
->portnum
;
75 u16 test_pid
= le16_to_cpu(dev
->descriptor
.idProduct
);
78 case TEST_SE0_NAK_PID
:
79 ret
= ehset_prepare_port_for_testing(hub_udev
, portnum
);
82 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
83 USB_RT_PORT
, USB_PORT_FEAT_TEST
,
84 (USB_TEST_SE0_NAK
<< 8) | portnum
,
85 NULL
, 0, 1000, GFP_KERNEL
);
88 ret
= ehset_prepare_port_for_testing(hub_udev
, portnum
);
91 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
92 USB_RT_PORT
, USB_PORT_FEAT_TEST
,
93 (USB_TEST_J
<< 8) | portnum
, NULL
, 0,
97 ret
= ehset_prepare_port_for_testing(hub_udev
, portnum
);
100 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
101 USB_RT_PORT
, USB_PORT_FEAT_TEST
,
102 (USB_TEST_K
<< 8) | portnum
, NULL
, 0,
105 case TEST_PACKET_PID
:
106 ret
= ehset_prepare_port_for_testing(hub_udev
, portnum
);
109 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
110 USB_RT_PORT
, USB_PORT_FEAT_TEST
,
111 (USB_TEST_PACKET
<< 8) | portnum
,
112 NULL
, 0, 1000, GFP_KERNEL
);
114 case TEST_HS_HOST_PORT_SUSPEND_RESUME
:
115 /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
117 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
118 USB_RT_PORT
, USB_PORT_FEAT_SUSPEND
,
119 portnum
, NULL
, 0, 1000, GFP_KERNEL
);
124 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_CLEAR_FEATURE
,
125 USB_RT_PORT
, USB_PORT_FEAT_SUSPEND
,
126 portnum
, NULL
, 0, 1000, GFP_KERNEL
);
128 case TEST_SINGLE_STEP_GET_DEV_DESC
:
129 /* Test: wait for 15secs -> GetDescriptor request */
132 ret
= usb_control_msg_recv(dev
, 0, USB_REQ_GET_DESCRIPTOR
,
133 USB_DIR_IN
, USB_DT_DEVICE
<< 8, 0,
134 &buf
, USB_DT_DEVICE_SIZE
,
135 USB_CTRL_GET_TIMEOUT
, GFP_KERNEL
);
137 case TEST_SINGLE_STEP_SET_FEATURE
:
139 * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
141 * Note, this test is only supported on root hubs since the
142 * SetPortFeature handling can only be done inside the HCD's
143 * hub_control callback function.
145 if (hub_udev
!= dev
->bus
->root_hub
) {
146 dev_err(&intf
->dev
, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
150 ret
= usb_control_msg_send(hub_udev
, 0, USB_REQ_SET_FEATURE
,
151 USB_RT_PORT
, USB_PORT_FEAT_TEST
,
152 (6 << 8) | portnum
, NULL
, 0,
153 60 * 1000, GFP_KERNEL
);
157 dev_err(&intf
->dev
, "%s: unsupported PID: 0x%x\n",
164 static void ehset_disconnect(struct usb_interface
*intf
)
168 static const struct usb_device_id ehset_id_table
[] = {
169 { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID
) },
170 { USB_DEVICE(0x1a0a, TEST_J_PID
) },
171 { USB_DEVICE(0x1a0a, TEST_K_PID
) },
172 { USB_DEVICE(0x1a0a, TEST_PACKET_PID
) },
173 { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME
) },
174 { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC
) },
175 { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE
) },
176 { } /* Terminating entry */
178 MODULE_DEVICE_TABLE(usb
, ehset_id_table
);
180 static struct usb_driver ehset_driver
= {
181 .name
= "usb_ehset_test",
182 .probe
= ehset_probe
,
183 .disconnect
= ehset_disconnect
,
184 .id_table
= ehset_id_table
,
187 module_usb_driver(ehset_driver
);
189 MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
190 MODULE_LICENSE("GPL v2");