usbd_uac2: fix clippies, add builder, support IN data

This commit is contained in:
2026-05-16 16:07:05 -07:00
parent 24e0083090
commit fb050c4a40
3 changed files with 94 additions and 65 deletions
+4 -4
View File
@@ -195,7 +195,7 @@ impl Descriptor for ClockSource {
writer.write_u8(self.bm_attributes())?; // bmAttributes
writer.write_u8(self.bm_controls())?; // bmControls
writer.write_u8(self.assoc_terminal)?; // bAssocTerminal
writer.write_u8(self.string.map_or(0, |n| u8::from(n)))?; // iClockSource
writer.write_u8(self.string.map_or(0, u8::from))?; // iClockSource
Ok(())
}
}
@@ -247,7 +247,7 @@ impl Descriptor for InputTerminal {
| ((self.overflow_control as u8) << 2)
| ((self.phantom_power_control as u8) << 4),
)?;
writer.write_u8(self.string.map_or(0, |s| u8::from(s)))?;
writer.write_u8(self.string.map_or(0, u8::from))?;
Ok(())
}
}
@@ -289,7 +289,7 @@ impl Descriptor for OutputTerminal {
| ((self.underflow_control as u8) << 6),
)?;
writer.write_u8(self.overflow_control as u8)?;
writer.write_u8(self.string.map_or(0, |n| u8::from(n)))?; // iTerminal
writer.write_u8(self.string.map_or(0, u8::from))?; // iTerminal
Ok(())
}
}
@@ -839,7 +839,7 @@ impl Descriptor for AudioStreamingInterface {
writer.write_u32::<LittleEndian>(self.format_bitmap as u32)?;
writer.write_u8(self.num_channels)?;
writer.write(&self.channel_config.bytes)?;
writer.write_u8(self.string.map_or(0, |s| u8::from(s)))?;
writer.write_u8(self.string.map_or(0, u8::from))?;
Ok(())
}
}
+89 -61
View File
@@ -16,7 +16,7 @@ use log::*;
use num_traits::{ConstZero, ToPrimitive};
use usb_device::control::{Recipient, Request, RequestType};
use usb_device::device::DEFAULT_ALTERNATE_SETTING;
use usb_device::device::{DEFAULT_ALTERNATE_SETTING, UsbDeviceBuilder, UsbVidPid};
use usb_device::endpoint::{self, Endpoint, EndpointDirection, In, Out};
use usb_device::{UsbDirection, class_prelude::*};
@@ -63,7 +63,7 @@ impl RangeType for u32 {}
/// Represent a range request/response.
///
/// ref: UAC2 5.2.2
#[derive(PartialEq, Eq, Ord)]
#[derive(PartialEq, Eq)]
pub struct RangeEntry<T: RangeType> {
pub min: T,
pub max: T,
@@ -93,10 +93,14 @@ impl<T: RangeType> RangeEntry<T> {
// The spec guarantees that ranges do not overlap, so compare by min is correct.
impl<T: RangeType + PartialOrd> PartialOrd for RangeEntry<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.min.partial_cmp(&other.min)
Some(self.cmp(other))
}
}
impl<T: RangeType + PartialOrd> Ord for RangeEntry<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.min.cmp(&other.min)
}
}
/// Represent Isochronous feedback as integer and fractional parts, internally as 16.16.
///
/// Provides conversions to and from the different USB formats.
@@ -146,6 +150,10 @@ pub trait AudioHandler<'a, B: UsbBus> {
/// `ep.read()`.
fn audio_data_rx(&mut self, ep: &Endpoint<'a, B, endpoint::Out>);
/// Called when we must produce audio data for the host. `ep` is ready for
/// `ep.write()`.
fn audio_data_tx(&mut self, ep: &Endpoint<'a, B, endpoint::In>);
/// Called when it's time to send an isochronous feedback update. Should
/// return the correct feedback payload. Feedback always runs at 1ms (in
/// this implementation), and will be passed the nominal frame size.
@@ -183,6 +191,7 @@ pub trait ClockSource {
fn sample_rate(&self) -> u32;
/// Called when the host requests to set the sample rate. Not necessarily called at all startups,
/// so alt_setting should start/stop the clock. Not required for 'fixed' clocks.
#[allow(unused_variables)]
fn set_sample_rate(
&mut self,
sample_rate: u32,
@@ -239,7 +248,7 @@ pub trait ClockSource {
};
let cs = descriptors::ClockSource {
id: id,
id,
clock_type: Self::CLOCK_TYPE,
sof_sync: Self::SOF_SYNC,
frequency_access,
@@ -367,6 +376,7 @@ pub struct TerminalConfig<D: EndpointDirection> {
}
impl<D: EndpointDirection> TerminalConfig<D> {
#[allow(clippy::too_many_arguments)]
fn new(
base_id: u8,
clock_source_id: u8,
@@ -400,7 +410,7 @@ impl<D: EndpointDirection> TerminalConfig<D> {
TerminalConfigBuilder::new()
}
}
impl<'a> TerminalConfigurationDescriptors for TerminalConfig<Out> {
impl TerminalConfigurationDescriptors for TerminalConfig<Out> {
fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) {
let input_terminal = InputTerminal {
id: self.base_id,
@@ -437,7 +447,7 @@ impl<'a> TerminalConfigurationDescriptors for TerminalConfig<Out> {
// fn get_interface_descriptor(&self, id: InterfaceIndex) )
}
impl<'a> TerminalConfigurationDescriptors for TerminalConfig<In> {
impl TerminalConfigurationDescriptors for TerminalConfig<In> {
fn get_configuration_descriptors(&self) -> (InputTerminal, OutputTerminal) {
let output_terminal = OutputTerminal {
id: self.base_id,
@@ -838,7 +848,7 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbClass<B>
// UAC2 4.7
if let Some(descs) = additional_descs {
for desc in descs.into_iter() {
for desc in descs.iter() {
desc.write_descriptor(writer)?;
}
}
@@ -893,10 +903,14 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbClass<B>
fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
debug!("EP {} IN complete", addr);
if let Some(fb_ep) = self.feedback.as_ref()
if let Some(_fb_ep) = self.feedback.as_ref()
&& addr.index() == self.fb_ep
{
self.emit_feedback();
} else if let Some(in_ep) = self.input.as_ref()
&& addr.index() == self.in_ep
{
self.audio_impl.audio_data_tx(&in_ep.endpoint);
} else {
debug!(" unexpected IN on {}", addr);
}
@@ -978,11 +992,11 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
fn class_request_out(&mut self, xfer: ControlOut<B>) {
let req = xfer.request();
match (req.recipient, req.request.try_into()) {
(Recipient::Interface, Ok(ClassSpecificRequest::Cur)) => self.set_interface_cur(xfer),
(Recipient::Interface, Ok(ClassSpecificRequest::Range)) => {}
(Recipient::Endpoint, Ok(ClassSpecificRequest::Cur)) => self.set_endpoint_cur(xfer),
(Recipient::Endpoint, Ok(ClassSpecificRequest::Range)) => {}
match (req.recipient, req.request.into()) {
(Recipient::Interface, ClassSpecificRequest::Cur) => self.set_interface_cur(xfer),
(Recipient::Interface, ClassSpecificRequest::Range) => {}
(Recipient::Endpoint, ClassSpecificRequest::Cur) => self.set_endpoint_cur(xfer),
(Recipient::Endpoint, ClassSpecificRequest::Range) => {}
_ => {
debug!(" Unimplemented.");
}
@@ -992,13 +1006,11 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
fn class_request_in(&mut self, xfer: ControlIn<B>) {
let req = xfer.request();
match (req.recipient, req.request.try_into()) {
(Recipient::Interface, Ok(ClassSpecificRequest::Cur)) => self.get_interface_cur(xfer),
(Recipient::Interface, Ok(ClassSpecificRequest::Range)) => {
self.get_interface_range(xfer)
}
(Recipient::Endpoint, Ok(ClassSpecificRequest::Cur)) => self.get_endpoint_cur(xfer),
(Recipient::Endpoint, Ok(ClassSpecificRequest::Range)) => self.get_endpoint_range(xfer),
match (req.recipient, req.request.into()) {
(Recipient::Interface, ClassSpecificRequest::Cur) => self.get_interface_cur(xfer),
(Recipient::Interface, ClassSpecificRequest::Range) => self.get_interface_range(xfer),
(Recipient::Endpoint, ClassSpecificRequest::Cur) => self.get_endpoint_cur(xfer),
(Recipient::Endpoint, ClassSpecificRequest::Range) => self.get_endpoint_range(xfer),
_ => {
debug!(" Unimplemented.");
}
@@ -1012,12 +1024,16 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
debug!(" SET_ALT_INTERFACE {} {}", iface, alt_setting);
if self.input.is_some() && iface == self.in_iface {
let old_alt = self.input.as_ref().unwrap().alt_setting;
if let Some(input) = &mut self.input
&& iface == self.in_iface
{
let old_alt = input.alt_setting;
if old_alt != alt_setting {
self.audio_impl
.alternate_setting_changed(UsbDirection::In, alt_setting);
self.input.as_mut().unwrap().alt_setting = alt_setting;
input.alt_setting = alt_setting;
// Start the IN cycle
self.audio_impl.audio_data_tx(&input.endpoint);
xfer.accept().ok();
}
} else if self.output.is_some() && iface == self.out_iface {
@@ -1041,13 +1057,15 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
let req = xfer.request();
let iface = req.index as u8;
debug!(" GET_ALT_INTERFACE {}", iface);
if self.input.is_some() && iface == self.in_iface {
xfer.accept_with(&[self.input.as_ref().unwrap().alt_setting])
.ok();
if let Some(input) = self.input.as_ref()
&& iface == self.in_iface
{
xfer.accept_with(&[input.alt_setting]).ok();
return;
} else if self.output.is_some() && iface == self.out_iface {
xfer.accept_with(&[self.output.as_ref().unwrap().alt_setting])
.ok();
} else if let Some(output) = self.output.as_ref()
&& iface == self.out_iface
{
xfer.accept_with(&[output.alt_setting]).ok();
return;
}
debug!(" Unimplemented.");
@@ -1109,9 +1127,8 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
channel: u8,
control: u8,
) {
match entity {
1 => return self.get_clock_cur(xfer, channel, control),
_ => {}
if entity == 1 {
return self.get_clock_cur(xfer, channel, control);
}
debug!(" Unimplemented.");
}
@@ -1123,49 +1140,48 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
channel: u8,
control: u8,
) {
match entity {
1 => return self.set_clock_cur(xfer, channel, control),
_ => {}
if entity == 1 {
return self.set_clock_cur(xfer, channel, control);
}
debug!(" Unimplemented.");
}
fn set_streaming_interface_cur(
&mut self,
xfer: ControlOut<B>,
direction: UsbDirection,
entity: u8,
channel: u8,
control: u8,
_xfer: ControlOut<B>,
_direction: UsbDirection,
_entity: u8,
_channel: u8,
_control: u8,
) {
debug!(" Unimplemented.");
}
fn get_endpoint_cur(&mut self, xfer: ControlIn<B>) {
let req = xfer.request();
let entity = (req.index >> 8) as u8;
let interface = (req.index & 0xff) as u8;
let control = (req.value >> 8) as u8;
let channel = (req.value & 0xff) as u8;
let _entity = (req.index >> 8) as u8;
let _interface = (req.index & 0xff) as u8;
let _control = (req.value >> 8) as u8;
let _channel = (req.value & 0xff) as u8;
debug!(" Unimplemented.");
}
fn get_endpoint_range(&mut self, xfer: ControlIn<B>) {
let req = xfer.request();
let entity = (req.index >> 8) as u8;
let interface = (req.index & 0xff) as u8;
let control = (req.value >> 8) as u8;
let channel = (req.value & 0xff) as u8;
let _entity = (req.index >> 8) as u8;
let _interface = (req.index & 0xff) as u8;
let _control = (req.value >> 8) as u8;
let _channel = (req.value & 0xff) as u8;
debug!(" Unimplemented.");
}
fn set_endpoint_cur(&mut self, xfer: ControlOut<B>) {
let req = xfer.request();
let entity = (req.index >> 8) as u8;
let interface = (req.index & 0xff) as u8;
let control = (req.value >> 8) as u8;
let channel = (req.value & 0xff) as u8;
let _entity = (req.index >> 8) as u8;
let _interface = (req.index & 0xff) as u8;
let _control = (req.value >> 8) as u8;
let _channel = (req.value & 0xff) as u8;
debug!(" Unimplemented.");
}
@@ -1203,8 +1219,8 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
}
}
fn get_clock_cur(&mut self, xfer: ControlIn<B>, channel: u8, control: u8) {
match control.try_into() {
Ok(ClockSourceControlSelector::SamFreqControl) => {
match control.into() {
ClockSourceControlSelector::SamFreqControl => {
debug!(" SamplingFreqControl");
if channel != 0 {
error!(
@@ -1222,7 +1238,7 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
})
.ok();
}
Ok(ClockSourceControlSelector::ClockValidControl) => {
ClockSourceControlSelector::ClockValidControl => {
debug!(" ClockValidControl");
if channel != 0 {
error!(
@@ -1248,8 +1264,8 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
}
}
fn set_clock_cur(&mut self, xfer: ControlOut<B>, channel: u8, control: u8) {
match control.try_into() {
Ok(ClockSourceControlSelector::SamFreqControl) => {
match control.into() {
ClockSourceControlSelector::SamFreqControl => {
debug!(" SamplingFreqControl");
if channel != 0 {
error!(
@@ -1266,7 +1282,7 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
);
xfer.accept().ok();
}
Err(e) => {
Err(_e) => {
error!(" SET SamplingFreqControl CUR ERROR BAD DATA");
}
}
@@ -1277,8 +1293,8 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
}
}
fn get_clock_range(&mut self, xfer: ControlIn<B>, channel: u8, control: u8) {
match control.try_into() {
Ok(ClockSourceControlSelector::SamFreqControl) => {
match control.into() {
ClockSourceControlSelector::SamFreqControl => {
debug!(" SamplingFreqControl");
if channel != 0 {
error!(
@@ -1321,3 +1337,15 @@ impl<'a, B: UsbBus, AU: AudioHandler<'a, B> + ClockSource> UsbAudioClass<'a, B,
}
}
}
/// Set up a `UsbDeviceBuilder` with the device IDs for Usb Audio Class 2.0
pub fn builder<'a, B: UsbBus>(
alloc: &'a UsbBusAllocator<B>,
vid_pid: UsbVidPid,
) -> UsbDeviceBuilder<'a, B> {
UsbDeviceBuilder::new(alloc, vid_pid)
.composite_with_iads() // required by UAC2 4.6
.device_class(0xef) // required by UAC2 4.2
.device_sub_class(0x02) // required by UAC2 4.2
.device_protocol(0x01) // required by UAC2 4.2
}
+1
View File
@@ -1,4 +1,5 @@
// src/log.rs (or log/mod.rs)
#[allow(unused_imports)]
#[cfg(feature = "defmt")]
pub use defmt::{debug, error, info, trace, warn};