From 62915fadb1fabfef011941cc8fbacca5df5cf50b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Feb 2020 22:35:56 +0100 Subject: [PATCH] Implement stream transfers. They only use one stream though, which defeats the purpose of streams, but at least transfers now work. --- usbhidd/src/main.rs | 50 ++++++++++++++--------------------- usbhidd/src/report_desc.rs | 2 +- usbscsid/src/main.rs | 8 ++++-- xhcid/src/driver_interface.rs | 16 +++++++++++ xhcid/src/xhci/context.rs | 23 +++++++++++++--- xhcid/src/xhci/mod.rs | 7 +++++ xhcid/src/xhci/scheme.rs | 42 +++++++++++++++++------------ 7 files changed, 94 insertions(+), 54 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 40304bfb42..8871b471fc 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -16,19 +16,6 @@ fn div_round_up(num: u32, denom: u32) -> u32 { if num % denom == 0 { num / denom } else { num / denom + 1 } } -bitflags! { - pub struct ModifierKeys: u8 { - const LEFT_CTRL = 1 << 0; - const LEFT_SHIFT = 1 << 1; - const LEFT_ALT = 1 << 2; - const LEFT_META = 1 << 3; - const RIGHT_CTRL = 1 << 4; - const RIGHT_SHIFT = 1 << 5; - const RIGHT_ALT = 1 << 6; - const RIGHT_META = 1 << 7; - } -} - struct BinaryView<'a> { data: &'a [u8], offset: usize, @@ -189,12 +176,9 @@ fn main() { let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); - let mut pressed_keys = vec! []; + let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); - let mut modifier_keys = ModifierKeys::empty(); - let mut last_modifier_keys = modifier_keys; - loop { std::thread::sleep(std::time::Duration::from_millis(10)); @@ -209,27 +193,35 @@ fn main() { let report_size = global_state.report_size.unwrap(); let report_count = global_state.report_count.unwrap(); - if input.contains(MainItemFlags::VARIABLE) { - // variable - //assert_eq!(state.logical_max.unwrap() - state.logical_min.unwrap(), report_count, "modifiers don't map"); + // TODO: For now, the dynamic value usages cannot overlap with selector usages... + // for now. + + if local_state.usage_min == Some(224) && local_state.usage_max == Some(231) { + // The usages that this descriptor references are all dynamic values. + } else { + // The usages are selectors. + } + + for report_index in 0..report_count { + } + + /*if input.contains(MainItemFlags::VARIABLE) { + // The item is a variable. + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); - // PRETTYFYME + if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { - std::mem::swap(&mut modifier_keys, &mut last_modifier_keys); - modifier_keys = match ModifierKeys::from_bits(binary_view.read_u8(0).unwrap()) { - Some(f) => f, - None => unreachable!(), - }; } else { println!("unknown report variable item"); } } else { + // The item is an array. + std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); pressed_keys.clear(); println!("INPUT FLAGS: {:?}", input); assert_eq!(report_size, 8); - // array for report_index in 0..report_count as usize { let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); let usage = binary_view.read_u8(0).expect("Failed to read array item"); @@ -238,10 +230,8 @@ fn main() { } println!("Report index array {}: {}", report_index, usage); } - - } + }*/ } - let changed_modifier_keys = modifier_keys ^ last_modifier_keys; for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) { if current == last { continue } if current != 0 { diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index 93c3083b78..b33927e13e 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -147,7 +147,7 @@ pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &Rep &LocalItem::StringMaximum(m) => current_state.str_max = Some(m), &LocalItem::Delimeter(_) => todo!(), }, - _ => todo!(), + _ => (), } } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index c5d12dbba2..9f427f6a52 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,6 +1,6 @@ use std::env; -use xhcid_interface::XhciClientHandle; +use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; pub mod scsi; @@ -17,6 +17,10 @@ fn main() { println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); let handle = XhciClientHandle::new(scheme, port); + + handle.configure_endpoints(&ConfigureEndpointsReq { + config_desc: 0, + }).expect("Failed to configure endpoints"); + let protocol = protocol::setup(&handle, protocol); - } diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index c68aeed058..d019d420f9 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -56,11 +56,20 @@ pub struct EndpDesc { pub interval: u8, pub ssc: Option, } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum EndpDirection { Out, In, Bidirectional, } +impl From for EndpDirection { + fn from(d: PortReqDirection) -> Self { + match d { + PortReqDirection::DeviceToHost => Self::In, + PortReqDirection::HostToDevice => Self::Out, + } + } +} impl EndpDesc { pub fn ty(self) -> EndpointTy { @@ -344,6 +353,13 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } + pub fn open_endpoint(&self, num: u8, direction: PortReqDirection) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num); + Ok(match direction { + PortReqDirection::HostToDevice => OpenOptions::new().read(false).write(true).create(false).open(path)?, + PortReqDirection::DeviceToHost => OpenOptions::new().read(true).write(false).create(false).open(path)?, + }) + } pub fn device_request<'a>( &self, req_type: PortReqTy, diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 77614e3d94..9403fa0ac5 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; @@ -123,7 +125,7 @@ pub enum StreamContextType { pub struct StreamContextArray { pub contexts: Dma<[StreamContext]>, - pub rings: Vec, + pub rings: BTreeMap, } impl StreamContextArray { @@ -131,13 +133,26 @@ impl StreamContextArray { unsafe { Ok(Self { contexts: Dma::zeroed_unsized(count)?, - rings: Vec::new(), + rings: BTreeMap::new(), }) } } pub fn add_ring(&mut self, stream_id: u16, link: bool) -> Result<()> { - // NOTE: stream_id is reserved - self.rings.insert(stream_id as usize, Ring::new(link)?); + // NOTE: stream_id 0 is reserved + assert_ne!(stream_id, 0); + + let ring = Ring::new(link)?; + let pointer = ring.register(); + let sct = StreamContextType::PrimaryRing; + + assert_eq!(pointer & (!0xE), pointer); + { + let context = &mut self.contexts[stream_id as usize]; + context.trl.write((pointer as u32) | ((sct as u32) << 1)); + context.trh.write((pointer >> 32) as u32); + // TODO: stopped edtla + } + self.rings.insert(stream_id, ring); Ok(()) } pub fn register(&self) -> u64 { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index cf6923afd4..ea50ba7aff 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -410,6 +410,13 @@ impl Xhci { Ok(()) } + pub fn ring_command_doorbell(&mut self) { + self.dbs[0].write(0); + } + pub fn ring_port_doorbell(&mut self, slot: u8, endpoint: u8, stream_id: u16) { + self.dbs[slot as usize].write(u32::from(endpoint) | (u32::from(stream_id) << 16)); + } + pub fn trigger_irq(&mut self) -> bool { // Read the Interrupter Pending bit. println!("preinterrupt"); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 6811ff0216..5ba1810407 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -408,17 +408,17 @@ impl Xhci { self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::Out(buf) } else { DeviceReqData::NoData }) } // TODO: Rename DeviceReqData to something more general. - fn transfer(&mut self, port_num: usize, endp_idx: u8, buf: DeviceReqData) -> Result { + fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result { let endp_num = endp_idx + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), // UB. - let mut dma_buffer = match buf { + let dma_buffer = match buf { DeviceReqData::Out(sbuf) => { - let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); Some(dma_buffer) } - DeviceReqData::In(dbuf) => { + DeviceReqData::In(ref dbuf) => { Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) } DeviceReqData::NoData => None, @@ -426,11 +426,20 @@ impl Xhci { let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADF))?; + + if endp_desc.is_isoch() { + return Err(Error::new(ENOSYS)); + } + + if EndpDirection::from(buf.direction()) != endp_desc.direction() { + return Err(Error::new(EBADF)); + } + let endp_state = port_state.endpoint_states.get_mut(&endp_idx).ok_or(Error::new(EBADF))?; let ring: &mut Ring = match endp_state { EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, - EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(1).ok_or(Error::new(EBADF))?, + EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(&1).ok_or(Error::new(EBADF))?, EndpointState::Init => return Err(Error::new(EIO)), }; // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. @@ -439,22 +448,21 @@ impl Xhci { { let (trb, cycle) = ring.next(); let (buffer, idt) = if len <= 8 && max_packet_size >= 8 { - buf.map_buf(|buf| { - let bytes = match <[u8; 8]>::try_from(buf) { - Ok(b) => b, - Err(_) => unreachable!(), - }; + buf.map_buf(|sbuf| { + let mut bytes = [0u8; 8]; + bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]); // FIXME: little endian, right? (u64::from_le_bytes(bytes), true) }).unwrap_or((0, false)) } else { - (dma_buffer.map(|dma| dma.physical()).unwrap_or(0) as u64, false) + (dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false) }; let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td trb.normal(buffer, len, cycle, estimated_td_size, false, true, false, true, idt, false); } - self.dbs[port_state.slot as usize].write(endp_num.into()); + let stream_id = 1u16; + self.dbs[port_state.slot as usize].write(u32::from(endp_num) | (u32::from(stream_id) << 16)); let bytes_transferred = { let event = self.cmd.next_event(); @@ -476,8 +484,8 @@ impl Xhci { u32::from(len) - event.transfer_length() }; - if let DeviceReqData::In(ref mut dbuf) = buf { - dbuf.copy_from_slice(dma_buffer.unwrap()); + if let DeviceReqData::In(dbuf) = &mut buf { + dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); } Ok(bytes_transferred) @@ -876,8 +884,8 @@ impl SchemeMut for Xhci { .get(&endpoint_num) .ok_or(Error::new(ENOENT))? { - EndpointState::Init => "status\n", - EndpointState::Ready { .. } => "transfer\nstatus\n", + EndpointState::Ready { .. } if endpoint_num != 0 => "transfer\nstatus\n", + EndpointState::Init | EndpointState::Ready { .. } => "status\n", } .as_bytes() .to_owned(); @@ -914,7 +922,7 @@ impl SchemeMut for Xhci { if endpoint_num == 0 { // Don't allow user programs to interface directly with the control // endpoint. - return Err(Error::new(EPERM)); + return Err(Error::new(ENOENT)); } let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?; match endp_desc.direction() {