From 08097d5a2d3572e15373ad1ab20ea28fc1840e91 Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 20 Jul 2026 21:05:26 +0900 Subject: [PATCH] redbear-ecmd, redbear-usbaudiod: fix endpoint numbering to xhcid global index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same latent bug class as the acmd fix (f505d18a89): both drivers used the USB endpoint ADDRESS number (ep.address & 0x0F) as the endpoint key, but xhcid keys endpoints by global enumeration index across all interfaces of the selected configuration. The two coincide only when the device's endpoint addresses are sequential in enumeration order — devices with non-sequential addresses (some modems/audio gear) would open the wrong endpoint or fail to open. Both now count endpoints in configuration order per selected configuration, matching xhcid's PortState::get_endp_desc indexing. Verified: cargo check -Z build-std --target x86_64-unknown-redox clean for both crates. --- .../system/redbear-ecmd/source/src/main.rs | 36 +++++++++++-------- .../redbear-usbaudiod/source/src/main.rs | 34 +++++++++++------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/local/recipes/system/redbear-ecmd/source/src/main.rs b/local/recipes/system/redbear-ecmd/source/src/main.rs index ead3d9ac16..0c1c2968c3 100644 --- a/local/recipes/system/redbear-ecmd/source/src/main.rs +++ b/local/recipes/system/redbear-ecmd/source/src/main.rs @@ -110,29 +110,35 @@ fn main() { let data_iface = data_iface.expect("No CDC ECM data interface found"); // Find bulk IN + bulk OUT on the data interface, and optional - // interrupt endpoint on the control interface. + // interrupt endpoint on the control interface. xhcid keys endpoints + // by GLOBAL index across all interfaces of the configuration (see + // xhcid PortState::get_endp_desc / endpoint_states) — the USB + // endpoint address number only coincides with that index when the + // device's addresses are sequential in enumeration order, so count + // endpoints in configuration order instead. let mut bulk_in_num = 0u8; let mut bulk_out_num = 0u8; let mut int_num = 0u8; for conf_desc in desc.config_descs.iter() { + // xhcid indexes endpoints within the selected configuration only; + // reset the counter per config and keep only the selected one. + let mut config_num = 0u8; for ifd in conf_desc.interface_descs.iter() { - if ifd.number == data_iface { - for ep in ifd.endpoints.iter() { - if ep.attributes & 0x03 == 0x02 { // bulk transfer type - match ep.direction() { - EndpDirection::In => bulk_in_num = ep.address & 0x0F, - EndpDirection::Out => bulk_out_num = ep.address & 0x0F, - _ => {} - } + for ep in ifd.endpoints.iter() { + config_num += 1; + if conf_desc.configuration_value != conf_val { + continue; + } + if ifd.number == data_iface && ep.attributes & 0x03 == 0x02 { // bulk transfer type + match ep.direction() { + EndpDirection::In => bulk_in_num = config_num, + EndpDirection::Out => bulk_out_num = config_num, + _ => {} } } - } - if ifd.number == ctrl_iface { - for ep in ifd.endpoints.iter() { - if ep.attributes & 0x03 == 0x03 { // interrupt transfer type - int_num = ep.address & 0x0F; - } + if ifd.number == ctrl_iface && ep.attributes & 0x03 == 0x03 { // interrupt transfer type + int_num = config_num; } } } diff --git a/local/recipes/system/redbear-usbaudiod/source/src/main.rs b/local/recipes/system/redbear-usbaudiod/source/src/main.rs index 3dc081faf3..05c9ed1bd5 100644 --- a/local/recipes/system/redbear-usbaudiod/source/src/main.rs +++ b/local/recipes/system/redbear-usbaudiod/source/src/main.rs @@ -188,24 +188,34 @@ fn main() { return; } - // Find isoch endpoints on the streaming interface + // Find isoch endpoints on the streaming interface. xhcid keys + // endpoints by GLOBAL index across all interfaces of the + // configuration (see xhcid PortState::get_endp_desc / + // endpoint_states) — the USB endpoint address number only coincides + // with that index when the device's addresses are sequential in + // enumeration order, so count endpoints in configuration order. let mut isoch_in_num = 0u8; let mut isoch_out_num = 0u8; let mut max_pkt_size = 0u16; for conf_desc in desc.config_descs.iter() { + // xhcid indexes endpoints within the selected configuration only; + // reset the counter per config and keep only the selected one. + let mut config_num = 0u8; for ifd in conf_desc.interface_descs.iter() { - if ifd.number == as_iface { - for ep in ifd.endpoints.iter() { - if ep.attributes & 0x03 == 0x01 { // isoch transfer type - if ep.max_packet_size > max_pkt_size { - max_pkt_size = ep.max_packet_size; - } - match ep.direction() { - EndpDirection::In => isoch_in_num = ep.address & 0x0F, - EndpDirection::Out => isoch_out_num = ep.address & 0x0F, - _ => {} - } + for ep in ifd.endpoints.iter() { + config_num += 1; + if conf_desc.configuration_value != conf_val { + continue; + } + if ifd.number == as_iface && ep.attributes & 0x03 == 0x01 { // isoch transfer type + if ep.max_packet_size > max_pkt_size { + max_pkt_size = ep.max_packet_size; + } + match ep.direction() { + EndpDirection::In => isoch_in_num = config_num, + EndpDirection::Out => isoch_out_num = config_num, + _ => {} } } }