From 8ad5c4fe8d714c9fc2672a321fb0f6dcc6cfa413 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 27 Apr 2025 16:14:02 +0800 Subject: [PATCH 01/27] chromium_ec: Extract i2c_passthrough to separate module TODO: Split out port and address code also Signed-off-by: Daniel Schaefer --- framework_lib/src/ccgx/device.rs | 121 ++---------------- .../src/chromium_ec/i2c_passthrough.rs | 118 +++++++++++++++++ framework_lib/src/chromium_ec/mod.rs | 1 + 3 files changed, 129 insertions(+), 111 deletions(-) create mode 100644 framework_lib/src/chromium_ec/i2c_passthrough.rs diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index aa1af5d0..ef7ac889 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -3,23 +3,17 @@ //! The current implementation talks to them by tunneling I2C through EC host commands. use alloc::format; -use alloc::string::ToString; -use alloc::vec; use alloc::vec::Vec; #[cfg(feature = "uefi")] use core::prelude::rust_2021::derive; use crate::ccgx::{AppVersion, BaseVersion, ControllerVersion}; -use crate::chromium_ec::command::EcCommands; -use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResult}; -use crate::util::{self, assert_win_len, Config, Platform}; -use std::mem::size_of; +use crate::chromium_ec::i2c_passthrough::*; +use crate::chromium_ec::{CrosEc, EcError, EcResult}; +use crate::util::{assert_win_len, Config, Platform}; use super::*; -/// Maximum transfer size for one I2C transaction supported by the chip -const MAX_I2C_CHUNK: usize = 128; - enum ControlRegisters { DeviceMode = 0, SiliconId = 2, // Two bytes long, First LSB, then MSB @@ -106,58 +100,6 @@ pub struct PdController { ec: CrosEc, } -fn passthrough_offset(dev_index: u16) -> u16 { - dev_index * 0x4000 -} - -#[repr(C, packed)] -struct EcParamsI2cPassthruMsg { - /// Slave address and flags - addr_and_flags: u16, - transfer_len: u16, -} - -#[repr(C, packed)] -struct EcParamsI2cPassthru { - port: u8, - /// How many messages - messages: u8, - msg: [EcParamsI2cPassthruMsg; 0], -} - -#[repr(C, packed)] -struct _EcI2cPassthruResponse { - i2c_status: u8, - /// How many messages - messages: u8, - data: [u8; 0], -} - -struct EcI2cPassthruResponse { - i2c_status: u8, // TODO: Can probably use enum - data: Vec, -} - -impl EcI2cPassthruResponse { - fn is_successful(&self) -> EcResult<()> { - if self.i2c_status & 1 > 0 { - return Err(EcError::DeviceError( - "I2C Transfer not acknowledged".to_string(), - )); - } - if self.i2c_status & (1 << 1) > 0 { - return Err(EcError::DeviceError("I2C Transfer timeout".to_string())); - } - // I'm not aware of any other errors, but there might be. - // But I don't think multiple errors can be indicated at the same time - assert_eq!(self.i2c_status, 0); - Ok(()) - } -} - -/// Indicate that it's a read, not a write -const I2C_READ_FLAG: u16 = 1 << 15; - #[derive(Debug, PartialEq)] pub enum FwMode { BootLoader = 0, @@ -194,13 +136,6 @@ impl PdController { pub fn new(port: PdPort, ec: CrosEc) -> Self { PdController { port, ec } } - /// Wrapped with support for dev id - /// TODO: Should move into chromium_ec module - /// TODO: Must not call CrosEc::new() otherwise the driver isn't configurable! - fn send_ec_command(&self, code: u16, dev_index: u16, data: &[u8]) -> EcResult> { - let command_id = code + passthrough_offset(dev_index); - self.ec.send_command(command_id, 0, data) - } fn i2c_read(&self, addr: u16, len: u16) -> EcResult { trace!( @@ -208,49 +143,13 @@ impl PdController { self.port.i2c_port().unwrap(), self.port.i2c_address() ); - trace!("i2c_read(addr: {}, len: {})", addr, len); - if usize::from(len) > MAX_I2C_CHUNK { - return EcResult::Err(EcError::DeviceError(format!( - "i2c_read too long. Must be <128, is: {}", - len - ))); - } - let addr_bytes = u16::to_le_bytes(addr); - let messages = vec![ - EcParamsI2cPassthruMsg { - addr_and_flags: self.port.i2c_address(), - transfer_len: addr_bytes.len() as u16, - }, - EcParamsI2cPassthruMsg { - addr_and_flags: self.port.i2c_address() + I2C_READ_FLAG, - transfer_len: len, // How much to read - }, - ]; - let msgs_len = size_of::() * messages.len(); - let msgs_buffer: &[u8] = unsafe { util::any_vec_as_u8_slice(&messages) }; - - let params = EcParamsI2cPassthru { - port: self.port.i2c_port()?, - messages: messages.len() as u8, - msg: [], // Messages are copied right after this struct - }; - let params_len = size_of::(); - let params_buffer: &[u8] = unsafe { util::any_as_u8_slice(¶ms) }; - - let mut buffer: Vec = vec![0; params_len + msgs_len + addr_bytes.len()]; - buffer[0..params_len].copy_from_slice(params_buffer); - buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer); - buffer[params_len + msgs_len..].copy_from_slice(&addr_bytes); - - let data = self.send_ec_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?; - let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) }; - let res_data = &data[size_of::<_EcI2cPassthruResponse>()..]; - // TODO: Seems to be either one, non-deterministically - debug_assert!(res.messages as usize == messages.len() || res.messages == 0); - Ok(EcI2cPassthruResponse { - i2c_status: res.i2c_status, - data: res_data.to_vec(), - }) + i2c_read( + &self.ec, + self.port.i2c_port().unwrap(), + self.port.i2c_address(), + addr, + len, + ) } fn ccgx_read(&self, reg: ControlRegisters, len: u16) -> EcResult> { diff --git a/framework_lib/src/chromium_ec/i2c_passthrough.rs b/framework_lib/src/chromium_ec/i2c_passthrough.rs new file mode 100644 index 00000000..9a1fac97 --- /dev/null +++ b/framework_lib/src/chromium_ec/i2c_passthrough.rs @@ -0,0 +1,118 @@ +use crate::chromium_ec::command::EcCommands; +use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResult}; +use crate::util; +use alloc::format; +use alloc::string::ToString; +use alloc::vec; +use alloc::vec::Vec; +use std::mem::size_of; + +/// Maximum transfer size for one I2C transaction supported by the chip +pub const MAX_I2C_CHUNK: usize = 128; + +#[repr(C, packed)] +pub struct EcParamsI2cPassthruMsg { + /// Slave address and flags + addr_and_flags: u16, + transfer_len: u16, +} + +#[repr(C, packed)] +pub struct EcParamsI2cPassthru { + port: u8, + /// How many messages + messages: u8, + msg: [EcParamsI2cPassthruMsg; 0], +} + +#[repr(C, packed)] +struct _EcI2cPassthruResponse { + i2c_status: u8, + /// How many messages + messages: u8, + data: [u8; 0], +} + +#[derive(Debug)] +pub struct EcI2cPassthruResponse { + pub i2c_status: u8, // TODO: Can probably use enum + pub data: Vec, +} + +impl EcI2cPassthruResponse { + pub fn is_successful(&self) -> EcResult<()> { + if self.i2c_status & 1 > 0 { + return Err(EcError::DeviceError( + "I2C Transfer not acknowledged".to_string(), + )); + } + if self.i2c_status & (1 << 1) > 0 { + return Err(EcError::DeviceError("I2C Transfer timeout".to_string())); + } + // I'm not aware of any other errors, but there might be. + // But I don't think multiple errors can be indicated at the same time + assert_eq!(self.i2c_status, 0); + Ok(()) + } +} + +/// Indicate that it's a read, not a write +const I2C_READ_FLAG: u16 = 1 << 15; + +pub fn i2c_read( + ec: &CrosEc, + i2c_port: u8, + i2c_addr: u16, + addr: u16, + len: u16, +) -> EcResult { + trace!( + "i2c_read(i2c_port: 0x{:X}, i2c_addr: 0x{:X}, addr: 0x{:X}, len: 0x{:X})", + i2c_port, + i2c_addr, + addr, + len + ); + if usize::from(len) > MAX_I2C_CHUNK { + return EcResult::Err(EcError::DeviceError(format!( + "i2c_read too long. Must be <128, is: {}", + len + ))); + } + let addr_bytes = u16::to_le_bytes(addr); + let messages = vec![ + EcParamsI2cPassthruMsg { + addr_and_flags: i2c_addr, + transfer_len: addr_bytes.len() as u16, + }, + EcParamsI2cPassthruMsg { + addr_and_flags: i2c_addr + I2C_READ_FLAG, + transfer_len: len, // How much to read + }, + ]; + let msgs_len = size_of::() * messages.len(); + let msgs_buffer: &[u8] = unsafe { util::any_vec_as_u8_slice(&messages) }; + + let params = EcParamsI2cPassthru { + port: i2c_port, + messages: messages.len() as u8, + msg: [], // Messages are copied right after this struct + }; + let params_len = size_of::(); + let params_buffer: &[u8] = unsafe { util::any_as_u8_slice(¶ms) }; + + let mut buffer: Vec = vec![0; params_len + msgs_len + addr_bytes.len()]; + buffer[0..params_len].copy_from_slice(params_buffer); + buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer); + buffer[params_len + msgs_len..].copy_from_slice(&addr_bytes); + + let data = ec.send_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?; + let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) }; + let res_data = &data[size_of::<_EcI2cPassthruResponse>()..]; + // TODO: Seems to be either one, non-deterministically + debug_assert!(res.messages as usize == messages.len() || res.messages == 0); + Ok(EcI2cPassthruResponse { + i2c_status: res.i2c_status, + data: res_data.to_vec(), + }) +} diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index e1a53c20..7ee21b72 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -22,6 +22,7 @@ pub mod command; pub mod commands; #[cfg(feature = "cros_ec_driver")] mod cros_ec; +pub mod i2c_passthrough; pub mod input_deck; mod portio; mod portio_mec; From 426090e9faf9d9a37975fb701d217c427936a041 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 28 Apr 2025 18:29:23 +0800 Subject: [PATCH 02/27] i2c_passthrough: Add i2c_write function Signed-off-by: Daniel Schaefer --- .../src/chromium_ec/i2c_passthrough.rs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/framework_lib/src/chromium_ec/i2c_passthrough.rs b/framework_lib/src/chromium_ec/i2c_passthrough.rs index 9a1fac97..dfebaafc 100644 --- a/framework_lib/src/chromium_ec/i2c_passthrough.rs +++ b/framework_lib/src/chromium_ec/i2c_passthrough.rs @@ -116,3 +116,49 @@ pub fn i2c_read( data: res_data.to_vec(), }) } + +pub fn i2c_write( + ec: &CrosEc, + i2c_port: u8, + i2c_addr: u16, + addr: u16, + data: &[u8], +) -> EcResult { + trace!( + " i2c_write(addr: {}, len: {}, data: {:?})", + addr, + data.len(), + data + ); + let addr_bytes = [addr as u8, (addr >> 8) as u8]; + let messages = vec![EcParamsI2cPassthruMsg { + addr_and_flags: i2c_addr, + transfer_len: (addr_bytes.len() + data.len()) as u16, + }]; + let msgs_len = size_of::() * messages.len(); + let msgs_buffer: &[u8] = unsafe { util::any_vec_as_u8_slice(&messages) }; + + let params = EcParamsI2cPassthru { + port: i2c_port, + messages: messages.len() as u8, + msg: [], // Messages are copied right after this struct + }; + let params_len = size_of::(); + let params_buffer: &[u8] = unsafe { util::any_as_u8_slice(¶ms) }; + + let mut buffer: Vec = vec![0; params_len + msgs_len + addr_bytes.len() + data.len()]; + buffer[0..params_len].copy_from_slice(params_buffer); + buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer); + buffer[params_len + msgs_len..params_len + msgs_len + addr_bytes.len()] + .copy_from_slice(&addr_bytes); + buffer[params_len + msgs_len + addr_bytes.len()..].copy_from_slice(data); + + let data = ec.send_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?; + let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) }; + assert_eq!(data.len(), size_of::<_EcI2cPassthruResponse>()); // No extra data other than the header + debug_assert_eq!(res.messages as usize, messages.len()); + Ok(EcI2cPassthruResponse { + i2c_status: res.i2c_status, + data: vec![], // Writing doesn't return any data + }) +} From 13e9c67bcf2f73b2b37df0b3c77da2e42568e9a3 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 2 May 2025 11:40:13 +0800 Subject: [PATCH 03/27] EXAMPLES.md: Fix layout --- EXAMPLES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES.md b/EXAMPLES.md index 4f1ae29c..50c611b7 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -186,6 +186,7 @@ Expansion Bay Door closed: true Board: DualInterposer Serial Number: FRAXXXXXXXXXXXXXXX +``` ## Check charger and battery status (Framework 12/13/16) From 208425401f07fb2b8b41ef785d9d2b44d7962d40 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 2 May 2025 17:09:20 +0800 Subject: [PATCH 04/27] Fix charge limit based on battery charge Following are fixed now ``` > sudo framework_tool --charge-rate-limit 80 0.8 > sudo framework_tool --charge-current-limit 80 2000 ``` Reported by: github.com/tjkirch Signed-off-by: Daniel Schaefer --- framework_lib/src/commandline/clap_std.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 11ef2b72..e9e6a9ba 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -157,12 +157,12 @@ struct ClapCli { /// Get or set max charge current limit #[arg(long)] - #[clap(num_args = ..2)] + #[clap(num_args = ..=2)] charge_current_limit: Vec, /// Get or set max charge current limit #[arg(long)] - #[clap(num_args = ..2)] + #[clap(num_args = ..=2)] charge_rate_limit: Vec, /// Get GPIO value by name From 8f347ae64b42cc165bac710e32b5440bc78f7866 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 2 May 2025 17:47:01 +0800 Subject: [PATCH 05/27] charge-limit: Fix documentation Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 4f1ae29c..52cb3e69 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -291,8 +291,8 @@ Battery Status Battery charging # Set charge rate/current limit only if battery is >80% charged -> sudo framework_tool --charge-rate-limit 80 0.8 -> sudo framework_tool --charge-current-limit 80 2000 +> sudo framework_tool --charge-rate-limit 0.8 80 +> sudo framework_tool --charge-current-limit 2000 80 ``` ## Stylus (Framework 12) From 98e8788ba6f9a00e71e585e4625b4549e0d08fc8 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 30 Oct 2023 15:31:54 +0800 Subject: [PATCH 06/27] chromium_ec: Use portio if /dev/cros_ec does not exist Then users don't manually have to specify `--driver portio` if the cros_ec kernel driver is not loaded. Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/cros_ec.rs | 2 +- framework_lib/src/chromium_ec/mod.rs | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/framework_lib/src/chromium_ec/cros_ec.rs b/framework_lib/src/chromium_ec/cros_ec.rs index a3b4928a..372c45ff 100644 --- a/framework_lib/src/chromium_ec/cros_ec.rs +++ b/framework_lib/src/chromium_ec/cros_ec.rs @@ -55,7 +55,7 @@ struct CrosEcCommandV2 { data: [u8; IN_SIZE], } -const DEV_PATH: &str = "/dev/cros_ec"; +pub const DEV_PATH: &str = "/dev/cros_ec"; lazy_static! { static ref CROS_EC_FD: Arc>> = Arc::new(Mutex::new(None)); diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index e0a3094a..4ca04926 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -239,14 +239,20 @@ impl Default for CrosEc { /// /// Depending on the availability we choose the first one as default fn available_drivers() -> Vec { - vec![ - #[cfg(feature = "win_driver")] - CrosEcDriverType::Windows, - #[cfg(feature = "cros_ec_driver")] - CrosEcDriverType::CrosEc, - #[cfg(not(feature = "windows"))] - CrosEcDriverType::Portio, - ] + let mut drivers = vec![]; + + #[cfg(feature = "win_driver")] + drivers.push(CrosEcDriverType::Windows); + + #[cfg(feature = "cros_ec_driver")] + if std::path::Path::new(cros_ec::DEV_PATH).exists() { + drivers.push(CrosEcDriverType::CrosEc); + } + + #[cfg(not(feature = "windows"))] + drivers.push(CrosEcDriverType::Portio); + + drivers } impl CrosEc { From aad94339fc3ea449e4a3d9e9036d15e4820e8572 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 2 May 2025 19:21:32 +0800 Subject: [PATCH 07/27] chromioum_ec: Autodetect Microchip EC when using portio Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 1 + framework_lib/src/chromium_ec/portio.rs | 72 +++++++++++---------- framework_lib/src/chromium_ec/portio_mec.rs | 10 +-- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 4ca04926..30621225 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -268,6 +268,7 @@ impl CrosEc { return None; } debug!("Chromium EC Driver: {:?}", driver); + Some(CrosEc { driver }) } diff --git a/framework_lib/src/chromium_ec/portio.rs b/framework_lib/src/chromium_ec/portio.rs index b453c41c..1f480187 100644 --- a/framework_lib/src/chromium_ec/portio.rs +++ b/framework_lib/src/chromium_ec/portio.rs @@ -12,10 +12,9 @@ use log::Level; #[cfg(feature = "linux_pio")] use nix::unistd::Uid; use num::FromPrimitive; -#[cfg(feature = "linux_pio")] -use std::sync::{Arc, Mutex}; +use spin::Mutex; -use crate::chromium_ec::{has_mec, portio_mec}; +use crate::chromium_ec::{portio_mec, EC_MEMMAP_ID}; use crate::os_specific; use crate::util; @@ -172,65 +171,68 @@ fn transfer_read(port: u16, address: u16, size: u16) -> Vec { buffer } -#[cfg(feature = "linux_pio")] +#[derive(PartialEq)] +#[allow(dead_code)] enum Initialized { NotYet, + SucceededMec, Succeeded, Failed, } -#[cfg(feature = "linux_pio")] lazy_static! { - static ref INITIALIZED: Arc> = Arc::new(Mutex::new(Initialized::NotYet)); + static ref INITIALIZED: Mutex = Mutex::new(Initialized::NotYet); } -#[cfg(not(feature = "linux_pio"))] -fn init() -> bool { - // Nothing to do for bare-metal (UEFI) port I/O - true +fn has_mec() -> bool { + let init = INITIALIZED.lock(); + *init != Initialized::Succeeded } -// In Linux userspace has to first request access to ioports -// TODO: Close these again after we're done -#[cfg(feature = "linux_pio")] fn init() -> bool { - let mut init = INITIALIZED.lock().unwrap(); + let mut init = INITIALIZED.lock(); match *init { // Can directly give up, trying again won't help Initialized::Failed => return false, // Already initialized, no need to do anything. - Initialized::Succeeded => return true, + Initialized::Succeeded | Initialized::SucceededMec => return true, Initialized::NotYet => {} } + // First try on MEC + portio_mec::init(); + let ec_id = portio_mec::transfer_read(MEC_MEMMAP_OFFSET + EC_MEMMAP_ID, 2); + if ec_id[0] == b'E' && ec_id[1] == b'C' { + *init = Initialized::SucceededMec; + return true; + } + + // In Linux userspace has to first request access to ioports + // TODO: Close these again after we're done + #[cfg(feature = "linux_pio")] if !Uid::effective().is_root() { error!("Must be root to use port based I/O for EC communication."); *init = Initialized::Failed; return false; } - + #[cfg(feature = "linux_pio")] unsafe { - if has_mec() { - portio_mec::mec_init(); - } else { - // 8 for request/response header, 0xFF for response - let res = ioperm(EC_LPC_ADDR_HOST_ARGS as u64, 8 + 0xFF, 1); - if res != 0 { - error!( - "ioperm failed. portio driver is likely block by Linux kernel lockdown mode" - ); - return false; - } - - let res = ioperm(EC_LPC_ADDR_HOST_CMD as u64, 1, 1); - assert_eq!(res, 0); - let res = ioperm(EC_LPC_ADDR_HOST_DATA as u64, 1, 1); - assert_eq!(res, 0); - - let res = ioperm(NPC_MEMMAP_OFFSET as u64, super::EC_MEMMAP_SIZE as u64, 1); - assert_eq!(res, 0); + // 8 for request/response header, 0xFF for response + let res = ioperm(EC_LPC_ADDR_HOST_ARGS as u64, 8 + 0xFF, 1); + if res != 0 { + error!("ioperm failed. portio driver is likely block by Linux kernel lockdown mode"); + return false; } + + let res = ioperm(EC_LPC_ADDR_HOST_CMD as u64, 1, 1); + assert_eq!(res, 0); + let res = ioperm(EC_LPC_ADDR_HOST_DATA as u64, 1, 1); + assert_eq!(res, 0); + + let res = ioperm(NPC_MEMMAP_OFFSET as u64, super::EC_MEMMAP_SIZE as u64, 1); + assert_eq!(res, 0); } + *init = Initialized::Succeeded; true } diff --git a/framework_lib/src/chromium_ec/portio_mec.rs b/framework_lib/src/chromium_ec/portio_mec.rs index 974b8686..471a3219 100644 --- a/framework_lib/src/chromium_ec/portio_mec.rs +++ b/framework_lib/src/chromium_ec/portio_mec.rs @@ -22,10 +22,12 @@ const _MEC_LPC_DATA_REGISTER1: u16 = 0x0805; const MEC_LPC_DATA_REGISTER2: u16 = 0x0806; const _MEC_LPC_DATA_REGISTER3: u16 = 0x0807; -#[cfg(feature = "linux_pio")] -pub unsafe fn mec_init() { - ioperm(EC_LPC_ADDR_HOST_DATA as u64, 8, 1); - ioperm(MEC_LPC_ADDRESS_REGISTER0 as u64, 10, 1); +pub fn init() { + #[cfg(feature = "linux_pio")] + unsafe { + ioperm(EC_LPC_ADDR_HOST_DATA as u64, 8, 1); + ioperm(MEC_LPC_ADDRESS_REGISTER0 as u64, 10, 1); + } } // TODO: Create a wrapper From 8799d7b4161bcdfa1cd1a00fd6140a6faa707652 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 3 May 2025 20:19:37 +0800 Subject: [PATCH 08/27] commandline: Remove --has-mec Now we can autodetect, we don't need it anymore, yay! Signed-off-by: Daniel Schaefer --- README.md | 2 - completions/bash/framework_tool | 4 -- completions/zsh/_framework_tool | 1 - framework_lib/src/ccgx/device.rs | 8 ++-- framework_lib/src/chromium_ec/mod.rs | 53 +++++++---------------- framework_lib/src/commandline/clap_std.rs | 10 +---- framework_lib/src/commandline/mod.rs | 11 ++--- framework_lib/src/commandline/uefi.rs | 24 ++-------- framework_lib/src/smbios.rs | 4 +- framework_lib/src/util.rs | 4 +- rgbkbd.py | 2 +- 11 files changed, 32 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 0e89f34b..0784ba54 100644 --- a/README.md +++ b/README.md @@ -202,8 +202,6 @@ Options: Specify I2C addresses of the PD chips (Advanced) --pd-ports Specify I2C ports of the PD chips (Advanced) - --has-mec - Specify the type of EC chip (MEC/MCHP or other) [possible values: true, false] -t, --test Run self-test to check if interaction with EC is possible -h, --help Print help information ``` diff --git a/completions/bash/framework_tool b/completions/bash/framework_tool index f96fcc23..7031b8d5 100755 --- a/completions/bash/framework_tool +++ b/completions/bash/framework_tool @@ -50,7 +50,6 @@ _framework_tool() { "--driver" "--pd-addrs" "--pd-ports" - "--has-mec" "-t" "--test" "-h" "--help" ) @@ -59,7 +58,6 @@ _framework_tool() { local inputdeck_modes=("auto" "off" "on") local console_modes=("recent" "follow") local drivers=("portio" "cros-ec" "windows") - local has_mec_options=("true" "false") local brightness_options=("high" "medium" "low" "ultra-low") local current_word prev_word @@ -77,8 +75,6 @@ _framework_tool() { COMPREPLY=( $(compgen -W "${console_modes[*]}" -- "$current_word") ) elif [[ $prev_word == "--driver" ]]; then COMPREPLY=( $(compgen -W "${drivers[*]}" -- "$current_word") ) - elif [[ $prev_word == "--has-mec" ]]; then - COMPREPLY=( $(compgen -W "${has_mec_options[*]}" -- "$current_word") ) elif [[ $prev_word == "--fp-brightness" ]]; then COMPREPLY=( $(compgen -W "${brightness_options[*]}" -- "$current_word") ) fi diff --git a/completions/zsh/_framework_tool b/completions/zsh/_framework_tool index ad6aa668..2d473c8f 100644 --- a/completions/zsh/_framework_tool +++ b/completions/zsh/_framework_tool @@ -48,7 +48,6 @@ options=( '--driver[Select which driver is used]:driver:(portio cros-ec windows)' '--pd-addrs[Specify I2C addresses of the PD chips (Advanced)]:pd_addrs' '--pd-ports[Specify I2C ports of the PD chips (Advanced)]:pd_ports' - '--has-mec[Specify the type of EC chip (MEC/MCHP or other)]:has_mec:(true false)' '-t[Run self-test to check if interaction with EC is possible]' '-h[Print help]' ) diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index aa1af5d0..b928d24d 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -41,8 +41,8 @@ impl PdPort { let platform = &(*config).as_ref().unwrap().platform; match (platform, self) { - (Platform::GenericFramework((left, _), _, _), PdPort::Left01) => *left, - (Platform::GenericFramework((_, right), _, _), PdPort::Right23) => *right, + (Platform::GenericFramework((left, _), _), PdPort::Left01) => *left, + (Platform::GenericFramework((_, right), _), PdPort::Right23) => *right, // Framework AMD Platforms (CCG8) ( Platform::Framework13Amd7080 @@ -70,8 +70,8 @@ impl PdPort { let platform = &(*config).as_ref().unwrap().platform; Ok(match (platform, self) { - (Platform::GenericFramework(_, (left, _), _), PdPort::Left01) => *left, - (Platform::GenericFramework(_, (_, right), _), PdPort::Right23) => *right, + (Platform::GenericFramework(_, (left, _)), PdPort::Left01) => *left, + (Platform::GenericFramework(_, (_, right)), PdPort::Right23) => *right, (Platform::IntelGen11, _) => 6, (Platform::IntelGen12 | Platform::IntelGen13, PdPort::Left01) => 6, (Platform::IntelGen12 | Platform::IntelGen13, PdPort::Right23) => 7, diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 30621225..82c1e0a8 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -201,24 +201,6 @@ const BOARD_VERSION_NPC_DB: [i32; BOARD_VERSION_COUNT] = [ 100, 311, 521, 721, 931, 1131, 1341, 1551, 1751, 1961, 2171, 2370, 2580, 2780, 2990, 3200, ]; -pub fn has_mec() -> bool { - let platform = smbios::get_platform().unwrap(); - if let Platform::GenericFramework(_, _, has_mec) = platform { - return has_mec; - } - - // TODO: Should turn this around - !matches!( - smbios::get_platform().unwrap(), - Platform::Framework13Amd7080 - | Platform::Framework16Amd7080 - | Platform::IntelCoreUltra1 - | Platform::Framework13AmdAi300 - | Platform::Framework12IntelGen13 - | Platform::FrameworkDesktopAmdAiMax300 - ) -} - pub trait CrosEcDriver { fn read_memory(&self, offset: u16, length: u16) -> Option>; fn send_command(&self, command: u16, command_version: u8, data: &[u8]) -> EcResult>; @@ -953,30 +935,25 @@ impl CrosEc { // Everything before is probably a header. // TODO: I don't think there are magic bytes on zephyr firmware // - if has_mec() { - println!(" Check MCHP magic byte at start of firmware code."); - // Make sure we can read at an offset and with arbitrary length - let data = self.read_ec_flash(FLASH_PROGRAM_OFFSET, 16).unwrap(); - debug!("Expecting beginning with 50 48 43 4D ('PHCM' in ASCII)"); - debug!("{:02X?}", data); - println!( - " {:02X?} ASCII:{:?}", - &data[..4], - core::str::from_utf8(&data[..4]) - ); - - if data[0..4] != [0x50, 0x48, 0x43, 0x4D] { - println!(" INVALID: {:02X?}", &data[0..3]); - res = Err(EcError::DeviceError(format!( - "INVALID: {:02X?}", - &data[0..3] - ))); - } + debug!(" Check MCHP magic bytes at start of firmware code."); + // Make sure we can read at an offset and with arbitrary length + let data = self.read_ec_flash(FLASH_PROGRAM_OFFSET, 16).unwrap(); + debug!("Expecting beginning with 50 48 43 4D ('PHCM' in ASCII)"); + debug!("{:02X?}", data); + debug!( + " {:02X?} ASCII:{:?}", + &data[..4], + core::str::from_utf8(&data[..4]) + ); + + let has_mec = data[0..4] == [0x50, 0x48, 0x43, 0x4D]; + if has_mec { + debug!(" Found MCHP magic bytes at start of firmware code."); } // ===== Test 4 ===== println!(" Read flash flags"); - let data = if has_mec() { + let data = if has_mec { self.read_ec_flash(MEC_FLASH_FLAGS, 0x80).unwrap() } else { self.read_ec_flash(NPC_FLASH_FLAGS, 0x80).unwrap() diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 3c81c755..b4b6e5b6 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -228,20 +228,15 @@ struct ClapCli { driver: Option, /// Specify I2C addresses of the PD chips (Advanced) - #[clap(number_of_values = 2, requires("pd_ports"), requires("has_mec"))] + #[clap(number_of_values = 2, requires("pd_ports"))] #[arg(long)] pd_addrs: Vec, /// Specify I2C ports of the PD chips (Advanced) - #[clap(number_of_values = 2, requires("pd_addrs"), requires("has_mec"))] + #[clap(number_of_values = 2, requires("pd_addrs"))] #[arg(long)] pd_ports: Vec, - /// Specify the type of EC chip (MEC/MCHP or other) - #[clap(requires("pd_addrs"), requires("pd_ports"))] - #[arg(long)] - has_mec: Option, - /// Run self-test to check if interaction with EC is possible #[arg(long, short)] test: bool, @@ -408,7 +403,6 @@ pub fn parse(args: &[String]) -> Cli { driver: args.driver, pd_addrs, pd_ports, - has_mec: args.has_mec, test: args.test, // TODO: Set help. Not very important because Clap handles this by itself help: false, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 87b08e3f..88fd1e61 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -191,7 +191,6 @@ pub struct Cli { pub hash: Option, pub pd_addrs: Option<(u16, u16)>, pub pd_ports: Option<(u8, u8)>, - pub has_mec: Option, pub help: bool, pub info: bool, pub flash_gpu_descriptor: Option<(u8, String)>, @@ -701,12 +700,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } // Must be run before any application code to set the config - if args.pd_addrs.is_some() && args.pd_ports.is_some() && args.has_mec.is_some() { - let platform = Platform::GenericFramework( - args.pd_addrs.unwrap(), - args.pd_ports.unwrap(), - args.has_mec.unwrap(), - ); + if args.pd_addrs.is_some() && args.pd_ports.is_some() { + let platform = Platform::GenericFramework(args.pd_addrs.unwrap(), args.pd_ports.unwrap()); Config::set(platform); } @@ -1169,7 +1164,7 @@ fn selftest(ec: &CrosEc) -> Option<()> { } else { println!(" SMBIOS Platform: Unknown"); println!(); - println!("Specify custom platform parameters with --pd-ports --pd-addrs --has-mec"); + println!("Specify custom platform parameters with --pd-ports --pd-addrs"); return None; }; diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 626f0bd0..1fd9e5d8 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -106,7 +106,6 @@ pub fn parse(args: &[String]) -> Cli { driver: Some(CrosEcDriverType::Portio), pd_addrs: None, pd_ports: None, - has_mec: None, test: false, help: false, flash_gpu_descriptor: None, @@ -610,22 +609,6 @@ pub fn parse(args: &[String]) -> Cli { None }; found_an_option = true; - } else if arg == "--has-mec" { - cli.has_mec = if args.len() > i + 1 { - if let Ok(b) = args[i + 1].parse::() { - Some(b) - } else { - println!( - "Invalid value for --has-mec: '{}'. Must be 'true' or 'false'.", - args[i + 1] - ); - None - } - } else { - println!("--has-mec requires extra boolean argument."); - None - }; - found_an_option = true; } else if arg == "--raw-command" { cli.raw_command = args[1..].to_vec(); } else if arg == "--compare-version" { @@ -699,11 +682,10 @@ pub fn parse(args: &[String]) -> Cli { } } - let custom_platform = cli.pd_addrs.is_some() && cli.pd_ports.is_some() && cli.has_mec.is_some(); - let no_customization = - cli.pd_addrs.is_none() && cli.pd_ports.is_none() && cli.has_mec.is_none(); + let custom_platform = cli.pd_addrs.is_some() && cli.pd_ports.is_some(); + let no_customization = cli.pd_addrs.is_none() && cli.pd_ports.is_none(); if !(custom_platform || no_customization) { - println!("To customize the platform you need to provide all of --pd-addrs, --pd-ports and --has-mec"); + println!("To customize the platform you need to provide all of --pd-addrs, and --pd-ports"); } if args.len() == 1 && cli.paginate { diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index b25ed153..1345b396 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -46,7 +46,7 @@ pub enum ConfigDigit0 { pub fn is_framework() -> bool { if matches!( get_platform(), - Some(Platform::GenericFramework((_, _), (_, _), _)) + Some(Platform::GenericFramework((_, _), (_, _))) ) { return true; } @@ -252,7 +252,7 @@ pub fn get_platform() -> Option { // Except if it's a GenericFramework platform let config = Config::get(); let platform = &(*config).as_ref().unwrap().platform; - if matches!(platform, Platform::GenericFramework((_, _), (_, _), _)) { + if matches!(platform, Platform::GenericFramework((_, _), (_, _))) { return Some(*platform); } } diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index cfb97368..972d82a3 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -36,8 +36,8 @@ pub enum Platform { /// Framework Desktop - AMD Ryzen AI Max 300 FrameworkDesktopAmdAiMax300, /// Generic Framework device - /// pd_addrs, pd_ports, has_mec - GenericFramework((u16, u16), (u8, u8), bool), + /// pd_addrs, pd_ports + GenericFramework((u16, u16), (u8, u8)), } #[derive(Debug, PartialEq, Clone, Copy)] diff --git a/rgbkbd.py b/rgbkbd.py index 9088b85e..c997d897 100755 --- a/rgbkbd.py +++ b/rgbkbd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Example invocation in fish shell # cargo build && sudo ./target/debug/framework_tool \ -# --driver portio --has-mec false --pd-ports 1 1 --pd-addrs 64 64 \ +# --driver portio --pd-ports 1 1 --pd-addrs 64 64 \ # (./rgbkbd.py | string split ' ') BRIGHTNESS = 1 From db46c4bbd77d3a01079d30edea6655be594b1a9b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 4 May 2025 20:33:10 +0800 Subject: [PATCH 09/27] Simplify features and detect based on OS Now we can build on Windows just with `cargo build`! Signed-off-by: Daniel Schaefer --- .github/workflows/ci.yml | 10 +- README.md | 21 +--- framework_lib/Cargo.toml | 80 +++++-------- framework_lib/src/chromium_ec/command.rs | 4 +- framework_lib/src/chromium_ec/mod.rs | 24 ++-- framework_lib/src/chromium_ec/portio.rs | 121 +------------------- framework_lib/src/chromium_ec/portio_mec.rs | 6 +- framework_lib/src/chromium_ec/protocol.rs | 108 +++++++++++++++++ framework_lib/src/chromium_ec/windows.rs | 2 +- framework_lib/src/commandline/mod.rs | 14 +-- framework_lib/src/csme.rs | 8 +- framework_lib/src/esrt/mod.rs | 12 +- framework_lib/src/lib.rs | 4 +- framework_lib/src/touchscreen.rs | 2 +- framework_lib/src/util.rs | 13 +-- framework_tool/Cargo.toml | 7 -- 16 files changed, 198 insertions(+), 238 deletions(-) create mode 100644 framework_lib/src/chromium_ec/protocol.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a261d25..92f5299d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: run: cargo install cross - name: Build FreeBSD tool - run: cross build --target=x86_64-unknown-freebsd --no-default-features --features cross_freebsd + run: cross build --target=x86_64-unknown-freebsd --no-default-features -p framework_lib - name: Upload FreeBSD App uses: actions/upload-artifact@v4 @@ -93,15 +93,15 @@ jobs: # Build debug library first to fail fast - name: Build library (Windows) - run: cargo build -p framework_lib --no-default-features --features "windows" + run: cargo build -p framework_lib - name: Build Windows tool run: | - cargo build -p framework_tool --no-default-features --features "windows" - cargo build -p framework_tool --no-default-features --features "windows" --release + cargo build -p framework_tool + cargo build -p framework_tool --release - name: Check if Windows tool can start - run: cargo run --no-default-features --features "windows" -- --help --release + run: cargo run -- --help --release # Upload release build so that vcruntime is statically linked - name: Upload Windows App diff --git a/README.md b/README.md index 0784ba54..7c41c4ca 100644 --- a/README.md +++ b/README.md @@ -130,23 +130,10 @@ Building on Windows or in general with fewer features: ```ps1 # Build the library and tool -cargo build --no-default-features --features "windows" +cargo build # Running the tool -cargo run --no-default-features --features "windows" -``` - -Cross compile from Linux to FreeBSD: - -```sh -# One time, install cross tool -cargo install cross - -# Make sure docker is started as well -sudo systemctl start docker - -# Build -cross build --target=x86_64-unknown-freebsd --no-default-features --features unix +cargo run ``` ## Running @@ -375,8 +362,8 @@ Keyboard backlight: 0% sudo pkg install hidapi # Build the library and tool -cargo build --no-default-features --features freebsd +cargo build # Running the tool -cargo run --no-default-features --features freebsd +cargo run ``` diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index b9a7cc91..21d57035 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -8,39 +8,18 @@ rust-version = "1.74" build = "build.rs" [features] -default = ["linux"] -# Linux/FreeBSD -unix = ["std", "raw_pio", "smbios", "dep:nix", "dep:libc"] -linux = ["unix", "linux_pio", "cros_ec_driver", "hidapi", "rusb"] -freebsd = ["unix", "freebsd_pio", "hidapi", "rusb"] -# hidapi and rusb don't seem to build in the cross container at the moment -cross_freebsd = ["unix", "freebsd_pio"] -# Windows does not have the cros_ec driver nor raw port I/O access to userspace -windows = ["std", "smbios", "dep:windows", "win_driver", "raw_pio", "hidapi", "rusb", "dep:wmi"] -smbios = ["dep:smbios-lib"] -std = ["dep:clap", "dep:clap-num", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std"] +default = ["std"] +std = ["hidapi", "rusb"] rusb = ["dep:rusb"] hidapi = ["dep:hidapi"] uefi = [ - "dep:plain", "raw_pio", "smbios", "lazy_static/spin_no_std", "dep:uefi", "dep:uefi-services", + "lazy_static/spin_no_std", # Otherwise I get: `LLVM ERROR: Do not know how to split the result of this operator!` # Seems to be a Ruset/LLVM bug when SSE is enabled. # See: https://github.com/rust-lang/rust/issues/61721 "sha2/force-soft" ] -# EC communication via Port I/O on FreeBSD -freebsd_pio = ["redox_hwio/std"] -# EC communication via Port I/O on Linux -linux_pio = ["dep:libc", "redox_hwio/std"] -# EC communication via raw Port I/O (e.g. UEFI or other ring 0 code) -raw_pio = [] -# EC communication via cros_ec driver on Linux -cros_ec_driver = [] - -# Chromium EC driver by DHowett -win_driver = [] - [build-dependencies] built = { version = "0.5", features = ["chrono", "git2"] } @@ -48,39 +27,42 @@ built = { version = "0.5", features = ["chrono", "git2"] } lazy_static = "1.4.0" sha2 = { version = "0.10.8", default-features = false, features = [ "force-soft" ] } regex = { version = "1.11.1", default-features = false } -redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false } -libc = { version = "0.2.155", optional = true } -clap = { version = "4.5", features = ["derive", "cargo"], optional = true } -clap-num = { version = "1.2.0", optional = true } -clap-verbosity-flag = { version = "2.2.1", optional = true } -nix = { version = "0.29.0", features = ["ioctl", "user"], optional = true } num = { version = "0.4", default-features = false } num-derive = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } -env_logger = { version = "0.11", optional = true } log = { version = "0.4", default-features = true } -uefi = { version = "0.20", features = ["alloc"], optional = true } -uefi-services = { version = "0.17", optional = true } -plain = { version = "0.2.3", optional = true } -spin = { version = "0.9.8", optional = false } -hidapi = { version = "2.6.3", optional = true, features = [ "windows-native" ] } -rusb = { version = "0.9.4", optional = true } +spin = { version = "0.9.8" } no-std-compat = { version = "0.4.1", features = [ "alloc" ] } guid_macros = { path = "../guid_macros" } -wmi = { version = "0.15.0", optional = true } +hidapi = { version = "2.6.3", features = [ "windows-native" ], optional = true } +rusb = { version = "0.9.4", optional = true } + +[target.'cfg(target_os = "uefi")'.dependencies] +uefi = { version = "0.20", features = ["alloc"] } +uefi-services = "0.17" +plain = "0.2.3" +redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false } +smbios-lib = { git = "https://github.com/FrameworkComputer/smbios-lib.git", branch = "no-std", default-features = false } + +[target.'cfg(windows)'.dependencies] +wmi = "0.15.0" +smbios-lib = { git = "https://github.com/FrameworkComputer/smbios-lib.git", branch = "no-std" } +env_logger = "0.11" +clap = { version = "4.5", features = ["derive", "cargo"] } +clap-num = { version = "1.2.0" } +clap-verbosity-flag = { version = "2.2.1" } -[dependencies.smbios-lib] -git = "https://github.com/FrameworkComputer/smbios-lib.git" -branch = "no-std" -optional = true -default-features = false -# Local development -#path = "../../smbios-lib" -# After my changes are upstreamed -#version = "0.9.0" +[target.'cfg(unix)'.dependencies] +libc = "0.2.155" +nix = { version = "0.29.0", features = ["ioctl", "user"] } +redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd" } +smbios-lib = { git = "https://github.com/FrameworkComputer/smbios-lib.git", branch = "no-std" } +env_logger = "0.11" +clap = { version = "4.5", features = ["derive", "cargo"] } +clap-num = { version = "1.2.0" } +clap-verbosity-flag = { version = "2.2.1" } -[dependencies.windows] -optional = true +[target.'cfg(windows)'.dependencies.windows] version = "0.59.0" features = [ "Win32_Foundation", diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index 416fd3e0..54b8db52 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -173,9 +173,9 @@ pub trait EcRequestRaw { { let response = self.send_command_vec_extra(ec, extra_data)?; // TODO: The Windows driver seems to return 20 more bytes than expected - #[cfg(feature = "win_driver")] + #[cfg(windows)] let expected = response.len() != std::mem::size_of::() + 20; - #[cfg(not(feature = "win_driver"))] + #[cfg(not(windows))] let expected = response.len() != std::mem::size_of::(); if expected { return Err(EcError::DeviceError(format!( diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 5e60b148..b1791240 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -21,13 +21,17 @@ use num_derive::FromPrimitive; pub mod command; pub mod commands; -#[cfg(feature = "cros_ec_driver")] +#[cfg(target_os = "linux")] mod cros_ec; pub mod i2c_passthrough; pub mod input_deck; +#[cfg(not(windows))] mod portio; +#[cfg(not(windows))] mod portio_mec; -#[cfg(feature = "win_driver")] +#[allow(dead_code)] +mod protocol; +#[cfg(windows)] mod windows; use alloc::format; @@ -224,15 +228,15 @@ impl Default for CrosEc { fn available_drivers() -> Vec { let mut drivers = vec![]; - #[cfg(feature = "win_driver")] + #[cfg(windows)] drivers.push(CrosEcDriverType::Windows); - #[cfg(feature = "cros_ec_driver")] + #[cfg(target_os = "linux")] if std::path::Path::new(cros_ec::DEV_PATH).exists() { drivers.push(CrosEcDriverType::CrosEc); } - #[cfg(not(feature = "windows"))] + #[cfg(not(windows))] drivers.push(CrosEcDriverType::Portio); drivers @@ -1320,10 +1324,11 @@ impl CrosEcDriver for CrosEc { // TODO: Change this function to return EcResult instead and print the error only in UI code print_err(match self.driver { + #[cfg(not(windows))] CrosEcDriverType::Portio => portio::read_memory(offset, length), - #[cfg(feature = "win_driver")] + #[cfg(windows)] CrosEcDriverType::Windows => windows::read_memory(offset, length), - #[cfg(feature = "cros_ec_driver")] + #[cfg(target_os = "linux")] CrosEcDriverType::CrosEc => cros_ec::read_memory(offset, length), _ => Err(EcError::DeviceError("No EC driver available".to_string())), }) @@ -1341,10 +1346,11 @@ impl CrosEcDriver for CrosEc { } match self.driver { + #[cfg(not(windows))] CrosEcDriverType::Portio => portio::send_command(command, command_version, data), - #[cfg(feature = "win_driver")] + #[cfg(windows)] CrosEcDriverType::Windows => windows::send_command(command, command_version, data), - #[cfg(feature = "cros_ec_driver")] + #[cfg(target_os = "linux")] CrosEcDriverType::CrosEc => cros_ec::send_command(command, command_version, data), _ => Err(EcError::DeviceError("No EC driver available".to_string())), } diff --git a/framework_lib/src/chromium_ec/portio.rs b/framework_lib/src/chromium_ec/portio.rs index 1f480187..152d5f40 100644 --- a/framework_lib/src/chromium_ec/portio.rs +++ b/framework_lib/src/chromium_ec/portio.rs @@ -4,130 +4,21 @@ use alloc::string::ToString; use alloc::vec; use alloc::vec::Vec; use core::convert::TryInto; -#[cfg(any(feature = "linux_pio", feature = "freebsd_pio", feature = "raw_pio"))] +#[cfg(not(windows))] use hwio::{Io, Pio}; -#[cfg(all(feature = "linux_pio", target_os = "linux"))] +#[cfg(target_os = "linux")] use libc::ioperm; use log::Level; -#[cfg(feature = "linux_pio")] +#[cfg(target_os = "linux")] use nix::unistd::Uid; use num::FromPrimitive; use spin::Mutex; +use crate::chromium_ec::protocol::*; use crate::chromium_ec::{portio_mec, EC_MEMMAP_ID}; use crate::os_specific; use crate::util; -/* - * Value written to legacy command port / prefix byte to indicate protocol - * 3+ structs are being used. Usage is bus-dependent. - */ -const EC_COMMAND_PROTOCOL_3: u8 = 0xda; - -// LPC command status byte masks -/// EC has written data but host hasn't consumed it yet -const _EC_LPC_STATUS_TO_HOST: u8 = 0x01; -/// Host has written data/command but EC hasn't consumed it yet -const EC_LPC_STATUS_FROM_HOST: u8 = 0x02; -/// EC is still processing a command -const EC_LPC_STATUS_PROCESSING: u8 = 0x04; -/// Previous command wasn't data but command -const _EC_LPC_STATUS_LAST_CMD: u8 = 0x08; -/// EC is in burst mode -const _EC_LPC_STATUS_BURST_MODE: u8 = 0x10; -/// SCI event is pending (requesting SCI query) -const _EC_LPC_STATUS_SCI_PENDING: u8 = 0x20; -/// SMI event is pending (requesting SMI query) -const _EC_LPC_STATUS_SMI_PENDING: u8 = 0x40; -/// Reserved -const _EC_LPC_STATUS_RESERVED: u8 = 0x80; - -/// EC is busy -const EC_LPC_STATUS_BUSY_MASK: u8 = EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING; - -// I/O addresses for ACPI commands -const _EC_LPC_ADDR_ACPI_DATA: u16 = 0x62; -const _EC_LPC_ADDR_ACPI_CMD: u16 = 0x66; - -// I/O addresses for host command -const EC_LPC_ADDR_HOST_DATA: u16 = 0x200; -const EC_LPC_ADDR_HOST_CMD: u16 = 0x204; - -// I/O addresses for host command args and params -// Protocol version 2 -const EC_LPC_ADDR_HOST_ARGS: u16 = 0x800; /* And 0x801, 0x802, 0x803 */ -const _EC_LPC_ADDR_HOST_PARAM: u16 = 0x804; /* For version 2 params; size is - * EC_PROTO2_MAX_PARAM_SIZE */ -// Protocol version 3 -const _EC_LPC_ADDR_HOST_PACKET: u16 = 0x800; /* Offset of version 3 packet */ -const EC_LPC_HOST_PACKET_SIZE: u16 = 0x100; /* Max size of version 3 packet */ - -const MEC_MEMMAP_OFFSET: u16 = 0x100; -const NPC_MEMMAP_OFFSET: u16 = 0xE00; - -// The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff -// and they tell the kernel that so we have to think of it as two parts. -const _EC_HOST_CMD_REGION0: u16 = 0x800; -const _EC_HOST_CMD_REGION1: u16 = 0x8800; -const _EC_HOST_CMD_REGION_SIZE: u16 = 0x80; - -// EC command register bit functions -const _EC_LPC_CMDR_DATA: u16 = 1 << 0; // Data ready for host to read -const _EC_LPC_CMDR_PENDING: u16 = 1 << 1; // Write pending to EC -const _EC_LPC_CMDR_BUSY: u16 = 1 << 2; // EC is busy processing a command -const _EC_LPC_CMDR_CMD: u16 = 1 << 3; // Last host write was a command -const _EC_LPC_CMDR_ACPI_BRST: u16 = 1 << 4; // Burst mode (not used) -const _EC_LPC_CMDR_SCI: u16 = 1 << 5; // SCI event is pending -const _EC_LPC_CMDR_SMI: u16 = 1 << 6; // SMI event is pending - -const EC_HOST_REQUEST_VERSION: u8 = 3; - -/// Request header of version 3 -#[repr(C, packed)] -struct EcHostRequest { - /// Version of this request structure (must be 3) - pub struct_version: u8, - - /// Checksum of entire request (header and data) - /// Everything added together adds up to 0 (wrapping around u8 limit) - pub checksum: u8, - - /// Command number - pub command: u16, - - /// Command version, usually 0 - pub command_version: u8, - - /// Reserved byte in protocol v3. Must be 0 - pub reserved: u8, - - /// Data length. Data is immediately after the header - pub data_len: u16, -} - -const EC_HOST_RESPONSE_VERSION: u8 = 3; - -/// Response header of version 3 -#[repr(C, packed)] -struct EcHostResponse { - /// Version of this request structure (must be 3) - pub struct_version: u8, - - /// Checksum of entire request (header and data) - pub checksum: u8, - - /// Status code of response. See enum _EcStatus - pub result: u16, - - /// Data length. Data is immediately after the header - pub data_len: u16, - - /// Reserved byte in protocol v3. Must be 0 - pub reserved: u16, -} -#[allow(dead_code)] -pub const HEADER_LEN: usize = std::mem::size_of::(); - fn transfer_write(buffer: &[u8]) { if has_mec() { return portio_mec::transfer_write(buffer); @@ -209,13 +100,13 @@ fn init() -> bool { // In Linux userspace has to first request access to ioports // TODO: Close these again after we're done - #[cfg(feature = "linux_pio")] + #[cfg(target_os = "linux")] if !Uid::effective().is_root() { error!("Must be root to use port based I/O for EC communication."); *init = Initialized::Failed; return false; } - #[cfg(feature = "linux_pio")] + #[cfg(target_os = "linux")] unsafe { // 8 for request/response header, 0xFF for response let res = ioperm(EC_LPC_ADDR_HOST_ARGS as u64, 8 + 0xFF, 1); diff --git a/framework_lib/src/chromium_ec/portio_mec.rs b/framework_lib/src/chromium_ec/portio_mec.rs index 471a3219..9d3664e2 100644 --- a/framework_lib/src/chromium_ec/portio_mec.rs +++ b/framework_lib/src/chromium_ec/portio_mec.rs @@ -5,11 +5,11 @@ use alloc::vec::Vec; use log::Level; use hwio::{Io, Pio}; -#[cfg(feature = "linux_pio")] +#[cfg(target_os = "linux")] use libc::ioperm; // I/O addresses for host command -#[cfg(feature = "linux_pio")] +#[cfg(target_os = "linux")] const EC_LPC_ADDR_HOST_DATA: u16 = 0x200; const MEC_EC_BYTE_ACCESS: u16 = 0x00; @@ -23,7 +23,7 @@ const MEC_LPC_DATA_REGISTER2: u16 = 0x0806; const _MEC_LPC_DATA_REGISTER3: u16 = 0x0807; pub fn init() { - #[cfg(feature = "linux_pio")] + #[cfg(target_os = "linux")] unsafe { ioperm(EC_LPC_ADDR_HOST_DATA as u64, 8, 1); ioperm(MEC_LPC_ADDRESS_REGISTER0 as u64, 10, 1); diff --git a/framework_lib/src/chromium_ec/protocol.rs b/framework_lib/src/chromium_ec/protocol.rs new file mode 100644 index 00000000..80152842 --- /dev/null +++ b/framework_lib/src/chromium_ec/protocol.rs @@ -0,0 +1,108 @@ +/* + * Value written to legacy command port / prefix byte to indicate protocol + * 3+ structs are being used. Usage is bus-dependent. + */ +pub const EC_COMMAND_PROTOCOL_3: u8 = 0xda; + +// LPC command status byte masks +/// EC has written data but host hasn't consumed it yet +const _EC_LPC_STATUS_TO_HOST: u8 = 0x01; +/// Host has written data/command but EC hasn't consumed it yet +pub const EC_LPC_STATUS_FROM_HOST: u8 = 0x02; +/// EC is still processing a command +pub const EC_LPC_STATUS_PROCESSING: u8 = 0x04; +/// Previous command wasn't data but command +const _EC_LPC_STATUS_LAST_CMD: u8 = 0x08; +/// EC is in burst mode +const _EC_LPC_STATUS_BURST_MODE: u8 = 0x10; +/// SCI event is pending (requesting SCI query) +const _EC_LPC_STATUS_SCI_PENDING: u8 = 0x20; +/// SMI event is pending (requesting SMI query) +const _EC_LPC_STATUS_SMI_PENDING: u8 = 0x40; +/// Reserved +const _EC_LPC_STATUS_RESERVED: u8 = 0x80; + +/// EC is busy +pub const EC_LPC_STATUS_BUSY_MASK: u8 = EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING; + +// I/O addresses for ACPI commands +const _EC_LPC_ADDR_ACPI_DATA: u16 = 0x62; +const _EC_LPC_ADDR_ACPI_CMD: u16 = 0x66; + +// I/O addresses for host command +pub const EC_LPC_ADDR_HOST_DATA: u16 = 0x200; +pub const EC_LPC_ADDR_HOST_CMD: u16 = 0x204; + +// I/O addresses for host command args and params +// Protocol version 2 +pub const EC_LPC_ADDR_HOST_ARGS: u16 = 0x800; /* And 0x801, 0x802, 0x803 */ +const _EC_LPC_ADDR_HOST_PARAM: u16 = 0x804; /* For version 2 params; size is + * EC_PROTO2_MAX_PARAM_SIZE */ +// Protocol version 3 +const _EC_LPC_ADDR_HOST_PACKET: u16 = 0x800; /* Offset of version 3 packet */ +pub const EC_LPC_HOST_PACKET_SIZE: u16 = 0x100; /* Max size of version 3 packet */ + +pub const MEC_MEMMAP_OFFSET: u16 = 0x100; +pub const NPC_MEMMAP_OFFSET: u16 = 0xE00; + +// The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff +// and they tell the kernel that so we have to think of it as two parts. +const _EC_HOST_CMD_REGION0: u16 = 0x800; +const _EC_HOST_CMD_REGION1: u16 = 0x8800; +const _EC_HOST_CMD_REGION_SIZE: u16 = 0x80; + +// EC command register bit functions +const _EC_LPC_CMDR_DATA: u16 = 1 << 0; // Data ready for host to read +const _EC_LPC_CMDR_PENDING: u16 = 1 << 1; // Write pending to EC +const _EC_LPC_CMDR_BUSY: u16 = 1 << 2; // EC is busy processing a command +const _EC_LPC_CMDR_CMD: u16 = 1 << 3; // Last host write was a command +const _EC_LPC_CMDR_ACPI_BRST: u16 = 1 << 4; // Burst mode (not used) +const _EC_LPC_CMDR_SCI: u16 = 1 << 5; // SCI event is pending +const _EC_LPC_CMDR_SMI: u16 = 1 << 6; // SMI event is pending + +pub const EC_HOST_REQUEST_VERSION: u8 = 3; + +/// Request header of version 3 +#[repr(C, packed)] +pub struct EcHostRequest { + /// Version of this request structure (must be 3) + pub struct_version: u8, + + /// Checksum of entire request (header and data) + /// Everything added together adds up to 0 (wrapping around u8 limit) + pub checksum: u8, + + /// Command number + pub command: u16, + + /// Command version, usually 0 + pub command_version: u8, + + /// Reserved byte in protocol v3. Must be 0 + pub reserved: u8, + + /// Data length. Data is immediately after the header + pub data_len: u16, +} + +pub const EC_HOST_RESPONSE_VERSION: u8 = 3; + +/// Response header of version 3 +#[repr(C, packed)] +pub struct EcHostResponse { + /// Version of this request structure (must be 3) + pub struct_version: u8, + + /// Checksum of entire request (header and data) + pub checksum: u8, + + /// Status code of response. See enum _EcStatus + pub result: u16, + + /// Data length. Data is immediately after the header + pub data_len: u16, + + /// Reserved byte in protocol v3. Must be 0 + pub reserved: u16, +} +pub const HEADER_LEN: usize = std::mem::size_of::(); diff --git a/framework_lib/src/chromium_ec/windows.rs b/framework_lib/src/chromium_ec/windows.rs index 6cd2db33..5b0cca68 100644 --- a/framework_lib/src/chromium_ec/windows.rs +++ b/framework_lib/src/chromium_ec/windows.rs @@ -11,7 +11,7 @@ use windows::{ }, }; -use crate::chromium_ec::portio::HEADER_LEN; +use crate::chromium_ec::protocol::HEADER_LEN; use crate::chromium_ec::EC_MEMMAP_SIZE; use crate::chromium_ec::{EcError, EcResponseStatus, EcResult}; diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 88fd1e61..786e4ed6 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -42,7 +42,7 @@ use crate::chromium_ec::commands::TabletModeOverride; use crate::chromium_ec::EcResponseStatus; use crate::chromium_ec::{print_err, EcFlashType}; use crate::chromium_ec::{EcError, EcResult}; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use crate::csme; use crate::ec_binary; use crate::esrt; @@ -54,7 +54,7 @@ use crate::smbios::ConfigDigit0; use crate::smbios::{dmidecode_string_val, get_smbios, is_framework}; #[cfg(feature = "hidapi")] use crate::touchpad::print_touchpad_fw_ver; -#[cfg(any(feature = "hidapi", feature = "windows"))] +#[cfg(feature = "hidapi")] use crate::touchscreen; #[cfg(feature = "uefi")] use crate::uefi::enable_page_break; @@ -483,7 +483,7 @@ fn print_versions(ec: &CrosEc) { } } - #[cfg(feature = "linux")] + #[cfg(target_os = "linux")] { println!("CSME"); if let Ok(csme) = csme::csme_from_sysfs() { @@ -821,7 +821,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { }; ec.set_tablet_mode(mode); } else if let Some(_enable) = &args.touchscreen_enable { - #[cfg(any(feature = "hidapi", feature = "windows"))] + #[cfg(feature = "hidapi")] if touchscreen::enable_touch(*_enable).is_none() { error!("Failed to enable/disable touch"); } @@ -1151,11 +1151,11 @@ fn hash(data: &[u8]) { println!("Hashes"); print!(" SHA256: "); - util::print_buffer_short(sha256); + util::print_buffer(sha256); print!(" SHA384: "); - util::print_buffer_short(sha384); + util::print_buffer(sha384); print!(" SHA512: "); - util::print_buffer_short(sha512); + util::print_buffer(sha512); } fn selftest(ec: &CrosEc) -> Option<()> { diff --git a/framework_lib/src/csme.rs b/framework_lib/src/csme.rs index 610560a2..5bd6c9eb 100644 --- a/framework_lib/src/csme.rs +++ b/framework_lib/src/csme.rs @@ -3,11 +3,11 @@ //! Currently only works on Linux (from sysfs). use core::fmt; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::fs; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::io; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::path::Path; pub struct CsmeInfo { @@ -85,7 +85,7 @@ impl fmt::Display for CsmeVersion { } } -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] pub fn csme_from_sysfs() -> io::Result { let dir = Path::new("/sys/class/mei"); let mut csme_info: Option = None; diff --git a/framework_lib/src/esrt/mod.rs b/framework_lib/src/esrt/mod.rs index feb98a2a..16770df5 100644 --- a/framework_lib/src/esrt/mod.rs +++ b/framework_lib/src/esrt/mod.rs @@ -22,11 +22,11 @@ use guid_macros::guid; #[cfg(feature = "uefi")] use uefi::{guid, Guid}; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::fs; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::io; -#[cfg(feature = "linux")] +#[cfg(target_os = "linux")] use std::path::Path; #[cfg(target_os = "freebsd")] @@ -262,7 +262,7 @@ pub fn print_esrt(esrt: &Esrt) { } } -#[cfg(all(not(feature = "uefi"), feature = "std", feature = "linux"))] +#[cfg(target_os = "linux")] /// On Linux read the ESRT table from the sysfs /// resource_version and resource_count_max are reported by sysfs, so they're defaulted to reaesonable values /// capsule_flags in sysfs seems to be 0 always. Not sure why. @@ -323,7 +323,7 @@ fn esrt_from_sysfs(dir: &Path) -> io::Result { Ok(esrt_table) } -#[cfg(all(not(feature = "uefi"), feature = "linux", target_os = "linux"))] +#[cfg(target_os = "linux")] pub fn get_esrt() -> Option { let res = esrt_from_sysfs(Path::new("/sys/firmware/efi/esrt/entries")).ok(); if res.is_none() { @@ -332,7 +332,7 @@ pub fn get_esrt() -> Option { res } -#[cfg(all(not(feature = "uefi"), feature = "windows"))] +#[cfg(all(not(feature = "uefi"), windows))] pub fn get_esrt() -> Option { let mut esrt_table = Esrt { resource_count: 0, diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index a237326a..661f9e14 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -20,9 +20,9 @@ pub mod camera; pub mod inputmodule; #[cfg(feature = "hidapi")] pub mod touchpad; -#[cfg(any(feature = "hidapi", feature = "windows"))] +#[cfg(feature = "hidapi")] pub mod touchscreen; -#[cfg(feature = "windows")] +#[cfg(all(feature = "hidapi", windows))] pub mod touchscreen_win; #[cfg(feature = "uefi")] diff --git a/framework_lib/src/touchscreen.rs b/framework_lib/src/touchscreen.rs index b06965a7..256df139 100644 --- a/framework_lib/src/touchscreen.rs +++ b/framework_lib/src/touchscreen.rs @@ -1,6 +1,6 @@ use hidapi::{HidApi, HidDevice}; -#[cfg(target_os = "windows")] +#[cfg(windows)] use crate::touchscreen_win; pub const ILI_VID: u16 = 0x222A; diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 972d82a3..4f34a18e 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -157,7 +157,7 @@ pub unsafe fn any_vec_as_u8_slice(p: &[T]) -> &[u8] { /// Print a byte buffer as a series of hex bytes pub fn print_buffer(buffer: &[u8]) { for byte in buffer { - print!("{:#X} ", byte); + print!("{:02x}", byte); } println!(); } @@ -232,15 +232,8 @@ pub fn find_sequence(haystack: &[u8], needle: &[u8]) -> Option { /// Assert length of an EC response from the windows driver /// It's always 20 more than expected. TODO: Figure out why pub fn assert_win_len(left: N, right: N) { - #[cfg(feature = "win_driver")] + #[cfg(windows)] assert_eq!(left, right + NumCast::from(20).unwrap()); - #[cfg(not(feature = "win_driver"))] + #[cfg(not(windows))] assert_eq!(left, right); } - -pub fn print_buffer_short(buffer: &[u8]) { - for byte in buffer { - print!("{:02x}", byte); - } - println!(); -} diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index ecef1fb0..da69ded0 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -3,15 +3,8 @@ name = "framework_tool" version = "0.4.0" edition = "2021" -[features] -default = ["linux"] -linux = ["framework_lib/linux"] -freebsd = ["framework_lib/freebsd"] -windows = ["framework_lib/windows"] - [dependencies.framework_lib] path = "../framework_lib" -default-features = false [build-dependencies] # Note: Only takes effect in release builds From 1117009119ac3205810f9f3752fd2a381a37e3b3 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 5 May 2025 09:47:45 +0800 Subject: [PATCH 10/27] --version: Add revision of mainboard ``` > framework_tool.exe --versions Mainboard Hardware Type: Laptop 13 (AMD Ryzen AI 300 Series) Revision: MassProduction [...] ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/commandline/mod.rs | 13 ++++++++++ framework_lib/src/smbios.rs | 36 +++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 88fd1e61..97bf7f7d 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -350,12 +350,25 @@ fn print_stylus_battery_level() { } fn print_versions(ec: &CrosEc) { + println!("Mainboard Hardware"); + if let Some(ver) = smbios::get_product_name() { + println!(" Type: {}", ver); + } else { + println!(" Type: Unknown"); + } + if let Some(ver) = smbios::get_baseboard_version() { + println!(" Revision: {:?}", ver); + } else { + println!(" Revision: Unknown"); + } println!("UEFI BIOS"); if let Some(smbios) = get_smbios() { let bios_entries = smbios.collect::(); let bios = bios_entries.first().unwrap(); println!(" Version: {}", bios.version()); println!(" Release Date: {}", bios.release_date()); + } else { + println!(" Version: Unknown"); } println!("EC Firmware"); diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 1345b396..5e713513 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -8,6 +8,7 @@ use std::io::ErrorKind; use crate::util::Config; pub use crate::util::Platform; use num_derive::FromPrimitive; +use num_traits::FromPrimitive; use smbioslib::*; #[cfg(feature = "uefi")] use spin::Mutex; @@ -215,7 +216,7 @@ pub fn get_smbios() -> Option { } } -fn get_product_name() -> Option { +pub fn get_product_name() -> Option { // On FreeBSD we can short-circuit and avoid parsing SMBIOS #[cfg(target_os = "freebsd")] if let Ok(product) = kenv_get("smbios.system.product") { @@ -225,6 +226,7 @@ fn get_product_name() -> Option { let smbios = get_smbios(); if smbios.is_none() { println!("Failed to find SMBIOS"); + return None; } let mut smbios = smbios.into_iter().flatten(); smbios.find_map(|undefined_struct| { @@ -237,6 +239,38 @@ fn get_product_name() -> Option { }) } +pub fn get_baseboard_version() -> Option { + // TODO: On FreeBSD we can short-circuit and avoid parsing SMBIOS + // #[cfg(target_os = "freebsd")] + // if let Ok(product) = kenv_get("smbios.system.product") { + // return Some(product); + // } + + let smbios = get_smbios(); + if smbios.is_none() { + error!("Failed to find SMBIOS"); + return None; + } + let mut smbios = smbios.into_iter().flatten(); + smbios.find_map(|undefined_struct| { + if let DefinedStruct::BaseBoardInformation(data) = undefined_struct.defined_struct() { + if let Some(version) = dmidecode_string_val(&data.version()) { + // Assumes it's ASCII, which is guaranteed by SMBIOS + let config_digit0 = &version[0..1]; + let config_digit0 = u8::from_str_radix(config_digit0, 16); + if let Ok(version_config) = + config_digit0.map(::from_u8) + { + return version_config; + } else { + error!(" Invalid BaseBoard Version: {}'", version); + } + } + } + None + }) +} + pub fn get_platform() -> Option { #[cfg(feature = "uefi")] let mut cached_platform = CACHED_PLATFORM.lock(); From 6531f1c1fea08419307cb63b1d56f9995e880d90 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 5 May 2025 10:46:01 +0800 Subject: [PATCH 11/27] uefi: Don't need sha2/force-soft anymore Linking doesn't fail anymore for UEFI builds. Signed-off-by: Daniel Schaefer --- framework_lib/Cargo.toml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 21d57035..849ef663 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -12,13 +12,7 @@ default = ["std"] std = ["hidapi", "rusb"] rusb = ["dep:rusb"] hidapi = ["dep:hidapi"] -uefi = [ - "lazy_static/spin_no_std", - # Otherwise I get: `LLVM ERROR: Do not know how to split the result of this operator!` - # Seems to be a Ruset/LLVM bug when SSE is enabled. - # See: https://github.com/rust-lang/rust/issues/61721 - "sha2/force-soft" -] +uefi = [ "lazy_static/spin_no_std" ] [build-dependencies] built = { version = "0.5", features = ["chrono", "git2"] } From f73981d9c1716a6cd5d2cf332cbc87ed177e3308 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 5 May 2025 10:55:12 +0800 Subject: [PATCH 12/27] Remove std feature There's no need for it, the only no_std environment is UEFI and it's unlikely there'll be another one. Maybe we could rename uefi to no_std in the future, but right now it makes no sense to duplicate it. Signed-off-by: Daniel Schaefer --- framework_lib/Cargo.toml | 3 +-- framework_lib/src/capsule.rs | 6 +++--- framework_lib/src/commandline/mod.rs | 4 ++-- framework_lib/src/util.rs | 22 +++++++++++----------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 849ef663..84355995 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -8,8 +8,7 @@ rust-version = "1.74" build = "build.rs" [features] -default = ["std"] -std = ["hidapi", "rusb"] +default = ["hidapi", "rusb"] rusb = ["dep:rusb"] hidapi = ["dep:hidapi"] uefi = [ "lazy_static/spin_no_std" ] diff --git a/framework_lib/src/capsule.rs b/framework_lib/src/capsule.rs index 9e6a35bc..971db631 100644 --- a/framework_lib/src/capsule.rs +++ b/framework_lib/src/capsule.rs @@ -11,9 +11,9 @@ use std::prelude::v1::*; use core::prelude::rust_2021::derive; -#[cfg(all(not(feature = "uefi"), feature = "std"))] +#[cfg(not(feature = "uefi"))] use std::fs::File; -#[cfg(all(not(feature = "uefi"), feature = "std"))] +#[cfg(not(feature = "uefi"))] use std::io::prelude::*; #[cfg(not(feature = "uefi"))] @@ -180,7 +180,7 @@ pub fn dump_winux_image(data: &[u8], header: &DisplayCapsule, filename: &str) { let image = &data[header_len..image_size]; - #[cfg(all(not(feature = "uefi"), feature = "std"))] + #[cfg(not(feature = "uefi"))] { let mut file = File::create(filename).unwrap(); file.write_all(image).unwrap(); diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 786e4ed6..f3c56eba 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -17,7 +17,7 @@ pub mod uefi; #[cfg(not(feature = "uefi"))] use std::fs; -#[cfg(all(not(feature = "uefi"), feature = "std"))] +#[cfg(not(feature = "uefi"))] use std::io::prelude::*; #[cfg(feature = "rusb")] @@ -553,7 +553,7 @@ fn flash_ec(ec: &CrosEc, ec_bin_path: &str, flash_type: EcFlashType) { fn dump_ec_flash(ec: &CrosEc, dump_path: &str) { let flash_bin = ec.get_entire_ec_flash().unwrap(); - #[cfg(all(not(feature = "uefi"), feature = "std"))] + #[cfg(not(feature = "uefi"))] { let mut file = fs::File::create(dump_path).unwrap(); file.write_all(&flash_bin).unwrap(); diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 4f34a18e..15444913 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -6,11 +6,11 @@ use std::prelude::v1::*; #[cfg(feature = "uefi")] use core::prelude::rust_2021::derive; -#[cfg(not(feature = "std"))] +#[cfg(feature = "uefi")] use alloc::sync::Arc; -#[cfg(not(feature = "std"))] +#[cfg(feature = "uefi")] use spin::{Mutex, MutexGuard}; -#[cfg(feature = "std")] +#[cfg(not(feature = "uefi"))] use std::sync::{Arc, Mutex, MutexGuard}; use crate::smbios; @@ -74,9 +74,9 @@ pub struct Config { impl Config { pub fn set(platform: Platform) { - #[cfg(feature = "std")] + #[cfg(not(feature = "uefi"))] let mut config = CONFIG.lock().unwrap(); - #[cfg(not(feature = "std"))] + #[cfg(feature = "uefi")] let mut config = CONFIG.lock(); if (*config).is_none() { @@ -87,9 +87,9 @@ impl Config { } } pub fn is_set() -> bool { - #[cfg(feature = "std")] + #[cfg(not(feature = "uefi"))] let config = CONFIG.lock().unwrap(); - #[cfg(not(feature = "std"))] + #[cfg(feature = "uefi")] let config = CONFIG.lock(); (*config).is_some() @@ -98,9 +98,9 @@ impl Config { pub fn get() -> MutexGuard<'static, Option> { trace!("Config::get() entry"); let unset = { - #[cfg(feature = "std")] + #[cfg(not(feature = "uefi"))] let config = CONFIG.lock().unwrap(); - #[cfg(not(feature = "std"))] + #[cfg(feature = "uefi")] let config = CONFIG.lock(); (*config).is_none() }; @@ -115,9 +115,9 @@ impl Config { None }; - #[cfg(feature = "std")] + #[cfg(not(feature = "uefi"))] let mut config = CONFIG.lock().unwrap(); - #[cfg(not(feature = "std"))] + #[cfg(feature = "uefi")] let mut config = CONFIG.lock(); if new_config.is_some() { From 96b7fcce39b4dfefbf401139bc3bf13568cf1ab4 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 5 May 2025 11:42:54 +0800 Subject: [PATCH 13/27] Don't require PD config if platform isn't detected Now even if the platform isn't detected, we can run the commands just fine. For example both of these work (if I comment out the smbios entry): ``` framework_tool --versions framework_tool --versions --pd-ports 1 2 --pd-addrs 66 64 ``` The first one just fails accessing I2C passthrough for the PD ports. This is the final change to allow just running the tool on any system in as many cases as possible - even if the linux kernel or framework_tool dose not recognize the system. Signed-off-by: Daniel Schaefer --- framework_lib/src/ccgx/device.rs | 24 +++++++++++++----------- framework_lib/src/smbios.rs | 9 ++++++--- framework_lib/src/util.rs | 2 ++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index 3163f082..532ad10e 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -30,11 +30,11 @@ pub enum PdPort { impl PdPort { /// SMBUS/I2C Address - fn i2c_address(&self) -> u16 { + fn i2c_address(&self) -> EcResult { let config = Config::get(); let platform = &(*config).as_ref().unwrap().platform; - match (platform, self) { + Ok(match (platform, self) { (Platform::GenericFramework((left, _), _), PdPort::Left01) => *left, (Platform::GenericFramework((_, right), _), PdPort::Right23) => *right, // Framework AMD Platforms (CCG8) @@ -52,10 +52,13 @@ impl PdPort { ) => 0x40, // TODO: It only has a single PD controller (Platform::FrameworkDesktopAmdAiMax300, _) => 0x08, + (Platform::UnknownSystem, _) => { + Err(EcError::DeviceError("Unsupported platform".to_string()))? + } // Framework Intel Platforms (CCG5 and CCG6) (_, PdPort::Left01) => 0x08, (_, PdPort::Right23) => 0x40, - } + }) } /// I2C port on the EC @@ -87,10 +90,9 @@ impl PdPort { ) => 2, // TODO: It only has a single PD controller (Platform::FrameworkDesktopAmdAiMax300, _) => 1, - // (_, _) => Err(EcError::DeviceError(format!( - // "Unsupported platform: {:?} {:?}", - // platform, self - // )))?, + (Platform::UnknownSystem, _) => { + Err(EcError::DeviceError("Unsupported platform".to_string()))? + } }) } } @@ -140,13 +142,13 @@ impl PdController { fn i2c_read(&self, addr: u16, len: u16) -> EcResult { trace!( "I2C passthrough from I2C Port {} to I2C Addr {}", - self.port.i2c_port().unwrap(), - self.port.i2c_address() + self.port.i2c_port()?, + self.port.i2c_address()? ); i2c_read( &self.ec, - self.port.i2c_port().unwrap(), - self.port.i2c_address(), + self.port.i2c_port()?, + self.port.i2c_address()?, addr, len, ) diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 1345b396..83190bd4 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -46,7 +46,7 @@ pub enum ConfigDigit0 { pub fn is_framework() -> bool { if matches!( get_platform(), - Some(Platform::GenericFramework((_, _), (_, _))) + Some(Platform::GenericFramework((_, _), (_, _))) | Some(Platform::UnknownSystem) ) { return true; } @@ -252,7 +252,10 @@ pub fn get_platform() -> Option { // Except if it's a GenericFramework platform let config = Config::get(); let platform = &(*config).as_ref().unwrap().platform; - if matches!(platform, Platform::GenericFramework((_, _), (_, _))) { + if matches!( + platform, + Platform::GenericFramework((_, _), (_, _)) | Platform::UnknownSystem + ) { return Some(*platform); } } @@ -270,7 +273,7 @@ pub fn get_platform() -> Option { "Laptop 13 (Intel Core Ultra Series 1)" => Some(Platform::IntelCoreUltra1), "Laptop 16 (AMD Ryzen 7040 Series)" => Some(Platform::Framework16Amd7080), "Desktop (AMD Ryzen AI Max 300 Series)" => Some(Platform::FrameworkDesktopAmdAiMax300), - _ => None, + _ => Some(Platform::UnknownSystem), }; if let Some(platform) = platform { diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 972d82a3..1aeb765e 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -38,6 +38,7 @@ pub enum Platform { /// Generic Framework device /// pd_addrs, pd_ports GenericFramework((u16, u16), (u8, u8)), + UnknownSystem, } #[derive(Debug, PartialEq, Clone, Copy)] @@ -61,6 +62,7 @@ impl Platform { Platform::Framework16Amd7080 => Some(PlatformFamily::Framework16), Platform::FrameworkDesktopAmdAiMax300 => Some(PlatformFamily::FrameworkDesktop), Platform::GenericFramework(..) => None, + Platform::UnknownSystem => None, } } } From 6d7afb404d2e79b626b7be162446d4f9c5938e4a Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 5 May 2025 13:49:43 +0800 Subject: [PATCH 14/27] --inputdeck: Fix Chassis Closed status Fixes: 49eb0b914ee2f11124614ba6d3f3259adf199fac That commit reversed the wording but not the variable. Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 5e60b148..87d45b13 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -510,7 +510,7 @@ impl CrosEc { let is_present = |p| if p { "Present" } else { "Missing" }; println!("Input Deck"); - println!(" Chassis Closed: {}", intrusion.currently_open); + println!(" Chassis Closed: {}", !intrusion.currently_open); println!(" Power Button Board: {}", is_present(pwrbtn.is_some())); println!(" Audio Daughterboard: {}", is_present(audio.is_some())); println!(" Touchpad: {}", is_present(tp.is_some())); @@ -538,7 +538,7 @@ impl CrosEc { let is_present = |p| if p { "Present" } else { "Missing" }; println!("Input Deck"); - println!(" Chassis Closed: {}", intrusion.currently_open); + println!(" Chassis Closed: {}", !intrusion.currently_open); println!(" Audio Daughterboard: {}", is_present(audio.is_some())); println!(" Touchpad: {}", is_present(tp.is_some())); @@ -548,7 +548,7 @@ impl CrosEc { pub fn print_fw16_inputdeck_status(&self) -> EcResult<()> { let intrusion = self.get_intrusion_status()?; let status = self.get_input_deck_status()?; - println!("Chassis Closed: {}", intrusion.currently_open); + println!("Chassis Closed: {}", !intrusion.currently_open); println!("Input Deck State: {:?}", status.state); println!("Touchpad present: {}", status.touchpad_present); println!("Positions:"); From d111ee5aa170906448b24c83cb682e9bc338b2e6 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 6 May 2025 17:50:08 +0800 Subject: [PATCH 15/27] windows: Run --versions command if double-clicked Signed-off-by: Daniel Schaefer --- Cargo.lock | 1 + framework_tool/Cargo.toml | 6 ++++++ framework_tool/src/main.rs | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 465dc6e0..3ee80253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,6 +424,7 @@ version = "0.4.0" dependencies = [ "framework_lib", "static_vcruntime", + "winapi", ] [[package]] diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index da69ded0..bc30ab61 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -9,3 +9,9 @@ path = "../framework_lib" [build-dependencies] # Note: Only takes effect in release builds static_vcruntime = "2.0" + +[target.'cfg(windows)'.dependencies.winapi] +version = "0.3.9" +features = [ + "wincon" +] diff --git a/framework_tool/src/main.rs b/framework_tool/src/main.rs index 3a4d54a4..251f85f4 100644 --- a/framework_tool/src/main.rs +++ b/framework_tool/src/main.rs @@ -6,9 +6,42 @@ fn get_args() -> Vec { } fn main() -> Result<(), &'static str> { - let args = commandline::parse(&get_args()); + let args = get_args(); + + // If the user double-clicks (opens from explorer/desktop), + // then we want to have the default behavior of showing a report of + // all firmware versions. + #[cfg(windows)] + let (args, double_clicked) = { + let double_clicked = unsafe { + // See https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922 + let mut plist: winapi::shared::minwindef::DWORD = 0; + let processes = winapi::um::wincon::GetConsoleProcessList(&mut plist, 1); + processes == 1 + }; + if double_clicked { + ( + vec![args[0].clone(), "--versions".to_string()], + double_clicked, + ) + } else { + (args, double_clicked) + } + }; + + let args = commandline::parse(&args); if (commandline::run_with_args(&args, false)) != 0 { return Err("Fail"); } + + // Prevent command prompt from auto closing + #[cfg(windows)] + if double_clicked { + println!(); + println!("Press ENTER to exit..."); + let mut line = String::new(); + let _ = std::io::stdin().read_line(&mut line).unwrap(); + } + Ok(()) } From 7336362ac1b22f945226168ad903c83bee279b82 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 6 May 2025 05:47:04 -0700 Subject: [PATCH 16/27] windows: Embed resource to always launch as admin Only in release builds, because running `cargo run` from non-admin terminal won't work with the resources. Signed-off-by: Daniel Schaefer --- Cargo.lock | 128 ++++++++++++++++++++- framework_tool/Cargo.toml | 1 + framework_tool/build.rs | 10 +- framework_tool/framework_tool-manifest.rc | 2 + framework_tool/framework_tool.exe.manifest | 10 ++ 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 framework_tool/framework_tool-manifest.rc create mode 100644 framework_tool/framework_tool.exe.manifest diff --git a/Cargo.lock b/Cargo.lock index 3ee80253..fb0f76b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,7 +127,7 @@ checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" dependencies = [ "semver", "serde", - "toml", + "toml 0.5.11", "url", ] @@ -354,6 +354,20 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "embed-resource" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.8.22", + "vswhom", + "winreg", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -377,6 +391,12 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -422,6 +442,7 @@ dependencies = [ name = "framework_tool" version = "0.4.0" dependencies = [ + "embed-resource", "framework_lib", "static_vcruntime", "winapi", @@ -567,6 +588,12 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + [[package]] name = "heck" version = "0.5.0" @@ -626,6 +653,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "io-kit-sys" version = "0.1.0" @@ -1070,6 +1107,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1208,6 +1254,47 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "typenum" version = "1.16.0" @@ -1313,6 +1400,26 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "wasm-bindgen" version = "0.2.84" @@ -1673,6 +1780,25 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wmi" version = "0.15.0" diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index bc30ab61..598d00c0 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -9,6 +9,7 @@ path = "../framework_lib" [build-dependencies] # Note: Only takes effect in release builds static_vcruntime = "2.0" +embed-resource = "3.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3.9" diff --git a/framework_tool/build.rs b/framework_tool/build.rs index 20e1c8e9..de98f1f6 100644 --- a/framework_tool/build.rs +++ b/framework_tool/build.rs @@ -1,3 +1,11 @@ fn main() { - static_vcruntime::metabuild(); + if !cfg!(debug_assertions) { + // Statically link vcruntime to allow running on clean install + static_vcruntime::metabuild(); + + // Embed resources file to force running as admin + embed_resource::compile("framework_tool-manifest.rc", embed_resource::NONE) + .manifest_optional() + .unwrap(); + } } diff --git a/framework_tool/framework_tool-manifest.rc b/framework_tool/framework_tool-manifest.rc new file mode 100644 index 00000000..68429585 --- /dev/null +++ b/framework_tool/framework_tool-manifest.rc @@ -0,0 +1,2 @@ +#define RT_MANIFEST 24 +1 RT_MANIFEST "framework_tool.exe.manifest" diff --git a/framework_tool/framework_tool.exe.manifest b/framework_tool/framework_tool.exe.manifest new file mode 100644 index 00000000..287bba26 --- /dev/null +++ b/framework_tool/framework_tool.exe.manifest @@ -0,0 +1,10 @@ + + + + + + + + + + From e1e57c922d830f84bc23938d5ba8c2419312316b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 01:11:24 +0800 Subject: [PATCH 17/27] Bump version to 0.4.1 Signed-off-by: Daniel Schaefer --- Cargo.lock | 6 +++--- framework_lib/Cargo.toml | 2 +- framework_tool/Cargo.toml | 2 +- framework_uefi/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 465dc6e0..01316989 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ [[package]] name = "framework_lib" -version = "0.4.0" +version = "0.4.1" dependencies = [ "built", "clap", @@ -420,7 +420,7 @@ dependencies = [ [[package]] name = "framework_tool" -version = "0.4.0" +version = "0.4.1" dependencies = [ "framework_lib", "static_vcruntime", @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "framework_uefi" -version = "0.4.0" +version = "0.4.1" dependencies = [ "framework_lib", "log", diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 84355995..f0477678 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_lib" -version = "0.4.0" +version = "0.4.1" edition = "2021" # Minimum Supported Rust Version # Ubuntu 24.04 LTS ships 1.75 diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index da69ded0..e9b3422b 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_tool" -version = "0.4.0" +version = "0.4.1" edition = "2021" [dependencies.framework_lib] diff --git a/framework_uefi/Cargo.toml b/framework_uefi/Cargo.toml index 13d6e0b5..d0ad0cc4 100644 --- a/framework_uefi/Cargo.toml +++ b/framework_uefi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_uefi" -version = "0.4.0" +version = "0.4.1" edition = "2021" # Minimum Supported Rust Version rust-version = "1.74" From 079af34d4b4d995ac9e0d78921f5f6201fdd3421 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 10:59:37 +0800 Subject: [PATCH 18/27] windows: Don't run --versions if any arguments provided Should always try to run as admin in release builds. But only autorun --versions if no arguments provided. Tested: - [x] Release Build with args - [x] Run from powershell - [x] Run from powershell with sudo "In new window" - [x] Run from powershell with sudo "With input disabled" - [x] Doubleclick from Explorer - This is impossible - [x] Release Build without args - [x] Run from powershell - This case autoruns --versions when it shouldn't - [x] Run from powershell with sudo "In new window" - This case autoruns --versions when it shouldn't - [x] Run from powershell with sudo "With input disabled" - [x] Doubleclick from Explorer - [x] Debug Build with args - [x] Run from powershell - [x] Run from powershell with sudo "In new window" - [x] Run from powershell with sudo "With input disabled" - [x] Doubleclick from Explorer - This is impossible - [x] Debug Build without args - [x] Run from powershell - [x] Run from powershell with sudo "In new window" - This case autoruns --versions when it shouldn't - [x] Run from powershell with sudo "With input disabled" - [x] Doubleclick from Explorer Signed-off-by: Daniel Schaefer --- framework_tool/src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/framework_tool/src/main.rs b/framework_tool/src/main.rs index 251f85f4..d755aa77 100644 --- a/framework_tool/src/main.rs +++ b/framework_tool/src/main.rs @@ -17,9 +17,16 @@ fn main() -> Result<(), &'static str> { // See https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922 let mut plist: winapi::shared::minwindef::DWORD = 0; let processes = winapi::um::wincon::GetConsoleProcessList(&mut plist, 1); + + // If we're the only process that means we're in a fresh terminal + // without CMD or powershell. This happens in some cases, for example + // if the user double-clicks the app from Explorer. processes == 1 }; - if double_clicked { + // But it also happens if launched from the commandline and a UAC prompt is necessary, + // for example with sudo set to open "In a new windows", therefore we also have to + // check that no commandline arguments were provided. + if double_clicked && args.len() == 1 { ( vec![args[0].clone(), "--versions".to_string()], double_clicked, From c49ad0c15a3f4757ba7ffecec763e66b63479696 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 13:49:50 +0800 Subject: [PATCH 19/27] --thermal: Add Framework 12 charger IC temp ``` > sudo framework_tool --thermal F75303_CPU: 35 C F75303_Skin: 33 C F75303_Local: 33 C Battery: 33 C PECI: 51 C Charger IC 32 C Fan Speed: 0 RPM ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index bb3e9ea4..266d4f07 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -340,6 +340,7 @@ pub fn print_thermal(ec: &CrosEc) { println!(" F75303_Local: {:>4}", TempSensor::from(temps[2])); println!(" Battery: {:>4}", TempSensor::from(temps[3])); println!(" PECI: {:>4}", TempSensor::from(temps[4])); + println!(" Charger IC {:>4}", TempSensor::from(temps[5])); } Some( From 8a6249fa2e7a2f38406af27738cb5f1b683f06c9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 13:59:20 +0800 Subject: [PATCH 20/27] --thermal: Print sensors we don't know about, if present Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 266d4f07..4868ba24 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -76,7 +76,7 @@ const EC_FAN_SPEED_ENTRIES: usize = 4; const EC_FAN_SPEED_STALLED_DEPRECATED: u16 = 0xFFFE; const EC_FAN_SPEED_NOT_PRESENT: u16 = 0xFFFF; -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum TempSensor { Ok(u8), NotPresent, @@ -311,7 +311,7 @@ pub fn print_thermal(ec: &CrosEc) { let fans = ec.read_memory(EC_MEMMAP_FAN, 0x08).unwrap(); let platform = smbios::get_platform(); - match platform { + let remaining_sensors = match platform { Some(Platform::IntelGen11) | Some(Platform::IntelGen12) | Some(Platform::IntelGen13) => { println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); println!(" F75303_CPU: {:>4}", TempSensor::from(temps[1])); @@ -324,6 +324,7 @@ pub fn print_thermal(ec: &CrosEc) { ) { println!(" F57397_VCCGT: {:>4}", TempSensor::from(temps[5])); } + 2 } Some(Platform::IntelCoreUltra1) => { @@ -332,6 +333,7 @@ pub fn print_thermal(ec: &CrosEc) { println!(" Battery: {:>4}", TempSensor::from(temps[2])); println!(" F75303_DDR: {:>4}", TempSensor::from(temps[3])); println!(" PECI: {:>4}", TempSensor::from(temps[4])); + 3 } Some(Platform::Framework12IntelGen13) => { @@ -341,6 +343,7 @@ pub fn print_thermal(ec: &CrosEc) { println!(" Battery: {:>4}", TempSensor::from(temps[3])); println!(" PECI: {:>4}", TempSensor::from(temps[4])); println!(" Charger IC {:>4}", TempSensor::from(temps[5])); + 2 } Some( @@ -357,6 +360,9 @@ pub fn print_thermal(ec: &CrosEc) { println!(" dGPU VRAM: {:>4}", TempSensor::from(temps[5])); println!(" dGPU AMB: {:>4}", TempSensor::from(temps[6])); println!(" dGPU temp: {:>4}", TempSensor::from(temps[7])); + 0 + } else { + 4 } } @@ -365,6 +371,7 @@ pub fn print_thermal(ec: &CrosEc) { println!(" F75303_DDR: {:>4}", TempSensor::from(temps[1])); println!(" F75303_AMB: {:>4}", TempSensor::from(temps[2])); println!(" APU: {:>4}", TempSensor::from(temps[3])); + 4 } _ => { @@ -376,6 +383,15 @@ pub fn print_thermal(ec: &CrosEc) { println!(" Temp 5: {:>4}", TempSensor::from(temps[5])); println!(" Temp 6: {:>4}", TempSensor::from(temps[6])); println!(" Temp 7: {:>4}", TempSensor::from(temps[7])); + 0 + } + }; + + // Just in case EC has more sensors than we know about, print them + for (i, temp) in temps.iter().enumerate().take(8).skip(8 - remaining_sensors) { + let temp = TempSensor::from(*temp); + if temp != TempSensor::NotPresent { + println!(" Temp {}: {:>4}", i, temp); } } From b80e2cba6e783550d342670a4aa51eed12232da1 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 14:15:17 +0800 Subject: [PATCH 21/27] --thermal: Align RPM with C ``` sudo framework_tool --thermal F75303_CPU: 36 C F75303_Skin: 34 C F75303_Local: 33 C Battery: 31 C PECI: 53 C Charger IC 30 C Fan Speed: 0 RPM ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 4868ba24..df0d8031 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -398,11 +398,11 @@ pub fn print_thermal(ec: &CrosEc) { for i in 0..EC_FAN_SPEED_ENTRIES { let fan = u16::from_le_bytes([fans[i * 2], fans[1 + i * 2]]); if fan == EC_FAN_SPEED_STALLED_DEPRECATED { - println!(" Fan Speed: {:>4} RPM (Stalled)", fan); + println!(" Fan Speed: {:>4} RPM (Stalled)", fan); } else if fan == EC_FAN_SPEED_NOT_PRESENT { info!(" Fan Speed: Not present"); } else { - println!(" Fan Speed: {:>4} RPM", fan); + println!(" Fan Speed: {:>4} RPM", fan); } } } From 4056948f290885ae577f651b0d850973a6dcfd51 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 17 Jul 2024 17:18:09 +0800 Subject: [PATCH 22/27] windows: Add app icon Signed-off-by: Daniel Schaefer --- Cargo.lock | 11 +++++++++++ framework_tool/Cargo.toml | 1 + framework_tool/build.rs | 8 ++++++++ res/framework_startmenuicon.ico | Bin 0 -> 89962 bytes 4 files changed, 20 insertions(+) create mode 100644 res/framework_startmenuicon.ico diff --git a/Cargo.lock b/Cargo.lock index fb0f76b6..86d1a77c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,6 +446,7 @@ dependencies = [ "framework_lib", "static_vcruntime", "winapi", + "winresource", ] [[package]] @@ -1799,6 +1800,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winresource" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4a67c78ee5782c0c1cb41bebc7e12c6e79644daa1650ebbc1de5d5b08593f7" +dependencies = [ + "toml 0.8.22", + "version_check", +] + [[package]] name = "wmi" version = "0.15.0" diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index 598d00c0..0469dab3 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -10,6 +10,7 @@ path = "../framework_lib" # Note: Only takes effect in release builds static_vcruntime = "2.0" embed-resource = "3.0" +winresource = "0.1.17" [target.'cfg(windows)'.dependencies.winapi] version = "0.3.9" diff --git a/framework_tool/build.rs b/framework_tool/build.rs index de98f1f6..87d2140e 100644 --- a/framework_tool/build.rs +++ b/framework_tool/build.rs @@ -1,4 +1,12 @@ fn main() { + // Add app icon + if std::env::var_os("CARGO_CFG_WINDOWS").is_some() { + winresource::WindowsResource::new() + .set_icon("..\\res\\framework_startmenuicon.ico") + .compile() + .unwrap(); + } + if !cfg!(debug_assertions) { // Statically link vcruntime to allow running on clean install static_vcruntime::metabuild(); diff --git a/res/framework_startmenuicon.ico b/res/framework_startmenuicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8c6be29a6b1462e13005c3c113d81888f51b73ab GIT binary patch literal 89962 zcmeI5d5|1c9mi)$AV2{zsNAqgRE|F^K?DV&%MlI{L=g~B5>N;z$XS94f!9#4@0~C#9lWa?~UB1aj)t-Fz zWG4daAa)jb6r|-NzD@c0HP{-srp++mO7Jd-+nM(JDfT}NtOq=qiNIQjIUJ0DwAi=W z_6En-fa)`EnutQx#WK*!&a~}IIere906cXc0bK(g0co-Bber1#0o|L_@sWFS#ABdS zJJa_68}iiFJaraz)wk{y+9mC){@T4D4;#~TD27)7#k8MkcbtD7 zq{Yg`Hr;n!2EGKQg6RF1zE1;(fqCE`z=e%zI-kR)-9W#Q#`#VM?|`)U6lt5r!-XQ* zlxB-!tA1X;kouQ5g0z_UZRXtC^A zFtrB?Ykyx?g=<%uCsKBrjRXFCRje2&CuOIvyg<{q9sC@e1?B*)d(nK*89?hv^_a;3Eye*u?(eZXXpl_X-ZgP`3yFuk9ztL|d2cY_=Xl*6KuY&!%z0!-IUD|x+8SI6fVx7X2iCYT7y zLOPdf-ArEVqg8XtN!jTP9B9>kOl()*c(BC5+8o=j$thN<(}co#z^azK3dkmq}Z)BS&sn|HIyVn=f$$q6F89MTUMUl z0i-pqy-FM4*bN|SoRW^$SVx&jV>X?>^Drq6ao**~E%Lpdshr8jAA`96S$}JMcvDkG zI*@aUg_vCGzz^3d&#@546J0x%LBF2AWo=v0<8^P@uXHkw>peu#cx3sm_bQcWekF0o6j{I)4dGaXItD_D7epH3>MfnxJ2?bhbP|Vy8W$lmU2}V(zsiQ7>>6VkZptsp6e-SGZ}EalQQX`byBz~s2f+sG?g zyKx=oH2oi9<9|Unb(D0Ba;coUcqggaiRNLx2$F2e!n*{So;r)bh3uXs=1Ir?2bsFB z&+EGJadh2d!4LWNPvGzW2ttRXzaKXOlIkNX?;+&w)}cL}?EV3E{spk{969t|=Ri;0 zMc^n73*%_|Q#n`eRRg9-=RxKBWnkLgsJtb}_v4=gp-a+u>C+$@Q`6sHMZT_$(v^iY zex&u4rtM3Tr{}7kvPEDHhbP6>G*4?iKHY_>n{&)H;5}g4rX+c~zf~W>Q?>|9;&4;r z(n)!W^R%X5>o!f+b$U67%dq*o+NN!Ox7HE(PR_Ygt*BYoW{dxs zJp#ugB8+dIpUcp@am0L`!}8Q0>e4$_Opb{}T zda@INyAYcedt2KUHQdoPFt721xG(*Nj-i6-KT?2jxn`wcpY{c{2o_s zdi`d*xj&V-+E}OEj()vg!IRwxT!;8}a$$O(AEHU}cFnNGUx`kCzRD-RuC%y1U-|x(tBl*%>#~3KJnq># zAEwFO!hTr$UW3c~!KWP6l^?&dU-nZS<@QPRKI};M9_aOCHv*qPeA+d`);5i||Jjl5 zW6|r$ZUl}(ysg?vlY2LMZ*-(vYZX1&jX(|YY5BLcO*Qo+N4jr9uP3_^xE}GgY9~#u zYU*2#bU$i0q+U7^c+gR9HDB})N4hn?eIww>P6XCR>Tt6tUT#aEpU?-$rDiLrseiZFD z*RaDz?Y5GsKGr6{li3L9-5V~RH!I(BBd+LL=wd#F>?q6M{fUID@L%U(VXHQ6WBcpq z{a`FQ$2zjbzxyMW2m?Rwbd<~Eo7nE6ucv2K{xr135Ff8sK2{MPd%PuU`%cWTem;Bx z&MyY>8Zh}=V+N-I=`uwc6PXXR*21K%QCac#>6)^=ALM-1VqVlAx)RuY7wnG6zuS@z z`nz+Jfv3(Qus*wwf@m8x^<96@>r)^P8bHb6K-Vr)_J?vbcgIs_5x9ii!}yu{)V-9h zc`nuuYo5!`fbI=U`ST94b^xB*i@- zG5RAg75A5s_1S_&U>f$AeCN^k3g%xC%{d#ROx4sVvbHOtli0KcFxBVMT!-BX>Sqzm z()-cXXE0G$8cW@#2u`Kg@G-XOxwZ*^N03v5>wJp4PBy7u`wTDvi=>Jdkx2-pYIXRG91f=t{X`P{U;fYh0a@=zteBm#B(gf z@pNRCm9!?p#&c>t163cc*GWF=d4{R}R47Md>fOwnDpI^3vk(`>NB2a%JO-h$gx^?- z-QSU0cDe=!!ggZ%^I2r?TJ``X*stfKj|0>33gz9DptEeO?^}$I;-q&gpHQ}-q}Y2L z+uj0U4cPenL5lveY&z9)jKa9zfu5p1-)bjUTe6d_>s}b6@bkOv7*z0mj>W#vAKRa5 z=ZaaG<}=IIvw@zc*p5#q{}gnUoo3@e=ucjs`nx|zgCdV5>t656z-B+HS-gE+WvfZu z_sjtkK~YHcbTD`rG|RhfzOO4Yu^%CaRWKE}BF#fN515*Vkfru~U74w?FbD6F*W18s zuqm)jo1owrpgEn=9opgg)7O=~TxiT$?`rxfI0$S8vXW}`bKoan5s(hoHI$^^*HylG zd6hc2A6yM|&C(idjVB!r_60K=-^J55?Q<2l54-}Ba#%#3udDLps)+T|%qCw~zOI_p zMi#!WD_>Vx>ZjSUzOH;-HLHy*d|y|-uCmlmvtxZ-`MPRW8(H|hP*-0m(fxOpT$SnA z6Uj;0X&)RYQ_TCp*3Xx{sIXtp#rh#vW%6|7hQ}dVJE>V5GhOI)8&r4C;^e(?MzyRns(tE+5 z1JQUC;rk2NbUDy`zUd&^*VP(~Y2Yw$8CVL6U~|+4*|Z1fXPScZ3qTR(>}uZUfuNK1 zVY=7d58Mr+xpnpZm)Nl}@Kle$Og@$X7x`F>Uah^#N(Ug|N#MeVQS|N)Jgpgl^$(g%$J>Yl<=_YqLPSTS4zvgGCsj<119 zAa9Znv%t$Biw{dVzG&|Sz@$>sI#{pzdH{5i8(oLG{d=(-YLs-JHV<^V_F3mx_1V<_ z^kgprnk#rSXqBIb*k^`4GrE?nKGFRkt$nCH+zR#u{W!LX+s*=pVjA|yGy)&*u=-YCC@RxRWI!7<)&@N1O+rKG+eKM+{| zzrj;mu2go^e^L_cClw)uJP8kJsIlK@$l!CZ!5fb7P#nmsMR@qw5ifG6Vi6o$THYWj zhoXKE^dJRMo)R`3+mDzB36Aaui-3%i$7X0eFDNnzj2t@@>_<`~ylTKB`4L{gl9C1w zTZ38*tmd2Y0Z)}Hs%dM3S63@f8a$*7279UUgBn(|sJ9FF7*h?7P2vR`>jwv$r6Ukh z=LMq03zXG)m^C?&7Z^3hnmyJx7J_<;XH?ib#@nhg46iyS4`VAE1UEV3c@vxR#ty~T z@O5M3d9a~2d5tR2-UPEw1?2@NJXyFpkmwqJx-NZ;Dc(Hi^JaCv-wo7YQq zY)94F#Kig=Wy{dmeyZfH66;wK2FLc(QRgMLkEC{#*xr)bB}&G%Rkh!wc3wY8)vaNB za6U*pZ(wI=^VsI3U z!sr@2F`%ftI;T9mT4*qzlwy#hc6q~*V~JyM>}Z5H*x)JVA(4Y%KjkK*YJ(R9J=U)a zPH?gQUy!hRK9s&dUXY!kAibz<@TeyWL8?&E;58~WsK}6q5;en`GC9T@Cgr+d2PIe6 P!S%KZZ+yQv)_?v#QgVSl literal 0 HcmV?d00001 From 3ac0088fa8fa39c6e0f1274df2b7c41aed893d2e Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 17:05:07 +0800 Subject: [PATCH 23/27] windows: Fix --console follow Now you can get a live view of the EC console on Windows, too. Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 4c99bcc9..afdaef0c 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -1044,21 +1044,21 @@ impl CrosEc { loop { match cmd.send_command_vec(self) { Ok(data) => { - // EC Buffer is empty. That means we've read everything from the snapshot - // The windows crosecbus driver returns all NULL instead of empty response - if data.is_empty() || data.iter().all(|x| *x == 0) { + // EC Buffer is empty. That means we've read everything from the snapshot. + // The windows crosecbus driver returns all NULL with a leading 0x01 instead of + // an empty response. + if data.is_empty() || data.iter().all(|x| *x == 0 || *x == 1) { debug!("Empty EC response. Stopping console read"); - // Don't read too fast, wait a second before reading more - os_specific::sleep(1_000_000); + // Don't read too fast, wait 100ms before reading more + os_specific::sleep(100_000); EcRequestConsoleSnapshot {}.send_command(self)?; cmd.subcmd = ConsoleReadSubCommand::ConsoleReadRecent as u8; continue; } let utf8 = std::str::from_utf8(&data).unwrap(); - let ascii = utf8 - .replace(|c: char| !c.is_ascii(), "") - .replace(['\0'], ""); + let full_ascii = utf8.replace(|c: char| !c.is_ascii(), ""); + let ascii = full_ascii.replace(['\0'], ""); print!("{}", ascii); } From 53bbee0204d7dd477c709e2ab18bbcaea825e417 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 18:02:10 +0800 Subject: [PATCH 24/27] --sensors: Hide accel if not present Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index bb3e9ea4..6fbee681 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -288,22 +288,25 @@ pub fn print_sensors(ec: &CrosEc) { let accel_1 = ec.read_memory(EC_MEMMAP_ACC_DATA + 2, 0x06).unwrap(); let accel_2 = ec.read_memory(EC_MEMMAP_ACC_DATA + 8, 0x06).unwrap(); - println!("Accelerometers:"); - println!(" Status Bit: {} 0x{:X}", acc_status, acc_status); - println!(" Present: {}", (acc_status & 0x80) > 0); - println!(" Busy: {}", (acc_status & 0x8) > 0); - print!(" Lid Angle: "); - if lid_angle == LID_ANGLE_UNRELIABLE { - println!("Unreliable"); - } else { - println!("{} Deg", lid_angle); + let present = (acc_status & 0x80) > 0; + if present { + println!("Accelerometers:"); + println!(" Status Bit: {} 0x{:X}", acc_status, acc_status); + println!(" Present: {}", present); + println!(" Busy: {}", (acc_status & 0x8) > 0); + print!(" Lid Angle: "); + if lid_angle == LID_ANGLE_UNRELIABLE { + println!("Unreliable"); + } else { + println!("{} Deg", lid_angle); + } + println!(" Sensor 1: {}", AccelData::from(accel_1)); + println!(" Sensor 2: {}", AccelData::from(accel_2)); + // Accelerometers + // Lid Angle: 26 Deg + // Sensor 1: 00.00 X 00.00 Y 00.00 Z + // Sensor 2: 00.00 X 00.00 Y 00.00 Z } - println!(" Sensor 1: {}", AccelData::from(accel_1)); - println!(" Sensor 2: {}", AccelData::from(accel_2)); - // Accelerometers - // Lid Angle: 26 Deg - // Sensor 1: 00.00 X 00.00 Y 00.00 Z - // Sensor 2: 00.00 X 00.00 Y 00.00 Z } pub fn print_thermal(ec: &CrosEc) { From 7c1b9886da471d20140c0c2cab50aba3279d5acb Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 18:05:18 +0800 Subject: [PATCH 25/27] EXAMPLES: Add more Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index b00f20d4..5616dad1 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -128,7 +128,7 @@ Positions: ## Check temperatures and fan speed ``` -> sudo ./target/debug/framework_tool --thermal +> sudo framework_tool --thermal F75303_Local: 43 C F75303_CPU: 44 C F75303_DDR: 39 C @@ -136,13 +136,28 @@ Positions: Fan Speed: 0 RPM ``` -## Check sensors (ALS and G-Sensor) +## Check sensors + +### Ambient Light (Framework 13, Framework 16) ``` -> sudo ./target/debug/framework_tool --sensors +> sudo framework_tool --sensors ALS: 76 Lux ``` +### Accelerometer (Framework 12) +``` +> sudo framework_tool --sensors +ALS: 0 Lux +Accelerometers: + Status Bit: 140 0x8C + Present: true + Busy: true + Lid Angle: 122 Deg + Sensor 1: X: 0.00G Y: 0.84G, Z: 0.52G + Sensor 2: X: -0.03G Y: 0.00G, Z: 1.01G +``` + ## Set custom fan duty/RPM ``` @@ -296,6 +311,45 @@ Battery Status > sudo framework_tool --charge-current-limit 2000 80 ``` +## EC Console + +``` +# Get recent EC console logs and watch for more +> framework_tool.exe --console follow +[53694.741000 Battery 62% (Display 61.1 %) / 3h:18 to empty] +[53715.010000 Battery 62% (Display 61.0 %) / 3h:21 to empty] +[53734.281200 Battery 62% (Display 60.9 %) / 3h:18 to empty] +[53738.037200 Battery 61% (Display 60.9 %) / 3h:6 to empty] +[53752.301500 Battery 61% (Display 60.8 %) / 3h:15 to empty] +``` + +## Keyboard backlight + +``` +# Check current keyboard backlight brightness +> framework_tool.exe --kblight +Keyboard backlight: 5% + +# Set keyboard backlight brightness +# Off +> framework_tool.exe --kblight 0 +# 20% +> framework_tool.exe --kblight 20 +``` + +## RGB LED (Framework Desktop) + +``` +# To set three LEDs to red, green, blue +sudo framework_tool --rgbkbd 0 0xFF0000 0x00FF00 0x0000FF + +# To clear 8 LEDs +sudo framework_tool --rgbkbd 0 0 0 0 0 0 0 0 0 + +# Just turn the 3rd LED red +sudo framework_tool --rgbkbd 2 0xFF0000 +``` + ## Stylus (Framework 12) ``` From d488a1f6b5334ba0c69b40ff6a1192b2dbe875a5 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 18:12:52 +0800 Subject: [PATCH 26/27] --sensors: Prettier formatting of Accel Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 9 +++------ framework_lib/src/power.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/EXAMPLES.md b/EXAMPLES.md index 5616dad1..fe734abd 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -150,12 +150,9 @@ ALS: 76 Lux > sudo framework_tool --sensors ALS: 0 Lux Accelerometers: - Status Bit: 140 0x8C - Present: true - Busy: true - Lid Angle: 122 Deg - Sensor 1: X: 0.00G Y: 0.84G, Z: 0.52G - Sensor 2: X: -0.03G Y: 0.00G, Z: 1.01G + Lid Angle: 122 Deg + Sensor 1: X=+0.00G Y=+0.84G, Z=+0.52G + Sensor 2: X=-0.03G Y=+0.00G, Z=+1.01G ``` ## Set custom fan duty/RPM diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 6fbee681..9cc15cd7 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -190,7 +190,7 @@ impl fmt::Display for AccelData { let x = (self.x as f32) / quarter; let y = (self.y as f32) / quarter; let z = (self.z as f32) / quarter; - write!(f, "X: {:.2}G Y: {:.2}G, Z: {:.2}G", x, y, z) + write!(f, "X={:+.2}G Y={:+.2}G, Z={:+.2}G", x, y, z) } } @@ -291,17 +291,17 @@ pub fn print_sensors(ec: &CrosEc) { let present = (acc_status & 0x80) > 0; if present { println!("Accelerometers:"); - println!(" Status Bit: {} 0x{:X}", acc_status, acc_status); - println!(" Present: {}", present); - println!(" Busy: {}", (acc_status & 0x8) > 0); - print!(" Lid Angle: "); + debug!(" Status Bit: {} 0x{:X}", acc_status, acc_status); + debug!(" Present: {}", present); + debug!(" Busy: {}", (acc_status & 0x8) > 0); + print!(" Lid Angle: "); if lid_angle == LID_ANGLE_UNRELIABLE { println!("Unreliable"); } else { println!("{} Deg", lid_angle); } - println!(" Sensor 1: {}", AccelData::from(accel_1)); - println!(" Sensor 2: {}", AccelData::from(accel_2)); + println!(" Sensor 1: {}", AccelData::from(accel_1)); + println!(" Sensor 2: {}", AccelData::from(accel_2)); // Accelerometers // Lid Angle: 26 Deg // Sensor 1: 00.00 X 00.00 Y 00.00 Z From 74281f3a9a2d5773ff049e5e8025902db912296b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 7 May 2025 18:19:48 +0800 Subject: [PATCH 27/27] EXAMPLES: Add system firmware example Signed-off-by: Daniel Schaefer --- EXAMPLES.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/EXAMPLES.md b/EXAMPLES.md index fe734abd..7b915984 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -2,6 +2,33 @@ ## Check firmware versions +### BIOS (Mainboard, UEFI, EC, PD) + +Example on Framework 13 AMD Ryzen AI 300 Series: + +``` +> framework_tool --versions +Mainboard Hardware + Type: Laptop 13 (AMD Ryzen AI 300 Series) + Revision: MassProduction +UEFI BIOS + Version: 03.00 + Release Date: 03/10/2025 +EC Firmware + Build version: "lilac-3.0.0-1541dc6 2025-05-05 11:31:24 zoid@localhost" + RO Version: "lilac-3.0.0-1541dc6" + RW Version: "lilac-3.0.0-1541dc6" + Current image: RO +PD Controllers + Right (01) + Main: 0.0.0E (Active) + Backup: 0.0.0E + Left (23) + Main: 0.0.0E (Active) + Backup: 0.0.0E +[...] +``` + ### Camera (Framework 12, Framework 13, Framework 16) Example on Framework 12: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy