Bug 1806468 [wpt PR 37579] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / testing / web-platform / tests / webusb / usbDevice_controlTransferIn-manual.https.html
blobc39e255e2bda421ec4d78acf07dae6990969ed3b
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 <script src="/resources/testharness.js"></script>
7 <script src="/resources/testharnessreport.js"></script>
8 <script src="resources/manual.js"></script>
9 </head>
10 <body>
11 <p>
12 These tests require a USB device to be connected.
13 </p>
14 <script>
15 const kGetDescriptorRequest = 0x06;
17 const kDeviceDescriptorType = 0x01;
18 const kDeviceDescriptorLength = 18;
20 const kConfigurationDescriptorType = 0x02;
21 const kConfigurationDescriptorLength = 9;
23 const kStringDescriptorType = 0x03;
24 const kStringDescriptorMaxLength = 0xFF;
26 const kInterfaceDescriptorType = 0x04;
27 const kInterfaceDescriptorLength = 9;
29 const kEndpointDescriptorType = 0x05;
30 const kEndpointDescriptorLength = 7;
32 let device = null;
33 let pending_subtests = 0;
34 const string_tests = new Set();
35 const string_languages = [];
37 async function subtest_complete() {
38 if (--pending_subtests == 0) {
39 await device.close();
43 function manual_usb_subtest(func, name, properties) {
44 pending_subtests++;
45 promise_test(async (test) => {
46 test.add_cleanup(subtest_complete);
47 await func(test);
48 }, name, properties);
51 function read_string(index, expected) {
52 // A device may use the same string in multiple places. Don't bother
53 // repeating the test.
54 if (string_tests.has(index)) {
55 return;
57 string_tests.add(index);
59 const string_values = new Set();
60 const decoder = new TextDecoder('utf-16le');
62 for (const language of string_languages) {
63 const language_string = language.toString(16).padStart(4, '0');
64 manual_usb_subtest(async (t) => {
65 if (expected != undefined) {
66 t.add_cleanup(() => {
67 if (string_values.size == string_languages.length) {
68 assert_true(string_values.has(expected));
70 });
73 const result = await device.controlTransferIn({
74 requestType: 'standard',
75 recipient: 'device',
76 request: kGetDescriptorRequest,
77 value: kStringDescriptorType << 8 | index,
78 index: language
79 }, kStringDescriptorMaxLength);
81 assert_equals(result.status, 'ok', 'transfer status');
82 const length = result.data.getUint8(0);
83 assert_greater_than_equal(length, 2, 'descriptor length');
84 assert_equals(result.data.byteLength, length, 'transfer length');
85 assert_equals(result.data.getUint8(1), kStringDescriptorType,
86 'descriptor type');
87 const string_buffer = new Uint8Array(
88 result.data.buffer, result.data.byteOffset + 2, length - 2);
89 string_values.add(decoder.decode(string_buffer));
91 `Read string descriptor ${index} in language 0x${language_string}`);
95 function check_interface_descriptor(configuration, data) {
96 assert_greater_than_equal(
97 data.getUint8(0), kInterfaceDescriptorLength, 'descriptor length');
99 const interface_number = data.getUint8(2);
100 const iface = configuration.interfaces.find((iface) => {
101 return iface.interfaceNumber == interface_number;
103 assert_not_equals(
104 iface, undefined, `unknown interface ${interface_number}`);
106 const alternate_setting = data.getUint8(3);
107 const alternate = iface.alternates.find((alternate) => {
108 return alternate.alternateSetting == alternate_setting;
110 assert_not_equals(
111 alternate, undefined, `unknown alternate ${alternate_setting}`);
113 assert_equals(data.getUint8(4), alternate.endpoints.length,
114 'number of endpoints');
115 assert_equals(
116 data.getUint8(5), alternate.interfaceClass, 'interface class');
117 assert_equals(data.getUint8(6), alternate.interfaceSubclass,
118 'interface subclass');
119 assert_equals(data.getUint8(7), alternate.interfaceProtocol,
120 'interface protocol');
122 const interface_string = data.getUint8(8);
123 if (interface_string != 0) {
124 // TODO(crbug.com/727819): Check that the string descriptor matches
125 // iface.interfaceName.
126 read_string(interface_string);
129 return alternate;
132 function check_endpoint_descriptor(alternate, data) {
133 assert_greater_than_equal(
134 data.getUint8(0), kEndpointDescriptorLength, 'descriptor length');
136 const endpoint_address = data.getUint8(2);
137 const direction = endpoint_address & 0x80 ? 'in' : 'out';
138 const endpoint_number = endpoint_address & 0x0f;
139 const endpoint = alternate.endpoints.find((endpoint) => {
140 return endpoint.direction == direction &&
141 endpoint.endpointNumber == endpoint_number;
143 assert_not_equals(
144 endpoint, undefined, `unknown endpoint ${endpoint_number}`);
146 const attributes = data.getUint8(3);
147 switch (attributes & 0x03) {
148 case 0:
149 assert_equals(endpoint.type, 'control', 'endpoint type');
150 break;
151 case 1:
152 assert_equals(endpoint.type, 'isochronous', 'endpoint type');
153 break;
154 case 2:
155 assert_equals(endpoint.type, 'bulk', 'endpoint type');
156 break;
157 case 3:
158 assert_equals(endpoint.type, 'interrupt', 'endpoint type');
159 break;
162 assert_equals(data.getUint16(4, /*littleEndian=*/true),
163 endpoint.packetSize, 'packet size');
166 function read_config_descriptor(config_value) {
167 manual_usb_subtest(async (t) => {
168 const configuration = device.configurations.find((config) => {
169 return config.configurationValue == config_value;
171 assert_not_equals(configuration, undefined);
173 let result = await device.controlTransferIn({
174 requestType: 'standard',
175 recipient: 'device',
176 request: kGetDescriptorRequest,
177 value: kConfigurationDescriptorType << 8 | (config_value - 1),
178 index: 0
179 }, kConfigurationDescriptorLength);
181 assert_equals(result.status, 'ok', 'transfer status');
182 let length = result.data.getUint8(0);
183 assert_greater_than_equal(
184 length, kConfigurationDescriptorLength, 'descriptor length');
185 assert_equals(result.data.byteLength, length, 'transfer length');
186 const total_length = result.data.getUint16(2, /*littleEndian=*/true);
188 result = await device.controlTransferIn({
189 requestType: 'standard',
190 recipient: 'device',
191 request: kGetDescriptorRequest,
192 value: kConfigurationDescriptorType << 8 | (config_value - 1),
193 index: 0
194 }, total_length);
196 assert_equals(result.status, 'ok', 'transfer status');
197 assert_equals(
198 result.data.byteLength, total_length, 'transfer length');
199 assert_equals(result.data.getUint8(0), length, 'descriptor length');
200 assert_equals(result.data.getUint8(1), kConfigurationDescriptorType,
201 'descriptor type');
202 assert_equals(result.data.getUint16(2, /*littleEndian=*/true),
203 total_length, 'total length');
204 assert_equals(
205 result.data.getUint8(4), configuration.interfaces.length,
206 'number of interfaces');
207 assert_equals(
208 result.data.getUint8(5), config_value, 'configuration value');
210 const configuration_string = result.data.getUint8(6);
211 if (configuration_string != 0) {
212 // TODO(crbug.com/727819): Check that the string descriptor matches
213 // configuration.configurationName.
214 read_string(configuration_string);
217 let offset = length;
218 let alternate = undefined;
219 while (offset < total_length) {
220 length = result.data.getUint8(offset);
221 assert_less_than_equal(offset + length, total_length);
223 const view = new DataView(
224 result.data.buffer, result.data.byteOffset + offset, length);
225 switch (view.getUint8(1)) {
226 case kConfigurationDescriptorType:
227 assert_unreached('cannot contain multiple config descriptors');
228 break;
229 case kInterfaceDescriptorType:
230 alternate = check_interface_descriptor(configuration, view);
231 break;
232 case kEndpointDescriptorType:
233 assert_not_equals(alternate, undefined,
234 'endpoint not defined after interface');
235 check_endpoint_descriptor(alternate, view);
236 break;
239 offset += length;
241 }, `Read config descriptor ${config_value}`);
244 function read_string_descriptor_languages(device_descriptor) {
245 manual_usb_subtest(async (t) => {
246 const result = await device.controlTransferIn({
247 requestType: 'standard',
248 recipient: 'device',
249 request: kGetDescriptorRequest,
250 value: kStringDescriptorType << 8,
251 index: 0
252 }, kStringDescriptorMaxLength);
254 assert_equals(result.status, 'ok', 'transfer status');
255 assert_equals(result.data.getUint8(1), kStringDescriptorType,
256 'descriptor type');
257 const length = result.data.getUint8(0);
258 assert_greater_than_equal(length, 2, 'descriptor length')
259 assert_greater_than_equal(
260 result.data.byteLength, length, 'transfer length');
262 for (let index = 2; index < length; index += 2) {
263 string_languages.push(
264 result.data.getUint16(index, /*littleEndian=*/true));
267 const manufacturer_string = device_descriptor.getUint8(14);
268 if (manufacturer_string != 0) {
269 assert_not_equals(device.manufacturerName, undefined);
270 read_string(manufacturer_string, device.manufacturerName);
273 const product_string = device_descriptor.getUint8(15);
274 if (product_string != 0) {
275 assert_not_equals(device.productName, undefined);
276 read_string(product_string, device.productName);
279 const serial_number_string = device_descriptor.getUint8(16);
280 if (serial_number_string != 0) {
281 assert_not_equals(device.serialNumber, undefined);
282 read_string(serial_number_string, device.serialNumber);
285 const num_configurations = device_descriptor.getUint8(17);
286 for (let config_value = 1; config_value <= num_configurations;
287 ++config_value) {
288 read_config_descriptor(config_value);
290 }, `Read supported languages`);
293 promise_test(async (t) => {
294 device = await getDeviceForManualTest();
295 await device.open();
297 const result = await device.controlTransferIn({
298 requestType: 'standard',
299 recipient: 'device',
300 request: kGetDescriptorRequest,
301 value: kDeviceDescriptorType << 8,
302 index: 0,
303 }, kDeviceDescriptorLength);
305 assert_equals(result.status, 'ok', 'transfer status');
306 assert_equals(
307 result.data.byteLength, kDeviceDescriptorLength, 'transfer length');
308 assert_greater_than_equal(
309 result.data.getUint8(0),
310 kDeviceDescriptorLength, 'descriptor length');
311 assert_equals(result.data.getUint8(1), kDeviceDescriptorType,
312 'descriptor type');
313 const bcd_usb = result.data.getUint16(2, /*littleEndian=*/true);
314 assert_equals(
315 bcd_usb >> 8, device.usbVersionMajor, 'USB version major');
316 assert_equals(
317 (bcd_usb & 0xf0) >> 4, device.usbVersionMinor, 'USB version minor');
318 assert_equals(
319 bcd_usb & 0xf, device.usbVersionSubminor, 'USV version subminor');
320 assert_equals(
321 result.data.getUint8(4), device.deviceClass, 'device class');
322 assert_equals(
323 result.data.getUint8(5), device.deviceSubclass, 'device subclass');
324 assert_equals(
325 result.data.getUint8(6), device.deviceProtocol, 'device protocol');
326 assert_equals(result.data.getUint16(8, /*littleEndian=*/true),
327 device.vendorId, 'vendor id');
328 assert_equals(result.data.getUint16(10, /*littleEndian=*/true),
329 device.productId, 'product id');
330 const bcd_device = result.data.getUint16(12, /*littleEndian=*/true);
331 assert_equals(
332 bcd_device >> 8, device.deviceVersionMajor, 'device version major');
333 assert_equals((bcd_device & 0xf0) >> 4, device.deviceVersionMinor,
334 'device version minor');
335 assert_equals(bcd_device & 0xf, device.deviceVersionSubminor,
336 'device version subminor');
337 assert_equals(result.data.getUint8(17), device.configurations.length,
338 'number of configurations');
340 read_string_descriptor_languages(result.data);
342 if (pending_subtests == 0) {
343 await device.close();
345 }, 'Read device descriptor');
346 </script>
347 </body>
348 </html>