mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
working with hardcoded devnode. need to change
This commit is contained in:
@@ -119,6 +119,7 @@ Models GA401, GA502, GU502 support LED brightness change only (no RGB).
|
|||||||
- `libdbus-1-dev`
|
- `libdbus-1-dev`
|
||||||
- `llvm`
|
- `llvm`
|
||||||
- `libclang-dev`
|
- `libclang-dev`
|
||||||
|
- `libudev-dev`
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ pub mod anime_matrix;
|
|||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||||
|
// static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||||
|
// static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
|
// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||||
|
// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||||
|
|
||||||
/// Writes aout the correct byte string for brightness
|
/// Writes aout the correct byte string for brightness
|
||||||
///
|
///
|
||||||
/// The HID descriptor looks like:
|
/// The HID descriptor looks like:
|
||||||
|
|||||||
@@ -34,21 +34,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
info!("Config loaded");
|
info!("Config loaded");
|
||||||
|
|
||||||
let mut rogcore = RogCore::new(
|
let mut rogcore = RogCore::new(laptop.usb_vendor(), laptop.usb_product());
|
||||||
laptop.usb_vendor(),
|
|
||||||
laptop.usb_product(),
|
|
||||||
laptop.key_endpoint(),
|
|
||||||
)
|
|
||||||
.map_or_else(
|
|
||||||
|err| {
|
|
||||||
error!("{}", err);
|
|
||||||
panic!("{}", err);
|
|
||||||
},
|
|
||||||
|daemon| {
|
|
||||||
info!("RogCore loaded");
|
|
||||||
daemon
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Reload settings
|
// Reload settings
|
||||||
rogcore
|
rogcore
|
||||||
@@ -59,8 +45,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
|
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
|
||||||
|
|
||||||
let mut led_writer = LedWriter::new(
|
let mut led_writer = LedWriter::new(
|
||||||
rogcore.get_raw_device_handle(),
|
"/dev/hidraw2".to_string(),
|
||||||
laptop.led_endpoint(),
|
|
||||||
laptop.supported_modes().to_owned(),
|
laptop.supported_modes().to_owned(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -136,6 +121,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
// spawning this in a function causes a segfault for reasons I haven't investigated yet
|
// spawning this in a function causes a segfault for reasons I haven't investigated yet
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
|
// TODO: MAKE SYS COMMANDS OPERATE USING CHANNEL LIKE AURA MODES
|
||||||
// Fan mode
|
// Fan mode
|
||||||
if let Ok(mut lock) = fan_mode.try_lock() {
|
if let Ok(mut lock) = fan_mode.try_lock() {
|
||||||
if let Some(n) = lock.take() {
|
if let Some(n) = lock.take() {
|
||||||
@@ -154,7 +140,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,4 +248,3 @@ async fn send_boot_signals(
|
|||||||
.unwrap_or_else(|_| 0);
|
.unwrap_or_else(|_| 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
use rog_client::{
|
|
||||||
aura_modes::{
|
|
||||||
AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW,
|
|
||||||
RGB, RIPPLE, SINGLE, STAR, STROBE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use rog_client::aura_modes::{
|
||||||
|
AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW, RGB,
|
||||||
|
RIPPLE, SINGLE, STAR, STROBE,
|
||||||
|
};
|
||||||
|
|
||||||
static HELP_ADDRESS: &str = "https://github.com/flukejones/rog-core";
|
static HELP_ADDRESS: &str = "https://github.com/flukejones/rog-core";
|
||||||
|
|
||||||
@@ -21,8 +19,6 @@ pub(crate) fn match_laptop() -> LaptopBase {
|
|||||||
usb_product: 0x1854,
|
usb_product: 0x1854,
|
||||||
//from `lsusb -vd 0b05:1866`
|
//from `lsusb -vd 0b05:1866`
|
||||||
led_endpoint: 0x04,
|
led_endpoint: 0x04,
|
||||||
//from `lsusb -vd 0b05:1866`
|
|
||||||
key_endpoint: 0x83,
|
|
||||||
supported_modes: vec![SINGLE, BREATHING, STROBE],
|
supported_modes: vec![SINGLE, BREATHING, STROBE],
|
||||||
support_animatrix: false,
|
support_animatrix: false,
|
||||||
};
|
};
|
||||||
@@ -47,8 +43,6 @@ fn select_1866_device(prod: u16) -> LaptopBase {
|
|||||||
usb_product: prod,
|
usb_product: prod,
|
||||||
//from `lsusb -vd 0b05:1866`
|
//from `lsusb -vd 0b05:1866`
|
||||||
led_endpoint: 0x04,
|
led_endpoint: 0x04,
|
||||||
//from `lsusb -vd 0b05:1866`
|
|
||||||
key_endpoint: 0x83,
|
|
||||||
supported_modes: vec![],
|
supported_modes: vec![],
|
||||||
support_animatrix: false,
|
support_animatrix: false,
|
||||||
};
|
};
|
||||||
@@ -72,12 +66,22 @@ fn select_1866_device(prod: u16) -> LaptopBase {
|
|||||||
SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET,
|
SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET,
|
||||||
FLASH, RGB,
|
FLASH, RGB,
|
||||||
];
|
];
|
||||||
} else if board_name.starts_with("G531")
|
} else if board_name.starts_with("G531") || board_name.starts_with("G731") {
|
||||||
|| board_name.starts_with("G731")
|
|
||||||
{
|
|
||||||
laptop.supported_modes = vec![
|
laptop.supported_modes = vec![
|
||||||
SINGLE, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET,
|
SINGLE,
|
||||||
FLASH, MULTISTATIC, RGB,
|
BREATHING,
|
||||||
|
STROBE,
|
||||||
|
RAINBOW,
|
||||||
|
STAR,
|
||||||
|
RAIN,
|
||||||
|
HIGHLIGHT,
|
||||||
|
LASER,
|
||||||
|
RIPPLE,
|
||||||
|
PULSE,
|
||||||
|
COMET,
|
||||||
|
FLASH,
|
||||||
|
MULTISTATIC,
|
||||||
|
RGB,
|
||||||
];
|
];
|
||||||
// RGB, limited effects, no zones
|
// RGB, limited effects, no zones
|
||||||
} else if board_name.starts_with("G512LI") || board_name.starts_with("G712LI") {
|
} else if board_name.starts_with("G512LI") || board_name.starts_with("G712LI") {
|
||||||
@@ -116,7 +120,6 @@ pub(super) struct LaptopBase {
|
|||||||
usb_vendor: u16,
|
usb_vendor: u16,
|
||||||
usb_product: u16,
|
usb_product: u16,
|
||||||
led_endpoint: u8,
|
led_endpoint: u8,
|
||||||
key_endpoint: u8,
|
|
||||||
supported_modes: Vec<u8>,
|
supported_modes: Vec<u8>,
|
||||||
support_animatrix: bool,
|
support_animatrix: bool,
|
||||||
}
|
}
|
||||||
@@ -125,9 +128,6 @@ impl LaptopBase {
|
|||||||
pub(super) fn led_endpoint(&self) -> u8 {
|
pub(super) fn led_endpoint(&self) -> u8 {
|
||||||
self.led_endpoint
|
self.led_endpoint
|
||||||
}
|
}
|
||||||
pub(super) fn key_endpoint(&self) -> u8 {
|
|
||||||
self.key_endpoint
|
|
||||||
}
|
|
||||||
pub(super) fn usb_vendor(&self) -> u16 {
|
pub(super) fn usb_vendor(&self) -> u16 {
|
||||||
self.usb_vendor
|
self.usb_vendor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
|
||||||
static LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
|
||||||
static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
|
||||||
static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
|
||||||
static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
|
||||||
|
|
||||||
// Only these two packets must be 17 bytes
|
// Only these two packets must be 17 bytes
|
||||||
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
@@ -13,104 +7,46 @@ use log::{error, info, warn};
|
|||||||
use rog_client::{
|
use rog_client::{
|
||||||
aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN,
|
aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN,
|
||||||
};
|
};
|
||||||
use rusb::DeviceHandle;
|
use std::fs::OpenOptions;
|
||||||
use std::marker::PhantomData;
|
use std::io::Write;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
/// UNSAFE: Must live as long as RogCore
|
/// UNSAFE: Must live as long as RogCore
|
||||||
///
|
///
|
||||||
/// Because we're holding a pointer to something that *may* go out of scope while the
|
/// Because we're holding a pointer to something that *may* go out of scope while the
|
||||||
/// pointer is held. We're relying on access to struct to be behind a Mutex, and for behaviour
|
/// pointer is held. We're relying on access to struct to be behind a Mutex, and for behaviour
|
||||||
/// that may cause invalididated pointer to cause the program to panic rather than continue.
|
/// that may cause invalididated pointer to cause the program to panic rather than continue.
|
||||||
pub struct LedWriter<'d, C: 'd>
|
pub struct LedWriter {
|
||||||
where
|
dev_node: String,
|
||||||
C: rusb::UsbContext,
|
|
||||||
{
|
|
||||||
handle: NonNull<DeviceHandle<C>>,
|
|
||||||
supported_modes: Vec<u8>,
|
supported_modes: Vec<u8>,
|
||||||
led_endpoint: u8,
|
|
||||||
initialised: bool,
|
|
||||||
flip_effect_write: bool,
|
flip_effect_write: bool,
|
||||||
_phantom: PhantomData<&'d DeviceHandle<C>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UNSAFE
|
impl LedWriter {
|
||||||
unsafe impl<'d, C> Send for LedWriter<'d, C> where C: rusb::UsbContext {}
|
|
||||||
unsafe impl<'d, C> Sync for LedWriter<'d, C> where C: rusb::UsbContext {}
|
|
||||||
|
|
||||||
impl<'d, C> LedWriter<'d, C>
|
|
||||||
where
|
|
||||||
C: rusb::UsbContext,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(dev_node: String, supported_modes: Vec<u8>) -> Self {
|
||||||
device_handle: NonNull<DeviceHandle<C>>,
|
|
||||||
led_endpoint: u8,
|
|
||||||
supported_modes: Vec<u8>,
|
|
||||||
) -> Self {
|
|
||||||
LedWriter {
|
LedWriter {
|
||||||
handle: device_handle,
|
dev_node,
|
||||||
led_endpoint,
|
|
||||||
supported_modes,
|
supported_modes,
|
||||||
initialised: false,
|
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn initialise(&mut self) -> Result<(), RogError> {
|
|
||||||
if !self.initialised {
|
|
||||||
self.write_bytes(&LED_INIT1).await?;
|
|
||||||
self.write_bytes(LED_INIT2.as_bytes()).await?;
|
|
||||||
self.write_bytes(&LED_INIT3).await?;
|
|
||||||
self.write_bytes(LED_INIT4.as_bytes()).await?;
|
|
||||||
self.write_bytes(&LED_INIT5).await?;
|
|
||||||
self.initialised = true;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn do_command(
|
pub async fn do_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
mode: AuraModes,
|
mode: AuraModes,
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
) -> Result<(), RogError> {
|
) -> Result<(), RogError> {
|
||||||
self.initialise().await?;
|
|
||||||
self.set_and_save(mode, config).await
|
self.set_and_save(mode, config).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should only be used if the bytes you are writing are verified correct
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
async fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
||||||
println!("1 Wrote: {:X?}", message);
|
if let Ok(mut file) = OpenOptions::new().write(true).open(&self.dev_node) {
|
||||||
match unsafe { self.handle.as_ref() }.write_interrupt(
|
file.write_all(message).unwrap();
|
||||||
self.led_endpoint,
|
return Ok(());
|
||||||
message,
|
|
||||||
Duration::from_millis(5),
|
|
||||||
) {
|
|
||||||
Ok(_) => {
|
|
||||||
let mut buf = [0; 32];
|
|
||||||
match unsafe { self.handle.as_ref() }.read_interrupt(
|
|
||||||
0x83,
|
|
||||||
&mut buf,
|
|
||||||
Duration::from_millis(5),
|
|
||||||
) {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("2 Read: {:X?}", buf);
|
|
||||||
}
|
|
||||||
Err(err) => match err {
|
|
||||||
rusb::Error::Timeout => {}
|
|
||||||
_ => error!("Failed to read to led interrupt: {:?}", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => match err {
|
|
||||||
rusb::Error::Timeout => {}
|
|
||||||
_ => error!("Failed to write to led interrupt: {:?}", err),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Err(RogError::NotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an effect block
|
/// Write an effect block
|
||||||
@@ -150,10 +86,6 @@ where
|
|||||||
config.current_mode = mode_num;
|
config.current_mode = mode_num;
|
||||||
config.set_mode_data(mode);
|
config.set_mode_data(mode);
|
||||||
config.write();
|
config.write();
|
||||||
info!(
|
|
||||||
"Switched LED mode to {}",
|
|
||||||
<&str>::from(&<AuraModes>::from(config.current_mode))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -198,7 +130,6 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn reload_last_builtin(&mut self, config: &mut Config) -> Result<(), RogError> {
|
pub async fn reload_last_builtin(&mut self, config: &mut Config) -> Result<(), RogError> {
|
||||||
self.initialise().await?;
|
|
||||||
// set current mode (if any)
|
// set current mode (if any)
|
||||||
if self.supported_modes.len() > 1 {
|
if self.supported_modes.len() > 1 {
|
||||||
if self.supported_modes.contains(&config.current_mode) {
|
if self.supported_modes.contains(&config.current_mode) {
|
||||||
|
|||||||
@@ -2,14 +2,11 @@
|
|||||||
|
|
||||||
use crate::{config::Config, error::RogError};
|
use crate::{config::Config, error::RogError};
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rusb::{Device, DeviceHandle};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::marker::{PhantomPinned};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
||||||
@@ -26,72 +23,11 @@ static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_
|
|||||||
/// - `LED_INIT4`
|
/// - `LED_INIT4`
|
||||||
/// - `LED_INIT2`
|
/// - `LED_INIT2`
|
||||||
/// - `LED_INIT4`
|
/// - `LED_INIT4`
|
||||||
pub struct RogCore {
|
pub struct RogCore {}
|
||||||
handle: DeviceHandle<rusb::GlobalContext>,
|
|
||||||
_pin: PhantomPinned,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RogCore {
|
impl RogCore {
|
||||||
pub fn new(vendor: u16, product: u16, match_endpoint: u8) -> Result<RogCore, Box<dyn Error>> {
|
pub fn new(vendor: u16, product: u16) -> Self {
|
||||||
let device = RogCore::get_device(vendor, product).map_err(|err| {
|
RogCore {}
|
||||||
error!("Could not find keyboard device: {:?}", err);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let dev_config = device.config_descriptor(0).map_err(|err| {
|
|
||||||
error!("Could not get keyboard device config: {:?}", err);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
info!("ACTIVE CONFIG: {:?}", dev_config.number());
|
|
||||||
|
|
||||||
// Interface with outputs
|
|
||||||
let mut interface = 2; // The interface with keyboard consumer device and LED control
|
|
||||||
// is #2 on 0x1866 device at least
|
|
||||||
for iface in dev_config.interfaces() {
|
|
||||||
for desc in iface.descriptors() {
|
|
||||||
for endpoint in desc.endpoint_descriptors() {
|
|
||||||
if endpoint.address() == match_endpoint {
|
|
||||||
info!("INTERVAL: {:?}", endpoint.interval());
|
|
||||||
info!("MAX_PKT_SIZE: {:?}", endpoint.max_packet_size());
|
|
||||||
info!("SYNC: {:?}", endpoint.sync_type());
|
|
||||||
info!("TRANSFER_TYPE: {:?}", endpoint.transfer_type());
|
|
||||||
info!("ENDPOINT: {:X?}", endpoint.address());
|
|
||||||
info!("INTERFACE: {:X?}", desc.interface_number());
|
|
||||||
interface = desc.interface_number();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut device = device.open().map_err(|err| {
|
|
||||||
error!("Could not open device: {:?}", err);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Err(err) = device.set_auto_detach_kernel_driver(true) {
|
|
||||||
warn!("Auto-detach kernel driver failed: {:?}", err);
|
|
||||||
warn!("Trying device reset");
|
|
||||||
device.reset()?;
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
|
||||||
device.set_auto_detach_kernel_driver(true)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::thread::sleep(std::time::Duration::from_millis(500));
|
|
||||||
Ok(RogCore {
|
|
||||||
handle: device,
|
|
||||||
_pin: PhantomPinned,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_device(vendor: u16, product: u16) -> Result<Device<rusb::GlobalContext>, rusb::Error> {
|
|
||||||
for device in rusb::devices()?.iter() {
|
|
||||||
let device_desc = device.device_descriptor()?;
|
|
||||||
if device_desc.vendor_id() == vendor && device_desc.product_id() == product {
|
|
||||||
return Ok(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(rusb::Error::NoDevice)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fan_path() -> Result<&'static str, std::io::Error> {
|
fn get_fan_path() -> Result<&'static str, std::io::Error> {
|
||||||
@@ -318,7 +254,6 @@ impl RogCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FanLevel {
|
pub enum FanLevel {
|
||||||
Normal,
|
Normal,
|
||||||
|
|||||||
Reference in New Issue
Block a user