use core::ffi;
use uefi_macros::unsafe_protocol;
use uefi_raw::protocol::usb::io::UsbIoProtocol;
use uefi_raw::protocol::usb::{
ConfigDescriptor, DataDirection, DeviceDescriptor, DeviceRequest, EndpointDescriptor,
InterfaceDescriptor, UsbTransferStatus,
};
use crate::data_types::PoolString;
use crate::{Char16, Result, StatusExt};
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(UsbIoProtocol::GUID)]
pub struct UsbIo(UsbIoProtocol);
impl UsbIo {
pub fn control_transfer(
&mut self,
request_type: u8,
request: u8,
value: u16,
index: u16,
transfer: ControlTransfer,
timeout: u32,
) -> Result<(), UsbTransferStatus> {
let (direction, buffer_ptr, length) = match transfer {
ControlTransfer::None => (DataDirection::NO_DATA, core::ptr::null_mut(), 0),
ControlTransfer::DataIn(buffer) => (
DataDirection::DATA_IN,
buffer.as_ptr().cast_mut(),
buffer.len(),
),
ControlTransfer::DataOut(buffer) => (
DataDirection::DATA_OUT,
buffer.as_ptr().cast_mut(),
buffer.len(),
),
};
let request_type = if direction == DataDirection::DATA_IN {
request_type | 0x80
} else if direction == DataDirection::DATA_OUT {
request_type & !0x80
} else {
request_type
};
let mut device_request = DeviceRequest {
request_type,
request,
value,
index,
length: length as u16,
};
let mut status = UsbTransferStatus::default();
unsafe {
(self.0.control_transfer)(
&mut self.0,
&mut device_request,
direction,
timeout,
buffer_ptr.cast::<ffi::c_void>(),
length,
&mut status,
)
}
.to_result_with_err(|_| status)
}
pub fn sync_bulk_send(
&mut self,
endpoint: u8,
buffer: &[u8],
timeout: usize,
) -> Result<usize, UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
let mut length = buffer.len();
unsafe {
(self.0.bulk_transfer)(
&mut self.0,
endpoint & !0x80,
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
&mut length,
timeout,
&mut status,
)
}
.to_result_with_err(|_| status)
.map(|()| length)
}
pub fn sync_bulk_receive(
&mut self,
endpoint: u8,
buffer: &mut [u8],
timeout: usize,
) -> Result<usize, UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
let mut length = buffer.len();
unsafe {
(self.0.bulk_transfer)(
&mut self.0,
endpoint | 0x80,
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
&mut length,
timeout,
&mut status,
)
}
.to_result_with_err(|_| status)
.map(|()| length)
}
pub fn sync_interrupt_send(
&mut self,
endpoint: u8,
buffer: &[u8],
timeout: usize,
) -> Result<usize, UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
let mut length = buffer.len();
unsafe {
(self.0.sync_interrupt_transfer)(
&mut self.0,
endpoint & !0x80,
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
&mut length,
timeout,
&mut status,
)
}
.to_result_with_err(|_| status)
.map(|()| length)
}
pub fn sync_interrupt_receive(
&mut self,
endpoint: u8,
buffer: &mut [u8],
timeout: usize,
) -> Result<usize, UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
let mut length = buffer.len();
unsafe {
(self.0.sync_interrupt_transfer)(
&mut self.0,
endpoint | 0x80,
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
&mut length,
timeout,
&mut status,
)
}
.to_result_with_err(|_| status)
.map(|()| length)
}
pub fn sync_isochronous_send(
&mut self,
endpoint: u8,
buffer: &[u8],
) -> Result<(), UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
unsafe {
(self.0.isochronous_transfer)(
&mut self.0,
endpoint & !0x80,
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
buffer.len(),
&mut status,
)
}
.to_result_with_err(|_| status)
}
pub fn sync_isochronous_receive(
&mut self,
endpoint: u8,
buffer: &mut [u8],
) -> Result<(), UsbTransferStatus> {
let mut status = UsbTransferStatus::default();
unsafe {
(self.0.isochronous_transfer)(
&mut self.0,
endpoint | 0x80,
buffer.as_mut_ptr().cast::<ffi::c_void>(),
buffer.len(),
&mut status,
)
}
.to_result_with_err(|_| status)
}
pub fn device_descriptor(&mut self) -> Result<DeviceDescriptor> {
let mut device_descriptor = unsafe { core::mem::zeroed() };
unsafe { (self.0.get_device_descriptor)(&mut self.0, &mut device_descriptor) }
.to_result_with_val(|| device_descriptor)
}
pub fn config_descriptor(&mut self) -> Result<ConfigDescriptor> {
let mut config_descriptor = unsafe { core::mem::zeroed() };
unsafe { (self.0.get_config_descriptor)(&mut self.0, &mut config_descriptor) }
.to_result_with_val(|| config_descriptor)
}
pub fn interface_descriptor(&mut self) -> Result<InterfaceDescriptor> {
let mut interface_descriptor = unsafe { core::mem::zeroed() };
unsafe { (self.0.get_interface_descriptor)(&mut self.0, &mut interface_descriptor) }
.to_result_with_val(|| interface_descriptor)
}
pub fn endpoint_descriptor(&mut self, endpoint: u8) -> Result<EndpointDescriptor> {
let mut endpoint_descriptor = unsafe { core::mem::zeroed() };
unsafe { (self.0.get_endpoint_descriptor)(&mut self.0, endpoint, &mut endpoint_descriptor) }
.to_result_with_val(|| endpoint_descriptor)
}
pub fn string_descriptor(&mut self, lang_id: u16, string_id: u8) -> Result<PoolString> {
let mut string_ptr = core::ptr::null_mut();
unsafe { (self.0.get_string_descriptor)(&mut self.0, lang_id, string_id, &mut string_ptr) }
.to_result()?;
unsafe { PoolString::new(string_ptr.cast::<Char16>()) }
}
pub fn supported_languages(&mut self) -> Result<&[u16]> {
let mut lang_id_table_ptr = core::ptr::null_mut();
let mut lang_id_table_size = 0;
unsafe {
(self.0.get_supported_languages)(
&mut self.0,
&mut lang_id_table_ptr,
&mut lang_id_table_size,
)
}
.to_result_with_val(|| unsafe {
core::slice::from_raw_parts(lang_id_table_ptr, usize::from(lang_id_table_size))
})
}
pub fn port_reset(&mut self) -> Result {
unsafe { (self.0.port_reset)(&mut self.0) }.to_result()
}
}
#[derive(Debug)]
pub enum ControlTransfer<'buffer> {
None,
DataIn(&'buffer mut [u8]),
DataOut(&'buffer [u8]),
}