Skip to content

Commit cfcfb54

Browse files
committed
uefi: Add safe sync EFI_USB_IO_PROTOCOL bindings
Add safe wrapper functions that provide access to the sync versions of each EFI_USB_IO_PROTOCOL transfer function.
1 parent 6447a39 commit cfcfb54

File tree

1 file changed

+202
-1
lines changed

1 file changed

+202
-1
lines changed

uefi/src/proto/usb/io.rs

+202-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
//! USB I/O protocol.
44
5+
use core::ffi;
6+
57
use uefi_macros::unsafe_protocol;
6-
use uefi_raw::protocol::usb::io::UsbIoProtocol;
8+
use uefi_raw::protocol::usb::io::{DataDirection, DeviceRequest, UsbIoProtocol, UsbTransferStatus};
79

810
use crate::data_types::PoolString;
911
use crate::{Char16, Result, StatusExt};
@@ -19,6 +21,194 @@ pub use uefi_raw::protocol::usb::io::{
1921
pub struct UsbIo(UsbIoProtocol);
2022

2123
impl UsbIo {
24+
/// Performs a USB Control transfer, allowing the driver to communicate with the USB device.
25+
pub fn control_transfer(
26+
&mut self,
27+
request_type: u8,
28+
request: u8,
29+
value: u16,
30+
index: u16,
31+
transfer: ControlTransfer,
32+
timeout: u32,
33+
) -> Result<(), UsbTransferStatus> {
34+
let (direction, buffer_ptr, length) = match transfer {
35+
ControlTransfer::None => (DataDirection::NO_DATA, core::ptr::null_mut(), 0),
36+
ControlTransfer::DataIn(buffer) => (
37+
DataDirection::DATA_IN,
38+
buffer.as_ptr().cast_mut(),
39+
buffer.len(),
40+
),
41+
ControlTransfer::DataOut(buffer) => (
42+
DataDirection::DATA_OUT,
43+
buffer.as_ptr().cast_mut(),
44+
buffer.len(),
45+
),
46+
};
47+
48+
let mut device_request = DeviceRequest {
49+
request_type,
50+
request,
51+
value,
52+
index,
53+
length: length as u16,
54+
};
55+
let mut status = UsbTransferStatus::default();
56+
57+
unsafe {
58+
(self.0.control_transfer)(
59+
&mut self.0,
60+
&mut device_request,
61+
direction,
62+
timeout,
63+
buffer_ptr.cast::<ffi::c_void>(),
64+
length,
65+
&mut status,
66+
)
67+
}
68+
.to_result_with_err(|_| status)
69+
}
70+
71+
/// Sends the provided buffer to a USB device over a bulk transfer pipe.
72+
///
73+
/// Returns the number of bytes that were actually sent to the device.
74+
pub fn sync_bulk_send(
75+
&mut self,
76+
endpoint: u8,
77+
buffer: &[u8],
78+
timeout: usize,
79+
) -> Result<usize, UsbTransferStatus> {
80+
let mut status = UsbTransferStatus::default();
81+
let mut length = buffer.len();
82+
83+
unsafe {
84+
(self.0.bulk_transfer)(
85+
&mut self.0,
86+
endpoint & !0x80,
87+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
88+
&mut length,
89+
timeout,
90+
&mut status,
91+
)
92+
}
93+
.to_result_with_err(|_| status)
94+
.map(|()| length)
95+
}
96+
97+
/// Fills the provided buffer with data from a USB device over a bulk transfer pipe.
98+
///
99+
/// Returns the number of bytes that were actually received from the device.
100+
pub fn sync_bulk_receive(
101+
&mut self,
102+
endpoint: u8,
103+
buffer: &mut [u8],
104+
timeout: usize,
105+
) -> Result<usize, UsbTransferStatus> {
106+
let mut status = UsbTransferStatus::default();
107+
let mut length = buffer.len();
108+
109+
unsafe {
110+
(self.0.bulk_transfer)(
111+
&mut self.0,
112+
endpoint | 0x80,
113+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
114+
&mut length,
115+
timeout,
116+
&mut status,
117+
)
118+
}
119+
.to_result_with_err(|_| status)
120+
.map(|()| length)
121+
}
122+
123+
/// Sends the provided buffer to a USB device through a synchronous interrupt transfer.
124+
pub fn sync_interrupt_send(
125+
&mut self,
126+
endpoint: u8,
127+
buffer: &[u8],
128+
timeout: usize,
129+
) -> Result<usize, UsbTransferStatus> {
130+
let mut status = UsbTransferStatus::default();
131+
let mut length = buffer.len();
132+
133+
unsafe {
134+
(self.0.sync_interrupt_transfer)(
135+
&mut self.0,
136+
endpoint & !0x80,
137+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
138+
&mut length,
139+
timeout,
140+
&mut status,
141+
)
142+
}
143+
.to_result_with_err(|_| status)
144+
.map(|()| length)
145+
}
146+
147+
/// Fills the provided buffer with data from a USB device through a synchronous interrupt
148+
/// transfer.
149+
pub fn sync_interrupt_receive(
150+
&mut self,
151+
endpoint: u8,
152+
buffer: &mut [u8],
153+
timeout: usize,
154+
) -> Result<usize, UsbTransferStatus> {
155+
let mut status = UsbTransferStatus::default();
156+
let mut length = buffer.len();
157+
158+
unsafe {
159+
(self.0.sync_interrupt_transfer)(
160+
&mut self.0,
161+
endpoint | 0x80,
162+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
163+
&mut length,
164+
timeout,
165+
&mut status,
166+
)
167+
}
168+
.to_result_with_err(|_| status)
169+
.map(|()| length)
170+
}
171+
172+
/// Sends the provided buffer to a USB device over an isochronous transfer pipe.
173+
pub fn sync_isochronous_send(
174+
&mut self,
175+
endpoint: u8,
176+
buffer: &[u8],
177+
) -> Result<(), UsbTransferStatus> {
178+
let mut status = UsbTransferStatus::default();
179+
180+
unsafe {
181+
(self.0.isochronous_transfer)(
182+
&mut self.0,
183+
endpoint & !0x80,
184+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
185+
buffer.len(),
186+
&mut status,
187+
)
188+
}
189+
.to_result_with_err(|_| status)
190+
}
191+
192+
/// Fills the provided buffer with data from a USB device over an isochronous transfer pipe.
193+
pub fn sync_isochronous_receive(
194+
&mut self,
195+
endpoint: u8,
196+
buffer: &mut [u8],
197+
) -> Result<(), UsbTransferStatus> {
198+
let mut status = UsbTransferStatus::default();
199+
200+
unsafe {
201+
(self.0.isochronous_transfer)(
202+
&mut self.0,
203+
endpoint | 0x80,
204+
buffer.as_mut_ptr().cast::<ffi::c_void>(),
205+
buffer.len(),
206+
&mut status,
207+
)
208+
}
209+
.to_result_with_err(|_| status)
210+
}
211+
22212
/// Returns information about USB devices, including the device's class, subclass, and number
23213
/// of configurations.
24214
pub fn device_descriptor(&mut self) -> Result<DeviceDescriptor> {
@@ -85,3 +275,14 @@ impl UsbIo {
85275
unsafe { (self.0.port_reset)(&mut self.0) }.to_result()
86276
}
87277
}
278+
279+
/// Controls what type of USB control transfer operation should occur.
280+
#[derive(Debug)]
281+
pub enum ControlTransfer<'buffer> {
282+
/// The USB control transfer has no data phase.
283+
None,
284+
/// The USB control transfer has an input data phase.
285+
DataIn(&'buffer mut [u8]),
286+
/// The USB control transfer has an output data phase.
287+
DataOut(&'buffer [u8]),
288+
}

0 commit comments

Comments
 (0)