Add a really basic interface to xhcid.

This commit is contained in:
4lDO2
2020-01-10 20:02:19 +11:00
parent e191e502e1
commit faa29b1854
9 changed files with 434 additions and 55 deletions
Generated
+39 -1
View File
@@ -264,6 +264,11 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ixgbed"
version = "1.0.0"
@@ -858,6 +863,11 @@ dependencies = [
"stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "safemem"
version = "0.3.1"
@@ -939,6 +949,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "serde"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
@@ -950,6 +963,16 @@ dependencies = [
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "slab"
version = "0.4.2"
@@ -960,6 +983,14 @@ name = "smallvec"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "spin"
version = "0.4.10"
@@ -1346,10 +1377,13 @@ dependencies = [
name = "xhcid"
version = "0.1.0"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1382,6 +1416,7 @@ dependencies = [
"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
@@ -1440,6 +1475,7 @@ dependencies = [
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b"
"checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
@@ -1452,8 +1488,10 @@ dependencies = [
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c"
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba"
+6
View File
@@ -36,3 +36,9 @@ class = 8
vendor = 33006
device = 51966
command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"]
[[drivers]]
name = "XHCI"
class = 12
subclass = 3
interface = 48
command = ["xhcid", "$NAME", "$BAR0", "$IRQ"]
+1
View File
@@ -0,0 +1 @@
/target
+4 -1
View File
@@ -4,8 +4,11 @@ version = "0.1.0"
edition = "2018"
[dependencies]
bitflags = "0.7"
bitflags = "1"
plain = "0.2"
spin = "0.4"
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" }
redox_syscall = "0.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
smallvec = { version = "1", features = ["serde"] }
+6 -6
View File
@@ -1,6 +1,6 @@
# [[drivers]]
# name = "XHCI"
# class = 12
# subclass = 3
# interface = 48
# command = ["xhcid", "$NAME", "$BAR0", "$IRQ"]
[[drivers]]
name = "XHCI"
class = 12
subclass = 3
interface = 48
command = ["xhcid", "$NAME", "$BAR0", "$IRQ"]
+7 -4
View File
@@ -6,7 +6,7 @@ extern crate syscall;
use event::{Event, EventQueue};
use std::cell::RefCell;
use std::env;
use std::{io, env};
use std::fs::File;
use std::io::{Result, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
@@ -37,7 +37,7 @@ fn main() {
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let socket_fd = syscall::open(":usb", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme");
let socket_fd = syscall::open(format!(":usb/{}-{}-{}", name, bar_str, irq_str), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme");
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) }));
let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
@@ -87,8 +87,11 @@ fn main() {
event_queue.add(socket_fd, move |_| -> Result<Option<()>> {
loop {
let mut packet = Packet::default();
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
break;
match socket_packet.borrow_mut().read(&mut packet) {
Ok(0) => break,
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
Ok(_) => (),
Err(err) => return Err(err),
}
let a = packet.a;
+41 -18
View File
@@ -1,5 +1,6 @@
use plain::Plain;
use std::{mem, slice};
use std::collections::BTreeMap;
use syscall::error::Result;
use syscall::io::{Dma, Io};
use crate::usb;
@@ -112,6 +113,16 @@ pub struct Xhci {
run: &'static mut RuntimeRegs,
dev_ctx: DeviceContextList,
cmd: CommandRing,
handles: BTreeMap<usize, scheme::Handle>,
next_handle: usize,
port_states: BTreeMap<usize, PortState>,
}
struct PortState {
slot: u8,
input_context: Dma<InputContext>,
ring: Ring,
}
impl Xhci {
@@ -178,6 +189,9 @@ impl Xhci {
run: run,
dev_ctx: DeviceContextList::new(max_slots)?,
cmd: CommandRing::new()?,
handles: BTreeMap::new(),
next_handle: 0,
port_states: BTreeMap::new(),
};
xhci.init(max_slots);
@@ -237,6 +251,24 @@ impl Xhci {
println!(" - XHCI initialized");
}
pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 {
let (cmd, cycle, event) = cmd.next();
cmd.enable_slot(0, cycle);
dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
let slot = (event.control.read() >> 24) as u8;
cmd.reserved(false);
event.reserved(false);
slot
}
pub fn probe(&mut self) -> Result<()> {
for (i, port) in self.ports.iter().enumerate() {
let data = port.read();
@@ -245,32 +277,18 @@ impl Xhci {
let flags = port.flags();
println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags);
if flags.contains(port::PORT_CCS) {
if flags.contains(port::PortFlags::PORT_CCS) {
//TODO: Link TRB when running to the end of the ring buffer
println!(" - Enable slot");
let slot;
{
let (cmd, cycle, event) = self.cmd.next();
self.run.ints[0].erdp.write(self.cmd.erdp()); // TODO: ?
cmd.enable_slot(0, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
slot = (event.control.read() >> 24) as u8;
cmd.reserved(false);
event.reserved(false);
}
self.run.ints[0].erdp.write(self.cmd.erdp());
let slot = Self::enable_port_slot(&mut self.cmd, &mut self.dbs);
println!(" - Slot {}", slot);
// transfer ring?
let mut ring = Ring::new(true)?;
let mut input = Dma::<InputContext>::zeroed()?;
@@ -360,6 +378,11 @@ impl Xhci {
}
}
}
self.port_states.insert(i, PortState {
slot,
input_context: input,
ring,
});
}
}
+22 -22
View File
@@ -1,28 +1,28 @@
use syscall::io::{Io, Mmio};
bitflags! {
pub flags PortFlags: u32 {
const PORT_CCS = 1 << 0,
const PORT_PED = 1 << 1,
const PORT_OCA = 1 << 3,
const PORT_PR = 1 << 4,
const PORT_PP = 1 << 9,
const PORT_PIC_AMB = 1 << 14,
const PORT_PIC_GRN = 1 << 15,
const PORT_LWS = 1 << 16,
const PORT_CSC = 1 << 17,
const PORT_PEC = 1 << 18,
const PORT_WRC = 1 << 19,
const PORT_OCC = 1 << 20,
const PORT_PRC = 1 << 21,
const PORT_PLC = 1 << 22,
const PORT_CEC = 1 << 23,
const PORT_CAS = 1 << 24,
const PORT_WCE = 1 << 25,
const PORT_WDE = 1 << 26,
const PORT_WOE = 1 << 27,
const PORT_DR = 1 << 30,
const PORT_WPR = 1 << 31,
pub struct PortFlags: u32 {
const PORT_CCS = 1 << 0;
const PORT_PED = 1 << 1;
const PORT_OCA = 1 << 3;
const PORT_PR = 1 << 4;
const PORT_PP = 1 << 9;
const PORT_PIC_AMB = 1 << 14;
const PORT_PIC_GRN = 1 << 15;
const PORT_LWS = 1 << 16;
const PORT_CSC = 1 << 17;
const PORT_PEC = 1 << 18;
const PORT_WRC = 1 << 19;
const PORT_OCC = 1 << 20;
const PORT_PRC = 1 << 21;
const PORT_PLC = 1 << 22;
const PORT_CEC = 1 << 23;
const PORT_CAS = 1 << 24;
const PORT_WCE = 1 << 25;
const PORT_WDE = 1 << 26;
const PORT_WOE = 1 << 27;
const PORT_DR = 1 << 30;
const PORT_WPR = 1 << 31;
}
}
+308 -3
View File
@@ -1,4 +1,309 @@
use super::Xhci;
use syscall::scheme::SchemeMut;
use std::{cmp, mem, str};
use std::io::prelude::*;
impl SchemeMut for Xhci {}
use plain::Plain;
use serde::Serialize;
use smallvec::SmallVec;
use syscall::io::Io;
use syscall::scheme::SchemeMut;
use syscall::{
EACCES, EBADF, EINVAL, EISDIR, ENOENT,
O_CREAT, O_DIRECTORY, O_STAT, ENOSYS, ENOTDIR,
MODE_DIR, MODE_FILE,
SEEK_CUR, SEEK_END, SEEK_SET,
Stat,
Error, Result
};
use super::{Device, Xhci};
use super::{port, usb};
pub enum Handle {
TopLevel(usize, Vec<u8>), // offset, contents (ports)
Port(usize, usize, Vec<u8>), // port, offset, contents
PortDesc(usize, usize, Vec<u8>), // port, offset, contents
}
#[derive(Serialize)]
struct PortDesc {
// I have no idea whether this number is useful to the API users.
slot: u8,
dev_desc: DevDescJson,
}
#[derive(Serialize)]
struct DevDescJson {
// TODO: length?
kind: u8,
usb: u16,
class: u8,
sub_class: u8,
protocol: u8,
packet_size: u8,
vendor: u16,
product: u16,
release: u16,
manufacturer_str: Option<String>,
product_str: Option<String>,
serial_str: Option<String>,
config_descs: SmallVec<[ConfDescJson; 1]>,
}
#[derive(Serialize)]
struct ConfDescJson {
// TODO: length?
kind: u8,
// TODO: total_length?
// TODO: configuration_value?
configuration: Option<String>,
attributes: u8,
max_power: u8,
interface_descs: SmallVec<[IfDescJson; 1]>,
}
#[derive(Serialize)]
struct EndpDescJson {
kind: u8,
address: u8,
attributes: u8,
max_packet_size: u16,
interval: u8,
}
#[derive(Serialize)]
struct IfDescJson {
// TODO: length?
kind: u8,
number: u8,
alternate_setting: u8,
class: u8,
sub_class: u8,
protocol: u8,
interface_str: Option<String>,
endpoints: SmallVec<[EndpDescJson; 2]>,
}
impl Xhci {
fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec<u8>) -> Result<()> {
let port = self.ports.get(port_id).ok_or(Error::new(ENOENT))?;
if !port.flags().contains(port::PortFlags::PORT_CCS) {
return Err(Error::new(ENOENT));
}
let st = self.port_states.get_mut(&port_id).unwrap();
// TODO: Should the descriptors be stored in PortState?
self.run.ints[0].erdp.write(self.cmd.erdp());
let mut dev = Device {
ring: &mut st.ring,
cmd: &mut self.cmd,
db: &mut self.dbs[st.slot as usize],
int: &mut self.run.ints[0],
};
let raw_dd = dev.get_device()?;
let (manufacturer_str, product_str, serial_str) = (
if raw_dd.manufacturer_str > 0 {
Some(dev.get_string(raw_dd.manufacturer_str)?)
} else { None },
if raw_dd.product_str > 0 {
Some(dev.get_string(raw_dd.product_str)?)
} else { None },
if raw_dd.serial_str > 0 {
Some(dev.get_string(raw_dd.serial_str)?)
} else { None },
);
let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> {
let (desc, data) = dev.get_config(index)?;
let extra_length = desc.total_length as usize - mem::size_of::<usb::ConfigDescriptor>();
let mut i = 0;
let interface_descs = (0..desc.interfaces).filter_map(|_| -> Option<Result<_>> {
let mut idesc = usb::InterfaceDescriptor::default();
if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() {
i += mem::size_of_val(&idesc);
let endpoints = (0..idesc.endpoints).filter_map(|_| {
let mut edesc = usb::EndpointDescriptor::default();
if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() {
Some(EndpDescJson {
address: edesc.address,
attributes: edesc.attributes,
interval: edesc.interval,
kind: edesc.kind,
max_packet_size: edesc.max_packet_size,
})
} else { None }
}).collect();
Some(Ok(IfDescJson {
kind: idesc.kind,
number: idesc.number,
alternate_setting: idesc.alternate_setting,
class: idesc.class,
sub_class: idesc.sub_class,
protocol: idesc.protocol,
interface_str: match if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)) } else { None } {
Some(Err(err)) => return Some(Err(err)),
Some(Ok(ok)) => Some(ok),
None => None,
},
endpoints,
}))
} else {
None
}
}).collect::<Result<SmallVec<_>>>()?;
Ok(ConfDescJson {
kind: desc.kind,
configuration: if desc.configuration_str > 0 { Some(dev.get_string(desc.configuration_str)?) } else { None },
attributes: desc.attributes,
max_power: desc.max_power,
interface_descs,
})
}).collect::<Result<SmallVec<_>>>()?;
let dev_desc = DevDescJson {
kind: raw_dd.kind,
usb: raw_dd.usb,
class: raw_dd.class,
sub_class: raw_dd.sub_class,
protocol: raw_dd.protocol,
packet_size: raw_dd.packet_size,
vendor: raw_dd.vendor,
product: raw_dd.product,
release: raw_dd.release,
manufacturer_str,
product_str,
serial_str,
config_descs,
};
let desc = PortDesc {
slot: st.slot,
dev_desc,
};
serde_json::to_writer_pretty(contents, &desc).unwrap();
Ok(())
}
}
impl SchemeMut for Xhci {
fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid != 0 { return Err(Error::new(EACCES)) }
if flags & O_CREAT != 0 { return Err(Error::new(EINVAL) ) }
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/');
if path_str.is_empty() {
if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 {
let mut contents = Vec::new();
for (index, _) in self.ports.iter().enumerate().filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) {
write!(contents, "port{}\n", index).unwrap();
}
let fd = self.next_handle;
self.handles.insert(fd, Handle::TopLevel(0, contents));
self.next_handle += 1;
Ok(fd)
} else {
return Err(Error::new(EISDIR));
}
} else if path_str.starts_with("port") {
let slash_idx = path_str.chars().position(|c| c == '/');
let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())];
let num = num_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && path_str[slash_idx.unwrap() + 1..].starts_with("descriptor") {
if flags & O_DIRECTORY != 0 {
return Err(Error::new(ENOTDIR));
}
let mut contents = Vec::new();
self.write_port_desc(num, &mut contents)?;
let fd = self.next_handle;
self.handles.insert(fd, Handle::PortDesc(num, 0, contents));
self.next_handle += 1;
return Ok(fd);
}
if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 {
let mut contents = Vec::new();
write!(contents, "descriptor\n").unwrap();
let fd = self.next_handle;
self.handles.insert(fd, Handle::Port(num, 0, contents));
self.next_handle += 1;
Ok(fd)
} else {
return Err(Error::new(EISDIR));
}
} else {
return Err(Error::new(ENOSYS));
}
}
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) => {
// TODO: Known size perhaps?
stat.st_mode = MODE_DIR;
stat.st_size = buf.len() as u64;
Ok(0)
}
Handle::PortDesc(_, _, ref buf) => {
stat.st_mode = MODE_FILE;
stat.st_size = buf.len() as u64;
Ok(0)
}
}
}
fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) => {
*offset = match whence {
SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())),
SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())),
SEEK_END => cmp::max(0, cmp::min(buf.len() + pos, buf.len())),
_ => return Err(Error::new(EINVAL)),
};
Ok(*offset)
}
}
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) => {
let max_bytes_to_read = cmp::min(src_buf.len(), buf.len());
let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset;
buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]);
*offset += bytes_to_read;
Ok(bytes_to_read)
}
}
}
fn close(&mut self, fd: usize) -> Result<usize> {
if self.handles.remove(&fd).is_none() {
return Err(Error::new(EBADF));
}
Ok(0)
}
}