Files
RedBear-OS/local/patches/base/P0-inputd-per-device-consumers.patch
vasilito 2b8dd96a5c fix: absorb redundant base daemon and driver patches
Consolidate ~30 absorbed base patches into surviving carriers. Add
new init service files, driver sources, and network/storage modules
for the base recipe. Move absorbed patches to local/patches/base/absorbed/.
2026-05-11 10:09:25 +01:00

245 lines
7.6 KiB
Diff

--- a/drivers/inputd/src/main.rs
+++ b/drivers/inputd/src/main.rs
@@ -18,7 +18,7 @@
use std::ops::ControlFlow;
use std::sync::atomic::{AtomicUsize, Ordering};
-use inputd::{ControlEvent, VtEvent, VtEventKind};
+use inputd::{ControlEvent, HotplugEventHeader, VtEvent, VtEventKind};
use libredox::errno::ESTALE;
use redox_scheme::scheme::SchemeSync;
@@ -49,6 +49,17 @@
notified: bool,
vt: usize,
},
+ DeviceConsumer {
+ device_name: String,
+ events: EventFlags,
+ pending: Vec<u8>,
+ notified: bool,
+ },
+ HotplugEvents {
+ events: EventFlags,
+ pending: Vec<u8>,
+ notified: bool,
+ },
Display {
events: EventFlags,
pending: Vec<VtEvent>,
@@ -89,6 +100,9 @@
"control",
];
+const DEVICE_ADD: u32 = 1;
+const DEVICE_REMOVE: u32 = 2;
+
enum ProducerKind {
Legacy,
Named(String),
@@ -116,7 +130,7 @@
}
fn register_named_producer(&mut self, name: &str) -> syscall::Result<Handle> {
- if name.is_empty() || RESERVED_DEVICE_NAMES.contains(&name) {
+ if name.is_empty() || name.contains('/') || RESERVED_DEVICE_NAMES.contains(&name) {
return Err(SysError::new(EINVAL));
}
@@ -126,9 +140,55 @@
let device_id = self.next_device_id.fetch_add(1, Ordering::SeqCst) as u32;
self.devices.insert(name.to_owned(), device_id);
+ self.queue_hotplug_event(DEVICE_ADD, device_id, name)?;
Ok(Handle::NamedProducer {
name: name.to_owned(),
})
+ }
+
+ fn drain_pending_bytes(pending: &mut Vec<u8>, buf: &mut [u8]) -> usize {
+ let copy = core::cmp::min(pending.len(), buf.len());
+
+ for (i, byte) in pending.drain(..copy).enumerate() {
+ buf[i] = byte;
+ }
+
+ copy
+ }
+
+ fn queue_hotplug_event(
+ &mut self,
+ kind: u32,
+ device_id: u32,
+ name: &str,
+ ) -> syscall::Result<()> {
+ let name_len = u32::try_from(name.len()).map_err(|_| SysError::new(EINVAL))?;
+ let header = HotplugEventHeader {
+ kind,
+ device_id,
+ name_len,
+ _reserved: 0,
+ };
+ let header_bytes = unsafe {
+ core::slice::from_raw_parts(
+ (&header as *const HotplugEventHeader).cast::<u8>(),
+ size_of::<HotplugEventHeader>(),
+ )
+ };
+
+ for handle in self.handles.values_mut() {
+ if let Handle::HotplugEvents {
+ pending, notified, ..
+ } = handle
+ {
+ pending.extend_from_slice(header_bytes);
+ pending.extend_from_slice(name.as_bytes());
+ *notified = false;
+ }
+ }
+
+ self.has_new_events = true;
+ Ok(())
}
fn route_legacy_consumer_events(&mut self, buf: &[u8]) {
@@ -150,9 +210,21 @@
}
}
- fn route_named_producer_events(&mut self, _name: &str, _buf: &[u8]) {
- // DeviceConsumer routing is added in a follow-up patch. Named producers already share the
- // legacy consumer path, so existing callers continue to receive these events.
+ fn route_named_producer_events(&mut self, name: &str, buf: &[u8]) {
+ for handle in self.handles.values_mut() {
+ match handle {
+ Handle::DeviceConsumer {
+ device_name,
+ pending,
+ notified,
+ ..
+ } if device_name == name => {
+ pending.extend_from_slice(buf);
+ *notified = false;
+ }
+ _ => continue,
+ }
+ }
}
fn switch_vt(&mut self, new_active: usize) {
@@ -319,7 +391,24 @@
is_earlyfb: command == "handle_early",
}
}
+ "events" if path_parts.next().is_none() => Handle::HotplugEvents {
+ events: EventFlags::empty(),
+ pending: Vec::new(),
+ notified: false,
+ },
"control" => Handle::Control,
+ device_name
+ if !device_name.is_empty()
+ && !RESERVED_DEVICE_NAMES.contains(&device_name)
+ && path_parts.next().is_none() =>
+ {
+ Handle::DeviceConsumer {
+ device_name: device_name.to_owned(),
+ events: EventFlags::empty(),
+ pending: Vec::new(),
+ notified: false,
+ }
+ }
_ => {
log::error!("invalid path '{path}'");
@@ -372,13 +461,11 @@
return Err(SysError::new(ESTALE));
}
- let copy = core::cmp::min(pending.len(), buf.len());
-
- for (i, byte) in pending.drain(..copy).enumerate() {
- buf[i] = byte;
- }
-
- Ok(copy)
+ Ok(Self::drain_pending_bytes(pending, buf))
+ }
+
+ Handle::DeviceConsumer { pending, .. } | Handle::HotplugEvents { pending, .. } => {
+ Ok(Self::drain_pending_bytes(pending, buf))
}
Handle::Display { pending, .. } => {
@@ -443,6 +530,10 @@
Handle::Consumer { .. } => {
log::error!("consumer tried to write");
+ return Err(SysError::new(EINVAL));
+ }
+ Handle::DeviceConsumer { .. } | Handle::HotplugEvents { .. } => {
+ log::error!("consumer or hotplug handle tried to write");
return Err(SysError::new(EINVAL));
}
Handle::Display { .. } => {
@@ -531,6 +622,16 @@
ref mut events,
ref mut notified,
..
+ }
+ | Handle::DeviceConsumer {
+ ref mut events,
+ ref mut notified,
+ ..
+ }
+ | Handle::HotplugEvents {
+ ref mut events,
+ ref mut notified,
+ ..
} => {
*events = flags;
*notified = false;
@@ -561,7 +662,12 @@
match handle {
Handle::NamedProducer { name } => {
- self.devices.remove(&name);
+ if let Some(device_id) = self.devices.remove(&name) {
+ self.queue_hotplug_event(DEVICE_REMOVE, device_id, &name)
+ .unwrap_or_else(|err| {
+ log::error!("failed to queue removal hotplug event for {name}: {err}");
+ });
+ }
}
Handle::Consumer { vt, .. } => {
self.vts.remove(&vt);
@@ -639,6 +745,28 @@
*notified = true;
}
+ Handle::DeviceConsumer {
+ events,
+ pending,
+ ref mut notified,
+ ..
+ }
+ | Handle::HotplugEvents {
+ events,
+ pending,
+ ref mut notified,
+ } => {
+ if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) {
+ continue;
+ }
+
+ socket_file.write_response(
+ Response::post_fevent(*id, EventFlags::EVENT_READ.bits()),
+ SignalBehavior::Restart,
+ )?;
+
+ *notified = true;
+ }
_ => {}
}
}