From 21c640267177977c77f46bd53afcf27cded36956 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 23 Sep 2026 09:25:29 +0200 Subject: [PATCH 1/2] --versions: Integrate with smartmontools library I tried rewriting what smartmontools does, it didn't turn out to be a good idea. Fortunately they're making it easier to use as a library, so let's do that. Signed-off-by: Daniel Schaefer --- .github/workflows/ci.yml | 6 +++--- Cargo.lock | 9 +++++++++ EXAMPLES.md | 22 ++++++++++++++++++++++ README.md | 18 ++++++++++++++++++ flake.nix | 6 ++++++ framework_lib/Cargo.toml | 3 +++ framework_lib/src/commandline/mod.rs | 27 +++++++++++++++++++++++++-- framework_tool/Cargo.toml | 1 + 8 files changed, 87 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59606b8..3d577f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: path: target/debug/framework_tool - name: Build Linux tool (Release) - run: cargo build -p framework_tool --release --features nvidia + run: cargo build -p framework_tool --release --features nvidia,smartmontools - name: Upload Linux App uses: actions/upload-artifact@v6 @@ -143,10 +143,10 @@ jobs: - name: Build Windows tool run: | cargo build -p framework_tool - cargo build -p framework_tool --release --features nvidia + cargo build -p framework_tool --release --features nvidia,smartmontools - name: Check if Windows tool can start - run: cargo run -- --help --release + run: target/release/framework_tool.exe --help # Upload release build so that vcruntime is statically linked - name: Upload Windows App diff --git a/Cargo.lock b/Cargo.lock index abd1418..85ae1c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,6 +435,7 @@ dependencies = [ "rusb", "sha1", "sha2", + "smartmon-sys", "spin 0.10.0", "uefi", "uefi-raw", @@ -1202,6 +1203,14 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "smartmon-sys" +version = "0.1.0" +source = "git+https://github.com/FrameworkComputer/smartmontools-sys#d622244834c27ac5931500a603846f3e5b21081f" +dependencies = [ + "cc", +] + [[package]] name = "spin" version = "0.9.8" diff --git a/EXAMPLES.md b/EXAMPLES.md index 5e24685..391bc33 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -240,6 +240,28 @@ Touchpad Firmware Version: v0E07 ``` +### Disks (needs `smartmontools` feature) + +Shows model, serial and firmware version of all ATA, NVMe and SCSI disks, +including NVMe drives behind USB bridges, like the Storage Expansion Card. + +``` +> framework_tool --versions +[...] +NVMe Device: /dev/sda (sntasmedia) + Model Number: 250GB Expansion Card + Serial Number: 071C4BE9098A2D57 + Firmware Version: UHFM00.7 +NVMe Device: /dev/sdb (sntasmedia) + Model Number: USB DISK 3.2 + Serial Number: 07001A60B3A20F79 + Firmware Version: UHFM10.0 +NVMe Device: /dev/nvme0 (nvme) + Model Number: WD PC SN8000S SDEPNRG-2T00 + Serial Number: 24434D800023 + Firmware Version: 63100000 +``` + ### Input modules (Laptop 16) Shows firmware version and location of the modules. diff --git a/README.md b/README.md index 3cb74e0..14eed61 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ On UEFI and FreeBSD raw port I/O is used - on Linux this can also be used as a f - [x] Retimer - [x] Touchpad (Linux, Windows, FreeBSD, not UEFI) - [x] Touchscreen (Linux, Windows, FreeBSD, not UEFI) + - [x] NVMe SSD (Linux only) + - [x] Storage Expansion Card, NVMe/SATA/SCSI disks (Needs `smartmontools` feature) - [x] Get Expansion Card Firmware (Not on UEFI so far) - [x] HDMI Expansion Card (`--dp-hdmi-info`) - [x] DisplayPort Expansion Card (`--dp-hdmi-info`) @@ -293,6 +295,22 @@ make -C framework_uefi ls -l framework_uefi/build/x86_64-unknown-uefi/boot.efi ``` +#### Optional: smartmontools + +With the `smartmontools` feature, `--versions` uses libsmartmon to show model, +serial and firmware version of all disks, including the Storage Expansion Card +and other NVMe drives behind USB bridges. + +The library is built from source by the `smartmon-sys` crate, only a C++ +compiler is needed. + +Note: smartmontools is licensed GPL-2.0-or-later, so a binary built with this +feature must be distributed under the GPL. + +``` +cargo build --features smartmontools +``` + ## Install local package ``` diff --git a/flake.nix b/flake.nix index 98aa00c..db63982 100644 --- a/flake.nix +++ b/flake.nix @@ -97,6 +97,8 @@ cargoLock = { lockFile = ./Cargo.lock; + # For smartmon-sys, fetched by the rev pinned in Cargo.lock + allowBuiltinFetchGit = true; }; buildType = profile; @@ -150,6 +152,8 @@ cargoLock = { lockFile = ./Cargo.lock; + # For smartmon-sys, fetched by the rev pinned in Cargo.lock + allowBuiltinFetchGit = true; }; buildType = profile; @@ -200,6 +204,8 @@ cargoLock = { lockFile = ./Cargo.lock; + # For smartmon-sys, fetched by the rev pinned in Cargo.lock + allowBuiltinFetchGit = true; }; buildType = profile; diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 512d7b3..d00f223 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -19,6 +19,8 @@ rusb = ["dep:rusb"] hidapi = ["dep:hidapi"] uefi = [ "lazy_static/spin_no_std" ] nvidia = ["dep:nvml-wrapper"] +# Needs libsmartmon (GPL-2.0-or-later), see README +smartmontools = ["dep:smartmon-sys"] [build-dependencies] built = { version = "0.8", features = ["chrono", "git2"] } @@ -39,6 +41,7 @@ hidapi = { version = "2.6.3", features = [ "windows-native" ], optional = true } rusb = { version = "0.9.4", optional = true } guid-create = { version = "0.5.0", default-features = false } zerocopy = { version = "0.8", default-features = false, features = ["derive"] } +smartmon-sys = { git = "https://github.com/FrameworkComputer/smartmontools-sys", optional = true } [target.'cfg(target_os = "uefi")'.dependencies] uefi = { version = "0.36.1", features = ["alloc", "global_allocator", "panic_handler", "logger"] } diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 9d4d005..dfe34cd 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -54,7 +54,7 @@ use crate::esrt::{self, ResourceType}; use crate::fw_uefi::enable_page_break; #[cfg(feature = "rusb")] use crate::inputmodule::check_inputmodule_version; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(feature = "smartmontools")))] use crate::nvme; use crate::os_specific; use crate::parade_retimer; @@ -843,7 +843,10 @@ fn print_versions(ec: &CrosEc) { #[cfg(feature = "hidapi")] print_dp_hdmi_details(false); - #[cfg(target_os = "linux")] + #[cfg(feature = "smartmontools")] + print_disk_versions(); + + #[cfg(all(target_os = "linux", not(feature = "smartmontools")))] for i in 0..4 { let device = format!("/dev/nvme{i}"); match nvme::get_nvme_firmware_version(&device) { @@ -863,6 +866,26 @@ fn print_versions(ec: &CrosEc) { print_nvidia_details(); } +#[cfg(feature = "smartmontools")] +fn print_disk_versions() { + match smartmon_sys::scan_disks() { + Ok(disks) => { + for disk in disks { + println!( + "{} Device: {} ({})", + disk.protocol, disk.name, disk.dev_type + ); + println!(" Model Number: {}", disk.model); + if !disk.serial.is_empty() { + println!(" Serial Number: {}", disk.serial); + } + println!(" Firmware Version: {}", disk.firmware); + } + } + Err(err) => error!("{}", err), + } +} + #[cfg(feature = "nvidia")] fn probably_has_nvidia() -> bool { match smbios::get_platform().and_then(Platform::which_family) { diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index a7f4f91..d4fc4ea 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -17,6 +17,7 @@ path = "src/main.rs" default = [ ] readonly = [ "framework_lib/readonly" ] nvidia = [ "framework_lib/nvidia" ] +smartmontools = [ "framework_lib/smartmontools" ] [dependencies.framework_lib] path = "../framework_lib" From a4857df2a057f4d0c4048b47e2abca306c1d31f2 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Wed, 23 Sep 2026 12:20:49 +0200 Subject: [PATCH 2/2] smartmon: Depend on published crate Signed-off-by: Daniel Schaefer --- Cargo.lock | 7 ++++--- README.md | 5 +++-- flake.nix | 6 ------ framework_lib/Cargo.toml | 4 ++-- framework_lib/src/commandline/mod.rs | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85ae1c1..00ca45a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,7 +435,7 @@ dependencies = [ "rusb", "sha1", "sha2", - "smartmon-sys", + "smartmon", "spin 0.10.0", "uefi", "uefi-raw", @@ -1204,9 +1204,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] -name = "smartmon-sys" +name = "smartmon" version = "0.1.0" -source = "git+https://github.com/FrameworkComputer/smartmontools-sys#d622244834c27ac5931500a603846f3e5b21081f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1356952f6fc09d25032f6f811a454b7a7c4b9ff24d5505f88b0a4cb4f6847cd" dependencies = [ "cc", ] diff --git a/README.md b/README.md index 14eed61..59103dd 100644 --- a/README.md +++ b/README.md @@ -301,8 +301,9 @@ With the `smartmontools` feature, `--versions` uses libsmartmon to show model, serial and firmware version of all disks, including the Storage Expansion Card and other NVMe drives behind USB bridges. -The library is built from source by the `smartmon-sys` crate, only a C++ -compiler is needed. +The library is built from source by the +[`smartmon`](https://crates.io/crates/smartmon) crate, only a C++ compiler is +needed. Note: smartmontools is licensed GPL-2.0-or-later, so a binary built with this feature must be distributed under the GPL. diff --git a/flake.nix b/flake.nix index db63982..98aa00c 100644 --- a/flake.nix +++ b/flake.nix @@ -97,8 +97,6 @@ cargoLock = { lockFile = ./Cargo.lock; - # For smartmon-sys, fetched by the rev pinned in Cargo.lock - allowBuiltinFetchGit = true; }; buildType = profile; @@ -152,8 +150,6 @@ cargoLock = { lockFile = ./Cargo.lock; - # For smartmon-sys, fetched by the rev pinned in Cargo.lock - allowBuiltinFetchGit = true; }; buildType = profile; @@ -204,8 +200,6 @@ cargoLock = { lockFile = ./Cargo.lock; - # For smartmon-sys, fetched by the rev pinned in Cargo.lock - allowBuiltinFetchGit = true; }; buildType = profile; diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index d00f223..2e03874 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -20,7 +20,7 @@ hidapi = ["dep:hidapi"] uefi = [ "lazy_static/spin_no_std" ] nvidia = ["dep:nvml-wrapper"] # Needs libsmartmon (GPL-2.0-or-later), see README -smartmontools = ["dep:smartmon-sys"] +smartmontools = ["dep:smartmon"] [build-dependencies] built = { version = "0.8", features = ["chrono", "git2"] } @@ -41,7 +41,7 @@ hidapi = { version = "2.6.3", features = [ "windows-native" ], optional = true } rusb = { version = "0.9.4", optional = true } guid-create = { version = "0.5.0", default-features = false } zerocopy = { version = "0.8", default-features = false, features = ["derive"] } -smartmon-sys = { git = "https://github.com/FrameworkComputer/smartmontools-sys", optional = true } +smartmon = { version = "0.1", optional = true } [target.'cfg(target_os = "uefi")'.dependencies] uefi = { version = "0.36.1", features = ["alloc", "global_allocator", "panic_handler", "logger"] } diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index dfe34cd..49dce62 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -868,7 +868,7 @@ fn print_versions(ec: &CrosEc) { #[cfg(feature = "smartmontools")] fn print_disk_versions() { - match smartmon_sys::scan_disks() { + match smartmon::scan_disks() { Ok(disks) => { for disk in disks { println!(