From 76c1d10281fc52f87f2a62b2fab827607b8f4f31 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 16:04:39 +0800 Subject: [PATCH 01/53] Add Framework13AmdAi300 Signed-off-by: Daniel Schaefer --- framework_lib/src/ccgx/device.rs | 24 ++++++++++++++++++++---- framework_lib/src/chromium_ec/mod.rs | 6 +++++- framework_lib/src/power.rs | 6 +++--- framework_lib/src/smbios.rs | 7 ++++--- framework_lib/src/util.rs | 10 ++++++---- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index 432db3b6..0c123086 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -44,8 +44,18 @@ impl PdPort { (Platform::GenericFramework((left, _), _, _), PdPort::Left01) => *left, (Platform::GenericFramework((_, right), _, _), PdPort::Right23) => *right, // Framework AMD Platforms (CCG8) - (Platform::Framework13Amd | Platform::Framework16, PdPort::Left01) => 0x42, - (Platform::Framework13Amd | Platform::Framework16, PdPort::Right23) => 0x40, + ( + Platform::Framework13Amd7080 + | Platform::Framework13AmdAi300 + | Platform::Framework16Amd7080, + PdPort::Left01, + ) => 0x42, + ( + Platform::Framework13Amd7080 + | Platform::Framework13AmdAi300 + | Platform::Framework16Amd7080, + PdPort::Right23, + ) => 0x40, // Framework Intel Platforms (CCG5 and CCG6) (_, PdPort::Left01) => 0x08, (_, PdPort::Right23) => 0x40, @@ -64,11 +74,17 @@ impl PdPort { (Platform::IntelGen12 | Platform::IntelGen13, PdPort::Left01) => 6, (Platform::IntelGen12 | Platform::IntelGen13, PdPort::Right23) => 7, ( - Platform::Framework13Amd | Platform::Framework16 | Platform::IntelCoreUltra1, + Platform::Framework13Amd7080 + | Platform::Framework16Amd7080 + | Platform::IntelCoreUltra1 + | Platform::Framework13AmdAi300 PdPort::Left01, ) => 1, ( - Platform::Framework13Amd | Platform::Framework16 | Platform::IntelCoreUltra1, + Platform::Framework13Amd7080 + | Platform::Framework16Amd7080 + | Platform::IntelCoreUltra1 + | Platform::Framework13AmdAi300 PdPort::Right23, ) => 2, // (_, _) => Err(EcError::DeviceError(format!( diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index f86fa839..4a83b9d5 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -125,9 +125,13 @@ pub fn has_mec() -> bool { return has_mec; } + // TODO: Should turn this around !matches!( smbios::get_platform().unwrap(), - Platform::Framework13Amd | Platform::Framework16 | Platform::IntelCoreUltra1 + Platform::Framework13Amd7080 + | Platform::Framework16Amd7080 + | Platform::IntelCoreUltra1 + | Platform::Framework13AmdAi300 ) } diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 1f8835a7..c770ecd9 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -216,12 +216,12 @@ pub fn print_thermal(ec: &CrosEc) { println!(" PECI: {:>4}", TempSensor::from(temps[4])); println!(" F57397_VCCGT: {:>4}", TempSensor::from(temps[5])); } - Some(Platform::Framework13Amd | Platform::Framework16) => { + Some(Platform::Framework13Amd7080 | Platform::Framework16Amd7080) => { println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); println!(" F75303_CPU: {:>4}", TempSensor::from(temps[1])); println!(" F75303_DDR: {:>4}", TempSensor::from(temps[2])); println!(" APU: {:>4}", TempSensor::from(temps[3])); - if matches!(platform, Some(Platform::Framework16)) { + if matches!(platform, Some(Platform::Framework16Amd7080)) { println!(" dGPU VR: {:>4}", TempSensor::from(temps[4])); println!(" dGPU VRAM: {:>4}", TempSensor::from(temps[5])); println!(" dGPU AMB: {:>4}", TempSensor::from(temps[6])); @@ -495,7 +495,7 @@ pub fn get_pd_info(ec: &CrosEc, ports: u8) -> Vec> { } pub fn get_and_print_pd_info(ec: &CrosEc) { - let fl16 = Some(crate::util::Platform::Framework16) == get_platform(); + let fl16 = Some(crate::util::Platform::Framework16Amd7080) == get_platform(); let ports = 4; // All our platforms have 4 PD ports so far let infos = get_pd_info(ec, ports); for (port, info) in infos.iter().enumerate().take(ports.into()) { diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 9c0ab1c7..aedd9cc7 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -262,10 +262,11 @@ pub fn get_platform() -> Option { "Laptop" => Some(Platform::IntelGen11), "Laptop (12th Gen Intel Core)" => Some(Platform::IntelGen12), "Laptop (13th Gen Intel Core)" => Some(Platform::IntelGen13), - "Laptop 13 (AMD Ryzen 7040Series)" => Some(Platform::Framework13Amd), - "Laptop 13 (AMD Ryzen 7040 Series)" => Some(Platform::Framework13Amd), + "Laptop 13 (AMD Ryzen 7040Series)" => Some(Platform::Framework13Amd7080), + "Laptop 13 (AMD Ryzen 7040 Series)" => Some(Platform::Framework13Amd7080), + "Laptop 13 (AMD Ryzen AI 300 Series)" => Some(Platform::Framework13AmdAi300), "Laptop 13 (Intel Core Ultra Series 1)" => Some(Platform::IntelCoreUltra1), - "Laptop 16 (AMD Ryzen 7040 Series)" => Some(Platform::Framework16), + "Laptop 16 (AMD Ryzen 7040 Series)" => Some(Platform::Framework16Amd7080), _ => None, }; diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 18a5a577..a66b5f20 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -25,10 +25,12 @@ pub enum Platform { IntelGen13, /// Framework 13 - Intel Core Ultra Series 1, Codenamed MeteorLake IntelCoreUltra1, - /// Framework 13 - AMD Ryzen - Framework13Amd, - /// Framework 16 - Framework16, + /// Framework 13 - AMD Ryzen 7080 Series + Framework13Amd7080, + /// Framework 13 - AMD Ryzen AI 300 Series + Framework13AmdAi300, + /// Framework 16 - AMD Ryzen 7080 Series + Framework16Amd7080, /// Generic Framework device /// pd_addrs, pd_ports, has_mec GenericFramework((u16, u16), (u8, u8), bool), From df56687e49739e81826ca08fa558d449f29713b6 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 16:09:33 +0800 Subject: [PATCH 02/53] Add FrameworkDesktopAmdAiMax300 Signed-off-by: Daniel Schaefer --- framework_lib/src/ccgx/device.rs | 4 ++++ framework_lib/src/chromium_ec/mod.rs | 1 + framework_lib/src/smbios.rs | 1 + framework_lib/src/util.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index 0c123086..cb083cd9 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -56,6 +56,8 @@ impl PdPort { | Platform::Framework16Amd7080, PdPort::Right23, ) => 0x40, + // TODO: It only has a single PD controller + (Platform::FrameworkDesktopAmdAiMax300, _) => 0x08, // Framework Intel Platforms (CCG5 and CCG6) (_, PdPort::Left01) => 0x08, (_, PdPort::Right23) => 0x40, @@ -87,6 +89,8 @@ impl PdPort { | Platform::Framework13AmdAi300 PdPort::Right23, ) => 2, + // TODO: It only has a single PD controller + (Platform::FrameworkDesktopAmdAiMax300, _) => 1, // (_, _) => Err(EcError::DeviceError(format!( // "Unsupported platform: {:?} {:?}", // platform, self diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 4a83b9d5..30718c3a 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -132,6 +132,7 @@ pub fn has_mec() -> bool { | Platform::Framework16Amd7080 | Platform::IntelCoreUltra1 | Platform::Framework13AmdAi300 + | Platform::FrameworkDesktopAmdAiMax300 ) } diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index aedd9cc7..1c1b27ea 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -267,6 +267,7 @@ pub fn get_platform() -> Option { "Laptop 13 (AMD Ryzen AI 300 Series)" => Some(Platform::Framework13AmdAi300), "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, }; diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index a66b5f20..513ccc00 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -31,6 +31,8 @@ pub enum Platform { Framework13AmdAi300, /// Framework 16 - AMD Ryzen 7080 Series Framework16Amd7080, + /// Framework Desktop - AMD Ryzen AI Max 300 + FrameworkDesktopAmdAiMax300, /// Generic Framework device /// pd_addrs, pd_ports, has_mec GenericFramework((u16, u16), (u8, u8), bool), From 428fc824a6413146c0ef051def43a80f8cd47160 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 16:10:07 +0800 Subject: [PATCH 03/53] Add Framework12IntelGen13 Signed-off-by: Daniel Schaefer --- framework_lib/src/ccgx/device.rs | 2 ++ framework_lib/src/chromium_ec/mod.rs | 1 + framework_lib/src/smbios.rs | 1 + framework_lib/src/util.rs | 2 ++ 4 files changed, 6 insertions(+) diff --git a/framework_lib/src/ccgx/device.rs b/framework_lib/src/ccgx/device.rs index cb083cd9..aa1af5d0 100644 --- a/framework_lib/src/ccgx/device.rs +++ b/framework_lib/src/ccgx/device.rs @@ -80,6 +80,7 @@ impl PdPort { | Platform::Framework16Amd7080 | Platform::IntelCoreUltra1 | Platform::Framework13AmdAi300 + | Platform::Framework12IntelGen13, PdPort::Left01, ) => 1, ( @@ -87,6 +88,7 @@ impl PdPort { | Platform::Framework16Amd7080 | Platform::IntelCoreUltra1 | Platform::Framework13AmdAi300 + | Platform::Framework12IntelGen13, PdPort::Right23, ) => 2, // TODO: It only has a single PD controller diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 30718c3a..ece6a5fe 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -132,6 +132,7 @@ pub fn has_mec() -> bool { | Platform::Framework16Amd7080 | Platform::IntelCoreUltra1 | Platform::Framework13AmdAi300 + | Platform::Framework12IntelGen13 | Platform::FrameworkDesktopAmdAiMax300 ) } diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 1c1b27ea..fa23c2fa 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -265,6 +265,7 @@ pub fn get_platform() -> Option { "Laptop 13 (AMD Ryzen 7040Series)" => Some(Platform::Framework13Amd7080), "Laptop 13 (AMD Ryzen 7040 Series)" => Some(Platform::Framework13Amd7080), "Laptop 13 (AMD Ryzen AI 300 Series)" => Some(Platform::Framework13AmdAi300), + "Laptop 12 (13th Gen Intel Core)" => Some(Platform::Framework12IntelGen13), "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), diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 513ccc00..3fa8f505 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -17,6 +17,8 @@ use crate::smbios; #[derive(Debug, PartialEq, Clone, Copy)] pub enum Platform { + /// Framework 12 + Framework12IntelGen13, /// Framework 13 - Intel 11th Gen, Codenamed TigerLake IntelGen11, /// Framework 13 - Intel 11th Gen, Codenamed AlderLake From d4c0548ab2159214ec19e8585c0843ce246ce62d Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:10:00 +0800 Subject: [PATCH 04/53] power: No VCCGT temp sensor on gen11 Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index c770ecd9..47c62efb 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -214,7 +214,12 @@ pub fn print_thermal(ec: &CrosEc) { println!(" F75303_DDR: {:>4}", TempSensor::from(temps[2])); println!(" Battery: {:>4}", TempSensor::from(temps[3])); println!(" PECI: {:>4}", TempSensor::from(temps[4])); - println!(" F57397_VCCGT: {:>4}", TempSensor::from(temps[5])); + if matches!( + platform, + Some(Platform::IntelGen12) | Some(Platform::IntelGen13) + ) { + println!(" F57397_VCCGT: {:>4}", TempSensor::from(temps[5])); + } } Some(Platform::Framework13Amd7080 | Platform::Framework16Amd7080) => { println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); From 5a9118d5e47ae1cf527ca7af073e0266492bfbe5 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:11:00 +0800 Subject: [PATCH 05/53] power: Add core ultra temp mapping Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 47c62efb..08aae220 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -221,6 +221,15 @@ pub fn print_thermal(ec: &CrosEc) { println!(" F57397_VCCGT: {:>4}", TempSensor::from(temps[5])); } } + + Some(Platform::IntelCoreUltra1) => { + println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); + println!(" F75303_CPU: {:>4}", TempSensor::from(temps[1])); + println!(" Battery: {:>4}", TempSensor::from(temps[2])); + println!(" F75303_DDR: {:>4}", TempSensor::from(temps[3])); + println!(" PECI: {:>4}", TempSensor::from(temps[4])); + } + Some(Platform::Framework13Amd7080 | Platform::Framework16Amd7080) => { println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); println!(" F75303_CPU: {:>4}", TempSensor::from(temps[1])); From 375625ac22faa239b6478225327f73adbca11867 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:11:42 +0800 Subject: [PATCH 06/53] thermal: Add Framework13AmdAi300 thermal mapping Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 08aae220..eced1c07 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -230,7 +230,11 @@ pub fn print_thermal(ec: &CrosEc) { println!(" PECI: {:>4}", TempSensor::from(temps[4])); } - Some(Platform::Framework13Amd7080 | Platform::Framework16Amd7080) => { + Some( + Platform::Framework13Amd7080 + | Platform::Framework13AmdAi300 + | Platform::Framework16Amd7080, + ) => { println!(" F75303_Local: {:>4}", TempSensor::from(temps[0])); println!(" F75303_CPU: {:>4}", TempSensor::from(temps[1])); println!(" F75303_DDR: {:>4}", TempSensor::from(temps[2])); From bdf377bc13ed790a5d9be7bcfbdfcb756b547bbc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:12:02 +0800 Subject: [PATCH 07/53] power: Add FrameworkDesktopAmdAiMax300 thermal mapping Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index eced1c07..8e6c6fb9 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -246,6 +246,14 @@ pub fn print_thermal(ec: &CrosEc) { println!(" dGPU temp: {:>4}", TempSensor::from(temps[7])); } } + + Some(Platform::FrameworkDesktopAmdAiMax300) => { + println!(" F75303_APU: {:>4}", TempSensor::from(temps[0])); + println!(" F75303_DDR: {:>4}", TempSensor::from(temps[1])); + println!(" F75303_AMB: {:>4}", TempSensor::from(temps[2])); + println!(" APU: {:>4}", TempSensor::from(temps[3])); + } + _ => { println!(" Temp 0: {:>4}", TempSensor::from(temps[0])); println!(" Temp 1: {:>4}", TempSensor::from(temps[1])); From edff45a41caba289cc13430b64003608fbb5cc0d Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:12:13 +0800 Subject: [PATCH 08/53] power: Add Framework12IntelGen13 thermal mapping Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 8e6c6fb9..b8477f63 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -230,6 +230,14 @@ pub fn print_thermal(ec: &CrosEc) { println!(" PECI: {:>4}", TempSensor::from(temps[4])); } + Some(Platform::Framework12IntelGen13) => { + println!(" F75303_CPU: {:>4}", TempSensor::from(temps[0])); + println!(" F75303_Skin: {:>4}", TempSensor::from(temps[1])); + println!(" F75303_Local: {:>4}", TempSensor::from(temps[2])); + println!(" Battery: {:>4}", TempSensor::from(temps[3])); + println!(" PECI: {:>4}", TempSensor::from(temps[4])); + } + Some( Platform::Framework13Amd7080 | Platform::Framework13AmdAi300 From 0321d5001c16c1507e36fa6a0edc01b26e86a8cc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 3 Dec 2024 10:12:13 +0800 Subject: [PATCH 09/53] framework_lib: Re-export Platform for public use util is a private module for implementation details. It does not need to be exported. But Platform is in there to avoid cyclic dependencies. Signed-off-by: Daniel Schaefer --- framework_lib/src/smbios.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 9c0ab1c7..f39f54b2 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -5,7 +5,8 @@ use std::prelude::v1::*; #[cfg(all(not(feature = "uefi"), not(target_os = "freebsd")))] use std::io::ErrorKind; -use crate::util::{Config, Platform}; +use crate::util::Config; +pub use crate::util::Platform; use num_derive::FromPrimitive; use smbioslib::*; #[cfg(feature = "uefi")] From 5a26a386f36effbc42dfb75e02935935fe2e39c0 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 3 Dec 2024 10:14:12 +0800 Subject: [PATCH 10/53] framework_lib: EcCurrentImage derive Debug Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index f86fa839..c0af860e 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -974,7 +974,7 @@ pub fn print_err(something: EcResult) -> Option { } /// Which of the two EC images is currently in-use -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum EcCurrentImage { Unknown = 0, RO = 1, From a2e4dd323f44234986a872743a7d625ae92056df Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 17:28:59 +0800 Subject: [PATCH 11/53] README: Update Signed-off-by: Daniel Schaefer --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f4927fc0..1c454543 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,16 @@ All of these need EC communication support in order to work. ###### Communication with Embedded Controller +- [x] Framework Laptop 12 (Intel 13th Gen) - [x] Framework Laptop 13 (Intel 11-13th Gen) -- [x] Framework Laptop 13 (AMD Ryzen) -- [x] Framework Laptop 16 (AMD Ryzen) +- [x] Framework Laptop 13 (AMD Ryzen 7080) +- [x] Framework Laptop 13 (AMD Ryzen AI 300) +- [x] Framework Laptop 16 (AMD Ryzen 7080) +- [x] Framework Desktop (AMD Ryzen AI Max 300) - [x] Port I/O communication on Linux -- [x] Port I/O communication on UEFI +- [x] Port I/O communication in UEFI - [x] Using `cros_ec` driver in Linux kernel +- [x] Using [Framework EC Windows driver](https://github.com/FrameworkComputer/crosecbus) based on [coolstar's](https://github.com/coolstar/crosecbus) - [x] Using [DHowett's Windows CrosEC driver](https://github.com/DHowett/FrameworkWindowsUtils) ## Prerequisites @@ -99,8 +103,8 @@ will install the right toolchain and version for this project. MSRV (Minimum Supported Rust Version): -- 1.61 for Linux/Windows -- 1.68 for UEFI +- 1.74 for Linux/Windows +- 1.74 for UEFI ```sh # Running linter @@ -131,10 +135,6 @@ ls -l framework_uefi/build/x86_64-unknown-uefi/boot.efi Building on Windows or in general with fewer features: ```ps1 -# Because we're fetching a private dependency from git, it might be necessary -# to force cargo to use the git commandline. In powershell run: -$env:CARGO_NET_GIT_FETCH_WITH_CLI='true' - # Build the library and tool cargo build --no-default-features --features "windows" From d3768c27a68d9e762017e800531512e1181c0934 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 18:32:51 +0800 Subject: [PATCH 12/53] Update dependencies Signed-off-by: Daniel Schaefer --- Cargo.lock | 110 ++++++++++++--------------------------- framework_lib/Cargo.toml | 8 ++- 2 files changed, 37 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2cb24fc..30842e31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -302,7 +302,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -319,7 +319,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -482,7 +482,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -553,7 +553,7 @@ version = "0.11.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -564,9 +564,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hidapi" -version = "2.6.1" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e58251020fe88fe0dae5ebcc1be92b4995214af84725b375d08354d0311c23c" +checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b" dependencies = [ "cc", "cfg-if", @@ -826,7 +826,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -908,9 +908,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -937,9 +937,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -955,9 +955,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -967,9 +967,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -978,9 +978,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rusb" @@ -1135,9 +1135,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -1155,22 +1155,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -1396,61 +1396,29 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-implement 0.52.0", - "windows-interface 0.52.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" dependencies = [ - "windows-core 0.59.0", + "windows-core", "windows-targets 0.53.0", ] -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ - "windows-implement 0.59.0", - "windows-interface 0.59.0", + "windows-implement", + "windows-interface", "windows-result", "windows-strings", "windows-targets 0.53.0", ] -[[package]] -name = "windows-implement" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - [[package]] name = "windows-implement" version = "0.59.0" @@ -1459,18 +1427,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", -] - -[[package]] -name = "windows-interface" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -1481,7 +1438,7 @@ checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.98", ] [[package]] @@ -1707,14 +1664,15 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wmi" -version = "0.13.3" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f0a4062ca522aad4705a2948fd4061b3857537990202a8ddd5af21607f79a" +checksum = "58078b4e28f04064dae68f6e11a6b93133c83b88dfd5ae16738ded4942db6544" dependencies = [ "chrono", "futures", "log", "serde", "thiserror", - "windows 0.52.0", + "windows 0.59.0", + "windows-core", ] diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 3dadedf9..81db759a 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -47,7 +47,7 @@ built = { version = "0.5", features = ["chrono", "git2"] } [dependencies] lazy_static = "1.4.0" sha2 = { version = "0.10.8", default-features = false, features = [ "force-soft" ] } -regex = { version = "1.10.6", default-features = false } +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"], optional = true } @@ -62,13 +62,11 @@ 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 2.6.2 needs nightly -# See: https://github.com/ruabmbua/hidapi-rs/pull/158 -hidapi = { version = "=2.6.1", optional = true } +hidapi = { version = "2.6.3", optional = true } rusb = { version = "0.9.4", optional = true } no-std-compat = { version = "0.4.1", features = [ "alloc" ] } guid_macros = { path = "../guid_macros" } -wmi = { version = "0.13.3", optional = true } +wmi = { version = "0.15.0", optional = true } [dependencies.smbios-lib] git = "https://github.com/FrameworkComputer/smbios-lib.git" From a7e4d15771d87b9906475e9270132b5725126c55 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 26 Feb 2025 10:45:33 +0800 Subject: [PATCH 13/53] Specify C-ABI when packing Clippy now warns about this: error: item uses `packed` representation without ABI-qualification Quote from clippy: > repr(packed) by default implies repr(Rust, packed). However, this > representation is not stable, which makes it less useful: the bulk of > repr(packed) use cases are for interfacing with certain binary formats > (where it needs to be repr(C, packed)) and for zero-copy deserialization > (which needs to be stable). The best use case for repr(Rust, packed) is > for reducing binary size Signed-off-by: Daniel Schaefer --- framework_lib/src/audio_card.rs | 4 ++-- framework_lib/src/ccgx/binary.rs | 2 +- framework_lib/src/ccgx/hid.rs | 2 +- framework_lib/src/ccgx/mod.rs | 4 ++-- framework_lib/src/esrt/mod.rs | 2 +- framework_lib/src/smbios.rs | 2 +- framework_lib/src/uefi/mod.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/framework_lib/src/audio_card.rs b/framework_lib/src/audio_card.rs index 8647791d..3baa33ca 100644 --- a/framework_lib/src/audio_card.rs +++ b/framework_lib/src/audio_card.rs @@ -15,7 +15,7 @@ enum CapeCommand { GetVersion = 0x0103, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy)] struct CapeMessage { _len: i16, @@ -25,7 +25,7 @@ struct CapeMessage { data: [u32; CAPE_DATA_LEN], } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy)] struct HidCapeMessage { _report_id: u16, diff --git a/framework_lib/src/ccgx/binary.rs b/framework_lib/src/ccgx/binary.rs index 30d7b33d..acb9c51a 100644 --- a/framework_lib/src/ccgx/binary.rs +++ b/framework_lib/src/ccgx/binary.rs @@ -44,7 +44,7 @@ const FW_VERSION_OFFSET: usize = 0xE0; const SMALL_ROW: usize = 0x80; const LARGE_ROW: usize = 0x100; -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug, Copy, Clone)] struct VersionInfo { base_version: u32, diff --git a/framework_lib/src/ccgx/hid.rs b/framework_lib/src/ccgx/hid.rs index cc46111b..e3e14dc0 100644 --- a/framework_lib/src/ccgx/hid.rs +++ b/framework_lib/src/ccgx/hid.rs @@ -25,7 +25,7 @@ const FW2_START: usize = 0x0200; const FW1_METADATA: usize = 0x03FF; const FW2_METADATA: usize = 0x03FE; -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug, Copy, Clone)] struct HidFirmwareInfo { report_id: u8, diff --git a/framework_lib/src/ccgx/mod.rs b/framework_lib/src/ccgx/mod.rs index 8c8f89d2..80b1b763 100644 --- a/framework_lib/src/ccgx/mod.rs +++ b/framework_lib/src/ccgx/mod.rs @@ -30,7 +30,7 @@ const CCG3_METADATA_OFFSET: usize = 0x40; const METADATA_MAGIC: u16 = u16::from_le_bytes([b'Y', b'C']); // CY (Cypress) const CCG8_METADATA_MAGIC: u16 = u16::from_le_bytes([b'F', b'I']); // IF (Infineon) -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug, Copy, Clone)] struct CyAcdMetadata { /// Offset 00: Single Byte FW Checksum @@ -64,7 +64,7 @@ struct CyAcdMetadata { } // TODO: Would be nice to check the checksums -#[repr(packed)] +#[repr(C, packed)] #[derive(Debug, Copy, Clone)] struct CyAcd2Metadata { /// Offset 00: App Firmware Start diff --git a/framework_lib/src/esrt/mod.rs b/framework_lib/src/esrt/mod.rs index 521c6352..feb98a2a 100644 --- a/framework_lib/src/esrt/mod.rs +++ b/framework_lib/src/esrt/mod.rs @@ -144,7 +144,7 @@ pub fn match_guid_kind(guid: &Guid) -> FrameworkGuidKind { } } -#[repr(packed)] +#[repr(C, packed)] struct _Esrt { resource_count: u32, resource_count_max: u32, diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index fa23c2fa..58a383b8 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -106,7 +106,7 @@ pub struct Smbios3 { } #[cfg(target_os = "freebsd")] -#[repr(packed)] +#[repr(C, packed)] pub struct Smbios { pub anchor: [u8; 4], pub checksum: u8, diff --git a/framework_lib/src/uefi/mod.rs b/framework_lib/src/uefi/mod.rs index 2d6ec747..71d85b44 100644 --- a/framework_lib/src/uefi/mod.rs +++ b/framework_lib/src/uefi/mod.rs @@ -99,7 +99,7 @@ pub fn enable_page_break() { } } -#[repr(packed)] +#[repr(C, packed)] pub struct Smbios { pub anchor: [u8; 4], pub checksum: u8, From 7eb8d79ce86a414073e4b16ef2f84af56b1f7b0f Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 8 Oct 2024 06:48:44 +0800 Subject: [PATCH 14/53] Add command to toggle tablet mode Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/command.rs | 1 + framework_lib/src/chromium_ec/commands.rs | 18 ++++++++++++++++ framework_lib/src/chromium_ec/mod.rs | 8 +++++++- framework_lib/src/commandline/clap_std.rs | 7 +++++++ framework_lib/src/commandline/mod.rs | 17 +++++++++++++++ framework_lib/src/commandline/uefi.rs | 25 ++++++++++++++++++++++- 6 files changed, 74 insertions(+), 2 deletions(-) diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index a0205780..cad2be87 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -33,6 +33,7 @@ pub enum EcCommands { PwmSetFanDuty = 0x0024, PwmSetDuty = 0x0025, PwmGetDuty = 0x0026, + SetTabletMode = 0x0031, GpioGet = 0x93, I2cPassthrough = 0x9e, ConsoleSnapshot = 0x97, diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 82057165..1265c798 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -225,6 +225,24 @@ impl EcRequest for EcRequestPwmGetDuty { } } +pub enum TabletModeOverride { + Default = 0, + ForceTablet = 1, + ForceClamshell = 2, +} + +#[repr(C, packed)] +pub struct EcRequestSetTabletMode { + /// See TabletModeOverride + pub mode: u8, +} + +impl EcRequest<()> for EcRequestSetTabletMode { + fn command_id() -> EcCommands { + EcCommands::SetTabletMode + } +} + #[repr(C, packed)] pub struct EcRequestGpioGetV0 { pub name: [u8; 32], diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 399aca05..137a37fe 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -387,7 +387,6 @@ impl CrosEc { } /// Check the current brightness of the keyboard backlight - /// pub fn get_keyboard_backlight(&self) -> EcResult { let kblight = EcRequestPwmGetDuty { pwm_type: PwmType::KbLight as u8, @@ -398,6 +397,13 @@ impl CrosEc { Ok((kblight.duty / (PWM_MAX_DUTY / 100)) as u8) } + /// Set tablet mode + pub fn set_tablet_mode(&self, mode: TabletModeOverride) { + let mode = mode as u8; + let res = EcRequestSetTabletMode { mode }.send_command(self); + print_err(res); + } + /// Overwrite RO and RW regions of EC flash /// MEC/Legacy EC /// | Start | End | Size | Region | diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 30e54d2e..140cb151 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -6,6 +6,7 @@ use clap::Parser; use crate::chromium_ec::CrosEcDriverType; use crate::commandline::{ Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg, + TabletModeArg, }; /// Swiss army knife for Framework laptops @@ -144,6 +145,11 @@ struct ClapCli { #[arg(long)] kblight: Option>, + /// Set tablet mode override + #[clap(value_enum)] + #[arg(long)] + tablet_mode: Option, + /// Get EC console, choose whether recent or to follow the output #[clap(value_enum)] #[arg(long)] @@ -263,6 +269,7 @@ pub fn parse(args: &[String]) -> Cli { get_gpio: args.get_gpio, fp_brightness: args.fp_brightness, kblight: args.kblight, + tablet_mode: args.tablet_mode, console: args.console, reboot_ec: args.reboot_ec, hash: args.hash.map(|x| x.into_os_string().into_string().unwrap()), diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 9a28c66b..e911f773 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -35,6 +35,7 @@ use crate::chromium_ec; use crate::chromium_ec::commands::DeckStateMode; use crate::chromium_ec::commands::FpLedBrightnessLevel; use crate::chromium_ec::commands::RebootEcCmd; +use crate::chromium_ec::commands::TabletModeOverride; use crate::chromium_ec::EcResponseStatus; use crate::chromium_ec::{print_err, EcFlashType}; use crate::chromium_ec::{EcError, EcResult}; @@ -61,6 +62,14 @@ use crate::chromium_ec::{CrosEc, CrosEcDriverType, HardwareDeviceType}; #[cfg(feature = "uefi")] use core::prelude::rust_2021::derive; +#[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))] +#[derive(Clone, Debug, PartialEq)] +pub enum TabletModeArg { + Auto, + Tablet, + Laptop, +} + #[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))] #[derive(Clone, Debug, PartialEq)] pub enum ConsoleArg { @@ -152,6 +161,7 @@ pub struct Cli { pub get_gpio: Option, pub fp_brightness: Option>, pub kblight: Option>, + pub tablet_mode: Option, pub console: Option, pub reboot_ec: Option, pub hash: Option, @@ -743,6 +753,13 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else { println!("Unable to tell"); } + } else if let Some(tablet_arg) = &args.tablet_mode { + let mode = match tablet_arg { + TabletModeArg::Auto => TabletModeOverride::Default, + TabletModeArg::Tablet => TabletModeOverride::ForceTablet, + TabletModeArg::Laptop => TabletModeOverride::ForceClamshell, + }; + ec.set_tablet_mode(mode); } else if let Some(console_arg) = &args.console { match console_arg { ConsoleArg::Follow => { diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 121fc052..69dee466 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -12,7 +12,7 @@ use uefi::Identify; use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType}; use crate::commandline::Cli; -use super::{ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg}; +use super::{ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg, TabletModeArg}; /// Get commandline arguments from UEFI environment pub fn get_args(boot_services: &BootServices) -> Vec { @@ -86,6 +86,7 @@ pub fn parse(args: &[String]) -> Cli { get_gpio: None, fp_brightness: None, kblight: None, + tablet_mode: None, console: None, reboot_ec: None, hash: None, @@ -214,6 +215,28 @@ pub fn parse(args: &[String]) -> Cli { Some(None) }; found_an_option = true; + } else if arg == "--tablet-mode" { + cli.tablet_mode = if args.len() > i + 1 { + let tablet_mode_arg = &args[i + 1]; + if tablet_mode_arg == "auto" { + Some(TabletModeArg::Auto) + } else if tablet_mode_arg == "tablet" { + Some(TabletModeArg::Tablet) + } else if tablet_mode_arg == "laptop" { + Some(TabletModeArg::Laptop) + } else { + println!( + "Need to provide a value for --tablet-mode: '{}'. {}", + args[i + 1], + "Must be one of: `auto`, `tablet` or `laptop`", + ); + None + } + } else { + println!("Need to provide a value for --tablet-mode. One of: `auto`, `tablet` or `laptop`"); + None + }; + found_an_option = true; } else if arg == "--fp-brightness" { cli.fp_brightness = if args.len() > i + 1 { let fp_brightness_arg = &args[i + 1]; From 6a80f74d3a3ca25c99516ca26b4cf2d7f3a7b5b9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 18 Dec 2024 15:42:01 +0800 Subject: [PATCH 15/53] framework_lib: Add ultra-low powerbutton brightness Must also have EC support Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/commands.rs | 1 + framework_lib/src/commandline/mod.rs | 2 ++ framework_lib/src/commandline/uefi.rs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 1265c798..d2b03c11 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -844,6 +844,7 @@ pub enum FpLedBrightnessLevel { High = 0, Medium = 1, Low = 2, + UltraLow = 3, } #[repr(C, packed)] diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index e911f773..6f3ec63f 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -93,6 +93,7 @@ pub enum FpBrightnessArg { High, Medium, Low, + UltraLow, } impl From for FpLedBrightnessLevel { fn from(w: FpBrightnessArg) -> FpLedBrightnessLevel { @@ -100,6 +101,7 @@ impl From for FpLedBrightnessLevel { FpBrightnessArg::High => FpLedBrightnessLevel::High, FpBrightnessArg::Medium => FpLedBrightnessLevel::Medium, FpBrightnessArg::Low => FpLedBrightnessLevel::Low, + FpBrightnessArg::UltraLow => FpLedBrightnessLevel::UltraLow, } } } diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 69dee466..3d2c3a4c 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -246,6 +246,8 @@ pub fn parse(args: &[String]) -> Cli { Some(Some(FpBrightnessArg::Medium)) } else if fp_brightness_arg == "low" { Some(Some(FpBrightnessArg::Low)) + } else if fp_brightness_arg == "ultra-low" { + Some(Some(FpBrightnessArg::UltraLow)) } else { println!("Invalid value for --fp-brightness: {}", fp_brightness_arg); None From 3c7bfea3234d6bc44e06881e7efacea0cdc65255 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 14 Feb 2025 18:20:35 +0800 Subject: [PATCH 16/53] framework_lib: Add auto powerbutton brightness Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/commands.rs | 1 + framework_lib/src/commandline/mod.rs | 2 ++ framework_lib/src/commandline/uefi.rs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index d2b03c11..1eaf4cbd 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -845,6 +845,7 @@ pub enum FpLedBrightnessLevel { Medium = 1, Low = 2, UltraLow = 3, + Auto = 0xFF, } #[repr(C, packed)] diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 6f3ec63f..4ec8363b 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -94,6 +94,7 @@ pub enum FpBrightnessArg { Medium, Low, UltraLow, + Auto, } impl From for FpLedBrightnessLevel { fn from(w: FpBrightnessArg) -> FpLedBrightnessLevel { @@ -102,6 +103,7 @@ impl From for FpLedBrightnessLevel { FpBrightnessArg::Medium => FpLedBrightnessLevel::Medium, FpBrightnessArg::Low => FpLedBrightnessLevel::Low, FpBrightnessArg::UltraLow => FpLedBrightnessLevel::UltraLow, + FpBrightnessArg::Auto => FpLedBrightnessLevel::Auto, } } } diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 3d2c3a4c..700dff45 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -248,6 +248,8 @@ pub fn parse(args: &[String]) -> Cli { Some(Some(FpBrightnessArg::Low)) } else if fp_brightness_arg == "ultra-low" { Some(Some(FpBrightnessArg::UltraLow)) + } else if fp_brightness_arg == "auto" { + Some(Some(FpBrightnessArg::Auto)) } else { println!("Invalid value for --fp-brightness: {}", fp_brightness_arg); None From 0b8763e1dee9773297729dfd4ffd6d59b97b44ec Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 4 Mar 2025 19:10:54 +0800 Subject: [PATCH 17/53] fp-brightness: Add support for V1 host command V0: - Set level (ultra-low, low, medium, high, auto) - Get percentage V1: - Set percentage - Get level (ultra-low, low, medium, high, auto) Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/commands.rs | 36 ++++++++++++++++++-- framework_lib/src/chromium_ec/mod.rs | 40 +++++++++++++++++++---- framework_lib/src/commandline/mod.rs | 9 +++-- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 1eaf4cbd..aceb548a 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -849,7 +849,7 @@ pub enum FpLedBrightnessLevel { } #[repr(C, packed)] -pub struct EcRequestFpLedLevelControl { +pub struct EcRequestFpLedLevelControlV0 { /// See enum FpLedBrightnessLevel pub set_level: u8, /// Boolean. >1 to get the level @@ -858,12 +858,42 @@ pub struct EcRequestFpLedLevelControl { #[repr(C, packed)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct EcResponseFpLedLevelControl { +pub struct EcResponseFpLedLevelControlV0 { + /// Current brightness, 1-100% + pub percentage: u8, +} + +impl EcRequest for EcRequestFpLedLevelControlV0 { + fn command_id() -> EcCommands { + EcCommands::FpLedLevelControl + } + fn command_version() -> u8 { + 0 + } +} + +#[repr(C, packed)] +pub struct EcRequestFpLedLevelControlV1 { + /// Percentage 1-100 + pub set_percentage: u8, + /// Boolean. >1 to get the level + pub get_level: u8, +} + +#[repr(C, packed)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct EcResponseFpLedLevelControlV1 { + /// Current brightness, 1-100% + pub percentage: u8, + /// Requested level. See enum FpLedBrightnessLevel pub level: u8, } -impl EcRequest for EcRequestFpLedLevelControl { +impl EcRequest for EcRequestFpLedLevelControlV1 { fn command_id() -> EcCommands { EcCommands::FpLedLevelControl } + fn command_version() -> u8 { + 1 + } } diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 137a37fe..2dc53206 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -313,6 +313,17 @@ impl CrosEc { Ok((limits.min_percentage, limits.max_percentage)) } + pub fn set_fp_led_percentage(&self, percentage: u8) -> EcResult<()> { + // Sending bytes manually because the Set command, as opposed to the Get command, + // does not return any data + let limits = &[percentage, 0x00]; + let data = self.send_command(EcCommands::FpLedLevelControl as u16, 1, limits)?; + + util::assert_win_len(data.len(), 0); + + Ok(()) + } + pub fn set_fp_led_level(&self, level: FpLedBrightnessLevel) -> EcResult<()> { // Sending bytes manually because the Set command, as opposed to the Get command, // does not return any data @@ -325,16 +336,33 @@ impl CrosEc { } /// Get fingerprint led brightness level - pub fn get_fp_led_level(&self) -> EcResult { - let res = EcRequestFpLedLevelControl { - set_level: 0xFF, + pub fn get_fp_led_level(&self) -> EcResult<(u8, Option)> { + let res = EcRequestFpLedLevelControlV1 { + set_percentage: 0xFF, get_level: 0xFF, } - .send_command(self)?; + .send_command(self); + + // If V1 does not exist, fall back + if let Err(EcError::Response(EcResponseStatus::InvalidVersion)) = res { + let res = EcRequestFpLedLevelControlV0 { + set_level: 0xFF, + get_level: 0xFF, + } + .send_command(self)?; + debug!("Current Brightness: {}%", res.percentage); + return Ok((res.percentage, None)); + } + + let res = res?; - debug!("Level Raw: {}", res.level); + debug!("Current Brightness: {}%", res.percentage); + debug!("Level Raw: {}", res.level); - Ok(res.level) + // TODO: can turn this into None and log + let level = FromPrimitive::from_u8(res.level) + .ok_or(EcError::DeviceError(format!("Invalid level {}", res.level)))?; + Ok((res.percentage, Some(level))) } /// Get the intrusion switch status (whether the chassis is open or not) diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 4ec8363b..3df01887 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -1364,8 +1364,13 @@ fn handle_fp_brightness(ec: &CrosEc, maybe_brightness: Option) ec.set_fp_led_level(brightness.into())?; } - let level = ec.get_fp_led_level()?; - println!("Fingerprint LED Brightness: {:?}%", level); + let (brightness, level) = ec.get_fp_led_level()?; + // TODO: Rename to power button + println!("Fingerprint LED Brightness"); + if let Some(level) = level { + println!(" Requested: {:?}", level); + } + println!(" Brightness: {}%", brightness); Ok(()) } From fd9696a40b7d370594695c50951fc3ff5382e98a Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 4 Mar 2025 20:11:29 +0800 Subject: [PATCH 18/53] fp-brightness: Add fp-led-level for V1 command Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/commands.rs | 2 ++ framework_lib/src/commandline/clap_std.rs | 9 ++++-- framework_lib/src/commandline/mod.rs | 28 +++++++++++++--- framework_lib/src/commandline/uefi.rs | 39 +++++++++++++++++------ 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index aceb548a..dfed6642 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -845,6 +845,8 @@ pub enum FpLedBrightnessLevel { Medium = 1, Low = 2, UltraLow = 3, + /// Custom: Only get, never set + Custom = 0xFE, Auto = 0xFF, } diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 140cb151..96b4cd6c 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -137,9 +137,13 @@ struct ClapCli { #[arg(long)] get_gpio: Option, - /// Get or set fingerprint LED brightness + /// Get or set fingerprint LED brightness level #[arg(long)] - fp_brightness: Option>, + fp_led_level: Option>, + + /// Get or set fingerprint LED brightness percentage + #[arg(long)] + fp_brightness: Option>, /// Set keyboard backlight percentage or get, if no value provided #[arg(long)] @@ -267,6 +271,7 @@ pub fn parse(args: &[String]) -> Cli { input_deck_mode: args.input_deck_mode, charge_limit: args.charge_limit, get_gpio: args.get_gpio, + fp_led_level: args.fp_led_level, fp_brightness: args.fp_brightness, kblight: args.kblight, tablet_mode: args.tablet_mode, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 3df01887..567e9e84 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -163,7 +163,8 @@ pub struct Cli { pub input_deck_mode: Option, pub charge_limit: Option>, pub get_gpio: Option, - pub fp_brightness: Option>, + pub fp_led_level: Option>, + pub fp_brightness: Option>, pub kblight: Option>, pub tablet_mode: Option, pub console: Option, @@ -745,6 +746,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else { println!("Not found"); } + } else if let Some(maybe_led_level) = &args.fp_led_level { + print_err(handle_fp_led_level(&ec, *maybe_led_level)); } else if let Some(maybe_brightness) = &args.fp_brightness { print_err(handle_fp_brightness(&ec, *maybe_brightness)); } else if let Some(Some(kblight)) = args.kblight { @@ -1013,7 +1016,8 @@ Options: --input-deck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only) --charge-limit [] Get or set battery charge limit (Percentage number as arg, e.g. '100') --get-gpio Get GPIO value by name - --fp-brightness []Get or set fingerprint LED brightness level [possible values: high, medium, low] + --fp-led-level [] Get or set fingerprint LED brightness level [possible values: high, medium, low] + --fp-brightness []Get or set fingerprint LED brightness percentage --kblight [] Set keyboard backlight percentage or get, if no value provided --console Get EC console, choose whether recent or to follow the output [possible values: recent, follow] --hash Hash a file of arbitrary data @@ -1359,9 +1363,25 @@ fn handle_charge_limit(ec: &CrosEc, maybe_limit: Option) -> EcResult<()> { Ok(()) } -fn handle_fp_brightness(ec: &CrosEc, maybe_brightness: Option) -> EcResult<()> { +fn handle_fp_led_level(ec: &CrosEc, maybe_led_level: Option) -> EcResult<()> { + if let Some(led_level) = maybe_led_level { + ec.set_fp_led_level(led_level.into())?; + } + + let (brightness, level) = ec.get_fp_led_level()?; + // TODO: Rename to power button + println!("Fingerprint LED Brightness"); + if let Some(level) = level { + println!(" Requested: {:?}", level); + } + println!(" Brightness: {}%", brightness); + + Ok(()) +} + +fn handle_fp_brightness(ec: &CrosEc, maybe_brightness: Option) -> EcResult<()> { if let Some(brightness) = maybe_brightness { - ec.set_fp_led_level(brightness.into())?; + ec.set_fp_led_percentage(brightness)?; } let (brightness, level) = ec.get_fp_led_level()?; diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 700dff45..e826cb25 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -84,6 +84,7 @@ pub fn parse(args: &[String]) -> Cli { input_deck_mode: None, charge_limit: None, get_gpio: None, + fp_led_level: None, fp_brightness: None, kblight: None, tablet_mode: None, @@ -237,21 +238,41 @@ pub fn parse(args: &[String]) -> Cli { None }; found_an_option = true; - } else if arg == "--fp-brightness" { - cli.fp_brightness = if args.len() > i + 1 { - let fp_brightness_arg = &args[i + 1]; - if fp_brightness_arg == "high" { + } else if arg == "--fp-led-level" { + cli.fp_led_level = if args.len() > i + 1 { + let fp_led_level_arg = &args[i + 1]; + if fp_led_level_arg == "high" { Some(Some(FpBrightnessArg::High)) - } else if fp_brightness_arg == "medium" { + } else if fp_led_level_arg == "medium" { Some(Some(FpBrightnessArg::Medium)) - } else if fp_brightness_arg == "low" { + } else if fp_led_level_arg == "low" { Some(Some(FpBrightnessArg::Low)) - } else if fp_brightness_arg == "ultra-low" { + } else if fp_led_level_arg == "ultra-low" { Some(Some(FpBrightnessArg::UltraLow)) - } else if fp_brightness_arg == "auto" { + } else if fp_led_level_arg == "auto" { Some(Some(FpBrightnessArg::Auto)) } else { - println!("Invalid value for --fp-brightness: {}", fp_brightness_arg); + println!("Invalid value for --fp-led-level: {}", fp_led_level_arg); + None + } + } else { + Some(None) + }; + found_an_option = true; + } else if arg == "--fp-brightness" { + cli.fp_brightness = if args.len() > i + 1 { + if let Ok(fp_brightness_arg) = args[i + 1].parse::() { + if fp_brightness_arg == 0 || fp_brightness_arg > 100 { + println!( + "Invalid value for --fp-brightness: {}. Must be in the range of 1-100", + fp_brightness_arg + ); + None + } else { + Some(Some(fp_brightness_arg)) + } + } else { + println!("Invalid value for --fp-brightness. Must be in the range of 1-100"); None } } else { From b276fddb32b51c640e7f59d90a6c74a6799da34b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 30 Sep 2024 20:24:11 +0800 Subject: [PATCH 19/53] Add accelerometer support Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 63 ++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index b8477f63..760247c2 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -54,12 +54,13 @@ const EC_MEMMAP_BATT_SERIAL: u16 = 0x70; // Battery Serial Number String const EC_MEMMAP_BATT_TYPE: u16 = 0x78; // Battery Type String const EC_MEMMAP_ALS: u16 = 0x80; // ALS readings in lux (2 X 16 bits) // Unused 0x84 - 0x8f -const _EC_MEMMAP_ACC_STATUS: u16 = 0x90; // Accelerometer status (8 bits ) - // Unused 0x91 -const _EC_MEMMAP_ACC_DATA: u16 = 0x92; // Accelerometers data 0x92 - 0x9f - // 0x92: u16Lid Angle if available, LID_ANGLE_UNRELIABLE otherwise - // 0x94 - 0x99: u161st Accelerometer - // 0x9a - 0x9f: u162nd Accelerometer +const EC_MEMMAP_ACC_STATUS: u16 = 0x90; // Accelerometer status (8 bits ) + // Unused 0x91 +const EC_MEMMAP_ACC_DATA: u16 = 0x92; // Accelerometers data 0x92 - 0x9f + // 0x92: u16Lid Angle if available, LID_ANGLE_UNRELIABLE otherwise + // 0x94 - 0x99: u161st Accelerometer + // 0x9a - 0x9f: u162nd Accelerometer +const LID_ANGLE_UNRELIABLE: u16 = 500; const _EC_MEMMAP_GYRO_DATA: u16 = 0xa0; // Gyroscope data 0xa0 - 0xa5 // Unused 0xa6 - 0xdf @@ -163,6 +164,28 @@ impl From for ReducedPowerInfo { } } +#[derive(Debug)] +struct AccelData { + x: u16, + y: u16, + z: u16, +} +impl From> for AccelData { + fn from(t: Vec) -> Self { + Self { + x: u16::from_le_bytes([t[0], t[1]]), + y: u16::from_le_bytes([t[2], t[3]]), + z: u16::from_le_bytes([t[4], t[5]]), + } + } +} +impl fmt::Display for AccelData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "X: {:>5} Y: {:>5}, Z: {:>5}", self.x, self.y, self.z) + } +} + + fn read_string(ec: &CrosEc, address: u16) -> String { let bytes = ec.read_memory(address, EC_MEMMAP_TEXT_MAX).unwrap(); String::from_utf8_lossy(bytes.as_slice()).replace(['\0'], "") @@ -200,6 +223,34 @@ pub fn get_als_reading(ec: &CrosEc) -> Option { pub fn print_sensors(ec: &CrosEc) { let als_int = get_als_reading(ec).unwrap(); println!("ALS: {:>4} Lux", als_int); + + // bit 4 = busy + // bit 7 = present + // #define EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK 0x0f + let acc_status = ec.read_memory(EC_MEMMAP_ACC_STATUS, 0x01).unwrap()[0]; + // While busy, keep reading + + let lid_angle = ec.read_memory(EC_MEMMAP_ACC_DATA, 0x02).unwrap(); + let lid_angle = u16::from_le_bytes([lid_angle[0], lid_angle[1]]); + 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); + } + 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 d46e7410b1b981f90d4d9872bcf382246c707dc3 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 21 Oct 2024 13:35:11 +0800 Subject: [PATCH 20/53] power: AccelData values are i16 Not unsigned Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 760247c2..1650ce16 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -164,18 +164,18 @@ impl From for ReducedPowerInfo { } } -#[derive(Debug)] -struct AccelData { - x: u16, - y: u16, - z: u16, +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AccelData { + pub x: i16, + pub y: i16, + pub z: i16, } impl From> for AccelData { fn from(t: Vec) -> Self { Self { - x: u16::from_le_bytes([t[0], t[1]]), - y: u16::from_le_bytes([t[2], t[3]]), - z: u16::from_le_bytes([t[4], t[5]]), + x: i16::from_le_bytes([t[0], t[1]]), + y: i16::from_le_bytes([t[2], t[3]]), + z: i16::from_le_bytes([t[4], t[5]]), } } } From 42c580377588b8a88513b8e54b7b57dedd7fb1c9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 21 Oct 2024 13:36:05 +0800 Subject: [PATCH 21/53] power: Add function to get accel data Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 1650ce16..219d83bd 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -185,7 +185,6 @@ impl fmt::Display for AccelData { } } - fn read_string(ec: &CrosEc, address: u16) -> String { let bytes = ec.read_memory(address, EC_MEMMAP_TEXT_MAX).unwrap(); String::from_utf8_lossy(bytes.as_slice()).replace(['\0'], "") @@ -220,6 +219,25 @@ pub fn get_als_reading(ec: &CrosEc) -> Option { Some(u32::from_le_bytes([als[0], als[1], als[2], als[3]])) } +pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, u16) { + // bit 4 = busy + // bit 7 = present + // #define EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK 0x0f + let _acc_status = ec.read_memory(EC_MEMMAP_ACC_STATUS, 0x01).unwrap()[0]; + // While busy, keep reading + + let lid_angle = ec.read_memory(EC_MEMMAP_ACC_DATA, 0x02).unwrap(); + let lid_angle = u16::from_le_bytes([lid_angle[0], lid_angle[1]]); + 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(); + + // TODO: Make sure we got a new sample + // println!(" Status Bit: {} 0x{:X}", acc_status, acc_status); + // println!(" Present: {}", (acc_status & 0x80) > 0); + // println!(" Busy: {}", (acc_status & 0x8) > 0); + (AccelData::from(accel_1), AccelData::from(accel_2), lid_angle) +} + pub fn print_sensors(ec: &CrosEc) { let als_int = get_als_reading(ec).unwrap(); println!("ALS: {:>4} Lux", als_int); From f2983542411c5f7cf42c0b8c1bc3269f6207c099 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 21 Oct 2024 13:46:02 +0800 Subject: [PATCH 22/53] power: Properly encode AccelData/LidAngle Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 219d83bd..3f3e5aa0 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -185,6 +185,28 @@ impl fmt::Display for AccelData { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum LidAngle { + Angle(u16), + Unreliable, +} +impl From for LidAngle { + fn from(a: u16) -> Self { + match a { + LID_ANGLE_UNRELIABLE => Self::Unreliable, + _ => Self::Angle(a), + } + } +} +impl fmt::Display for LidAngle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Angle(deg) => write!(f, "{}", deg), + Self::Unreliable => write!(f, "Unreliable"), + } + } +} + fn read_string(ec: &CrosEc, address: u16) -> String { let bytes = ec.read_memory(address, EC_MEMMAP_TEXT_MAX).unwrap(); String::from_utf8_lossy(bytes.as_slice()).replace(['\0'], "") @@ -219,7 +241,7 @@ pub fn get_als_reading(ec: &CrosEc) -> Option { Some(u32::from_le_bytes([als[0], als[1], als[2], als[3]])) } -pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, u16) { +pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, LidAngle) { // bit 4 = busy // bit 7 = present // #define EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK 0x0f @@ -235,7 +257,11 @@ pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, u16) { // println!(" Status Bit: {} 0x{:X}", acc_status, acc_status); // println!(" Present: {}", (acc_status & 0x80) > 0); // println!(" Busy: {}", (acc_status & 0x8) > 0); - (AccelData::from(accel_1), AccelData::from(accel_2), lid_angle) + ( + AccelData::from(accel_1), + AccelData::from(accel_2), + LidAngle::from(lid_angle), + ) } pub fn print_sensors(ec: &CrosEc) { From 742f2c82ef4937080254ecf79c7d6f8e045709c9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 5 Feb 2025 18:27:53 +0800 Subject: [PATCH 23/53] framework_lib: Print accelerometer data in G It can show from -2G up to 2G. Signed-off-by: Daniel Schaefer --- framework_lib/src/power.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index 3f3e5aa0..d69dda24 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -181,7 +181,11 @@ impl From> for AccelData { } impl fmt::Display for AccelData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "X: {:>5} Y: {:>5}, Z: {:>5}", self.x, self.y, self.z) + let quarter: f32 = 0xFFFF as f32 / 4.0; + 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) } } From 26401516a721070f667da73c92dbca5b50b7d2cc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 10 Mar 2025 13:13:42 -0700 Subject: [PATCH 24/53] chromium: Add device_complete to diags Was added to EC in fwk: add device_complete 1753269e7e2c03c6ef667ae59fd594d2b753533f Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/commands.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index dfed6642..01b7f71b 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -772,6 +772,7 @@ pub struct EcRequestGetHwDiag {} pub struct EcResponseGetHwDiag { pub hw_diag: u32, pub bios_complete: u8, + pub device_complete: u8, } impl EcResponseGetHwDiag { From f31af68e8cd3e50f18b4e3e901e78d186617dedc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 20 Feb 2025 16:18:47 +0800 Subject: [PATCH 25/53] chromium_ec: Make commands it all uint16 Only code formatting difference. Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/command.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index cad2be87..e7cffeed 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -34,18 +34,18 @@ pub enum EcCommands { PwmSetDuty = 0x0025, PwmGetDuty = 0x0026, SetTabletMode = 0x0031, - GpioGet = 0x93, - I2cPassthrough = 0x9e, - ConsoleSnapshot = 0x97, - ConsoleRead = 0x98, + GpioGet = 0x0093, + I2cPassthrough = 0x009e, + ConsoleSnapshot = 0x0097, + ConsoleRead = 0x0098, /// List the features supported by the firmware - GetFeatures = 0x0D, + GetFeatures = 0x000D, /// Force reboot, causes host reboot as well - Reboot = 0xD1, + Reboot = 0x00D1, /// Control EC boot - RebootEc = 0xD2, + RebootEc = 0x00D2, /// Get information about PD controller power - UsbPdPowerInfo = 0x103, + UsbPdPowerInfo = 0x0103, // Framework specific commands /// Configure the behavior of the flash notify From a718e635b8c793ab807aae12f1a83f3811eabd17 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 20 Feb 2025 16:19:49 +0800 Subject: [PATCH 26/53] framework_lib: Add support for RgbKbdSetColor HC Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/command.rs | 2 ++ framework_lib/src/chromium_ec/commands.rs | 31 +++++++++++++++++++++++ framework_lib/src/chromium_ec/mod.rs | 15 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index e7cffeed..247ff5ee 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -46,6 +46,8 @@ pub enum EcCommands { RebootEc = 0x00D2, /// Get information about PD controller power UsbPdPowerInfo = 0x0103, + RgbKbdSetColor = 0x013A, + RgbKbd = 0x013B, // Framework specific commands /// Configure the behavior of the flash notify diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 01b7f71b..c4944db8 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -518,6 +518,37 @@ impl EcRequest for EcRequestUsbPdPowerInfo { } } +// TODO: Actually 128, but if we go above ~80 EC returns REQUEST_TRUNCATED +// At least when I use the portio driver +pub const EC_RGBKBD_MAX_KEY_COUNT: usize = 64; + +#[repr(C, packed)] +#[derive(Default, Clone, Copy, Debug)] +pub struct RgbS { + pub r: u8, + pub g: u8, + pub b: u8, +} + +#[repr(C, packed)] +pub struct EcRequestRgbKbdSetColor { + /// Specifies the starting key ID whose color is being changed + pub start_key: u8, + /// Specifies # of elements in color + pub length: u8, + /// RGB color data array of length up to MAX_KEY_COUNT + pub color: [RgbS; EC_RGBKBD_MAX_KEY_COUNT], +} + +#[repr(C, packed)] +pub struct EcResponseRgbKbdSetColor {} + +impl EcRequest for EcRequestRgbKbdSetColor { + fn command_id() -> EcCommands { + EcCommands::RgbKbdSetColor + } +} + // --- Framework Specific commands --- #[repr(C, packed)] diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 2dc53206..c7734e06 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -921,6 +921,21 @@ impl CrosEc { let res = request.send_command(self)?; Ok(res.val == 1) } + + pub fn rgbkbd_set_color(&self, start_key: u8, colors: Vec) -> EcResult<()> { + let mut request = EcRequestRgbKbdSetColor { + start_key, + length: colors.len() as u8, + color: [(); EC_RGBKBD_MAX_KEY_COUNT].map(|()| Default::default()), + }; + + for (i, color) in colors.iter().enumerate() { + request.color[i] = *color; + } + + let _res = request.send_command(self)?; + Ok(()) + } } #[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))] From b69985ae1f3ce667be3473da00c67ac4ac7f8f41 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 20 Feb 2025 16:20:21 +0800 Subject: [PATCH 27/53] Add --rgbkbd commandline Works like this: ``` > cargo build && sudo ./target/debug/framework_tool --rgbkbd 0 16711680 65280 255 ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/commandline/clap_std.rs | 9 +++++++++ framework_lib/src/commandline/mod.rs | 17 +++++++++++++++++ framework_lib/src/commandline/uefi.rs | 13 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 96b4cd6c..51837517 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -3,6 +3,7 @@ //! as well as on the UEFI shell tool. use clap::Parser; +use crate::chromium_ec::commands::EC_RGBKBD_MAX_KEY_COUNT; use crate::chromium_ec::CrosEcDriverType; use crate::commandline::{ Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg, @@ -149,6 +150,13 @@ struct ClapCli { #[arg(long)] kblight: Option>, + /// Set the color of to . Multiple colors for adjacent keys can be set at once. + /// [ ...] + /// Example: 0 0xFF000 0x00FF00 0x0000FF + #[clap(num_args = 2..EC_RGBKBD_MAX_KEY_COUNT)] + #[arg(long)] + rgbkbd: Vec, + /// Set tablet mode override #[clap(value_enum)] #[arg(long)] @@ -274,6 +282,7 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: args.fp_led_level, fp_brightness: args.fp_brightness, kblight: args.kblight, + rgbkbd: args.rgbkbd, tablet_mode: args.tablet_mode, console: args.console, reboot_ec: args.reboot_ec, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 567e9e84..01a40fe5 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -35,6 +35,7 @@ use crate::chromium_ec; use crate::chromium_ec::commands::DeckStateMode; use crate::chromium_ec::commands::FpLedBrightnessLevel; use crate::chromium_ec::commands::RebootEcCmd; +use crate::chromium_ec::commands::RgbS; use crate::chromium_ec::commands::TabletModeOverride; use crate::chromium_ec::EcResponseStatus; use crate::chromium_ec::{print_err, EcFlashType}; @@ -166,6 +167,7 @@ pub struct Cli { pub fp_led_level: Option>, pub fp_brightness: Option>, pub kblight: Option>, + pub rgbkbd: Vec, pub tablet_mode: Option, pub console: Option, pub reboot_ec: Option, @@ -753,6 +755,21 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else if let Some(Some(kblight)) = args.kblight { assert!(kblight <= 100); ec.set_keyboard_backlight(kblight); + } else if !args.rgbkbd.is_empty() { + if args.rgbkbd.len() < 2 { + println!( + "Must provide at least 2 arguments. Provided only: {}", + args.rgbkbd.len() + ); + } else { + let start_key = args.rgbkbd[0] as u8; + let colors = args.rgbkbd[1..].iter().map(|color| RgbS { + r: ((color & 0x00FF0000) >> 16) as u8, + g: ((color & 0x0000FF00) >> 8) as u8, + b: (color & 0x000000FF) as u8, + }); + ec.rgbkbd_set_color(start_key, colors.collect()).unwrap(); + } } else if let Some(None) = args.kblight { print!("Keyboard backlight: "); if let Some(percentage) = print_err(ec.get_keyboard_backlight()) { diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index e826cb25..ce350868 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -87,6 +87,7 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: None, fp_brightness: None, kblight: None, + rgbkbd: vec![], tablet_mode: None, console: None, reboot_ec: None, @@ -216,6 +217,18 @@ pub fn parse(args: &[String]) -> Cli { Some(None) }; found_an_option = true; + } else if arg == "--rgbkbd" { + cli.rgbkbd = if args.len() > i + 2 { + let mut colors = Vec::::new(); + for color_i in i + 1..args.len() { + // TODO: Fail parsing instead of unwrap() + colors.push(args[color_i].parse::().unwrap()); + } + colors + } else { + println!("--rgbkbd requires at least 2 arguments, the start key and an RGB value"); + vec![] + } } else if arg == "--tablet-mode" { cli.tablet_mode = if args.len() > i + 1 { let tablet_mode_arg = &args[i + 1]; From 054f1b8e74f2ceee91bf08dec3002bfdb615fc7e Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 23 Feb 2025 20:21:44 +0800 Subject: [PATCH 28/53] rgbkbd: Add sample script for --rgbkbd command Signed-off-by: Daniel Schaefer --- rgbkbd.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 rgbkbd.py diff --git a/rgbkbd.py b/rgbkbd.py new file mode 100755 index 00000000..9088b85e --- /dev/null +++ b/rgbkbd.py @@ -0,0 +1,37 @@ +#!/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 \ +# (./rgbkbd.py | string split ' ') + +BRIGHTNESS = 1 +RED = int(0xFF * BRIGHTNESS) << 16 +GREEN = int(0xFF * BRIGHTNESS) << 8 +BLUE = int(0xFF * BRIGHTNESS) +CYAN = GREEN + BLUE +YELLOW = RED + GREEN +PURPLE = BLUE + RED +WHITE = RED + GREEN + BLUE + +grid_4x4 = [ + [ YELLOW, RED, RED, RED, YELLOW ], + [ RED, WHITE, GREEN, WHITE, RED ], + [ RED, GREEN, BLUE, GREEN, RED ], + [ RED, WHITE, GREEN, WHITE, RED ], + [ YELLOW, RED, RED, RED, YELLOW ], +] + +fan_8leds = [[ + # WHITE, CYAN, BLUE, GREEN, PURPLE, RED, YELLOW, WHITE + RED, RED, RED, RED, + GREEN, GREEN, GREEN, GREEN +]] + +# colors = grid_4x4 +colors = fan_8leds + +print('--rgbkbd 0', end='') +for row in colors: + for col in row: + print(' ', end='') + print(col, end='') From 9324ad44dbd1f0f26df1541d589acaffc8986b74 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 4 Mar 2025 10:11:50 +0800 Subject: [PATCH 29/53] rgbkbd: Accept hex values ``` sudo framework_tool --rgbkbd 0 0xFF0000 0x00FF00 0x0000FF ``` Signed-off-by: Daniel Schaefer --- Cargo.lock | 10 ++++++++++ framework_lib/Cargo.toml | 3 ++- framework_lib/src/commandline/clap_std.rs | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30842e31..10110b18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,15 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-num" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822c4000301ac390e65995c62207501e3ef800a1fc441df913a5e8e4dc374816" +dependencies = [ + "num-traits", +] + [[package]] name = "clap-verbosity-flag" version = "2.2.1" @@ -383,6 +392,7 @@ version = "0.2.1" dependencies = [ "built", "clap", + "clap-num", "clap-verbosity-flag", "env_logger", "guid_macros", diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 81db759a..fb5096ca 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -18,7 +18,7 @@ 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-verbosity-flag", "dep:env_logger", "smbios-lib?/std"] +std = ["dep:clap", "dep:clap-num", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std"] rusb = ["dep:rusb"] hidapi = ["dep:hidapi"] uefi = [ @@ -51,6 +51,7 @@ 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"], 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 } diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 51837517..6fafdc67 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -2,6 +2,7 @@ //! This way we can use it in the regular OS commandline tool on Linux and Windows, //! as well as on the UEFI shell tool. use clap::Parser; +use clap_num::maybe_hex; use crate::chromium_ec::commands::EC_RGBKBD_MAX_KEY_COUNT; use crate::chromium_ec::CrosEcDriverType; @@ -154,7 +155,7 @@ struct ClapCli { /// [ ...] /// Example: 0 0xFF000 0x00FF00 0x0000FF #[clap(num_args = 2..EC_RGBKBD_MAX_KEY_COUNT)] - #[arg(long)] + #[arg(long, value_parser=maybe_hex::)] rgbkbd: Vec, /// Set tablet mode override From 0424c811e2dccf49e801b33df75b5954ea01b38b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 17 Mar 2025 10:58:18 +0800 Subject: [PATCH 30/53] rgbkbd: Send unlimited number of LEDs with multiple HCs Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 20 +++++++++++--------- framework_lib/src/commandline/clap_std.rs | 3 +-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index c7734e06..05713c34 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -923,17 +923,19 @@ impl CrosEc { } pub fn rgbkbd_set_color(&self, start_key: u8, colors: Vec) -> EcResult<()> { - let mut request = EcRequestRgbKbdSetColor { - start_key, - length: colors.len() as u8, - color: [(); EC_RGBKBD_MAX_KEY_COUNT].map(|()| Default::default()), - }; + for (chunk, colors) in colors.chunks(EC_RGBKBD_MAX_KEY_COUNT).enumerate() { + let mut request = EcRequestRgbKbdSetColor { + start_key: start_key + ((chunk * EC_RGBKBD_MAX_KEY_COUNT) as u8), + length: colors.len() as u8, + color: [(); EC_RGBKBD_MAX_KEY_COUNT].map(|()| Default::default()), + }; - for (i, color) in colors.iter().enumerate() { - request.color[i] = *color; - } + for (i, color) in colors.iter().enumerate() { + request.color[i] = *color; + } - let _res = request.send_command(self)?; + let _res = request.send_command(self)?; + } Ok(()) } } diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 6fafdc67..96249b8e 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -4,7 +4,6 @@ use clap::Parser; use clap_num::maybe_hex; -use crate::chromium_ec::commands::EC_RGBKBD_MAX_KEY_COUNT; use crate::chromium_ec::CrosEcDriverType; use crate::commandline::{ Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg, @@ -154,7 +153,7 @@ struct ClapCli { /// Set the color of to . Multiple colors for adjacent keys can be set at once. /// [ ...] /// Example: 0 0xFF000 0x00FF00 0x0000FF - #[clap(num_args = 2..EC_RGBKBD_MAX_KEY_COUNT)] + #[clap(num_args = 2..)] #[arg(long, value_parser=maybe_hex::)] rgbkbd: Vec, From 52b1c47658123cb610dbd9ffb4fa740b2ac86409 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 21 Mar 2025 15:59:29 +0800 Subject: [PATCH 31/53] freebsd: Build with latest stable on gh actions Signed-off-by: Daniel Schaefer --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdadf0df..da60cb70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Rust toolchain run: | rm rust-toolchain.toml - rustup toolchain install 1.75.0-x86_64-unknown-freebsd + rustup target add x86_64-unknown-freebsd rustup show - name: Install cross compilation tool From a83ec0c191fc7ebf32b8109c5a217d2ae0cad82a Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 21 Mar 2025 03:26:52 +0800 Subject: [PATCH 32/53] camera: Print firmware of camera Example on Framework 12: ``` > framework_tool --versions [...] Framework Laptop 12 Webcam Module Firmware Version: 0.1.6 ``` Example on Framework 13: ``` > framework_tool --versions [...] Laptop Webcam Module (2nd Gen) Firmware Version: 1.1.1 ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/camera.rs | 29 ++++++++++++++++++++++++++++ framework_lib/src/commandline/mod.rs | 4 ++++ framework_lib/src/lib.rs | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 framework_lib/src/camera.rs diff --git a/framework_lib/src/camera.rs b/framework_lib/src/camera.rs new file mode 100644 index 00000000..0c4b6c36 --- /dev/null +++ b/framework_lib/src/camera.rs @@ -0,0 +1,29 @@ +pub const FRAMEWORK_VID: u16 = 0x32AC; +pub const FRAMEWORK13_16_2ND_GEN_PID: u16 = 0x001C; +pub const FRAMEWORK12_PID: u16 = 0x001D; + +/// Get and print the firmware version of the camera +pub fn check_camera_version() { + for dev in rusb::devices().unwrap().iter() { + let dev_descriptor = dev.device_descriptor().unwrap(); + if dev_descriptor.vendor_id() != FRAMEWORK_VID + || (dev_descriptor.product_id() != FRAMEWORK13_16_2ND_GEN_PID + && dev_descriptor.product_id() != FRAMEWORK12_PID) + { + debug!( + "Skipping {:04X}:{:04X}", + dev_descriptor.vendor_id(), + dev_descriptor.product_id() + ); + continue; + } + let handle = dev.open().unwrap(); + + let dev_descriptor = dev.device_descriptor().unwrap(); + let i_product = dev_descriptor + .product_string_index() + .and_then(|x| handle.read_string_descriptor_ascii(x).ok()); + println!("{}", i_product.unwrap_or_default()); + println!(" Firmware Version: {}", dev_descriptor.device_version()); + } +} diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 01a40fe5..c134bb09 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -23,6 +23,8 @@ use std::io::prelude::*; #[cfg(feature = "rusb")] use crate::audio_card::check_synaptics_fw_version; use crate::built_info; +#[cfg(feature = "rusb")] +use crate::camera::check_camera_version; use crate::capsule; use crate::capsule_content::{ find_bios_version, find_ec_in_bios_cap, find_pd_in_bios_cap, find_retimer_version, @@ -470,6 +472,8 @@ fn print_versions(ec: &CrosEc) { println!(" Unknown"); } } + #[cfg(feature = "rusb")] + check_camera_version(); } fn print_esrt() { diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 40be376d..a5c4e71d 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -14,6 +14,8 @@ extern crate log; #[cfg(feature = "rusb")] pub mod audio_card; +#[cfg(feature = "rusb")] +pub mod camera; #[cfg(feature = "uefi")] #[macro_use] From 95cbdc3cc091b33b22ace0a5bbcb627c767549a1 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 23:13:42 +0800 Subject: [PATCH 33/53] ccgx: Extract CCG8 PD version from capsule ``` > framework_tool --ho2-capsule Framework_Laptop_13_Ryzen7040_capsule_signed_allsku_3.08.cap [...] Detected CCG8 firmware FW 1 Silicon ID: 0x11c5 Silicon Family: 0x3580 Version: 0.0.1C Base Ver: 3.7.0.0D0 Row size: 256 B Start Row: 290 Rows: 474 Size: 121444 B Size: 118 KB FW 2 Silicon ID: 0x11c5 Silicon Family: 0x3580 Version: 0.0.1C Base Ver: 3.7.0.0D0 Row size: 256 B Start Row: 29 Rows: 175 Size: 45024 B Size: 43 KB ``` Signed-off-by: Daniel Schaefer --- README.md | 2 +- framework_lib/src/capsule_content.rs | 5 ++++- framework_lib/src/ccgx/binary.rs | 5 +++-- framework_lib/src/commandline/mod.rs | 5 ++++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1c454543..88b90844 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ see the [Support Matrices](support-matrices.md). - [x] HO2 BIOS Capsule (`--ho2-capsule`) - [x] BIOS Version - [x] EC Version - - [x] CCG5/CCG6 PD Version + - [x] CCG5/CCG6/CCG8 PD Version - [x] UEFI Capsule (`--capsule`) - [x] Parse metadata from capsule binary - [x] Determine type (GUID) of capsule binary diff --git a/framework_lib/src/capsule_content.rs b/framework_lib/src/capsule_content.rs index ca9d9ec6..cceb7ed1 100644 --- a/framework_lib/src/capsule_content.rs +++ b/framework_lib/src/capsule_content.rs @@ -8,7 +8,7 @@ use crate::alloc::string::ToString; use alloc::string::String; use core::convert::TryInto; -use crate::ccgx::binary::{CCG5_PD_LEN, CCG6_PD_LEN}; +use crate::ccgx::binary::{CCG5_PD_LEN, CCG6_PD_LEN, CCG8_PD_LEN}; use crate::ec_binary::EC_LEN; use crate::util; @@ -57,10 +57,13 @@ pub fn find_pd_in_bios_cap(data: &[u8]) -> Option<&[u8]> { // they're the same version let ccg5_needle = &[0x00, 0x20, 0x00, 0x20, 0x11, 0x00]; let ccg6_needle = &[0x00, 0x40, 0x00, 0x20, 0x11, 0x00]; + let ccg8_needle = &[0x00, 0x80, 0x00, 0x20, 0xAD, 0x0C]; if let Some(found_pd1) = util::find_sequence(data, ccg5_needle) { Some(&data[found_pd1..found_pd1 + CCG5_PD_LEN]) } else if let Some(found_pd1) = util::find_sequence(data, ccg6_needle) { Some(&data[found_pd1..found_pd1 + CCG6_PD_LEN]) + } else if let Some(found_pd1) = util::find_sequence(data, ccg8_needle) { + Some(&data[found_pd1..found_pd1 + CCG8_PD_LEN]) } else { None } diff --git a/framework_lib/src/ccgx/binary.rs b/framework_lib/src/ccgx/binary.rs index acb9c51a..09c16855 100644 --- a/framework_lib/src/ccgx/binary.rs +++ b/framework_lib/src/ccgx/binary.rs @@ -53,8 +53,9 @@ struct VersionInfo { silicon_family: u16, } -pub const CCG5_PD_LEN: usize = 0x2_0000; -pub const CCG6_PD_LEN: usize = 0x2_0000; +pub const CCG5_PD_LEN: usize = 0x20_000; +pub const CCG6_PD_LEN: usize = 0x20_000; +pub const CCG8_PD_LEN: usize = 0x40_000; /// Information about all the firmware in a PD binary file /// diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 01a40fe5..d08a6dc7 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -957,7 +957,10 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { analyze_ec_fw(ec_bin); } if let Some(pd_bin) = find_pd_in_bios_cap(&data) { + debug!("Found PD binary in BIOS capsule"); analyze_ccgx_pd_fw(pd_bin); + } else { + debug!("Didn't find PD binary in BIOS capsule"); } } } else if let Some(dump_path) = &args.dump_ec_flash { @@ -1280,7 +1283,7 @@ fn analyze_ccgx_pd_fw(data: &[u8]) { ccgx::binary::print_fw(&versions.main_fw); return; } else { - println!("Failed to read versions") + println!("Failed to read PD versions") } } From 12b39558618469dd79444ec16dfeb13f3c0c71fe Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 23:27:15 +0800 Subject: [PATCH 34/53] capsule: Fix reading BIOS platform and version Can't believe it has never been correct... ``` > framework_tool --ho2-capsule Framework_Laptop_13_12th_Gen_Intel_Core_capsule_signed_allsku_3.09.cap File Size: 36130244 B Size: 35283 KB BIOS Platform: HFW30 BIOS Version: 03.09 [...] > framework_tool --ho2-capsule Framework_Laptop_13_Ryzen7040_capsule_signed_allsku_3.08.cap File Size: 36129956 B Size: 35283 KB BIOS Platform: JFP30 BIOS Version: 03.08 [...] ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/capsule_content.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/framework_lib/src/capsule_content.rs b/framework_lib/src/capsule_content.rs index cceb7ed1..5dfe5241 100644 --- a/framework_lib/src/capsule_content.rs +++ b/framework_lib/src/capsule_content.rs @@ -29,13 +29,14 @@ pub fn find_bios_version(data: &[u8]) -> Option { let needle = b"$BVDT"; let found = util::find_sequence(data, needle)?; + // One of: GFW30, HFW3T, HFW30, IFR30, KFM30, JFP30, LFK30, IFGA3, IFGP6, LFR20, LFSP0 let platform_offset = found + 0xA + needle.len() - 1; - let platform = std::str::from_utf8(&data[platform_offset..platform_offset + 4]) + let platform = std::str::from_utf8(&data[platform_offset..platform_offset + 5]) .map(|x| x.to_string()) .ok()?; - let ver_offset = found + 0xE + needle.len() - 1; - let version = std::str::from_utf8(&data[ver_offset..ver_offset + 4]) + let ver_offset = found + 0x10 + needle.len() - 1; + let version = std::str::from_utf8(&data[ver_offset..ver_offset + 5]) .map(|x| x.to_string()) .ok()?; From 721a938bbb8b54f75cc8471df418c9beb512a0f8 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 23:33:38 +0800 Subject: [PATCH 35/53] It's H2O, not HO2 Signed-off-by: Daniel Schaefer --- README.md | 4 ++-- framework_lib/src/commandline/clap_std.rs | 6 +++--- framework_lib/src/commandline/mod.rs | 13 ++++++++----- framework_lib/src/commandline/uefi.rs | 8 ++++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 88b90844..f9089bb6 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ see the [Support Matrices](support-matrices.md). - [x] CCG5 PD (11th Gen TigerLake) (`--pd-bin`) - [x] CCG6 PD (12th Gen AlderLake) (`--pd-bin`) - [x] CCG8 PD (Framework 16) (`--pd-bin`) - - [x] HO2 BIOS Capsule (`--ho2-capsule`) + - [x] H2O BIOS Capsule (`--h2o-capsule`) - [x] BIOS Version - [x] EC Version - [x] CCG5/CCG6/CCG8 PD Version @@ -182,7 +182,7 @@ Options: --ec-bin Parse versions from EC firmware binary file --capsule Parse UEFI Capsule information from binary file --dump Dump extracted UX capsule bitmap image to a file - --ho2-capsule Parse UEFI Capsule information from binary file + --h2o-capsule Parse UEFI Capsule information from binary file --intrusion Show status of intrusion switch --inputmodules Show status of the input modules (Framework 16 only) --kblight [] Set keyboard backlight percentage or get, if no value provided diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 96249b8e..f9299e6d 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -100,7 +100,7 @@ struct ClapCli { /// Parse UEFI Capsule information from binary file #[arg(long)] - ho2_capsule: Option, + h2o_capsule: Option, /// Dump EC flash contents #[arg(long)] @@ -259,8 +259,8 @@ pub fn parse(args: &[String]) -> Cli { .capsule .map(|x| x.into_os_string().into_string().unwrap()), dump: args.dump.map(|x| x.into_os_string().into_string().unwrap()), - ho2_capsule: args - .ho2_capsule + h2o_capsule: args + .h2o_capsule .map(|x| x.into_os_string().into_string().unwrap()), dump_ec_flash: args .dump_ec_flash diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index d08a6dc7..c42d97d9 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -152,7 +152,7 @@ pub struct Cli { pub ec_bin: Option, pub capsule: Option, pub dump: Option, - pub ho2_capsule: Option, + pub h2o_capsule: Option, pub dump_ec_flash: Option, pub flash_ec: Option, pub flash_ro_ec: Option, @@ -932,7 +932,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { println!("Capsule is invalid."); } } - } else if let Some(capsule_path) = &args.ho2_capsule { + } else if let Some(capsule_path) = &args.h2o_capsule { #[cfg(feature = "uefi")] let data = crate::uefi::fs::shell_read_file(capsule_path); #[cfg(not(feature = "uefi"))] @@ -954,7 +954,10 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { println!(" BIOS Version: {:>18}", cap.version); } if let Some(ec_bin) = find_ec_in_bios_cap(&data) { + debug!("Found EC binary in BIOS capsule"); analyze_ec_fw(ec_bin); + } else { + debug!("Didn't find EC binary in BIOS capsule"); } if let Some(pd_bin) = find_pd_in_bios_cap(&data) { debug!("Found PD binary in BIOS capsule"); @@ -1025,7 +1028,7 @@ Options: --ec-bin Parse versions from EC firmware binary file --capsule Parse UEFI Capsule information from binary file --dump Dump extracted UX capsule bitmap image to a file - --ho2-capsule Parse UEFI Capsule information from binary file + --h2o-capsule Parse UEFI Capsule information from binary file --dump-ec-flash Dump EC flash contents --flash-ec Flash EC with new firmware from file --flash-ro-ec Flash EC with new firmware from file @@ -1292,13 +1295,13 @@ pub fn analyze_ec_fw(data: &[u8]) { if let Some(ver) = ec_binary::read_ec_version(data, true) { ec_binary::print_ec_version(&ver, true); } else { - println!("Failed to read version") + println!("Failed to read EC version") } // Readwrite firmware if let Some(ver) = ec_binary::read_ec_version(data, false) { ec_binary::print_ec_version(&ver, false); } else { - println!("Failed to read version") + println!("Failed to read EC version") } } diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index ce350868..261720fc 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -78,7 +78,7 @@ pub fn parse(args: &[String]) -> Cli { flash_rw_ec: None, capsule: None, dump: None, - ho2_capsule: None, + h2o_capsule: None, intrusion: false, inputmodules: false, input_deck_mode: None, @@ -374,11 +374,11 @@ pub fn parse(args: &[String]) -> Cli { None }; found_an_option = true; - } else if arg == "--ho2-capsule" { - cli.ho2_capsule = if args.len() > i + 1 { + } else if arg == "--h2o-capsule" { + cli.h2o_capsule = if args.len() > i + 1 { Some(args[i + 1].clone()) } else { - println!("--ho2-capsule requires extra argument to denote input file"); + println!("--h2o-capsule requires extra argument to denote input file"); None }; found_an_option = true; From f8a80adad9268a55d03e82700e0e31dc0722a47b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 23:44:48 +0800 Subject: [PATCH 36/53] capsule: Fix EC version detection for Zephyr based Now it can work for both legacy and zephyr based ECs. Tested on Intel 12th gen, AMD Ryzen 7040, AMD Ryzen AI 300, Framework Desktop. ``` > framework_tool --h2o-capsule Framework_Laptop_13_Ryzen7040_capsule_signed_allsku_3.08.cap [...] EC Type: RO Version: azalea_v3.4.113382-ec:ec916d,os RollbackVer: 0 Platform: azalea Version: 3.4.113382 Commit: ec916d Size: 258048 B Size: 252 KB EC Type: RW Version: azalea_v3.4.113382-ec:ec916d,os RollbackVer: 0 Platform: azalea Version: 3.4.113382 Commit: ec916d Size: 258048 B Size: 252 KB [...] ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/capsule_content.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/framework_lib/src/capsule_content.rs b/framework_lib/src/capsule_content.rs index 5dfe5241..81199bda 100644 --- a/framework_lib/src/capsule_content.rs +++ b/framework_lib/src/capsule_content.rs @@ -44,12 +44,10 @@ pub fn find_bios_version(data: &[u8]) -> Option { } pub fn find_ec_in_bios_cap(data: &[u8]) -> Option<&[u8]> { - let needle = b"_IFLASH_EC_IMG_"; - let found_iflash = util::find_sequence(data, needle)?; - // The actual EC binary is a few bytes after `_IFLASH_EC_IMG_`. - // Just earch for the first 4 bytes that seem to appear in all EC images. - let found = util::find_sequence(&data[found_iflash..], &[0x10, 0x00, 0x00, 0xf7])?; - Some(&data[found_iflash + found..found_iflash + found + EC_LEN]) + let needle = b"$_IFLASH_EC_IMG_"; + let found = util::find_sequence(data, needle)?; + let ec_offset = found + 0x9 + needle.len() - 1; + Some(&data[ec_offset..ec_offset + EC_LEN]) } pub fn find_pd_in_bios_cap(data: &[u8]) -> Option<&[u8]> { From 4ba840d437e78847498cd1b816555a220b285db2 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 23:47:28 +0800 Subject: [PATCH 37/53] README: Update to latest status Signed-off-by: Daniel Schaefer --- README.md | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f9089bb6..28a10603 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,10 @@ see the [Support Matrices](support-matrices.md). - [x] ESRT table (UEFI, Linux, FreeBSD only) (`--esrt`) - [x] SMBIOS - [x] Get firmware version from binary file - - [x] Legacy EC (Intel 13th Gen and earlier) (`--ec-bin`) - - [x] Zephyr EC (AMD) (`--ec-bin`) + - [x] EC (Legacy and Zephyr based) (`--ec-bin`) - [x] CCG5 PD (11th Gen TigerLake) (`--pd-bin`) - - [x] CCG6 PD (12th Gen AlderLake) (`--pd-bin`) - - [x] CCG8 PD (Framework 16) (`--pd-bin`) + - [x] CCG6 PD (Intel systems, Framework Desktop) (`--pd-bin`) + - [x] CCG8 PD (AMD Laptops) (`--pd-bin`) - [x] H2O BIOS Capsule (`--h2o-capsule`) - [x] BIOS Version - [x] EC Version @@ -53,16 +52,6 @@ see the [Support Matrices](support-matrices.md). - [x] DisplayPort Expansion Card (`--dp-hdmi-update`) - [ ] Audio Expansion Card -###### Firmware Update - -Note: Use fwupd. - -- [ ] Flash firmware - - [ ] BIOS - - [ ] EC - - [ ] PD - - [ ] Expansion Cards - ###### System Status All of these need EC communication support in order to work. @@ -90,6 +79,7 @@ All of these need EC communication support in order to work. - [x] Framework Desktop (AMD Ryzen AI Max 300) - [x] Port I/O communication on Linux - [x] Port I/O communication in UEFI +- [x] Port I/O communication on FreeBSD - [x] Using `cros_ec` driver in Linux kernel - [x] Using [Framework EC Windows driver](https://github.com/FrameworkComputer/crosecbus) based on [coolstar's](https://github.com/coolstar/crosecbus) - [x] Using [DHowett's Windows CrosEC driver](https://github.com/DHowett/FrameworkWindowsUtils) From 35b4d4e88b9a873311570e5363722647ddd82bcc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 24 Mar 2025 22:54:10 +0800 Subject: [PATCH 38/53] camera: Don't crash if something's wrong Signed-off-by: Daniel Schaefer --- framework_lib/src/camera.rs | 5 +++-- framework_lib/src/commandline/mod.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/framework_lib/src/camera.rs b/framework_lib/src/camera.rs index 0c4b6c36..c99d9915 100644 --- a/framework_lib/src/camera.rs +++ b/framework_lib/src/camera.rs @@ -3,7 +3,7 @@ pub const FRAMEWORK13_16_2ND_GEN_PID: u16 = 0x001C; pub const FRAMEWORK12_PID: u16 = 0x001D; /// Get and print the firmware version of the camera -pub fn check_camera_version() { +pub fn check_camera_version() -> Result<(), rusb::Error> { for dev in rusb::devices().unwrap().iter() { let dev_descriptor = dev.device_descriptor().unwrap(); if dev_descriptor.vendor_id() != FRAMEWORK_VID @@ -19,11 +19,12 @@ pub fn check_camera_version() { } let handle = dev.open().unwrap(); - let dev_descriptor = dev.device_descriptor().unwrap(); + let dev_descriptor = dev.device_descriptor()?; let i_product = dev_descriptor .product_string_index() .and_then(|x| handle.read_string_descriptor_ascii(x).ok()); println!("{}", i_product.unwrap_or_default()); println!(" Firmware Version: {}", dev_descriptor.device_version()); } + Ok(()) } diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index c134bb09..20d77a81 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -473,7 +473,7 @@ fn print_versions(ec: &CrosEc) { } } #[cfg(feature = "rusb")] - check_camera_version(); + let _ignore_err = check_camera_version(); } fn print_esrt() { From 56d9022811f46e7035df345870d85995bc09ca6f Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 22 Mar 2025 00:11:41 +0800 Subject: [PATCH 39/53] touchpad: Show IC type and firmware version Example on Framework 13: ``` > framework_tool --version [...] Touchpad IC Type: 0274 Firmware Version: v0704 ``` Signed-off-by: Daniel Schaefer --- README.md | 1 + framework_lib/src/commandline/mod.rs | 5 +++ framework_lib/src/lib.rs | 2 + framework_lib/src/touchpad.rs | 65 ++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 framework_lib/src/touchpad.rs diff --git a/README.md b/README.md index 1c454543..01d2205e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ see the [Support Matrices](support-matrices.md). - [x] PD - [x] ME (Only on Linux) - [x] Retimer + - [x] Touchpad (Linux and Windows) - [x] Get Expansion Card Firmware (Not on UEFI so far) - [x] HDMI Expansion Card (`--dp-hdmi-info`) - [x] DisplayPort Expansion Card (`--dp-hdmi-info`) diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 20d77a81..bd5302eb 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -50,6 +50,8 @@ use crate::power; use crate::smbios; 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(feature = "uefi")] use crate::uefi::enable_page_break; use crate::util; @@ -474,6 +476,9 @@ fn print_versions(ec: &CrosEc) { } #[cfg(feature = "rusb")] let _ignore_err = check_camera_version(); + + #[cfg(feature = "hidapi")] + let _ignore_err = print_touchpad_fw_ver(); } fn print_esrt() { diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index a5c4e71d..50fa9b03 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -16,6 +16,8 @@ extern crate log; pub mod audio_card; #[cfg(feature = "rusb")] pub mod camera; +#[cfg(feature = "hidapi")] +pub mod touchpad; #[cfg(feature = "uefi")] #[macro_use] diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs new file mode 100644 index 00000000..fe4be04d --- /dev/null +++ b/framework_lib/src/touchpad.rs @@ -0,0 +1,65 @@ +use hidapi::{HidApi, HidDevice, HidError}; + +pub const PIX_VID: u16 = 0x093A; +pub const PIX_REPORT_ID: u8 = 0x43; + +fn read_byte(device: &HidDevice, addr: u8) -> Result { + device.send_feature_report(&[PIX_REPORT_ID, addr, 0x10, 0])?; + + let mut buf = [0u8; 4]; + buf[0] = PIX_REPORT_ID; + + device.get_feature_report(&mut buf)?; + Ok(buf[3]) +} + +fn read_ver(device: &HidDevice) -> Result { + Ok(u16::from_le_bytes([ + read_byte(device, 0xb2)?, + read_byte(device, 0xb3)?, + ])) +} + +pub fn print_touchpad_fw_ver() -> Result<(), HidError> { + debug!("Looking for touchpad HID device"); + match HidApi::new() { + Ok(api) => { + for dev_info in api.device_list() { + let vid = dev_info.vendor_id(); + let pid = dev_info.product_id(); + let usage_page = dev_info.usage_page(); + + debug!( + " Found {:04X}:{:04X} (Usage Page {:04X})", + vid, pid, usage_page + ); + if vid != PIX_VID || (pid != 0x0274 && pid != 0x0239) { + debug!( + " Skipping VID:PID. Expected {:04X}:{:04X}/{:04X}", + PIX_VID, 0x0274, 0x0239 + ); + continue; + } + if usage_page != 0xFF00 { + debug!(" Skipping usage page. Expected {:04X}", 0xFF00); + continue; + } + + debug!(" Found matching touchpad HID device"); + let device = dev_info.open_device(&api).unwrap(); + + println!("Touchpad"); + println!(" IC Type: {:04X}", pid); + println!(" Firmware Version: v{:04X}", read_ver(&device)?); + // If we found one, there's no need to look for more + return Ok(()); + } + } + Err(e) => { + eprintln!("Failed to open hidapi. Error: {e}"); + return Err(e); + } + }; + + Ok(()) +} From 4aa392adb830bfdd55e616b16734485c7a2dc4b3 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 29 Mar 2025 19:05:13 +0800 Subject: [PATCH 40/53] windows: Upload release binary So that the vcruntime DLL is built in and runs on freshly installed windows systems. Signed-off-by: Daniel Schaefer --- .github/workflows/ci.yml | 10 +++++++--- framework_tool/Cargo.toml | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da60cb70..2a261d25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,20 +91,24 @@ jobs: - name: Setup Rust toolchain run: rustup show + # Build debug library first to fail fast - name: Build library (Windows) run: cargo build -p framework_lib --no-default-features --features "windows" - name: Build Windows tool - run: cargo build -p framework_tool --no-default-features --features "windows" + run: | + cargo build -p framework_tool --no-default-features --features "windows" + cargo build -p framework_tool --no-default-features --features "windows" --release - name: Check if Windows tool can start - run: cargo run --no-default-features --features "windows" -- --help + run: cargo run --no-default-features --features "windows" -- --help --release + # Upload release build so that vcruntime is statically linked - name: Upload Windows App uses: actions/upload-artifact@v4 with: name: framework_tool.exe - path: target/debug/framework_tool.exe + path: target/release/framework_tool.exe test: diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index f4d3bfa9..1a6d4dec 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -14,4 +14,5 @@ path = "../framework_lib" default-features = false [build-dependencies] +# Note: Only takes effect in release builds static_vcruntime = "2.0" From 8454d666a35527ecee9c6ffba716891d53ef8621 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 10 Apr 2025 11:53:37 +0800 Subject: [PATCH 41/53] chromium_mod: First convert then slice More efficient. Highlighted by new clippy lint: ``` error: calling `as_bytes` after slicing a string --> framework_lib/src/chromium_ec/mod.rs:919:45 | 919 | request.name[..end].copy_from_slice(name[..end].as_bytes()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&name.as_bytes()[..end]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#sliced_string_as_bytes = note: `-D clippy::sliced-string-as-bytes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::sliced_string_as_bytes)]` ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 05713c34..17702689 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -916,7 +916,7 @@ impl CrosEc { let mut request = EcRequestGpioGetV0 { name: [0; MAX_LEN] }; let end = MAX_LEN.min(name.len()); - request.name[..end].copy_from_slice(name[..end].as_bytes()); + request.name[..end].copy_from_slice(&name.as_bytes()[..end]); let res = request.send_command(self)?; Ok(res.val == 1) From aa45491f9fe09ce6630d03bcaf4ce321e094a8f5 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 17 Jul 2024 14:13:25 +0800 Subject: [PATCH 42/53] windows: Don't panic if driver not installed Trying it out without running as admin to cause it to fail accessing the driver. ``` > cargo run --no-default-features --features "windows" -p framework_tool -- --test Self-Test SMBIOS Platform: Framework13AmdAi300 Dump EC memory region [ERROR] Failed to find Windows driver. Error { code: HRESULT(0x80070005), message: "Access is denied." } [ERROR] Failed to communicate with EC. Reason: "Failed to initialize" Failed to read EC memory region FAILED!! Error: "Fail" error: process didn't exit successfully: `target\debug\framework_tool.exe --test` (exit code: 1) > cargo run --no-default-features --features "windows" -p framework_tool -- --test Self-Test SMBIOS Platform: Framework13AmdAi300 Dump EC memory region thread 'main' panicked at framework_lib\src\chromium_ec\windows.rs:46:14: called `Result::unwrap()` on an `Err` value: Error { code: HRESULT(0x80070005), message: "Access is denied." } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: process didn't exit successfully: `target\debug\framework_tool.exe --test` (exit code: 101) ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/windows.rs | 43 ++++++++++++++---------- framework_lib/src/commandline/mod.rs | 3 +- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/framework_lib/src/chromium_ec/windows.rs b/framework_lib/src/chromium_ec/windows.rs index 4e026663..6cd2db33 100644 --- a/framework_lib/src/chromium_ec/windows.rs +++ b/framework_lib/src/chromium_ec/windows.rs @@ -25,31 +25,40 @@ lazy_static! { static ref DEVICE: Arc>> = Arc::new(Mutex::new(None)); } -fn init() { +fn init() -> bool { let mut device = DEVICE.lock().unwrap(); if (*device).is_some() { - return; + return true; } let path = w!(r"\\.\GLOBALROOT\Device\CrosEC"); - unsafe { - *device = Some(DevHandle( - CreateFileW( - path, - FILE_GENERIC_READ.0 | FILE_GENERIC_WRITE.0, - FILE_SHARE_READ | FILE_SHARE_WRITE, - None, - OPEN_EXISTING, - FILE_FLAGS_AND_ATTRIBUTES(0), - None, - ) - .unwrap(), - )); - } + let res = unsafe { + CreateFileW( + path, + FILE_GENERIC_READ.0 | FILE_GENERIC_WRITE.0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + None, + OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES(0), + None, + ) + }; + let handle = match res { + Ok(h) => h, + Err(err) => { + error!("Failed to find Windows driver. {:?}", err); + return false; + } + }; + + *device = Some(DevHandle(handle)); + true } pub fn read_memory(offset: u16, length: u16) -> EcResult> { - init(); + if !init() { + return Err(EcError::DeviceError("Failed to initialize".to_string())); + } let mut rm = CrosEcReadMem { offset: offset as u32, bytes: length as u32, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 6dc42884..fa284951 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -1111,7 +1111,8 @@ fn selftest(ec: &CrosEc) -> Option<()> { if let Some(mem) = ec.dump_mem_region() { util::print_multiline_buffer(&mem, 0); } else { - println!(" Failed to read EC memory region") + println!(" Failed to read EC memory region"); + return None; } println!(" Checking EC memory mapped magic bytes"); From de3fd04ac7d8cb980f8fef90c85ecc61823567d9 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Tue, 25 Mar 2025 13:41:09 +0800 Subject: [PATCH 43/53] framework12: Support reading touchpad version Must already be on firmware 0E06 or higher. ``` > framework_tool --versions [...] Touchpad IC Type: 0239 Firmware Version: v0E06 ``` Signed-off-by: Daniel Schaefer --- framework_lib/src/touchpad.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index fe4be04d..e3c2f4da 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -1,22 +1,30 @@ use hidapi::{HidApi, HidDevice, HidError}; pub const PIX_VID: u16 = 0x093A; -pub const PIX_REPORT_ID: u8 = 0x43; +pub const P274_REPORT_ID: u8 = 0x43; +pub const P239_REPORT_ID: u8 = 0x42; -fn read_byte(device: &HidDevice, addr: u8) -> Result { - device.send_feature_report(&[PIX_REPORT_ID, addr, 0x10, 0])?; +fn read_byte(device: &HidDevice, report_id: u8, addr: u8) -> Result { + device.send_feature_report(&[report_id, addr, 0x10, 0])?; let mut buf = [0u8; 4]; - buf[0] = PIX_REPORT_ID; + buf[0] = report_id; device.get_feature_report(&mut buf)?; Ok(buf[3]) } -fn read_ver(device: &HidDevice) -> Result { +fn read_239_ver(device: &HidDevice) -> Result { Ok(u16::from_le_bytes([ - read_byte(device, 0xb2)?, - read_byte(device, 0xb3)?, + read_byte(device, P239_REPORT_ID, 0x16)?, + read_byte(device, P239_REPORT_ID, 0x18)?, + ])) +} + +fn read_274_ver(device: &HidDevice) -> Result { + Ok(u16::from_le_bytes([ + read_byte(device, P274_REPORT_ID, 0xb2)?, + read_byte(device, P274_REPORT_ID, 0xb3)?, ])) } @@ -50,7 +58,13 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { println!("Touchpad"); println!(" IC Type: {:04X}", pid); - println!(" Firmware Version: v{:04X}", read_ver(&device)?); + let ver = match pid { + 0x0239 => format!("{:04X}", read_239_ver(&device)?), + 0x0274 => format!("{:04X}", read_274_ver(&device)?), + _ => "Unsupported".to_string(), + }; + println!(" Firmware Version: v{}", ver); + // If we found one, there's no need to look for more return Ok(()); } From e85b0d3853514649b3ac31ac763e59bdafe0e722 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 30 Mar 2025 12:17:04 +0800 Subject: [PATCH 44/53] touchpad: Also print HID descriptor version On Windows you can read it using HidD_GetAttributes. The Linux kernel does not expose this. Signed-off-by: Daniel Schaefer --- framework_lib/src/touchpad.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index e3c2f4da..08146b72 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -36,6 +36,7 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { let vid = dev_info.vendor_id(); let pid = dev_info.product_id(); let usage_page = dev_info.usage_page(); + let hid_ver = dev_info.release_number(); debug!( " Found {:04X}:{:04X} (Usage Page {:04X})", @@ -58,6 +59,7 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { println!("Touchpad"); println!(" IC Type: {:04X}", pid); + let ver = match pid { 0x0239 => format!("{:04X}", read_239_ver(&device)?), 0x0274 => format!("{:04X}", read_274_ver(&device)?), @@ -65,6 +67,16 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { }; println!(" Firmware Version: v{}", ver); + // Linux does not expose a useful version number for I2C HID devices + #[cfg(target_os = "linux")] + debug!(" HID Version {:04X}", hid_ver); + #[cfg(not(target_os = "linux"))] + if ver != format!("{:04X}", hid_ver) { + println!(" HID Version v{:04X}", hid_ver); + } else if log_enabled!(Level::Debug) { + println!(" HID Version v{:04X}", hid_ver); + } + // If we found one, there's no need to look for more return Ok(()); } From 6e1d4119716e452daa80575d6202b9084fc78f5b Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sat, 29 Mar 2025 19:05:29 +0800 Subject: [PATCH 45/53] touchpad: Dump whole config space Signed-off-by: Daniel Schaefer --- framework_lib/src/touchpad.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index 08146b72..72bc30c8 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -1,4 +1,5 @@ use hidapi::{HidApi, HidDevice, HidError}; +use log::Level; pub const PIX_VID: u16 = 0x093A; pub const P274_REPORT_ID: u8 = 0x43; @@ -67,6 +68,35 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { }; println!(" Firmware Version: v{}", ver); + if log_enabled!(Level::Debug) { + println!(" Config space 1"); + print!(" "); + for x in 0..16 { + print!("0{:X} ", x); + } + println!(); + for y in 0..16 { + print!("{:X}0 ", y); + for x in 0..16 { + print!("{:02X} ", read_byte(&device, 0x42, x + 16 * y)?); + } + println!(); + } + println!(" Config space 2"); + print!(" "); + for x in 0..16 { + print!("0{:X} ", x); + } + println!(); + for y in 0..16 { + print!("{:X}0 ", y); + for x in 0..16 { + print!("{:02X} ", read_byte(&device, 0x43, x + 16 * y)?); + } + println!(); + } + } + // Linux does not expose a useful version number for I2C HID devices #[cfg(target_os = "linux")] debug!(" HID Version {:04X}", hid_ver); From 6c57b1e168fb049b04dc3998735fa630cb1b1dd1 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Fri, 21 Mar 2025 23:22:40 +0800 Subject: [PATCH 46/53] touchscreen: Dump firmware version and protocol ``` > framework_tool --versions [...] Touchscreen Firmware Version: v7.0.0.4.0.0.0.0 USI Protocol: false MPP Protocol: true ``` Signed-off-by: Daniel Schaefer --- README.md | 6 +- framework_lib/Cargo.toml | 9 +- framework_lib/src/commandline/mod.rs | 5 + framework_lib/src/lib.rs | 4 + framework_lib/src/touchscreen.rs | 142 +++++++++++++++++++++++++++ framework_lib/src/touchscreen_win.rs | 101 +++++++++++++++++++ 6 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 framework_lib/src/touchscreen.rs create mode 100644 framework_lib/src/touchscreen_win.rs diff --git a/README.md b/README.md index 771675a2..c97ad722 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ see the [Support Matrices](support-matrices.md). - [x] PD - [x] ME (Only on Linux) - [x] Retimer - - [x] Touchpad (Linux and Windows) + - [x] Touchpad (Linux, Windows, FreeBSD, not UEFI) + - [x] Touchscreen (Linux, Windows, FreeBSD, not UEFI) - [x] Get Expansion Card Firmware (Not on UEFI so far) - [x] HDMI Expansion Card (`--dp-hdmi-info`) - [x] DisplayPort Expansion Card (`--dp-hdmi-info`) @@ -69,6 +70,7 @@ All of these need EC communication support in order to work. - [x] Get and set keyboard brightness (`--kblight`) - [x] Get and set battery charge limit (`--charge-limit`) - [x] Get and set fingerprint LED brightness (`--fp-brightness`) +- [x] Disable/Enable touchscreen (`--touchscreen-enable`) ###### Communication with Embedded Controller @@ -177,6 +179,8 @@ Options: --intrusion Show status of intrusion switch --inputmodules Show status of the input modules (Framework 16 only) --kblight [] Set keyboard backlight percentage or get, if no value provided + --touchscreen-enable + Enable/disable touchscreen [possible values: true, false] --console Get EC console, choose whether recent or to follow the output [possible values: recent, follow] --driver Select which driver is used. By default portio is used [possible values: portio, cros-ec, windows] -t, --test Run self-test to check if interaction with EC is possible diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index fb5096ca..b0d41eec 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -63,7 +63,7 @@ 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 } +hidapi = { version = "2.6.3", optional = true, features = [ "windows-native" ] } rusb = { version = "0.9.4", optional = true } no-std-compat = { version = "0.4.1", features = [ "alloc" ] } guid_macros = { path = "../guid_macros" } @@ -89,5 +89,12 @@ features = [ "Win32_System_IO", "Win32_System_Ioctl", "Win32_System_SystemServices", + # For HID devices + "Win32_Devices_DeviceAndDriverInstallation", + "Win32_Devices_HumanInterfaceDevice", + "Win32_Devices_Properties", + "Win32_Storage_EnhancedStorage", + "Win32_System_Threading", + "Win32_UI_Shell_PropertiesSystem" ] diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index fa284951..ef38f4fa 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -52,6 +52,8 @@ 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(feature = "hidapi")] +use crate::touchscreen::print_touchscreen_fw_ver; #[cfg(feature = "uefi")] use crate::uefi::enable_page_break; use crate::util; @@ -479,6 +481,9 @@ fn print_versions(ec: &CrosEc) { #[cfg(feature = "hidapi")] let _ignore_err = print_touchpad_fw_ver(); + + #[cfg(feature = "hidapi")] + let _ignore_err = print_touchscreen_fw_ver(); } fn print_esrt() { diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 50fa9b03..b0c92e4d 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -18,6 +18,10 @@ pub mod audio_card; pub mod camera; #[cfg(feature = "hidapi")] pub mod touchpad; +#[cfg(any(feature = "hidapi", feature = "windows"))] +pub mod touchscreen; +#[cfg(feature = "windows")] +pub mod touchscreen_win; #[cfg(feature = "uefi")] #[macro_use] diff --git a/framework_lib/src/touchscreen.rs b/framework_lib/src/touchscreen.rs new file mode 100644 index 00000000..a602018d --- /dev/null +++ b/framework_lib/src/touchscreen.rs @@ -0,0 +1,142 @@ +use hidapi::{HidApi, HidDevice}; + +#[cfg(target_os = "windows")] +use crate::touchscreen_win; + +pub const ILI_VID: u16 = 0x222A; +pub const ILI_PID: u16 = 0x5539; +pub const USI_BITMAP: u8 = 1 << 1; +pub const MPP_BITMAP: u8 = 1 << 2; + +struct HidapiTouchScreen { + device: HidDevice, +} + +impl TouchScreen for HidapiTouchScreen { + fn open_device() -> Option { + debug!("Looking for touchscreen HID device"); + match HidApi::new() { + Ok(api) => { + for dev_info in api.device_list() { + let vid = dev_info.vendor_id(); + let pid = dev_info.product_id(); + let usage_page = dev_info.usage_page(); + if vid != ILI_VID { + trace!(" Skipping VID:PID. Expected {:04X}:*", ILI_VID); + continue; + } + debug!( + " Found {:04X}:{:04X} (Usage Page {:04X})", + vid, pid, usage_page + ); + if usage_page != 0xFF00 { + debug!(" Skipping usage page. Expected {:04X}", 0xFF00); + continue; + } + if pid != ILI_PID { + debug!(" Warning: PID is {:04X}, expected {:04X}", pid, ILI_PID); + } + + debug!(" Found matching touchscreen HID device"); + debug!(" Path: {:?}", dev_info.path()); + debug!(" IC Type: {:04X}", pid); + + // Unwrapping because if we can enumerate it, we should be able to open it + let device = dev_info.open_device(&api).unwrap(); + debug!(" Opened device."); + + return Some(HidapiTouchScreen { device }); + } + } + Err(e) => { + error!("Failed to open hidapi. Error: {e}"); + } + }; + + None + } + + fn send_message(&self, message_id: u8, read_len: usize, data: Vec) -> Option> { + let report_id = 0x03; + let data_len = data.len(); + let mut msg = [0u8; 0x40]; + msg[0] = report_id; + msg[1] = 0xA3; + msg[2] = data_len as u8; + msg[3] = read_len as u8; + msg[4] = message_id; + for (i, b) in data.into_iter().enumerate() { + msg[5 + i] = b; + } + + // Not sure why, but on Windows we just have to write an output report + // HidApiError { message: "HidD_SetFeature: (0x00000057) The parameter is incorrect." } + // Still doesn't work on Windows. Need to write a byte more than the buffer is long + #[cfg(target_os = "windows")] + let send_feature_report = false; + #[cfg(not(target_os = "windows"))] + let send_feature_report = true; + + if send_feature_report { + debug!(" send_feature_report {:X?}", msg); + self.device.send_feature_report(&msg).ok()?; + } else { + debug!(" Writing {:X?}", msg); + self.device.write(&msg).ok()?; + }; + + if read_len == 0 { + return Some(vec![]); + } + + let msg_len = 3 + data_len; + let mut buf: [u8; 0x40] = [0; 0x40]; + debug!(" Reading"); + let res = self.device.read(&mut buf); + debug!(" res: {:?}", res); + debug!(" Read buf: {:X?}", buf); + Some(buf[msg_len..msg_len + read_len].to_vec()) + } +} + +pub trait TouchScreen { + fn open_device() -> Option + where + Self: std::marker::Sized; + fn send_message(&self, message_id: u8, read_len: usize, data: Vec) -> Option>; + + fn check_fw_version(&self) -> Option<()> { + println!("Touchscreen"); + let res = self.send_message(0x42, 3, vec![0])?; + let ver = res + .iter() + .skip(1) + .fold(format!("{:02X}", res[0]), |acc, &x| { + acc + "." + &format!("{:02X}", x) + }); + // Expecting 06.00.0A + debug!(" Protocol Version: v{}", ver); + + let res = self.send_message(0x40, 8, vec![0])?; + let ver = res + .iter() + .skip(1) + .fold(res[0].to_string(), |acc, &x| acc + "." + &x.to_string()); + println!(" Firmware Version: v{}", ver); + + let res = self.send_message(0x20, 16, vec![0])?; + println!(" USI Protocol: {:?}", (res[15] & USI_BITMAP) > 0); + println!(" MPP Protocol: {:?}", (res[15] & MPP_BITMAP) > 0); + + Some(()) + } +} + +pub fn print_touchscreen_fw_ver() -> Option<()> { + #[cfg(target_os = "windows")] + let device = touchscreen_win::NativeWinTouchScreen::open_device()?; + #[cfg(not(target_os = "windows"))] + let device = HidapiTouchScreen::open_device()?; + + device.check_fw_version() +} diff --git a/framework_lib/src/touchscreen_win.rs b/framework_lib/src/touchscreen_win.rs new file mode 100644 index 00000000..2a1be801 --- /dev/null +++ b/framework_lib/src/touchscreen_win.rs @@ -0,0 +1,101 @@ +use crate::touchscreen::TouchScreen; +#[allow(unused_imports)] +use windows::{ + core::*, + Win32::{ + Devices::HumanInterfaceDevice::*, + Devices::Properties::*, + Foundation::*, + Storage::FileSystem::*, + System::Threading::ResetEvent, + System::IO::{CancelIoEx, DeviceIoControl}, + System::{Ioctl::*, IO::*}, + }, +}; + +pub struct NativeWinTouchScreen { + handle: HANDLE, +} + +impl TouchScreen for NativeWinTouchScreen { + fn open_device() -> Option { + // TODO: I don't know if this might be different on other systems + // Should enumerate and find the right one + // See: https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/finding-and-opening-a-hid-collection + let path = + w!(r"\\?\HID#ILIT2901&Col03#5&357cbf85&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}"); + + let res = unsafe { + CreateFileW( + path, + FILE_GENERIC_WRITE.0 | FILE_GENERIC_READ.0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + None, + OPEN_EXISTING, + // hidapi-rs is using FILE_FLAG_OVERLAPPED but it doesn't look like we need that + FILE_FLAGS_AND_ATTRIBUTES(0), + None, + ) + }; + let handle = match res { + Ok(h) => h, + Err(err) => { + error!("Failed to open device {:?}", err); + return None; + } + }; + + debug!("Opened {:?}", path); + + Some(NativeWinTouchScreen { handle }) + } + + fn send_message(&self, message_id: u8, read_len: usize, data: Vec) -> Option> { + let report_id = 0x03; + let data_len = data.len(); + let mut msg = [0u8; 0x40]; + let msg_len = 3 + data_len; + msg[0] = report_id; + msg[1] = 0xA3; + msg[2] = data_len as u8; + msg[3] = read_len as u8; + msg[4] = message_id; + for (i, b) in data.into_iter().enumerate() { + msg[5 + i] = b; + } + + let mut buf = [0u8; 0x40]; + buf[0] = report_id; + + unsafe { + debug!(" HidD_SetOutputReport {:X?}", msg); + let success = HidD_SetOutputReport( + self.handle, + // Microsoft docs says that the first byte of the message has to be the report ID. + // This is normal with HID implementations. + // But it seems on Windows (at least for this device's firmware) we have to set the + // length as one more than the buffer is long. + // Otherwise no data is returned in the read call later. + msg.as_mut_ptr() as _, + msg.len() as u32 + 1, + ); + debug!(" Success: {}", success); + + if read_len == 0 { + return Some(vec![]); + } + + let mut bytes_read = 0; + debug!(" ReadFile"); + // HidD_GetFeature doesn't work, have to use ReadFile + // Microsoft does recommend that + // https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/obtaining-hid-reports + let res = ReadFile(self.handle, Some(&mut buf), Some(&mut bytes_read), None); + debug!(" Success: {:?}, Bytes: {}", res, bytes_read); + debug!(" Read buf: {:X?}", buf); + debug!(" Read msg: {:X?}", msg); + } + + Some(buf[msg_len..msg_len + read_len].to_vec()) + } +} From e004b7d84446bec28287d4fbd1fa8221ebc92fcc Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 13 Apr 2025 23:12:38 +0800 Subject: [PATCH 47/53] touchscreen: Allow turning touch on and off Signed-off-by: Daniel Schaefer --- framework_lib/src/commandline/clap_std.rs | 6 ++++++ framework_lib/src/commandline/mod.rs | 12 +++++++++--- framework_lib/src/commandline/uefi.rs | 1 + framework_lib/src/touchscreen.rs | 16 +++++++++++++++- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index f9299e6d..6bbd6b40 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -162,6 +162,11 @@ struct ClapCli { #[arg(long)] tablet_mode: Option, + /// Enable/disable touchscreen + #[clap(value_enum)] + #[arg(long)] + touchscreen_enable: Option, + /// Get EC console, choose whether recent or to follow the output #[clap(value_enum)] #[arg(long)] @@ -284,6 +289,7 @@ pub fn parse(args: &[String]) -> Cli { kblight: args.kblight, rgbkbd: args.rgbkbd, tablet_mode: args.tablet_mode, + touchscreen_enable: args.touchscreen_enable, console: args.console, reboot_ec: args.reboot_ec, hash: args.hash.map(|x| x.into_os_string().into_string().unwrap()), diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index ef38f4fa..03179a1c 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -52,8 +52,8 @@ 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(feature = "hidapi")] -use crate::touchscreen::print_touchscreen_fw_ver; +#[cfg(any(feature = "hidapi", feature = "windows"))] +use crate::touchscreen; #[cfg(feature = "uefi")] use crate::uefi::enable_page_break; use crate::util; @@ -175,6 +175,7 @@ pub struct Cli { pub kblight: Option>, pub rgbkbd: Vec, pub tablet_mode: Option, + pub touchscreen_enable: Option, pub console: Option, pub reboot_ec: Option, pub hash: Option, @@ -483,7 +484,7 @@ fn print_versions(ec: &CrosEc) { let _ignore_err = print_touchpad_fw_ver(); #[cfg(feature = "hidapi")] - let _ignore_err = print_touchscreen_fw_ver(); + let _ignore_err = touchscreen::print_fw_ver(); } fn print_esrt() { @@ -798,6 +799,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { TabletModeArg::Laptop => TabletModeOverride::ForceClamshell, }; ec.set_tablet_mode(mode); + } else if let Some(_enable) = &args.touchscreen_enable { + #[cfg(any(feature = "hidapi", feature = "windows"))] + if touchscreen::enable_touch(*_enable).is_none() { + error!("Failed to enable/disable touch"); + } } else if let Some(console_arg) = &args.console { match console_arg { ConsoleArg::Follow => { diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 261720fc..39ea2867 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -89,6 +89,7 @@ pub fn parse(args: &[String]) -> Cli { kblight: None, rgbkbd: vec![], tablet_mode: None, + touchscreen_enable: None, console: None, reboot_ec: None, hash: None, diff --git a/framework_lib/src/touchscreen.rs b/framework_lib/src/touchscreen.rs index a602018d..c155c173 100644 --- a/framework_lib/src/touchscreen.rs +++ b/framework_lib/src/touchscreen.rs @@ -130,9 +130,14 @@ pub trait TouchScreen { Some(()) } + + fn enable_touch(&self, enable: bool) -> Option<()> { + self.send_message(0x38, 0, vec![!enable as u8, 0x00])?; + Some(()) + } } -pub fn print_touchscreen_fw_ver() -> Option<()> { +pub fn print_fw_ver() -> Option<()> { #[cfg(target_os = "windows")] let device = touchscreen_win::NativeWinTouchScreen::open_device()?; #[cfg(not(target_os = "windows"))] @@ -140,3 +145,12 @@ pub fn print_touchscreen_fw_ver() -> Option<()> { device.check_fw_version() } + +pub fn enable_touch(enable: bool) -> Option<()> { + #[cfg(target_os = "windows")] + let device = touchscreen_win::NativeWinTouchScreen::open_device()?; + #[cfg(not(target_os = "windows"))] + let device = HidapiTouchScreen::open_device()?; + + device.enable_touch(enable) +} From 2ddf76239be0bc96d3f411335a9e1b5044eecba3 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Mon, 14 Apr 2025 17:31:31 +0800 Subject: [PATCH 48/53] README: Update Signed-off-by: Daniel Schaefer --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c97ad722..ded23458 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ see the [Support Matrices](support-matrices.md). - [x] Get firmware version from system (`--versions`) - [x] BIOS - [x] EC - - [x] PD + - [x] PD Controller - [x] ME (Only on Linux) - [x] Retimer - [x] Touchpad (Linux, Windows, FreeBSD, not UEFI) @@ -69,7 +69,8 @@ All of these need EC communication support in order to work. - [x] Get and set keyboard brightness (`--kblight`) - [x] Get and set battery charge limit (`--charge-limit`) -- [x] Get and set fingerprint LED brightness (`--fp-brightness`) +- [x] Get and set fingerprint LED brightness (`--fp-brightness`, `--fp-led-level`) +- [x] Override tablet mode, instead of follow G-Sensor and hall sensor (`--tablet-mode`) - [x] Disable/Enable touchscreen (`--touchscreen-enable`) ###### Communication with Embedded Controller @@ -178,11 +179,30 @@ Options: --h2o-capsule Parse UEFI Capsule information from binary file --intrusion Show status of intrusion switch --inputmodules Show status of the input modules (Framework 16 only) + --input-deck-mode + Set input deck power mode [possible values: auto, off, on] (Framework 16 only) [possible values: auto, off, on] + --charge-limit [] + Get or set max charge limit + --get-gpio + Get GPIO value by name + --fp-led-level [] + Get or set fingerprint LED brightness level [possible values: high, medium, low, ultra-low, auto] + --fp-brightness [] + Get or set fingerprint LED brightness percentage --kblight [] Set keyboard backlight percentage or get, if no value provided + --tablet-mode Set tablet mode override [possible values: auto, tablet, laptop] --touchscreen-enable Enable/disable touchscreen [possible values: true, false] --console Get EC console, choose whether recent or to follow the output [possible values: recent, follow] + --reboot-ec Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump] + --hash Hash a file of arbitrary data --driver Select which driver is used. By default portio is used [possible values: portio, cros-ec, windows] + --pd-addrs + 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 ``` From 87f21325a636131a6f948ca63012139831f4317b Mon Sep 17 00:00:00 2001 From: Kieran Levin Date: Wed, 1 Nov 2023 16:08:28 -0500 Subject: [PATCH 49/53] Add commands to read/write GPU serial TEST=Tested on platform to overwrite the serial And I can see the serial updates to the new value after rebooting the EC. Signed-off-by: Kieran Levin Co-Authored-By: Daniel Schaefer --- framework_lib/Cargo.toml | 2 +- framework_lib/src/chromium_ec/command.rs | 4 ++ framework_lib/src/chromium_ec/commands.rs | 46 +++++++++++++ framework_lib/src/chromium_ec/mod.rs | 31 +++++++++ framework_lib/src/commandline/clap_std.rs | 78 ++++++++++++++++++----- framework_lib/src/commandline/mod.rs | 9 +++ framework_lib/src/commandline/uefi.rs | 37 ++++++++++- 7 files changed, 188 insertions(+), 19 deletions(-) diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index fb5096ca..266c971b 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -50,7 +50,7 @@ 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"], 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 } diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index 247ff5ee..0eaa9395 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -88,6 +88,10 @@ pub enum EcCommands { ExpansionBayStatus = 0x3E1B, /// Get hardware diagnostics GetHwDiag = 0x3E1C, + /// Get gpu bay serial + GetGpuSerial = 0x3E1D, + /// Set gpu bay serial and program structure + ProgramGpuEeprom = 0x3E1F, } pub trait EcRequest { diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index c4944db8..6bde4170 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -931,3 +931,49 @@ impl EcRequest for EcRequestFpLedLevelControlV1 { 1 } } + +#[repr(C, packed)] +pub struct EcRequestGetGpuSerial { + pub idx: u8, +} + +#[repr(C, packed)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct EcResponseGetGpuSerial { + pub idx: u8, + pub valid: u8, + pub serial: [u8; 20], +} + +impl EcRequest for EcRequestGetGpuSerial { + fn command_id() -> EcCommands { + EcCommands::GetGpuSerial + } +} + +#[repr(u8)] +pub enum SetGpuSerialMagic { + /// 7700S config magic value + WriteGPUConfig = 0x0D, + /// SSD config magic value + WriteSSDConfig = 0x55, +} + +#[repr(C, packed)] +pub struct EcRequestSetGpuSerial { + pub magic: u8, + pub idx: u8, + pub serial: [u8; 20], +} + +#[repr(C, packed)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct EcResponseSetGpuSerial { + pub valid: u8, +} + +impl EcRequest for EcRequestSetGpuSerial { + fn command_id() -> EcCommands { + EcCommands::ProgramGpuEeprom + } +} diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index 17702689..acbd5c0c 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -33,6 +33,7 @@ use alloc::string::String; use alloc::string::ToString; use alloc::vec; use alloc::vec::Vec; + #[cfg(feature = "uefi")] use core::prelude::rust_2021::derive; use num_traits::FromPrimitive; @@ -789,6 +790,36 @@ impl CrosEc { res } + /// Get the GPU Serial + /// + pub fn get_gpu_serial(&self) -> EcResult { + let gpuserial: EcResponseGetGpuSerial = + EcRequestGetGpuSerial { idx: 0 }.send_command(self)?; + let serial: String = String::from_utf8(gpuserial.serial.to_vec()).unwrap(); + + if gpuserial.valid == 0 { + return Err(EcError::DeviceError("No valid GPU serial".to_string())); + } + + Ok(serial) + } + + /// Set the GPU Serial + /// + /// # Arguments + /// `newserial` - a string that is 18 characters long + pub fn set_gpu_serial(&self, magic: u8, newserial: String) -> EcResult { + let mut array_tmp: [u8; 20] = [0; 20]; + array_tmp[..18].copy_from_slice(newserial.as_bytes()); + let result = EcRequestSetGpuSerial { + magic, + idx: 0, + serial: array_tmp, + } + .send_command(self)?; + Ok(result.valid) + } + /// Requests recent console output from EC and constantly asks for more /// Prints the output and returns it when an error is encountered pub fn console_read(&self) -> EcResult { diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index f9299e6d..22298a01 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -1,9 +1,12 @@ //! Module to factor out commandline interaction //! This way we can use it in the regular OS commandline tool on Linux and Windows, //! as well as on the UEFI shell tool. +use clap::error::ErrorKind; use clap::Parser; +use clap::{arg, command, Arg, Args, FromArgMatches}; use clap_num::maybe_hex; +use crate::chromium_ec::commands::SetGpuSerialMagic; use crate::chromium_ec::CrosEcDriverType; use crate::commandline::{ Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg, @@ -203,31 +206,71 @@ struct ClapCli { /// Parse a list of commandline arguments and return the struct pub fn parse(args: &[String]) -> Cli { - let args = ClapCli::parse_from(args); + // Step 1 - Define args that can't be derived + let cli = command!() + .arg(Arg::new("fgd").long("flash-gpu-descriptor").num_args(2)) + .disable_version_flag(true); + // Step 2 - Define args from derived struct + let mut cli = ClapCli::augment_args(cli); + + // Step 3 - Parse args that can't be derived + let matches = cli.clone().get_matches_from(args); + let fgd = matches + .get_many::("fgd") + .unwrap_or_default() + .map(|v| v.as_str()) + .collect::>(); + let flash_gpu_descriptor = if !fgd.is_empty() { + let hex_magic = if let Some(hex_magic) = fgd[0].strip_prefix("0x") { + u8::from_str_radix(hex_magic, 16) + } else { + // Force parse error + u8::from_str_radix("", 16) + }; + + let magic = if let Ok(magic) = fgd[0].parse::() { + magic + } else if let Ok(hex_magic) = hex_magic { + hex_magic + } else if fgd[0].to_uppercase() == "GPU" { + SetGpuSerialMagic::WriteGPUConfig as u8 + } else if fgd[0].to_uppercase() == "SSD" { + SetGpuSerialMagic::WriteSSDConfig as u8 + } else { + cli.error( + ErrorKind::InvalidValue, + "First argument of --flash-gpu-descriptor must be an integer or one of: 'GPU', 'SSD'", + ) + .exit(); + }; + if fgd[1].len() != 18 { + cli.error( + ErrorKind::InvalidValue, + "Second argument of --flash-gpu-descriptor must be an 18 digit serial number", + ) + .exit(); + } + Some((magic, fgd[1].to_string())) + } else { + None + }; + + // Step 4 - Parse from derived struct + let args = ClapCli::from_arg_matches(&matches) + .map_err(|err| err.exit()) + .unwrap(); let pd_addrs = match args.pd_addrs.len() { 2 => Some((args.pd_addrs[0], args.pd_addrs[1])), 0 => None, - _ => { - // Actually unreachable, checked by clap - println!( - "Must provide exactly to PD Addresses. Provided: {:?}", - args.pd_addrs - ); - std::process::exit(1); - } + // Checked by clap + _ => unreachable!(), }; let pd_ports = match args.pd_ports.len() { 2 => Some((args.pd_ports[0], args.pd_ports[1])), 0 => None, - _ => { - // Actually unreachable, checked by clap - println!( - "Must provide exactly to PD Ports. Provided: {:?}", - args.pd_ports - ); - std::process::exit(1); - } + // Checked by clap + _ => unreachable!(), }; Cli { @@ -299,6 +342,7 @@ pub fn parse(args: &[String]) -> Cli { // UEFI only - every command needs to implement a parameter to enable the pager paginate: false, info: args.info, + flash_gpu_descriptor, raw_command: vec![], } } diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index fa284951..1d6ae7cf 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -181,6 +181,7 @@ pub struct Cli { pub has_mec: Option, pub help: bool, pub info: bool, + pub flash_gpu_descriptor: Option<(u8, String)>, // UEFI only pub allupdate: bool, pub paginate: bool, @@ -1004,6 +1005,13 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { println!(" Size: {:>20} KB", data.len() / 1024); hash(&data); } + } else if let Some(gpu_descriptor) = &args.flash_gpu_descriptor { + let res = ec.set_gpu_serial(gpu_descriptor.0, gpu_descriptor.1.to_ascii_uppercase()); + match res { + Ok(1) => println!("GPU Descriptor successfully written"), + Ok(x) => println!("GPU Descriptor write failed with status code: {}", x), + Err(err) => println!("GPU Descriptor write failed with error: {:?}", err), + } } 0 @@ -1053,6 +1061,7 @@ Options: --kblight [] Set keyboard backlight percentage or get, if no value provided --console Get EC console, choose whether recent or to follow the output [possible values: recent, follow] --hash Hash a file of arbitrary data + --flash-gpu-descriptor <18 DIGIT SN> Overwrite the GPU bay descriptor SN and type. -t, --test Run self-test to check if interaction with EC is possible -h, --help Print help information -b Print output one screen at a time diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 261720fc..fd4e9528 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -1,4 +1,4 @@ -use alloc::string::String; +use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; @@ -9,6 +9,7 @@ use uefi::proto::shell_params::*; use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType}; use uefi::Identify; +use crate::chromium_ec::commands::SetGpuSerialMagic; use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType}; use crate::commandline::Cli; @@ -99,6 +100,7 @@ pub fn parse(args: &[String]) -> Cli { has_mec: None, test: false, help: false, + flash_gpu_descriptor: None, allupdate: false, info: false, raw_command: vec![], @@ -513,6 +515,39 @@ pub fn parse(args: &[String]) -> Cli { println!("Need to provide a value for --console. Possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right"); None }; + } else if arg == "--flash-gpu-descriptor" { + cli.flash_gpu_descriptor = if args.len() > i + 2 { + let sn = args[i + 2].to_string(); + let magic = &args[i + 1]; + + let hex_magic = if let Some(hex_magic) = magic.strip_prefix("0x") { + u8::from_str_radix(hex_magic, 16) + } else { + // Force parse error + u8::from_str_radix("", 16) + }; + + if let Ok(magic) = magic.parse::() { + Some((magic, sn)) + } else if let Ok(hex_magic) = hex_magic { + Some((hex_magic, sn)) + } else if magic.to_uppercase() == "GPU" { + Some((SetGpuSerialMagic::WriteGPUConfig as u8, sn)) + } else if magic.to_uppercase() == "SSD" { + Some((SetGpuSerialMagic::WriteSSDConfig as u8, sn)) + } else { + println!( + "Invalid values for --flash_gpu_descriptor: '{} {}'. Must be u8, 18 character string.", + args[i + 1], + args[i + 2] + ); + None + } + } else { + println!("Need to provide a value for --flash_gpu_descriptor. TYPE_MAGIC SERIAL"); + None + }; + found_an_option = true; } } From ce27036b23245e9e85d33f0186b65c8672a46c0a Mon Sep 17 00:00:00 2001 From: Lars Engels Date: Mon, 24 Mar 2025 21:41:28 +0100 Subject: [PATCH 50/53] Add ZSH completion for framework_tool --- completions/zsh/_framework_tool | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 completions/zsh/_framework_tool diff --git a/completions/zsh/_framework_tool b/completions/zsh/_framework_tool new file mode 100644 index 00000000..896c587d --- /dev/null +++ b/completions/zsh/_framework_tool @@ -0,0 +1,51 @@ +#compdef framework_tool + +local -a options + +options=( + '-v[Increase logging verbosity]' + '-q[Decrease logging verbosity]' + '--versions[Show current firmware versions]' + '--version[Show tool version information (Add -vv for more details)]' + '--features[Show features supported by the firmware]' + '--esrt[Display the UEFI ESRT table]' + '--device[Specify device type]:device:(bios ec pd0 pd1 rtm01 rtm23 ac-left ac-right)' + '--compare-version[Specify version to compare]:compare_version' + '--power[Show current power status of battery and AC (Add -vv for more details)]' + '--thermal[Print thermal information (Temperatures and Fan speed)]' + '--sensors[Print sensor information (ALS, G-Sensor)]' + '--pdports[Show information about USB-C PD ports]' + '--info[Show info from SMBIOS (Only on UEFI)]' + '--pd-info[Show details about the PD controllers]' + '--dp-hdmi-info[Show details about connected DP or HDMI Expansion Cards]' + '--dp-hdmi-update[Update the DisplayPort or HDMI Expansion Card]:update_bin' + '--audio-card-info[Show details about connected Audio Expansion Cards (Needs root privileges)]' + '--privacy[Show privacy switch statuses (camera and microphone)]' + '--pd-bin[Parse versions from PD firmware binary file]:pd_bin' + '--ec-bin[Parse versions from EC firmware binary file]:ec_bin' + '--capsule[Parse UEFI Capsule information from binary file]:capsule' + '--dump[Dump extracted UX capsule bitmap image to a file]:dump' + '--ho2-capsule[Parse UEFI Capsule information from binary file]:ho2_capsule' + '--dump-ec-flash[Dump EC flash contents]:dump_ec_flash' + '--flash-ec[Flash EC with new firmware from file]:flash_ec' + '--flash-ro-ec[Flash EC with new RO firmware from file]:flash_ro_ec' + '--flash-rw-ec[Flash EC with new RW firmware from file]:flash_rw_ec' + '--intrusion[Show status of intrusion switch]' + '--inputmodules[Show status of the input modules (Framework 16 only)]' + '--input-deck-mode[Set input deck power mode]:input_deck_mode:(auto off on)' + '--charge-limit[Get or set max charge limit]:charge_limit' + '--get-gpio[Get GPIO value by name]:get_gpio' + '--fp-brightness[Get or set fingerprint LED brightness]:fp_brightness:(high medium low)' + '--kblight[Set keyboard backlight percentage or get, if no value provided]:kblight' + '--console[Get EC console, choose whether recent or to follow the output]:console:(recent follow)' + '--reboot-ec[Control EC RO/RW jump]:reboot_ec:(reboot jump-ro jump-rw cancel-jump disable-jump)' + '--hash[Hash a file of arbitrary data]:hash' + '--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]' +) + +_arguments -s -S $options From 034a1093c483aa6a92d1b9bbd019c3a9c0f7edf2 Mon Sep 17 00:00:00 2001 From: Lars Engels Date: Mon, 24 Mar 2025 21:48:37 +0100 Subject: [PATCH 51/53] Add Bash completion for framework_tool --- completions/bash/framework_tool | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 completions/bash/framework_tool diff --git a/completions/bash/framework_tool b/completions/bash/framework_tool new file mode 100755 index 00000000..a0826437 --- /dev/null +++ b/completions/bash/framework_tool @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Bash completion for framework_tool + +_framework_tool() { + local options + options=( + "-v" "--verbose" + "-q" "--quiet" + "--versions" + "--version" + "--features" + "--esrt" + "--device" + "--compare-version" + "--power" + "--thermal" + "--sensors" + "--pdports" + "--info" + "--pd-info" + "--dp-hdmi-info" + "--dp-hdmi-update" + "--audio-card-info" + "--privacy" + "--pd-bin" + "--ec-bin" + "--capsule" + "--dump" + "--ho2-capsule" + "--dump-ec-flash" + "--flash-ec" + "--flash-ro-ec" + "--flash-rw-ec" + "--intrusion" + "--inputmodules" + "--input-deck-mode" + "--charge-limit" + "--get-gpio" + "--fp-brightness" + "--kblight" + "--console" + "--reboot-ec" + "--hash" + "--driver" + "--pd-addrs" + "--pd-ports" + "--has-mec" + "-t" "--test" + "-h" "--help" + ) + + local devices=("bios" "ec" "pd0" "pd1" "rtm01" "rtm23" "ac-left" "ac-right") + local input_deck_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") + + local current_word prev_word + current_word="${COMP_WORDS[COMP_CWORD]}" + prev_word="${COMP_WORDS[COMP_CWORD-1]}" + + # Handle options + if [[ $COMP_CWORD -eq 1 ]]; then + COMPREPLY=( $(compgen -W "${options[*]}" -- "$current_word") ) + elif [[ $prev_word == "--device" ]]; then + COMPREPLY=( $(compgen -W "${devices[*]}" -- "$current_word") ) + elif [[ $prev_word == "--input-deck-mode" ]]; then + COMPREPLY=( $(compgen -W "${input_deck_modes[*]}" -- "$current_word") ) + elif [[ $prev_word == "--console" ]]; then + 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 + + return 0 +} + +complete -F _framework_tool framework_tool From 8a90c3789d09945900bea583f10c56d242cf28a1 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 17 Apr 2025 02:44:00 +0800 Subject: [PATCH 52/53] completions: Add new commands Signed-off-by: Daniel Schaefer --- completions/bash/framework_tool | 7 ++++++- completions/zsh/_framework_tool | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/completions/bash/framework_tool b/completions/bash/framework_tool index a0826437..24f41d46 100755 --- a/completions/bash/framework_tool +++ b/completions/bash/framework_tool @@ -5,6 +5,7 @@ _framework_tool() { local options options=( + "--flash-gpu-descriptor" "-v" "--verbose" "-q" "--quiet" "--versions" @@ -37,8 +38,12 @@ _framework_tool() { "--input-deck-mode" "--charge-limit" "--get-gpio" + "--fp-led-level" "--fp-brightness" "--kblight" + "--rgbkbd" + "--tablet-mode" + "--touchscreen-enable" "--console" "--reboot-ec" "--hash" @@ -55,7 +60,7 @@ _framework_tool() { local console_modes=("recent" "follow") local drivers=("portio" "cros-ec" "windows") local has_mec_options=("true" "false") - local brightness_options=("high" "medium" "low") + local brightness_options=("high" "medium" "low" "ultra-low") local current_word prev_word current_word="${COMP_WORDS[COMP_CWORD]}" diff --git a/completions/zsh/_framework_tool b/completions/zsh/_framework_tool index 896c587d..70ea7516 100644 --- a/completions/zsh/_framework_tool +++ b/completions/zsh/_framework_tool @@ -3,6 +3,7 @@ local -a options options=( + '--flash-gpu-descriptor[]' '-v[Increase logging verbosity]' '-q[Decrease logging verbosity]' '--versions[Show current firmware versions]' @@ -35,8 +36,12 @@ options=( '--input-deck-mode[Set input deck power mode]:input_deck_mode:(auto off on)' '--charge-limit[Get or set max charge limit]:charge_limit' '--get-gpio[Get GPIO value by name]:get_gpio' - '--fp-brightness[Get or set fingerprint LED brightness]:fp_brightness:(high medium low)' + '--fp-led-level-gpio[Get or set fingerprint LED brightness level]:fp_led_level:(high medium low ultra-low auto)' + '--fp-brightness[Get or set fingerprint LED brightness]:fp_brightness' '--kblight[Set keyboard backlight percentage or get, if no value provided]:kblight' + '--rgbkbd[Set the color of to .]' + '--tablet-mode[Set tablet mode override]:tablet_mode:(auto tablet laptop)' + '--touchscreen-enable[Enable/disable touchscreen]:touchscreen_enable:(true false)' '--console[Get EC console, choose whether recent or to follow the output]:console:(recent follow)' '--reboot-ec[Control EC RO/RW jump]:reboot_ec:(reboot jump-ro jump-rw cancel-jump disable-jump)' '--hash[Hash a file of arbitrary data]:hash' From 1691c2cdb7f40c98bb9bde7f6b692870db54fc0a Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 17 Apr 2025 02:49:36 +0800 Subject: [PATCH 53/53] Bump to 0.3.0 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 10110b18..228dd7f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,7 @@ dependencies = [ [[package]] name = "framework_lib" -version = "0.2.1" +version = "0.3.0" dependencies = [ "built", "clap", @@ -420,7 +420,7 @@ dependencies = [ [[package]] name = "framework_tool" -version = "0.2.1" +version = "0.3.0" dependencies = [ "framework_lib", "static_vcruntime", @@ -428,7 +428,7 @@ dependencies = [ [[package]] name = "framework_uefi" -version = "0.2.1" +version = "0.3.0" dependencies = [ "framework_lib", "log", diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 3b802a81..27819125 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_lib" -version = "0.2.1" +version = "0.3.0" 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 1a6d4dec..d5a8958d 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_tool" -version = "0.2.1" +version = "0.3.0" edition = "2021" [features] diff --git a/framework_uefi/Cargo.toml b/framework_uefi/Cargo.toml index a8e579b0..8b7755c0 100644 --- a/framework_uefi/Cargo.toml +++ b/framework_uefi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_uefi" -version = "0.2.1" +version = "0.3.0" edition = "2021" # Minimum Supported Rust Version rust-version = "1.74" 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