diff --git a/local/recipes/system/redbear-ecmd/source/Cargo.toml b/local/recipes/system/redbear-ecmd/source/Cargo.toml index e47223399c..d605bb1239 100644 --- a/local/recipes/system/redbear-ecmd/source/Cargo.toml +++ b/local/recipes/system/redbear-ecmd/source/Cargo.toml @@ -14,6 +14,9 @@ xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } +[target.'cfg(target_os = "redox")'.dependencies] +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } + [patch.crates-io] redox_syscall = { path = "../../../../../local/sources/syscall" } libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-ecmd/source/src/main.rs b/local/recipes/system/redbear-ecmd/source/src/main.rs index 479315d681..fda4cb00b9 100644 --- a/local/recipes/system/redbear-ecmd/source/src/main.rs +++ b/local/recipes/system/redbear-ecmd/source/src/main.rs @@ -6,6 +6,10 @@ //! Implements the CDC ECM subclass for USB Ethernet adapters: //! control requests (packet filter, multicast), bidirectional //! bulk I/O for Ethernet frames, and CDC notification handling. +//! On Redox: registers /scheme/net/usbECM_ for netstack integration. + +#[cfg(target_os = "redox")] +mod scheme; use std::{env, io, io::{Read, Write}, thread, time}; diff --git a/local/recipes/system/redbear-ecmd/source/src/scheme.rs b/local/recipes/system/redbear-ecmd/source/src/scheme.rs new file mode 100644 index 0000000000..8c9a9058fa --- /dev/null +++ b/local/recipes/system/redbear-ecmd/source/src/scheme.rs @@ -0,0 +1,50 @@ +use std::sync::Mutex; + +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; +use syscall::error::{Error, Result, EBADF, EINVAL}; +use syscall::flag::{MODE_FILE, O_RDWR, O_STAT}; + +use xhcid_interface::XhciEndpHandle; + +pub struct EcmScheme { + bulk_in: Mutex, + bulk_out: Mutex, + open_count: Mutex, +} + +impl EcmScheme { + pub fn new(bulk_in: XhciEndpHandle, bulk_out: XhciEndpHandle) -> Self { + Self { bulk_in: Mutex::new(bulk_in), bulk_out: Mutex::new(bulk_out), open_count: Mutex::new(0) } + } +} + +impl SchemeSync for EcmScheme { + fn openat(&self, id: usize, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { + if id != 1 { return Err(Error::new(EBADF)); } + if path.is_empty() || path == "." || path == "/" { + *self.open_count.lock().unwrap_or_else(|e| e.into_inner()) += 1; + return Ok(OpenResult::ThisScheme { number: 1, flags: O_STAT | MODE_FILE }); + } + let mut count = self.open_count.lock().unwrap_or_else(|e| e.into_inner()); + let next_id = 2 + *count; *count += 1; + Ok(OpenResult::OtherScheme { number: next_id, flags: O_RDWR }) + } + fn read(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { + if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); } + self.bulk_in.lock().unwrap_or_else(|e| e.into_inner()) + .transfer_read(buf).map(|s| s.bytes_transferred as usize) + .map_err(|e| { log::warn!("ECM scheme: read: {}", e); Error::new(EINVAL) }) + } + fn write(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result { + if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); } + self.bulk_out.lock().unwrap_or_else(|e| e.into_inner()) + .transfer_write(buf).map(|s| s.bytes_transferred as usize) + .map_err(|e| { log::warn!("ECM scheme: write: {}", e); Error::new(EINVAL) }) + } + fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { Ok(()) } + fn close(&self, id: usize, _ctx: &CallerCtx) -> Result<()> { + if id >= 2 { let mut c = self.open_count.lock().unwrap_or_else(|e| e.into_inner()); *c = c.saturating_sub(1); } + Ok(()) + } +} diff --git a/local/recipes/system/redbear-usbaudiod/source/Cargo.toml b/local/recipes/system/redbear-usbaudiod/source/Cargo.toml index f4a68e480b..3670fa9c11 100644 --- a/local/recipes/system/redbear-usbaudiod/source/Cargo.toml +++ b/local/recipes/system/redbear-usbaudiod/source/Cargo.toml @@ -14,6 +14,9 @@ xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } +[target.'cfg(target_os = "redox")'.dependencies] +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } + [patch.crates-io] redox_syscall = { path = "../../../../../local/sources/syscall" } libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-usbaudiod/source/src/main.rs b/local/recipes/system/redbear-usbaudiod/source/src/main.rs index 62913f1bf8..c0d8fa6a3c 100644 --- a/local/recipes/system/redbear-usbaudiod/source/src/main.rs +++ b/local/recipes/system/redbear-usbaudiod/source/src/main.rs @@ -9,6 +9,10 @@ //! - Audio Streaming Interface (PCM isochronous audio data) //! - Sample rates: 8000, 11025, 16000, 22050, 44100, 48000 Hz //! - 1-2 channels (mono/stereo), 8/16-bit +//! On Redox: registers /scheme/audio/usbAudio_ for audiod integration. + +#[cfg(target_os = "redox")] +mod scheme; use std::{env, io, io::{Read, Write}, thread, time}; diff --git a/local/recipes/system/redbear-usbaudiod/source/src/scheme.rs b/local/recipes/system/redbear-usbaudiod/source/src/scheme.rs new file mode 100644 index 0000000000..ccc283a1e3 --- /dev/null +++ b/local/recipes/system/redbear-usbaudiod/source/src/scheme.rs @@ -0,0 +1,56 @@ +use std::sync::Mutex; + +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; +use syscall::error::{Error, Result, EBADF, EINVAL}; +use syscall::flag::{MODE_FILE, O_RDONLY, O_WRONLY, O_STAT}; + +use xhcid_interface::XhciEndpHandle; + +pub struct AudioScheme { + isoch_in: Mutex, + isoch_out: Mutex>, + open_count: Mutex, +} + +impl AudioScheme { + pub fn new(isoch_in: XhciEndpHandle, isoch_out: Option) -> Self { + Self { isoch_in: Mutex::new(isoch_in), isoch_out: Mutex::new(isoch_out), open_count: Mutex::new(0) } + } +} + +impl SchemeSync for AudioScheme { + fn openat(&self, id: usize, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { + if id != 1 { return Err(Error::new(EBADF)); } + let mut c = self.open_count.lock().unwrap_or_else(|e| e.into_inner()); + if path.is_empty() || path == "." || path == "/" { + *c += 1; return Ok(OpenResult::ThisScheme { number: 1, flags: O_STAT | MODE_FILE }); + } + let flags = match path { + "capture" | "rec" => O_RDONLY, + "playback" | "play" => if self.isoch_out.lock().unwrap_or_else(|e| e.into_inner()).is_some() { O_WRONLY } else { return Err(Error::new(EINVAL)); }, + _ => O_RDWR, + }; + let next_id = 2 + *c; *c += 1; + Ok(OpenResult::OtherScheme { number: next_id, flags }) + } + fn read(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { + if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); } + self.isoch_in.lock().unwrap_or_else(|e| e.into_inner()) + .transfer_read(buf).map(|s| s.bytes_transferred as usize) + .map_err(|e| { log::warn!("Audio scheme: read: {}", e); Error::new(EINVAL) }) + } + fn write(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result { + if id < 2 || buf.is_empty() { return Err(Error::new(EBADF)); } + match self.isoch_out.lock().unwrap_or_else(|e| e.into_inner()).as_mut() { + Some(out) => out.transfer_write(buf).map(|s| s.bytes_transferred as usize) + .map_err(|e| { log::warn!("Audio scheme: write: {}", e); Error::new(EINVAL) }), + None => Err(Error::new(EINVAL)), + } + } + fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { Ok(()) } + fn close(&self, id: usize, _ctx: &CallerCtx) -> Result<()> { + if id >= 2 { let mut c = self.open_count.lock().unwrap_or_else(|e| e.into_inner()); *c = c.saturating_sub(1); } + Ok(()) + } +}