xhcid: allow configuring multiple interfaces
This commit is contained in:
+19
-2
@@ -215,12 +215,30 @@ unsafe impl Sync for Xhci {}
|
||||
struct PortState {
|
||||
slot: u8,
|
||||
cfg_idx: Option<u8>,
|
||||
if_idx: Option<u8>,
|
||||
input_context: Mutex<Dma<InputContext>>,
|
||||
dev_desc: Option<DevDesc>,
|
||||
endpoint_states: BTreeMap<u8, EndpointState>,
|
||||
}
|
||||
|
||||
impl PortState {
|
||||
//TODO: fetch using endpoint number instead
|
||||
fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> {
|
||||
let cfg_idx = self.cfg_idx?;
|
||||
let config_desc = self.dev_desc.as_ref()?
|
||||
.config_descs.get(cfg_idx as usize)?;
|
||||
let mut endp_count = 0;
|
||||
for if_desc in config_desc.interface_descs.iter() {
|
||||
for endp_desc in if_desc.endpoints.iter() {
|
||||
if endp_idx == endp_count {
|
||||
return Some(endp_desc);
|
||||
}
|
||||
endp_count += 1;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum RingOrStreams {
|
||||
Ring(Ring),
|
||||
Streams(StreamContextArray),
|
||||
@@ -546,7 +564,6 @@ impl Xhci {
|
||||
input_context: Mutex::new(input),
|
||||
dev_desc: None,
|
||||
cfg_idx: None,
|
||||
if_idx: None,
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState {
|
||||
|
||||
+24
-50
@@ -375,19 +375,10 @@ impl Xhci {
|
||||
let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?;
|
||||
let mut port_state = self.port_state_mut(port_num)?;
|
||||
|
||||
let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) {
|
||||
(Some(c), Some(i)) => (c, i),
|
||||
_ => return Err(Error::new(EIO)),
|
||||
};
|
||||
|
||||
let slot = port_state.slot;
|
||||
|
||||
let (doorbell_data_stream, doorbell_data_no_stream) = {
|
||||
let endp_desc = port_state
|
||||
.dev_desc.as_ref().unwrap()
|
||||
.config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))?
|
||||
.interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))?
|
||||
.endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?;
|
||||
let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
//TODO: clean this up
|
||||
(
|
||||
@@ -501,14 +492,10 @@ impl Xhci {
|
||||
}
|
||||
|
||||
async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> {
|
||||
let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?;
|
||||
let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) {
|
||||
(Some(c), Some(i)) => (c, i),
|
||||
_ => return Err(Error::new(EIO)),
|
||||
};
|
||||
|
||||
let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?;
|
||||
let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?;
|
||||
let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc);
|
||||
|
||||
let slot = self
|
||||
@@ -619,23 +606,31 @@ impl Xhci {
|
||||
let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
port_state.cfg_idx = Some(req.config_desc);
|
||||
port_state.if_idx = Some(req.interface_desc.unwrap_or(0));
|
||||
|
||||
let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints;
|
||||
//TODO: USE ENDPOINTS FROM ALL INTERFACES
|
||||
let mut endp_desc_count = 0;
|
||||
let mut new_context_entries = 1;
|
||||
for if_desc in config_desc.interface_descs.iter() {
|
||||
for endpoint in if_desc.endpoints.iter() {
|
||||
endp_desc_count += 1;
|
||||
let entry = Self::endp_num_to_dci(endp_desc_count, endpoint);
|
||||
if entry > new_context_entries {
|
||||
new_context_entries = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
new_context_entries += 1;
|
||||
|
||||
if endpoints.len() >= 31 {
|
||||
warn!("endpoints length {} >= 31", endpoints.len());
|
||||
if endp_desc_count >= 31 {
|
||||
warn!("endpoints length {} >= 31", endp_desc_count);
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
|
||||
(
|
||||
endpoints.len(),
|
||||
(match endpoints.last() {
|
||||
Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l),
|
||||
None => 1,
|
||||
}) + 1,
|
||||
endp_desc_count,
|
||||
new_context_entries,
|
||||
config_desc.configuration_value,
|
||||
)
|
||||
};
|
||||
@@ -683,8 +678,7 @@ impl Xhci {
|
||||
|
||||
let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?;
|
||||
let dev_desc = port_state.dev_desc.as_ref().unwrap();
|
||||
let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints;
|
||||
let endp_desc = endpoints.get(endp_idx as usize).ok_or_else(|| {
|
||||
let endp_desc = port_state.get_endp_desc(endp_idx).ok_or_else(|| {
|
||||
warn!("failed to find endpoint {}", endp_idx);
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
@@ -922,23 +916,7 @@ impl Xhci {
|
||||
.get_mut(&port_num)
|
||||
.ok_or(Error::new(EBADFD))?;
|
||||
|
||||
let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) {
|
||||
(Some(c), Some(i)) => (c, i),
|
||||
_ => return Err(Error::new(EIO)),
|
||||
};
|
||||
|
||||
let endp_desc: &EndpDesc = port_state
|
||||
.dev_desc
|
||||
.as_ref().unwrap()
|
||||
.config_descs
|
||||
.get(usize::from(cfg_idx))
|
||||
.ok_or(Error::new(EIO))?
|
||||
.interface_descs
|
||||
.get(usize::from(if_idx))
|
||||
.ok_or(Error::new(EIO))?
|
||||
.endpoints
|
||||
.get(endp_idx as usize)
|
||||
.ok_or(Error::new(EBADFD))?;
|
||||
let endp_desc: &EndpDesc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?;
|
||||
|
||||
let direction = endp_desc.direction();
|
||||
|
||||
@@ -1856,15 +1834,11 @@ impl Xhci {
|
||||
endp_num: u8,
|
||||
deque_ptr_and_cycle: u64,
|
||||
) -> Result<()> {
|
||||
let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?;
|
||||
let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?;
|
||||
let slot = port_state.slot;
|
||||
|
||||
let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) {
|
||||
(Some(c), Some(i)) => (c, i),
|
||||
_ => return Err(Error::new(EIO)),
|
||||
};
|
||||
|
||||
let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?;
|
||||
let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?;
|
||||
let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc);
|
||||
|
||||
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
|
||||
|
||||
Reference in New Issue
Block a user