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:
4lDO2
2020-02-11 11:39:29 +01:00
parent d82ae0a5f6
commit 05392696fe
6 changed files with 204 additions and 36 deletions
+5 -3
View File
@@ -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;
+44 -2
View File
@@ -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
View File
@@ -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;
+10 -1
View File
@@ -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 {
+1 -1
View File
@@ -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
View File
@@ -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);
}