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:
+20
-30
@@ -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 {
|
||||
|
||||
@@ -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!(),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user