Skip to content

Commit 8dfbdda

Browse files
authored
Merge branch 'master' into readme
2 parents 4f6b3d5 + cb8e6d4 commit 8dfbdda

File tree

13 files changed

+235
-82
lines changed

13 files changed

+235
-82
lines changed

.github/workflows/ci.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
on:
2+
push:
3+
branches: [ staging, trying, master ]
4+
pull_request:
5+
6+
name: CI
7+
8+
jobs:
9+
ci-linux:
10+
name: CI
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
rust: [stable]
16+
17+
include:
18+
# Test nightly but don't fail
19+
- rust: nightly
20+
experimental: true
21+
TARGET: x86_64-unknown-linux-gnu
22+
23+
steps:
24+
- uses: actions/checkout@v2
25+
26+
- uses: actions-rs/toolchain@v1
27+
with:
28+
profile: minimal
29+
toolchain: ${{ matrix.rust }}
30+
target: ${{ matrix.TARGET }}
31+
override: true
32+
33+
- name: Install libusb library
34+
run: sudo apt-get install -y libusb-1.0.0-dev
35+
36+
- uses: actions-rs/cargo@v1
37+
with:
38+
command: check
39+
args: --all-targets
40+
41+
- uses: actions-rs/cargo@v1
42+
with:
43+
command: check
44+
args: --features control-buffer-256

.github/workflows/rustfmt.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
on:
2+
push:
3+
branches: [ staging, trying, master ]
4+
pull_request:
5+
6+
name: Code formatting check
7+
8+
jobs:
9+
fmt:
10+
name: Rustfmt
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- uses: actions-rs/toolchain@v1
15+
with:
16+
profile: minimal
17+
toolchain: stable
18+
override: true
19+
components: rustfmt
20+
- uses: actions-rs/cargo@v1
21+
with:
22+
command: fmt
23+
args: --all -- --check

.travis.yml

Lines changed: 0 additions & 14 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Fixed
11+
* Fixed an issue where USB devices were not enumerating on Windows ([#32](https://github.com/rust-embedded-community/usb-device/issues/82))
12+
13+
...
14+
15+
## [0.2.8] - 2021-03-13
16+
17+
## [0.2.7] - 2020-10-03
18+
19+
## [0.2.6] - 2020-09-22
20+
21+
## [0.2.5] - 2020-02-10
22+
23+
## [0.2.4] - 2020-02-01
24+
25+
## [0.2.3] - 2019-08-28
26+
27+
## [0.2.2] - 2019-07-27
28+
29+
## [0.2.1] - 2019-06-07
30+
31+
## [0.2.0] - 2019-06-07
32+
33+
## 0.1.0 - 2019-06-07
34+
35+
This is the initial release to crates.io.
36+
37+
[Unreleased]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.8...HEAD
38+
[0.2.8]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.7...v0.2.8
39+
[0.2.7]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.6...v0.2.7
40+
[0.2.6]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.5...v0.2.6
41+
[0.2.5]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.4...v0.2.5
42+
[0.2.4]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.3...v0.2.4
43+
[0.2.3]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.2...v0.2.3
44+
[0.2.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.1...v0.2.2
45+
[0.2.1]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.0...v0.2.1
46+
[0.2.0]: https://github.com/rust-embedded-community/usb-device/compare/v0.1.0...v0.2.0

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,10 @@ Class crates
3636

3737
* [usbd-hid](https://github.com/twitchyliquid64/usbd-hid) [![Crates.io](https://img.shields.io/crates/v/usbd-hid.svg)](https://crates.io/crates/usbd-hid) - HID class
3838
* [usbd-serial](https://github.com/mvirkkunen/usbd-serial) [![Crates.io](https://img.shields.io/crates/v/usbd-serial.svg)](https://crates.io/crates/usbd-serial) - CDC-ACM serial port class
39+
40+
41+
Others
42+
------
43+
44+
Other implementations for USB in Rust
45+
* [embassy-usb](https://github.com/embassy-rs/embassy/blob/master/embassy-usb/src/driver.rs), an async variant.

src/bus.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl<B: UsbBus> UsbBusAllocator<B> {
211211
///
212212
/// This directly delegates to [`UsbBus::alloc_ep`], so see that method for details. In most
213213
/// cases classes should call the endpoint type specific methods instead.
214-
pub fn alloc<'a, D: EndpointDirection>(
214+
pub fn alloc<D: EndpointDirection>(
215215
&self,
216216
ep_addr: Option<EndpointAddress>,
217217
ep_type: EndpointType,

src/control_pipe.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ impl<B: UsbBus> ControlPipe<'_, B> {
5151
}
5252

5353
pub fn waiting_for_response(&self) -> bool {
54-
match self.state {
55-
ControlState::CompleteOut | ControlState::CompleteIn(_) => true,
56-
_ => false,
57-
}
54+
matches!(
55+
self.state,
56+
ControlState::CompleteOut | ControlState::CompleteIn(_)
57+
)
5858
}
5959

6060
pub fn data(&self) -> &[u8] {
@@ -65,7 +65,7 @@ impl<B: UsbBus> ControlPipe<'_, B> {
6565
self.state = ControlState::Idle;
6666
}
6767

68-
pub fn handle_setup<'p>(&'p mut self) -> Option<Request> {
68+
pub fn handle_setup(&mut self) -> Option<Request> {
6969
let count = match self.ep_out.read(&mut self.buf[..]) {
7070
Ok(count) => count,
7171
Err(UsbError::WouldBlock) => return None,
@@ -122,10 +122,10 @@ impl<B: UsbBus> ControlPipe<'_, B> {
122122
return Some(req);
123123
}
124124

125-
return None;
125+
None
126126
}
127127

128-
pub fn handle_out<'p>(&'p mut self) -> Option<Request> {
128+
pub fn handle_out(&mut self) -> Option<Request> {
129129
match self.state {
130130
ControlState::DataOut(req) => {
131131
let i = self.i;
@@ -147,7 +147,9 @@ impl<B: UsbBus> ControlPipe<'_, B> {
147147
return Some(req);
148148
}
149149
}
150-
ControlState::StatusOut => {
150+
// The host may terminate a DATA stage early by sending a zero-length status packet
151+
// acknowledging the data we sent it.
152+
ControlState::StatusOut | ControlState::DataIn | ControlState::DataInLast => {
151153
self.ep_out.read(&mut []).ok();
152154
self.state = ControlState::Idle;
153155
}
@@ -160,7 +162,7 @@ impl<B: UsbBus> ControlPipe<'_, B> {
160162
}
161163
}
162164

163-
return None;
165+
None
164166
}
165167

166168
pub fn handle_in_complete(&mut self) -> bool {
@@ -191,7 +193,7 @@ impl<B: UsbBus> ControlPipe<'_, B> {
191193
}
192194
};
193195

194-
return false;
196+
false
195197
}
196198

197199
fn write_in_chunk(&mut self) {

src/descriptor.rs

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::cmp::min;
2+
13
use crate::bus::{InterfaceNumber, StringIndex, UsbBus};
24
use crate::device;
35
use crate::endpoint::{Endpoint, EndpointDirection};
@@ -61,20 +63,45 @@ impl DescriptorWriter<'_> {
6163

6264
/// Writes an arbitrary (usually class-specific) descriptor.
6365
pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) -> Result<()> {
64-
let length = descriptor.len();
66+
self.write_with(descriptor_type, |buf| {
67+
if descriptor.len() > buf.len() {
68+
return Err(UsbError::BufferOverflow);
69+
}
6570

66-
if (self.position + 2 + length) > self.buf.len() || (length + 2) > 255 {
71+
buf[..descriptor.len()].copy_from_slice(descriptor);
72+
73+
Ok(descriptor.len())
74+
})
75+
}
76+
77+
/// Writes an arbitrary (usually class-specific) descriptor by using a callback function.
78+
///
79+
/// The callback function gets a reference to the remaining buffer space, and it should write
80+
/// the descriptor into it and return the number of bytes written. If the descriptor doesn't
81+
/// fit, the function should return `Err(UsbError::BufferOverflow)`. That and any error returned
82+
/// by it will be propagated up.
83+
pub fn write_with(
84+
&mut self,
85+
descriptor_type: u8,
86+
f: impl FnOnce(&mut [u8]) -> Result<usize>,
87+
) -> Result<()> {
88+
if self.position + 2 > self.buf.len() {
6789
return Err(UsbError::BufferOverflow);
6890
}
6991

70-
self.buf[self.position] = (length + 2) as u8;
71-
self.buf[self.position + 1] = descriptor_type;
92+
let data_end = min(self.buf.len(), self.position + 256);
93+
let data_buf = &mut self.buf[self.position + 2..data_end];
94+
95+
let total_len = f(data_buf)? + 2;
7296

73-
let start = self.position + 2;
97+
if self.position + total_len > self.buf.len() {
98+
return Err(UsbError::BufferOverflow);
99+
}
74100

75-
self.buf[start..start + length].copy_from_slice(descriptor);
101+
self.buf[self.position] = total_len as u8;
102+
self.buf[self.position + 1] = descriptor_type;
76103

77-
self.position = start + length;
104+
self.position += total_len;
78105

79106
Ok(())
80107
}
@@ -264,26 +291,46 @@ impl DescriptorWriter<'_> {
264291
pub fn endpoint<'e, B: UsbBus, D: EndpointDirection>(
265292
&mut self,
266293
endpoint: &Endpoint<'e, B, D>,
294+
) -> Result<()> {
295+
self.endpoint_ex(endpoint, |_| Ok(0))
296+
}
297+
298+
/// Writes an endpoint descriptor with extra trailing data.
299+
///
300+
/// This is rarely needed and shouldn't be used except for compatibility with standard USB
301+
/// classes that require it. Extra data is normally written in a separate class specific
302+
/// descriptor.
303+
///
304+
/// # Arguments
305+
///
306+
/// * `endpoint` - Endpoint previously allocated with
307+
/// [`UsbBusAllocator`](crate::bus::UsbBusAllocator).
308+
/// * `f` - Callback for the extra data. See `write_with` for more information.
309+
pub fn endpoint_ex<'e, B: UsbBus, D: EndpointDirection>(
310+
&mut self,
311+
endpoint: &Endpoint<'e, B, D>,
312+
f: impl FnOnce(&mut [u8]) -> Result<usize>,
267313
) -> Result<()> {
268314
match self.num_endpoints_mark {
269315
Some(mark) => self.buf[mark] += 1,
270316
None => return Err(UsbError::InvalidState),
271317
};
272318

273-
let mps = endpoint.max_packet_size();
319+
self.write_with(descriptor_type::ENDPOINT, |buf| {
320+
if buf.len() < 5 {
321+
return Err(UsbError::BufferOverflow);
322+
}
274323

275-
self.write(
276-
descriptor_type::ENDPOINT,
277-
&[
278-
endpoint.address().into(), // bEndpointAddress
279-
endpoint.ep_type() as u8, // bmAttributes
280-
mps as u8,
281-
(mps >> 8) as u8, // wMaxPacketSize
282-
endpoint.interval(), // bInterval
283-
],
284-
)?;
324+
let mps = endpoint.max_packet_size();
285325

286-
Ok(())
326+
buf[0] = endpoint.address().into();
327+
buf[1] = endpoint.ep_type() as u8;
328+
buf[2] = mps as u8;
329+
buf[3] = (mps >> 8) as u8;
330+
buf[4] = endpoint.interval();
331+
332+
Ok(f(&mut buf[5..])? + 5)
333+
})
287334
}
288335

289336
/// Writes a string descriptor.
@@ -325,7 +372,7 @@ pub struct BosWriter<'w, 'a: 'w> {
325372
impl<'w, 'a: 'w> BosWriter<'w, 'a> {
326373
pub(crate) fn new(writer: &'w mut DescriptorWriter<'a>) -> Self {
327374
Self {
328-
writer: writer,
375+
writer,
329376
num_caps_mark: None,
330377
}
331378
}

0 commit comments

Comments
 (0)