From b84a1850488659d195a7ca4e5d58d3342d82acac Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 09:04:38 -0700 Subject: [PATCH 01/39] Use clap for an actual ectool CLI --- Cargo.lock | 194 ++++++++++++++++++++++++++++++++++++++++++++- ectool/Cargo.toml | 2 +- ectool/src/main.rs | 64 ++++++++++----- 3 files changed, 237 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98cec86..8b60ec6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,55 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "autocfg" version = "1.2.0" @@ -76,6 +125,46 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "color-eyre" version = "0.6.3" @@ -103,6 +192,12 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + [[package]] name = "crosec" version = "0.1.0" @@ -118,7 +213,7 @@ dependencies = [ name = "ectool" version = "0.1.0" dependencies = [ - "bytemuck", + "clap", "color-eyre", "crosec", ] @@ -139,12 +234,24 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "lazy_static" version = "1.4.0" @@ -263,6 +370,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.60" @@ -351,8 +464,87 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index a634273..3df6dae 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] crosec = { version = "0.1.0", path = "../crosec" } color-eyre = "0.6.2" -bytemuck = "1.16.0" +clap = { version = "4.5.4", features = ["derive"] } diff --git a/ectool/src/main.rs b/ectool/src/main.rs index ca73d0d..8e5f9bc 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,33 +1,55 @@ +use clap::{Parser, Subcommand}; use color_eyre::eyre::Result; use crosec::commands::{ get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version, }; +#[derive(Parser)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Checks for basic communication with EC + Hello, + /// Prints EC version + Version, + /// Prints chip info + ChipInfo +} + fn main() -> Result<()> { color_eyre::install()?; - println!("Hello command"); - let status = ec_cmd_hello()?; - if status { - println!("EC says hello!"); - } else { - println!("EC did not say hello :("); - } + let cli = Cli::parse(); - println!("Version command"); - let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version()?; - println!("RO version: {ro_ver}"); - println!("RW version: {rw_ver}"); - println!("Firmware copy: {firmware_copy}"); - println!("Build info: {build_info}"); - println!("Tool version: {tool_version}"); - - println!("Chip info command"); - let (vendor, name, revision) = ec_cmd_get_chip_info()?; - println!("Chip info:"); - println!(" vendor: {vendor}"); - println!(" name: {name}"); - println!(" revision: {revision}"); + match cli.command { + Commands::Hello => { + let status = ec_cmd_hello()?; + if status { + println!("EC says hello!"); + } else { + println!("EC did not say hello :("); + } + }, + Commands::Version => { + let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version()?; + println!("RO version: {ro_ver}"); + println!("RW version: {rw_ver}"); + println!("Firmware copy: {firmware_copy}"); + println!("Build info: {build_info}"); + println!("Tool version: {tool_version}"); + }, + Commands::ChipInfo => { + let (vendor, name, revision) = ec_cmd_get_chip_info()?; + println!("Chip info:"); + println!(" vendor: {vendor}"); + println!(" name: {name}"); + println!(" revision: {revision}"); + } + } Ok(()) } \ No newline at end of file From 1ba33c60abab9a328055d6eb588805c491e17a84 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 09:22:03 -0700 Subject: [PATCH 02/39] Board version command --- Cargo.lock | 6 ++++-- crosec/src/commands/board_version.rs | 9 +++++++++ crosec/src/commands/mod.rs | 5 +++++ ectool/Cargo.toml | 2 ++ ectool/src/main.rs | 13 ++++++++++--- 5 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 crosec/src/commands/board_version.rs diff --git a/Cargo.lock b/Cargo.lock index 8b60ec6..5d9c314 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,9 +213,11 @@ dependencies = [ name = "ectool" version = "0.1.0" dependencies = [ + "bytemuck", "clap", "color-eyre", "crosec", + "num-traits", ] [[package]] @@ -303,9 +305,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] diff --git a/crosec/src/commands/board_version.rs b/crosec/src/commands/board_version.rs new file mode 100644 index 0000000..022f1d0 --- /dev/null +++ b/crosec/src/commands/board_version.rs @@ -0,0 +1,9 @@ +use std::mem::size_of; +use crate::{ec_command, EcCmdResult, EcInterface}; +use crate::commands::CrosEcCmd; + +pub fn ec_cmd_board_version() -> EcCmdResult { + let mut result = ec_command(CrosEcCmd::GetBoardVersion, 0, Default::default(), EcInterface::Dev(String::from("/dev/cros_ec")))?; + result.resize(size_of::(), Default::default()); + Ok(u32::from_le_bytes(result.try_into().unwrap())) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index b9c4cc2..938cfa3 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -1,11 +1,16 @@ +use num_derive::FromPrimitive; + +#[derive(Copy, Clone, FromPrimitive)] #[repr(u32)] pub enum CrosEcCmd { Hello = 0x0001, Version = 0x0002, GetBuildInfo = 0x0004, GetChipInfo = 0x0005, + GetBoardVersion = 0x0006, } pub mod get_chip_info; pub mod hello; pub mod version; +pub mod board_version; diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index 3df6dae..bab205a 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -9,3 +9,5 @@ edition = "2021" crosec = { version = "0.1.0", path = "../crosec" } color-eyre = "0.6.2" clap = { version = "4.5.4", features = ["derive"] } +num-traits = "0.2.19" +bytemuck = "1.16.0" diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 8e5f9bc..1365d95 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -3,6 +3,7 @@ use color_eyre::eyre::Result; use crosec::commands::{ get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version, }; +use crosec::commands::board_version::ec_cmd_board_version; #[derive(Parser)] struct Cli { @@ -17,7 +18,9 @@ enum Commands { /// Prints EC version Version, /// Prints chip info - ChipInfo + ChipInfo, + /// Prints the board version + BoardVersion, } fn main() -> Result<()> { @@ -33,7 +36,7 @@ fn main() -> Result<()> { } else { println!("EC did not say hello :("); } - }, + } Commands::Version => { let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version()?; println!("RO version: {ro_ver}"); @@ -41,13 +44,17 @@ fn main() -> Result<()> { println!("Firmware copy: {firmware_copy}"); println!("Build info: {build_info}"); println!("Tool version: {tool_version}"); - }, + } Commands::ChipInfo => { let (vendor, name, revision) = ec_cmd_get_chip_info()?; println!("Chip info:"); println!(" vendor: {vendor}"); println!(" name: {name}"); println!(" revision: {revision}"); + }, + Commands::BoardVersion => { + let board_version = ec_cmd_board_version()?; + println!("Board version: {board_version}"); } } From 227d7ad236d817abc986e268b32dd45e96364421 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 11:01:27 -0700 Subject: [PATCH 03/39] Get command versions --- crosec/src/commands/get_cmd_versions.rs | 38 +++++++++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 21 ++++++++++++-- 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 crosec/src/commands/get_cmd_versions.rs diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs new file mode 100644 index 0000000..6512e79 --- /dev/null +++ b/crosec/src/commands/get_cmd_versions.rs @@ -0,0 +1,38 @@ +use bytemuck::{Pod, Zeroable}; +use crate::commands::CrosEcCmd; +use crate::{ec_command, EcCmdResult, EcInterface}; + +#[repr(C)] +#[derive(Pod, Copy, Clone, Zeroable)] +struct EcParamsGetCmdVersionV1 { + cmd: u16, +} + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +struct EcParamsGetCmdVersionV0 { + cmd: u8, +} + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +struct EcResponseGetCmdVersion { + version_mask: u32, +} + +pub fn ec_cmd_get_cmd_versions(cmd: CrosEcCmd) -> EcCmdResult { + let result = match ec_command(CrosEcCmd::GetCmdVersions, 1, bytemuck::bytes_of(&EcParamsGetCmdVersionV1 { + cmd: cmd as u16 + }), EcInterface::Default) { + Ok(response) => { + Ok(response) + }, + Err(_e) => { + ec_command(CrosEcCmd::GetCmdVersions, 0, bytemuck::bytes_of(&EcParamsGetCmdVersionV0 { + cmd: cmd as u8 + }), EcInterface::Default) + } + }?; + let response = bytemuck::from_bytes::(&result); + Ok(response.version_mask) +} \ No newline at end of file diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 938cfa3..ed41328 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -8,9 +8,11 @@ pub enum CrosEcCmd { GetBuildInfo = 0x0004, GetChipInfo = 0x0005, GetBoardVersion = 0x0006, + GetCmdVersions = 0x0008, } pub mod get_chip_info; pub mod hello; pub mod version; pub mod board_version; +pub mod get_cmd_versions; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 1365d95..e36e178 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,9 +1,9 @@ use clap::{Parser, Subcommand}; use color_eyre::eyre::Result; -use crosec::commands::{ - get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version, -}; +use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version}; use crosec::commands::board_version::ec_cmd_board_version; +use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; +use num_traits::cast::FromPrimitive; #[derive(Parser)] struct Cli { @@ -21,6 +21,10 @@ enum Commands { ChipInfo, /// Prints the board version BoardVersion, + /// Prints supported version mask for a command number + CmdVersions { + command: u32 + }, } fn main() -> Result<()> { @@ -55,6 +59,17 @@ fn main() -> Result<()> { Commands::BoardVersion => { let board_version = ec_cmd_board_version()?; println!("Board version: {board_version}"); + }, + Commands::CmdVersions {command} => { + match CrosEcCmd::from_u32(command) { + Some(cmd) => { + let versions = ec_cmd_get_cmd_versions(cmd)?; + println!("Versions: {versions:#b}"); + }, + None => { + println!("Unknown Command"); + } + } } } From fded85b565f6ea27e70106e882f48593bc257c08 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 11:32:19 -0700 Subject: [PATCH 04/39] Command version constants --- crosec/src/commands/get_cmd_versions.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index 6512e79..4d9375f 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -20,6 +20,9 @@ struct EcResponseGetCmdVersion { version_mask: u32, } +pub const V0: u32 = 0b01; +pub const V1: u32 = 0b10; + pub fn ec_cmd_get_cmd_versions(cmd: CrosEcCmd) -> EcCmdResult { let result = match ec_command(CrosEcCmd::GetCmdVersions, 1, bytemuck::bytes_of(&EcParamsGetCmdVersionV1 { cmd: cmd as u16 From 1d61b72160aeab107a00182853e92fb522d5cd95 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 11:33:43 -0700 Subject: [PATCH 05/39] Set fan target RPM --- crosec/src/commands/mod.rs | 2 ++ crosec/src/commands/set_fan_target_rpm.rs | 41 +++++++++++++++++++++++ ectool/src/main.rs | 18 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 crosec/src/commands/set_fan_target_rpm.rs diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index ed41328..cdc48b0 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -9,10 +9,12 @@ pub enum CrosEcCmd { GetChipInfo = 0x0005, GetBoardVersion = 0x0006, GetCmdVersions = 0x0008, + SetFanTargetRpm = 0x0021, } pub mod get_chip_info; pub mod hello; pub mod version; pub mod board_version; +pub mod set_fan_target_rpm; pub mod get_cmd_versions; diff --git a/crosec/src/commands/set_fan_target_rpm.rs b/crosec/src/commands/set_fan_target_rpm.rs new file mode 100644 index 0000000..1dffb91 --- /dev/null +++ b/crosec/src/commands/set_fan_target_rpm.rs @@ -0,0 +1,41 @@ +use std::mem::size_of; +use bytemuck::{Pod, Zeroable}; + +use crate::{ec_command, EcCmdResult, EcInterface}; +use crate::commands::CrosEcCmd; + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +struct EcParamsSetFanTargetRpmV0 { + rpm: u32, +} + +struct EcParamsSetFanTargetRpmV1 { + rpm: u32, + fan_index: u8, +} + +impl EcParamsSetFanTargetRpmV1 { + pub fn to_le_bytes(self) -> [u8; size_of::() + size_of::()] { + [self.rpm.to_le_bytes().to_vec(), self.fan_index.to_le_bytes().to_vec()].concat().try_into().unwrap() + } +} + +pub fn ec_cmd_set_fan_target_rpm(rpm: u32, fan_index: Option) -> EcCmdResult<()> { + // v0 can only set the RPM for all fans + // v1 can set the RPM for a specific fan + match fan_index { + Some(index) => { + ec_command(CrosEcCmd::SetFanTargetRpm, 1, &EcParamsSetFanTargetRpmV1 { + rpm, + fan_index: index, + }.to_le_bytes(), EcInterface::Default)?; + } + None => { + ec_command(CrosEcCmd::SetFanTargetRpm, 0, &bytemuck::bytes_of(&EcParamsSetFanTargetRpmV0 { + rpm + }), EcInterface::Default)?; + } + }; + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index e36e178..6a1d52a 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -4,6 +4,7 @@ use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec use crosec::commands::board_version::ec_cmd_board_version; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use num_traits::cast::FromPrimitive; +use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; #[derive(Parser)] struct Cli { @@ -25,6 +26,12 @@ enum Commands { CmdVersions { command: u32 }, + /// Set target fan RPM + SetFanTargetRpm { + rpm: u32, + #[arg()] + index: Option + } } fn main() -> Result<()> { @@ -70,6 +77,17 @@ fn main() -> Result<()> { println!("Unknown Command"); } } + }, + Commands::SetFanTargetRpm {rpm, index} => { + ec_cmd_set_fan_target_rpm(rpm, index)?; + match index { + Some(index) => { + println!("Set RPM to {rpm} for fan {index}"); + }, + None => { + println!("Set RPM to {rpm} for all fans"); + } + } } } From a94d8ce65a26923b0e64ffca14e3648d20d327f7 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 17 May 2024 16:01:36 -0700 Subject: [PATCH 06/39] Get EC features --- crosec/src/commands/get_features.rs | 15 +++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 9 ++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 crosec/src/commands/get_features.rs diff --git a/crosec/src/commands/get_features.rs b/crosec/src/commands/get_features.rs new file mode 100644 index 0000000..a8a83ea --- /dev/null +++ b/crosec/src/commands/get_features.rs @@ -0,0 +1,15 @@ +use bytemuck::{Pod, Zeroable}; +use crate::{ec_command, EcCmdResult, EcInterface}; +use crate::commands::CrosEcCmd; + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +struct EcResponseGetFeatures { + flags: u64, +} + +pub fn ec_cmd_get_features() -> EcCmdResult { + let response = ec_command(CrosEcCmd::GetFeatures, 0, Default::default(), EcInterface::Default)?; + let response = bytemuck::from_bytes::(&response); + Ok(response.flags) +} \ No newline at end of file diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index cdc48b0..a0c1016 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -9,6 +9,7 @@ pub enum CrosEcCmd { GetChipInfo = 0x0005, GetBoardVersion = 0x0006, GetCmdVersions = 0x0008, + GetFeatures = 0x000D, SetFanTargetRpm = 0x0021, } @@ -18,3 +19,4 @@ pub mod version; pub mod board_version; pub mod set_fan_target_rpm; pub mod get_cmd_versions; +pub mod get_features; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 6a1d52a..695b1f3 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -4,6 +4,7 @@ use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec use crosec::commands::board_version::ec_cmd_board_version; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use num_traits::cast::FromPrimitive; +use crosec::commands::get_features::ec_cmd_get_features; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; #[derive(Parser)] @@ -31,7 +32,9 @@ enum Commands { rpm: u32, #[arg()] index: Option - } + }, + /// Get supported features + GetFeatures } fn main() -> Result<()> { @@ -88,6 +91,10 @@ fn main() -> Result<()> { println!("Set RPM to {rpm} for all fans"); } } + }, + Commands::GetFeatures => { + let features = ec_cmd_get_features()?; + println!("EC supported features: {features:#b}"); } } From ed15d217782aecd003fa60e48855fa4001525db4 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 18 May 2024 16:18:46 -0700 Subject: [PATCH 07/39] Get number of fans Includes a big change that needs a fd to be provided to all ec command functions --- crosec/src/commands/board_version.rs | 9 +++-- crosec/src/commands/get_chip_info.rs | 8 ++-- crosec/src/commands/get_cmd_versions.rs | 11 +++-- crosec/src/commands/get_features.rs | 11 +++-- crosec/src/commands/hello.rs | 8 ++-- crosec/src/commands/mod.rs | 2 + crosec/src/commands/read_mem.rs | 36 +++++++++++++++++ crosec/src/commands/set_fan_target_rpm.rs | 11 +++-- crosec/src/commands/version.rs | 11 ++--- crosec/src/{dev.rs => ec_command.rs} | 13 ++---- crosec/src/get_number_of_fans.rs | 39 ++++++++++++++++++ crosec/src/lib.rs | 20 +++++---- crosec/src/read_mem_any.rs | 12 ++++++ ectool/src/main.rs | 49 ++++++++++++++--------- 14 files changed, 177 insertions(+), 63 deletions(-) create mode 100644 crosec/src/commands/read_mem.rs rename crosec/src/{dev.rs => ec_command.rs} (77%) create mode 100644 crosec/src/get_number_of_fans.rs create mode 100644 crosec/src/read_mem_any.rs diff --git a/crosec/src/commands/board_version.rs b/crosec/src/commands/board_version.rs index 022f1d0..b77469c 100644 --- a/crosec/src/commands/board_version.rs +++ b/crosec/src/commands/board_version.rs @@ -1,9 +1,12 @@ +use std::ffi::c_int; use std::mem::size_of; -use crate::{ec_command, EcCmdResult, EcInterface}; + use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command; +use crate::EcCmdResult; -pub fn ec_cmd_board_version() -> EcCmdResult { - let mut result = ec_command(CrosEcCmd::GetBoardVersion, 0, Default::default(), EcInterface::Dev(String::from("/dev/cros_ec")))?; +pub fn ec_cmd_board_version(fd: c_int) -> EcCmdResult { + let mut result = ec_command(CrosEcCmd::GetBoardVersion, 0, Default::default(), fd)?; result.resize(size_of::(), Default::default()); Ok(u32::from_le_bytes(result.try_into().unwrap())) } diff --git a/crosec/src/commands/get_chip_info.rs b/crosec/src/commands/get_chip_info.rs index e6cf836..6e83103 100644 --- a/crosec/src/commands/get_chip_info.rs +++ b/crosec/src/commands/get_chip_info.rs @@ -1,6 +1,8 @@ use bytemuck::{Pod, Zeroable}; +use nix::libc::c_int; -use crate::{commands::CrosEcCmd, ec_command, EcCmdResult, EcInterface}; +use crate::{commands::CrosEcCmd, EcCmdResult}; +use crate::ec_command::ec_command; #[repr(C, align(4))] #[derive(Pod, Zeroable, Copy, Clone)] @@ -10,7 +12,7 @@ struct EcResponseGetChipInfo { revision: [u8; 32], } -pub fn ec_cmd_get_chip_info() -> EcCmdResult<(String, String, String)> { +pub fn ec_cmd_get_chip_info(fd: c_int) -> EcCmdResult<(String, String, String)> { let params = EcResponseGetChipInfo { vendor: [0; 32], name: [0; 32], @@ -19,7 +21,7 @@ pub fn ec_cmd_get_chip_info() -> EcCmdResult<(String, String, String)> { let params_slice = bytemuck::bytes_of(¶ms); - let result = ec_command(CrosEcCmd::GetChipInfo, 0, params_slice, EcInterface::Dev(String::from("/dev/cros_ec")))?; + let result = ec_command(CrosEcCmd::GetChipInfo, 0, params_slice, fd)?; let response = bytemuck::from_bytes::(&result); let vendor = String::from_utf8(response.vendor.to_vec()).unwrap_or_default(); diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index 4d9375f..1fb4071 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -1,6 +1,9 @@ use bytemuck::{Pod, Zeroable}; +use nix::libc::c_int; + use crate::commands::CrosEcCmd; -use crate::{ec_command, EcCmdResult, EcInterface}; +use crate::ec_command::ec_command; +use crate::EcCmdResult; #[repr(C)] #[derive(Pod, Copy, Clone, Zeroable)] @@ -23,17 +26,17 @@ struct EcResponseGetCmdVersion { pub const V0: u32 = 0b01; pub const V1: u32 = 0b10; -pub fn ec_cmd_get_cmd_versions(cmd: CrosEcCmd) -> EcCmdResult { +pub fn ec_cmd_get_cmd_versions(fd: c_int, cmd: CrosEcCmd) -> EcCmdResult { let result = match ec_command(CrosEcCmd::GetCmdVersions, 1, bytemuck::bytes_of(&EcParamsGetCmdVersionV1 { cmd: cmd as u16 - }), EcInterface::Default) { + }), fd) { Ok(response) => { Ok(response) }, Err(_e) => { ec_command(CrosEcCmd::GetCmdVersions, 0, bytemuck::bytes_of(&EcParamsGetCmdVersionV0 { cmd: cmd as u8 - }), EcInterface::Default) + }), fd) } }?; let response = bytemuck::from_bytes::(&result); diff --git a/crosec/src/commands/get_features.rs b/crosec/src/commands/get_features.rs index a8a83ea..f2ab995 100644 --- a/crosec/src/commands/get_features.rs +++ b/crosec/src/commands/get_features.rs @@ -1,6 +1,9 @@ use bytemuck::{Pod, Zeroable}; -use crate::{ec_command, EcCmdResult, EcInterface}; +use nix::libc::c_int; + use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command; +use crate::EcCmdResult; #[repr(C)] #[derive(Pod, Zeroable, Copy, Clone)] @@ -8,8 +11,10 @@ struct EcResponseGetFeatures { flags: u64, } -pub fn ec_cmd_get_features() -> EcCmdResult { - let response = ec_command(CrosEcCmd::GetFeatures, 0, Default::default(), EcInterface::Default)?; +pub const EC_FEATURE_PWM_FAN: u64 = 0b100; + +pub fn ec_cmd_get_features(fd: c_int) -> EcCmdResult { + let response = ec_command(CrosEcCmd::GetFeatures, 0, Default::default(), fd)?; let response = bytemuck::from_bytes::(&response); Ok(response.flags) } \ No newline at end of file diff --git a/crosec/src/commands/hello.rs b/crosec/src/commands/hello.rs index 661c074..5a85c63 100644 --- a/crosec/src/commands/hello.rs +++ b/crosec/src/commands/hello.rs @@ -1,6 +1,8 @@ use bytemuck::{NoUninit, Pod, Zeroable}; +use nix::libc::c_int; -use crate::{commands::CrosEcCmd, ec_command, EcCmdResult, EcInterface}; +use crate::{commands::CrosEcCmd, EcCmdResult}; +use crate::ec_command::ec_command; const INPUT_DATA: u32 = 0xa0b0c0d0; const EXPECTED_OUTPUT: u32 = 0xa1b2c3d4; @@ -17,13 +19,13 @@ struct EcResponseHello { out_data: u32, } -pub fn ec_cmd_hello() -> EcCmdResult { +pub fn ec_cmd_hello(fd: c_int) -> EcCmdResult { let params = EcParamsHello { in_data: INPUT_DATA, }; let params_slice = bytemuck::bytes_of(¶ms); - let result = ec_command(CrosEcCmd::Hello, 0, params_slice, EcInterface::Dev(String::from("/dev/cros_ec")))?; + let result = ec_command(CrosEcCmd::Hello, 0, params_slice, fd)?; Ok(bytemuck::try_from_bytes::(&result).map_or( false, |response| response.out_data == EXPECTED_OUTPUT) diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index a0c1016..dff4954 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -8,6 +8,7 @@ pub enum CrosEcCmd { GetBuildInfo = 0x0004, GetChipInfo = 0x0005, GetBoardVersion = 0x0006, + ReadMemMap = 0x0007, GetCmdVersions = 0x0008, GetFeatures = 0x000D, SetFanTargetRpm = 0x0021, @@ -20,3 +21,4 @@ pub mod board_version; pub mod set_fan_target_rpm; pub mod get_cmd_versions; pub mod get_features; +pub mod read_mem; diff --git a/crosec/src/commands/read_mem.rs b/crosec/src/commands/read_mem.rs new file mode 100644 index 0000000..49a3c7e --- /dev/null +++ b/crosec/src/commands/read_mem.rs @@ -0,0 +1,36 @@ +use std::ffi::c_int; +use bytemuck::{Pod, Zeroable}; +use nix::{ioctl_readwrite}; +use crate::CROS_EC_IOC_MAGIC; + +const EC_MEM_MAP_SIZE: usize = 255; + +#[repr(C, align(1))] +#[derive(Pod, Zeroable, Copy, Clone)] +struct EcParamsReadMem { + offset: u8, + size: u8, +} + +#[repr(C)] +struct EcResponseReadMemV2 { + offset: u32, + bytes: u32, + buffer: [u8; EC_MEM_MAP_SIZE], +} + +ioctl_readwrite!(cros_ec_read_mem, CROS_EC_IOC_MAGIC, 1, EcResponseReadMemV2); + +pub fn ec_cmd_read_mem(fd: c_int, offset: u32, bytes: u32) -> Result, c_int> { + let mut response = EcResponseReadMemV2 { + offset, + bytes, + buffer: [0; EC_MEM_MAP_SIZE], + }; + let status = unsafe { cros_ec_read_mem(fd, &mut response) }.unwrap(); + if status >= 0 { + Ok(response.buffer[..bytes as usize].to_vec()) + } else { + Err(status) + } +} diff --git a/crosec/src/commands/set_fan_target_rpm.rs b/crosec/src/commands/set_fan_target_rpm.rs index 1dffb91..2b74a80 100644 --- a/crosec/src/commands/set_fan_target_rpm.rs +++ b/crosec/src/commands/set_fan_target_rpm.rs @@ -1,8 +1,11 @@ +use std::ffi::c_int; use std::mem::size_of; + use bytemuck::{Pod, Zeroable}; -use crate::{ec_command, EcCmdResult, EcInterface}; use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command; +use crate::EcCmdResult; #[repr(C)] #[derive(Pod, Zeroable, Copy, Clone)] @@ -21,7 +24,7 @@ impl EcParamsSetFanTargetRpmV1 { } } -pub fn ec_cmd_set_fan_target_rpm(rpm: u32, fan_index: Option) -> EcCmdResult<()> { +pub fn ec_cmd_set_fan_target_rpm(fd: c_int, rpm: u32, fan_index: Option) -> EcCmdResult<()> { // v0 can only set the RPM for all fans // v1 can set the RPM for a specific fan match fan_index { @@ -29,12 +32,12 @@ pub fn ec_cmd_set_fan_target_rpm(rpm: u32, fan_index: Option) -> EcCmdResult ec_command(CrosEcCmd::SetFanTargetRpm, 1, &EcParamsSetFanTargetRpmV1 { rpm, fan_index: index, - }.to_le_bytes(), EcInterface::Default)?; + }.to_le_bytes(), fd)?; } None => { ec_command(CrosEcCmd::SetFanTargetRpm, 0, &bytemuck::bytes_of(&EcParamsSetFanTargetRpmV0 { rpm - }), EcInterface::Default)?; + }), fd)?; } }; Ok(()) diff --git a/crosec/src/commands/version.rs b/crosec/src/commands/version.rs index 97ea7b2..4456944 100644 --- a/crosec/src/commands/version.rs +++ b/crosec/src/commands/version.rs @@ -1,11 +1,12 @@ use std::mem::size_of; use bytemuck::{Pod, Zeroable}; +use nix::libc::c_int; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -use crate::{commands::CrosEcCmd, ec_command, EcCmdResult, EcInterface}; -use crate::dev::BUF_SIZE; +use crate::{commands::CrosEcCmd, EcCmdResult}; +use crate::ec_command::{BUF_SIZE, ec_command}; const TOOLVERSION: &str = env!("CARGO_PKG_VERSION"); @@ -28,7 +29,7 @@ enum EcImage { RwB = 4, } -pub fn ec_cmd_version() -> EcCmdResult<(String, String, String, String, String)> { +pub fn ec_cmd_version(fd: c_int) -> EcCmdResult<(String, String, String, String, String)> { let params = EcResponseVersionV1 { version_string_ro: [0; 32], version_string_rw: [0; 32], @@ -40,7 +41,7 @@ pub fn ec_cmd_version() -> EcCmdResult<(String, String, String, String, String)> let build_string: [u8; BUF_SIZE] = [0; BUF_SIZE]; let params_slice = bytemuck::bytes_of(¶ms); - let mut result = ec_command(CrosEcCmd::Version, 0, params_slice, EcInterface::Dev(String::from("/dev/cros_ec")))?; + let mut result = ec_command(CrosEcCmd::Version, 0, params_slice, fd)?; result.resize(size_of::(), Default::default()); let response = bytemuck::from_bytes::(&result); @@ -58,7 +59,7 @@ pub fn ec_cmd_version() -> EcCmdResult<(String, String, String, String, String)> let build_string_slice = &build_string; - let result = ec_command(CrosEcCmd::GetBuildInfo, 0, build_string_slice, EcInterface::Dev(String::from("/dev/cros_ec")))?; + let result = ec_command(CrosEcCmd::GetBuildInfo, 0, build_string_slice, fd)?; let build_info = String::from_utf8(result).unwrap_or(String::from("")); Ok((ro_ver, rw_ver, image, build_info, String::from(TOOLVERSION))) diff --git a/crosec/src/dev.rs b/crosec/src/ec_command.rs similarity index 77% rename from crosec/src/dev.rs rename to crosec/src/ec_command.rs index 42ac48c..134e471 100644 --- a/crosec/src/dev.rs +++ b/crosec/src/ec_command.rs @@ -1,10 +1,9 @@ -use std::fs::File; +use std::os::raw::c_int; use crate::commands::CrosEcCmd; -use crate::EcCmdResult; +use crate::{CROS_EC_IOC_MAGIC, EcCmdResult}; use crate::EcError; use nix::ioctl_readwrite; use num_traits::FromPrimitive; -use std::os::unix::io::AsRawFd; use super::EcResponseStatus; @@ -31,10 +30,9 @@ struct CrosEcCommandV2 { data: [u8; IN_SIZE], } -const CROS_EC_IOC_MAGIC: u8 = 0xEC; ioctl_readwrite!(cros_ec_cmd, CROS_EC_IOC_MAGIC, 0, _CrosEcCommandV2); -pub fn dev_ec_command(command: CrosEcCmd, command_version: u8, data: &[u8], dev_path: &str) -> EcCmdResult> { +pub fn ec_command(command: CrosEcCmd, command_version: u8, data: &[u8], fd: c_int) -> EcCmdResult> { let size = std::cmp::min(IN_SIZE, data.len()); @@ -50,10 +48,7 @@ pub fn dev_ec_command(command: CrosEcCmd, command_version: u8, data: &[u8], dev_ cmd.data[0..size].copy_from_slice(data); let cmd_ptr = &mut cmd as *mut _ as *mut _CrosEcCommandV2; - let cros_ec_fd = File::open(dev_path).unwrap(); - let fildes = cros_ec_fd.as_raw_fd(); - - let result = unsafe { cros_ec_cmd(fildes, cmd_ptr) }; + let result = unsafe { cros_ec_cmd(fd, cmd_ptr) }; let status = FromPrimitive::from_u32(cmd.result).ok_or(EcError::UnknownResponseCode(cmd.result))?; let EcResponseStatus::Success = status else { diff --git a/crosec/src/get_number_of_fans.rs b/crosec/src/get_number_of_fans.rs new file mode 100644 index 0000000..e3779de --- /dev/null +++ b/crosec/src/get_number_of_fans.rs @@ -0,0 +1,39 @@ +use std::ffi::c_int; +use std::fmt::{Debug, Display, Formatter}; +use crate::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; +use crate::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_MEM_MAP_FAN, EcError}; +use crate::read_mem_any::read_mem_any; + +#[derive(Debug)] +pub enum Error { + GetFeatures(EcError), + ReadMem(c_int), +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::GetFeatures(e) => { + write!(f, "Error getting features: {:#?}", e) + }, + Self::ReadMem(e) => { + write!(f, "Error reading memory: {:#?}", e) + } + } + } +} + +pub fn get_number_of_fans(fd: c_int) -> Result { + let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; + let number_of_fans = if features & EC_FEATURE_PWM_FAN != 0 { + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN).map_err(|e| Error::ReadMem(e))? + .into_iter() + .filter(|data| *data != EC_FAN_SPEED_NOT_PRESENT) + .count() + } else { + 0 + }; + Ok(number_of_fans) +} \ No newline at end of file diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index d59d0f0..b04ebb0 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -1,12 +1,12 @@ -pub mod commands; -pub mod dev; - -use crate::commands::CrosEcCmd; -use dev::dev_ec_command; use nix::errno::Errno; use num_derive::FromPrimitive; use thiserror::Error; +pub mod commands; +pub mod ec_command; +pub mod read_mem_any; +pub mod get_number_of_fans; + // In the future, portio should be supported as well pub enum EcInterface { Dev(String), @@ -50,9 +50,7 @@ pub enum EcError { pub type EcCmdResult = Result; -pub fn ec_command(command: CrosEcCmd, command_version: u8, data: &[u8], interface: EcInterface) -> EcCmdResult> { - match interface { - EcInterface::Dev(path) => dev_ec_command(command, command_version, data, &path), - EcInterface::Default => dev_ec_command(command, command_version, data, "/dev/cros_ec"), - } -} \ No newline at end of file +pub const EC_FAN_SPEED_ENTRIES: usize = 4; +pub const EC_FAN_SPEED_NOT_PRESENT: u16 = 0xffff; +pub const EC_MEM_MAP_FAN: u8 = 0x10; +pub const CROS_EC_IOC_MAGIC: u8 = 0xEC; diff --git a/crosec/src/read_mem_any.rs b/crosec/src/read_mem_any.rs new file mode 100644 index 0000000..157996c --- /dev/null +++ b/crosec/src/read_mem_any.rs @@ -0,0 +1,12 @@ +use std::ffi::c_int; +use std::mem::size_of; + +use bytemuck::AnyBitPattern; + +use crate::commands::read_mem::ec_cmd_read_mem; + +pub fn read_mem_any(fd: c_int, offset: u8) -> Result { + let result = ec_cmd_read_mem(fd, offset as u32, size_of::() as u32)?; + let result = bytemuck::from_bytes(&result); + Ok(*result) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 695b1f3..217c850 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,11 +1,16 @@ +use std::fs::File; +use std::os::fd::AsRawFd; + use clap::{Parser, Subcommand}; use color_eyre::eyre::Result; +use num_traits::cast::FromPrimitive; + use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version}; use crosec::commands::board_version::ec_cmd_board_version; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; -use num_traits::cast::FromPrimitive; use crosec::commands::get_features::ec_cmd_get_features; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; +use crosec::get_number_of_fans::get_number_of_fans; #[derive(Parser)] struct Cli { @@ -31,20 +36,24 @@ enum Commands { SetFanTargetRpm { rpm: u32, #[arg()] - index: Option + index: Option, }, /// Get supported features - GetFeatures + GetFeatures, + /// Get number of fans + GetNumberOfFans, } fn main() -> Result<()> { color_eyre::install()?; let cli = Cli::parse(); + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); match cli.command { Commands::Hello => { - let status = ec_cmd_hello()?; + let status = ec_cmd_hello(fd)?; if status { println!("EC says hello!"); } else { @@ -52,7 +61,7 @@ fn main() -> Result<()> { } } Commands::Version => { - let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version()?; + let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version(fd)?; println!("RO version: {ro_ver}"); println!("RW version: {rw_ver}"); println!("Firmware copy: {firmware_copy}"); @@ -60,42 +69,46 @@ fn main() -> Result<()> { println!("Tool version: {tool_version}"); } Commands::ChipInfo => { - let (vendor, name, revision) = ec_cmd_get_chip_info()?; + let (vendor, name, revision) = ec_cmd_get_chip_info(fd)?; println!("Chip info:"); println!(" vendor: {vendor}"); println!(" name: {name}"); println!(" revision: {revision}"); - }, + } Commands::BoardVersion => { - let board_version = ec_cmd_board_version()?; + let board_version = ec_cmd_board_version(fd)?; println!("Board version: {board_version}"); - }, - Commands::CmdVersions {command} => { + } + Commands::CmdVersions { command } => { match CrosEcCmd::from_u32(command) { Some(cmd) => { - let versions = ec_cmd_get_cmd_versions(cmd)?; + let versions = ec_cmd_get_cmd_versions(fd, cmd)?; println!("Versions: {versions:#b}"); - }, + } None => { println!("Unknown Command"); } } - }, - Commands::SetFanTargetRpm {rpm, index} => { - ec_cmd_set_fan_target_rpm(rpm, index)?; + } + Commands::SetFanTargetRpm { rpm, index } => { + ec_cmd_set_fan_target_rpm(fd, rpm, index)?; match index { Some(index) => { println!("Set RPM to {rpm} for fan {index}"); - }, + } None => { println!("Set RPM to {rpm} for all fans"); } } - }, + } Commands::GetFeatures => { - let features = ec_cmd_get_features()?; + let features = ec_cmd_get_features(fd)?; println!("EC supported features: {features:#b}"); } + Commands::GetNumberOfFans => { + let number_of_fans = get_number_of_fans(fd).unwrap(); + println!("Number of fans: {number_of_fans}"); + } } Ok(()) From 14f2a73c05a6fcb96a341f6a9a2f3b3ca73223ee Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sun, 19 May 2024 22:29:51 -0700 Subject: [PATCH 08/39] Get fan RPM --- crosec/src/lib.rs | 1 + ectool/src/main.rs | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index b04ebb0..c24ec79 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -52,5 +52,6 @@ pub type EcCmdResult = Result; pub const EC_FAN_SPEED_ENTRIES: usize = 4; pub const EC_FAN_SPEED_NOT_PRESENT: u16 = 0xffff; +pub const EC_FAN_SPEED_STALLED: u16 = 0xfffe; pub const EC_MEM_MAP_FAN: u8 = 0x10; pub const CROS_EC_IOC_MAGIC: u8 = 0xEC; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 217c850..f400a71 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -8,9 +8,11 @@ use num_traits::cast::FromPrimitive; use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version}; use crosec::commands::board_version::ec_cmd_board_version; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; -use crosec::commands::get_features::ec_cmd_get_features; +use crosec::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; -use crosec::get_number_of_fans::get_number_of_fans; +use crosec::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN}; +use crosec::get_number_of_fans::{Error, get_number_of_fans}; +use crosec::read_mem_any::read_mem_any; #[derive(Parser)] struct Cli { @@ -42,6 +44,8 @@ enum Commands { GetFeatures, /// Get number of fans GetNumberOfFans, + /// Get the speed of fans, in RPM + GetFanRpm, } fn main() -> Result<()> { @@ -109,6 +113,25 @@ fn main() -> Result<()> { let number_of_fans = get_number_of_fans(fd).unwrap(); println!("Number of fans: {number_of_fans}"); } + Commands::GetFanRpm => { + let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; + if features & EC_FEATURE_PWM_FAN != 0 { + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN).map_err(|e| Error::ReadMem(e))? + .into_iter() + .enumerate() + .for_each(|(i, fan)| match fan { + EC_FAN_SPEED_NOT_PRESENT => {} + EC_FAN_SPEED_STALLED => { + println!("Fan {i} stalled"); + } + fan_speed => { + println!("Fan {i} RPM: {fan_speed}"); + } + }); + } else { + println!("No fans"); + }; + } } Ok(()) From 1120872a17733cb114cd134af20c1f36de3c81f7 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sun, 19 May 2024 22:47:02 -0700 Subject: [PATCH 09/39] ectool console --- crosec/src/commands/mod.rs | 2 ++ crosec/src/console.rs | 20 ++++++++++++++++++++ crosec/src/lib.rs | 1 + ectool/src/main.rs | 8 ++++++++ 4 files changed, 31 insertions(+) create mode 100644 crosec/src/console.rs diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index dff4954..0fddb36 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -12,6 +12,8 @@ pub enum CrosEcCmd { GetCmdVersions = 0x0008, GetFeatures = 0x000D, SetFanTargetRpm = 0x0021, + ConsoleSnapshot = 0x0097, + ConsoleRead = 0x0098, } pub mod get_chip_info; diff --git a/crosec/src/console.rs b/crosec/src/console.rs new file mode 100644 index 0000000..eb63262 --- /dev/null +++ b/crosec/src/console.rs @@ -0,0 +1,20 @@ +use std::ffi::c_int; + +use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command; +use crate::EcCmdResult; + +pub fn console(fd: c_int) -> EcCmdResult { + ec_command(CrosEcCmd::ConsoleSnapshot, 0, Default::default(), fd)?; + let mut console = String::default(); + loop { + let output = ec_command(CrosEcCmd::ConsoleRead, 0, Default::default(), fd)?; + let chunk = String::from_utf8(output).unwrap(); + if !chunk.is_empty() { + console += &chunk; + } else { + break; + } + } + Ok(console) +} diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index c24ec79..fd06361 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -6,6 +6,7 @@ pub mod commands; pub mod ec_command; pub mod read_mem_any; pub mod get_number_of_fans; +pub mod console; // In the future, portio should be supported as well pub enum EcInterface { diff --git a/ectool/src/main.rs b/ectool/src/main.rs index f400a71..3ef22c8 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -11,6 +11,7 @@ use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use crosec::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; use crosec::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN}; +use crosec::console::console; use crosec::get_number_of_fans::{Error, get_number_of_fans}; use crosec::read_mem_any::read_mem_any; @@ -46,6 +47,8 @@ enum Commands { GetNumberOfFans, /// Get the speed of fans, in RPM GetFanRpm, + /// Prints the last output to the EC debug console + Console, } fn main() -> Result<()> { @@ -131,6 +134,11 @@ fn main() -> Result<()> { } else { println!("No fans"); }; + }, + Commands::Console => { + let console = console(fd)?; + let console = console.trim(); + println!("{console}"); } } From 5e1b846c03a312385806d21e3d8dd5f61e9d9cdf Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Mon, 20 May 2024 13:51:45 -0700 Subject: [PATCH 10/39] Battery command --- crosec/src/battery.rs | 59 +++++++++++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 3 +- crosec/src/lib.rs | 28 +++++++++++++++++ crosec/src/read_mem_string.rs | 8 +++++ ectool/src/main.rs | 7 +++++ 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 crosec/src/battery.rs create mode 100644 crosec/src/read_mem_string.rs diff --git a/crosec/src/battery.rs b/crosec/src/battery.rs new file mode 100644 index 0000000..e7b88ec --- /dev/null +++ b/crosec/src/battery.rs @@ -0,0 +1,59 @@ +use std::ffi::c_int; +use crate::commands::CrosEcCmd; +use crate::commands::get_cmd_versions::{ec_cmd_get_cmd_versions, V1}; +use crate::{EC_MEM_MAP_BATTERY_CAPACITY, EC_MEM_MAP_BATTERY_CYCLE_COUNT, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE, EC_MEM_MAP_BATTERY_FLAGS, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY, EC_MEM_MAP_BATTERY_MANUFACTURER, EC_MEM_MAP_BATTERY_MODEL, EC_MEM_MAP_BATTERY_RATE, EC_MEM_MAP_BATTERY_SERIAL, EC_MEM_MAP_BATTERY_TYPE, EC_MEM_MAP_BATTERY_VERSION, EC_MEM_MAP_BATTERY_VOLTAGE, EcCmdResult}; +use crate::read_mem_any::read_mem_any; +use crate::read_mem_string::read_mem_string; + +#[derive(Debug, Clone)] +pub struct BatteryInfo { + pub oem_name: String, + pub model_number: String, + pub chemistry: String, + pub serial_number: String, + pub design_capacity: i32, + pub last_full_charge: i32, + pub design_output_voltage: i32, + pub cycle_count: i32, + pub present_voltage: i32, + pub present_current: i32, + pub remaining_capacity: i32, + pub flags: u8, +} + +pub fn battery(fd: c_int) -> EcCmdResult { + if ec_cmd_get_cmd_versions(fd, CrosEcCmd::BatteryGetStatic)? & V1 != 0 { + panic!("Battery info needs to be gotten with the {:?} command", CrosEcCmd::BatteryGetStatic); + } else { + let battery_version = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VERSION).unwrap(); + if battery_version < 1 { + panic!("Battery version {battery_version} is not supported"); + } + let flags = read_mem_any::(fd, EC_MEM_MAP_BATTERY_FLAGS).unwrap(); + let oem_name = read_mem_string(fd, EC_MEM_MAP_BATTERY_MANUFACTURER).unwrap(); + let model_number = read_mem_string(fd, EC_MEM_MAP_BATTERY_MODEL).unwrap(); + let chemistry = read_mem_string(fd, EC_MEM_MAP_BATTERY_TYPE).unwrap(); + let serial_number = read_mem_string(fd, EC_MEM_MAP_BATTERY_SERIAL).unwrap(); + let design_capacity = read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY).unwrap(); + let last_full_charge = read_mem_any::(fd, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY).unwrap(); + let design_output_voltage = read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE).unwrap(); + let cycle_count = read_mem_any::(fd, EC_MEM_MAP_BATTERY_CYCLE_COUNT).unwrap(); + let present_voltage = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VOLTAGE).unwrap(); + let present_current = read_mem_any::(fd, EC_MEM_MAP_BATTERY_RATE).unwrap(); + let remaining_capacity = read_mem_any::(fd, EC_MEM_MAP_BATTERY_CAPACITY).unwrap(); + Ok(BatteryInfo { + flags, + oem_name, + model_number, + chemistry, + serial_number, + design_capacity, + last_full_charge, + design_output_voltage, + cycle_count, + present_voltage, + present_current, + remaining_capacity + }) + } +} \ No newline at end of file diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 0fddb36..cdf2cb0 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -1,6 +1,6 @@ use num_derive::FromPrimitive; -#[derive(Copy, Clone, FromPrimitive)] +#[derive(Copy, Clone, FromPrimitive, Debug)] #[repr(u32)] pub enum CrosEcCmd { Hello = 0x0001, @@ -14,6 +14,7 @@ pub enum CrosEcCmd { SetFanTargetRpm = 0x0021, ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, + BatteryGetStatic = 0x0600, } pub mod get_chip_info; diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index fd06361..91ac1a9 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -7,6 +7,8 @@ pub mod ec_command; pub mod read_mem_any; pub mod get_number_of_fans; pub mod console; +pub mod battery; +pub mod read_mem_string; // In the future, portio should be supported as well pub enum EcInterface { @@ -51,8 +53,34 @@ pub enum EcError { pub type EcCmdResult = Result; + pub const EC_FAN_SPEED_ENTRIES: usize = 4; pub const EC_FAN_SPEED_NOT_PRESENT: u16 = 0xffff; pub const EC_FAN_SPEED_STALLED: u16 = 0xfffe; +pub const EC_MEM_MAP_MAX_TEXT_SIZE: usize = 8; + pub const EC_MEM_MAP_FAN: u8 = 0x10; +/// Version of data in 0x40 - 0x7f +pub const EC_MEM_MAP_BATTERY_VERSION: u8 = 0x24; +/// Battery Present Voltage +pub const EC_MEM_MAP_BATTERY_VOLTAGE: u8 = 0x40; +/// Battery Present Rate +pub const EC_MEM_MAP_BATTERY_RATE: u8 = 0x44; +/// Battery Remaining Capacity +pub const EC_MEM_MAP_BATTERY_CAPACITY: u8 = 0x48; +/// Battery State, see below (8-bit) +pub const EC_MEM_MAP_BATTERY_FLAGS: u8 = 0x4c; +/// Battery Count (8-bit) +pub const EC_MEM_MAP_BATTERY_COUNT: u8 = 0x4d; +/// Current Battery Data Index (8-bit) +pub const EC_MEM_MAP_BATTERY_INDEX: u8 = 0x4e; +pub const EC_MEM_MAP_BATTERY_DESIGN_CAPACITY: u8 = 0x50; +pub const EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE: u8 = 0x54; +pub const EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY: u8 = 0x58; +pub const EC_MEM_MAP_BATTERY_CYCLE_COUNT: u8 = 0x5c; +pub const EC_MEM_MAP_BATTERY_MANUFACTURER: u8 = 0x60; +pub const EC_MEM_MAP_BATTERY_MODEL: u8 = 0x68; +pub const EC_MEM_MAP_BATTERY_SERIAL: u8 = 0x70; +pub const EC_MEM_MAP_BATTERY_TYPE: u8 = 0x78; + pub const CROS_EC_IOC_MAGIC: u8 = 0xEC; diff --git a/crosec/src/read_mem_string.rs b/crosec/src/read_mem_string.rs new file mode 100644 index 0000000..fc95453 --- /dev/null +++ b/crosec/src/read_mem_string.rs @@ -0,0 +1,8 @@ +use std::ffi::c_int; +use crate::commands::read_mem::ec_cmd_read_mem; +use crate::EC_MEM_MAP_MAX_TEXT_SIZE; + +pub fn read_mem_string(fd: c_int, offset: u8) -> Result { + let string = ec_cmd_read_mem(fd, offset as u32, EC_MEM_MAP_MAX_TEXT_SIZE as u32)?; + Ok(String::from_utf8(string).unwrap()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 3ef22c8..9fd036a 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -11,6 +11,7 @@ use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use crosec::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; use crosec::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN}; +use crosec::battery::battery; use crosec::console::console; use crosec::get_number_of_fans::{Error, get_number_of_fans}; use crosec::read_mem_any::read_mem_any; @@ -49,6 +50,8 @@ enum Commands { GetFanRpm, /// Prints the last output to the EC debug console Console, + /// Prints battery info + Battery } fn main() -> Result<()> { @@ -139,6 +142,10 @@ fn main() -> Result<()> { let console = console(fd)?; let console = console.trim(); println!("{console}"); + }, + Commands::Battery => { + let battery_info = battery(fd)?; + println!("{battery_info:#?}"); } } From 7f4d0aa3accb2ef0be1d6f22c1de49fd1b9761ee Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 29 May 2024 18:03:29 -0700 Subject: [PATCH 11/39] Charge control commands --- crosec/src/commands/charge_control.rs | 74 ++++++++++++++++ crosec/src/commands/get_cmd_versions.rs | 5 +- crosec/src/commands/mod.rs | 2 + ectool/src/main.rs | 108 +++++++++++++++++++----- 4 files changed, 165 insertions(+), 24 deletions(-) create mode 100644 crosec/src/commands/charge_control.rs diff --git a/crosec/src/commands/charge_control.rs b/crosec/src/commands/charge_control.rs new file mode 100644 index 0000000..3c5748f --- /dev/null +++ b/crosec/src/commands/charge_control.rs @@ -0,0 +1,74 @@ +use crate::commands::get_cmd_versions::{ec_cmd_get_cmd_versions, V2}; +use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command; +use crate::EcCmdResult; +use bytemuck::{Pod, Zeroable}; +use std::ffi::c_int; + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)] +pub struct Sustainer { + pub min_percent: i8, + pub max_percent: i8, +} + +#[derive(Debug)] +pub enum ChargeControl { + Normal(Option), + Idle, + Discharge, +} + +pub fn supports_get_and_sustainer(fd: c_int) -> EcCmdResult { + let versions = ec_cmd_get_cmd_versions(fd, CrosEcCmd::ChargeControl)?; + Ok(versions & V2 != 0) +} + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +pub struct EcParamsChargeControl { + mode: u32, + command: u8, + reserved: u8, + sustain: Sustainer, +} + +const CHARGE_CONTROL_MODE_SET: u8 = 0; +// const CHARGE_CONTROL_MODE_GET: u8 = 1; + +const CHARGE_CONTROL_COMMAND_NORMAL: u32 = 0; +const CHARGE_CONTROL_COMMAND_IDLE: u32 = 1; +const CHARGE_CONTROL_COMMAND_DISCHARGE: u32 = 2; + +pub fn get_charge_control(_fd: c_int) -> EcCmdResult { + panic!("Not implemented yet"); +} + +pub fn set_charge_control(fd: c_int, charge_control: ChargeControl) -> EcCmdResult<()> { + let params = EcParamsChargeControl { + command: CHARGE_CONTROL_MODE_SET, + mode: match charge_control { + ChargeControl::Normal(_) => CHARGE_CONTROL_COMMAND_NORMAL, + ChargeControl::Idle => CHARGE_CONTROL_COMMAND_IDLE, + ChargeControl::Discharge => CHARGE_CONTROL_COMMAND_DISCHARGE, + }, + reserved: Default::default(), + sustain: match charge_control { + ChargeControl::Normal(sustain) => sustain.unwrap_or(Sustainer { + min_percent: -1, + max_percent: -1, + }), + _ => Default::default(), + }, + }; + ec_command( + CrosEcCmd::ChargeControl, + { + let version = ec_cmd_get_cmd_versions(fd, CrosEcCmd::ChargeControl)?; + Ok(if version & V2 != 0 { 2 } else { 1 }) + }?, + bytemuck::bytes_of(¶ms), + fd, + )?; + Ok(()) +} diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index 1fb4071..2ca4ab1 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -23,8 +23,9 @@ struct EcResponseGetCmdVersion { version_mask: u32, } -pub const V0: u32 = 0b01; -pub const V1: u32 = 0b10; +pub const V0: u32 = 0b001; +pub const V1: u32 = 0b010; +pub const V2: u32 = 0b100; pub fn ec_cmd_get_cmd_versions(fd: c_int, cmd: CrosEcCmd) -> EcCmdResult { let result = match ec_command(CrosEcCmd::GetCmdVersions, 1, bytemuck::bytes_of(&EcParamsGetCmdVersionV1 { diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index cdf2cb0..a33dfee 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -12,6 +12,7 @@ pub enum CrosEcCmd { GetCmdVersions = 0x0008, GetFeatures = 0x000D, SetFanTargetRpm = 0x0021, + ChargeControl = 0x0096, ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, BatteryGetStatic = 0x0600, @@ -25,3 +26,4 @@ pub mod set_fan_target_rpm; pub mod get_cmd_versions; pub mod get_features; pub mod read_mem; +pub mod charge_control; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 9fd036a..2939e8a 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -5,16 +5,24 @@ use clap::{Parser, Subcommand}; use color_eyre::eyre::Result; use num_traits::cast::FromPrimitive; -use crosec::commands::{CrosEcCmd, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version}; +use crosec::battery::battery; use crosec::commands::board_version::ec_cmd_board_version; +use crosec::commands::charge_control::{ + get_charge_control, set_charge_control, supports_get_and_sustainer, Sustainer, +}; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use crosec::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; -use crosec::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN}; -use crosec::battery::battery; +use crosec::commands::{ + charge_control, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, + version::ec_cmd_version, CrosEcCmd, +}; use crosec::console::console; -use crosec::get_number_of_fans::{Error, get_number_of_fans}; +use crosec::get_number_of_fans::{get_number_of_fans, Error}; use crosec::read_mem_any::read_mem_any; +use crosec::{ + EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, +}; #[derive(Parser)] struct Cli { @@ -33,9 +41,7 @@ enum Commands { /// Prints the board version BoardVersion, /// Prints supported version mask for a command number - CmdVersions { - command: u32 - }, + CmdVersions { command: u32 }, /// Set target fan RPM SetFanTargetRpm { rpm: u32, @@ -51,7 +57,26 @@ enum Commands { /// Prints the last output to the EC debug console Console, /// Prints battery info - Battery + Battery, + ChargeControl { + #[command(subcommand)] + command: Option, + }, +} + +#[derive(Subcommand)] +enum ChargeControlSubcommands { + /// Charge the battery with external power and power the device with external power + Normal { + /// Minimum battery % to keep the battery at + min_percent: Option, + /// Maximum battery & to keep the battery at. If this isn't specified, this will be set to the same as the min %. + max_percent: Option, + }, + /// Power the device with external power, but do not charge the battery + Idle, + /// Power the device with the battery and do not charge the battery + Discharge, } fn main() -> Result<()> { @@ -89,17 +114,15 @@ fn main() -> Result<()> { let board_version = ec_cmd_board_version(fd)?; println!("Board version: {board_version}"); } - Commands::CmdVersions { command } => { - match CrosEcCmd::from_u32(command) { - Some(cmd) => { - let versions = ec_cmd_get_cmd_versions(fd, cmd)?; - println!("Versions: {versions:#b}"); - } - None => { - println!("Unknown Command"); - } + Commands::CmdVersions { command } => match CrosEcCmd::from_u32(command) { + Some(cmd) => { + let versions = ec_cmd_get_cmd_versions(fd, cmd)?; + println!("Versions: {versions:#b}"); } - } + None => { + println!("Unknown Command"); + } + }, Commands::SetFanTargetRpm { rpm, index } => { ec_cmd_set_fan_target_rpm(fd, rpm, index)?; match index { @@ -122,7 +145,8 @@ fn main() -> Result<()> { Commands::GetFanRpm => { let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; if features & EC_FEATURE_PWM_FAN != 0 { - read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN).map_err(|e| Error::ReadMem(e))? + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN) + .map_err(|e| Error::ReadMem(e))? .into_iter() .enumerate() .for_each(|(i, fan)| match fan { @@ -137,17 +161,57 @@ fn main() -> Result<()> { } else { println!("No fans"); }; - }, + } Commands::Console => { let console = console(fd)?; let console = console.trim(); println!("{console}"); - }, + } Commands::Battery => { let battery_info = battery(fd)?; println!("{battery_info:#?}"); } + Commands::ChargeControl { command } => match command { + None => { + if supports_get_and_sustainer(fd)? { + let charge_control = get_charge_control(fd)?; + println!("{charge_control:#?}"); + } else { + println!("This EC doesn't support getting charge control"); + } + } + Some(command) => match command { + ChargeControlSubcommands::Normal { + min_percent, + max_percent, + } => match min_percent { + Some(min_percent) => { + let max_percent = max_percent.unwrap_or(min_percent); + set_charge_control( + fd, + charge_control::ChargeControl::Normal(Some(Sustainer { + min_percent: min_percent as i8, + max_percent: max_percent as i8, + })), + )?; + println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); + } + None => { + set_charge_control(fd, charge_control::ChargeControl::Normal(None))?; + println!("Set charge control to normal"); + } + }, + ChargeControlSubcommands::Idle => { + println!("Set charge control to idle"); + set_charge_control(fd, charge_control::ChargeControl::Idle)?; + } + ChargeControlSubcommands::Discharge => { + println!("Set charge control to discharge"); + set_charge_control(fd, charge_control::ChargeControl::Discharge)?; + } + }, + }, } Ok(()) -} \ No newline at end of file +} From a33802e9249732f100214d1608f98f788d09fcd0 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:15:02 -0700 Subject: [PATCH 12/39] Add hello and console commands for cros_fp Made big changes to how the ec command function works to allow different input and output sizes at runtime instead of hard-coding max sizes. Initializes the minimum amount of memory necessary for an ec command. --- crosec/src/battery.rs | 28 +++-- crosec/src/commands/board_version.rs | 7 +- crosec/src/commands/charge_control.rs | 37 +++--- crosec/src/commands/get_chip_info.rs | 14 +-- crosec/src/commands/get_cmd_versions.rs | 29 ++--- crosec/src/commands/get_features.rs | 15 +-- crosec/src/commands/get_protocol_info.rs | 47 +++++++ crosec/src/commands/hello.rs | 21 ++-- crosec/src/commands/mod.rs | 12 +- crosec/src/commands/read_mem.rs | 6 +- crosec/src/commands/set_fan_target_rpm.rs | 33 +++-- crosec/src/commands/version.rs | 33 ++--- crosec/src/console.rs | 17 ++- crosec/src/ec_command.rs | 96 +++++++++------ crosec/src/get_number_of_fans.rs | 13 +- crosec/src/lib.rs | 8 +- ectool/src/main.rs | 143 +++++++++++++++------- 17 files changed, 348 insertions(+), 211 deletions(-) create mode 100644 crosec/src/commands/get_protocol_info.rs diff --git a/crosec/src/battery.rs b/crosec/src/battery.rs index e7b88ec..f991335 100644 --- a/crosec/src/battery.rs +++ b/crosec/src/battery.rs @@ -1,9 +1,16 @@ -use std::ffi::c_int; -use crate::commands::CrosEcCmd; use crate::commands::get_cmd_versions::{ec_cmd_get_cmd_versions, V1}; -use crate::{EC_MEM_MAP_BATTERY_CAPACITY, EC_MEM_MAP_BATTERY_CYCLE_COUNT, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE, EC_MEM_MAP_BATTERY_FLAGS, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY, EC_MEM_MAP_BATTERY_MANUFACTURER, EC_MEM_MAP_BATTERY_MODEL, EC_MEM_MAP_BATTERY_RATE, EC_MEM_MAP_BATTERY_SERIAL, EC_MEM_MAP_BATTERY_TYPE, EC_MEM_MAP_BATTERY_VERSION, EC_MEM_MAP_BATTERY_VOLTAGE, EcCmdResult}; +use crate::commands::CrosEcCmd; use crate::read_mem_any::read_mem_any; use crate::read_mem_string::read_mem_string; +use crate::{ + EcCmdResult, EC_MEM_MAP_BATTERY_CAPACITY, EC_MEM_MAP_BATTERY_CYCLE_COUNT, + EC_MEM_MAP_BATTERY_DESIGN_CAPACITY, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE, + EC_MEM_MAP_BATTERY_FLAGS, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY, + EC_MEM_MAP_BATTERY_MANUFACTURER, EC_MEM_MAP_BATTERY_MODEL, EC_MEM_MAP_BATTERY_RATE, + EC_MEM_MAP_BATTERY_SERIAL, EC_MEM_MAP_BATTERY_TYPE, EC_MEM_MAP_BATTERY_VERSION, + EC_MEM_MAP_BATTERY_VOLTAGE, +}; +use std::ffi::c_int; #[derive(Debug, Clone)] pub struct BatteryInfo { @@ -23,7 +30,10 @@ pub struct BatteryInfo { pub fn battery(fd: c_int) -> EcCmdResult { if ec_cmd_get_cmd_versions(fd, CrosEcCmd::BatteryGetStatic)? & V1 != 0 { - panic!("Battery info needs to be gotten with the {:?} command", CrosEcCmd::BatteryGetStatic); + panic!( + "Battery info needs to be gotten with the {:?} command", + CrosEcCmd::BatteryGetStatic + ); } else { let battery_version = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VERSION).unwrap(); if battery_version < 1 { @@ -35,8 +45,10 @@ pub fn battery(fd: c_int) -> EcCmdResult { let chemistry = read_mem_string(fd, EC_MEM_MAP_BATTERY_TYPE).unwrap(); let serial_number = read_mem_string(fd, EC_MEM_MAP_BATTERY_SERIAL).unwrap(); let design_capacity = read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY).unwrap(); - let last_full_charge = read_mem_any::(fd, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY).unwrap(); - let design_output_voltage = read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE).unwrap(); + let last_full_charge = + read_mem_any::(fd, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY).unwrap(); + let design_output_voltage = + read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE).unwrap(); let cycle_count = read_mem_any::(fd, EC_MEM_MAP_BATTERY_CYCLE_COUNT).unwrap(); let present_voltage = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VOLTAGE).unwrap(); let present_current = read_mem_any::(fd, EC_MEM_MAP_BATTERY_RATE).unwrap(); @@ -53,7 +65,7 @@ pub fn battery(fd: c_int) -> EcCmdResult { cycle_count, present_voltage, present_current, - remaining_capacity + remaining_capacity, }) } -} \ No newline at end of file +} diff --git a/crosec/src/commands/board_version.rs b/crosec/src/commands/board_version.rs index b77469c..3d18f7d 100644 --- a/crosec/src/commands/board_version.rs +++ b/crosec/src/commands/board_version.rs @@ -1,12 +1,9 @@ use std::ffi::c_int; -use std::mem::size_of; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; pub fn ec_cmd_board_version(fd: c_int) -> EcCmdResult { - let mut result = ec_command(CrosEcCmd::GetBoardVersion, 0, Default::default(), fd)?; - result.resize(size_of::(), Default::default()); - Ok(u32::from_le_bytes(result.try_into().unwrap())) + ec_command_bytemuck(CrosEcCmd::GetBoardVersion, 0, &(), fd) } diff --git a/crosec/src/commands/charge_control.rs b/crosec/src/commands/charge_control.rs index 3c5748f..2bfdb78 100644 --- a/crosec/src/commands/charge_control.rs +++ b/crosec/src/commands/charge_control.rs @@ -1,6 +1,6 @@ use crate::commands::get_cmd_versions::{ec_cmd_get_cmd_versions, V2}; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; use bytemuck::{Pod, Zeroable}; use std::ffi::c_int; @@ -45,29 +45,28 @@ pub fn get_charge_control(_fd: c_int) -> EcCmdResult { } pub fn set_charge_control(fd: c_int, charge_control: ChargeControl) -> EcCmdResult<()> { - let params = EcParamsChargeControl { - command: CHARGE_CONTROL_MODE_SET, - mode: match charge_control { - ChargeControl::Normal(_) => CHARGE_CONTROL_COMMAND_NORMAL, - ChargeControl::Idle => CHARGE_CONTROL_COMMAND_IDLE, - ChargeControl::Discharge => CHARGE_CONTROL_COMMAND_DISCHARGE, - }, - reserved: Default::default(), - sustain: match charge_control { - ChargeControl::Normal(sustain) => sustain.unwrap_or(Sustainer { - min_percent: -1, - max_percent: -1, - }), - _ => Default::default(), - }, - }; - ec_command( + ec_command_bytemuck( CrosEcCmd::ChargeControl, { let version = ec_cmd_get_cmd_versions(fd, CrosEcCmd::ChargeControl)?; Ok(if version & V2 != 0 { 2 } else { 1 }) }?, - bytemuck::bytes_of(¶ms), + &EcParamsChargeControl { + command: CHARGE_CONTROL_MODE_SET, + mode: match charge_control { + ChargeControl::Normal(_) => CHARGE_CONTROL_COMMAND_NORMAL, + ChargeControl::Idle => CHARGE_CONTROL_COMMAND_IDLE, + ChargeControl::Discharge => CHARGE_CONTROL_COMMAND_DISCHARGE, + }, + reserved: Default::default(), + sustain: match charge_control { + ChargeControl::Normal(sustain) => sustain.unwrap_or(Sustainer { + min_percent: -1, + max_percent: -1, + }), + _ => Default::default(), + }, + }, fd, )?; Ok(()) diff --git a/crosec/src/commands/get_chip_info.rs b/crosec/src/commands/get_chip_info.rs index 6e83103..af755ae 100644 --- a/crosec/src/commands/get_chip_info.rs +++ b/crosec/src/commands/get_chip_info.rs @@ -1,8 +1,7 @@ use bytemuck::{Pod, Zeroable}; use nix::libc::c_int; -use crate::{commands::CrosEcCmd, EcCmdResult}; -use crate::ec_command::ec_command; +use crate::{commands::CrosEcCmd, ec_command::ec_command_bytemuck, EcCmdResult}; #[repr(C, align(4))] #[derive(Pod, Zeroable, Copy, Clone)] @@ -13,16 +12,7 @@ struct EcResponseGetChipInfo { } pub fn ec_cmd_get_chip_info(fd: c_int) -> EcCmdResult<(String, String, String)> { - let params = EcResponseGetChipInfo { - vendor: [0; 32], - name: [0; 32], - revision: [0; 32], - }; - - let params_slice = bytemuck::bytes_of(¶ms); - - let result = ec_command(CrosEcCmd::GetChipInfo, 0, params_slice, fd)?; - let response = bytemuck::from_bytes::(&result); + let response: EcResponseGetChipInfo = ec_command_bytemuck(CrosEcCmd::GetChipInfo, 0, &(), fd)?; let vendor = String::from_utf8(response.vendor.to_vec()).unwrap_or_default(); let name = String::from_utf8(response.name.to_vec()).unwrap_or_default(); diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index 2ca4ab1..84e3bd3 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -2,7 +2,7 @@ use bytemuck::{Pod, Zeroable}; use nix::libc::c_int; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; #[repr(C)] @@ -28,18 +28,19 @@ pub const V1: u32 = 0b010; pub const V2: u32 = 0b100; pub fn ec_cmd_get_cmd_versions(fd: c_int, cmd: CrosEcCmd) -> EcCmdResult { - let result = match ec_command(CrosEcCmd::GetCmdVersions, 1, bytemuck::bytes_of(&EcParamsGetCmdVersionV1 { - cmd: cmd as u16 - }), fd) { - Ok(response) => { - Ok(response) - }, - Err(_e) => { - ec_command(CrosEcCmd::GetCmdVersions, 0, bytemuck::bytes_of(&EcParamsGetCmdVersionV0 { - cmd: cmd as u8 - }), fd) - } + let response: EcResponseGetCmdVersion = match ec_command_bytemuck( + CrosEcCmd::GetCmdVersions, + 1, + &EcParamsGetCmdVersionV1 { cmd: cmd as u16 }, + fd, + ) { + Ok(response) => Ok(response), + Err(_e) => ec_command_bytemuck( + CrosEcCmd::GetCmdVersions, + 0, + &EcParamsGetCmdVersionV0 { cmd: cmd as u8 }, + fd, + ), }?; - let response = bytemuck::from_bytes::(&result); Ok(response.version_mask) -} \ No newline at end of file +} diff --git a/crosec/src/commands/get_features.rs b/crosec/src/commands/get_features.rs index f2ab995..7a443a3 100644 --- a/crosec/src/commands/get_features.rs +++ b/crosec/src/commands/get_features.rs @@ -1,20 +1,11 @@ -use bytemuck::{Pod, Zeroable}; use nix::libc::c_int; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; -#[repr(C)] -#[derive(Pod, Zeroable, Copy, Clone)] -struct EcResponseGetFeatures { - flags: u64, -} - pub const EC_FEATURE_PWM_FAN: u64 = 0b100; pub fn ec_cmd_get_features(fd: c_int) -> EcCmdResult { - let response = ec_command(CrosEcCmd::GetFeatures, 0, Default::default(), fd)?; - let response = bytemuck::from_bytes::(&response); - Ok(response.flags) -} \ No newline at end of file + ec_command_bytemuck(CrosEcCmd::GetFeatures, 0, &(), fd) +} diff --git a/crosec/src/commands/get_protocol_info.rs b/crosec/src/commands/get_protocol_info.rs new file mode 100644 index 0000000..3b7f64a --- /dev/null +++ b/crosec/src/commands/get_protocol_info.rs @@ -0,0 +1,47 @@ +use std::{ffi::c_int, mem::size_of}; + +use bytemuck::{Pod, Zeroable}; + +use crate::{commands::CrosEcCmd, ec_command::ec_command_bytemuck, EcCmdResult}; + +#[derive(Pod, Zeroable, Clone, Copy)] +#[repr(C)] +pub struct EcResponseGetProtocolInfo { + protocol_versions: u32, + max_request_packet_size: u16, + max_response_packet_size: u16, + flags: u32, +} + +impl EcResponseGetProtocolInfo { + pub fn max_ec_input_size(&self) -> usize { + self.max_request_packet_size as usize - size_of::() + } + + pub fn max_ec_output_size(&self) -> usize { + self.max_response_packet_size as usize - size_of::() + } +} + +#[repr(C)] +struct EcHostRequest { + struct_version: u8, + checksum: u8, + command: u16, + command_version: u8, + reserved: u8, + data_len: u16, +} + +#[repr(C)] +struct EcHostResponse { + struct_version: u8, + checksum: u8, + result: u16, + data_len: u16, + reserved: u16, +} + +pub fn get_protocol_info(fd: c_int) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::GetProtocolInfo, 0, &(), fd) +} diff --git a/crosec/src/commands/hello.rs b/crosec/src/commands/hello.rs index 5a85c63..7aeb109 100644 --- a/crosec/src/commands/hello.rs +++ b/crosec/src/commands/hello.rs @@ -1,8 +1,8 @@ use bytemuck::{NoUninit, Pod, Zeroable}; use nix::libc::c_int; +use crate::ec_command::ec_command_bytemuck; use crate::{commands::CrosEcCmd, EcCmdResult}; -use crate::ec_command::ec_command; const INPUT_DATA: u32 = 0xa0b0c0d0; const EXPECTED_OUTPUT: u32 = 0xa1b2c3d4; @@ -20,14 +20,13 @@ struct EcResponseHello { } pub fn ec_cmd_hello(fd: c_int) -> EcCmdResult { - let params = EcParamsHello { - in_data: INPUT_DATA, - }; - let params_slice = bytemuck::bytes_of(¶ms); - - let result = ec_command(CrosEcCmd::Hello, 0, params_slice, fd)?; - Ok(bytemuck::try_from_bytes::(&result).map_or( - false, - |response| response.out_data == EXPECTED_OUTPUT) - ) + let response = ec_command_bytemuck::<_, EcResponseHello>( + CrosEcCmd::Hello, + 0, + &EcParamsHello { + in_data: INPUT_DATA, + }, + fd, + )?; + Ok(response.out_data == EXPECTED_OUTPUT) } diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index a33dfee..c96419a 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -10,6 +10,7 @@ pub enum CrosEcCmd { GetBoardVersion = 0x0006, ReadMemMap = 0x0007, GetCmdVersions = 0x0008, + GetProtocolInfo = 0x000B, GetFeatures = 0x000D, SetFanTargetRpm = 0x0021, ChargeControl = 0x0096, @@ -18,12 +19,13 @@ pub enum CrosEcCmd { BatteryGetStatic = 0x0600, } -pub mod get_chip_info; -pub mod hello; -pub mod version; pub mod board_version; -pub mod set_fan_target_rpm; +pub mod charge_control; +pub mod get_chip_info; pub mod get_cmd_versions; pub mod get_features; +pub mod get_protocol_info; +pub mod hello; pub mod read_mem; -pub mod charge_control; +pub mod set_fan_target_rpm; +pub mod version; diff --git a/crosec/src/commands/read_mem.rs b/crosec/src/commands/read_mem.rs index 49a3c7e..2af25b8 100644 --- a/crosec/src/commands/read_mem.rs +++ b/crosec/src/commands/read_mem.rs @@ -1,7 +1,7 @@ -use std::ffi::c_int; -use bytemuck::{Pod, Zeroable}; -use nix::{ioctl_readwrite}; use crate::CROS_EC_IOC_MAGIC; +use bytemuck::{Pod, Zeroable}; +use nix::ioctl_readwrite; +use std::ffi::c_int; const EC_MEM_MAP_SIZE: usize = 255; diff --git a/crosec/src/commands/set_fan_target_rpm.rs b/crosec/src/commands/set_fan_target_rpm.rs index 2b74a80..3385b5e 100644 --- a/crosec/src/commands/set_fan_target_rpm.rs +++ b/crosec/src/commands/set_fan_target_rpm.rs @@ -4,7 +4,7 @@ use std::mem::size_of; use bytemuck::{Pod, Zeroable}; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; #[repr(C)] @@ -20,7 +20,13 @@ struct EcParamsSetFanTargetRpmV1 { impl EcParamsSetFanTargetRpmV1 { pub fn to_le_bytes(self) -> [u8; size_of::() + size_of::()] { - [self.rpm.to_le_bytes().to_vec(), self.fan_index.to_le_bytes().to_vec()].concat().try_into().unwrap() + [ + self.rpm.to_le_bytes().to_vec(), + self.fan_index.to_le_bytes().to_vec(), + ] + .concat() + .try_into() + .unwrap() } } @@ -29,15 +35,24 @@ pub fn ec_cmd_set_fan_target_rpm(fd: c_int, rpm: u32, fan_index: Option) -> // v1 can set the RPM for a specific fan match fan_index { Some(index) => { - ec_command(CrosEcCmd::SetFanTargetRpm, 1, &EcParamsSetFanTargetRpmV1 { - rpm, - fan_index: index, - }.to_le_bytes(), fd)?; + ec_command_bytemuck( + CrosEcCmd::SetFanTargetRpm, + 1, + &EcParamsSetFanTargetRpmV1 { + rpm, + fan_index: index, + } + .to_le_bytes(), + fd, + )?; } None => { - ec_command(CrosEcCmd::SetFanTargetRpm, 0, &bytemuck::bytes_of(&EcParamsSetFanTargetRpmV0 { - rpm - }), fd)?; + ec_command_bytemuck( + CrosEcCmd::SetFanTargetRpm, + 0, + &EcParamsSetFanTargetRpmV0 { rpm }, + fd, + )?; } }; Ok(()) diff --git a/crosec/src/commands/version.rs b/crosec/src/commands/version.rs index 4456944..0ab8fb2 100644 --- a/crosec/src/commands/version.rs +++ b/crosec/src/commands/version.rs @@ -1,12 +1,15 @@ -use std::mem::size_of; - use bytemuck::{Pod, Zeroable}; use nix::libc::c_int; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -use crate::{commands::CrosEcCmd, EcCmdResult}; -use crate::ec_command::{BUF_SIZE, ec_command}; +use crate::{ + commands::CrosEcCmd, + ec_command::{ec_command_bytemuck, ec_command_with_dynamic_output_size}, + EcCmdResult, +}; + +use super::get_protocol_info::EcResponseGetProtocolInfo; const TOOLVERSION: &str = env!("CARGO_PKG_VERSION"); @@ -29,7 +32,10 @@ enum EcImage { RwB = 4, } -pub fn ec_cmd_version(fd: c_int) -> EcCmdResult<(String, String, String, String, String)> { +pub fn ec_cmd_version( + fd: c_int, + protocol_info: &EcResponseGetProtocolInfo, +) -> EcCmdResult<(String, String, String, String, String)> { let params = EcResponseVersionV1 { version_string_ro: [0; 32], version_string_rw: [0; 32], @@ -38,12 +44,7 @@ pub fn ec_cmd_version(fd: c_int) -> EcCmdResult<(String, String, String, String, cros_fwid_rw: [0; 32], }; - let build_string: [u8; BUF_SIZE] = [0; BUF_SIZE]; - let params_slice = bytemuck::bytes_of(¶ms); - - let mut result = ec_command(CrosEcCmd::Version, 0, params_slice, fd)?; - result.resize(size_of::(), Default::default()); - let response = bytemuck::from_bytes::(&result); + let response: EcResponseVersionV1 = ec_command_bytemuck(CrosEcCmd::Version, 0, ¶ms, fd)?; let ro_ver = String::from_utf8(response.version_string_ro.to_vec()).unwrap_or_default(); let rw_ver = String::from_utf8(response.version_string_rw.to_vec()).unwrap_or_default(); @@ -57,9 +58,13 @@ pub fn ec_cmd_version(fd: c_int) -> EcCmdResult<(String, String, String, String, None => String::from("Unknown"), }; - let build_string_slice = &build_string; - - let result = ec_command(CrosEcCmd::GetBuildInfo, 0, build_string_slice, fd)?; + let result = ec_command_with_dynamic_output_size( + CrosEcCmd::GetBuildInfo, + 0, + &[0; 248], + protocol_info.max_ec_output_size(), + fd, + )?; let build_info = String::from_utf8(result).unwrap_or(String::from("")); Ok((ro_ver, rw_ver, image, build_info, String::from(TOOLVERSION))) diff --git a/crosec/src/console.rs b/crosec/src/console.rs index eb63262..b60623b 100644 --- a/crosec/src/console.rs +++ b/crosec/src/console.rs @@ -1,15 +1,24 @@ use std::ffi::c_int; +use crate::commands::get_protocol_info::EcResponseGetProtocolInfo; use crate::commands::CrosEcCmd; -use crate::ec_command::ec_command; +use crate::ec_command::{ec_command_bytemuck, ec_command_with_dynamic_output_size}; use crate::EcCmdResult; -pub fn console(fd: c_int) -> EcCmdResult { - ec_command(CrosEcCmd::ConsoleSnapshot, 0, Default::default(), fd)?; +pub fn console(fd: c_int, protocol_info: &EcResponseGetProtocolInfo) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::ConsoleSnapshot, 0, &(), fd)?; let mut console = String::default(); loop { - let output = ec_command(CrosEcCmd::ConsoleRead, 0, Default::default(), fd)?; + let output = ec_command_with_dynamic_output_size( + CrosEcCmd::ConsoleRead, + 0, + Default::default(), + protocol_info.max_ec_output_size(), + fd, + )?; let chunk = String::from_utf8(output).unwrap(); + // Get rid of trailing null characters + let chunk = chunk.trim_end_matches('\0'); if !chunk.is_empty() { console += &chunk; } else { diff --git a/crosec/src/ec_command.rs b/crosec/src/ec_command.rs index 134e471..bcfdf7d 100644 --- a/crosec/src/ec_command.rs +++ b/crosec/src/ec_command.rs @@ -1,60 +1,76 @@ -use std::os::raw::c_int; use crate::commands::CrosEcCmd; -use crate::{CROS_EC_IOC_MAGIC, EcCmdResult}; use crate::EcError; +use crate::{EcCmdResult, CROS_EC_IOC_MAGIC}; +use bytemuck::{bytes_of, from_bytes, AnyBitPattern, NoUninit, Pod, Zeroable}; use nix::ioctl_readwrite; use num_traits::FromPrimitive; +use std::cmp::max; +use std::mem::size_of; +use std::os::raw::c_int; use super::EcResponseStatus; -pub const IN_SIZE: usize = 256; -pub const BUF_SIZE: usize = IN_SIZE - 8; - +#[derive(Debug, Pod, Zeroable, Clone, Copy)] #[repr(C)] -struct _CrosEcCommandV2 { +struct CrosEcCommandV2 { version: u32, command: u32, - outsize: u32, - insize: u32, + ec_input_size: u32, + ec_output_size: u32, result: u32, data: [u8; 0], } -#[repr(C)] -struct CrosEcCommandV2 { - version: u32, - command: CrosEcCmd, - outsize: u32, - insize: u32, - result: u32, - data: [u8; IN_SIZE], -} - -ioctl_readwrite!(cros_ec_cmd, CROS_EC_IOC_MAGIC, 0, _CrosEcCommandV2); - -pub fn ec_command(command: CrosEcCmd, command_version: u8, data: &[u8], fd: c_int) -> EcCmdResult> { - - let size = std::cmp::min(IN_SIZE, data.len()); +ioctl_readwrite!(cros_ec_cmd, CROS_EC_IOC_MAGIC, 0, CrosEcCommandV2); - let mut cmd = CrosEcCommandV2 { +pub fn ec_command_with_dynamic_output_size( + command: CrosEcCmd, + command_version: u8, + input_buffer: &[u8], + output_size: usize, + fd: c_int, +) -> EcCmdResult> { + let buffer_size = max(input_buffer.len(), output_size); + let cmd_without_data = CrosEcCommandV2 { version: command_version as u32, - command, - outsize: size as u32, - insize: IN_SIZE as u32, + command: command as u32, + ec_input_size: input_buffer.len() as u32, + ec_output_size: output_size as u32, result: 0xFF, - data: [0; IN_SIZE], + data: [], }; + let mut cmd_vec = bytemuck::bytes_of(&cmd_without_data).to_vec(); + cmd_vec.extend({ + let mut buffer = input_buffer.to_vec(); + buffer.resize(buffer_size, Default::default()); + buffer + }); + let result = unsafe { cros_ec_cmd(fd, cmd_vec.as_mut_ptr() as *mut _ as *mut CrosEcCommandV2) }; + let _output_size = result.map_err(|err| EcError::DeviceError(err))?; + let cmd_without_data = + bytemuck::from_bytes::(&cmd_vec[..size_of::()]); + let status = FromPrimitive::from_u32(cmd_without_data.result) + .ok_or(EcError::UnknownResponseCode(cmd_without_data.result))?; + match status { + EcResponseStatus::Success => Ok(cmd_vec + [size_of::()..size_of::() + output_size] + .to_vec()), + status => Err(EcError::Response(status)), + } +} - cmd.data[0..size].copy_from_slice(data); - let cmd_ptr = &mut cmd as *mut _ as *mut _CrosEcCommandV2; - - let result = unsafe { cros_ec_cmd(fd, cmd_ptr) }; - let status = - FromPrimitive::from_u32(cmd.result).ok_or(EcError::UnknownResponseCode(cmd.result))?; - let EcResponseStatus::Success = status else { - return Err(EcError::Response(status)); - }; - result - .map(|result| cmd.data[0..result as usize].to_vec()) - .map_err(|err| EcError::DeviceError(err)) +pub fn ec_command_bytemuck( + command: CrosEcCmd, + command_version: u8, + input: &Request, + fd: c_int, +) -> EcCmdResult { + let response = ec_command_with_dynamic_output_size( + command, + command_version, + bytes_of(input), + size_of::(), + fd, + )?; + Ok(from_bytes::(&response).to_owned()) } diff --git a/crosec/src/get_number_of_fans.rs b/crosec/src/get_number_of_fans.rs index e3779de..3283cd4 100644 --- a/crosec/src/get_number_of_fans.rs +++ b/crosec/src/get_number_of_fans.rs @@ -1,8 +1,8 @@ -use std::ffi::c_int; -use std::fmt::{Debug, Display, Formatter}; use crate::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; -use crate::{EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_MEM_MAP_FAN, EcError}; use crate::read_mem_any::read_mem_any; +use crate::{EcError, EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_MEM_MAP_FAN}; +use std::ffi::c_int; +use std::fmt::{Debug, Display, Formatter}; #[derive(Debug)] pub enum Error { @@ -17,7 +17,7 @@ impl Display for Error { match self { Self::GetFeatures(e) => { write!(f, "Error getting features: {:#?}", e) - }, + } Self::ReadMem(e) => { write!(f, "Error reading memory: {:#?}", e) } @@ -28,7 +28,8 @@ impl Display for Error { pub fn get_number_of_fans(fd: c_int) -> Result { let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; let number_of_fans = if features & EC_FEATURE_PWM_FAN != 0 { - read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN).map_err(|e| Error::ReadMem(e))? + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN) + .map_err(|e| Error::ReadMem(e))? .into_iter() .filter(|data| *data != EC_FAN_SPEED_NOT_PRESENT) .count() @@ -36,4 +37,4 @@ pub fn get_number_of_fans(fd: c_int) -> Result { 0 }; Ok(number_of_fans) -} \ No newline at end of file +} diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index 91ac1a9..2d8dd73 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -2,12 +2,12 @@ use nix::errno::Errno; use num_derive::FromPrimitive; use thiserror::Error; +pub mod battery; pub mod commands; +pub mod console; pub mod ec_command; -pub mod read_mem_any; pub mod get_number_of_fans; -pub mod console; -pub mod battery; +pub mod read_mem_any; pub mod read_mem_string; // In the future, portio should be supported as well @@ -53,6 +53,8 @@ pub enum EcError { pub type EcCmdResult = Result; +pub const CROS_EC_PATH: &str = "/dev/cros_ec"; +pub const CROS_FP_PATH: &str = "/dev/cros_fp"; pub const EC_FAN_SPEED_ENTRIES: usize = 4; pub const EC_FAN_SPEED_NOT_PRESENT: u16 = 0xffff; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 2939e8a..234520a 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,8 +1,9 @@ use std::fs::File; use std::os::fd::AsRawFd; -use clap::{Parser, Subcommand}; +use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; +use crosec::commands::get_protocol_info::get_protocol_info; use num_traits::cast::FromPrimitive; use crosec::battery::battery; @@ -21,7 +22,8 @@ use crosec::console::console; use crosec::get_number_of_fans::{get_number_of_fans, Error}; use crosec::read_mem_any::read_mem_any; use crosec::{ - EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, + CROS_EC_PATH, CROS_FP_PATH, EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, + EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, }; #[derive(Parser)] @@ -30,10 +32,29 @@ struct Cli { command: Commands, } +#[derive(Clone, Copy, ValueEnum, Default)] +enum Device { + #[default] + Ec, + Fp, +} + +impl Device { + pub fn get_path(&self) -> &'static str { + match self { + Self::Ec => CROS_EC_PATH, + Self::Fp => CROS_FP_PATH, + } + } +} + #[derive(Subcommand)] enum Commands { /// Checks for basic communication with EC - Hello, + Hello { + #[arg()] + device: Option, + }, /// Prints EC version Version, /// Prints chip info @@ -55,7 +76,10 @@ enum Commands { /// Get the speed of fans, in RPM GetFanRpm, /// Prints the last output to the EC debug console - Console, + Console { + #[arg()] + device: Option, + }, /// Prints battery info Battery, ChargeControl { @@ -83,11 +107,11 @@ fn main() -> Result<()> { color_eyre::install()?; let cli = Cli::parse(); - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); match cli.command { - Commands::Hello => { + Commands::Hello { device } => { + let file = File::open(device.unwrap_or_default().get_path()).unwrap(); + let fd = file.as_raw_fd(); let status = ec_cmd_hello(fd)?; if status { println!("EC says hello!"); @@ -96,7 +120,11 @@ fn main() -> Result<()> { } } Commands::Version => { - let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = ec_cmd_version(fd)?; + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); + let max_sizes = get_protocol_info(fd)?; + let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = + ec_cmd_version(fd, &max_sizes)?; println!("RO version: {ro_ver}"); println!("RW version: {rw_ver}"); println!("Firmware copy: {firmware_copy}"); @@ -104,6 +132,8 @@ fn main() -> Result<()> { println!("Tool version: {tool_version}"); } Commands::ChipInfo => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let (vendor, name, revision) = ec_cmd_get_chip_info(fd)?; println!("Chip info:"); println!(" vendor: {vendor}"); @@ -111,11 +141,15 @@ fn main() -> Result<()> { println!(" revision: {revision}"); } Commands::BoardVersion => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let board_version = ec_cmd_board_version(fd)?; println!("Board version: {board_version}"); } Commands::CmdVersions { command } => match CrosEcCmd::from_u32(command) { Some(cmd) => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let versions = ec_cmd_get_cmd_versions(fd, cmd)?; println!("Versions: {versions:#b}"); } @@ -124,6 +158,8 @@ fn main() -> Result<()> { } }, Commands::SetFanTargetRpm { rpm, index } => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); ec_cmd_set_fan_target_rpm(fd, rpm, index)?; match index { Some(index) => { @@ -135,14 +171,20 @@ fn main() -> Result<()> { } } Commands::GetFeatures => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let features = ec_cmd_get_features(fd)?; println!("EC supported features: {features:#b}"); } Commands::GetNumberOfFans => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let number_of_fans = get_number_of_fans(fd).unwrap(); println!("Number of fans: {number_of_fans}"); } Commands::GetFanRpm => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; if features & EC_FEATURE_PWM_FAN != 0 { read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN) @@ -162,55 +204,64 @@ fn main() -> Result<()> { println!("No fans"); }; } - Commands::Console => { - let console = console(fd)?; + Commands::Console { device } => { + let file = File::open(device.unwrap_or_default().get_path()).unwrap(); + let fd = file.as_raw_fd(); + let max_sizes = get_protocol_info(fd)?; + let console = console(fd, &max_sizes)?; let console = console.trim(); println!("{console}"); } Commands::Battery => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); let battery_info = battery(fd)?; println!("{battery_info:#?}"); } - Commands::ChargeControl { command } => match command { - None => { - if supports_get_and_sustainer(fd)? { - let charge_control = get_charge_control(fd)?; - println!("{charge_control:#?}"); - } else { - println!("This EC doesn't support getting charge control"); + Commands::ChargeControl { command } => { + let file = File::open("/dev/cros_ec").unwrap(); + let fd = file.as_raw_fd(); + match command { + None => { + if supports_get_and_sustainer(fd)? { + let charge_control = get_charge_control(fd)?; + println!("{charge_control:#?}"); + } else { + println!("This EC doesn't support getting charge control"); + } } - } - Some(command) => match command { - ChargeControlSubcommands::Normal { - min_percent, - max_percent, - } => match min_percent { - Some(min_percent) => { - let max_percent = max_percent.unwrap_or(min_percent); - set_charge_control( - fd, - charge_control::ChargeControl::Normal(Some(Sustainer { - min_percent: min_percent as i8, - max_percent: max_percent as i8, - })), - )?; - println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); + Some(command) => match command { + ChargeControlSubcommands::Normal { + min_percent, + max_percent, + } => match min_percent { + Some(min_percent) => { + let max_percent = max_percent.unwrap_or(min_percent); + set_charge_control( + fd, + charge_control::ChargeControl::Normal(Some(Sustainer { + min_percent: min_percent as i8, + max_percent: max_percent as i8, + })), + )?; + println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); + } + None => { + set_charge_control(fd, charge_control::ChargeControl::Normal(None))?; + println!("Set charge control to normal"); + } + }, + ChargeControlSubcommands::Idle => { + println!("Set charge control to idle"); + set_charge_control(fd, charge_control::ChargeControl::Idle)?; } - None => { - set_charge_control(fd, charge_control::ChargeControl::Normal(None))?; - println!("Set charge control to normal"); + ChargeControlSubcommands::Discharge => { + println!("Set charge control to discharge"); + set_charge_control(fd, charge_control::ChargeControl::Discharge)?; } }, - ChargeControlSubcommands::Idle => { - println!("Set charge control to idle"); - set_charge_control(fd, charge_control::ChargeControl::Idle)?; - } - ChargeControlSubcommands::Discharge => { - println!("Set charge control to discharge"); - set_charge_control(fd, charge_control::ChargeControl::Discharge)?; - } - }, - }, + } + } } Ok(()) From 614d48da0ba7dcfac1d6e8e9d9bfcbdb30f3d2f1 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:18:09 -0700 Subject: [PATCH 13/39] remove unused EcInterface enum --- crosec/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index 2d8dd73..3c292cd 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -10,12 +10,6 @@ pub mod get_number_of_fans; pub mod read_mem_any; pub mod read_mem_string; -// In the future, portio should be supported as well -pub enum EcInterface { - Dev(String), - Default, -} - #[derive(FromPrimitive, Debug, Copy, Clone)] pub enum EcResponseStatus { Success = 0, From 4bfb52f9d8a2295c9e8c0a35b72117312a60d2b5 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:31:48 -0700 Subject: [PATCH 14/39] fp-info command --- crosec/src/commands/fp_info.rs | 39 ++++++++++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 12 ++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 crosec/src/commands/fp_info.rs diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs new file mode 100644 index 0000000..52a2963 --- /dev/null +++ b/crosec/src/commands/fp_info.rs @@ -0,0 +1,39 @@ +use std::ffi::c_int; + +use bytemuck::{Pod, Zeroable}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::{ + get_cmd_versions::{ec_cmd_get_cmd_versions, V1}, + CrosEcCmd, +}; + +#[repr(C, align(4))] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] +pub struct EcResponseFpInfo { + pub vendor_id: u32, + pub product_id: u32, + pub model_id: u32, + pub version: u32, + pub frame_size: u32, + pub pixel_format: u32, + pub width: u16, + pub height: u16, + pub bpp: u16, + pub errors: u16, + pub template_size: u32, + pub template_max: u16, + pub template_valid: u16, + pub template_dirty: u32, + pub template_version: u32, +} + +pub fn fp_info(fd: c_int) -> EcCmdResult { + let versions = ec_cmd_get_cmd_versions(fd, CrosEcCmd::FpInfo)?; + if versions & V1 == 0 { + panic!("fp doesn't support V1. Other versions are currently not implemented"); + } + let info: EcResponseFpInfo = ec_command_bytemuck(CrosEcCmd::FpInfo, 1, &(), fd)?; + Ok(info) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index c96419a..8c4c8c0 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -16,11 +16,13 @@ pub enum CrosEcCmd { ChargeControl = 0x0096, ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, + FpInfo = 0x0403, BatteryGetStatic = 0x0600, } pub mod board_version; pub mod charge_control; +pub mod fp_info; pub mod get_chip_info; pub mod get_cmd_versions; pub mod get_features; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 234520a..5a1de98 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -3,6 +3,7 @@ use std::os::fd::AsRawFd; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; +use crosec::commands::fp_info::fp_info; use crosec::commands::get_protocol_info::get_protocol_info; use num_traits::cast::FromPrimitive; @@ -62,7 +63,9 @@ enum Commands { /// Prints the board version BoardVersion, /// Prints supported version mask for a command number - CmdVersions { command: u32 }, + CmdVersions { + command: u32, + }, /// Set target fan RPM SetFanTargetRpm { rpm: u32, @@ -86,6 +89,7 @@ enum Commands { #[command(subcommand)] command: Option, }, + FpInfo, } #[derive(Subcommand)] @@ -262,6 +266,12 @@ fn main() -> Result<()> { }, } } + Commands::FpInfo => { + let file = File::open(CROS_FP_PATH).unwrap(); + let fd = file.as_raw_fd(); + let info = fp_info(fd)?; + println!("{info:#?}"); + } } Ok(()) From 2808fdba95de26b9da8a3029cf39753622fbac8f Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:39:48 -0700 Subject: [PATCH 15/39] fp-stats command --- crosec/src/commands/fp_stats.rs | 29 +++++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 8 ++++++++ 3 files changed, 39 insertions(+) create mode 100644 crosec/src/commands/fp_stats.rs diff --git a/crosec/src/commands/fp_stats.rs b/crosec/src/commands/fp_stats.rs new file mode 100644 index 0000000..f9b7700 --- /dev/null +++ b/crosec/src/commands/fp_stats.rs @@ -0,0 +1,29 @@ +use std::ffi::c_int; + +use bytemuck::{Pod, Zeroable}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::CrosEcCmd; + +#[repr(C, packed)] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] +pub struct EcResponseFpStats { + pub capture_time_us: u32, + pub matching_time_us: u32, + pub overall_time_us: u32, + pub overall_t0: OverallT0, + pub timestamps_invalid: u8, + pub template_matched: i8, +} + +#[repr(C, packed)] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] +pub struct OverallT0 { + pub lo: u32, + pub hi: u32, +} + +pub fn fp_stats(fd: c_int) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::FpStats, 0, &(), fd) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 8c4c8c0..bf588ae 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -17,12 +17,14 @@ pub enum CrosEcCmd { ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, FpInfo = 0x0403, + FpStats = 0x0407, BatteryGetStatic = 0x0600, } pub mod board_version; pub mod charge_control; pub mod fp_info; +pub mod fp_stats; pub mod get_chip_info; pub mod get_cmd_versions; pub mod get_features; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 5a1de98..f059d21 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -4,6 +4,7 @@ use std::os::fd::AsRawFd; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; use crosec::commands::fp_info::fp_info; +use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; use num_traits::cast::FromPrimitive; @@ -90,6 +91,7 @@ enum Commands { command: Option, }, FpInfo, + FpStats, } #[derive(Subcommand)] @@ -272,6 +274,12 @@ fn main() -> Result<()> { let info = fp_info(fd)?; println!("{info:#?}"); } + Commands::FpStats => { + let file = File::open(CROS_FP_PATH).unwrap(); + let fd = file.as_raw_fd(); + let stats = fp_stats(fd)?; + println!("{stats:#?}"); + } } Ok(()) From 1d1d30a506d2227a91e2988cb98de7df7ea7edca Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:00:11 -0700 Subject: [PATCH 16/39] set fp seed command This command can only be run once per reboot (I'm pretty sure) so it can be hard to debug. Luckily it worked 1st try for me. --- crosec/src/commands/fp_set_seed.rs | 31 ++++++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 20 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 crosec/src/commands/fp_set_seed.rs diff --git a/crosec/src/commands/fp_set_seed.rs b/crosec/src/commands/fp_set_seed.rs new file mode 100644 index 0000000..884e374 --- /dev/null +++ b/crosec/src/commands/fp_set_seed.rs @@ -0,0 +1,31 @@ +use std::ffi::c_int; + +use bytemuck::{Pod, Zeroable}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::CrosEcCmd; + +pub const FP_CONTEXT_TPM_BYTES: usize = 32; +const FP_TEMPLATE_FORMAT_VERSION: u16 = 4; + +#[repr(C, align(4))] +#[derive(Pod, Zeroable, Clone, Copy)] +struct EcParamsFpSeed { + pub struct_version: u16, + pub reserved: u16, + pub seed: [u8; FP_CONTEXT_TPM_BYTES], +} + +pub fn fp_set_seed(fd: c_int, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { + ec_command_bytemuck( + CrosEcCmd::FpSetSeed, + 0, + &EcParamsFpSeed { + struct_version: FP_TEMPLATE_FORMAT_VERSION, + reserved: Default::default(), + seed, + }, + fd, + ) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index bf588ae..c77c42a 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -18,12 +18,14 @@ pub enum CrosEcCmd { ConsoleRead = 0x0098, FpInfo = 0x0403, FpStats = 0x0407, + FpSetSeed = 0x0408, BatteryGetStatic = 0x0600, } pub mod board_version; pub mod charge_control; pub mod fp_info; +pub mod fp_set_seed; pub mod fp_stats; pub mod get_chip_info; pub mod get_cmd_versions; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index f059d21..a5c0b90 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -4,6 +4,7 @@ use std::os::fd::AsRawFd; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; use crosec::commands::fp_info::fp_info; +use crosec::commands::fp_set_seed::{fp_set_seed, FP_CONTEXT_TPM_BYTES}; use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; use num_traits::cast::FromPrimitive; @@ -92,6 +93,9 @@ enum Commands { }, FpInfo, FpStats, + FpSetSeed { + seed: String, + }, } #[derive(Subcommand)] @@ -280,6 +284,22 @@ fn main() -> Result<()> { let stats = fp_stats(fd)?; println!("{stats:#?}"); } + Commands::FpSetSeed { seed } => { + match as TryInto<[u8; FP_CONTEXT_TPM_BYTES]>>::try_into( + seed.as_bytes().to_owned(), + ) { + Ok(seed) => { + let file = File::open(CROS_FP_PATH).unwrap(); + let fd = file.as_raw_fd(); + fp_set_seed(fd, seed)?; + println!("Set fp seed"); + } + Err(seed) => { + let seed_len = seed.len(); + println!("The seed must be {FP_CONTEXT_TPM_BYTES} bytes long. The seed you inputted is {seed_len} bytes long."); + } + } + } } Ok(()) From 06efbf5d5950f1e337b330ee8a0eb442036bb49b Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:32:28 -0700 Subject: [PATCH 17/39] fp mode command The same EC command is used for changing the fp mode and also just getting the fp mode. --- Cargo.lock | 27 ++++++++++++++++ crosec/Cargo.toml | 2 ++ crosec/src/commands/fp_mode.rs | 57 ++++++++++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/src/main.rs | 21 +++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 crosec/src/commands/fp_mode.rs diff --git a/Cargo.lock b/Cargo.lock index 5d9c314..b13d9da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,6 +206,8 @@ dependencies = [ "nix", "num-derive", "num-traits", + "strum", + "strum_macros", "thiserror", ] @@ -363,6 +365,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "sharded-slab" version = "0.1.7" @@ -378,6 +386,25 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.60" diff --git a/crosec/Cargo.toml b/crosec/Cargo.toml index ae9169e..bd21405 100644 --- a/crosec/Cargo.toml +++ b/crosec/Cargo.toml @@ -10,4 +10,6 @@ bytemuck = { version = "1.16.0", features = ["derive"] } nix = { version = "0.27.1", features = ["ioctl"] } num-derive = "0.4.2" num-traits = "0.2.18" +strum = "0.26.2" +strum_macros = "0.26.4" thiserror = "1.0.57" diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs new file mode 100644 index 0000000..4dec604 --- /dev/null +++ b/crosec/src/commands/fp_mode.rs @@ -0,0 +1,57 @@ +use bytemuck::{Pod, Zeroable}; +use std::ffi::c_int; +use strum::IntoEnumIterator; +use strum_macros::{EnumIter, EnumString, IntoStaticStr}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::CrosEcCmd; + +/// Note that with the ChromiumOS ectool, to start enrolling, as well as continue the next step in enrolling, you do `ectool --name=cros_fp fpmode enroll`. The equivalent of this is to do `ectool fp-mode EnrollImage EnrollSession`. +#[derive(EnumString, EnumIter, IntoStaticStr, Clone, Copy)] +#[repr(u32)] +pub enum FpMode { + Reset = 0b00000000000000000000000000000000, + DeepSleep = 0b00000000000000000000000000000001, + FingerDown = 0b00000000000000000000000000000010, + FingerUp = 0b00000000000000000000000000000100, + Capture = 0b00000000000000000000000000001000, + EnrollSession = 0b00000000000000000000000000010000, + EnrollImage = 0b00000000000000000000000000100000, + Match = 0b00000000000000000000000001000000, + ResetSensor = 0b00000000000000000000000010000000, + Maintanence = 0b00000000000000000000000100000000, + DontChange = 0b10000000000000000000000000000000, +} + +impl FpMode { + pub fn display(fp_mode: u32) -> String { + let flags = match fp_mode { + 0 => >::into(Self::Reset).to_owned(), + fp_mode => Self::iter() + .filter(|flag| fp_mode as u32 & *flag as u32 != 0) + .map(|flag| >::into(flag)) + .collect::>() + .join(", "), + }; + format!("{fp_mode:#b} ({flags})") + } +} + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy)] +struct EcParamsFpMode { + mode: u32, +} + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy)] +struct EcResponseFpMode { + mode: u32, +} + +pub fn fp_mode(fd: c_int, mode: u32) -> EcCmdResult { + let response: EcResponseFpMode = + ec_command_bytemuck(CrosEcCmd::FpMode, 0, &EcParamsFpMode { mode }, fd)?; + Ok(response.mode) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index c77c42a..c53e0d6 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -16,6 +16,7 @@ pub enum CrosEcCmd { ChargeControl = 0x0096, ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, + FpMode = 0x0402, FpInfo = 0x0403, FpStats = 0x0407, FpSetSeed = 0x0408, @@ -25,6 +26,7 @@ pub enum CrosEcCmd { pub mod board_version; pub mod charge_control; pub mod fp_info; +pub mod fp_mode; pub mod fp_set_seed; pub mod fp_stats; pub mod get_chip_info; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index a5c0b90..d364940 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,9 +1,11 @@ use std::fs::File; use std::os::fd::AsRawFd; +use std::str::FromStr; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; use crosec::commands::fp_info::fp_info; +use crosec::commands::fp_mode::{fp_mode, FpMode}; use crosec::commands::fp_set_seed::{fp_set_seed, FP_CONTEXT_TPM_BYTES}; use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; @@ -96,6 +98,9 @@ enum Commands { FpSetSeed { seed: String, }, + FpMode { + mode: Vec, + }, } #[derive(Subcommand)] @@ -300,6 +305,22 @@ fn main() -> Result<()> { } } } + Commands::FpMode { mode } => { + let mode = if mode.len() > 0 { + let mut mode_number: u32 = 0; + for mode in mode { + mode_number |= FpMode::from_str(&mode)? as u32; + } + mode_number + } else { + FpMode::DontChange as u32 + }; + let file = File::open(CROS_FP_PATH).unwrap(); + let fd = file.as_raw_fd(); + let mode = fp_mode(fd, mode)?; + let display = FpMode::display(mode); + println!("FP mode: {display}"); + } } Ok(()) From cb213aaedb1f405a0a319006d3459896b9d88e9d Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:12:19 -0700 Subject: [PATCH 18/39] wait_event function The function can wait for any event and detect the type of the event. It has in depth Rust-safe types for the fingerprint events. --- crosec/src/lib.rs | 1 + crosec/src/wait_event/event.rs | 82 ++++++++++++++++++ crosec/src/wait_event/fingerprint.rs | 125 +++++++++++++++++++++++++++ crosec/src/wait_event/mod.rs | 50 +++++++++++ ectool/src/main.rs | 17 ++++ 5 files changed, 275 insertions(+) create mode 100644 crosec/src/wait_event/event.rs create mode 100644 crosec/src/wait_event/fingerprint.rs create mode 100644 crosec/src/wait_event/mod.rs diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index 3c292cd..4cf0ea6 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -9,6 +9,7 @@ pub mod ec_command; pub mod get_number_of_fans; pub mod read_mem_any; pub mod read_mem_string; +pub mod wait_event; #[derive(FromPrimitive, Debug, Copy, Clone)] pub enum EcResponseStatus { diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs new file mode 100644 index 0000000..7053345 --- /dev/null +++ b/crosec/src/wait_event/event.rs @@ -0,0 +1,82 @@ +use std::{ + io::{self, Read}, + mem::size_of, +}; + +use bytemuck::{from_bytes, Pod, Zeroable}; +use num_derive::FromPrimitive; +use strum_macros::{EnumString, IntoStaticStr}; + +use crate::wait_event::fingerprint::EcMkbpEventFingerprint; + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct EcResponseMotionSenseFifoInfo { + size: u16, + count: u16, + timestamp: u32, + total_lost: u16, + lost: [u16; 0], +} + +#[derive(Debug)] +#[repr(u8)] +pub enum EcMkbpEvent { + KeyMatrix([u8; 13]), + HostEvent(u32), + HostEvent64(u64), + SensorFifo(EcResponseMotionSenseFifoInfo), + Buttons(u32), + Switches(u32), + Fingerprint(EcMkbpEventFingerprint), + Sysrq(u32), + CecEvent(u32), +} + +#[derive(Debug, IntoStaticStr, EnumString, FromPrimitive, Clone, Copy)] +#[repr(u8)] +pub enum EcMkbpEventType { + KeyMatrix, + HostEvent, + SensorFifo, + Buttons, + Switches, + Fingerprint, + Sysrq, + HostEvent64, + CecEvent, + CecMessage, + DpAltModeEntered, + OnlineCalibration, + Pchg, +} +impl EcMkbpEventType { + fn data_size(&self) -> usize { + match self { + Self::KeyMatrix => size_of::<[u8; 13]>(), + Self::HostEvent => size_of::(), + Self::SensorFifo => size_of::(), + Self::Buttons => size_of::(), + Self::Switches => size_of::(), + Self::Fingerprint => size_of::(), + Self::Sysrq => size_of::(), + Self::HostEvent64 => size_of::(), + Self::CecEvent => size_of::(), + _ => 0, + } + } + + pub(crate) fn read(&self, stream: &mut T) -> io::Result { + let mut event = vec![Default::default(); size_of::() + self.data_size()]; + stream.read_exact(&mut event)?; + debug_assert_eq!(event[0], *self as u8); + event.remove(0); + let data = event; + Ok(match self { + EcMkbpEventType::Fingerprint => { + EcMkbpEvent::Fingerprint(from_bytes::(&data).to_owned()) + } + event_type => panic!("{event_type:#?} from_bytes not implemented yet"), + }) + } +} diff --git a/crosec/src/wait_event/fingerprint.rs b/crosec/src/wait_event/fingerprint.rs new file mode 100644 index 0000000..0a46b61 --- /dev/null +++ b/crosec/src/wait_event/fingerprint.rs @@ -0,0 +1,125 @@ +use std::fmt::Debug; + +use bytemuck::{Pod, Zeroable}; + +#[derive(Debug)] +pub enum EcMkbpEventFingerprintEnrollError { + LowQuality, + Immobile, + LowCoverage, + Internal, +} + +#[derive(Debug)] +pub struct EcMkbpEventFingerprintEnroll { + pub percentage: u8, + pub error: Option, +} + +#[derive(Debug)] +pub struct EcMkbpEventFingerprintMatch { + pub index: usize, + /// If `Some`, his means that the fingerprint matched an existing template and the existing template was updated to more accurately match future fingerprints. + /// `None` if `EC_MKBP_FP_ERR_MATCH_YES`. + /// `Some(Ok)` if `EC_MKBP_FP_ERR_MATCH_YES_UPDATED`. + /// `Some(Err)` if `EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED`. + // TODO: Find the CrOS EC documentation for this and add the link here + pub update: Option>, +} + +#[derive(Debug)] +pub enum EcMkbpEventFingerprintNoMatchError { + /// `EC_MKBP_FP_ERR_MATCH_NO_INTERNAL` - Probably means there was an internal error. + Internal, + /// `EC_MKBP_FP_ERR_MATCH_NO_TEMPLATES` - This either means there are no templates, or something's wrong with the templates. Idk which one. + Templates, + /// `EC_MKBP_FP_ERR_MATCH_NO_LOW_QUALITY` - My guess is this might happen if the sensor or finger is dirty + LowQuality, + /// `EC_MKBP_FP_ERR_MATCH_NO_LOW_COVERAGE` - My guess is this might happen if only a small part of a finger is sensed + LowCoverage, +} + +#[derive(Debug)] +pub enum EcMkbpEventFingerprintMatchResult { + Match(EcMkbpEventFingerprintMatch), + NoMatch(Result<(), EcMkbpEventFingerprintNoMatchError>), +} + +#[derive(Debug)] +pub enum EcMkbpEventFingerprintRust { + /// Contains the enroll progress, as a percentage + Enroll(EcMkbpEventFingerprintEnroll), + Match(EcMkbpEventFingerprintMatchResult), + FingerDown, + FingerUp, + ImageReady, +} + +const EC_MKBP_EVENT_FINGERPRINT_ERROR_MASK: u32 = 0x0000000F; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct EcMkbpEventFingerprint { + fp_events: u32, +} +impl EcMkbpEventFingerprint { + /// Get a Rust-friendly format. Uses CPU to call and format uses more memory. + pub fn rust(&self) -> EcMkbpEventFingerprintRust { + match self.fp_events { + fp_events if fp_events & (1 << 27) != 0 => { + EcMkbpEventFingerprintRust::Enroll(EcMkbpEventFingerprintEnroll { + percentage: ((self.fp_events & 0x00000FF0) >> 4).try_into().unwrap(), + error: match self.fp_events & EC_MKBP_EVENT_FINGERPRINT_ERROR_MASK { + 0 => None, + 1 => Some(EcMkbpEventFingerprintEnrollError::LowQuality), + 2 => Some(EcMkbpEventFingerprintEnrollError::Immobile), + 3 => Some(EcMkbpEventFingerprintEnrollError::LowCoverage), + 5 => Some(EcMkbpEventFingerprintEnrollError::Internal), + unknown_error => panic!("Unknown error: {unknown_error}"), + }, + }) + } + fp_events if fp_events & (1 << 28) != 0 => EcMkbpEventFingerprintRust::Match({ + let code = self.fp_events & EC_MKBP_EVENT_FINGERPRINT_ERROR_MASK; + let get_match_index = || ((self.fp_events & 0x0000F000) >> 12) as usize; + match code { + 0 => EcMkbpEventFingerprintMatchResult::NoMatch(Ok(())), + 6 => EcMkbpEventFingerprintMatchResult::NoMatch(Err( + EcMkbpEventFingerprintNoMatchError::Internal, + )), + 7 => EcMkbpEventFingerprintMatchResult::NoMatch(Err( + EcMkbpEventFingerprintNoMatchError::Templates, + )), + 2 => EcMkbpEventFingerprintMatchResult::NoMatch(Err( + EcMkbpEventFingerprintNoMatchError::LowQuality, + )), + 4 => EcMkbpEventFingerprintMatchResult::NoMatch(Err( + EcMkbpEventFingerprintNoMatchError::LowCoverage, + )), + 1 => EcMkbpEventFingerprintMatchResult::Match(EcMkbpEventFingerprintMatch { + index: get_match_index(), + update: None, + }), + 3 => EcMkbpEventFingerprintMatchResult::Match(EcMkbpEventFingerprintMatch { + index: get_match_index(), + update: Some(Ok(())), + }), + 5 => EcMkbpEventFingerprintMatchResult::Match(EcMkbpEventFingerprintMatch { + index: get_match_index(), + update: Some(Err(())), + }), + code => panic!("Unknown error code: {code} ({code:#b})"), + } + }), + fp_events if fp_events & (1 << 29) != 0 => EcMkbpEventFingerprintRust::FingerDown, + fp_events if fp_events & (1 << 30) != 0 => EcMkbpEventFingerprintRust::FingerUp, + fp_events if fp_events & (1 << 31) != 0 => EcMkbpEventFingerprintRust::ImageReady, + fp_events => panic!("Unknown FP event: {fp_events} ({fp_events:#b})"), + } + } +} +impl Debug for EcMkbpEventFingerprint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.rust().fmt(f) + } +} diff --git a/crosec/src/wait_event/mod.rs b/crosec/src/wait_event/mod.rs new file mode 100644 index 0000000..79d345a --- /dev/null +++ b/crosec/src/wait_event/mod.rs @@ -0,0 +1,50 @@ +use std::{fs::File, os::fd::AsRawFd}; + +use event::{EcMkbpEvent, EcMkbpEventType}; +use nix::{ + libc::{ioctl, poll, pollfd}, + request_code_none, +}; + +use crate::CROS_EC_IOC_MAGIC; + +pub mod event; +pub mod fingerprint; + +const POLL_IN: i16 = 0x001; + +#[derive(Debug)] +pub enum PollData { + EventHappened(EcMkbpEvent), + Timeout, + SomethingElseHappened(i16), +} + +pub fn wait_event( + file: &mut File, + event_type: EcMkbpEventType, + timeout: i32, +) -> Result { + let mask = 1 << event_type as u8; + unsafe { + ioctl( + file.as_raw_fd(), + request_code_none!(CROS_EC_IOC_MAGIC, 2), + mask, + ) + }; + let mut fds = pollfd { + fd: file.as_raw_fd(), + events: POLL_IN, + revents: Default::default(), + }; + let result = unsafe { poll(&mut fds, 1, timeout) }; + match result { + 0 => Ok(PollData::Timeout), + 1 => match fds.revents { + POLL_IN => Ok(PollData::EventHappened(event_type.read(file).unwrap())), + events => Ok(PollData::SomethingElseHappened(events)), + }, + result => Err(result), + } +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index d364940..e45f11f 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -9,6 +9,7 @@ use crosec::commands::fp_mode::{fp_mode, FpMode}; use crosec::commands::fp_set_seed::{fp_set_seed, FP_CONTEXT_TPM_BYTES}; use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; +use crosec::wait_event::{event::EcMkbpEventType, wait_event}; use num_traits::cast::FromPrimitive; use crosec::battery::battery; @@ -101,6 +102,12 @@ enum Commands { FpMode { mode: Vec, }, + WaitEvent { + event_type: String, + /// Timeout in milliseconds + timeout: i32, + device: Option, + }, } #[derive(Subcommand)] @@ -321,6 +328,16 @@ fn main() -> Result<()> { let display = FpMode::display(mode); println!("FP mode: {display}"); } + Commands::WaitEvent { + event_type, + device, + timeout, + } => { + let mut file = File::open(device.unwrap_or_default().get_path())?; + let result = + wait_event(&mut file, EcMkbpEventType::from_str(&event_type)?, timeout).unwrap(); + println!("{result:#?}"); + } } Ok(()) From 9625eb15017ff0cd8e616bcb2e754c7a19ea88d6 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 09:06:53 -0700 Subject: [PATCH 19/39] Use &mut File instead of raw fd for safe functions --- crosec/src/battery.rs | 33 +++---- crosec/src/commands/board_version.rs | 7 +- crosec/src/commands/charge_control.rs | 15 ++-- crosec/src/commands/fp_info.rs | 7 +- crosec/src/commands/fp_mode.rs | 12 ++- crosec/src/commands/fp_set_seed.rs | 6 +- crosec/src/commands/fp_stats.rs | 6 +- crosec/src/commands/get_chip_info.rs | 8 +- crosec/src/commands/get_cmd_versions.rs | 7 +- crosec/src/commands/get_features.rs | 7 +- crosec/src/commands/get_protocol_info.rs | 6 +- crosec/src/commands/hello.rs | 8 +- crosec/src/commands/read_mem.rs | 6 +- crosec/src/commands/set_fan_target_rpm.rs | 13 ++- crosec/src/commands/version.rs | 10 ++- crosec/src/console.rs | 9 +- crosec/src/get_number_of_fans.rs | 7 +- crosec/src/read_mem_any.rs | 5 +- crosec/src/read_mem_string.rs | 7 +- ectool/src/main.rs | 100 ++++++++++------------ 20 files changed, 146 insertions(+), 133 deletions(-) diff --git a/crosec/src/battery.rs b/crosec/src/battery.rs index f991335..c8a0d5c 100644 --- a/crosec/src/battery.rs +++ b/crosec/src/battery.rs @@ -10,7 +10,7 @@ use crate::{ EC_MEM_MAP_BATTERY_SERIAL, EC_MEM_MAP_BATTERY_TYPE, EC_MEM_MAP_BATTERY_VERSION, EC_MEM_MAP_BATTERY_VOLTAGE, }; -use std::ffi::c_int; +use std::fs::File; #[derive(Debug, Clone)] pub struct BatteryInfo { @@ -28,31 +28,32 @@ pub struct BatteryInfo { pub flags: u8, } -pub fn battery(fd: c_int) -> EcCmdResult { - if ec_cmd_get_cmd_versions(fd, CrosEcCmd::BatteryGetStatic)? & V1 != 0 { +pub fn battery(file: &mut File) -> EcCmdResult { + if ec_cmd_get_cmd_versions(file, CrosEcCmd::BatteryGetStatic)? & V1 != 0 { panic!( "Battery info needs to be gotten with the {:?} command", CrosEcCmd::BatteryGetStatic ); } else { - let battery_version = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VERSION).unwrap(); + let battery_version = read_mem_any::(file, EC_MEM_MAP_BATTERY_VERSION).unwrap(); if battery_version < 1 { panic!("Battery version {battery_version} is not supported"); } - let flags = read_mem_any::(fd, EC_MEM_MAP_BATTERY_FLAGS).unwrap(); - let oem_name = read_mem_string(fd, EC_MEM_MAP_BATTERY_MANUFACTURER).unwrap(); - let model_number = read_mem_string(fd, EC_MEM_MAP_BATTERY_MODEL).unwrap(); - let chemistry = read_mem_string(fd, EC_MEM_MAP_BATTERY_TYPE).unwrap(); - let serial_number = read_mem_string(fd, EC_MEM_MAP_BATTERY_SERIAL).unwrap(); - let design_capacity = read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY).unwrap(); + let flags = read_mem_any::(file, EC_MEM_MAP_BATTERY_FLAGS).unwrap(); + let oem_name = read_mem_string(file, EC_MEM_MAP_BATTERY_MANUFACTURER).unwrap(); + let model_number = read_mem_string(file, EC_MEM_MAP_BATTERY_MODEL).unwrap(); + let chemistry = read_mem_string(file, EC_MEM_MAP_BATTERY_TYPE).unwrap(); + let serial_number = read_mem_string(file, EC_MEM_MAP_BATTERY_SERIAL).unwrap(); + let design_capacity = + read_mem_any::(file, EC_MEM_MAP_BATTERY_DESIGN_CAPACITY).unwrap(); let last_full_charge = - read_mem_any::(fd, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY).unwrap(); + read_mem_any::(file, EC_MEM_MAP_BATTERY_LAST_FULL_CHARGE_CAPACITY).unwrap(); let design_output_voltage = - read_mem_any::(fd, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE).unwrap(); - let cycle_count = read_mem_any::(fd, EC_MEM_MAP_BATTERY_CYCLE_COUNT).unwrap(); - let present_voltage = read_mem_any::(fd, EC_MEM_MAP_BATTERY_VOLTAGE).unwrap(); - let present_current = read_mem_any::(fd, EC_MEM_MAP_BATTERY_RATE).unwrap(); - let remaining_capacity = read_mem_any::(fd, EC_MEM_MAP_BATTERY_CAPACITY).unwrap(); + read_mem_any::(file, EC_MEM_MAP_BATTERY_DESIGN_VOLTAGE).unwrap(); + let cycle_count = read_mem_any::(file, EC_MEM_MAP_BATTERY_CYCLE_COUNT).unwrap(); + let present_voltage = read_mem_any::(file, EC_MEM_MAP_BATTERY_VOLTAGE).unwrap(); + let present_current = read_mem_any::(file, EC_MEM_MAP_BATTERY_RATE).unwrap(); + let remaining_capacity = read_mem_any::(file, EC_MEM_MAP_BATTERY_CAPACITY).unwrap(); Ok(BatteryInfo { flags, oem_name, diff --git a/crosec/src/commands/board_version.rs b/crosec/src/commands/board_version.rs index 3d18f7d..0b5b3de 100644 --- a/crosec/src/commands/board_version.rs +++ b/crosec/src/commands/board_version.rs @@ -1,9 +1,10 @@ -use std::ffi::c_int; +use std::fs::File; +use std::os::fd::AsRawFd; use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; -pub fn ec_cmd_board_version(fd: c_int) -> EcCmdResult { - ec_command_bytemuck(CrosEcCmd::GetBoardVersion, 0, &(), fd) +pub fn ec_cmd_board_version(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::GetBoardVersion, 0, &(), file.as_raw_fd()) } diff --git a/crosec/src/commands/charge_control.rs b/crosec/src/commands/charge_control.rs index 2bfdb78..050dd88 100644 --- a/crosec/src/commands/charge_control.rs +++ b/crosec/src/commands/charge_control.rs @@ -3,7 +3,8 @@ use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; use bytemuck::{Pod, Zeroable}; -use std::ffi::c_int; +use std::fs::File; +use std::os::fd::AsRawFd; #[repr(C)] #[derive(Pod, Zeroable, Copy, Clone, Default, Debug)] @@ -19,8 +20,8 @@ pub enum ChargeControl { Discharge, } -pub fn supports_get_and_sustainer(fd: c_int) -> EcCmdResult { - let versions = ec_cmd_get_cmd_versions(fd, CrosEcCmd::ChargeControl)?; +pub fn supports_get_and_sustainer(file: &mut File) -> EcCmdResult { + let versions = ec_cmd_get_cmd_versions(file, CrosEcCmd::ChargeControl)?; Ok(versions & V2 != 0) } @@ -40,15 +41,15 @@ const CHARGE_CONTROL_COMMAND_NORMAL: u32 = 0; const CHARGE_CONTROL_COMMAND_IDLE: u32 = 1; const CHARGE_CONTROL_COMMAND_DISCHARGE: u32 = 2; -pub fn get_charge_control(_fd: c_int) -> EcCmdResult { +pub fn get_charge_control(_file: &mut File) -> EcCmdResult { panic!("Not implemented yet"); } -pub fn set_charge_control(fd: c_int, charge_control: ChargeControl) -> EcCmdResult<()> { +pub fn set_charge_control(file: &mut File, charge_control: ChargeControl) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::ChargeControl, { - let version = ec_cmd_get_cmd_versions(fd, CrosEcCmd::ChargeControl)?; + let version = ec_cmd_get_cmd_versions(file, CrosEcCmd::ChargeControl)?; Ok(if version & V2 != 0 { 2 } else { 1 }) }?, &EcParamsChargeControl { @@ -67,7 +68,7 @@ pub fn set_charge_control(fd: c_int, charge_control: ChargeControl) -> EcCmdResu _ => Default::default(), }, }, - fd, + file.as_raw_fd(), )?; Ok(()) } diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs index 52a2963..b0909c2 100644 --- a/crosec/src/commands/fp_info.rs +++ b/crosec/src/commands/fp_info.rs @@ -1,4 +1,4 @@ -use std::ffi::c_int; +use std::{fs::File, os::fd::AsRawFd}; use bytemuck::{Pod, Zeroable}; @@ -29,8 +29,9 @@ pub struct EcResponseFpInfo { pub template_version: u32, } -pub fn fp_info(fd: c_int) -> EcCmdResult { - let versions = ec_cmd_get_cmd_versions(fd, CrosEcCmd::FpInfo)?; +pub fn fp_info(file: &mut File) -> EcCmdResult { + let fd = file.as_raw_fd(); + let versions = ec_cmd_get_cmd_versions(file, CrosEcCmd::FpInfo)?; if versions & V1 == 0 { panic!("fp doesn't support V1. Other versions are currently not implemented"); } diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs index 4dec604..bfe2faa 100644 --- a/crosec/src/commands/fp_mode.rs +++ b/crosec/src/commands/fp_mode.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use std::ffi::c_int; +use std::{fs::File, os::fd::AsRawFd}; use strum::IntoEnumIterator; use strum_macros::{EnumIter, EnumString, IntoStaticStr}; @@ -50,8 +50,12 @@ struct EcResponseFpMode { mode: u32, } -pub fn fp_mode(fd: c_int, mode: u32) -> EcCmdResult { - let response: EcResponseFpMode = - ec_command_bytemuck(CrosEcCmd::FpMode, 0, &EcParamsFpMode { mode }, fd)?; +pub fn fp_mode(file: &mut File, mode: u32) -> EcCmdResult { + let response: EcResponseFpMode = ec_command_bytemuck( + CrosEcCmd::FpMode, + 0, + &EcParamsFpMode { mode }, + file.as_raw_fd(), + )?; Ok(response.mode) } diff --git a/crosec/src/commands/fp_set_seed.rs b/crosec/src/commands/fp_set_seed.rs index 884e374..0bff0e2 100644 --- a/crosec/src/commands/fp_set_seed.rs +++ b/crosec/src/commands/fp_set_seed.rs @@ -1,4 +1,4 @@ -use std::ffi::c_int; +use std::{fs::File, os::fd::AsRawFd}; use bytemuck::{Pod, Zeroable}; @@ -17,7 +17,7 @@ struct EcParamsFpSeed { pub seed: [u8; FP_CONTEXT_TPM_BYTES], } -pub fn fp_set_seed(fd: c_int, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { +pub fn fp_set_seed(file: &mut File, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::FpSetSeed, 0, @@ -26,6 +26,6 @@ pub fn fp_set_seed(fd: c_int, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<( reserved: Default::default(), seed, }, - fd, + file.as_raw_fd(), ) } diff --git a/crosec/src/commands/fp_stats.rs b/crosec/src/commands/fp_stats.rs index f9b7700..4d2f8f8 100644 --- a/crosec/src/commands/fp_stats.rs +++ b/crosec/src/commands/fp_stats.rs @@ -1,4 +1,4 @@ -use std::ffi::c_int; +use std::{fs::File, os::fd::AsRawFd}; use bytemuck::{Pod, Zeroable}; @@ -24,6 +24,6 @@ pub struct OverallT0 { pub hi: u32, } -pub fn fp_stats(fd: c_int) -> EcCmdResult { - ec_command_bytemuck(CrosEcCmd::FpStats, 0, &(), fd) +pub fn fp_stats(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::FpStats, 0, &(), file.as_raw_fd()) } diff --git a/crosec/src/commands/get_chip_info.rs b/crosec/src/commands/get_chip_info.rs index af755ae..744b6d5 100644 --- a/crosec/src/commands/get_chip_info.rs +++ b/crosec/src/commands/get_chip_info.rs @@ -1,5 +1,6 @@ +use std::{fs::File, os::fd::AsRawFd}; + use bytemuck::{Pod, Zeroable}; -use nix::libc::c_int; use crate::{commands::CrosEcCmd, ec_command::ec_command_bytemuck, EcCmdResult}; @@ -11,8 +12,9 @@ struct EcResponseGetChipInfo { revision: [u8; 32], } -pub fn ec_cmd_get_chip_info(fd: c_int) -> EcCmdResult<(String, String, String)> { - let response: EcResponseGetChipInfo = ec_command_bytemuck(CrosEcCmd::GetChipInfo, 0, &(), fd)?; +pub fn ec_cmd_get_chip_info(file: &mut File) -> EcCmdResult<(String, String, String)> { + let response: EcResponseGetChipInfo = + ec_command_bytemuck(CrosEcCmd::GetChipInfo, 0, &(), file.as_raw_fd())?; let vendor = String::from_utf8(response.vendor.to_vec()).unwrap_or_default(); let name = String::from_utf8(response.name.to_vec()).unwrap_or_default(); diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index 84e3bd3..ab0d84d 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -1,5 +1,7 @@ +use std::fs::File; +use std::os::fd::AsRawFd; + use bytemuck::{Pod, Zeroable}; -use nix::libc::c_int; use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; @@ -27,7 +29,8 @@ pub const V0: u32 = 0b001; pub const V1: u32 = 0b010; pub const V2: u32 = 0b100; -pub fn ec_cmd_get_cmd_versions(fd: c_int, cmd: CrosEcCmd) -> EcCmdResult { +pub fn ec_cmd_get_cmd_versions(file: &mut File, cmd: CrosEcCmd) -> EcCmdResult { + let fd = file.as_raw_fd(); let response: EcResponseGetCmdVersion = match ec_command_bytemuck( CrosEcCmd::GetCmdVersions, 1, diff --git a/crosec/src/commands/get_features.rs b/crosec/src/commands/get_features.rs index 7a443a3..684ac4a 100644 --- a/crosec/src/commands/get_features.rs +++ b/crosec/src/commands/get_features.rs @@ -1,4 +1,5 @@ -use nix::libc::c_int; +use std::fs::File; +use std::os::fd::AsRawFd; use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; @@ -6,6 +7,6 @@ use crate::EcCmdResult; pub const EC_FEATURE_PWM_FAN: u64 = 0b100; -pub fn ec_cmd_get_features(fd: c_int) -> EcCmdResult { - ec_command_bytemuck(CrosEcCmd::GetFeatures, 0, &(), fd) +pub fn ec_cmd_get_features(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::GetFeatures, 0, &(), file.as_raw_fd()) } diff --git a/crosec/src/commands/get_protocol_info.rs b/crosec/src/commands/get_protocol_info.rs index 3b7f64a..126840d 100644 --- a/crosec/src/commands/get_protocol_info.rs +++ b/crosec/src/commands/get_protocol_info.rs @@ -1,4 +1,4 @@ -use std::{ffi::c_int, mem::size_of}; +use std::{fs::File, mem::size_of, os::fd::AsRawFd}; use bytemuck::{Pod, Zeroable}; @@ -42,6 +42,6 @@ struct EcHostResponse { reserved: u16, } -pub fn get_protocol_info(fd: c_int) -> EcCmdResult { - ec_command_bytemuck(CrosEcCmd::GetProtocolInfo, 0, &(), fd) +pub fn get_protocol_info(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::GetProtocolInfo, 0, &(), file.as_raw_fd()) } diff --git a/crosec/src/commands/hello.rs b/crosec/src/commands/hello.rs index 7aeb109..acfa1a0 100644 --- a/crosec/src/commands/hello.rs +++ b/crosec/src/commands/hello.rs @@ -1,5 +1,7 @@ +use std::fs::File; +use std::os::fd::AsRawFd; + use bytemuck::{NoUninit, Pod, Zeroable}; -use nix::libc::c_int; use crate::ec_command::ec_command_bytemuck; use crate::{commands::CrosEcCmd, EcCmdResult}; @@ -19,14 +21,14 @@ struct EcResponseHello { out_data: u32, } -pub fn ec_cmd_hello(fd: c_int) -> EcCmdResult { +pub fn ec_cmd_hello(file: &mut File) -> EcCmdResult { let response = ec_command_bytemuck::<_, EcResponseHello>( CrosEcCmd::Hello, 0, &EcParamsHello { in_data: INPUT_DATA, }, - fd, + file.as_raw_fd(), )?; Ok(response.out_data == EXPECTED_OUTPUT) } diff --git a/crosec/src/commands/read_mem.rs b/crosec/src/commands/read_mem.rs index 2af25b8..53f2a55 100644 --- a/crosec/src/commands/read_mem.rs +++ b/crosec/src/commands/read_mem.rs @@ -1,7 +1,7 @@ use crate::CROS_EC_IOC_MAGIC; use bytemuck::{Pod, Zeroable}; use nix::ioctl_readwrite; -use std::ffi::c_int; +use std::{ffi::c_int, fs::File, os::fd::AsRawFd}; const EC_MEM_MAP_SIZE: usize = 255; @@ -21,13 +21,13 @@ struct EcResponseReadMemV2 { ioctl_readwrite!(cros_ec_read_mem, CROS_EC_IOC_MAGIC, 1, EcResponseReadMemV2); -pub fn ec_cmd_read_mem(fd: c_int, offset: u32, bytes: u32) -> Result, c_int> { +pub fn ec_cmd_read_mem(file: &mut File, offset: u32, bytes: u32) -> Result, c_int> { let mut response = EcResponseReadMemV2 { offset, bytes, buffer: [0; EC_MEM_MAP_SIZE], }; - let status = unsafe { cros_ec_read_mem(fd, &mut response) }.unwrap(); + let status = unsafe { cros_ec_read_mem(file.as_raw_fd(), &mut response) }.unwrap(); if status >= 0 { Ok(response.buffer[..bytes as usize].to_vec()) } else { diff --git a/crosec/src/commands/set_fan_target_rpm.rs b/crosec/src/commands/set_fan_target_rpm.rs index 3385b5e..2710cfe 100644 --- a/crosec/src/commands/set_fan_target_rpm.rs +++ b/crosec/src/commands/set_fan_target_rpm.rs @@ -1,5 +1,6 @@ -use std::ffi::c_int; +use std::fs::File; use std::mem::size_of; +use std::os::fd::AsRawFd; use bytemuck::{Pod, Zeroable}; @@ -30,7 +31,11 @@ impl EcParamsSetFanTargetRpmV1 { } } -pub fn ec_cmd_set_fan_target_rpm(fd: c_int, rpm: u32, fan_index: Option) -> EcCmdResult<()> { +pub fn ec_cmd_set_fan_target_rpm( + file: &mut File, + rpm: u32, + fan_index: Option, +) -> EcCmdResult<()> { // v0 can only set the RPM for all fans // v1 can set the RPM for a specific fan match fan_index { @@ -43,7 +48,7 @@ pub fn ec_cmd_set_fan_target_rpm(fd: c_int, rpm: u32, fan_index: Option) -> fan_index: index, } .to_le_bytes(), - fd, + file.as_raw_fd(), )?; } None => { @@ -51,7 +56,7 @@ pub fn ec_cmd_set_fan_target_rpm(fd: c_int, rpm: u32, fan_index: Option) -> CrosEcCmd::SetFanTargetRpm, 0, &EcParamsSetFanTargetRpmV0 { rpm }, - fd, + file.as_raw_fd(), )?; } }; diff --git a/crosec/src/commands/version.rs b/crosec/src/commands/version.rs index 0ab8fb2..033eef5 100644 --- a/crosec/src/commands/version.rs +++ b/crosec/src/commands/version.rs @@ -1,5 +1,6 @@ +use std::{fs::File, os::fd::AsRawFd}; + use bytemuck::{Pod, Zeroable}; -use nix::libc::c_int; use num_derive::FromPrimitive; use num_traits::FromPrimitive; @@ -33,7 +34,7 @@ enum EcImage { } pub fn ec_cmd_version( - fd: c_int, + file: &mut File, protocol_info: &EcResponseGetProtocolInfo, ) -> EcCmdResult<(String, String, String, String, String)> { let params = EcResponseVersionV1 { @@ -44,7 +45,8 @@ pub fn ec_cmd_version( cros_fwid_rw: [0; 32], }; - let response: EcResponseVersionV1 = ec_command_bytemuck(CrosEcCmd::Version, 0, ¶ms, fd)?; + let response: EcResponseVersionV1 = + ec_command_bytemuck(CrosEcCmd::Version, 0, ¶ms, file.as_raw_fd())?; let ro_ver = String::from_utf8(response.version_string_ro.to_vec()).unwrap_or_default(); let rw_ver = String::from_utf8(response.version_string_rw.to_vec()).unwrap_or_default(); @@ -63,7 +65,7 @@ pub fn ec_cmd_version( 0, &[0; 248], protocol_info.max_ec_output_size(), - fd, + file.as_raw_fd(), )?; let build_info = String::from_utf8(result).unwrap_or(String::from("")); diff --git a/crosec/src/console.rs b/crosec/src/console.rs index b60623b..79f371b 100644 --- a/crosec/src/console.rs +++ b/crosec/src/console.rs @@ -1,12 +1,13 @@ -use std::ffi::c_int; +use std::fs::File; +use std::os::fd::AsRawFd; use crate::commands::get_protocol_info::EcResponseGetProtocolInfo; use crate::commands::CrosEcCmd; use crate::ec_command::{ec_command_bytemuck, ec_command_with_dynamic_output_size}; use crate::EcCmdResult; -pub fn console(fd: c_int, protocol_info: &EcResponseGetProtocolInfo) -> EcCmdResult { - ec_command_bytemuck(CrosEcCmd::ConsoleSnapshot, 0, &(), fd)?; +pub fn console(file: &mut File, protocol_info: &EcResponseGetProtocolInfo) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::ConsoleSnapshot, 0, &(), file.as_raw_fd())?; let mut console = String::default(); loop { let output = ec_command_with_dynamic_output_size( @@ -14,7 +15,7 @@ pub fn console(fd: c_int, protocol_info: &EcResponseGetProtocolInfo) -> EcCmdRes 0, Default::default(), protocol_info.max_ec_output_size(), - fd, + file.as_raw_fd(), )?; let chunk = String::from_utf8(output).unwrap(); // Get rid of trailing null characters diff --git a/crosec/src/get_number_of_fans.rs b/crosec/src/get_number_of_fans.rs index 3283cd4..949cd80 100644 --- a/crosec/src/get_number_of_fans.rs +++ b/crosec/src/get_number_of_fans.rs @@ -3,6 +3,7 @@ use crate::read_mem_any::read_mem_any; use crate::{EcError, EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_MEM_MAP_FAN}; use std::ffi::c_int; use std::fmt::{Debug, Display, Formatter}; +use std::fs::File; #[derive(Debug)] pub enum Error { @@ -25,10 +26,10 @@ impl Display for Error { } } -pub fn get_number_of_fans(fd: c_int) -> Result { - let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; +pub fn get_number_of_fans(file: &mut File) -> Result { + let features = ec_cmd_get_features(file).map_err(|e| Error::GetFeatures(e))?; let number_of_fans = if features & EC_FEATURE_PWM_FAN != 0 { - read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN) + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(file, EC_MEM_MAP_FAN) .map_err(|e| Error::ReadMem(e))? .into_iter() .filter(|data| *data != EC_FAN_SPEED_NOT_PRESENT) diff --git a/crosec/src/read_mem_any.rs b/crosec/src/read_mem_any.rs index 157996c..a0fb7b4 100644 --- a/crosec/src/read_mem_any.rs +++ b/crosec/src/read_mem_any.rs @@ -1,12 +1,13 @@ use std::ffi::c_int; +use std::fs::File; use std::mem::size_of; use bytemuck::AnyBitPattern; use crate::commands::read_mem::ec_cmd_read_mem; -pub fn read_mem_any(fd: c_int, offset: u8) -> Result { - let result = ec_cmd_read_mem(fd, offset as u32, size_of::() as u32)?; +pub fn read_mem_any(file: &mut File, offset: u8) -> Result { + let result = ec_cmd_read_mem(file, offset as u32, size_of::() as u32)?; let result = bytemuck::from_bytes(&result); Ok(*result) } diff --git a/crosec/src/read_mem_string.rs b/crosec/src/read_mem_string.rs index fc95453..7547b1b 100644 --- a/crosec/src/read_mem_string.rs +++ b/crosec/src/read_mem_string.rs @@ -1,8 +1,9 @@ -use std::ffi::c_int; use crate::commands::read_mem::ec_cmd_read_mem; use crate::EC_MEM_MAP_MAX_TEXT_SIZE; +use std::ffi::c_int; +use std::fs::File; -pub fn read_mem_string(fd: c_int, offset: u8) -> Result { - let string = ec_cmd_read_mem(fd, offset as u32, EC_MEM_MAP_MAX_TEXT_SIZE as u32)?; +pub fn read_mem_string(file: &mut File, offset: u8) -> Result { + let string = ec_cmd_read_mem(file, offset as u32, EC_MEM_MAP_MAX_TEXT_SIZE as u32)?; Ok(String::from_utf8(string).unwrap()) } diff --git a/ectool/src/main.rs b/ectool/src/main.rs index e45f11f..685f374 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,5 +1,4 @@ use std::fs::File; -use std::os::fd::AsRawFd; use std::str::FromStr; use clap::{Parser, Subcommand, ValueEnum}; @@ -132,9 +131,8 @@ fn main() -> Result<()> { match cli.command { Commands::Hello { device } => { - let file = File::open(device.unwrap_or_default().get_path()).unwrap(); - let fd = file.as_raw_fd(); - let status = ec_cmd_hello(fd)?; + let mut file = File::open(device.unwrap_or_default().get_path())?; + let status = ec_cmd_hello(&mut file)?; if status { println!("EC says hello!"); } else { @@ -142,11 +140,10 @@ fn main() -> Result<()> { } } Commands::Version => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let max_sizes = get_protocol_info(fd)?; + let mut file = File::open(CROS_EC_PATH)?; + let max_sizes = get_protocol_info(&mut file)?; let (ro_ver, rw_ver, firmware_copy, build_info, tool_version) = - ec_cmd_version(fd, &max_sizes)?; + ec_cmd_version(&mut file, &max_sizes)?; println!("RO version: {ro_ver}"); println!("RW version: {rw_ver}"); println!("Firmware copy: {firmware_copy}"); @@ -154,25 +151,22 @@ fn main() -> Result<()> { println!("Tool version: {tool_version}"); } Commands::ChipInfo => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let (vendor, name, revision) = ec_cmd_get_chip_info(fd)?; + let mut file = File::open(CROS_EC_PATH)?; + let (vendor, name, revision) = ec_cmd_get_chip_info(&mut file)?; println!("Chip info:"); println!(" vendor: {vendor}"); println!(" name: {name}"); println!(" revision: {revision}"); } Commands::BoardVersion => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let board_version = ec_cmd_board_version(fd)?; + let mut file = File::open(CROS_EC_PATH)?; + let board_version = ec_cmd_board_version(&mut file)?; println!("Board version: {board_version}"); } Commands::CmdVersions { command } => match CrosEcCmd::from_u32(command) { Some(cmd) => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let versions = ec_cmd_get_cmd_versions(fd, cmd)?; + let mut file = File::open(CROS_EC_PATH)?; + let versions = ec_cmd_get_cmd_versions(&mut file, cmd)?; println!("Versions: {versions:#b}"); } None => { @@ -180,9 +174,8 @@ fn main() -> Result<()> { } }, Commands::SetFanTargetRpm { rpm, index } => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - ec_cmd_set_fan_target_rpm(fd, rpm, index)?; + let mut file = File::open(CROS_EC_PATH)?; + ec_cmd_set_fan_target_rpm(&mut file, rpm, index)?; match index { Some(index) => { println!("Set RPM to {rpm} for fan {index}"); @@ -193,23 +186,20 @@ fn main() -> Result<()> { } } Commands::GetFeatures => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let features = ec_cmd_get_features(fd)?; + let mut file = File::open(CROS_EC_PATH)?; + let features = ec_cmd_get_features(&mut file)?; println!("EC supported features: {features:#b}"); } Commands::GetNumberOfFans => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let number_of_fans = get_number_of_fans(fd).unwrap(); + let mut file = File::open(CROS_EC_PATH)?; + let number_of_fans = get_number_of_fans(&mut file).unwrap(); println!("Number of fans: {number_of_fans}"); } Commands::GetFanRpm => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let features = ec_cmd_get_features(fd).map_err(|e| Error::GetFeatures(e))?; + let mut file = File::open(CROS_EC_PATH)?; + let features = ec_cmd_get_features(&mut file).map_err(|e| Error::GetFeatures(e))?; if features & EC_FEATURE_PWM_FAN != 0 { - read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(fd, EC_MEM_MAP_FAN) + read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(&mut file, EC_MEM_MAP_FAN) .map_err(|e| Error::ReadMem(e))? .into_iter() .enumerate() @@ -227,26 +217,23 @@ fn main() -> Result<()> { }; } Commands::Console { device } => { - let file = File::open(device.unwrap_or_default().get_path()).unwrap(); - let fd = file.as_raw_fd(); - let max_sizes = get_protocol_info(fd)?; - let console = console(fd, &max_sizes)?; + let mut file = File::open(device.unwrap_or_default().get_path())?; + let max_sizes = get_protocol_info(&mut file)?; + let console = console(&mut file, &max_sizes)?; let console = console.trim(); println!("{console}"); } Commands::Battery => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); - let battery_info = battery(fd)?; + let mut file = File::open(CROS_EC_PATH)?; + let battery_info = battery(&mut file)?; println!("{battery_info:#?}"); } Commands::ChargeControl { command } => { - let file = File::open("/dev/cros_ec").unwrap(); - let fd = file.as_raw_fd(); + let mut file = File::open(CROS_EC_PATH)?; match command { None => { - if supports_get_and_sustainer(fd)? { - let charge_control = get_charge_control(fd)?; + if supports_get_and_sustainer(&mut file)? { + let charge_control = get_charge_control(&mut file)?; println!("{charge_control:#?}"); } else { println!("This EC doesn't support getting charge control"); @@ -260,7 +247,7 @@ fn main() -> Result<()> { Some(min_percent) => { let max_percent = max_percent.unwrap_or(min_percent); set_charge_control( - fd, + &mut file, charge_control::ChargeControl::Normal(Some(Sustainer { min_percent: min_percent as i8, max_percent: max_percent as i8, @@ -269,31 +256,32 @@ fn main() -> Result<()> { println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); } None => { - set_charge_control(fd, charge_control::ChargeControl::Normal(None))?; + set_charge_control( + &mut file, + charge_control::ChargeControl::Normal(None), + )?; println!("Set charge control to normal"); } }, ChargeControlSubcommands::Idle => { println!("Set charge control to idle"); - set_charge_control(fd, charge_control::ChargeControl::Idle)?; + set_charge_control(&mut file, charge_control::ChargeControl::Idle)?; } ChargeControlSubcommands::Discharge => { println!("Set charge control to discharge"); - set_charge_control(fd, charge_control::ChargeControl::Discharge)?; + set_charge_control(&mut file, charge_control::ChargeControl::Discharge)?; } }, } } Commands::FpInfo => { - let file = File::open(CROS_FP_PATH).unwrap(); - let fd = file.as_raw_fd(); - let info = fp_info(fd)?; + let mut file = File::open(CROS_FP_PATH)?; + let info = fp_info(&mut file)?; println!("{info:#?}"); } Commands::FpStats => { - let file = File::open(CROS_FP_PATH).unwrap(); - let fd = file.as_raw_fd(); - let stats = fp_stats(fd)?; + let mut file = File::open(CROS_FP_PATH)?; + let stats = fp_stats(&mut file)?; println!("{stats:#?}"); } Commands::FpSetSeed { seed } => { @@ -301,9 +289,8 @@ fn main() -> Result<()> { seed.as_bytes().to_owned(), ) { Ok(seed) => { - let file = File::open(CROS_FP_PATH).unwrap(); - let fd = file.as_raw_fd(); - fp_set_seed(fd, seed)?; + let mut file = File::open(CROS_FP_PATH)?; + fp_set_seed(&mut file, seed)?; println!("Set fp seed"); } Err(seed) => { @@ -322,9 +309,8 @@ fn main() -> Result<()> { } else { FpMode::DontChange as u32 }; - let file = File::open(CROS_FP_PATH).unwrap(); - let fd = file.as_raw_fd(); - let mode = fp_mode(fd, mode)?; + let mut file = File::open(CROS_FP_PATH)?; + let mode = fp_mode(&mut file, mode)?; let display = FpMode::display(mode); println!("FP mode: {display}"); } From cc8858ef4334476274d7a52ceddb5df890d79a59 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:17:15 -0700 Subject: [PATCH 20/39] Download fp frame and templates --- Cargo.lock | 906 ++++++++++++++++++++++++++- crosec/Cargo.toml | 1 + crosec/src/commands/fp_download.rs | 108 ++++ crosec/src/commands/fp_info.rs | 5 + crosec/src/commands/mod.rs | 3 + ectool/Cargo.toml | 1 + ectool/src/fp_download_subcommand.rs | 68 ++ ectool/src/main.rs | 8 + 8 files changed, 1099 insertions(+), 1 deletion(-) create mode 100644 crosec/src/commands/fp_download.rs create mode 100644 ectool/src/fp_download_subcommand.rs diff --git a/Cargo.lock b/Cargo.lock index b13d9da..5b6c4a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "anstream" version = "0.6.14" @@ -66,12 +72,64 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -87,12 +145,42 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitstream-io" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c12d1856e42f0d817a835fe55853957c85c8c8a470114029143d3f12671446e" + +[[package]] +name = "built" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytemuck" version = "1.16.0" @@ -113,11 +201,38 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "cc" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] [[package]] name = "cfg-if" @@ -192,18 +307,34 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crosec" version = "0.1.0" dependencies = [ "bytemuck", "nix", + "num", "num-derive", "num-traits", "strum", @@ -211,6 +342,37 @@ dependencies = [ "thiserror", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "ectool" version = "0.1.0" @@ -219,9 +381,38 @@ dependencies = [ "clap", "color-eyre", "crosec", + "image", "num-traits", ] +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "eyre" version = "0.6.12" @@ -232,48 +423,255 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "image" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +dependencies = [ + "byteorder-lite", + "thiserror", +] + +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -281,19 +679,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", + "simd-adler32", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags", + "bitflags 2.5.0", "cfg-if", "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -305,6 +759,37 @@ dependencies = [ "syn", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -335,12 +820,43 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.81" @@ -350,6 +866,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.36" @@ -359,6 +909,115 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -371,6 +1030,41 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -380,6 +1074,36 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "strsim" version = "0.11.1" @@ -416,6 +1140,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + [[package]] name = "thiserror" version = "1.0.59" @@ -446,6 +1189,51 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -499,12 +1287,95 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "windows-sys" version = "0.52.0" @@ -577,3 +1448,36 @@ name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ff33f391015ecab21cd092389215eb265ef9496a9a07b6bee7d3529831deda" +dependencies = [ + "memchr", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] diff --git a/crosec/Cargo.toml b/crosec/Cargo.toml index bd21405..8db8bdd 100644 --- a/crosec/Cargo.toml +++ b/crosec/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] bytemuck = { version = "1.16.0", features = ["derive"] } nix = { version = "0.27.1", features = ["ioctl"] } +num = "0.4.3" num-derive = "0.4.2" num-traits = "0.2.18" strum = "0.26.2" diff --git a/crosec/src/commands/fp_download.rs b/crosec/src/commands/fp_download.rs new file mode 100644 index 0000000..237316a --- /dev/null +++ b/crosec/src/commands/fp_download.rs @@ -0,0 +1,108 @@ +use std::{fs::File, os::fd::AsRawFd, thread::sleep, time::Duration}; + +use bytemuck::{bytes_of, Pod, Zeroable}; + +use crate::ec_command::ec_command_with_dynamic_output_size; + +use super::{fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd}; + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy)] +struct EcParamsFpFrame { + /// The offset contains the template index or FP_FRAME_INDEX_RAW_IMAGE + /// in the high nibble, and the real offset within the frame in + /// FP_FRAME_OFFSET_MASK. + offset: u32, + size: u32, +} + +const FP_FRAME_INDEX_RAW_IMAGE: u32 = 0; + +/// This can be changed. `3` is what the ChromiumOS ectool uses. +const MAX_ATTEMPTS: usize = 3; + +pub enum DownloadType { + /// (aka `FP_FRAME_INDEX_SIMPLE_IMAGE`) for the a single grayscale image + SimpleImage, + /// (aka `FP_FRAME_INDEX_RAW_IMAGE`) for the full vendor raw finger image. + RawImage, + Template(usize), +} + +/// Downloads a frame buffer from the FPMCU. +/// The downloaded data might be either the finger image or a finger template. +pub fn fp_download( + file: &mut File, + fp_info: &EcResponseFpInfo, + protocol_info: &EcResponseGetProtocolInfo, + download_type: &DownloadType, +) -> Vec { + let (size, index) = match download_type { + DownloadType::SimpleImage => (fp_info.get_simple_image_size(), FP_FRAME_INDEX_RAW_IMAGE), + DownloadType::RawImage => (fp_info.frame_size as usize, FP_FRAME_INDEX_RAW_IMAGE), + DownloadType::Template(template_index) => { + (fp_info.template_size as usize, *template_index as u32) + } + }; + // The template may be (and probably is) bigger than the max output size, so we need to download it in chunks + let number_of_chunks = size.div_ceil(protocol_info.max_ec_output_size()); + let mut chunks = Vec::>::with_capacity(number_of_chunks); + for chunk_index in 0..number_of_chunks { + let bytes_read = chunk_index * protocol_info.max_ec_output_size(); + let remaining_bytes = size - bytes_read; + let current_chunk_size = remaining_bytes.min(protocol_info.max_ec_output_size()); + let mut attempt = 0; + loop { + let result = ec_command_with_dynamic_output_size( + CrosEcCmd::FpFrame, + 0, + bytes_of(&EcParamsFpFrame { + offset: (index << 28) + (bytes_read as u32), + size: current_chunk_size as u32, + }), + current_chunk_size, + file.as_raw_fd(), + ); + if let Ok(chunk) = result { + chunks.push(chunk); + break; + } else { + attempt += 1; + if attempt == MAX_ATTEMPTS { + panic!("Could not successfully get the fp frame in {MAX_ATTEMPTS} attempts"); + } + // Using micros and not millis to be more like original `usleep(100000)` from ChromiumOS's ectool + sleep(Duration::from_micros(100_000)); + } + } + } + chunks.concat() +} + +/// A safe wrapper around the actual template so you don't try to upload arbitrary data +pub struct FpTemplate { + buffer: Vec, +} + +impl Into> for FpTemplate { + fn into(self) -> Vec { + self.buffer + } +} + +impl FpTemplate { + pub fn buffer(&self) -> &Vec { + &self.buffer + } +} + +pub fn fp_download_template( + file: &mut File, + fp_info: &EcResponseFpInfo, + protocol_info: &EcResponseGetProtocolInfo, + index: usize, +) -> FpTemplate { + FpTemplate { + buffer: fp_download(file, fp_info, protocol_info, &DownloadType::Template(index)), + } +} diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs index b0909c2..286e4fe 100644 --- a/crosec/src/commands/fp_info.rs +++ b/crosec/src/commands/fp_info.rs @@ -28,6 +28,11 @@ pub struct EcResponseFpInfo { pub template_dirty: u32, pub template_version: u32, } +impl EcResponseFpInfo { + pub(crate) fn get_simple_image_size(&self) -> usize { + (self.width as usize) * (self.height as usize) * (self.bpp as usize) / 8 + } +} pub fn fp_info(file: &mut File) -> EcCmdResult { let fd = file.as_raw_fd(); diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index c53e0d6..4f8f9e5 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -18,6 +18,8 @@ pub enum CrosEcCmd { ConsoleRead = 0x0098, FpMode = 0x0402, FpInfo = 0x0403, + FpFrame = 0x0404, + FpTemplate = 0x0405, FpStats = 0x0407, FpSetSeed = 0x0408, BatteryGetStatic = 0x0600, @@ -25,6 +27,7 @@ pub enum CrosEcCmd { pub mod board_version; pub mod charge_control; +pub mod fp_download; pub mod fp_info; pub mod fp_mode; pub mod fp_set_seed; diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index bab205a..e7a1be1 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -11,3 +11,4 @@ color-eyre = "0.6.2" clap = { version = "4.5.4", features = ["derive"] } num-traits = "0.2.19" bytemuck = "1.16.0" +image = "0.25.1" diff --git a/ectool/src/fp_download_subcommand.rs b/ectool/src/fp_download_subcommand.rs new file mode 100644 index 0000000..47dc18f --- /dev/null +++ b/ectool/src/fp_download_subcommand.rs @@ -0,0 +1,68 @@ +use std::{ + fs::File, + io::{stdout, Write}, +}; + +use clap::{Subcommand, ValueEnum}; +use color_eyre::eyre::Result; +use crosec::{ + commands::{ + fp_download::{fp_download, fp_download_template, DownloadType}, + fp_info::fp_info, + get_protocol_info::get_protocol_info, + }, + CROS_FP_PATH, +}; +use image::{ + codecs::pnm::{PnmEncoder, PnmSubtype, SampleEncoding}, + ImageEncoder, +}; + +#[derive(ValueEnum, Clone, Copy, Default)] +pub enum FrameType { + Raw, + #[default] + Pgm, +} + +#[derive(Subcommand)] +pub enum FpDownloadSubcommand { + Frame { frame_type: Option }, + Template { index: usize }, +} + +pub fn fp_download_subcommand(command: FpDownloadSubcommand) -> Result<()> { + let mut file = File::open(CROS_FP_PATH)?; + let fp_info = fp_info(&mut file)?; + let protocol_info = get_protocol_info(&mut file)?; + match command { + FpDownloadSubcommand::Frame { frame_type } => match frame_type.unwrap_or_default() { + FrameType::Raw => { + let frame = + fp_download(&mut file, &fp_info, &protocol_info, &DownloadType::RawImage); + stdout().write_all(&frame)?; + } + FrameType::Pgm => { + let frame = fp_download( + &mut file, + &fp_info, + &protocol_info, + &DownloadType::SimpleImage, + ); + PnmEncoder::new(stdout()) + .with_subtype(PnmSubtype::Graymap(SampleEncoding::Binary)) + .write_image( + &frame, + fp_info.width as u32, + fp_info.height as u32, + image::ExtendedColorType::L8, + )?; + } + }, + FpDownloadSubcommand::Template { index } => { + let template = fp_download_template(&mut file, &fp_info, &protocol_info, index); + stdout().write_all(template.buffer())?; + } + } + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 685f374..afe94a4 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -9,6 +9,7 @@ use crosec::commands::fp_set_seed::{fp_set_seed, FP_CONTEXT_TPM_BYTES}; use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; use crosec::wait_event::{event::EcMkbpEventType, wait_event}; +use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; use num_traits::cast::FromPrimitive; use crosec::battery::battery; @@ -31,6 +32,8 @@ use crosec::{ EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, }; +mod fp_download_subcommand; + #[derive(Parser)] struct Cli { #[command(subcommand)] @@ -107,6 +110,10 @@ enum Commands { timeout: i32, device: Option, }, + FpDownload { + #[command(subcommand)] + command: FpDownloadSubcommand, + }, } #[derive(Subcommand)] @@ -324,6 +331,7 @@ fn main() -> Result<()> { wait_event(&mut file, EcMkbpEventType::from_str(&event_type)?, timeout).unwrap(); println!("{result:#?}"); } + Commands::FpDownload { command } => fp_download_subcommand(command)?, } Ok(()) From 4a81f0c0a714edfade5100fbd7be3dc1f2fbdd61 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:22:41 -0700 Subject: [PATCH 21/39] Move charge control subcommand to new file --- ectool/src/charge_control_subcommand.rs | 73 +++++++++++++++++++++++++ ectool/src/main.rs | 72 ++---------------------- 2 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 ectool/src/charge_control_subcommand.rs diff --git a/ectool/src/charge_control_subcommand.rs b/ectool/src/charge_control_subcommand.rs new file mode 100644 index 0000000..dd2255e --- /dev/null +++ b/ectool/src/charge_control_subcommand.rs @@ -0,0 +1,73 @@ +use std::fs::File; + +use clap::Subcommand; +use color_eyre::eyre::Result; +use crosec::{ + commands::charge_control::{ + get_charge_control, set_charge_control, supports_get_and_sustainer, ChargeControl, + Sustainer, + }, + CROS_EC_PATH, +}; + +#[derive(Subcommand)] +pub enum ChargeControlSubcommand { + /// Charge the battery with external power and power the device with external power + Normal { + /// Minimum battery % to keep the battery at + min_percent: Option, + /// Maximum battery & to keep the battery at. If this isn't specified, this will be set to the same as the min %. + max_percent: Option, + }, + /// Power the device with external power, but do not charge the battery + Idle, + /// Power the device with the battery and do not charge the battery + Discharge, +} + +pub fn charge_control_subcommand(command: Option) -> Result<()> { + { + let mut file = File::open(CROS_EC_PATH)?; + match command { + None => { + if supports_get_and_sustainer(&mut file)? { + let charge_control = get_charge_control(&mut file)?; + println!("{charge_control:#?}"); + } else { + println!("This EC doesn't support getting charge control"); + } + } + Some(command) => match command { + ChargeControlSubcommand::Normal { + min_percent, + max_percent, + } => match min_percent { + Some(min_percent) => { + let max_percent = max_percent.unwrap_or(min_percent); + set_charge_control( + &mut file, + ChargeControl::Normal(Some(Sustainer { + min_percent: min_percent as i8, + max_percent: max_percent as i8, + })), + )?; + println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); + } + None => { + set_charge_control(&mut file, ChargeControl::Normal(None))?; + println!("Set charge control to normal"); + } + }, + ChargeControlSubcommand::Idle => { + println!("Set charge control to idle"); + set_charge_control(&mut file, ChargeControl::Idle)?; + } + ChargeControlSubcommand::Discharge => { + println!("Set charge control to discharge"); + set_charge_control(&mut file, ChargeControl::Discharge)?; + } + }, + } + } + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index afe94a4..1c7973b 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,6 +1,7 @@ use std::fs::File; use std::str::FromStr; +use charge_control_subcommand::{charge_control_subcommand, ChargeControlSubcommand}; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; use crosec::commands::fp_info::fp_info; @@ -14,15 +15,11 @@ use num_traits::cast::FromPrimitive; use crosec::battery::battery; use crosec::commands::board_version::ec_cmd_board_version; -use crosec::commands::charge_control::{ - get_charge_control, set_charge_control, supports_get_and_sustainer, Sustainer, -}; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; use crosec::commands::get_features::{ec_cmd_get_features, EC_FEATURE_PWM_FAN}; use crosec::commands::set_fan_target_rpm::ec_cmd_set_fan_target_rpm; use crosec::commands::{ - charge_control, get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, - version::ec_cmd_version, CrosEcCmd, + get_chip_info::ec_cmd_get_chip_info, hello::ec_cmd_hello, version::ec_cmd_version, CrosEcCmd, }; use crosec::console::console; use crosec::get_number_of_fans::{get_number_of_fans, Error}; @@ -32,6 +29,7 @@ use crosec::{ EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, }; +mod charge_control_subcommand; mod fp_download_subcommand; #[derive(Parser)] @@ -94,7 +92,7 @@ enum Commands { Battery, ChargeControl { #[command(subcommand)] - command: Option, + command: Option, }, FpInfo, FpStats, @@ -116,21 +114,6 @@ enum Commands { }, } -#[derive(Subcommand)] -enum ChargeControlSubcommands { - /// Charge the battery with external power and power the device with external power - Normal { - /// Minimum battery % to keep the battery at - min_percent: Option, - /// Maximum battery & to keep the battery at. If this isn't specified, this will be set to the same as the min %. - max_percent: Option, - }, - /// Power the device with external power, but do not charge the battery - Idle, - /// Power the device with the battery and do not charge the battery - Discharge, -} - fn main() -> Result<()> { color_eyre::install()?; @@ -235,52 +218,7 @@ fn main() -> Result<()> { let battery_info = battery(&mut file)?; println!("{battery_info:#?}"); } - Commands::ChargeControl { command } => { - let mut file = File::open(CROS_EC_PATH)?; - match command { - None => { - if supports_get_and_sustainer(&mut file)? { - let charge_control = get_charge_control(&mut file)?; - println!("{charge_control:#?}"); - } else { - println!("This EC doesn't support getting charge control"); - } - } - Some(command) => match command { - ChargeControlSubcommands::Normal { - min_percent, - max_percent, - } => match min_percent { - Some(min_percent) => { - let max_percent = max_percent.unwrap_or(min_percent); - set_charge_control( - &mut file, - charge_control::ChargeControl::Normal(Some(Sustainer { - min_percent: min_percent as i8, - max_percent: max_percent as i8, - })), - )?; - println!("Set charge control to normal with sustainer from {min_percent}% to {max_percent}%"); - } - None => { - set_charge_control( - &mut file, - charge_control::ChargeControl::Normal(None), - )?; - println!("Set charge control to normal"); - } - }, - ChargeControlSubcommands::Idle => { - println!("Set charge control to idle"); - set_charge_control(&mut file, charge_control::ChargeControl::Idle)?; - } - ChargeControlSubcommands::Discharge => { - println!("Set charge control to discharge"); - set_charge_control(&mut file, charge_control::ChargeControl::Discharge)?; - } - }, - } - } + Commands::ChargeControl { command } => charge_control_subcommand(command)?, Commands::FpInfo => { let mut file = File::open(CROS_FP_PATH)?; let info = fp_info(&mut file)?; From c4b35607fb6f73cfab502ae6506d8ea09f2b7d02 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:11:04 -0700 Subject: [PATCH 22/39] Upload template command Also includes a fix for downloading templates --- crosec/src/commands/fp_download.rs | 15 +++-- crosec/src/commands/fp_info.rs | 7 +++ crosec/src/commands/fp_upload_template.rs | 69 +++++++++++++++++++++++ crosec/src/commands/get_protocol_info.rs | 2 +- crosec/src/commands/mod.rs | 1 + ectool/src/fp_upload_template_command.rs | 26 +++++++++ ectool/src/main.rs | 5 ++ 7 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 crosec/src/commands/fp_upload_template.rs create mode 100644 ectool/src/fp_upload_template_command.rs diff --git a/crosec/src/commands/fp_download.rs b/crosec/src/commands/fp_download.rs index 237316a..8790d8b 100644 --- a/crosec/src/commands/fp_download.rs +++ b/crosec/src/commands/fp_download.rs @@ -41,7 +41,7 @@ pub fn fp_download( DownloadType::SimpleImage => (fp_info.get_simple_image_size(), FP_FRAME_INDEX_RAW_IMAGE), DownloadType::RawImage => (fp_info.frame_size as usize, FP_FRAME_INDEX_RAW_IMAGE), DownloadType::Template(template_index) => { - (fp_info.template_size as usize, *template_index as u32) + (fp_info.template_size as usize, *template_index as u32 + 1) } }; // The template may be (and probably is) bigger than the max output size, so we need to download it in chunks @@ -81,18 +81,23 @@ pub fn fp_download( /// A safe wrapper around the actual template so you don't try to upload arbitrary data pub struct FpTemplate { - buffer: Vec, + vec: Vec, } impl Into> for FpTemplate { fn into(self) -> Vec { - self.buffer + self.vec } } impl FpTemplate { pub fn buffer(&self) -> &Vec { - &self.buffer + &self.vec + } + + /// Make sure your buffer is actually a compatible fp template + pub unsafe fn from_vec_unchecked(vec: Vec) -> Self { + FpTemplate { vec } } } @@ -103,6 +108,6 @@ pub fn fp_download_template( index: usize, ) -> FpTemplate { FpTemplate { - buffer: fp_download(file, fp_info, protocol_info, &DownloadType::Template(index)), + vec: fp_download(file, fp_info, protocol_info, &DownloadType::Template(index)), } } diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs index 286e4fe..89a2cad 100644 --- a/crosec/src/commands/fp_info.rs +++ b/crosec/src/commands/fp_info.rs @@ -16,16 +16,23 @@ pub struct EcResponseFpInfo { pub product_id: u32, pub model_id: u32, pub version: u32, + /// The size of the PGM image, in bytes pub frame_size: u32, pub pixel_format: u32, pub width: u16, pub height: u16, pub bpp: u16, pub errors: u16, + /// The template size, in bytes pub template_size: u32, + /// The maximum number of templates the FP can store and match at once pub template_max: u16, + /// The number of templates loaded into the FP pub template_valid: u16, + /// The first bit (the rightmost) represents template 0, the 2nd bit form the right represents template 1, etc. + /// If the bit is 1, that means that the template has been updated by the FP and the updated version has not been downloaded yet. pub template_dirty: u32, + /// This version could increase after an update to the FP firmware pub template_version: u32, } impl EcResponseFpInfo { diff --git a/crosec/src/commands/fp_upload_template.rs b/crosec/src/commands/fp_upload_template.rs new file mode 100644 index 0000000..0f293d2 --- /dev/null +++ b/crosec/src/commands/fp_upload_template.rs @@ -0,0 +1,69 @@ +use std::{fs::File, mem::offset_of, os::fd::AsRawFd}; + +use bytemuck::{bytes_of, Pod, Zeroable}; + +use crate::{ec_command::ec_command_with_dynamic_output_size, EcCmdResult}; + +use super::{ + fp_download::FpTemplate, fp_info::EcResponseFpInfo, + get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd, +}; + +#[derive(Pod, Zeroable, Clone, Copy)] +#[repr(C)] +struct EcParamsFpTemplateWithoutData { + offset: u32, + size: u32, + data: [u8; 0], +} + +/// Flag in the 'size' field indicating that the full template has been sent +const FP_TEMPLATE_COMMIT: u32 = 0x80000000; + +pub fn fp_upload_template( + file: &mut File, + protocol_info: &EcResponseGetProtocolInfo, + fp_info: &EcResponseFpInfo, + template: &FpTemplate, +) -> EcCmdResult<()> { + assert_eq!( + template.buffer().len(), + fp_info.template_size as usize, + "The given template must match the fp sensor's template size" + ); + // TODO(b/78544921): removing 32 bits is a workaround for the MCU bug + // Idk what this bug is, but the ChromiumOS ectool removes 4 bytes, so we should too + let max_chunk_size = + protocol_info.max_ec_output_size() - offset_of!(EcParamsFpTemplateWithoutData, data) - 4; + let number_of_chunks = template + .buffer() + .len() + .div_ceil(protocol_info.max_ec_input_size()); + for chunk_index in 0..number_of_chunks { + ec_command_with_dynamic_output_size( + CrosEcCmd::FpTemplate, + 0, + &{ + let bytes_uploaded = chunk_index * max_chunk_size; + let size = (template.buffer().len() - bytes_uploaded).min(max_chunk_size); + let mut vec = bytes_of(&EcParamsFpTemplateWithoutData { + offset: bytes_uploaded as u32, + size: { + let mut size = size as u32; + if chunk_index == number_of_chunks - 1 { + size |= FP_TEMPLATE_COMMIT; + } + size + }, + data: [], + }) + .to_vec(); + vec.extend_from_slice(&template.buffer()[bytes_uploaded..bytes_uploaded + size]); + vec + }, + 0, + file.as_raw_fd(), + )?; + } + Ok(()) +} diff --git a/crosec/src/commands/get_protocol_info.rs b/crosec/src/commands/get_protocol_info.rs index 126840d..69b0b25 100644 --- a/crosec/src/commands/get_protocol_info.rs +++ b/crosec/src/commands/get_protocol_info.rs @@ -4,7 +4,7 @@ use bytemuck::{Pod, Zeroable}; use crate::{commands::CrosEcCmd, ec_command::ec_command_bytemuck, EcCmdResult}; -#[derive(Pod, Zeroable, Clone, Copy)] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] #[repr(C)] pub struct EcResponseGetProtocolInfo { protocol_versions: u32, diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 4f8f9e5..e2b87f5 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -32,6 +32,7 @@ pub mod fp_info; pub mod fp_mode; pub mod fp_set_seed; pub mod fp_stats; +pub mod fp_upload_template; pub mod get_chip_info; pub mod get_cmd_versions; pub mod get_features; diff --git a/ectool/src/fp_upload_template_command.rs b/ectool/src/fp_upload_template_command.rs new file mode 100644 index 0000000..76529f7 --- /dev/null +++ b/ectool/src/fp_upload_template_command.rs @@ -0,0 +1,26 @@ +use std::{ + fs::File, + io::{stdin, Read}, +}; + +use color_eyre::eyre::Result; +use crosec::{ + commands::{ + fp_download::FpTemplate, fp_info::fp_info, fp_upload_template::fp_upload_template, + get_protocol_info::get_protocol_info, + }, + CROS_FP_PATH, +}; + +pub fn fp_upload_template_command() -> Result<()> { + let mut buf = Default::default(); + println!("Reading from stdin. If this command is taking a long time, it's probably because there is no EOF inputted from stdin."); + stdin().read_to_end(&mut buf)?; + let template = unsafe { FpTemplate::from_vec_unchecked(buf) }; + let mut file = File::open(CROS_FP_PATH)?; + let protocol_info = get_protocol_info(&mut file)?; + let fp_info = fp_info(&mut file)?; + fp_upload_template(&mut file, &protocol_info, &fp_info, &template)?; + println!("Uploaded template"); + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 1c7973b..6378ff6 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -11,6 +11,7 @@ use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; use crosec::wait_event::{event::EcMkbpEventType, wait_event}; use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; +use fp_upload_template_command::fp_upload_template_command; use num_traits::cast::FromPrimitive; use crosec::battery::battery; @@ -31,6 +32,7 @@ use crosec::{ mod charge_control_subcommand; mod fp_download_subcommand; +mod fp_upload_template_command; #[derive(Parser)] struct Cli { @@ -112,6 +114,8 @@ enum Commands { #[command(subcommand)] command: FpDownloadSubcommand, }, + /// Uploads template from stdin + FpUploadTemplate, } fn main() -> Result<()> { @@ -270,6 +274,7 @@ fn main() -> Result<()> { println!("{result:#?}"); } Commands::FpDownload { command } => fp_download_subcommand(command)?, + Commands::FpUploadTemplate => fp_upload_template_command()?, } Ok(()) From 6da00c5e9a8ef838595fc2d4ede0dcb8103f7061 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Fri, 7 Jun 2024 08:40:11 -0700 Subject: [PATCH 23/39] Add clap feature to crosec for better fp-mode command --- Cargo.lock | 13 +++++++------ crosec/Cargo.toml | 4 ++++ crosec/src/commands/fp_mode.rs | 1 + ectool/Cargo.toml | 2 +- ectool/src/main.rs | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b6c4a5..a342345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,9 +242,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" dependencies = [ "clap_builder", "clap_derive", @@ -252,9 +252,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" dependencies = [ "anstream", "anstyle", @@ -264,9 +264,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck", "proc-macro2", @@ -333,6 +333,7 @@ name = "crosec" version = "0.1.0" dependencies = [ "bytemuck", + "clap", "nix", "num", "num-derive", diff --git a/crosec/Cargo.toml b/crosec/Cargo.toml index 8db8bdd..a832b8e 100644 --- a/crosec/Cargo.toml +++ b/crosec/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bytemuck = { version = "1.16.0", features = ["derive"] } +clap = { version = "4.5.6", optional = true } nix = { version = "0.27.1", features = ["ioctl"] } num = "0.4.3" num-derive = "0.4.2" @@ -14,3 +15,6 @@ num-traits = "0.2.18" strum = "0.26.2" strum_macros = "0.26.4" thiserror = "1.0.57" + +[features] +clap = ["dep:clap"] diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs index bfe2faa..fc9980e 100644 --- a/crosec/src/commands/fp_mode.rs +++ b/crosec/src/commands/fp_mode.rs @@ -9,6 +9,7 @@ use super::CrosEcCmd; /// Note that with the ChromiumOS ectool, to start enrolling, as well as continue the next step in enrolling, you do `ectool --name=cros_fp fpmode enroll`. The equivalent of this is to do `ectool fp-mode EnrollImage EnrollSession`. #[derive(EnumString, EnumIter, IntoStaticStr, Clone, Copy)] +#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[repr(u32)] pub enum FpMode { Reset = 0b00000000000000000000000000000000, diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index e7a1be1..8d8e4fa 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -crosec = { version = "0.1.0", path = "../crosec" } +crosec = { version = "0.1.0", path = "../crosec", features = ["clap"] } color-eyre = "0.6.2" clap = { version = "4.5.4", features = ["derive"] } num-traits = "0.2.19" diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 6378ff6..b7e525f 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -102,7 +102,7 @@ enum Commands { seed: String, }, FpMode { - mode: Vec, + mode: Vec, }, WaitEvent { event_type: String, @@ -252,7 +252,7 @@ fn main() -> Result<()> { let mode = if mode.len() > 0 { let mut mode_number: u32 = 0; for mode in mode { - mode_number |= FpMode::from_str(&mode)? as u32; + mode_number |= mode as u32; } mode_number } else { From 80f4101b73b1c5214608aa9911e2f737f8057530 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 08:36:30 -0700 Subject: [PATCH 24/39] Add no-timeout mode to wait_event --- crosec/src/wait_event/mod.rs | 34 ++++++++++++++++++++-------------- ectool/src/main.rs | 3 ++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/crosec/src/wait_event/mod.rs b/crosec/src/wait_event/mod.rs index 79d345a..a195220 100644 --- a/crosec/src/wait_event/mod.rs +++ b/crosec/src/wait_event/mod.rs @@ -20,10 +20,11 @@ pub enum PollData { SomethingElseHappened(i16), } +/// If no timeout is specified, this function will wait for an unlimited amount of time pub fn wait_event( file: &mut File, event_type: EcMkbpEventType, - timeout: i32, + timeout: Option, ) -> Result { let mask = 1 << event_type as u8; unsafe { @@ -33,18 +34,23 @@ pub fn wait_event( mask, ) }; - let mut fds = pollfd { - fd: file.as_raw_fd(), - events: POLL_IN, - revents: Default::default(), - }; - let result = unsafe { poll(&mut fds, 1, timeout) }; - match result { - 0 => Ok(PollData::Timeout), - 1 => match fds.revents { - POLL_IN => Ok(PollData::EventHappened(event_type.read(file).unwrap())), - events => Ok(PollData::SomethingElseHappened(events)), - }, - result => Err(result), + match timeout { + Some(timeout) => { + let mut fds = pollfd { + fd: file.as_raw_fd(), + events: POLL_IN, + revents: Default::default(), + }; + let result = unsafe { poll(&mut fds, 1, timeout) }; + match result { + 0 => Ok(PollData::Timeout), + 1 => match fds.revents { + POLL_IN => Ok(PollData::EventHappened(event_type.read(file).unwrap())), + events => Ok(PollData::SomethingElseHappened(events)), + }, + result => Err(result), + } + } + None => Ok(PollData::EventHappened(event_type.read(file).unwrap())), } } diff --git a/ectool/src/main.rs b/ectool/src/main.rs index b7e525f..fff505e 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -107,7 +107,8 @@ enum Commands { WaitEvent { event_type: String, /// Timeout in milliseconds - timeout: i32, + timeout: Option, + #[arg(short, long)] device: Option, }, FpDownload { From 16e89ed9c014686f479aa3c2c67701254e44c429 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 08:41:25 -0700 Subject: [PATCH 25/39] clap::ValueEnum for EcMkbpEventType --- crosec/src/wait_event/event.rs | 4 ++-- ectool/src/main.rs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs index 7053345..ad61e21 100644 --- a/crosec/src/wait_event/event.rs +++ b/crosec/src/wait_event/event.rs @@ -5,7 +5,6 @@ use std::{ use bytemuck::{from_bytes, Pod, Zeroable}; use num_derive::FromPrimitive; -use strum_macros::{EnumString, IntoStaticStr}; use crate::wait_event::fingerprint::EcMkbpEventFingerprint; @@ -33,7 +32,8 @@ pub enum EcMkbpEvent { CecEvent(u32), } -#[derive(Debug, IntoStaticStr, EnumString, FromPrimitive, Clone, Copy)] +#[derive(Debug, FromPrimitive, Clone, Copy)] +#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[repr(u8)] pub enum EcMkbpEventType { KeyMatrix, diff --git a/ectool/src/main.rs b/ectool/src/main.rs index fff505e..5b6e3aa 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,5 +1,4 @@ use std::fs::File; -use std::str::FromStr; use charge_control_subcommand::{charge_control_subcommand, ChargeControlSubcommand}; use clap::{Parser, Subcommand, ValueEnum}; @@ -105,7 +104,7 @@ enum Commands { mode: Vec, }, WaitEvent { - event_type: String, + event_type: EcMkbpEventType, /// Timeout in milliseconds timeout: Option, #[arg(short, long)] @@ -270,8 +269,7 @@ fn main() -> Result<()> { timeout, } => { let mut file = File::open(device.unwrap_or_default().get_path())?; - let result = - wait_event(&mut file, EcMkbpEventType::from_str(&event_type)?, timeout).unwrap(); + let result = wait_event(&mut file, event_type, timeout).unwrap(); println!("{result:#?}"); } Commands::FpDownload { command } => fp_download_subcommand(command)?, From b086358215008e86f2307ff146db83dfa5b3d49f Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 08:48:56 -0700 Subject: [PATCH 26/39] Better fp-seed bad seed feedback --- ectool/src/check_seed.rs | 11 +++++++++++ ectool/src/main.rs | 21 +++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 ectool/src/check_seed.rs diff --git a/ectool/src/check_seed.rs b/ectool/src/check_seed.rs new file mode 100644 index 0000000..37530d7 --- /dev/null +++ b/ectool/src/check_seed.rs @@ -0,0 +1,11 @@ +use crosec::commands::fp_set_seed::FP_CONTEXT_TPM_BYTES; + +pub fn check_seed(seed: &str) -> Result<[u8; FP_CONTEXT_TPM_BYTES], String> { + match as TryInto<[u8; FP_CONTEXT_TPM_BYTES]>>::try_into(seed.as_bytes().to_owned()) { + Ok(seed) => Ok(seed), + Err(seed) => { + let seed_len = seed.len(); + Err(format!("The seed must be {FP_CONTEXT_TPM_BYTES} bytes long. The seed you inputted is {seed_len} bytes long.")) + } + } +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 5b6e3aa..33d2393 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,6 +1,7 @@ use std::fs::File; use charge_control_subcommand::{charge_control_subcommand, ChargeControlSubcommand}; +use check_seed::check_seed; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; use crosec::commands::fp_info::fp_info; @@ -30,6 +31,7 @@ use crosec::{ }; mod charge_control_subcommand; +mod check_seed; mod fp_download_subcommand; mod fp_upload_template_command; @@ -98,7 +100,8 @@ enum Commands { FpInfo, FpStats, FpSetSeed { - seed: String, + #[arg(value_parser = check_seed)] + seed: [u8; FP_CONTEXT_TPM_BYTES], }, FpMode { mode: Vec, @@ -234,19 +237,9 @@ fn main() -> Result<()> { println!("{stats:#?}"); } Commands::FpSetSeed { seed } => { - match as TryInto<[u8; FP_CONTEXT_TPM_BYTES]>>::try_into( - seed.as_bytes().to_owned(), - ) { - Ok(seed) => { - let mut file = File::open(CROS_FP_PATH)?; - fp_set_seed(&mut file, seed)?; - println!("Set fp seed"); - } - Err(seed) => { - let seed_len = seed.len(); - println!("The seed must be {FP_CONTEXT_TPM_BYTES} bytes long. The seed you inputted is {seed_len} bytes long."); - } - } + let mut file = File::open(CROS_FP_PATH)?; + fp_set_seed(&mut file, seed)?; + println!("Set fp seed"); } Commands::FpMode { mode } => { let mode = if mode.len() > 0 { From 37a554ecf678caa3c78afa6fdb4139e5bfc113a9 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 08:53:20 -0700 Subject: [PATCH 27/39] Add version and about to ectool --- ectool/Cargo.toml | 1 + ectool/src/main.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index 8d8e4fa..7dd242e 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -2,6 +2,7 @@ name = "ectool" version = "0.1.0" edition = "2021" +description = "A Rust CLI for interfacing with the ChromeOS Embedded Controller." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 33d2393..8393bd0 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -36,6 +36,7 @@ mod fp_download_subcommand; mod fp_upload_template_command; #[derive(Parser)] +#[command(version, about)] struct Cli { #[command(subcommand)] command: Commands, From 22e0d43981a1c3f5fc34f39003b7647fdedb3923 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:51:32 -0700 Subject: [PATCH 28/39] Remove unused EcParamsReadMem --- crosec/src/commands/read_mem.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crosec/src/commands/read_mem.rs b/crosec/src/commands/read_mem.rs index 53f2a55..22f9537 100644 --- a/crosec/src/commands/read_mem.rs +++ b/crosec/src/commands/read_mem.rs @@ -1,17 +1,9 @@ use crate::CROS_EC_IOC_MAGIC; -use bytemuck::{Pod, Zeroable}; use nix::ioctl_readwrite; use std::{ffi::c_int, fs::File, os::fd::AsRawFd}; const EC_MEM_MAP_SIZE: usize = 255; -#[repr(C, align(1))] -#[derive(Pod, Zeroable, Copy, Clone)] -struct EcParamsReadMem { - offset: u8, - size: u8, -} - #[repr(C)] struct EcResponseReadMemV2 { offset: u32, From 311b3b0e2dbc1ad8598069fbb56d0f7b3b40f5be Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:52:01 -0700 Subject: [PATCH 29/39] Nix flake --- flake.lock | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 26 +++++++++++ 2 files changed, 156 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..420238d --- /dev/null +++ b/flake.lock @@ -0,0 +1,130 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1717602782, + "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1706487304, + "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1717813066, + "narHash": "sha256-wqbRwq3i7g5EHIui0bIi84mdqZ/It1AXBSLJ5tafD28=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "6dc3e45fe4aee36efeed24d64fc68b1f989d5465", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..afea022 --- /dev/null +++ b/flake.nix @@ -0,0 +1,26 @@ +{ + description = "A devShell example"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + in + { + devShells.default = with pkgs; mkShell { + buildInputs = [ + rust-bin.stable.latest.default + ]; + }; + } + ); +} From a64baa9e7604550a1ed1e82a85c2262596c6dadb Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 12 Jun 2024 10:32:18 -0700 Subject: [PATCH 30/39] Use trait for File in `fp_mode` --- crosec/src/commands/fp_mode.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs index fc9980e..8a632ca 100644 --- a/crosec/src/commands/fp_mode.rs +++ b/crosec/src/commands/fp_mode.rs @@ -1,5 +1,6 @@ +use std::os::fd::AsRawFd; + use bytemuck::{Pod, Zeroable}; -use std::{fs::File, os::fd::AsRawFd}; use strum::IntoEnumIterator; use strum_macros::{EnumIter, EnumString, IntoStaticStr}; @@ -51,7 +52,7 @@ struct EcResponseFpMode { mode: u32, } -pub fn fp_mode(file: &mut File, mode: u32) -> EcCmdResult { +pub fn fp_mode(file: &mut File, mode: u32) -> EcCmdResult { let response: EcResponseFpMode = ec_command_bytemuck( CrosEcCmd::FpMode, 0, From a2d5504d867ec1a3ac41f75ec298feaca3fc9ed9 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:01:38 -0700 Subject: [PATCH 31/39] Some improvements Added an async wait_event function, added get encryption status function, made some more functions use generic trait for file. --- Cargo.lock | 591 +++++++++++++++++- crosec/Cargo.toml | 1 + crosec/src/commands/fp_download.rs | 8 +- .../src/commands/fp_get_encryption_status.rs | 21 + crosec/src/commands/fp_info.rs | 6 +- crosec/src/commands/fp_mode.rs | 2 +- crosec/src/commands/fp_set_seed.rs | 4 +- crosec/src/commands/fp_upload_template.rs | 8 +- crosec/src/commands/get_cmd_versions.rs | 3 +- crosec/src/commands/get_protocol_info.rs | 4 +- crosec/src/commands/mod.rs | 2 + crosec/src/wait_event/event.rs | 28 +- crosec/src/wait_event/mod.rs | 27 +- .../src/fp_get_encryption_status_command.rs | 11 + ectool/src/main.rs | 8 +- 15 files changed, 680 insertions(+), 44 deletions(-) create mode 100644 crosec/src/commands/fp_get_encryption_status.rs create mode 100644 ectool/src/fp_get_encryption_status_command.rs diff --git a/Cargo.lock b/Cargo.lock index a342345..59d8e73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,7 +59,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -69,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -101,6 +101,154 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.0", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.3.3", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.2", + "rustix 0.38.34", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.2.0" @@ -169,6 +317,19 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c12d1856e42f0d817a835fe55853957c85c8c8a470114029143d3f12671446e" +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.3.0", + "piper", +] + [[package]] name = "built" version = "0.7.3" @@ -319,6 +480,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -332,6 +502,7 @@ dependencies = [ name = "crosec" version = "0.1.0" dependencies = [ + "async-std", "bytemuck", "clap", "nix", @@ -398,6 +569,43 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "exr" version = "1.72.0" @@ -424,6 +632,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "fdeflate" version = "0.3.4" @@ -452,6 +675,55 @@ dependencies = [ "spin", ] +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "getrandom" version = "0.2.14" @@ -479,6 +751,18 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "half" version = "2.4.1" @@ -501,6 +785,18 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "image" version = "0.25.1" @@ -556,6 +852,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -567,6 +872,17 @@ dependencies = [ "syn", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -597,6 +913,24 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -626,6 +960,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "lock_api" version = "0.4.12" @@ -641,6 +987,9 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "value-bag", +] [[package]] name = "loop9" @@ -821,6 +1170,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "paste" version = "1.0.15" @@ -833,6 +1188,23 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand 2.1.0", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -852,6 +1224,37 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.34", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1025,6 +1428,33 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -1090,12 +1520,31 @@ dependencies = [ "quote", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.9.8" @@ -1305,12 +1754,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + [[package]] name = "version-compare" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1342,6 +1803,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -1371,19 +1844,75 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "weezl" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1392,28 +1921,46 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -1426,24 +1973,48 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.5" diff --git a/crosec/Cargo.toml b/crosec/Cargo.toml index a832b8e..7942f73 100644 --- a/crosec/Cargo.toml +++ b/crosec/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-std = "1.12.0" bytemuck = { version = "1.16.0", features = ["derive"] } clap = { version = "4.5.6", optional = true } nix = { version = "0.27.1", features = ["ioctl"] } diff --git a/crosec/src/commands/fp_download.rs b/crosec/src/commands/fp_download.rs index 8790d8b..bdd47d3 100644 --- a/crosec/src/commands/fp_download.rs +++ b/crosec/src/commands/fp_download.rs @@ -1,10 +1,10 @@ -use std::{fs::File, os::fd::AsRawFd, thread::sleep, time::Duration}; +use std::{os::fd::AsRawFd, thread::sleep, time::Duration}; use bytemuck::{bytes_of, Pod, Zeroable}; use crate::ec_command::ec_command_with_dynamic_output_size; -use super::{fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd}; +use super::{CrosEcCmd, fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo}; #[repr(C)] #[derive(Pod, Zeroable, Clone, Copy)] @@ -31,7 +31,7 @@ pub enum DownloadType { /// Downloads a frame buffer from the FPMCU. /// The downloaded data might be either the finger image or a finger template. -pub fn fp_download( +pub fn fp_download( file: &mut File, fp_info: &EcResponseFpInfo, protocol_info: &EcResponseGetProtocolInfo, @@ -101,7 +101,7 @@ impl FpTemplate { } } -pub fn fp_download_template( +pub fn fp_download_template( file: &mut File, fp_info: &EcResponseFpInfo, protocol_info: &EcResponseGetProtocolInfo, diff --git a/crosec/src/commands/fp_get_encryption_status.rs b/crosec/src/commands/fp_get_encryption_status.rs new file mode 100644 index 0000000..47ac684 --- /dev/null +++ b/crosec/src/commands/fp_get_encryption_status.rs @@ -0,0 +1,21 @@ +use std::os::fd::AsRawFd; +use bytemuck::{Pod, Zeroable}; +use crate::commands::CrosEcCmd; +use crate::ec_command::ec_command_bytemuck; +use crate::EcCmdResult; + +#[repr(u32)] +pub enum FpEncryptionStatus { + SeedSet = 0b1 +} + +#[derive(Pod, Zeroable, Copy, Clone)] +#[repr(C)] +pub struct EcResponseFpGetEncryptionStatus { + pub valid_flags: u32, + pub status: u32, +} + +pub fn fp_get_encryption_status(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::FpGetEncryptionStatus, 0, &(), file.as_raw_fd()) +} \ No newline at end of file diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs index 89a2cad..4a49c44 100644 --- a/crosec/src/commands/fp_info.rs +++ b/crosec/src/commands/fp_info.rs @@ -1,12 +1,12 @@ -use std::{fs::File, os::fd::AsRawFd}; +use std::os::fd::AsRawFd; use bytemuck::{Pod, Zeroable}; use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; use super::{ - get_cmd_versions::{ec_cmd_get_cmd_versions, V1}, CrosEcCmd, + get_cmd_versions::{ec_cmd_get_cmd_versions, V1}, }; #[repr(C, align(4))] @@ -41,7 +41,7 @@ impl EcResponseFpInfo { } } -pub fn fp_info(file: &mut File) -> EcCmdResult { +pub fn fp_info(file: &mut File) -> EcCmdResult { let fd = file.as_raw_fd(); let versions = ec_cmd_get_cmd_versions(file, CrosEcCmd::FpInfo)?; if versions & V1 == 0 { diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs index 8a632ca..cafecff 100644 --- a/crosec/src/commands/fp_mode.rs +++ b/crosec/src/commands/fp_mode.rs @@ -9,7 +9,7 @@ use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; use super::CrosEcCmd; /// Note that with the ChromiumOS ectool, to start enrolling, as well as continue the next step in enrolling, you do `ectool --name=cros_fp fpmode enroll`. The equivalent of this is to do `ectool fp-mode EnrollImage EnrollSession`. -#[derive(EnumString, EnumIter, IntoStaticStr, Clone, Copy)] +#[derive(EnumString, EnumIter, IntoStaticStr, Clone, Copy, Debug)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[repr(u32)] pub enum FpMode { diff --git a/crosec/src/commands/fp_set_seed.rs b/crosec/src/commands/fp_set_seed.rs index 0bff0e2..fc35009 100644 --- a/crosec/src/commands/fp_set_seed.rs +++ b/crosec/src/commands/fp_set_seed.rs @@ -1,4 +1,4 @@ -use std::{fs::File, os::fd::AsRawFd}; +use std::os::fd::AsRawFd; use bytemuck::{Pod, Zeroable}; @@ -17,7 +17,7 @@ struct EcParamsFpSeed { pub seed: [u8; FP_CONTEXT_TPM_BYTES], } -pub fn fp_set_seed(file: &mut File, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { +pub fn fp_set_seed(file: &mut File, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::FpSetSeed, 0, diff --git a/crosec/src/commands/fp_upload_template.rs b/crosec/src/commands/fp_upload_template.rs index 0f293d2..2c6a90c 100644 --- a/crosec/src/commands/fp_upload_template.rs +++ b/crosec/src/commands/fp_upload_template.rs @@ -1,12 +1,12 @@ -use std::{fs::File, mem::offset_of, os::fd::AsRawFd}; +use std::{mem::offset_of, os::fd::AsRawFd}; use bytemuck::{bytes_of, Pod, Zeroable}; use crate::{ec_command::ec_command_with_dynamic_output_size, EcCmdResult}; use super::{ - fp_download::FpTemplate, fp_info::EcResponseFpInfo, - get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd, + CrosEcCmd, fp_download::FpTemplate, + fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo, }; #[derive(Pod, Zeroable, Clone, Copy)] @@ -20,7 +20,7 @@ struct EcParamsFpTemplateWithoutData { /// Flag in the 'size' field indicating that the full template has been sent const FP_TEMPLATE_COMMIT: u32 = 0x80000000; -pub fn fp_upload_template( +pub fn fp_upload_template( file: &mut File, protocol_info: &EcResponseGetProtocolInfo, fp_info: &EcResponseFpInfo, diff --git a/crosec/src/commands/get_cmd_versions.rs b/crosec/src/commands/get_cmd_versions.rs index ab0d84d..cca1cc4 100644 --- a/crosec/src/commands/get_cmd_versions.rs +++ b/crosec/src/commands/get_cmd_versions.rs @@ -1,4 +1,3 @@ -use std::fs::File; use std::os::fd::AsRawFd; use bytemuck::{Pod, Zeroable}; @@ -29,7 +28,7 @@ pub const V0: u32 = 0b001; pub const V1: u32 = 0b010; pub const V2: u32 = 0b100; -pub fn ec_cmd_get_cmd_versions(file: &mut File, cmd: CrosEcCmd) -> EcCmdResult { +pub fn ec_cmd_get_cmd_versions(file: &mut File, cmd: CrosEcCmd) -> EcCmdResult { let fd = file.as_raw_fd(); let response: EcResponseGetCmdVersion = match ec_command_bytemuck( CrosEcCmd::GetCmdVersions, diff --git a/crosec/src/commands/get_protocol_info.rs b/crosec/src/commands/get_protocol_info.rs index 69b0b25..66c6228 100644 --- a/crosec/src/commands/get_protocol_info.rs +++ b/crosec/src/commands/get_protocol_info.rs @@ -1,4 +1,4 @@ -use std::{fs::File, mem::size_of, os::fd::AsRawFd}; +use std::{mem::size_of, os::fd::AsRawFd}; use bytemuck::{Pod, Zeroable}; @@ -42,6 +42,6 @@ struct EcHostResponse { reserved: u16, } -pub fn get_protocol_info(file: &mut File) -> EcCmdResult { +pub fn get_protocol_info(file: &mut File) -> EcCmdResult { ec_command_bytemuck(CrosEcCmd::GetProtocolInfo, 0, &(), file.as_raw_fd()) } diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index e2b87f5..1a86ca6 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -22,6 +22,7 @@ pub enum CrosEcCmd { FpTemplate = 0x0405, FpStats = 0x0407, FpSetSeed = 0x0408, + FpGetEncryptionStatus = 0x0409, BatteryGetStatic = 0x0600, } @@ -29,6 +30,7 @@ pub mod board_version; pub mod charge_control; pub mod fp_download; pub mod fp_info; +pub mod fp_get_encryption_status; pub mod fp_mode; pub mod fp_set_seed; pub mod fp_stats; diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs index ad61e21..7d197ed 100644 --- a/crosec/src/wait_event/event.rs +++ b/crosec/src/wait_event/event.rs @@ -1,7 +1,6 @@ -use std::{ - io::{self, Read}, - mem::size_of, -}; +use std::io; +use std::mem::size_of; +use async_std::io::ReadExt; use bytemuck::{from_bytes, Pod, Zeroable}; use num_derive::FromPrimitive; @@ -50,6 +49,7 @@ pub enum EcMkbpEventType { OnlineCalibration, Pchg, } + impl EcMkbpEventType { fn data_size(&self) -> usize { match self { @@ -66,17 +66,27 @@ impl EcMkbpEventType { } } - pub(crate) fn read(&self, stream: &mut T) -> io::Result { - let mut event = vec![Default::default(); size_of::() + self.data_size()]; - stream.read_exact(&mut event)?; + fn parse_event(&self, event: &mut Vec) -> EcMkbpEvent { debug_assert_eq!(event[0], *self as u8); event.remove(0); let data = event; - Ok(match self { + match self { EcMkbpEventType::Fingerprint => { EcMkbpEvent::Fingerprint(from_bytes::(&data).to_owned()) } event_type => panic!("{event_type:#?} from_bytes not implemented yet"), - }) + } + } + + pub(crate) fn read_sync(&self, stream: &mut T) -> io::Result { + let mut event = vec![Default::default(); size_of::() + self.data_size()]; + stream.read_exact(&mut event)?; + Ok(self.parse_event(&mut event)) + } + + pub(crate) async fn read_async(&self, stream: &mut T) -> io::Result { + let mut event = vec![Default::default(); size_of::() + self.data_size()]; + stream.read_exact(&mut event).await?; + Ok(self.parse_event(&mut event)) } } diff --git a/crosec/src/wait_event/mod.rs b/crosec/src/wait_event/mod.rs index a195220..faca0f9 100644 --- a/crosec/src/wait_event/mod.rs +++ b/crosec/src/wait_event/mod.rs @@ -1,11 +1,13 @@ -use std::{fs::File, os::fd::AsRawFd}; +use std::io; +use std::os::fd::AsRawFd; -use event::{EcMkbpEvent, EcMkbpEventType}; use nix::{ libc::{ioctl, poll, pollfd}, request_code_none, }; +use event::{EcMkbpEvent, EcMkbpEventType}; + use crate::CROS_EC_IOC_MAGIC; pub mod event; @@ -21,7 +23,7 @@ pub enum PollData { } /// If no timeout is specified, this function will wait for an unlimited amount of time -pub fn wait_event( +pub fn wait_event_sync( file: &mut File, event_type: EcMkbpEventType, timeout: Option, @@ -45,12 +47,27 @@ pub fn wait_event( match result { 0 => Ok(PollData::Timeout), 1 => match fds.revents { - POLL_IN => Ok(PollData::EventHappened(event_type.read(file).unwrap())), + POLL_IN => Ok(PollData::EventHappened(event_type.read_sync(file).unwrap())), events => Ok(PollData::SomethingElseHappened(events)), }, result => Err(result), } } - None => Ok(PollData::EventHappened(event_type.read(file).unwrap())), + None => Ok(PollData::EventHappened(event_type.read_sync(file).unwrap())), } } + +pub async fn wait_event_async( + file: &mut File, + event_type: EcMkbpEventType, +) -> io::Result { + let mask = 1 << event_type as u8; + unsafe { + ioctl( + file.as_raw_fd(), + request_code_none!(CROS_EC_IOC_MAGIC, 2), + mask, + ) + }; + event_type.read_async(file).await +} \ No newline at end of file diff --git a/ectool/src/fp_get_encryption_status_command.rs b/ectool/src/fp_get_encryption_status_command.rs new file mode 100644 index 0000000..295f5ed --- /dev/null +++ b/ectool/src/fp_get_encryption_status_command.rs @@ -0,0 +1,11 @@ +use std::fs::File; +use crosec::commands::fp_get_encryption_status::{EcResponseFpGetEncryptionStatus, fp_get_encryption_status}; +use crosec::CROS_FP_PATH; + +pub fn fp_get_encryption_status_command() -> color_eyre::Result<()> { + let mut file = File::open(CROS_FP_PATH)?; + let EcResponseFpGetEncryptionStatus { status, valid_flags } = fp_get_encryption_status(&mut file)?; + println!("FPMCU encryption status: {status:#b}"); + println!("Valid flags: {valid_flags:#b}"); + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 8393bd0..b123a8d 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -9,7 +9,7 @@ use crosec::commands::fp_mode::{fp_mode, FpMode}; use crosec::commands::fp_set_seed::{fp_set_seed, FP_CONTEXT_TPM_BYTES}; use crosec::commands::fp_stats::fp_stats; use crosec::commands::get_protocol_info::get_protocol_info; -use crosec::wait_event::{event::EcMkbpEventType, wait_event}; +use crosec::wait_event::{event::EcMkbpEventType, wait_event_sync}; use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; use fp_upload_template_command::fp_upload_template_command; use num_traits::cast::FromPrimitive; @@ -29,11 +29,13 @@ use crosec::{ CROS_EC_PATH, CROS_FP_PATH, EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, }; +use crate::fp_get_encryption_status_command::fp_get_encryption_status_command; mod charge_control_subcommand; mod check_seed; mod fp_download_subcommand; mod fp_upload_template_command; +mod fp_get_encryption_status_command; #[derive(Parser)] #[command(version, about)] @@ -120,6 +122,7 @@ enum Commands { }, /// Uploads template from stdin FpUploadTemplate, + FpGetEncryptionStatus, } fn main() -> Result<()> { @@ -263,11 +266,12 @@ fn main() -> Result<()> { timeout, } => { let mut file = File::open(device.unwrap_or_default().get_path())?; - let result = wait_event(&mut file, event_type, timeout).unwrap(); + let result = wait_event_sync(&mut file, event_type, timeout).unwrap(); println!("{result:#?}"); } Commands::FpDownload { command } => fp_download_subcommand(command)?, Commands::FpUploadTemplate => fp_upload_template_command()?, + Commands::FpGetEncryptionStatus => fp_get_encryption_status_command()?, } Ok(()) From a8121a0c08d33ea1ce031ec826745329d91ec7ad Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 08:47:52 -0700 Subject: [PATCH 32/39] Add HostEvent enum Particularly, the InterfaceReady event is useful for knowing when the FPMCU was turned on. --- crosec/src/wait_event/event.rs | 14 ++++- crosec/src/wait_event/host_event.rs | 94 +++++++++++++++++++++++++++++ crosec/src/wait_event/mod.rs | 1 + ectool/src/main.rs | 5 +- 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 crosec/src/wait_event/host_event.rs diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs index 7d197ed..3708273 100644 --- a/crosec/src/wait_event/event.rs +++ b/crosec/src/wait_event/event.rs @@ -1,12 +1,14 @@ +use async_std::io::ReadExt; use std::io; use std::mem::size_of; -use async_std::io::ReadExt; use bytemuck::{from_bytes, Pod, Zeroable}; use num_derive::FromPrimitive; use crate::wait_event::fingerprint::EcMkbpEventFingerprint; +use super::host_event::EcMkbpEventHostEvent; + #[derive(Debug, Clone, Copy, Pod, Zeroable)] #[repr(C, packed)] pub struct EcResponseMotionSenseFifoInfo { @@ -21,7 +23,7 @@ pub struct EcResponseMotionSenseFifoInfo { #[repr(u8)] pub enum EcMkbpEvent { KeyMatrix([u8; 13]), - HostEvent(u32), + HostEvent(EcMkbpEventHostEvent), HostEvent64(u64), SensorFifo(EcResponseMotionSenseFifoInfo), Buttons(u32), @@ -74,6 +76,9 @@ impl EcMkbpEventType { EcMkbpEventType::Fingerprint => { EcMkbpEvent::Fingerprint(from_bytes::(&data).to_owned()) } + EcMkbpEventType::HostEvent => { + EcMkbpEvent::HostEvent(from_bytes::(&data).to_owned()) + } event_type => panic!("{event_type:#?} from_bytes not implemented yet"), } } @@ -84,7 +89,10 @@ impl EcMkbpEventType { Ok(self.parse_event(&mut event)) } - pub(crate) async fn read_async(&self, stream: &mut T) -> io::Result { + pub(crate) async fn read_async( + &self, + stream: &mut T, + ) -> io::Result { let mut event = vec![Default::default(); size_of::() + self.data_size()]; stream.read_exact(&mut event).await?; Ok(self.parse_event(&mut event)) diff --git a/crosec/src/wait_event/host_event.rs b/crosec/src/wait_event/host_event.rs new file mode 100644 index 0000000..051588e --- /dev/null +++ b/crosec/src/wait_event/host_event.rs @@ -0,0 +1,94 @@ +use std::fmt::Debug; + +use bytemuck::{Pod, Zeroable}; +use num::FromPrimitive; +use num_derive::FromPrimitive; +use strum_macros::IntoStaticStr; + +/// Host event codes. ACPI query EC command uses code 0 to mean "no event +/// pending". We explicitly specify each value in the enum listing so they won't +/// change if we delete/insert an item or rearrange the list (it needs to be +/// stable across platforms, not just within a single compiled instance). +#[repr(u32)] +#[derive(FromPrimitive, IntoStaticStr, Debug)] +pub enum HostEventCode { + None = 0, + LidClosed = 1 << 0, + LidOpen = 1 << 1, + PowerButton = 1 << 2, + AcConnected = 1 << 3, + AcDisconnected = 1 << 4, + BatteryLow = 1 << 5, + BatteryCritical = 1 << 6, + Battery = 1 << 7, + ThermalThreshold = 1 << 8, + /// Event generated by a device attached to the EC + Device = 1 << 9, + Thermal = 1 << 10, + /// GPU related event. Formerly named EC_HOST_EVENT_USB_CHARGER. + Gpu = 1 << 11, + KeyPressed = 1 << 12, + /// EC has finished initializing the host interface. The host can check + /// for this event following sending a EC_CMD_REBOOT_EC command to + /// determine when the EC is ready to accept subsequent commands. + InterfaceReady = 1 << 13, + /// Keyboard recovery combo has been pressed + KeyboardRecovery = 1 << 14, + /// Shutdown due to thermal overload + ThermalShutdown = 1 << 15, + /// Shutdown due to battery level too low + BatteryShutdown = 1 << 16, + /// Suggest that the AP throttle itself + ThrottleStart = 1 << 17, + /// Suggest that the AP resume normal speed + ThrottleStop = 1 << 18, + /// Hang detect logic detected a hang and host event timeout expired + HangDetect = 1 << 19, + /// Hang detect logic detected a hang and warm rebooted the AP + HangReboot = 1 << 20, + /// PD MCU triggering host event + PdMcu = 1 << 21, + /// Battery Status flags have changed + BatteryStatus = 1 << 22, + /// EC encountered a panic, triggering a reset + Panic = 1 << 23, + /// Keyboard fastboot combo has been pressed + KeyboardFastboot = 1 << 24, + /// EC RTC event occurred + Rtc = 1 << 25, + /// Emulate MKBP event + Mkbp = 1 << 26, + /// EC desires to change state of host-controlled USB mux + UsbMux = 1 << 27, + /// The device has changed "modes". This can be one of the following: + /// - TABLET/LAPTOP mode + /// - detachable base attach/detach event + ModeChange = 1 << 28, + /// Keyboard recovery combo with hardware reinitialization + KeyboardRecoveryHwReinit = 1 << 29, + /// WoV + Wov = 1 << 30, + /// The high bit of the event mask is not used as a host event code. If + /// it reads back as set, then the entire event mask should be considered + /// invalid by the host. This can happen when reading the raw event status + /// via EC_MEMMAP_HOST_EVENTS but the LPC interface is not initialized on + /// the EC, or improperly configured on the host. + Invalid = 1 << 31, +} + +#[derive(Pod, Zeroable, Clone, Copy)] +#[repr(C)] +pub struct EcMkbpEventHostEvent { + host_event: u32, +} +impl EcMkbpEventHostEvent { + /// Try getting the host event code enum. If it for some reason is something else, that's an error. + pub fn rust(self) -> Result { + HostEventCode::from_u32(self.host_event).ok_or(self.host_event) + } +} +impl Debug for EcMkbpEventHostEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.rust().fmt(f) + } +} diff --git a/crosec/src/wait_event/mod.rs b/crosec/src/wait_event/mod.rs index faca0f9..cf027d9 100644 --- a/crosec/src/wait_event/mod.rs +++ b/crosec/src/wait_event/mod.rs @@ -12,6 +12,7 @@ use crate::CROS_EC_IOC_MAGIC; pub mod event; pub mod fingerprint; +pub mod host_event; const POLL_IN: i16 = 0x001; diff --git a/ectool/src/main.rs b/ectool/src/main.rs index b123a8d..9615699 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -14,6 +14,7 @@ use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; use fp_upload_template_command::fp_upload_template_command; use num_traits::cast::FromPrimitive; +use crate::fp_get_encryption_status_command::fp_get_encryption_status_command; use crosec::battery::battery; use crosec::commands::board_version::ec_cmd_board_version; use crosec::commands::get_cmd_versions::ec_cmd_get_cmd_versions; @@ -29,13 +30,12 @@ use crosec::{ CROS_EC_PATH, CROS_FP_PATH, EC_FAN_SPEED_ENTRIES, EC_FAN_SPEED_NOT_PRESENT, EC_FAN_SPEED_STALLED, EC_MEM_MAP_FAN, }; -use crate::fp_get_encryption_status_command::fp_get_encryption_status_command; mod charge_control_subcommand; mod check_seed; mod fp_download_subcommand; -mod fp_upload_template_command; mod fp_get_encryption_status_command; +mod fp_upload_template_command; #[derive(Parser)] #[command(version, about)] @@ -266,6 +266,7 @@ fn main() -> Result<()> { timeout, } => { let mut file = File::open(device.unwrap_or_default().get_path())?; + println!("Waiting for event..."); let result = wait_event_sync(&mut file, event_type, timeout).unwrap(); println!("{result:#?}"); } From 980e60e868f2038028112c573f70120a68add2ad Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 08:49:14 -0700 Subject: [PATCH 33/39] No unused deps --- Cargo.lock | 1 - crosec/src/lib.rs | 2 ++ ectool/Cargo.toml | 1 - ectool/src/main.rs | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59d8e73..5d41b9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -549,7 +549,6 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" name = "ectool" version = "0.1.0" dependencies = [ - "bytemuck", "clap", "color-eyre", "crosec", diff --git a/crosec/src/lib.rs b/crosec/src/lib.rs index 4cf0ea6..35432f4 100644 --- a/crosec/src/lib.rs +++ b/crosec/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(unused_crate_dependencies)] + use nix::errno::Errno; use num_derive::FromPrimitive; use thiserror::Error; diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index 7dd242e..4089e54 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -11,5 +11,4 @@ crosec = { version = "0.1.0", path = "../crosec", features = ["clap"] } color-eyre = "0.6.2" clap = { version = "4.5.4", features = ["derive"] } num-traits = "0.2.19" -bytemuck = "1.16.0" image = "0.25.1" diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 9615699..fd18481 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -1,3 +1,5 @@ +#![warn(unused_crate_dependencies)] + use std::fs::File; use charge_control_subcommand::{charge_control_subcommand, ChargeControlSubcommand}; From 94f055f390d94df56ef9ea837b7e29a5101dff45 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:32:22 -0700 Subject: [PATCH 34/39] Get uptime info command --- crosec/src/commands/get_uptime_info.rs | 51 ++++++++++++++++++++++++++ crosec/src/commands/mod.rs | 4 +- ectool/src/get_uptime_info_command.rs | 12 ++++++ ectool/src/main.rs | 6 +++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 crosec/src/commands/get_uptime_info.rs create mode 100644 ectool/src/get_uptime_info_command.rs diff --git a/crosec/src/commands/get_uptime_info.rs b/crosec/src/commands/get_uptime_info.rs new file mode 100644 index 0000000..0f54fee --- /dev/null +++ b/crosec/src/commands/get_uptime_info.rs @@ -0,0 +1,51 @@ +use std::os::fd::AsRawFd; + +use bytemuck::{Pod, Zeroable}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::CrosEcCmd; + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] +pub struct EcResponseUptimeInfo { + /// Number of milliseconds since the last EC boot. Sysjump resets + /// typically do not restart the EC's time_since_boot epoch. + /// + /// WARNING: The EC's sense of time is much less accurate than the AP's + /// sense of time, in both phase and frequency. This timebase is similar + /// to CLOCK_MONOTONIC_RAW, but with 1% or more frequency error. + pub time_since_ec_boot_ms: u32, + + /// Number of times the AP was reset by the EC since the last EC boot. + /// Note that the AP may be held in reset by the EC during the initial + /// boot sequence, such that the very first AP boot may count as more + /// than one here. + pub ap_resets_since_ec_boot: u32, + + /// The set of flags which describe the EC's most recent reset. + /// See EC_RESET_FLAG_* for details. + pub ec_reset_flags: u32, + + /// Empty log entries have both the cause and timestamp set to zero. + pub recent_ap_reset: [ApResetLogEntry; 4], +} + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy, Debug)] +pub struct ApResetLogEntry { + /// See enum chipset_{reset,shutdown}_reason for details. + pub reset_cause: u16, + + /// Reserved for protocol growth. + pub reserved: u16, + + /// The time of the reset's assertion, in milliseconds since the + /// last EC boot, in the same epoch as time_since_ec_boot_ms. + /// Set to zero if the log entry is empty. + pub reset_time_ms: u32, +} + +pub fn ec_cmd_get_uptime_info(file: &mut File) -> EcCmdResult { + ec_command_bytemuck(CrosEcCmd::GetUptimeInfo, 0, &(), file.as_raw_fd()) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 1a86ca6..5bde990 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -16,6 +16,7 @@ pub enum CrosEcCmd { ChargeControl = 0x0096, ConsoleSnapshot = 0x0097, ConsoleRead = 0x0098, + GetUptimeInfo = 0x0121, FpMode = 0x0402, FpInfo = 0x0403, FpFrame = 0x0404, @@ -29,8 +30,8 @@ pub enum CrosEcCmd { pub mod board_version; pub mod charge_control; pub mod fp_download; -pub mod fp_info; pub mod fp_get_encryption_status; +pub mod fp_info; pub mod fp_mode; pub mod fp_set_seed; pub mod fp_stats; @@ -39,6 +40,7 @@ pub mod get_chip_info; pub mod get_cmd_versions; pub mod get_features; pub mod get_protocol_info; +pub mod get_uptime_info; pub mod hello; pub mod read_mem; pub mod set_fan_target_rpm; diff --git a/ectool/src/get_uptime_info_command.rs b/ectool/src/get_uptime_info_command.rs new file mode 100644 index 0000000..82a588c --- /dev/null +++ b/ectool/src/get_uptime_info_command.rs @@ -0,0 +1,12 @@ +use std::fs::File; + +use crosec::commands::get_uptime_info::ec_cmd_get_uptime_info; + +use crate::Device; + +pub fn get_uptime_info_commnad(device: Option) -> color_eyre::Result<()> { + let mut file = File::open(device.unwrap_or_default().get_path())?; + let uptime_info = ec_cmd_get_uptime_info(&mut file)?; + println!("Uptime info: {uptime_info:#?}"); + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index fd18481..31978ef 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -14,6 +14,7 @@ use crosec::commands::get_protocol_info::get_protocol_info; use crosec::wait_event::{event::EcMkbpEventType, wait_event_sync}; use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; use fp_upload_template_command::fp_upload_template_command; +use get_uptime_info_command::get_uptime_info_commnad; use num_traits::cast::FromPrimitive; use crate::fp_get_encryption_status_command::fp_get_encryption_status_command; @@ -38,6 +39,7 @@ mod check_seed; mod fp_download_subcommand; mod fp_get_encryption_status_command; mod fp_upload_template_command; +mod get_uptime_info_command; #[derive(Parser)] #[command(version, about)] @@ -125,6 +127,9 @@ enum Commands { /// Uploads template from stdin FpUploadTemplate, FpGetEncryptionStatus, + GetUptimeInfo { + device: Option, + }, } fn main() -> Result<()> { @@ -275,6 +280,7 @@ fn main() -> Result<()> { Commands::FpDownload { command } => fp_download_subcommand(command)?, Commands::FpUploadTemplate => fp_upload_template_command()?, Commands::FpGetEncryptionStatus => fp_get_encryption_status_command()?, + Commands::GetUptimeInfo { device } => get_uptime_info_commnad(device)?, } Ok(()) From 1c8d72892246d4cce0b031e0b596f2e08edf98b6 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:21:51 -0700 Subject: [PATCH 35/39] Multiple event types when waiting for event --- Cargo.lock | 5 +-- crosec/src/wait_event/event.rs | 58 +++++++++++++++++++++------------- crosec/src/wait_event/mod.rs | 41 ++++++++++++++++-------- ectool/Cargo.toml | 1 + ectool/src/main.rs | 11 +++++-- 5 files changed, 75 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d41b9b..0d20f3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -554,6 +554,7 @@ dependencies = [ "crosec", "image", "num-traits", + "strum", ] [[package]] @@ -1561,9 +1562,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "strum_macros" diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs index 3708273..7c2ecd2 100644 --- a/crosec/src/wait_event/event.rs +++ b/crosec/src/wait_event/event.rs @@ -1,6 +1,9 @@ use async_std::io::ReadExt; +use num::FromPrimitive; use std::io; use std::mem::size_of; +use strum::IntoEnumIterator; +use strum_macros::EnumIter; use bytemuck::{from_bytes, Pod, Zeroable}; use num_derive::FromPrimitive; @@ -32,8 +35,37 @@ pub enum EcMkbpEvent { Sysrq(u32), CecEvent(u32), } +impl EcMkbpEvent { + fn max_event_size() -> usize { + EcMkbpEventType::iter() + .map(|e| e.data_size()) + .max() + .unwrap_or_default() + } + + fn from_bytes(bytes: &[u8]) -> Self { + let event_type = EcMkbpEventType::from_u8(bytes[0]).unwrap(); + event_type.event_from_bytes(&mut bytes[1..1 + event_type.data_size()].to_vec()) + } + + pub(crate) fn read_sync(stream: &mut T) -> io::Result { + let mut buf: Vec = + vec![Default::default(); size_of::() + Self::max_event_size()]; + stream.read(&mut buf)?; + Ok(Self::from_bytes(&buf)) + } + + pub(crate) async fn read_async( + stream: &mut T, + ) -> io::Result { + let mut buf: Vec = + vec![Default::default(); size_of::() + Self::max_event_size()]; + stream.read(&mut buf).await?; + Ok(Self::from_bytes(&buf)) + } +} -#[derive(Debug, FromPrimitive, Clone, Copy)] +#[derive(Debug, FromPrimitive, Clone, Copy, EnumIter, PartialEq)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[repr(u8)] pub enum EcMkbpEventType { @@ -68,33 +100,15 @@ impl EcMkbpEventType { } } - fn parse_event(&self, event: &mut Vec) -> EcMkbpEvent { - debug_assert_eq!(event[0], *self as u8); - event.remove(0); - let data = event; + fn event_from_bytes(&self, event: &[u8]) -> EcMkbpEvent { match self { EcMkbpEventType::Fingerprint => { - EcMkbpEvent::Fingerprint(from_bytes::(&data).to_owned()) + EcMkbpEvent::Fingerprint(from_bytes::(&event).to_owned()) } EcMkbpEventType::HostEvent => { - EcMkbpEvent::HostEvent(from_bytes::(&data).to_owned()) + EcMkbpEvent::HostEvent(from_bytes::(&event).to_owned()) } event_type => panic!("{event_type:#?} from_bytes not implemented yet"), } } - - pub(crate) fn read_sync(&self, stream: &mut T) -> io::Result { - let mut event = vec![Default::default(); size_of::() + self.data_size()]; - stream.read_exact(&mut event)?; - Ok(self.parse_event(&mut event)) - } - - pub(crate) async fn read_async( - &self, - stream: &mut T, - ) -> io::Result { - let mut event = vec![Default::default(); size_of::() + self.data_size()]; - stream.read_exact(&mut event).await?; - Ok(self.parse_event(&mut event)) - } } diff --git a/crosec/src/wait_event/mod.rs b/crosec/src/wait_event/mod.rs index cf027d9..4d858cd 100644 --- a/crosec/src/wait_event/mod.rs +++ b/crosec/src/wait_event/mod.rs @@ -1,5 +1,4 @@ -use std::io; -use std::os::fd::AsRawFd; +use std::{io, os::fd::AsRawFd}; use nix::{ libc::{ioctl, poll, pollfd}, @@ -23,18 +22,26 @@ pub enum PollData { SomethingElseHappened(i16), } +fn get_mask>(event_types: I) -> i32 { + let mut mask = i32::default(); + for event_type in event_types { + mask |= 1 << event_type as u8; + } + assert_ne!(mask, 0, "Must specify at least one event type"); + mask +} + /// If no timeout is specified, this function will wait for an unlimited amount of time -pub fn wait_event_sync( +pub fn wait_event_sync>( file: &mut File, - event_type: EcMkbpEventType, + event_types: I, timeout: Option, ) -> Result { - let mask = 1 << event_type as u8; unsafe { ioctl( file.as_raw_fd(), request_code_none!(CROS_EC_IOC_MAGIC, 2), - mask, + get_mask(event_types), ) }; match timeout { @@ -48,27 +55,33 @@ pub fn wait_event_sync( match result { 0 => Ok(PollData::Timeout), 1 => match fds.revents { - POLL_IN => Ok(PollData::EventHappened(event_type.read_sync(file).unwrap())), + POLL_IN => Ok(PollData::EventHappened( + EcMkbpEvent::read_sync(file).unwrap(), + )), events => Ok(PollData::SomethingElseHappened(events)), }, result => Err(result), } } - None => Ok(PollData::EventHappened(event_type.read_sync(file).unwrap())), + None => Ok(PollData::EventHappened( + EcMkbpEvent::read_sync(file).unwrap(), + )), } } -pub async fn wait_event_async( +pub async fn wait_event_async< + File: AsRawFd + async_std::io::Read + Unpin, + I: IntoIterator, +>( file: &mut File, - event_type: EcMkbpEventType, + event_types: I, ) -> io::Result { - let mask = 1 << event_type as u8; unsafe { ioctl( file.as_raw_fd(), request_code_none!(CROS_EC_IOC_MAGIC, 2), - mask, + get_mask(event_types), ) }; - event_type.read_async(file).await -} \ No newline at end of file + EcMkbpEvent::read_async(file).await +} diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index 4089e54..9c2f404 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -12,3 +12,4 @@ color-eyre = "0.6.2" clap = { version = "4.5.4", features = ["derive"] } num-traits = "0.2.19" image = "0.25.1" +strum = "0.26.3" diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 31978ef..c55c831 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -16,6 +16,7 @@ use fp_download_subcommand::{fp_download_subcommand, FpDownloadSubcommand}; use fp_upload_template_command::fp_upload_template_command; use get_uptime_info_command::get_uptime_info_commnad; use num_traits::cast::FromPrimitive; +use strum::IntoEnumIterator; use crate::fp_get_encryption_status_command::fp_get_encryption_status_command; use crosec::battery::battery; @@ -114,8 +115,9 @@ enum Commands { mode: Vec, }, WaitEvent { - event_type: EcMkbpEventType, + event_types: Vec, /// Timeout in milliseconds + #[arg(short, long)] timeout: Option, #[arg(short, long)] device: Option, @@ -268,13 +270,16 @@ fn main() -> Result<()> { println!("FP mode: {display}"); } Commands::WaitEvent { - event_type, + mut event_types, device, timeout, } => { + if event_types.len() == 0 { + event_types = EcMkbpEventType::iter().collect(); + } let mut file = File::open(device.unwrap_or_default().get_path())?; println!("Waiting for event..."); - let result = wait_event_sync(&mut file, event_type, timeout).unwrap(); + let result = wait_event_sync(&mut file, event_types, timeout).unwrap(); println!("{result:#?}"); } Commands::FpDownload { command } => fp_download_subcommand(command)?, From 05120f154616281c24c6d4280f5299eaaa431fec Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:26:19 -0700 Subject: [PATCH 36/39] cargo fmt --- crosec/src/commands/fp_download.rs | 2 +- crosec/src/commands/fp_get_encryption_status.rs | 12 +++++++----- crosec/src/commands/fp_info.rs | 2 +- crosec/src/commands/fp_set_seed.rs | 5 ++++- crosec/src/commands/fp_upload_template.rs | 4 ++-- ectool/src/fp_get_encryption_status_command.rs | 11 ++++++++--- 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/crosec/src/commands/fp_download.rs b/crosec/src/commands/fp_download.rs index bdd47d3..486711d 100644 --- a/crosec/src/commands/fp_download.rs +++ b/crosec/src/commands/fp_download.rs @@ -4,7 +4,7 @@ use bytemuck::{bytes_of, Pod, Zeroable}; use crate::ec_command::ec_command_with_dynamic_output_size; -use super::{CrosEcCmd, fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo}; +use super::{fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd}; #[repr(C)] #[derive(Pod, Zeroable, Clone, Copy)] diff --git a/crosec/src/commands/fp_get_encryption_status.rs b/crosec/src/commands/fp_get_encryption_status.rs index 47ac684..ee57681 100644 --- a/crosec/src/commands/fp_get_encryption_status.rs +++ b/crosec/src/commands/fp_get_encryption_status.rs @@ -1,12 +1,12 @@ -use std::os::fd::AsRawFd; -use bytemuck::{Pod, Zeroable}; use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; +use bytemuck::{Pod, Zeroable}; +use std::os::fd::AsRawFd; #[repr(u32)] pub enum FpEncryptionStatus { - SeedSet = 0b1 + SeedSet = 0b1, } #[derive(Pod, Zeroable, Copy, Clone)] @@ -16,6 +16,8 @@ pub struct EcResponseFpGetEncryptionStatus { pub status: u32, } -pub fn fp_get_encryption_status(file: &mut File) -> EcCmdResult { +pub fn fp_get_encryption_status( + file: &mut File, +) -> EcCmdResult { ec_command_bytemuck(CrosEcCmd::FpGetEncryptionStatus, 0, &(), file.as_raw_fd()) -} \ No newline at end of file +} diff --git a/crosec/src/commands/fp_info.rs b/crosec/src/commands/fp_info.rs index 4a49c44..14cd7a2 100644 --- a/crosec/src/commands/fp_info.rs +++ b/crosec/src/commands/fp_info.rs @@ -5,8 +5,8 @@ use bytemuck::{Pod, Zeroable}; use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; use super::{ - CrosEcCmd, get_cmd_versions::{ec_cmd_get_cmd_versions, V1}, + CrosEcCmd, }; #[repr(C, align(4))] diff --git a/crosec/src/commands/fp_set_seed.rs b/crosec/src/commands/fp_set_seed.rs index fc35009..b582807 100644 --- a/crosec/src/commands/fp_set_seed.rs +++ b/crosec/src/commands/fp_set_seed.rs @@ -17,7 +17,10 @@ struct EcParamsFpSeed { pub seed: [u8; FP_CONTEXT_TPM_BYTES], } -pub fn fp_set_seed(file: &mut File, seed: [u8; FP_CONTEXT_TPM_BYTES]) -> EcCmdResult<()> { +pub fn fp_set_seed( + file: &mut File, + seed: [u8; FP_CONTEXT_TPM_BYTES], +) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::FpSetSeed, 0, diff --git a/crosec/src/commands/fp_upload_template.rs b/crosec/src/commands/fp_upload_template.rs index 2c6a90c..679ce4e 100644 --- a/crosec/src/commands/fp_upload_template.rs +++ b/crosec/src/commands/fp_upload_template.rs @@ -5,8 +5,8 @@ use bytemuck::{bytes_of, Pod, Zeroable}; use crate::{ec_command::ec_command_with_dynamic_output_size, EcCmdResult}; use super::{ - CrosEcCmd, fp_download::FpTemplate, - fp_info::EcResponseFpInfo, get_protocol_info::EcResponseGetProtocolInfo, + fp_download::FpTemplate, fp_info::EcResponseFpInfo, + get_protocol_info::EcResponseGetProtocolInfo, CrosEcCmd, }; #[derive(Pod, Zeroable, Clone, Copy)] diff --git a/ectool/src/fp_get_encryption_status_command.rs b/ectool/src/fp_get_encryption_status_command.rs index 295f5ed..fc7bfe7 100644 --- a/ectool/src/fp_get_encryption_status_command.rs +++ b/ectool/src/fp_get_encryption_status_command.rs @@ -1,10 +1,15 @@ -use std::fs::File; -use crosec::commands::fp_get_encryption_status::{EcResponseFpGetEncryptionStatus, fp_get_encryption_status}; +use crosec::commands::fp_get_encryption_status::{ + fp_get_encryption_status, EcResponseFpGetEncryptionStatus, +}; use crosec::CROS_FP_PATH; +use std::fs::File; pub fn fp_get_encryption_status_command() -> color_eyre::Result<()> { let mut file = File::open(CROS_FP_PATH)?; - let EcResponseFpGetEncryptionStatus { status, valid_flags } = fp_get_encryption_status(&mut file)?; + let EcResponseFpGetEncryptionStatus { + status, + valid_flags, + } = fp_get_encryption_status(&mut file)?; println!("FPMCU encryption status: {status:#b}"); println!("Valid flags: {valid_flags:#b}"); Ok(()) From c64772c5d5c3ead1fb05910187f1f6ab4f27514b Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:04:31 -0700 Subject: [PATCH 37/39] Meet cargo clippy rules --- crosec/src/commands/fp_download.rs | 8 +++--- crosec/src/commands/fp_mode.rs | 4 +-- crosec/src/commands/set_fan_target_rpm.rs | 32 ++++++++++++----------- crosec/src/console.rs | 2 +- crosec/src/ec_command.rs | 2 +- crosec/src/get_number_of_fans.rs | 4 +-- crosec/src/wait_event/event.rs | 12 ++++----- ectool/src/main.rs | 8 +++--- 8 files changed, 38 insertions(+), 34 deletions(-) diff --git a/crosec/src/commands/fp_download.rs b/crosec/src/commands/fp_download.rs index 486711d..edcf721 100644 --- a/crosec/src/commands/fp_download.rs +++ b/crosec/src/commands/fp_download.rs @@ -84,9 +84,9 @@ pub struct FpTemplate { vec: Vec, } -impl Into> for FpTemplate { - fn into(self) -> Vec { - self.vec +impl From for Vec { + fn from(value: FpTemplate) -> Self { + value.vec } } @@ -96,6 +96,8 @@ impl FpTemplate { } /// Make sure your buffer is actually a compatible fp template + /// # Safety + /// Make sure you're uploading a template from the same FPMCU with the same version and the same seed set. pub unsafe fn from_vec_unchecked(vec: Vec) -> Self { FpTemplate { vec } } diff --git a/crosec/src/commands/fp_mode.rs b/crosec/src/commands/fp_mode.rs index cafecff..a0c1a5c 100644 --- a/crosec/src/commands/fp_mode.rs +++ b/crosec/src/commands/fp_mode.rs @@ -31,8 +31,8 @@ impl FpMode { let flags = match fp_mode { 0 => >::into(Self::Reset).to_owned(), fp_mode => Self::iter() - .filter(|flag| fp_mode as u32 & *flag as u32 != 0) - .map(|flag| >::into(flag)) + .filter(|flag| fp_mode & *flag as u32 != 0) + .map(>::into) .collect::>() .join(", "), }; diff --git a/crosec/src/commands/set_fan_target_rpm.rs b/crosec/src/commands/set_fan_target_rpm.rs index 2710cfe..d145371 100644 --- a/crosec/src/commands/set_fan_target_rpm.rs +++ b/crosec/src/commands/set_fan_target_rpm.rs @@ -1,8 +1,7 @@ use std::fs::File; -use std::mem::size_of; use std::os::fd::AsRawFd; -use bytemuck::{Pod, Zeroable}; +use bytemuck::{NoUninit, Pod, Zeroable}; use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; @@ -14,22 +13,25 @@ struct EcParamsSetFanTargetRpmV0 { rpm: u32, } +#[derive(Clone, Copy, NoUninit)] +#[repr(C, align(1))] struct EcParamsSetFanTargetRpmV1 { rpm: u32, fan_index: u8, + _padding: [u8; 3], } -impl EcParamsSetFanTargetRpmV1 { - pub fn to_le_bytes(self) -> [u8; size_of::() + size_of::()] { - [ - self.rpm.to_le_bytes().to_vec(), - self.fan_index.to_le_bytes().to_vec(), - ] - .concat() - .try_into() - .unwrap() - } -} +// impl EcParamsSetFanTargetRpmV1 { +// pub fn to_le_bytes(self) -> [u8; size_of::() + size_of::()] { +// [ +// self.rpm.to_le_bytes().to_vec(), +// self.fan_index.to_le_bytes().to_vec(), +// ] +// .concat() +// .try_into() +// .unwrap() +// } +// } pub fn ec_cmd_set_fan_target_rpm( file: &mut File, @@ -46,8 +48,8 @@ pub fn ec_cmd_set_fan_target_rpm( &EcParamsSetFanTargetRpmV1 { rpm, fan_index: index, - } - .to_le_bytes(), + _padding: Default::default(), + }, file.as_raw_fd(), )?; } diff --git a/crosec/src/console.rs b/crosec/src/console.rs index 79f371b..d681747 100644 --- a/crosec/src/console.rs +++ b/crosec/src/console.rs @@ -21,7 +21,7 @@ pub fn console(file: &mut File, protocol_info: &EcResponseGetProtocolInfo) -> Ec // Get rid of trailing null characters let chunk = chunk.trim_end_matches('\0'); if !chunk.is_empty() { - console += &chunk; + console += chunk; } else { break; } diff --git a/crosec/src/ec_command.rs b/crosec/src/ec_command.rs index bcfdf7d..b5f303a 100644 --- a/crosec/src/ec_command.rs +++ b/crosec/src/ec_command.rs @@ -46,7 +46,7 @@ pub fn ec_command_with_dynamic_output_size( buffer }); let result = unsafe { cros_ec_cmd(fd, cmd_vec.as_mut_ptr() as *mut _ as *mut CrosEcCommandV2) }; - let _output_size = result.map_err(|err| EcError::DeviceError(err))?; + let _output_size = result.map_err(EcError::DeviceError)?; let cmd_without_data = bytemuck::from_bytes::(&cmd_vec[..size_of::()]); let status = FromPrimitive::from_u32(cmd_without_data.result) diff --git a/crosec/src/get_number_of_fans.rs b/crosec/src/get_number_of_fans.rs index 949cd80..13b0228 100644 --- a/crosec/src/get_number_of_fans.rs +++ b/crosec/src/get_number_of_fans.rs @@ -27,10 +27,10 @@ impl Display for Error { } pub fn get_number_of_fans(file: &mut File) -> Result { - let features = ec_cmd_get_features(file).map_err(|e| Error::GetFeatures(e))?; + let features = ec_cmd_get_features(file).map_err(Error::GetFeatures)?; let number_of_fans = if features & EC_FEATURE_PWM_FAN != 0 { read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(file, EC_MEM_MAP_FAN) - .map_err(|e| Error::ReadMem(e))? + .map_err(Error::ReadMem)? .into_iter() .filter(|data| *data != EC_FAN_SPEED_NOT_PRESENT) .count() diff --git a/crosec/src/wait_event/event.rs b/crosec/src/wait_event/event.rs index 7c2ecd2..acdd3c5 100644 --- a/crosec/src/wait_event/event.rs +++ b/crosec/src/wait_event/event.rs @@ -45,14 +45,14 @@ impl EcMkbpEvent { fn from_bytes(bytes: &[u8]) -> Self { let event_type = EcMkbpEventType::from_u8(bytes[0]).unwrap(); - event_type.event_from_bytes(&mut bytes[1..1 + event_type.data_size()].to_vec()) + event_type.event_from_bytes(bytes[1..1 + event_type.data_size()].to_vec()) } pub(crate) fn read_sync(stream: &mut T) -> io::Result { let mut buf: Vec = vec![Default::default(); size_of::() + Self::max_event_size()]; - stream.read(&mut buf)?; - Ok(Self::from_bytes(&buf)) + let bytes_read = stream.read(&mut buf)?; + Ok(Self::from_bytes(&buf[..bytes_read])) } pub(crate) async fn read_async( @@ -60,8 +60,8 @@ impl EcMkbpEvent { ) -> io::Result { let mut buf: Vec = vec![Default::default(); size_of::() + Self::max_event_size()]; - stream.read(&mut buf).await?; - Ok(Self::from_bytes(&buf)) + let bytes_read = stream.read(&mut buf).await?; + Ok(Self::from_bytes(&buf[..bytes_read])) } } @@ -100,7 +100,7 @@ impl EcMkbpEventType { } } - fn event_from_bytes(&self, event: &[u8]) -> EcMkbpEvent { + fn event_from_bytes(&self, event: Vec) -> EcMkbpEvent { match self { EcMkbpEventType::Fingerprint => { EcMkbpEvent::Fingerprint(from_bytes::(&event).to_owned()) diff --git a/ectool/src/main.rs b/ectool/src/main.rs index c55c831..345bc01 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -207,10 +207,10 @@ fn main() -> Result<()> { } Commands::GetFanRpm => { let mut file = File::open(CROS_EC_PATH)?; - let features = ec_cmd_get_features(&mut file).map_err(|e| Error::GetFeatures(e))?; + let features = ec_cmd_get_features(&mut file).map_err(Error::GetFeatures)?; if features & EC_FEATURE_PWM_FAN != 0 { read_mem_any::<[u16; EC_FAN_SPEED_ENTRIES]>(&mut file, EC_MEM_MAP_FAN) - .map_err(|e| Error::ReadMem(e))? + .map_err(Error::ReadMem)? .into_iter() .enumerate() .for_each(|(i, fan)| match fan { @@ -255,7 +255,7 @@ fn main() -> Result<()> { println!("Set fp seed"); } Commands::FpMode { mode } => { - let mode = if mode.len() > 0 { + let mode = if !mode.is_empty() { let mut mode_number: u32 = 0; for mode in mode { mode_number |= mode as u32; @@ -274,7 +274,7 @@ fn main() -> Result<()> { device, timeout, } => { - if event_types.len() == 0 { + if event_types.is_empty() { event_types = EcMkbpEventType::iter().collect(); } let mut file = File::open(device.unwrap_or_default().get_path())?; From e49755995915d44efeb08ee6c25cead34be9edf4 Mon Sep 17 00:00:00 2001 From: Rajas Paranjpe <52586855+ChocolateLoverRaj@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:10:30 -0700 Subject: [PATCH 38/39] Charge current limit command --- Cargo.lock | 18 ++++++++++++ crosec/Cargo.toml | 1 + crosec/src/commands/charge_control.rs | 10 ++++--- crosec/src/commands/charge_current_limit.rs | 29 +++++++++++++++++++ crosec/src/commands/mod.rs | 2 ++ ectool/Cargo.toml | 1 + ectool/src/charge_current_limit_subcommand.rs | 11 +++++++ ectool/src/main.rs | 8 +++++ 8 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 crosec/src/commands/charge_current_limit.rs create mode 100644 ectool/src/charge_current_limit_subcommand.rs diff --git a/Cargo.lock b/Cargo.lock index 0d20f3d..0eafdfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,6 +512,7 @@ dependencies = [ "strum", "strum_macros", "thiserror", + "uom", ] [[package]] @@ -555,6 +556,7 @@ dependencies = [ "image", "num-traits", "strum", + "uom", ] [[package]] @@ -1725,12 +1727,28 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "uom" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd36e5350a65d112584053ee91843955826bf9e56ec0d1351214e01f6d7cd9c" +dependencies = [ + "num-traits", + "typenum", +] + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/crosec/Cargo.toml b/crosec/Cargo.toml index 7942f73..02cd582 100644 --- a/crosec/Cargo.toml +++ b/crosec/Cargo.toml @@ -16,6 +16,7 @@ num-traits = "0.2.18" strum = "0.26.2" strum_macros = "0.26.4" thiserror = "1.0.57" +uom = "0.36.0" [features] clap = ["dep:clap"] diff --git a/crosec/src/commands/charge_control.rs b/crosec/src/commands/charge_control.rs index 050dd88..73ff4ba 100644 --- a/crosec/src/commands/charge_control.rs +++ b/crosec/src/commands/charge_control.rs @@ -3,7 +3,6 @@ use crate::commands::CrosEcCmd; use crate::ec_command::ec_command_bytemuck; use crate::EcCmdResult; use bytemuck::{Pod, Zeroable}; -use std::fs::File; use std::os::fd::AsRawFd; #[repr(C)] @@ -20,7 +19,7 @@ pub enum ChargeControl { Discharge, } -pub fn supports_get_and_sustainer(file: &mut File) -> EcCmdResult { +pub fn supports_get_and_sustainer(file: &mut File) -> EcCmdResult { let versions = ec_cmd_get_cmd_versions(file, CrosEcCmd::ChargeControl)?; Ok(versions & V2 != 0) } @@ -41,11 +40,14 @@ const CHARGE_CONTROL_COMMAND_NORMAL: u32 = 0; const CHARGE_CONTROL_COMMAND_IDLE: u32 = 1; const CHARGE_CONTROL_COMMAND_DISCHARGE: u32 = 2; -pub fn get_charge_control(_file: &mut File) -> EcCmdResult { +pub fn get_charge_control(_file: &mut File) -> EcCmdResult { panic!("Not implemented yet"); } -pub fn set_charge_control(file: &mut File, charge_control: ChargeControl) -> EcCmdResult<()> { +pub fn set_charge_control( + file: &mut File, + charge_control: ChargeControl, +) -> EcCmdResult<()> { ec_command_bytemuck( CrosEcCmd::ChargeControl, { diff --git a/crosec/src/commands/charge_current_limit.rs b/crosec/src/commands/charge_current_limit.rs new file mode 100644 index 0000000..e86f6cb --- /dev/null +++ b/crosec/src/commands/charge_current_limit.rs @@ -0,0 +1,29 @@ +use std::os::fd::AsRawFd; + +use bytemuck::{Pod, Zeroable}; +use uom::si::{electric_current::milliampere, f32::ElectricCurrent}; + +use crate::{ec_command::ec_command_bytemuck, EcCmdResult}; + +use super::CrosEcCmd; + +#[repr(C)] +#[derive(Pod, Zeroable, Copy, Clone)] +pub struct EcParamsChargeCurrentLimit { + limit: u32, // in mA +} + +/// Limit the charging current. The EC command sends the charging current limit to the nearest mA. +pub fn set_charge_current_limit( + file: &mut File, + limit: ElectricCurrent, +) -> EcCmdResult<()> { + ec_command_bytemuck( + CrosEcCmd::ChargeCurrentLimit, + 0, + &EcParamsChargeCurrentLimit { + limit: limit.get::() as u32, + }, + file.as_raw_fd(), + ) +} diff --git a/crosec/src/commands/mod.rs b/crosec/src/commands/mod.rs index 5bde990..8154e73 100644 --- a/crosec/src/commands/mod.rs +++ b/crosec/src/commands/mod.rs @@ -25,10 +25,12 @@ pub enum CrosEcCmd { FpSetSeed = 0x0408, FpGetEncryptionStatus = 0x0409, BatteryGetStatic = 0x0600, + ChargeCurrentLimit = 0x00A1, } pub mod board_version; pub mod charge_control; +pub mod charge_current_limit; pub mod fp_download; pub mod fp_get_encryption_status; pub mod fp_info; diff --git a/ectool/Cargo.toml b/ectool/Cargo.toml index 9c2f404..3604e14 100644 --- a/ectool/Cargo.toml +++ b/ectool/Cargo.toml @@ -13,3 +13,4 @@ clap = { version = "4.5.4", features = ["derive"] } num-traits = "0.2.19" image = "0.25.1" strum = "0.26.3" +uom = "0.36.0" diff --git a/ectool/src/charge_current_limit_subcommand.rs b/ectool/src/charge_current_limit_subcommand.rs new file mode 100644 index 0000000..22ead40 --- /dev/null +++ b/ectool/src/charge_current_limit_subcommand.rs @@ -0,0 +1,11 @@ +use std::fs::File; + +use color_eyre::eyre::Result; +use crosec::{commands::charge_current_limit::set_charge_current_limit, CROS_EC_PATH}; +use uom::si::electric_current::{milliampere, ElectricCurrent}; + +pub fn charge_current_limit_subcommand(limit: u32) -> Result<()> { + let mut file = File::open(CROS_EC_PATH)?; + set_charge_current_limit(&mut file, ElectricCurrent::new::(limit.into()))?; + Ok(()) +} diff --git a/ectool/src/main.rs b/ectool/src/main.rs index 345bc01..950c6c4 100644 --- a/ectool/src/main.rs +++ b/ectool/src/main.rs @@ -3,6 +3,7 @@ use std::fs::File; use charge_control_subcommand::{charge_control_subcommand, ChargeControlSubcommand}; +use charge_current_limit_subcommand::charge_current_limit_subcommand; use check_seed::check_seed; use clap::{Parser, Subcommand, ValueEnum}; use color_eyre::eyre::Result; @@ -36,6 +37,7 @@ use crosec::{ }; mod charge_control_subcommand; +mod charge_current_limit_subcommand; mod check_seed; mod fp_download_subcommand; mod fp_get_encryption_status_command; @@ -132,6 +134,11 @@ enum Commands { GetUptimeInfo { device: Option, }, + ChargeCurrentLimit { + /// Limit in mA + #[arg()] + limit: u32, + }, } fn main() -> Result<()> { @@ -286,6 +293,7 @@ fn main() -> Result<()> { Commands::FpUploadTemplate => fp_upload_template_command()?, Commands::FpGetEncryptionStatus => fp_get_encryption_status_command()?, Commands::GetUptimeInfo { device } => get_uptime_info_commnad(device)?, + Commands::ChargeCurrentLimit { limit } => charge_current_limit_subcommand(limit)?, } Ok(()) From 10417b139af20bfa48700ff47e203692d73dff7c Mon Sep 17 00:00:00 2001 From: Lleyton Gray Date: Sun, 27 Oct 2024 19:10:44 -0700 Subject: [PATCH 39/39] fix: use lossy conversion --- ectool/src/charge_current_limit_subcommand.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ectool/src/charge_current_limit_subcommand.rs b/ectool/src/charge_current_limit_subcommand.rs index 22ead40..7fdcd4f 100644 --- a/ectool/src/charge_current_limit_subcommand.rs +++ b/ectool/src/charge_current_limit_subcommand.rs @@ -6,6 +6,6 @@ use uom::si::electric_current::{milliampere, ElectricCurrent}; pub fn charge_current_limit_subcommand(limit: u32) -> Result<()> { let mut file = File::open(CROS_EC_PATH)?; - set_charge_current_limit(&mut file, ElectricCurrent::new::(limit.into()))?; + set_charge_current_limit(&mut file, ElectricCurrent::new::(limit as f32))?; Ok(()) }