Implement stream transfers.

They only use one stream though, which defeats the purpose of streams,
but at least transfers now work.
This commit is contained in:
4lDO2
2020-02-09 22:35:56 +01:00
parent 6b70e80d20
commit 62915fadb1
7 changed files with 94 additions and 54 deletions
+20 -30
View File
@@ -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::<u8>::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 {
+1 -1
View File
@@ -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!(),
_ => (),
}
}
+6 -2
View File
@@ -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);
}
+16
View File
@@ -56,11 +56,20 @@ pub struct EndpDesc {
pub interval: u8,
pub ssc: Option<SuperSpeedCmp>,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndpDirection {
Out,
In,
Bidirectional,
}
impl From<PortReqDirection> 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<File, XhciClientHandleError> {
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,
+19 -4
View File
@@ -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<Ring>,
pub rings: BTreeMap<u16, Ring>,
}
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 {
+7
View File
@@ -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");
+25 -17
View File
@@ -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<u32> {
fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result<u32> {
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() {