diff options
Diffstat (limited to 'testing/web-platform/tests/webusb/usbDevice_controlTransferIn-manual.https.html')
-rw-r--r-- | testing/web-platform/tests/webusb/usbDevice_controlTransferIn-manual.https.html | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webusb/usbDevice_controlTransferIn-manual.https.html b/testing/web-platform/tests/webusb/usbDevice_controlTransferIn-manual.https.html new file mode 100644 index 0000000000..c39e255e2b --- /dev/null +++ b/testing/web-platform/tests/webusb/usbDevice_controlTransferIn-manual.https.html @@ -0,0 +1,348 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="resources/manual.js"></script> + </head> + <body> + <p> + These tests require a USB device to be connected. + </p> + <script> + const kGetDescriptorRequest = 0x06; + + const kDeviceDescriptorType = 0x01; + const kDeviceDescriptorLength = 18; + + const kConfigurationDescriptorType = 0x02; + const kConfigurationDescriptorLength = 9; + + const kStringDescriptorType = 0x03; + const kStringDescriptorMaxLength = 0xFF; + + const kInterfaceDescriptorType = 0x04; + const kInterfaceDescriptorLength = 9; + + const kEndpointDescriptorType = 0x05; + const kEndpointDescriptorLength = 7; + + let device = null; + let pending_subtests = 0; + const string_tests = new Set(); + const string_languages = []; + + async function subtest_complete() { + if (--pending_subtests == 0) { + await device.close(); + } + } + + function manual_usb_subtest(func, name, properties) { + pending_subtests++; + promise_test(async (test) => { + test.add_cleanup(subtest_complete); + await func(test); + }, name, properties); + } + + function read_string(index, expected) { + // A device may use the same string in multiple places. Don't bother + // repeating the test. + if (string_tests.has(index)) { + return; + } + string_tests.add(index); + + const string_values = new Set(); + const decoder = new TextDecoder('utf-16le'); + + for (const language of string_languages) { + const language_string = language.toString(16).padStart(4, '0'); + manual_usb_subtest(async (t) => { + if (expected != undefined) { + t.add_cleanup(() => { + if (string_values.size == string_languages.length) { + assert_true(string_values.has(expected)); + } + }); + } + + const result = await device.controlTransferIn({ + requestType: 'standard', + recipient: 'device', + request: kGetDescriptorRequest, + value: kStringDescriptorType << 8 | index, + index: language + }, kStringDescriptorMaxLength); + + assert_equals(result.status, 'ok', 'transfer status'); + const length = result.data.getUint8(0); + assert_greater_than_equal(length, 2, 'descriptor length'); + assert_equals(result.data.byteLength, length, 'transfer length'); + assert_equals(result.data.getUint8(1), kStringDescriptorType, + 'descriptor type'); + const string_buffer = new Uint8Array( + result.data.buffer, result.data.byteOffset + 2, length - 2); + string_values.add(decoder.decode(string_buffer)); + }, + `Read string descriptor ${index} in language 0x${language_string}`); + } + } + + function check_interface_descriptor(configuration, data) { + assert_greater_than_equal( + data.getUint8(0), kInterfaceDescriptorLength, 'descriptor length'); + + const interface_number = data.getUint8(2); + const iface = configuration.interfaces.find((iface) => { + return iface.interfaceNumber == interface_number; + }); + assert_not_equals( + iface, undefined, `unknown interface ${interface_number}`); + + const alternate_setting = data.getUint8(3); + const alternate = iface.alternates.find((alternate) => { + return alternate.alternateSetting == alternate_setting; + }); + assert_not_equals( + alternate, undefined, `unknown alternate ${alternate_setting}`); + + assert_equals(data.getUint8(4), alternate.endpoints.length, + 'number of endpoints'); + assert_equals( + data.getUint8(5), alternate.interfaceClass, 'interface class'); + assert_equals(data.getUint8(6), alternate.interfaceSubclass, + 'interface subclass'); + assert_equals(data.getUint8(7), alternate.interfaceProtocol, + 'interface protocol'); + + const interface_string = data.getUint8(8); + if (interface_string != 0) { + // TODO(crbug.com/727819): Check that the string descriptor matches + // iface.interfaceName. + read_string(interface_string); + } + + return alternate; + } + + function check_endpoint_descriptor(alternate, data) { + assert_greater_than_equal( + data.getUint8(0), kEndpointDescriptorLength, 'descriptor length'); + + const endpoint_address = data.getUint8(2); + const direction = endpoint_address & 0x80 ? 'in' : 'out'; + const endpoint_number = endpoint_address & 0x0f; + const endpoint = alternate.endpoints.find((endpoint) => { + return endpoint.direction == direction && + endpoint.endpointNumber == endpoint_number; + }); + assert_not_equals( + endpoint, undefined, `unknown endpoint ${endpoint_number}`); + + const attributes = data.getUint8(3); + switch (attributes & 0x03) { + case 0: + assert_equals(endpoint.type, 'control', 'endpoint type'); + break; + case 1: + assert_equals(endpoint.type, 'isochronous', 'endpoint type'); + break; + case 2: + assert_equals(endpoint.type, 'bulk', 'endpoint type'); + break; + case 3: + assert_equals(endpoint.type, 'interrupt', 'endpoint type'); + break; + } + + assert_equals(data.getUint16(4, /*littleEndian=*/true), + endpoint.packetSize, 'packet size'); + } + + function read_config_descriptor(config_value) { + manual_usb_subtest(async (t) => { + const configuration = device.configurations.find((config) => { + return config.configurationValue == config_value; + }); + assert_not_equals(configuration, undefined); + + let result = await device.controlTransferIn({ + requestType: 'standard', + recipient: 'device', + request: kGetDescriptorRequest, + value: kConfigurationDescriptorType << 8 | (config_value - 1), + index: 0 + }, kConfigurationDescriptorLength); + + assert_equals(result.status, 'ok', 'transfer status'); + let length = result.data.getUint8(0); + assert_greater_than_equal( + length, kConfigurationDescriptorLength, 'descriptor length'); + assert_equals(result.data.byteLength, length, 'transfer length'); + const total_length = result.data.getUint16(2, /*littleEndian=*/true); + + result = await device.controlTransferIn({ + requestType: 'standard', + recipient: 'device', + request: kGetDescriptorRequest, + value: kConfigurationDescriptorType << 8 | (config_value - 1), + index: 0 + }, total_length); + + assert_equals(result.status, 'ok', 'transfer status'); + assert_equals( + result.data.byteLength, total_length, 'transfer length'); + assert_equals(result.data.getUint8(0), length, 'descriptor length'); + assert_equals(result.data.getUint8(1), kConfigurationDescriptorType, + 'descriptor type'); + assert_equals(result.data.getUint16(2, /*littleEndian=*/true), + total_length, 'total length'); + assert_equals( + result.data.getUint8(4), configuration.interfaces.length, + 'number of interfaces'); + assert_equals( + result.data.getUint8(5), config_value, 'configuration value'); + + const configuration_string = result.data.getUint8(6); + if (configuration_string != 0) { + // TODO(crbug.com/727819): Check that the string descriptor matches + // configuration.configurationName. + read_string(configuration_string); + } + + let offset = length; + let alternate = undefined; + while (offset < total_length) { + length = result.data.getUint8(offset); + assert_less_than_equal(offset + length, total_length); + + const view = new DataView( + result.data.buffer, result.data.byteOffset + offset, length); + switch (view.getUint8(1)) { + case kConfigurationDescriptorType: + assert_unreached('cannot contain multiple config descriptors'); + break; + case kInterfaceDescriptorType: + alternate = check_interface_descriptor(configuration, view); + break; + case kEndpointDescriptorType: + assert_not_equals(alternate, undefined, + 'endpoint not defined after interface'); + check_endpoint_descriptor(alternate, view); + break; + } + + offset += length; + } + }, `Read config descriptor ${config_value}`); + } + + function read_string_descriptor_languages(device_descriptor) { + manual_usb_subtest(async (t) => { + const result = await device.controlTransferIn({ + requestType: 'standard', + recipient: 'device', + request: kGetDescriptorRequest, + value: kStringDescriptorType << 8, + index: 0 + }, kStringDescriptorMaxLength); + + assert_equals(result.status, 'ok', 'transfer status'); + assert_equals(result.data.getUint8(1), kStringDescriptorType, + 'descriptor type'); + const length = result.data.getUint8(0); + assert_greater_than_equal(length, 2, 'descriptor length') + assert_greater_than_equal( + result.data.byteLength, length, 'transfer length'); + + for (let index = 2; index < length; index += 2) { + string_languages.push( + result.data.getUint16(index, /*littleEndian=*/true)); + } + + const manufacturer_string = device_descriptor.getUint8(14); + if (manufacturer_string != 0) { + assert_not_equals(device.manufacturerName, undefined); + read_string(manufacturer_string, device.manufacturerName); + } + + const product_string = device_descriptor.getUint8(15); + if (product_string != 0) { + assert_not_equals(device.productName, undefined); + read_string(product_string, device.productName); + } + + const serial_number_string = device_descriptor.getUint8(16); + if (serial_number_string != 0) { + assert_not_equals(device.serialNumber, undefined); + read_string(serial_number_string, device.serialNumber); + } + + const num_configurations = device_descriptor.getUint8(17); + for (let config_value = 1; config_value <= num_configurations; + ++config_value) { + read_config_descriptor(config_value); + } + }, `Read supported languages`); + } + + promise_test(async (t) => { + device = await getDeviceForManualTest(); + await device.open(); + + const result = await device.controlTransferIn({ + requestType: 'standard', + recipient: 'device', + request: kGetDescriptorRequest, + value: kDeviceDescriptorType << 8, + index: 0, + }, kDeviceDescriptorLength); + + assert_equals(result.status, 'ok', 'transfer status'); + assert_equals( + result.data.byteLength, kDeviceDescriptorLength, 'transfer length'); + assert_greater_than_equal( + result.data.getUint8(0), + kDeviceDescriptorLength, 'descriptor length'); + assert_equals(result.data.getUint8(1), kDeviceDescriptorType, + 'descriptor type'); + const bcd_usb = result.data.getUint16(2, /*littleEndian=*/true); + assert_equals( + bcd_usb >> 8, device.usbVersionMajor, 'USB version major'); + assert_equals( + (bcd_usb & 0xf0) >> 4, device.usbVersionMinor, 'USB version minor'); + assert_equals( + bcd_usb & 0xf, device.usbVersionSubminor, 'USV version subminor'); + assert_equals( + result.data.getUint8(4), device.deviceClass, 'device class'); + assert_equals( + result.data.getUint8(5), device.deviceSubclass, 'device subclass'); + assert_equals( + result.data.getUint8(6), device.deviceProtocol, 'device protocol'); + assert_equals(result.data.getUint16(8, /*littleEndian=*/true), + device.vendorId, 'vendor id'); + assert_equals(result.data.getUint16(10, /*littleEndian=*/true), + device.productId, 'product id'); + const bcd_device = result.data.getUint16(12, /*littleEndian=*/true); + assert_equals( + bcd_device >> 8, device.deviceVersionMajor, 'device version major'); + assert_equals((bcd_device & 0xf0) >> 4, device.deviceVersionMinor, + 'device version minor'); + assert_equals(bcd_device & 0xf, device.deviceVersionSubminor, + 'device version subminor'); + assert_equals(result.data.getUint8(17), device.configurations.length, + 'number of configurations'); + + read_string_descriptor_languages(result.data); + + if (pending_subtests == 0) { + await device.close(); + } + }, 'Read device descriptor'); + </script> + </body> +</html> |