Use more correct params in configure_endpoint.
Most importantly in the endpoint contexts of the input context, specifying the properties of the endpoints that are being configured.
This commit is contained in:
@@ -85,6 +85,7 @@ pub struct BulkOnlyTransport<'a> {
|
||||
bulk_out_num: u8,
|
||||
max_lun: u8,
|
||||
current_tag: u32,
|
||||
interface_num: u8,
|
||||
}
|
||||
|
||||
pub const FEATURE_ENDPOINT_HALT: u16 = 0;
|
||||
@@ -96,6 +97,8 @@ impl<'a> BulkOnlyTransport<'a> {
|
||||
let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8;
|
||||
let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8;
|
||||
|
||||
bulk_only_mass_storage_reset(handle, if_desc.number.into())?;
|
||||
|
||||
let max_lun = get_max_lun(handle, 0)?;
|
||||
println!("BOT_MAX_LUN {}", max_lun);
|
||||
|
||||
@@ -109,13 +112,14 @@ impl<'a> BulkOnlyTransport<'a> {
|
||||
handle,
|
||||
max_lun,
|
||||
current_tag: 0,
|
||||
interface_num: if_desc.number,
|
||||
})
|
||||
}
|
||||
fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> {
|
||||
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT)
|
||||
}
|
||||
fn reset_recovery(&mut self) -> Result<(), ProtocolError> {
|
||||
bulk_only_mass_storage_reset(self.handle, 0)?;
|
||||
bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?;
|
||||
self.clear_stall(self.bulk_in_num.into())?;
|
||||
self.clear_stall(self.bulk_out_num.into())?;
|
||||
|
||||
@@ -128,8 +132,6 @@ impl<'a> BulkOnlyTransport<'a> {
|
||||
|
||||
impl<'a> Protocol for BulkOnlyTransport<'a> {
|
||||
fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<(), ProtocolError> {
|
||||
dbg!(self.bulk_in_status.current_status()?);
|
||||
dbg!(self.bulk_out_status.current_status()?);
|
||||
self.current_tag += 1;
|
||||
let tag = self.current_tag;
|
||||
|
||||
|
||||
@@ -38,6 +38,15 @@ pub struct DevDesc {
|
||||
pub config_descs: SmallVec<[ConfDesc; 1]>,
|
||||
}
|
||||
|
||||
impl DevDesc {
|
||||
pub fn major_version(&self) -> u8 {
|
||||
((self.usb & 0xFF00) >> 8) as u8
|
||||
}
|
||||
pub fn minor_version(&self) -> u8 {
|
||||
self.usb as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfDesc {
|
||||
pub kind: u8,
|
||||
@@ -56,6 +65,7 @@ pub struct EndpDesc {
|
||||
pub max_packet_size: u16,
|
||||
pub interval: u8,
|
||||
pub ssc: Option<SuperSpeedCmp>,
|
||||
pub sspc: Option<SuperSpeedPlusIsochCmp>,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum EndpDirection {
|
||||
@@ -131,6 +141,31 @@ impl EndpDesc {
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
})
|
||||
}
|
||||
pub fn is_superspeed(&self) -> bool {
|
||||
self.ssc.is_some()
|
||||
}
|
||||
pub fn is_superspeedplus(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
fn interrupt_usage_bits(&self) -> u8 {
|
||||
assert!(self.is_interrupt());
|
||||
(self.attributes & 0x20) >> 4
|
||||
}
|
||||
pub fn is_periodic(&self) -> bool {
|
||||
#[repr(u8)]
|
||||
enum InterruptUsageBits {
|
||||
Periodic,
|
||||
Notification,
|
||||
Rsvd2,
|
||||
Rsvd3,
|
||||
}
|
||||
|
||||
if self.is_interrupt() {
|
||||
self.interrupt_usage_bits() == InterruptUsageBits::Periodic as u8
|
||||
} else {
|
||||
self.is_isoch()
|
||||
}
|
||||
}
|
||||
pub fn max_streams(&self) -> u8 {
|
||||
self.ssc
|
||||
.as_ref()
|
||||
@@ -156,6 +191,9 @@ impl EndpDesc {
|
||||
pub fn max_burst(&self) -> u8 {
|
||||
self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0)
|
||||
}
|
||||
pub fn has_ssp_companion(&self) -> bool {
|
||||
self.ssc.map(|ssc| ssc.attributes & (1 << 7) != 0).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct IfDesc {
|
||||
@@ -177,7 +215,11 @@ pub struct SuperSpeedCmp {
|
||||
pub attributes: u8,
|
||||
pub bytes_per_interval: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct SuperSpeedPlusIsochCmp {
|
||||
pub kind: u8,
|
||||
pub bytes_per_interval: u32,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct HidDesc {
|
||||
pub kind: u8,
|
||||
@@ -536,7 +578,7 @@ impl XhciEndpTransferHandle {
|
||||
let mut status_buf = [0u8; 32];
|
||||
let status_bytes_read = self.0.read(&mut status_buf)?;
|
||||
|
||||
let status = serde_json::from_slice(dbg!(&status_buf[..status_bytes_read]))?;
|
||||
let status = serde_json::from_slice(&status_buf[..status_bytes_read])?;
|
||||
|
||||
if let PortTransferStatus::ShortPacket(len) = status {
|
||||
if len as usize != bytes_transferred {
|
||||
|
||||
+39
-3
@@ -1,3 +1,5 @@
|
||||
use std::slice;
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct BosDescriptor {
|
||||
@@ -32,6 +34,21 @@ pub struct BosSuperSpeedDesc {
|
||||
pub u1_dev_exit_lat: u8,
|
||||
pub u2_dev_exit_lat: u16,
|
||||
}
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct BosSuperSpeedPlusDesc {
|
||||
pub len: u8,
|
||||
pub kind: u8,
|
||||
pub cap_ty: u8,
|
||||
pub _rsvd0: u8,
|
||||
pub attrs: u32,
|
||||
pub func_supp: u32,
|
||||
pub _rsvd1: u16,
|
||||
sublink_speed_attr: [u32; 0],
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for BosSuperSpeedPlusDesc {}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct BosUsb2ExtDesc {
|
||||
@@ -46,12 +63,22 @@ unsafe impl plain::Plain for BosUsb2ExtDesc {}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DeviceCapability {
|
||||
Usb2Ext = 2,
|
||||
SuperSpeed = 3,
|
||||
Usb2Ext = 0x02,
|
||||
SuperSpeed,
|
||||
SuperSpeedPlus = 0x0A,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for BosSuperSpeedDesc {}
|
||||
|
||||
impl BosSuperSpeedPlusDesc {
|
||||
pub fn ssac(&self) -> u8 {
|
||||
(self.attrs & 0x0000_000F) as u8
|
||||
}
|
||||
pub fn sublink_speed_attr(&self) -> &[u32] {
|
||||
unsafe { slice::from_raw_parts(&self.sublink_speed_attr as *const u32, self.ssac() as usize + 1) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BosDevDescIter<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
@@ -84,8 +111,9 @@ impl<'a> Iterator for BosDevDescIter<'a> {
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum BosAnyDevDesc {
|
||||
SuperSpeed(BosSuperSpeedDesc),
|
||||
Usb2Ext(BosUsb2ExtDesc),
|
||||
SuperSpeed(BosSuperSpeedDesc),
|
||||
SuperSpeedPlus(BosSuperSpeedPlusDesc),
|
||||
}
|
||||
|
||||
impl BosAnyDevDesc {
|
||||
@@ -95,6 +123,12 @@ impl BosAnyDevDesc {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn is_superspeedplus(&self) -> bool {
|
||||
match self {
|
||||
Self::SuperSpeedPlus(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BosAnyDevDescIter<'a> {
|
||||
@@ -120,6 +154,8 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> {
|
||||
Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?))
|
||||
} else if base.cap_ty == DeviceCapability::SuperSpeed as u8 {
|
||||
Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?))
|
||||
} else if base.cap_ty == DeviceCapability::SuperSpeedPlus as u8 {
|
||||
Some(BosAnyDevDesc::SuperSpeedPlus(*plain::from_bytes(slice).ok()?))
|
||||
} else if base.cap_ty == 0 {
|
||||
// TODO
|
||||
return None;
|
||||
|
||||
@@ -45,9 +45,18 @@ pub struct SuperSpeedCompanionDescriptor {
|
||||
pub attributes: u8,
|
||||
pub bytes_per_interval: u16,
|
||||
}
|
||||
|
||||
unsafe impl Plain for SuperSpeedCompanionDescriptor {}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct SuperSpeedPlusIsochCmpDescriptor {
|
||||
pub length: u8,
|
||||
pub kind: u8,
|
||||
pub reserved: u16,
|
||||
pub bytes_per_interval: u32,
|
||||
}
|
||||
unsafe impl Plain for SuperSpeedPlusIsochCmpDescriptor {}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct HidDescriptor {
|
||||
|
||||
@@ -2,7 +2,7 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuper
|
||||
pub use self::config::ConfigDescriptor;
|
||||
pub use self::device::DeviceDescriptor;
|
||||
pub use self::endpoint::{
|
||||
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, ENDP_ATTR_TY_MASK,
|
||||
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK,
|
||||
};
|
||||
pub use self::interface::InterfaceDescriptor;
|
||||
pub use self::setup::Setup;
|
||||
|
||||
+105
-26
@@ -21,6 +21,7 @@ use super::context::{
|
||||
InputContext, SlotState, StreamContext, StreamContextArray, ENDPOINT_CONTEXT_STATUS_MASK,
|
||||
};
|
||||
use super::doorbell::Doorbell;
|
||||
use super::extended::ProtocolSpeed;
|
||||
use super::operational::OperationalRegs;
|
||||
use super::ring::Ring;
|
||||
use super::runtime::RuntimeRegs;
|
||||
@@ -82,6 +83,7 @@ impl From<usb::EndpointDescriptor> for EndpDesc {
|
||||
interval: d.interval,
|
||||
max_packet_size: d.max_packet_size,
|
||||
ssc: None,
|
||||
sspc: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +113,15 @@ impl From<usb::SuperSpeedCompanionDescriptor> for SuperSpeedCmp {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<usb::SuperSpeedPlusIsochCmpDescriptor> for SuperSpeedPlusIsochCmp {
|
||||
fn from(r: usb::SuperSpeedPlusIsochCmpDescriptor) -> Self {
|
||||
Self {
|
||||
kind: r.kind,
|
||||
bytes_per_interval: r.bytes_per_interval,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IfDesc {
|
||||
fn new(
|
||||
dev: &mut Device,
|
||||
@@ -146,6 +157,7 @@ pub enum AnyDescriptor {
|
||||
Endpoint(usb::EndpointDescriptor),
|
||||
Hid(usb::HidDescriptor),
|
||||
SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor),
|
||||
SuperSpeedPlusCompanion(usb::SuperSpeedPlusIsochCmpDescriptor),
|
||||
}
|
||||
|
||||
impl AnyDescriptor {
|
||||
@@ -169,6 +181,7 @@ impl AnyDescriptor {
|
||||
5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?),
|
||||
33 => Self::Hid(*plain::from_bytes(bytes).ok()?),
|
||||
48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?),
|
||||
49 => Self::SuperSpeedPlusCompanion(*plain::from_bytes(bytes).ok()?),
|
||||
_ => {
|
||||
//panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes);
|
||||
return None;
|
||||
@@ -269,6 +282,65 @@ impl Xhci {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn endp_ctx_interval(speed_id: &ProtocolSpeed, endp_desc: &EndpDesc) -> u8 {
|
||||
/// Logarithmic (base 2) 125 µs periods per millisecond.
|
||||
const MILLISEC_PERIODS: u8 = 3;
|
||||
|
||||
// TODO: Also check the Speed ID for superspeed(plus).
|
||||
if (speed_id.is_lowspeed() || speed_id.is_fullspeed()) && endp_desc.is_interrupt() {
|
||||
// The interval field has values 1-255, ranging from 1 ms to 255 ms.
|
||||
// TODO: This is correct, right?
|
||||
let last_power_of_two = 8 - endp_desc.interval.leading_zeros() as u8;
|
||||
last_power_of_two - 1 + MILLISEC_PERIODS
|
||||
} else if speed_id.is_fullspeed() && endp_desc.is_isoch() {
|
||||
// bInterval has values 1-16, ranging from 1 ms to 32,768 ms.
|
||||
endp_desc.interval - 1 + MILLISEC_PERIODS
|
||||
} else if (speed_id.is_fullspeed() || endp_desc.is_superspeed() || endp_desc.is_superspeedplus()) && (endp_desc.is_interrupt() || endp_desc.is_isoch()) {
|
||||
// bInterval has values 1-16, but ranging from 125 µs to 4096 ms.
|
||||
endp_desc.interval - 1
|
||||
} else {
|
||||
// This includes superspeed(plus) control and bulk endpoints in particular.
|
||||
0
|
||||
}
|
||||
}
|
||||
fn endp_ctx_max_burst(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc) -> u8 {
|
||||
if speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch()) {
|
||||
assert_eq!(dev_desc.major_version(), 2);
|
||||
((endp_desc.max_packet_size & 0x0C00) >> 11) as u8
|
||||
} else if endp_desc.is_superspeed() {
|
||||
endp_desc.max_burst()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
}
|
||||
fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 {
|
||||
// TODO: Control endpoint? Encoding?
|
||||
endp_desc.max_packet_size & 0x03FF
|
||||
}
|
||||
fn endp_ctx_max_esit_payload(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc, max_packet_size: u16, max_burst_size: u8) -> u32 {
|
||||
const KIB: u32 = 1024;
|
||||
|
||||
if dev_desc.major_version() == 2 && endp_desc.is_periodic() {
|
||||
u32::from(max_packet_size) * (u32::from(max_burst_size) + 1)
|
||||
} else if !endp_desc.has_ssp_companion() {
|
||||
u32::from(endp_desc.ssc.as_ref().unwrap().bytes_per_interval)
|
||||
} else if endp_desc.has_ssp_companion() {
|
||||
endp_desc.sspc.as_ref().unwrap().bytes_per_interval
|
||||
} else if speed_id.is_fullspeed() && endp_desc.is_interrupt() {
|
||||
64
|
||||
} else if speed_id.is_fullspeed() && endp_desc.is_isoch() {
|
||||
1 * KIB
|
||||
} else if (speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch())) || endp_desc.is_superspeed() && endp_desc.is_interrupt() {
|
||||
3 * KIB
|
||||
} else if endp_desc.is_superspeed() && endp_desc.is_isoch() {
|
||||
48 * KIB
|
||||
} else {
|
||||
// TODO: Is "maximum allowed" ESIT payload, the same as "maximum" ESIT payload.
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> {
|
||||
let mut req: ConfigureEndpointsReq =
|
||||
serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?;
|
||||
@@ -286,9 +358,7 @@ impl Xhci {
|
||||
}
|
||||
|
||||
let port_speed_id = self.ports[port].speed();
|
||||
// FIXME
|
||||
let speed_id = self.lookup_psiv(port as u8, port_speed_id);
|
||||
dbg!(speed_id);
|
||||
let speed_id: &ProtocolSpeed = self.lookup_psiv(port as u8, port_speed_id).ok_or(Error::new(EIO))?;
|
||||
|
||||
let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?;
|
||||
let input_context: &mut Dma<InputContext> = &mut port_state.input_context;
|
||||
@@ -302,12 +372,12 @@ impl Xhci {
|
||||
|
||||
let current_slot_a = input_context.device.slot.a.read();
|
||||
|
||||
let endpoints = &port_state
|
||||
.dev_desc
|
||||
let dev_desc = &port_state.dev_desc;
|
||||
let endpoints = &dev_desc
|
||||
.config_descs
|
||||
.get(req.config_desc as usize)
|
||||
.ok_or(Error::new(EBADMSG))?
|
||||
.interface_descs[0]
|
||||
.interface_descs.get(req.interface_desc.unwrap_or(0) as usize).ok_or(Error::new(EBADMSG))?
|
||||
.endpoints;
|
||||
|
||||
if endpoints.len() >= 31 {
|
||||
@@ -342,7 +412,6 @@ impl Xhci {
|
||||
.ok_or(Error::new(EIO))?;
|
||||
let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?;
|
||||
|
||||
// TODO: Check if streams are actually supported.
|
||||
let max_streams = endp_desc.max_streams();
|
||||
let max_psa_size = self.cap.max_psa_size();
|
||||
|
||||
@@ -357,17 +426,17 @@ impl Xhci {
|
||||
// TODO: Interval related fields
|
||||
// TODO: Max ESIT payload size.
|
||||
|
||||
// TODO: The max burst size is non-zero for high-speed isoch endpoints. How are the USB2
|
||||
// speeds detected?
|
||||
// I presume that USB 3 devices can never be in low/full/high-speed mode, but
|
||||
// always SuperSpeed (gen 1 and 2 etc.).
|
||||
|
||||
let max_burst_size = endp_desc.max_burst();
|
||||
let max_packet_size = endp_desc.max_packet_size;
|
||||
|
||||
let mult = endp_desc.isoch_mult(lec);
|
||||
|
||||
let interval = endp_desc.interval;
|
||||
let max_packet_size = Self::endp_ctx_max_packet_size(endp_desc);
|
||||
let max_burst_size = Self::endp_ctx_max_burst(speed_id, dev_desc, endp_desc);
|
||||
|
||||
let max_esit_payload = Self::endp_ctx_max_esit_payload(speed_id, dev_desc, endp_desc, max_packet_size, max_burst_size);
|
||||
let max_esit_payload_lo = max_esit_payload as u16;
|
||||
let max_esit_payload_hi = ((max_esit_payload & 0x00FF_0000) >> 16) as u8;
|
||||
|
||||
let interval = Self::endp_ctx_interval(speed_id, endp_desc);
|
||||
|
||||
let max_error_count = 3;
|
||||
let ep_ty = endp_desc.xhci_ep_type()?;
|
||||
let host_initiate_disable = false;
|
||||
@@ -384,7 +453,6 @@ impl Xhci {
|
||||
assert_eq!(ep_ty & 0x7, ep_ty);
|
||||
assert_eq!(mult & 0x3, mult);
|
||||
assert_eq!(max_error_count & 0x3, max_error_count);
|
||||
|
||||
assert_ne!(ep_ty, 0); // 0 means invalid.
|
||||
|
||||
let ring_ptr = if max_streams != 0 {
|
||||
@@ -399,7 +467,6 @@ impl Xhci {
|
||||
array_ptr,
|
||||
"stream ctx ptr not aligned to 16 bytes"
|
||||
);
|
||||
|
||||
port_state.endpoint_states.insert(
|
||||
endp_num,
|
||||
EndpointState::Ready(super::RingOrStreams::Streams(array)),
|
||||
@@ -415,22 +482,20 @@ impl Xhci {
|
||||
ring_ptr,
|
||||
"ring pointer not aligned to 16 bytes"
|
||||
);
|
||||
|
||||
port_state.endpoint_states.insert(
|
||||
endp_num,
|
||||
EndpointState::Ready(super::RingOrStreams::Ring(ring)),
|
||||
);
|
||||
|
||||
ring_ptr
|
||||
};
|
||||
|
||||
assert_eq!(primary_streams & 0x1F, primary_streams);
|
||||
|
||||
endp_ctx.a.write(
|
||||
u32::from(mult) << 8
|
||||
| u32::from(interval) << 16
|
||||
| u32::from(primary_streams) << 10
|
||||
| u32::from(linear_stream_array) << 15,
|
||||
| u32::from(linear_stream_array) << 15
|
||||
| u32::from(interval) << 16
|
||||
| u32::from(max_esit_payload_hi) << 24
|
||||
);
|
||||
endp_ctx.b.write(
|
||||
max_error_count << 1
|
||||
@@ -439,9 +504,14 @@ impl Xhci {
|
||||
| u32::from(max_burst_size) << 8
|
||||
| u32::from(max_packet_size) << 16,
|
||||
);
|
||||
|
||||
endp_ctx.trl.write(ring_ptr as u32);
|
||||
endp_ctx.trh.write((ring_ptr >> 32) as u32);
|
||||
endp_ctx.c.write(u32::from(avg_trb_len));
|
||||
|
||||
endp_ctx.c.write(
|
||||
u32::from(avg_trb_len)
|
||||
| (u32::from(max_esit_payload_lo) << 16)
|
||||
);
|
||||
}
|
||||
|
||||
self.run.ints[0].erdp.write(self.cmd.erdp());
|
||||
@@ -719,8 +789,9 @@ impl Xhci {
|
||||
);
|
||||
|
||||
let (bos_desc, bos_data) = dev.get_bos()?;
|
||||
let has_superspeed =
|
||||
let supports_superspeed =
|
||||
usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed());
|
||||
let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus());
|
||||
|
||||
let config_descs = (0..raw_dd.configurations)
|
||||
.map(|index| -> Result<_> {
|
||||
@@ -756,12 +827,20 @@ impl Xhci {
|
||||
};
|
||||
let mut endp = EndpDesc::from(next);
|
||||
|
||||
if has_superspeed {
|
||||
if supports_superspeed {
|
||||
let next = match iter.next() {
|
||||
Some(AnyDescriptor::SuperSpeedCompanion(n)) => n,
|
||||
_ => break,
|
||||
};
|
||||
endp.ssc = Some(SuperSpeedCmp::from(next));
|
||||
|
||||
if endp.has_ssp_companion() && supports_superspeedplus {
|
||||
let next = match iter.next() {
|
||||
Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n,
|
||||
_ => break,
|
||||
};
|
||||
endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next));
|
||||
}
|
||||
}
|
||||
endpoints.push(endp);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user