Skip to content

Commit 999b133

Browse files
committed
iso 传输
1 parent e1df403 commit 999b133

2 files changed

Lines changed: 132 additions & 10 deletions

File tree

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

Lines changed: 113 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,17 +313,42 @@ impl<T: kind::Sealed, D: direction::Sealed> Endpoint<T, D> {
313313
)
314314
}
315315

316-
/// 创建Isoch TRB
316+
/// 创建Isoch TRB,根据xHCI规范优化
317317
fn create_isoch_trb(&self, addr_bus: usize, len: usize) -> transfer::Allowed {
318318
transfer::Allowed::Isoch(
319319
*Isoch::new()
320320
.set_data_buffer_pointer(addr_bus as _)
321321
.set_trb_transfer_length(len as _)
322322
.set_interrupter_target(0)
323-
.set_interrupt_on_completion(),
323+
.set_interrupt_on_completion(), // .set_start_isoch_asap() // 如果方法可用则启用
324324
)
325325
}
326326

327+
/// 创建Normal TRB用于Isoch TD的链接
328+
fn create_normal_trb_for_isoch(
329+
&self,
330+
addr_bus: usize,
331+
len: usize,
332+
is_last: bool,
333+
) -> transfer::Allowed {
334+
if is_last {
335+
transfer::Allowed::Normal(
336+
*Normal::new()
337+
.set_data_buffer_pointer(addr_bus as _)
338+
.set_trb_transfer_length(len as _)
339+
.set_interrupter_target(0)
340+
.set_interrupt_on_completion(),
341+
)
342+
} else {
343+
transfer::Allowed::Normal(
344+
*Normal::new()
345+
.set_data_buffer_pointer(addr_bus as _)
346+
.set_trb_transfer_length(len as _)
347+
.set_interrupter_target(0),
348+
)
349+
}
350+
}
351+
327352
/// 执行传输的通用方法
328353
fn execute_transfer<'a>(
329354
&mut self,
@@ -334,6 +359,62 @@ impl<T: kind::Sealed, D: direction::Sealed> Endpoint<T, D> {
334359
self.raw
335360
.enque([trb].into_iter(), self.desc.direction, addr_virt, len)
336361
}
362+
363+
/// 执行多包ISO传输的通用方法
364+
fn execute_iso_transfer<'a>(
365+
&mut self,
366+
trbs: Vec<transfer::Allowed>,
367+
addr_virt: usize,
368+
len: usize,
369+
) -> ResultTransfer<'a> {
370+
self.raw
371+
.enque(trbs.into_iter(), self.desc.direction, addr_virt, len)
372+
}
373+
374+
/// 创建多包ISO传输的TRB列表
375+
fn create_iso_trb_list(
376+
&self,
377+
addr_bus: usize,
378+
len: usize,
379+
num_iso_packets: usize,
380+
) -> Vec<transfer::Allowed> {
381+
let mut trbs = Vec::new();
382+
let packet_size = if len == 0 {
383+
0
384+
} else {
385+
len.div_ceil(num_iso_packets)
386+
};
387+
388+
for i in 0..num_iso_packets {
389+
let offset = i * packet_size;
390+
if offset >= len {
391+
break; // 避免越界
392+
}
393+
let remaining = len - offset;
394+
let current_size = if remaining >= packet_size {
395+
packet_size
396+
} else {
397+
remaining
398+
};
399+
400+
if current_size > 0 {
401+
let current_addr = addr_bus + offset;
402+
let is_last = (i == num_iso_packets - 1) || (offset + current_size >= len);
403+
404+
if i == 0 {
405+
// 第一个TRB必须是Isoch TRB
406+
let trb = self.create_isoch_trb(current_addr, current_size);
407+
trbs.push(trb);
408+
} else {
409+
// 后续TRB使用Normal TRB
410+
let trb = self.create_normal_trb_for_isoch(current_addr, current_size, is_last);
411+
trbs.push(trb);
412+
}
413+
}
414+
}
415+
416+
trbs
417+
}
337418
}
338419

339420
impl Endpoint<kind::Bulk, direction::In> {
@@ -381,24 +462,46 @@ impl Endpoint<kind::Interrupt, direction::Out> {
381462
}
382463

383464
impl Endpoint<kind::Isochronous, direction::In> {
384-
pub fn transfer<'a>(&mut self, data: &'a mut [u8]) -> ResultTransfer<'a> {
465+
pub fn transfer_multi_packet<'a>(
466+
&mut self,
467+
data: &'a mut [u8],
468+
num_iso_packets: usize,
469+
) -> ResultTransfer<'a> {
385470
self.validate_endpoint(Direction::In, EndpointType::Isochronous)?;
386471

387472
let (len, addr_virt, addr_bus) = self.prepare_in_buffer(data);
388-
let trb = self.create_isoch_trb(addr_bus, len);
389473

390-
self.execute_transfer(trb, addr_virt, len)
474+
if num_iso_packets <= 1 || len == 0 {
475+
// 单包传输,使用原有逻辑
476+
let trb = self.create_isoch_trb(addr_bus, len);
477+
return self.execute_transfer(trb, addr_virt, len);
478+
}
479+
480+
// 多包传输,使用公共方法创建TRB列表
481+
let trbs = self.create_iso_trb_list(addr_bus, len, num_iso_packets);
482+
self.execute_iso_transfer(trbs, addr_virt, len)
391483
}
392484
}
393485

394486
impl Endpoint<kind::Isochronous, direction::Out> {
395-
pub fn transfer<'a>(&mut self, data: &'a [u8]) -> ResultTransfer<'a> {
487+
pub fn transfer_multi_packet<'a>(
488+
&mut self,
489+
data: &'a [u8],
490+
num_iso_packets: usize,
491+
) -> ResultTransfer<'a> {
396492
self.validate_endpoint(Direction::Out, EndpointType::Isochronous)?;
397493

398494
let (len, addr_virt, addr_bus) = self.prepare_out_buffer(data);
399-
let trb = self.create_isoch_trb(addr_bus, len);
400495

401-
self.execute_transfer(trb, addr_virt, len)
496+
if num_iso_packets <= 1 || len == 0 {
497+
// 单包传输,使用原有逻辑
498+
let trb = self.create_isoch_trb(addr_bus, len);
499+
return self.execute_transfer(trb, addr_virt, len);
500+
}
501+
502+
// 多包传输,使用公共方法创建TRB列表
503+
let trbs = self.create_iso_trb_list(addr_bus, len, num_iso_packets);
504+
self.execute_iso_transfer(trbs, addr_virt, len)
402505
}
403506
}
404507

@@ -435,12 +538,12 @@ impl usb_if::host::EndpointInterruptOut for Endpoint<kind::Interrupt, direction:
435538

436539
impl usb_if::host::EndpintIsoIn for Endpoint<kind::Isochronous, direction::In> {
437540
fn submit<'a>(&mut self, data: &'a mut [u8], num_iso_packets: usize) -> ResultTransfer<'a> {
438-
self.transfer(data)
541+
self.transfer_multi_packet(data, num_iso_packets)
439542
}
440543
}
441544

442545
impl usb_if::host::EndpintIsoOut for Endpoint<kind::Isochronous, direction::Out> {
443546
fn submit<'a>(&mut self, data: &'a [u8], num_iso_packets: usize) -> ResultTransfer<'a> {
444-
self.transfer(data)
547+
self.transfer_multi_packet(data, num_iso_packets)
445548
}
446549
}

usb-host/test_isoch.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// 临时测试文件,用于探索Isoch TRB的API
2+
use xhci::ring::trb::transfer::Isoch;
3+
4+
fn main() {
5+
let mut isoch = Isoch::new();
6+
7+
// 探索可用的方法
8+
isoch
9+
.set_data_buffer_pointer(0)
10+
.set_trb_transfer_length(0)
11+
.set_interrupter_target(0)
12+
.set_interrupt_on_completion();
13+
14+
// 尝试其他可能的方法
15+
// isoch.set_transfer_burst_count();
16+
// isoch.set_transfer_last_burst_packet_count();
17+
// isoch.set_frame_id();
18+
// isoch.set_start_isoch_asap();
19+
}

0 commit comments

Comments
 (0)