diff --git a/drivers/i2c/designware/src/lib.rs b/drivers/i2c/designware/src/lib.rs index c90bcb775b..e3c868c855 100644 --- a/drivers/i2c/designware/src/lib.rs +++ b/drivers/i2c/designware/src/lib.rs @@ -595,7 +595,7 @@ pub mod endpoint { use anyhow::{Context, Result}; use i2c_interface::{I2cTransferRequest, I2cTransferResponse, I2cTransferStatus}; - use redox_scheme::scheme::{register_sync_scheme, SchemeSync}; + use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult, Socket}; use scheme_utils::{Blocking, HandleMap}; use syscall::schemev2::NewFdFlags; @@ -861,8 +861,17 @@ pub mod endpoint { handles: HandleMap::new(), controllers, }; - register_sync_scheme(&socket, scheme_name, &mut endpoint) - .with_context(|| format!("failed to register {scheme_name} scheme"))?; + + // type={scheme} handshake: deliver the capability fd to init over + // INIT_NOTIFY so init registers /scheme/ and returns from + // call_ro(FD). register_sync_scheme alone deadlocks init (ptyd-class). + let cap_id = endpoint + .scheme_root() + .context("failed to compute scheme root")?; + let cap_fd = socket + .create_this_scheme_fd(0, cap_id, 0, 0) + .context("failed to create scheme capability fd")?; + notify_init_scheme_fd(cap_fd).context("failed to deliver scheme fd to init")?; log::info!( "dw-i2c: serving /scheme/{scheme_name} with {} controller(s)", @@ -882,6 +891,16 @@ pub mod endpoint { Ok(()) } + fn notify_init_scheme_fd(cap_fd: usize) -> Result<()> { + let pipe_fd: usize = std::env::var("INIT_NOTIFY") + .context("INIT_NOTIFY is not set")? + .parse() + .context("INIT_NOTIFY is not a valid fd")?; + syscall::call_wo(pipe_fd, &cap_fd.to_ne_bytes(), syscall::CallFlags::FD, &[]) + .context("failed to write scheme fd to the INIT_NOTIFY pipe")?; + Ok(()) + } + #[cfg(test)] mod tests { use super::*;