Skip to content

Commit fddbdbf

Browse files
authored
Merge pull request #144 from rust-embedded-community/feature/control-buffer-args
Constructing the control pipe from a user-provided buffer
2 parents 6a44a84 + 1111d41 commit fddbdbf

File tree

9 files changed

+61
-34
lines changed

9 files changed

+61
-34
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ jobs:
3131
run: sudo apt-get install -y libusb-1.0.0-dev
3232

3333
- run: cargo check --all-targets
34-
- run: cargo check --features control-buffer-256
3534
- run: cargo check --features defmt
35+
- run: cargo check --features log

.github/workflows/rustfmt.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ jobs:
1717
- run: cargo fmt --all -- --check
1818
- run: cargo clippy --all-features
1919
- run: cargo clippy --features defmt
20-
- run: cargo clippy --features control-buffer-256
20+
- run: cargo clippy --features log
2121
- run: cargo clippy

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
### Changed
11+
* [breaking] The control pipe is now provided in the `UsbDeviceBuilder` API to allow for user-provided control
12+
pipes. This makes it so that control pipes have configurable sizing.
13+
1014
## [0.3.2] - 2024-03-06
1115

1216
### Added

Cargo.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ rusb = "0.9.1"
2020
rand = "0.8.5"
2121

2222
[features]
23-
# Use a 256 byte buffer for control transfers instead of 128.
24-
control-buffer-256 = []
25-
26-
# Enable logging and tracing via the `log` crate
27-
log = ["dep:log"]
2823

2924
# Use larger endpoint buffers for highspeed operation (default fullspeed)
3025
#

src/control_pipe.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,28 @@ enum ControlState {
2020
Error,
2121
}
2222

23-
// Maximum length of control transfer data stage in bytes. 128 bytes by default. You can define the
24-
// feature "control-buffer-256" to make it 256 bytes if you have larger control transfers.
25-
#[cfg(not(feature = "control-buffer-256"))]
26-
const CONTROL_BUF_LEN: usize = 128;
27-
#[cfg(feature = "control-buffer-256")]
28-
const CONTROL_BUF_LEN: usize = 256;
29-
3023
/// Buffers and parses USB control transfers.
3124
pub struct ControlPipe<'a, B: UsbBus> {
3225
ep_out: EndpointOut<'a, B>,
3326
ep_in: EndpointIn<'a, B>,
3427
state: ControlState,
35-
buf: [u8; CONTROL_BUF_LEN],
28+
buf: &'a mut [u8],
3629
static_in_buf: Option<&'static [u8]>,
3730
i: usize,
3831
len: usize,
3932
}
4033

4134
impl<B: UsbBus> ControlPipe<'_, B> {
42-
pub fn new<'a>(ep_out: EndpointOut<'a, B>, ep_in: EndpointIn<'a, B>) -> ControlPipe<'a, B> {
35+
pub fn new<'a>(
36+
buf: &'a mut [u8],
37+
ep_out: EndpointOut<'a, B>,
38+
ep_in: EndpointIn<'a, B>,
39+
) -> ControlPipe<'a, B> {
4340
ControlPipe {
4441
ep_out,
4542
ep_in,
4643
state: ControlState::Idle,
47-
buf: [0; CONTROL_BUF_LEN],
44+
buf,
4845
static_in_buf: None,
4946
i: 0,
5047
len: 0,

src/device.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
8282
type ClassList<'a, B> = [&'a mut dyn UsbClass<B>];
8383

8484
impl<B: UsbBus> UsbDevice<'_, B> {
85-
pub(crate) fn build<'a>(alloc: &'a UsbBusAllocator<B>, config: Config<'a>) -> UsbDevice<'a, B> {
85+
pub(crate) fn build<'a>(
86+
alloc: &'a UsbBusAllocator<B>,
87+
config: Config<'a>,
88+
control_buffer: &'a mut [u8],
89+
) -> UsbDevice<'a, B> {
8690
let control_out = alloc
8791
.alloc(
8892
Some(0x00.into()),
@@ -106,7 +110,7 @@ impl<B: UsbBus> UsbDevice<'_, B> {
106110
UsbDevice {
107111
bus,
108112
config,
109-
control: ControlPipe::new(control_out, control_in),
113+
control: ControlPipe::new(control_buffer, control_out, control_in),
110114
device_state: UsbDeviceState::Default,
111115
remote_wakeup_enabled: false,
112116
self_powered: false,

src/device_builder.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub struct UsbVidPid(pub u16, pub u16);
88
/// Used to build new [`UsbDevice`]s.
99
pub struct UsbDeviceBuilder<'a, B: UsbBus> {
1010
alloc: &'a UsbBusAllocator<B>,
11+
control_buffer: &'a mut [u8],
1112
config: Config<'a>,
1213
}
1314

@@ -32,6 +33,8 @@ pub enum BuilderError {
3233
InvalidPacketSize,
3334
/// Configuration specifies higher USB power draw than allowed
3435
PowerTooHigh,
36+
/// The provided control buffer is too small for the provided maximum packet size.
37+
ControlBufferTooSmall,
3538
}
3639

3740
/// Provides basic string descriptors about the device, including the manufacturer, product name,
@@ -82,9 +85,14 @@ impl<'a> StringDescriptors<'a> {
8285

8386
impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> {
8487
/// Creates a builder for constructing a new [`UsbDevice`].
85-
pub fn new(alloc: &'a UsbBusAllocator<B>, vid_pid: UsbVidPid) -> UsbDeviceBuilder<'a, B> {
88+
pub fn new(
89+
alloc: &'a UsbBusAllocator<B>,
90+
vid_pid: UsbVidPid,
91+
control_buffer: &'a mut [u8],
92+
) -> UsbDeviceBuilder<'a, B> {
8693
UsbDeviceBuilder {
8794
alloc,
95+
control_buffer,
8896
config: Config {
8997
device_class: 0x00,
9098
device_sub_class: 0x00,
@@ -104,8 +112,16 @@ impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> {
104112
}
105113

106114
/// Creates the [`UsbDevice`] instance with the configuration in this builder.
107-
pub fn build(self) -> UsbDevice<'a, B> {
108-
UsbDevice::build(self.alloc, self.config)
115+
pub fn build(self) -> Result<UsbDevice<'a, B>, BuilderError> {
116+
if self.control_buffer.len() < self.config.max_packet_size_0 as usize {
117+
return Err(BuilderError::ControlBufferTooSmall);
118+
}
119+
120+
Ok(UsbDevice::build(
121+
self.alloc,
122+
self.config,
123+
self.control_buffer,
124+
))
109125
}
110126

111127
builder_fields! {
@@ -188,6 +204,10 @@ impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> {
188204
_ => return Err(BuilderError::InvalidPacketSize),
189205
}
190206

207+
if self.control_buffer.len() < max_packet_size_0 as usize {
208+
return Err(BuilderError::ControlBufferTooSmall);
209+
}
210+
191211
self.config.max_packet_size_0 = max_packet_size_0;
192212
Ok(self)
193213
}

src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ pub mod endpoint;
134134
/// To implement USB support for your own project, the required code is usually as follows:
135135
///
136136
/// ``` ignore
137+
/// use core::cell::UnsafeCell;
137138
/// use usb_device::prelude::*;
138139
/// use usb_serial; // example class crate (not included)
139140
///
141+
/// static mut CONTROL_BUFFER: UnsafeCell<[u8; 128]> = UnsafeCell::new([0; 128]);
142+
///
140143
/// // Create the device-specific USB peripheral driver. The exact name and arguments are device
141144
/// // specific, so check the documentation for your device driver crate.
142145
/// let usb_bus = device_specific_usb::UsbBus::new(...);
@@ -151,12 +154,12 @@ pub mod endpoint;
151154
/// // pair. Additional builder arguments can specify parameters such as device class code or
152155
/// // product name. If using an existing class, remember to check the class crate documentation
153156
/// // for correct values.
154-
/// let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x5824, 0x27dd))
157+
/// let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x5824, 0x27dd), unsafe { CONTROL_BUFFER.get_mut() })
155158
/// .strings(&[StringDescriptors::new(LangID::EN)
156159
/// .product("Serial port")])
157160
/// .expect("Failed to set strings")
158161
/// .device_class(usb_serial::DEVICE_CLASS)
159-
/// .build();
162+
/// .build().unwrap();
160163
///
161164
/// // At this point the USB peripheral is enabled and a connected host will attempt to enumerate
162165
/// // it.

src/test_class.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#![allow(missing_docs)]
22

33
use crate::class_prelude::*;
4-
use crate::descriptor::lang_id::LangID;
54
use crate::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid};
65
use crate::Result;
6+
use core::cell::UnsafeCell;
77
use core::cmp;
88

99
#[cfg(feature = "test-class-high-speed")]
@@ -22,6 +22,8 @@ mod sizes {
2222
pub const INTERRUPT_ENDPOINT: u16 = 31;
2323
}
2424

25+
static mut CONTROL_BUFFER: UnsafeCell<[u8; 256]> = UnsafeCell::new([0; 256]);
26+
2527
/// Test USB class for testing USB driver implementations. Supports various endpoint types and
2628
/// requests for testing USB peripheral drivers on actual hardware.
2729
pub struct TestClass<'a, B: UsbBus> {
@@ -94,7 +96,7 @@ impl<B: UsbBus> TestClass<'_, B> {
9496

9597
/// Convenience method to create a UsbDevice that is configured correctly for TestClass.
9698
pub fn make_device<'a>(&self, usb_bus: &'a UsbBusAllocator<B>) -> UsbDevice<'a, B> {
97-
self.make_device_builder(usb_bus).build()
99+
self.make_device_builder(usb_bus).build().unwrap()
98100
}
99101

100102
/// Convenience method to create a UsbDeviceBuilder that is configured correctly for TestClass.
@@ -112,14 +114,16 @@ impl<B: UsbBus> TestClass<'_, B> {
112114
&self,
113115
usb_bus: &'a UsbBusAllocator<B>,
114116
) -> UsbDeviceBuilder<'a, B> {
115-
UsbDeviceBuilder::new(usb_bus, UsbVidPid(VID, PID))
116-
.strings(&[StringDescriptors::default()
117-
.manufacturer(MANUFACTURER)
118-
.product(PRODUCT)
119-
.serial_number(SERIAL_NUMBER)])
120-
.unwrap()
121-
.max_packet_size_0(sizes::CONTROL_ENDPOINT)
122-
.unwrap()
117+
UsbDeviceBuilder::new(usb_bus, UsbVidPid(VID, PID), unsafe {
118+
CONTROL_BUFFER.get_mut()
119+
})
120+
.strings(&[StringDescriptors::default()
121+
.manufacturer(MANUFACTURER)
122+
.product(PRODUCT)
123+
.serial_number(SERIAL_NUMBER)])
124+
.unwrap()
125+
.max_packet_size_0(sizes::CONTROL_ENDPOINT)
126+
.unwrap()
123127
}
124128

125129
/// Must be called after polling the UsbDevice.

0 commit comments

Comments
 (0)