Skip to content

Commit fe0c951

Browse files
ZR233claude
andcommitted
fix(xhci): set chain bit on ISO TRBs and preserve raw config descriptor
- Set chain bit on non-final ISO/Normal TRBs so the xHCI controller correctly chains multi-packet isochronous transfers - Always set SIA (Start Isoch ASAP) on isochronous TRBs - Add `raw` field to `ConfigurationDescriptor` to preserve the original descriptor bytes for later use Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 0c82abf commit fe0c951

3 files changed

Lines changed: 26 additions & 8 deletions

File tree

usb-host/src/backend/kmod/xhci/endpoint.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,35 @@ impl Endpoint {
115115

116116
fn enque_iso(&mut self, bus_addr: u64, packet_lengths: &[usize]) -> TransferId {
117117
if packet_lengths.len() <= 1 {
118-
self.enque_iso_trb(bus_addr, packet_lengths.first().copied().unwrap_or(0))
118+
self.enque_iso_trb(
119+
bus_addr,
120+
packet_lengths.first().copied().unwrap_or(0),
121+
false,
122+
true,
123+
)
119124
} else {
120125
self.enque_iso_multi(bus_addr, packet_lengths)
121126
}
122127
}
123128

124-
fn enque_iso_trb(&mut self, bus_addr: u64, buff_len: usize) -> TransferId {
129+
fn enque_iso_trb(
130+
&mut self,
131+
bus_addr: u64,
132+
buff_len: usize,
133+
chain: bool,
134+
ioc: bool,
135+
) -> TransferId {
125136
let mut trb = Isoch::new();
126137
trb.set_data_buffer_pointer(bus_addr as _)
127138
.set_trb_transfer_length(buff_len as _)
128139
.set_interrupter_target(0)
129-
.set_interrupt_on_completion();
130-
131-
// if use_sia {
132-
// trb.set_start_isoch_asap(); // 启用SIA
133-
// }
140+
.set_start_isoch_asap();
141+
if chain {
142+
trb.set_chain_bit();
143+
}
144+
if ioc {
145+
trb.set_interrupt_on_completion();
146+
}
134147

135148
// 创建Isoch TRB
136149
let trb = transfer::Allowed::Isoch(trb);
@@ -149,7 +162,7 @@ impl Endpoint {
149162

150163
if index == 0 {
151164
// 第一个TRB必须是Isoch TRB
152-
id = self.enque_iso_trb(current_addr, current_size as _);
165+
id = self.enque_iso_trb(current_addr, current_size as _, !is_last, is_last);
153166
} else {
154167
// 后续TRB使用Normal TRB
155168
let mut trb = Normal::new();
@@ -159,6 +172,8 @@ impl Endpoint {
159172

160173
if is_last {
161174
trb.set_interrupt_on_completion();
175+
} else {
176+
trb.set_chain_bit();
162177
}
163178
let trb = transfer::Allowed::Normal(trb);
164179
id = self.enque_trb(trb);

usb-host/src/backend/umod/device.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ fn libusb_get_configuration_descriptors(
163163
string_index: NonZero::new(desc.iConfiguration),
164164
string: None,
165165
interfaces,
166+
raw: Vec::new(),
166167
};
167168
unsafe { libusb_free_config_descriptor(desc) };
168169
Ok(out)

usb-if/src/descriptor/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pub struct ConfigurationDescriptor {
178178
pub string_index: Option<NonZero<u8>>,
179179
pub string: Option<String>,
180180
pub interfaces: Vec<InterfaceDescriptors>,
181+
pub raw: Vec<u8>,
181182
}
182183

183184
impl ConfigurationDescriptor {
@@ -230,6 +231,7 @@ impl From<parser::ConfigurationDescriptor<'_>> for ConfigurationDescriptor {
230231
string_index: desc.string_index(),
231232
interfaces: desc.interfaces().map(InterfaceDescriptors::from).collect(),
232233
string: None,
234+
raw: desc.as_bytes().to_vec(),
233235
}
234236
}
235237
}

0 commit comments

Comments
 (0)