mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Create rog-platform, refactor rogcc ipc-file handling
- Create new rog-platform crate to manage all i/o in a universal way + kbd-led handling + platform handling (asus-nb-wmi) + hidraw + usbraw - Refactor how ROGCC handles IPC for background open, run-in-bg
This commit is contained in:
12
rog-platform/Cargo.toml
Normal file
12
rog-platform/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "rog_platform"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
log = "*"
|
||||
udev = "^0.6"
|
||||
rusb = "^0.9"
|
||||
sysfs-class = "^0.1"
|
||||
51
rog-platform/src/error.rs
Normal file
51
rog-platform/src/error.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::fmt;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, PlatformError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PlatformError {
|
||||
ParseVendor,
|
||||
ParseNum,
|
||||
Udev(String, std::io::Error),
|
||||
USB(rusb::Error),
|
||||
Path(String, std::io::Error),
|
||||
Read(String, std::io::Error),
|
||||
Write(String, std::io::Error),
|
||||
NotSupported,
|
||||
AttrNotFound(String),
|
||||
MissingFunction(String),
|
||||
MissingLedBrightNode(String, std::io::Error),
|
||||
Io(String, std::io::Error),
|
||||
NoAuraKeyboard,
|
||||
NoAuraNode,
|
||||
}
|
||||
|
||||
impl fmt::Display for PlatformError {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PlatformError::ParseVendor => write!(f, "Parse gfx vendor error"),
|
||||
PlatformError::ParseNum => write!(f, "Parse number error"),
|
||||
PlatformError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
|
||||
PlatformError::USB(error) => write!(f, "usb {}", error),
|
||||
PlatformError::Path(path, error) => write!(f, "Path {}: {}", path, error),
|
||||
PlatformError::Read(path, error) => write!(f, "Read {}: {}", path, error),
|
||||
PlatformError::Write(path, error) => write!(f, "Write {}: {}", path, error),
|
||||
PlatformError::NotSupported => write!(f, "Not supported"),
|
||||
PlatformError::AttrNotFound(deets) => write!(f, "Attribute not found: {}", deets),
|
||||
PlatformError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
|
||||
PlatformError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
|
||||
PlatformError::Io(path, detail) => write!(f, "std::io error: {} {}", path, detail),
|
||||
PlatformError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
|
||||
PlatformError::NoAuraNode => write!(f, "No Aura keyboard node found"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for PlatformError {}
|
||||
|
||||
impl From<rusb::Error> for PlatformError {
|
||||
fn from(err: rusb::Error) -> Self {
|
||||
PlatformError::USB(err)
|
||||
}
|
||||
}
|
||||
55
rog-platform/src/hid_raw.rs
Normal file
55
rog-platform/src/hid_raw.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::{fs::OpenOptions, io::Write, path::PathBuf};
|
||||
|
||||
use log::{info, warn};
|
||||
|
||||
use crate::error::{PlatformError, Result};
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
pub struct HidRaw(PathBuf);
|
||||
|
||||
impl HidRaw {
|
||||
pub fn new(id_product: &str) -> Result<Self> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
|
||||
enumerator.match_subsystem("hidraw").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
for device in enumerator
|
||||
.scan_devices()
|
||||
.map_err(|e| PlatformError::Io("enumerator".to_owned(), e))?
|
||||
{
|
||||
if let Some(parent) = device
|
||||
.parent_with_subsystem_devtype("usb", "usb_device")
|
||||
.map_err(|e| PlatformError::Io(device.devpath().to_string_lossy().to_string(), e))?
|
||||
{
|
||||
if let Some(parent) = parent.attribute_value("idProduct") {
|
||||
if parent == id_product {
|
||||
if let Some(dev_node) = device.devnode() {
|
||||
info!("Using device at: {:?} for LED control", dev_node);
|
||||
return Ok(Self(dev_node.to_owned()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(PlatformError::MissingFunction(format!(
|
||||
"hidraw dev {} not found",
|
||||
id_product
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn write_bytes(&self, message: &[u8]) -> Result<()> {
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.open(&self.0)
|
||||
.map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e))?;
|
||||
// println!("write: {:02x?}", &message);
|
||||
file.write_all(message)
|
||||
.map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e))
|
||||
}
|
||||
}
|
||||
59
rog-platform/src/keyboard_led.rs
Normal file
59
rog-platform/src/keyboard_led.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use log::warn;
|
||||
|
||||
use crate::{
|
||||
attr_u8, attr_u8_array,
|
||||
error::{PlatformError, Result},
|
||||
to_device,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, PartialOrd)]
|
||||
pub struct KeyboardLed(PathBuf);
|
||||
|
||||
impl KeyboardLed {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
|
||||
enumerator.match_subsystem("leds").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
enumerator
|
||||
.match_sysname("asus::kbd_backlight")
|
||||
.map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
for device in enumerator.scan_devices().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("scan_devices failed".into(), err)
|
||||
})? {
|
||||
return Ok(Self(device.syspath().to_owned()));
|
||||
}
|
||||
Err(PlatformError::MissingFunction(
|
||||
"asus::kbd_backlight not found".into(),
|
||||
))
|
||||
}
|
||||
|
||||
attr_u8!(has_brightness, get_brightness, set_brightness, "brightness");
|
||||
|
||||
attr_u8_array!(
|
||||
has_keyboard_rgb_mode,
|
||||
get_keyboard_rgb_mode,
|
||||
set_keyboard_rgb_mode,
|
||||
"kbd_rgb_mode"
|
||||
);
|
||||
|
||||
attr_u8_array!(
|
||||
has_keyboard_rgb_state,
|
||||
get_keyboard_rgb_state,
|
||||
set_keyboard_rgb_state,
|
||||
"kbd_rgb_state"
|
||||
);
|
||||
}
|
||||
191
rog-platform/src/lib.rs
Normal file
191
rog-platform/src/lib.rs
Normal file
@@ -0,0 +1,191 @@
|
||||
pub mod error;
|
||||
pub mod hid_raw;
|
||||
pub mod keyboard_led;
|
||||
pub mod platform;
|
||||
pub mod usb_raw;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use error::{PlatformError, Result};
|
||||
use udev::Device;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! attr_bool {
|
||||
($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => {
|
||||
pub fn $hasser(&self) -> bool {
|
||||
match to_device(&self.0) {
|
||||
Ok(p) => crate::has_attr(&p, $attr_name),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn $getter(&self) -> Result<bool> {
|
||||
crate::read_attr_bool(&to_device(&self.0)?, $attr_name)
|
||||
}
|
||||
|
||||
pub fn $setter(&self, value: bool) -> Result<()> {
|
||||
crate::write_attr_bool(&mut to_device(&self.0)?, $attr_name, value)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! attr_u8 {
|
||||
($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => {
|
||||
pub fn $hasser(&self) -> bool {
|
||||
match to_device(&self.0) {
|
||||
Ok(p) => crate::has_attr(&p, $attr_name),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn $getter(&self) -> Result<u8> {
|
||||
crate::read_attr_u8(&to_device(&self.0)?, $attr_name)
|
||||
}
|
||||
|
||||
pub fn $setter(&self, value: u8) -> Result<()> {
|
||||
crate::write_attr_u8(&mut to_device(&self.0)?, $attr_name, value)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! attr_u8_array {
|
||||
($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => {
|
||||
pub fn $hasser(&self) -> bool {
|
||||
match to_device(&self.0) {
|
||||
Ok(p) => crate::has_attr(&p, $attr_name),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn $getter(&self) -> Result<Vec<u8>> {
|
||||
crate::read_attr_u8_array(&to_device(&self.0)?, $attr_name)
|
||||
}
|
||||
|
||||
pub fn $setter(&self, values: &[u8]) -> Result<()> {
|
||||
crate::write_attr_u8_array(&mut to_device(&self.0)?, $attr_name, values)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn to_device(sys_path: &Path) -> Result<Device> {
|
||||
Device::from_syspath(sys_path)
|
||||
.map_err(|e| PlatformError::Udev("Couldn't transform syspath to device".to_string(), e))
|
||||
}
|
||||
|
||||
pub fn has_attr(device: &Device, attr_name: &str) -> bool {
|
||||
for attr in device.attributes() {
|
||||
if attr.name() == attr_name {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn read_attr_bool(device: &Device, attr_name: &str) -> Result<bool> {
|
||||
if let Some(value) = device.attribute_value(attr_name) {
|
||||
let tmp = value.to_string_lossy();
|
||||
if tmp.trim() == "0" {
|
||||
return Ok(false);
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
Err(PlatformError::AttrNotFound(attr_name.to_string()))
|
||||
}
|
||||
|
||||
pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<()> {
|
||||
device
|
||||
.set_attribute_value(attr, &(value as u8).to_string())
|
||||
.map_err(|e| PlatformError::Io(attr.into(), e))
|
||||
}
|
||||
|
||||
pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result<u8> {
|
||||
if let Some(value) = device.attribute_value(attr_name) {
|
||||
let tmp = value.to_string_lossy();
|
||||
return Ok(tmp.parse::<u8>().map_err(|_| PlatformError::ParseNum)?);
|
||||
}
|
||||
Err(PlatformError::AttrNotFound(attr_name.to_string()))
|
||||
}
|
||||
|
||||
pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> {
|
||||
device
|
||||
.set_attribute_value(attr, &(value).to_string())
|
||||
.map_err(|e| PlatformError::Io(attr.into(), e))
|
||||
}
|
||||
|
||||
pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result<Vec<u8>> {
|
||||
if let Some(value) = device.attribute_value(attr_name) {
|
||||
let tmp = value.to_string_lossy();
|
||||
let tmp = tmp
|
||||
.split(' ')
|
||||
.map(|v| u8::from_str_radix(v, 10).unwrap_or(0))
|
||||
.collect();
|
||||
return Ok(tmp);
|
||||
}
|
||||
Err(PlatformError::AttrNotFound(attr_name.to_string()))
|
||||
}
|
||||
|
||||
pub fn write_attr_u8_array(device: &mut Device, attr: &str, values: &[u8]) -> Result<()> {
|
||||
let tmp: String = values.iter().map(|v| format!("{} ", v)).collect();
|
||||
let tmp = tmp.trim();
|
||||
device
|
||||
.set_attribute_value(attr, &tmp)
|
||||
.map_err(|e| PlatformError::Io(attr.into(), e))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn check() {
|
||||
let data = [1, 2, 3, 4, 5];
|
||||
|
||||
let tmp: String = data.iter().map(|v| format!("{} ", v)).collect();
|
||||
let tmp = tmp.trim();
|
||||
assert_eq!(tmp, "1 2 3 4 5");
|
||||
|
||||
let tmp: Vec<u8> = tmp
|
||||
.split(' ')
|
||||
.map(|v| u8::from_str_radix(v, 10).unwrap_or(0))
|
||||
.collect();
|
||||
assert_eq!(tmp, &[1, 2, 3, 4, 5]);
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn find_led_node(id_product: &str) -> Result<Device, PlatformError> {
|
||||
// let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
// warn!("{}", err);
|
||||
// PlatformError::Udev("enumerator failed".into(), err)
|
||||
// })?;
|
||||
// enumerator.match_subsystem("hidraw").map_err(|err| {
|
||||
// warn!("{}", err);
|
||||
// PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
// })?;
|
||||
|
||||
// for device in enumerator.scan_devices().map_err(|err| {
|
||||
// warn!("{}", err);
|
||||
// PlatformError::Udev("scan_devices failed".into(), err)
|
||||
// })? {
|
||||
// if let Some(parent) = device
|
||||
// .parent_with_subsystem_devtype("usb", "usb_device")
|
||||
// .map_err(|err| {
|
||||
// warn!("{}", err);
|
||||
// PlatformError::Udev("parent_with_subsystem_devtype failed".into(), err)
|
||||
// })?
|
||||
// {
|
||||
// if parent
|
||||
// .attribute_value("idProduct")
|
||||
// .ok_or_else(|| PlatformError::NotFound("LED idProduct".into()))?
|
||||
// == id_product
|
||||
// {
|
||||
// if let Some(dev_node) = device.devnode() {
|
||||
// info!("Using device at: {:?} for LED control", dev_node);
|
||||
// return Ok(device);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Err(PlatformError::MissingFunction(
|
||||
// "ASUS LED device node not found".into(),
|
||||
// ))
|
||||
// }
|
||||
69
rog-platform/src/platform.rs
Normal file
69
rog-platform/src/platform.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use log::warn;
|
||||
|
||||
use crate::{
|
||||
attr_bool,
|
||||
error::{PlatformError, Result},
|
||||
to_device,
|
||||
};
|
||||
|
||||
/// The "platform" device provides access to things like:
|
||||
/// - dgpu_disable
|
||||
/// - egpu_enable
|
||||
/// - panel_od
|
||||
/// - dgpu_only
|
||||
/// - keyboard_mode, set keyboard RGB mode and speed
|
||||
/// - keyboard_state, set keyboard power states
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
pub struct AsusPlatform(PathBuf);
|
||||
|
||||
impl AsusPlatform {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
enumerator.match_subsystem("platform").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
enumerator.match_sysname("asus-nb-wmi").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
for device in enumerator.scan_devices().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("scan_devices failed".into(), err)
|
||||
})? {
|
||||
return Ok(Self(device.syspath().to_owned()));
|
||||
}
|
||||
Err(PlatformError::MissingFunction(
|
||||
"asus-nb-wmi not found".into(),
|
||||
))
|
||||
}
|
||||
|
||||
attr_bool!(
|
||||
has_dgpu_disable,
|
||||
get_dgpu_disable,
|
||||
set_dgpu_disable,
|
||||
"dgpu_disable"
|
||||
);
|
||||
|
||||
attr_bool!(
|
||||
has_egpu_enable,
|
||||
get_egpu_enable,
|
||||
set_egpu_enable,
|
||||
"egpu_enable"
|
||||
);
|
||||
|
||||
attr_bool!(has_panel_od, get_panel_od, set_panel_od, "panel_od");
|
||||
|
||||
attr_bool!(
|
||||
has_gpu_mux_mode,
|
||||
get_gpu_mux_mode,
|
||||
set_gpu_mux_mode,
|
||||
"gpu_mux_mode"
|
||||
);
|
||||
}
|
||||
48
rog-platform/src/usb_raw.rs
Normal file
48
rog-platform/src/usb_raw.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use rusb::{Device, DeviceHandle};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::error::{PlatformError, Result};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct USBRaw(DeviceHandle<rusb::GlobalContext>);
|
||||
|
||||
impl USBRaw {
|
||||
pub fn new(id_product: u16) -> Result<Self> {
|
||||
for device in rusb::devices()?.iter() {
|
||||
let device_desc = device.device_descriptor()?;
|
||||
if device_desc.vendor_id() == 0x0b05 && device_desc.product_id() == id_product {
|
||||
let handle = Self::get_dev_handle(device)?;
|
||||
return Ok(Self(handle));
|
||||
}
|
||||
}
|
||||
|
||||
Err(PlatformError::MissingFunction(format!(
|
||||
"USBRaw dev {} not found",
|
||||
id_product
|
||||
)))
|
||||
}
|
||||
|
||||
fn get_dev_handle(
|
||||
device: Device<rusb::GlobalContext>,
|
||||
) -> Result<DeviceHandle<rusb::GlobalContext>> {
|
||||
// We don't expect this ID to ever change
|
||||
let mut device = device.open()?;
|
||||
device.reset()?;
|
||||
device.set_auto_detach_kernel_driver(true)?;
|
||||
device.claim_interface(0)?;
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
pub fn write_bytes(&self, message: &[u8]) -> Result<usize> {
|
||||
self.0
|
||||
.write_control(
|
||||
0x21, // request_type
|
||||
0x09, // request
|
||||
0x35e, // value
|
||||
0x00, // index
|
||||
message,
|
||||
Duration::from_millis(200),
|
||||
)
|
||||
.map_err(|e| PlatformError::USB(e))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user