Skip to content

Commit 7b35821

Browse files
committed
uefi: Implement USB getters and sync transfers
1 parent 8e5df27 commit 7b35821

File tree

2 files changed

+298
-0
lines changed

2 files changed

+298
-0
lines changed

uefi/src/proto/usb/io.rs

+296
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
//! USB I/O protocol.
4+
5+
use core::ffi;
6+
7+
use uefi_macros::unsafe_protocol;
8+
use uefi_raw::protocol::usb::io::UsbIoProtocol;
9+
use uefi_raw::protocol::usb::{
10+
ConfigDescriptor, DataDirection, DeviceDescriptor, DeviceRequest, EndpointDescriptor,
11+
InterfaceDescriptor, UsbTransferStatus,
12+
};
13+
14+
use crate::data_types::PoolString;
15+
use crate::{Char16, Result, StatusExt};
16+
17+
/// USB I/O protocol.
18+
#[derive(Debug)]
19+
#[repr(transparent)]
20+
#[unsafe_protocol(UsbIoProtocol::GUID)]
21+
pub struct UsbIo(UsbIoProtocol);
22+
23+
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 request_type = if direction == DataDirection::DATA_IN {
49+
request_type | 0x80
50+
} else if direction == DataDirection::DATA_OUT {
51+
request_type & !0x80
52+
} else {
53+
request_type
54+
};
55+
56+
let mut device_request = DeviceRequest {
57+
request_type,
58+
request,
59+
value,
60+
index,
61+
length: length as u16,
62+
};
63+
let mut status = UsbTransferStatus::default();
64+
65+
unsafe {
66+
(self.0.control_transfer)(
67+
&mut self.0,
68+
&mut device_request,
69+
direction,
70+
timeout,
71+
buffer_ptr.cast::<ffi::c_void>(),
72+
length,
73+
&mut status,
74+
)
75+
}
76+
.to_result_with_err(|_| status)
77+
}
78+
79+
/// Sends the provided buffer to a USB device over a bulk transfer pipe.
80+
///
81+
/// Returns the number of bytes that were actually sent to the device.
82+
pub fn sync_bulk_send(
83+
&mut self,
84+
endpoint: u8,
85+
buffer: &[u8],
86+
timeout: usize,
87+
) -> Result<usize, UsbTransferStatus> {
88+
let mut status = UsbTransferStatus::default();
89+
let mut length = buffer.len();
90+
91+
unsafe {
92+
(self.0.bulk_transfer)(
93+
&mut self.0,
94+
endpoint & !0x80,
95+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
96+
&mut length,
97+
timeout,
98+
&mut status,
99+
)
100+
}
101+
.to_result_with_err(|_| status)
102+
.map(|()| length)
103+
}
104+
105+
/// Fills the provided buffer with data from a USB device over a bulk transfer pipe.
106+
///
107+
/// Returns the number of bytes that were actually received from the device.
108+
pub fn sync_bulk_receive(
109+
&mut self,
110+
endpoint: u8,
111+
buffer: &mut [u8],
112+
timeout: usize,
113+
) -> Result<usize, UsbTransferStatus> {
114+
let mut status = UsbTransferStatus::default();
115+
let mut length = buffer.len();
116+
117+
unsafe {
118+
(self.0.bulk_transfer)(
119+
&mut self.0,
120+
endpoint | 0x80,
121+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
122+
&mut length,
123+
timeout,
124+
&mut status,
125+
)
126+
}
127+
.to_result_with_err(|_| status)
128+
.map(|()| length)
129+
}
130+
131+
/// Sends the provided buffer to a USB device through a synchronous interrupt transfer.
132+
pub fn sync_interrupt_send(
133+
&mut self,
134+
endpoint: u8,
135+
buffer: &[u8],
136+
timeout: usize,
137+
) -> Result<usize, UsbTransferStatus> {
138+
let mut status = UsbTransferStatus::default();
139+
let mut length = buffer.len();
140+
141+
unsafe {
142+
(self.0.sync_interrupt_transfer)(
143+
&mut self.0,
144+
endpoint & !0x80,
145+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
146+
&mut length,
147+
timeout,
148+
&mut status,
149+
)
150+
}
151+
.to_result_with_err(|_| status)
152+
.map(|()| length)
153+
}
154+
155+
/// Fills the provided buffer with data from a USB device through a synchronous interrupt
156+
/// transfer.
157+
pub fn sync_interrupt_receive(
158+
&mut self,
159+
endpoint: u8,
160+
buffer: &mut [u8],
161+
timeout: usize,
162+
) -> Result<usize, UsbTransferStatus> {
163+
let mut status = UsbTransferStatus::default();
164+
let mut length = buffer.len();
165+
166+
unsafe {
167+
(self.0.sync_interrupt_transfer)(
168+
&mut self.0,
169+
endpoint | 0x80,
170+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
171+
&mut length,
172+
timeout,
173+
&mut status,
174+
)
175+
}
176+
.to_result_with_err(|_| status)
177+
.map(|()| length)
178+
}
179+
180+
/// Sends the provided buffer to a USB device over an isochronous transfer pipe.
181+
pub fn sync_isochronous_send(
182+
&mut self,
183+
endpoint: u8,
184+
buffer: &[u8],
185+
) -> Result<(), UsbTransferStatus> {
186+
let mut status = UsbTransferStatus::default();
187+
188+
unsafe {
189+
(self.0.isochronous_transfer)(
190+
&mut self.0,
191+
endpoint & !0x80,
192+
buffer.as_ptr().cast_mut().cast::<ffi::c_void>(),
193+
buffer.len(),
194+
&mut status,
195+
)
196+
}
197+
.to_result_with_err(|_| status)
198+
}
199+
200+
/// Fills the provided buffer with data from a USB device over an isochronous transfer pipe.
201+
pub fn sync_isochronous_receive(
202+
&mut self,
203+
endpoint: u8,
204+
buffer: &mut [u8],
205+
) -> Result<(), UsbTransferStatus> {
206+
let mut status = UsbTransferStatus::default();
207+
208+
unsafe {
209+
(self.0.isochronous_transfer)(
210+
&mut self.0,
211+
endpoint | 0x80,
212+
buffer.as_mut_ptr().cast::<ffi::c_void>(),
213+
buffer.len(),
214+
&mut status,
215+
)
216+
}
217+
.to_result_with_err(|_| status)
218+
}
219+
220+
/// Returns information about USB devices, including the device's class, subclass, and number
221+
/// of configurations.
222+
pub fn device_descriptor(&mut self) -> Result<DeviceDescriptor> {
223+
let mut device_descriptor = unsafe { core::mem::zeroed() };
224+
225+
unsafe { (self.0.get_device_descriptor)(&mut self.0, &mut device_descriptor) }
226+
.to_result_with_val(|| device_descriptor)
227+
}
228+
229+
/// Returns information about the active configuration of the USB device.
230+
pub fn config_descriptor(&mut self) -> Result<ConfigDescriptor> {
231+
let mut config_descriptor = unsafe { core::mem::zeroed() };
232+
233+
unsafe { (self.0.get_config_descriptor)(&mut self.0, &mut config_descriptor) }
234+
.to_result_with_val(|| config_descriptor)
235+
}
236+
237+
/// Returns information about the interface of the USB device.
238+
pub fn interface_descriptor(&mut self) -> Result<InterfaceDescriptor> {
239+
let mut interface_descriptor = unsafe { core::mem::zeroed() };
240+
241+
unsafe { (self.0.get_interface_descriptor)(&mut self.0, &mut interface_descriptor) }
242+
.to_result_with_val(|| interface_descriptor)
243+
}
244+
245+
/// Returns information about the interface of the USB device.
246+
pub fn endpoint_descriptor(&mut self, endpoint: u8) -> Result<EndpointDescriptor> {
247+
let mut endpoint_descriptor = unsafe { core::mem::zeroed() };
248+
249+
unsafe { (self.0.get_endpoint_descriptor)(&mut self.0, endpoint, &mut endpoint_descriptor) }
250+
.to_result_with_val(|| endpoint_descriptor)
251+
}
252+
253+
/// Returns the string associated with `string_id` in the language associated with `lang_id`.
254+
pub fn string_descriptor(&mut self, lang_id: u16, string_id: u8) -> Result<PoolString> {
255+
let mut string_ptr = core::ptr::null_mut();
256+
257+
unsafe { (self.0.get_string_descriptor)(&mut self.0, lang_id, string_id, &mut string_ptr) }
258+
.to_result()?;
259+
unsafe { PoolString::new(string_ptr.cast::<Char16>()) }
260+
}
261+
262+
/// Returns all of the language ID codes that the USB device supports.
263+
pub fn supported_languages(&mut self) -> Result<&[u16]> {
264+
let mut lang_id_table_ptr = core::ptr::null_mut();
265+
let mut lang_id_table_size = 0;
266+
267+
unsafe {
268+
(self.0.get_supported_languages)(
269+
&mut self.0,
270+
&mut lang_id_table_ptr,
271+
&mut lang_id_table_size,
272+
)
273+
}
274+
.to_result_with_val(|| unsafe {
275+
core::slice::from_raw_parts(lang_id_table_ptr, usize::from(lang_id_table_size))
276+
})
277+
}
278+
279+
/// Resets and reconfigures the USB controller.
280+
///
281+
/// This function should work for all USB devices except USB Hub Controllers.
282+
pub fn port_reset(&mut self) -> Result {
283+
unsafe { (self.0.port_reset)(&mut self.0) }.to_result()
284+
}
285+
}
286+
287+
/// Controls what type of USB control transfer operation should occur.
288+
#[derive(Debug)]
289+
pub enum ControlTransfer<'buffer> {
290+
/// The USB control transfer has no data phase.
291+
None,
292+
/// The USB control transfer has an input data phase.
293+
DataIn(&'buffer mut [u8]),
294+
/// The USB control transfer has an output data phase.
295+
DataOut(&'buffer [u8]),
296+
}

uefi/src/proto/usb/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ pub use uefi_raw::protocol::usb::{
88
AsyncUsbTransferCallback, ConfigDescriptor, DeviceDescriptor, EndpointDescriptor,
99
InterfaceDescriptor, UsbTransferStatus,
1010
};
11+
12+
pub mod io;

0 commit comments

Comments
 (0)