mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
188 lines
7.4 KiB
Rust
188 lines
7.4 KiB
Rust
// Plan:
|
|
// - Manager has udev monitor on USB looking for ROG devices
|
|
// - If a device is found, add it to watch
|
|
// - Add it to Zbus server
|
|
// - If udev sees device removed then remove the zbus path
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use log::{debug, error, info, warn};
|
|
use mio::{Events, Interest, Poll, Token};
|
|
use rog_aura::AuraDeviceType;
|
|
use rog_platform::hid_raw::HidRaw;
|
|
use tokio::task::spawn_blocking;
|
|
use udev::{Device, MonitorBuilder};
|
|
use zbus::object_server::SignalContext;
|
|
use zbus::zvariant::{ObjectPath, OwnedObjectPath};
|
|
use zbus::Connection;
|
|
|
|
use crate::ctrl_aura::controller::CtrlKbdLed;
|
|
use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_PATH};
|
|
use crate::error::RogError;
|
|
use crate::{CtrlTask, Reloadable};
|
|
|
|
pub struct AuraManager {
|
|
_connection: Connection,
|
|
}
|
|
|
|
impl AuraManager {
|
|
pub async fn new(connection: Connection) -> Result<Self, RogError> {
|
|
let conn_copy = connection.clone();
|
|
let mut interfaces = HashSet::new();
|
|
|
|
// Do the initial keyboard detection:
|
|
let all = CtrlKbdLed::find_all()?;
|
|
for ctrl in all {
|
|
let path = ctrl.dbus_path.clone();
|
|
interfaces.insert(path.clone()); // ensure we record the initial stuff
|
|
let sig_ctx = CtrlAuraZbus::signal_context(&connection)?;
|
|
let sig_ctx2 = sig_ctx.clone();
|
|
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
|
|
start_tasks(zbus, connection.clone(), sig_ctx2, path).await?;
|
|
}
|
|
|
|
let manager = Self {
|
|
_connection: connection,
|
|
};
|
|
|
|
// detect all plugged in aura devices (eventually)
|
|
// only USB devices are detected for here
|
|
spawn_blocking(move || {
|
|
let mut monitor = MonitorBuilder::new()?.match_subsystem("hidraw")?.listen()?;
|
|
let mut poll = Poll::new()?;
|
|
let mut events = Events::with_capacity(1024);
|
|
poll.registry()
|
|
.register(&mut monitor, Token(0), Interest::READABLE)?;
|
|
|
|
loop {
|
|
if poll.poll(&mut events, None).is_err() {
|
|
continue;
|
|
}
|
|
for event in monitor.iter() {
|
|
let parent = if let Some(parent) =
|
|
event.parent_with_subsystem_devtype("usb", "usb_device")?
|
|
{
|
|
parent
|
|
} else {
|
|
continue;
|
|
};
|
|
|
|
let action = if let Some(action) = event.action() {
|
|
action
|
|
} else {
|
|
continue;
|
|
};
|
|
|
|
let id_product = if let Some(id_product) = parent.attribute_value("idProduct") {
|
|
id_product.to_string_lossy()
|
|
} else {
|
|
continue;
|
|
};
|
|
|
|
let path = if let Some(path) = dbus_path_for_dev(&parent) {
|
|
path
|
|
} else {
|
|
continue;
|
|
};
|
|
|
|
let aura_device = AuraDeviceType::from(&*id_product);
|
|
if aura_device == AuraDeviceType::Unknown {
|
|
warn!("idProduct:{id_product:?} is unknown, not using");
|
|
continue;
|
|
}
|
|
|
|
if action == "remove" {
|
|
if interfaces.remove(&path) {
|
|
info!("AuraManager removing: {path:?}");
|
|
let conn_copy = conn_copy.clone();
|
|
tokio::spawn(async move {
|
|
let res = conn_copy
|
|
.object_server()
|
|
.remove::<CtrlAuraZbus, _>(&path)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Failed to remove {path:?}, {e:?}");
|
|
e
|
|
})?;
|
|
info!("AuraManager removed: {path:?}, {res}");
|
|
Ok::<(), RogError>(())
|
|
});
|
|
}
|
|
} else if action == "add" {
|
|
if interfaces.contains(&path) {
|
|
debug!("Already a ctrl at {path:?}");
|
|
continue;
|
|
}
|
|
|
|
// Need to check the driver is asus to prevent using hid_generic
|
|
if let Some(p2) = event.parent() {
|
|
if let Some(driver) = p2.driver() {
|
|
// There is a tree of devices added so filter by driver
|
|
if driver != "asus" {
|
|
debug!("{id_product:?} driver was not asus, skipping");
|
|
continue;
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if let Some(dev_node) = event.devnode() {
|
|
if let Ok(raw) = HidRaw::from_device(event.device())
|
|
.map_err(|e| error!("device path error: {e:?}"))
|
|
{
|
|
if let Ok(mut ctrl) = CtrlKbdLed::from_hidraw(raw, path.clone()) {
|
|
ctrl.config = CtrlKbdLed::init_config(&id_product);
|
|
interfaces.insert(path.clone());
|
|
info!("AuraManager starting device at: {dev_node:?}, {path:?}");
|
|
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
|
|
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
|
|
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
|
|
let conn_copy = conn_copy.clone();
|
|
tokio::spawn(async move {
|
|
start_tasks(zbus, conn_copy.clone(), sig_ctx, path).await
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
// Required for return type on spawn
|
|
#[allow(unreachable_code)]
|
|
Ok::<(), RogError>(())
|
|
});
|
|
Ok(manager)
|
|
}
|
|
}
|
|
|
|
pub(crate) fn dbus_path_for_dev(parent: &Device) -> Option<OwnedObjectPath> {
|
|
if let Some(filename) = super::filename_partial(parent) {
|
|
return Some(
|
|
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/{filename}")).into(),
|
|
);
|
|
}
|
|
None
|
|
}
|
|
|
|
pub(crate) fn dbus_path_for_tuf() -> OwnedObjectPath {
|
|
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/tuf")).into()
|
|
}
|
|
|
|
async fn start_tasks(
|
|
mut zbus: CtrlAuraZbus,
|
|
connection: Connection,
|
|
_signal_ctx: SignalContext<'static>,
|
|
path: OwnedObjectPath,
|
|
) -> Result<(), RogError> {
|
|
// let task = zbus.clone();
|
|
// let signal_ctx = signal_ctx.clone();
|
|
zbus.reload()
|
|
.await
|
|
.unwrap_or_else(|err| warn!("Controller error: {}", err));
|
|
connection.object_server().at(path, zbus).await.unwrap();
|
|
// TODO: skip this until we keep handles to tasks so they can be killed
|
|
// task.create_tasks(signal_ctx).await
|
|
Ok(())
|
|
}
|