|
| 1 | +// SPDX-License-Identifier: MIT OR Apache-2.0 |
| 2 | + |
| 3 | +use core::mem; |
| 4 | +use uefi::proto::usb::DeviceDescriptor; |
| 5 | +use uefi::proto::usb::io::{ControlTransfer, UsbIo}; |
| 6 | +use uefi::{Status, boot}; |
| 7 | + |
| 8 | +const DEVICE_TO_HOST: u8 = 1 << 7; |
| 9 | +const STANDARD_REQUEST: u8 = 0b00 << 5; |
| 10 | +const DEVICE_RECIPIENT: u8 = 0b0_0000; |
| 11 | +const GET_DESCRIPTOR_REQUEST: u8 = 6; |
| 12 | +const DEVICE_DESCRIPTOR: u8 = 1; |
| 13 | + |
| 14 | +/// This test iterates through all of the exposed active USB interfaces and |
| 15 | +/// performs checks on each to validate that descriptor acquisition and control |
| 16 | +/// transfers work correctly. |
| 17 | +pub fn test() { |
| 18 | + info!("Testing USB I/O protocol"); |
| 19 | + |
| 20 | + let handles = boot::locate_handle_buffer(boot::SearchType::from_proto::<UsbIo>()) |
| 21 | + .expect("failed to acquire USB I/O handles"); |
| 22 | + |
| 23 | + for handle in handles.iter().copied() { |
| 24 | + let mut io = boot::open_protocol_exclusive::<UsbIo>(handle) |
| 25 | + .expect("failed to open USB I/O protocol"); |
| 26 | + |
| 27 | + let device = io |
| 28 | + .device_descriptor() |
| 29 | + .expect("failed to acquire USB device descriptor"); |
| 30 | + io.config_descriptor() |
| 31 | + .expect("failed to acquire USB config descriptor"); |
| 32 | + io.interface_descriptor() |
| 33 | + .expect("failed to acquire USB interface descriptor"); |
| 34 | + |
| 35 | + for endpoint_index in 0..16 { |
| 36 | + let result = io.endpoint_descriptor(endpoint_index); |
| 37 | + if result |
| 38 | + .as_ref() |
| 39 | + .is_err_and(|error| error.status() == Status::NOT_FOUND) |
| 40 | + { |
| 41 | + continue; |
| 42 | + } |
| 43 | + |
| 44 | + result.expect("failed to acquire USB endpoint descriptor"); |
| 45 | + } |
| 46 | + |
| 47 | + let supported_languages = io |
| 48 | + .supported_languages() |
| 49 | + .expect("failed to acquire supported language list"); |
| 50 | + let test_language = supported_languages[0]; |
| 51 | + |
| 52 | + for string_index in 0..=u8::MAX { |
| 53 | + let result = io.string_descriptor(test_language, string_index); |
| 54 | + if result |
| 55 | + .as_ref() |
| 56 | + .is_err_and(|error| error.status() == Status::NOT_FOUND) |
| 57 | + { |
| 58 | + continue; |
| 59 | + } |
| 60 | + |
| 61 | + result.expect("failed to acquire string descriptor"); |
| 62 | + } |
| 63 | + |
| 64 | + let mut buffer = [0u8; mem::size_of::<DeviceDescriptor>()]; |
| 65 | + |
| 66 | + io.control_transfer( |
| 67 | + DEVICE_TO_HOST | STANDARD_REQUEST | DEVICE_RECIPIENT, |
| 68 | + GET_DESCRIPTOR_REQUEST, |
| 69 | + u16::from(DEVICE_DESCRIPTOR) << 8, |
| 70 | + 0, |
| 71 | + ControlTransfer::DataIn(&mut buffer[..mem::size_of::<DeviceDescriptor>()]), |
| 72 | + 0, |
| 73 | + ) |
| 74 | + .expect("failed control transfer"); |
| 75 | + unsafe { |
| 76 | + assert_eq!( |
| 77 | + device, |
| 78 | + buffer.as_ptr().cast::<DeviceDescriptor>().read_unaligned() |
| 79 | + ) |
| 80 | + } |
| 81 | + } |
| 82 | +} |
0 commit comments