Merge from main

This commit is contained in:
jochen@g14
2024-03-30 18:44:15 +01:00
15 changed files with 536 additions and 467 deletions

View File

@@ -68,7 +68,7 @@ impl CtrlAnime {
let node = if usb.is_some() {
unsafe { Node::Usb(usb.unwrap_unchecked()) }
} else if hid.is_some() {
unsafe { Node::Hid(hid.unwrap_unchecked().0) }
unsafe { Node::Hid(hid.unwrap_unchecked()) }
} else {
return Err(RogError::Anime(AnimeError::NoDevice));
};

View File

@@ -18,6 +18,12 @@ pub enum AuraPowerConfig {
AuraDevRog2(AuraPower),
}
impl Default for AuraPowerConfig {
fn default() -> Self {
Self::AuraDevTuf(HashSet::default())
}
}
impl AuraPowerConfig {
/// Invalid for TUF laptops
pub fn to_bytes(control: &Self) -> [u8; 4] {
@@ -101,7 +107,7 @@ impl From<&AuraPowerConfig> for AuraPowerDev {
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
#[derive(Deserialize, Serialize, Default, Debug, Clone)]
// #[serde(default)]
pub struct AuraConfig {
pub config_name: String,
@@ -116,7 +122,7 @@ pub struct AuraConfig {
impl AuraConfig {
/// Detect the keyboard type and load from default DB if data available
pub fn new_with(prod_id: AuraDevice) -> Self {
info!("creating new AuraConfig");
info!("Setting up AuraConfig for {prod_id:?}");
Self::from_default_support(prod_id, &LaptopLedData::get_data())
}
}
@@ -142,10 +148,6 @@ impl StdConfig for AuraConfig {
impl StdConfigLoad for AuraConfig {}
impl AuraConfig {
pub fn set_filename(&mut self, prod_id: AuraDevice) {
self.config_name = format!("aura_{prod_id:?}.ron");
}
pub fn from_default_support(prod_id: AuraDevice, support_data: &LaptopLedData) -> Self {
// create a default config here
let enabled = if prod_id.is_new_style() {

View File

@@ -1,10 +1,10 @@
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashSet};
use config_traits::{StdConfig, StdConfigLoad};
use inotify::Inotify;
use log::info;
use log::{debug, info, warn};
use rog_aura::advanced::{LedUsbPackets, UsbPackets};
use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES};
use rog_aura::aura_detection::LaptopLedData;
use rog_aura::usb::{AuraDevice, LED_APPLY, LED_SET};
use rog_aura::{AuraEffect, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN};
use rog_platform::hid_raw::HidRaw;
@@ -59,84 +59,102 @@ pub struct CtrlKbdLed {
}
impl CtrlKbdLed {
pub fn new(data: LaptopLedData) -> Result<Self, RogError> {
let mut led_prod = AuraDevice::Unknown;
let mut usb_node = None;
for prod in ASUS_KEYBOARD_DEVICES {
match HidRaw::new(prod.into()) {
Ok(node) => {
led_prod = prod;
usb_node = Some(node);
info!(
"Looked for keyboard controller 0x{}: Found",
<&str>::from(prod)
);
break;
pub fn find_all(data: &LaptopLedData) -> Result<Vec<Self>, RogError> {
info!("Searching for all Aura devices");
let mut devices = Vec::new();
let mut found = HashSet::new(); // track and ensure we use only one hidraw per prod_id
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);
err
})?;
enumerator.match_subsystem("hidraw").map_err(|err| {
warn!("{}", err);
err
})?;
for end_point in enumerator.scan_devices()? {
// usb_device gives us a product and vendor ID
if let Some(usb_device) =
end_point.parent_with_subsystem_devtype("usb", "usb_device")?
{
// The asus_wmi driver latches MCU that controls the USB endpoints
if let Some(parent) = end_point.parent() {
if let Some(driver) = parent.driver() {
// There is a tree of devices added so filter by driver
if driver != "asus" {
continue;
}
} else {
continue;
}
}
Err(err) => info!(
"Looked for keyboard controller 0x{}: {err}",
<&str>::from(prod)
),
// Device is something like 002, while its parent is the MCU
// Think of it like the device is an endpoint of the USB device attached
let mut aura_dev = AuraDevice::Unknown;
if let Some(usb_id) = usb_device.attribute_value("idProduct") {
aura_dev = AuraDevice::from(usb_id.to_str().unwrap());
if aura_dev == AuraDevice::Unknown || found.contains(&aura_dev) {
log::debug!("Unknown or invalid device: {usb_id:?}, skipping");
continue;
}
found.insert(aura_dev);
}
let dev_node = if let Some(dev_node) = usb_device.devnode() {
dev_node
} else {
debug!("Device has no devnode, skipping");
continue;
};
info!("AuraControl found device at: {:?}", dev_node);
let dbus_path = dbus_path_for_dev(&usb_device).unwrap_or_default();
let dev = HidRaw::from_device(end_point)?;
let mut dev = Self::from_hidraw(dev, dbus_path, data)?;
dev.config = Self::init_config(aura_dev, data);
devices.push(dev);
}
}
info!("Found {} Aura devices", devices.len());
let mut dbus_path = Default::default();
let rgb_led = KeyboardLed::new()?;
let led_node = if let Some(rog) = usb_node {
info!("Found ROG USB keyboard");
dbus_path = dbus_path_for_dev(rog.1).unwrap_or_default();
LEDNode::Rog(rgb_led, rog.0)
} else if rgb_led.has_kbd_rgb_mode() {
info!("Found TUF keyboard");
LEDNode::KbdLed(rgb_led.clone())
} else {
return Err(RogError::NoAuraKeyboard);
// LEDNode::None
};
// New loads data from the DB also
let config = Self::init_config(led_prod, &data);
let ctrl = CtrlKbdLed {
led_prod,
led_node, // on TUF this is the same as rgb_led / kd_brightness
supported_data: data,
per_key_mode_active: false,
config,
dbus_path,
};
Ok(ctrl)
Ok(devices)
}
pub fn from_device(
/// The generated data from this function has a default config. This config
/// should be overwritten. The reason for the default config is because
/// of async issues between this and udev/hidraw
pub fn from_hidraw(
device: HidRaw,
dbus_path: OwnedObjectPath,
data: LaptopLedData,
data: &LaptopLedData,
) -> Result<Self, RogError> {
let rgb_led = KeyboardLed::new()?;
let prod_id = AuraDevice::from(device.prod_id());
if prod_id == AuraDevice::Unknown {
log::error!("{} is AuraDevice::Unknown", device.prod_id());
return Err(RogError::NoAuraNode);
}
// New loads data from the DB also
let config = Self::init_config(prod_id, &data);
// let config = Self::init_config(prod_id, data);
let ctrl = CtrlKbdLed {
led_prod: prod_id,
led_node: LEDNode::Rog(rgb_led, device), /* on TUF this is the same as rgb_led /
* kd_brightness */
supported_data: data,
led_node: LEDNode::Rog(rgb_led, device),
supported_data: data.clone(),
per_key_mode_active: false,
config,
config: AuraConfig::default(),
dbus_path,
};
Ok(ctrl)
}
fn init_config(prod_id: AuraDevice, supported_basic_modes: &LaptopLedData) -> AuraConfig {
pub fn init_config(prod_id: AuraDevice, supported_basic_modes: &LaptopLedData) -> AuraConfig {
// New loads data from the DB also
let mut config_init = AuraConfig::new_with(prod_id);
// config_init.set_filename(prod_id);
let mut config_loaded = config_init.clone().load();
config_loaded.set_filename(prod_id);
// update the initialised data with what we loaded from disk
for mode in &mut config_init.builtins {
// update init values from loaded values if they exist

View File

@@ -5,14 +5,14 @@
// - If udev sees device removed then remove the zbus path
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
use log::{error, info, warn};
use log::{debug, error, info, warn};
use mio::{Events, Interest, Poll, Token};
use rog_aura::aura_detection::LaptopLedData;
use rog_aura::usb::AuraDevice;
use rog_platform::hid_raw::HidRaw;
use tokio::sync::Mutex;
use tokio::task::spawn_blocking;
use udev::{Device, MonitorBuilder};
// use zbus::fdo::ObjectManager;
use zbus::object_server::SignalContext;
@@ -26,38 +26,31 @@ use crate::{CtrlTask, Reloadable};
pub struct AuraManager {
_connection: Connection,
_interfaces: Arc<Mutex<HashSet<OwnedObjectPath>>>,
}
impl AuraManager {
pub async fn new(mut connection: Connection) -> Result<Self, RogError> {
pub async fn new(connection: Connection) -> Result<Self, RogError> {
let conn_copy = connection.clone();
let data = LaptopLedData::get_data();
let mut interfaces = HashSet::new();
// Do the initial keyboard detection:
match CtrlKbdLed::new(data.clone()) {
Ok(ctrl) => {
let path = ctrl.dbus_path.clone();
let sig_ctx = CtrlAuraZbus::signal_context(&connection)?;
let sig_ctx2 = sig_ctx.clone();
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
start_tasks(zbus, &mut connection, sig_ctx2, &path).await?;
}
Err(err) => {
error!("Keyboard control: {}", err);
}
let all = CtrlKbdLed::find_all(&data)?;
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?;
}
// connection.object_server().at("/org/asuslinux",
// ObjectManager).await.unwrap();
let manager = Self {
_connection: connection,
_interfaces: Default::default(),
};
// detect all plugged in aura devices (eventually)
tokio::spawn(async move {
spawn_blocking(move || {
let mut monitor = MonitorBuilder::new()?.match_subsystem("hidraw")?.listen()?;
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);
@@ -65,46 +58,71 @@ impl AuraManager {
.register(&mut monitor, Token(0), Interest::READABLE)?;
loop {
poll.poll(&mut events, None).unwrap();
if poll.poll(&mut events, None).is_err() {
continue;
}
for event in monitor.iter() {
if let Some(parent) =
let parent = if let Some(parent) =
event.parent_with_subsystem_devtype("usb", "usb_device")?
{
let action = if let Some(action) = event.action() {
action
} else {
continue;
};
parent
} else {
continue;
};
if action == "remove" {
if let Some(path) = dbus_path_for_dev(parent.clone()) {
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>(())
});
}
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 = AuraDevice::from(&*id_product);
if aura_device == AuraDevice::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;
}
let id_product =
if let Some(id_product) = parent.attribute_value("idProduct") {
id_product
} else {
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 {
@@ -112,50 +130,30 @@ impl AuraManager {
}
}
// try conversion to known idProduct
let aura_device = AuraDevice::from(id_product.to_str().unwrap());
if aura_device != AuraDevice::Unknown {
if action == "add" {
let dev_node = if let Some(dev_node) = event.devnode() {
dev_node
} else {
continue;
};
if let Ok(raw) = HidRaw::from_device(event.device())
.map_err(|e| error!("device path error: {e:?}"))
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(), &data)
{
let path = if let Some(path) = dbus_path_for_dev(parent) {
path
} else {
continue;
};
if let Ok(ctrl) =
CtrlKbdLed::from_device(raw, path.clone(), data.clone())
{
info!("AuraManager found device at: {:?}", dev_node);
let mut conn_copy = conn_copy.clone();
//
tokio::spawn(async move {
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
// Now add it to device list
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
start_tasks(zbus, &mut conn_copy, sig_ctx, &path)
.await?;
Ok::<(), RogError>(())
}); // Can't get result from here due to
// MonitorSocket
}
ctrl.config = CtrlKbdLed::init_config(aura_device, &data);
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
});
}
}
} else {
warn!("idProduct:{id_product:?} is unknown, not using")
}
}
};
}
}
// Required for return type on tokio::spawn
// Required for return type on spawn
#[allow(unreachable_code)]
Ok::<(), RogError>(())
});
@@ -163,7 +161,7 @@ impl AuraManager {
}
}
pub(crate) fn dbus_path_for_dev(parent: Device) -> Option<OwnedObjectPath> {
pub(crate) fn dbus_path_for_dev(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(id_product) = parent.attribute_value("idProduct") {
let id_product = id_product.to_string_lossy();
let path = if let Some(devnum) = parent.attribute_value("devnum") {
@@ -184,20 +182,17 @@ pub(crate) fn dbus_path_for_dev(parent: Device) -> Option<OwnedObjectPath> {
async fn start_tasks(
mut zbus: CtrlAuraZbus,
connection: &mut Connection,
signal_ctx: SignalContext<'static>,
path: &ObjectPath<'static>,
connection: Connection,
_signal_ctx: SignalContext<'static>,
path: OwnedObjectPath,
) -> Result<(), RogError> {
let task = zbus.clone();
// 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(&ObjectPath::from_str_unchecked(path), zbus)
.await
.unwrap();
task.create_tasks(signal_ctx).await.ok();
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(())
}

View File

@@ -210,23 +210,29 @@ impl CtrlTask for CtrlAuraZbus {
}
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let load_save = |start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| {
// If waking up
if !start {
info!("CtrlKbdLedTask reloading brightness and modes");
lock.led_node
.set_brightness(lock.config.brightness.into())
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
.ok();
lock.write_current_config_mode()
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
.ok();
} else if start {
Self::update_config(&mut lock)
.map_err(|e| error!("CtrlKbdLedTask: {e}"))
.ok();
}
};
let load_save =
|start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| -> Result<(), RogError> {
// If waking up
if !start {
info!("CtrlKbdLedTask reloading brightness and modes");
lock.led_node
.set_brightness(lock.config.brightness.into())
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
lock.write_current_config_mode().map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
} else if start {
Self::update_config(&mut lock).map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
}
Ok(())
};
let inner1 = self.0.clone();
let inner3 = self.0.clone();
@@ -235,14 +241,16 @@ impl CtrlTask for CtrlAuraZbus {
let inner1 = inner1.clone();
async move {
let lock = inner1.lock().await;
load_save(sleeping, lock);
load_save(sleeping, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
},
move |_shutting_down| {
let inner3 = inner3.clone();
async move {
let lock = inner3.lock().await;
load_save(false, lock);
load_save(false, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
},
move |_lid_closed| {
@@ -266,7 +274,8 @@ impl CtrlTask for CtrlAuraZbus {
.unwrap()
.for_each(|_| async {
if let Some(lock) = ctrl2.try_lock() {
load_save(true, lock);
load_save(true, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
})
.await;

View File

@@ -30,7 +30,7 @@ macro_rules! platform_get_value {
$self.platform
.get()
.map_err(|err| {
warn!("RogPlatform: {}: {}", $prop_name, err);
warn!("{}: {}", $prop_name, err);
FdoErr::Failed(format!("RogPlatform: {}: {}", $prop_name, err))
})
})
@@ -381,7 +381,7 @@ impl CtrlPlatform {
#[zbus(property)]
fn gpu_mux_mode(&self) -> Result<u8, FdoErr> {
self.platform.get_gpu_mux_mode().map_err(|err| {
warn!("RogPlatform: set_gpu_mux_mode {err}");
warn!("get_gpu_mux_mode {err}");
FdoErr::NotSupported("RogPlatform: set_gpu_mux_mode not supported".to_owned())
})
}
@@ -390,7 +390,7 @@ impl CtrlPlatform {
async fn set_gpu_mux_mode(&mut self, mode: u8) -> Result<(), FdoErr> {
if self.platform.has_gpu_mux_mode() {
self.set_gfx_mode(mode.into()).map_err(|err| {
warn!("RogPlatform: set_gpu_mux_mode {}", err);
warn!("set_gpu_mux_mode {}", err);
FdoErr::Failed(format!("RogPlatform: set_gpu_mux_mode: {err}"))
})?;
self.config.lock().await.write();
@@ -420,7 +420,7 @@ impl CtrlPlatform {
self.platform
.set_throttle_thermal_policy(policy.into())
.map_err(|err| {
warn!("RogPlatform: throttle_thermal_policy {}", err);
warn!("throttle_thermal_policy {}", err);
FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}"))
})?;
Ok(self.throttle_thermal_policy_changed(&ctxt).await?)
@@ -448,7 +448,7 @@ impl CtrlPlatform {
self.platform
.set_throttle_thermal_policy(policy.into())
.map_err(|err| {
warn!("RogPlatform: throttle_thermal_policy {}", err);
warn!("throttle_thermal_policy {}", err);
FdoErr::Failed(format!("RogPlatform: throttle_thermal_policy: {err}"))
})
} else {

View File

@@ -21,6 +21,7 @@ use asusd::ctrl_slash::trait_impls::CtrlSlashZbus;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// console_subscriber::init();
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()