diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f5604d..32037c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,9 +62,21 @@ jobs: - name: Upload Linux App uses: actions/upload-artifact@v4 with: - name: framework_tool + name: framework_tool_debug path: target/debug/framework_tool + - name: Build Linux tool (Release) + run: cargo build -p framework_tool --release + + - name: Upload Linux App + uses: actions/upload-artifact@v4 + with: + name: framework_tool + path: target/release/framework_tool + + - name: Make sure nothing changed (e.g. Cargo.lock) + run: git diff --exit-code + build-uefi: name: Build UEFI runs-on: ubuntu-24.04 diff --git a/Cargo.lock b/Cargo.lock index 8bac508..dfee2ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "framework_lib" -version = "0.4.4" +version = "0.4.5" dependencies = [ "built", "clap", @@ -435,12 +435,13 @@ dependencies = [ "uefi", "uefi-services", "windows 0.59.0", + "windows-version", "wmi", ] [[package]] name = "framework_tool" -version = "0.4.4" +version = "0.4.5" dependencies = [ "embed-resource", "framework_lib", @@ -451,7 +452,7 @@ dependencies = [ [[package]] name = "framework_uefi" -version = "0.4.4" +version = "0.4.5" dependencies = [ "framework_lib", "log", @@ -582,8 +583,9 @@ dependencies = [ [[package]] name = "guid-create" -version = "0.4.1" -source = "git+https://github.com/FrameworkComputer/guid-create?branch=no-rand#84c3ad2e8b64a12beebb460804a65da55434cfd9" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c332e3cc6970b85f68ff39438fdb87b5c9e27a0260d720d7d550701d9964baa0" dependencies = [ "winapi", ] @@ -1559,6 +1561,12 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-result" version = "0.3.0" @@ -1642,6 +1650,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-version" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" diff --git a/EXAMPLES.md b/EXAMPLES.md index 2361b19..557d834 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -1,5 +1,142 @@ # Example usage +Built-in help: + +``` +> framework_tool +Swiss army knife for Framework laptops + +Usage: framework_tool [OPTIONS] + +Options: + --flash-gpu-descriptor + + -v, --verbose... + Increase logging verbosity + -q, --quiet... + Decrease logging verbosity + --versions + List current firmware versions + --version + Show tool version information (Add -vv for more details) + --features + Show features support by the firmware + --esrt + Display the UEFI ESRT table + --device + [possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right] + --compare-version + + --power + Show current power status of battery and AC (Add -vv for more details) + --thermal + Print thermal information (Temperatures and Fan speed) + --sensors + Print sensor information (ALS, G-Sensor) + --fansetduty [...] + Set fan duty cycle (0-100%) + --fansetrpm [...] + Set fan RPM (limited by EC fan table max RPM) + --autofanctrl + Turn on automatic fan speed control + --pdports + Show information about USB-C PD ports + --info + Show info from SMBIOS (Only on UEFI) + --pd-info + Show details about the PD controllers + --pd-reset + Reset a specific PD controller (for debugging only) + --pd-disable + Disable all ports on a specific PD controller (for debugging only) + --pd-enable + Enable all ports on a specific PD controller (for debugging only) + --dp-hdmi-info + Show details about connected DP or HDMI Expansion Cards + --dp-hdmi-update + Update the DisplayPort or HDMI Expansion Card + --audio-card-info + Show details about connected Audio Expansion Cards (Needs root privileges) + --privacy + Show privacy switch statuses (camera and microphone) + --pd-bin + Parse versions from PD firmware binary file + --ec-bin + Parse versions from EC firmware binary file + --capsule + Parse UEFI Capsule information from binary file + --dump + Dump extracted UX capsule bitmap image to a file + --h2o-capsule + Parse UEFI Capsule information from binary file + --dump-ec-flash + Dump EC flash contents + --flash-ec + Flash EC (RO+RW) with new firmware from file - may render your hardware unbootable! + --flash-ro-ec + Flash EC with new RO firmware from file - may render your hardware unbootable! + --flash-rw-ec + Flash EC with new RW firmware from file + --intrusion + Show status of intrusion switch + --inputdeck + Show status of the input modules (Framework 16 only) + --inputdeck-mode + Set input deck power mode [possible values: auto, off, on] (Framework 16 only) [possible values: auto, off, on] + --expansion-bay + Show status of the expansion bay (Framework 16 only) + --charge-limit [] + Get or set max charge limit + --charge-current-limit ... + Set max charge current limit + --charge-rate-limit ... + Set max charge current limit + --get-gpio [] + Get GPIO value by name or all, if no name provided + --fp-led-level [] + Get or set fingerprint LED brightness level [possible values: high, medium, low, ultra-low, auto] + --fp-brightness [] + Get or set fingerprint LED brightness percentage + --kblight [] + Set keyboard backlight percentage or get, if no value provided + --remap-key + Remap a key by changing the scancode + --rgbkbd ... + Set the color of to . Multiple colors for adjacent keys can be set at once. [ ...] Example: 0 0xFF000 0x00FF00 0x0000FF + --tablet-mode + Set tablet mode override [possible values: auto, tablet, laptop] + --touchscreen-enable + Enable/disable touchscreen [possible values: true, false] + --stylus-battery + Check stylus battery level (USI 2.0 stylus only) + --console + Get EC console, choose whether recent or to follow the output [possible values: recent, follow] + --reboot-ec + Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump] + --ec-hib-delay [] + Get or set EC hibernate delay (S5 to G3) + --hash + Hash a file of arbitrary data + --driver + Select which driver is used. By default portio is used [possible values: portio, cros-ec, windows] + --pd-addrs + Specify I2C addresses of the PD chips (Advanced) + --pd-ports + Specify I2C ports of the PD chips (Advanced) + -t, --test + Run self-test to check if interaction with EC is possible + -f, --force + Force execution of an unsafe command - may render your hardware unbootable! + --dry-run + Simulate execution of a command (e.g. --flash-ec) + --flash-gpu-descriptor-file + File to write to the gpu EEPROM + --dump-gpu-descriptor-file + File to dump the gpu EEPROM to + -h, --help + Print help +``` + ## Check firmware versions ### BIOS (Mainboard, UEFI, EC, PD, Retimer) diff --git a/EXAMPLES_ADVANCED.md b/EXAMPLES_ADVANCED.md index 0ece899..a350df3 100644 --- a/EXAMPLES_ADVANCED.md +++ b/EXAMPLES_ADVANCED.md @@ -1,5 +1,33 @@ # Advanced debugging +## Verbosity + +To debug, increase the verbosity from the commandline with `-v`. +The verbosity levels are: + +| Commandline | Level | +|-------------|--------| +| `-q` | No log | +| None | Error | +| `-v` | Warn | +| `-vv` | Info | +| `-vvv` | Debug | +| `-vvvv` | Trace | + +For example it is useful to check which EC driver is used: + +``` +> framework_tool --kblight -vvv +[DEBUG] Chromium EC Driver: CrosEc +[DEBUG] send_command(command=0x22, ver=0, data_len=0) +Keyboard backlight: 0% + +> framework_tool --driver portio --kblight -vvv +[DEBUG] Chromium EC Driver: Portio +[DEBUG] send_command(command=0x22, ver=0, data_len=0) +Keyboard backlight: 0% +``` + ## PD ### Check PD state @@ -39,7 +67,7 @@ Left / Ports 23 > sudo framework_tool --pd-enable 0 ``` -### Check EFI Resource Table +## Check EFI Resource Table On Framework Desktop: @@ -60,6 +88,30 @@ ESRT Entry 0 Last Attempt Status: Success ``` +## Manually overriding tablet mode status + +If you have a suspicion that the embedded controller does not control tablet +mode correctly based on Hall and G-Sensor, you can manually force a mode. + +This may also be useful if you want to use the touchpad and keyboard while the +lid is folded back - for example if you're using an external display only (Cyberdeck). +In this case you can force laptop mode. + +Tablet mode: +- Sets a GPIO connected to the touchpad to disable it +- Stops the EC from sending keypresses to the CPU + +``` +# Force tablet mode to disable touchpad and keyboard +> framework_tool --tablet-mode tablet + +# Force laptop mode to always keep touchpad and keyboard enabled +> framework_tool --tablet-mode laptop + +# Let the EC handle tablet mode automatically based on sensors +> framework_tool --tablet-mode auto +``` + ## Flashing EC firmware **IMPORTANT** Flashing EC firmware yourself is not recommended. It may render @@ -165,3 +217,58 @@ Capsule Header Capsule Size: 2180 KB Type: Framework Retimer23 (Right) ``` + +## Version Check + +Check if the firmware version is what you expect, returns exit code 0 on +succcess, 1 on failure. + +``` +# Check which devices it's available for +> ./framework_tool --device + [possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right] + +For more information try '--help' + +# Successful compare +> ./framework_tool --device bios --compare-version 03.01 +Target Version "03.01" +Comparing BIOS version "03.01" +Compared version: 0 +> echo $? +0 + +# Failed compare +> ./framework_tool --device bios --compare-version 03.00 + Finished dev [unoptimized + debuginfo] target(s) in 0.05s +Target Version "03.00" +Comparing BIOS version "03.01" +Compared version: 1 +Error: "Fail" + +> echo $? +1 +``` + +On UEFI Shell: + +``` +# Check if AC is attached on left side +Shell> fs0:framework_tool.efi --device ac-left --compare-version 1 +Target Version "1" +Comparing AcLeft "1" +Comparison Result: 0 +# It is +Shell> echo %lasterror% +0x0 + +# Check if AC is attached on right side +Shell> fs0:framework_tool.efi --device ac-right --compare-version 1 +Target Version "1" +Comparing AcLeft "0" +Comparison Result: 1 + +# It is not +Shell> echo %lasterror% +0x1 +``` diff --git a/README.md b/README.md index c40160a..eb44489 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,36 @@ Rust libraries and tools to interact with the system. The tool works on Linux, Windows and the UEFI shell. -Download it from the latest [GH Actions](https://github.com/FrameworkComputer/framework-system/actions?query=branch%3Amain) run on the main branch. -Most features are supported on every "OS". See below for details. +Most features are supported on every "OS". + +You can find lots of examples in [EXAMPLES.md](./EXAMPLES.md). + +## Installation + +### Linux + +- [NixOS](https://github.com/NixOS/nixpkgs/blob/nixos-25.05/pkgs/by-name/fr/framework-tool/package.nix) + - `nix-shell -p framework-tool` +- [ArchLinux](https://archlinux.org/packages/extra/x86_64/framework-system/) + - `pacman -Sy framework-system` +- [Bazzite](https://github.com/ublue-os/bazzite/pull/3026) +- Others + - Build from source + - Or download [latest binary](https://github.com/FrameworkComputer/framework-system/releases/latest/download/framework_tool) +- ChromeOS + - Build from source + +### Windows + +``` +winget install FrameworkComputer.framework_tool +``` + +### FreeBSD + +``` +sudo pkg install framework-system +``` ## Features @@ -27,18 +55,18 @@ On UEFI and FreeBSD raw port I/O is used - on Linux this can also be used as a f | | Port I/O | Linux | Windows | |---------------------|----------| ------|---------| | Framework 12 | | | | -| Intel Core 12th Gen | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | Yes | +| Intel Core 12th Gen | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | Yes | | Framework 13 | | | | -| Intel Core 11th Gen | Yes | [6.11](https://github.com/torvalds/linux/commit/04ca0a51f1e63bd553fd4af8e9af0fe094fa4f0a) | Not yet | -| Intel Core 12th Gen | Yes | [6.13](https://github.com/torvalds/linux/commit/dcd59d0d7d51b2a4b768fc132b0d74a97dfd6d6a) | Not yet | -| Intel Core 13th Gen | Yes | [6.13](https://github.com/torvalds/linux/commit/dcd59d0d7d51b2a4b768fc132b0d74a97dfd6d6a) | Not yet | -| AMD Ryzen 7040 | Yes | [6.10](https://github.com/torvalds/linux/commit/c8f460d991df93d87de01a96b783cad5a2da9616) | Soon | -| Intel Core Ultra 1S | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | Soon | -| AMD Ryzen AI 300 | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | Yes | +| Intel Core 11th Gen | Yes | [6.11](https://github.com/torvalds/linux/commit/04ca0a51f1e63bd553fd4af8e9af0fe094fa4f0a) | Not yet | +| Intel Core 12th Gen | Yes | [6.13](https://github.com/torvalds/linux/commit/dcd59d0d7d51b2a4b768fc132b0d74a97dfd6d6a) | Not yet | +| Intel Core 13th Gen | Yes | [6.13](https://github.com/torvalds/linux/commit/dcd59d0d7d51b2a4b768fc132b0d74a97dfd6d6a) | Not yet | +| AMD Ryzen 7040 | Yes | [6.10](https://github.com/torvalds/linux/commit/c8f460d991df93d87de01a96b783cad5a2da9616) | BIOS 3.16+ | +| Intel Core Ultra S1 | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | BIOS 3.06+ | +| AMD Ryzen AI 300 | Yes | [6.12](https://github.com/torvalds/linux/commit/62be134abf4250474a7a694837064bc783d2b291) | Yes | | Framework 16 | | | | -| AMD Ryzen 7040 | Yes | [6.10](https://github.com/torvalds/linux/commit/c8f460d991df93d87de01a96b783cad5a2da9616) | Soon | +| AMD Ryzen 7040 | Yes | [6.10](https://github.com/torvalds/linux/commit/c8f460d991df93d87de01a96b783cad5a2da9616) | BIOS 3.06+ | | Framework Desktop | | | | -| AMD Ryzen AI Max | Yes | [6.15](https://github.com/torvalds/linux/commit/d83c45aeec9b223fe6db4175e9d1c4f5699cc37a) | Yes | +| AMD Ryzen AI Max | Yes | [6.15](https://github.com/torvalds/linux/commit/d83c45aeec9b223fe6db4175e9d1c4f5699cc37a) | Yes | ###### Firmware Information @@ -109,18 +137,32 @@ All of these need EC communication support in order to work. - [x] Using [Framework EC Windows driver](https://github.com/FrameworkComputer/crosecbus) based on [coolstar's](https://github.com/coolstar/crosecbus) - [x] Using [DHowett's Windows CrosEC driver](https://github.com/DHowett/FrameworkWindowsUtils) -## Prerequisites +## Building -Only [Rustup](https://rustup.rs/) is needed. Based on `rust-toolchain.toml` it -will install the right toolchain and version for this project. +### Dependencies -## Building +[Rustup](https://rustup.rs/) is convenient for setting up the right Rust version. +Based on `rust-toolchain.toml` it will install the right toolchain and version for this project. MSRV (Minimum Supported Rust Version): - 1.74 for Linux/Windows - 1.74 for UEFI +System dependencies + +``` +# NixOS +nix-shell --run fish -p cargo systemd udev hidapi pkg-config +direnv shell + +# Fedora +sudo dnf install systemd-devel hidapi-devel + +# FreeBSD +sudo pkg install hidapi +``` + ```sh # Running linter cargo clippy @@ -147,14 +189,6 @@ make -C framework_uefi ls -l framework_uefi/build/x86_64-unknown-uefi/boot.efi ``` -### Dependencies - -``` -# NixOS -nix-shell --run fish -p cargo systemd udev hidapi pkg-config -direnv shell -``` - ## Install local package ``` @@ -165,179 +199,10 @@ direnv shell ## Running -Run without any arguments to see the help: - -``` -> cargo run -Swiss army knife for Framework laptops - -Usage: framework_tool [OPTIONS] - -Options: - -v, --verbose... More output per occurrence - -q, --quiet... Less output per occurrence - --versions List current firmware versions version - --esrt Display the UEFI ESRT table - --power Show current power status (battery and AC) - --pdports Show information about USB-C PD ports - --info Show info from SMBIOS (Only on UEFI) - --pd-info Show details about the PD controllers - --dp-hdmi-info Show details about connected DP or HDMI Expansion Cards - --dp-hdmi-update Update the DisplayPort or HDMI Expansion Card - --audio-card-info Show details about connected Audio Expansion Cards (Needs root privileges) - --privacy Show privacy switch statuses (camera and microphone) - --pd-bin Parse versions from PD firmware binary file - --ec-bin Parse versions from EC firmware binary file - --capsule Parse UEFI Capsule information from binary file - --dump Dump extracted UX capsule bitmap image to a file - --h2o-capsule Parse UEFI Capsule information from binary file - --intrusion Show status of intrusion switch - --inputdeck Show status of the input deck - --input-deck-mode - Set input deck power mode [possible values: auto, off, on] (Framework 16 only) [possible values: auto, off, on] - --expansion-bay Show status of the expansion bay (Framework 16 only) - --charge-limit [] - Get or set max charge limit - --get-gpio [] - Get GPIO value by name or all, if no name provided - --fp-led-level [] - Get or set fingerprint LED brightness level [possible values: high, medium, low, ultra-low, auto] - --fp-brightness [] - Get or set fingerprint LED brightness percentage - --kblight [] Set keyboard backlight percentage or get, if no value provided - --tablet-mode Set tablet mode override [possible values: auto, tablet, laptop] - --touchscreen-enable - Enable/disable touchscreen [possible values: true, false] - --console Get EC console, choose whether recent or to follow the output [possible values: recent, follow] - --reboot-ec Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump] - --hash Hash a file of arbitrary data - --driver Select which driver is used. By default portio is used [possible values: portio, cros-ec, windows] - --pd-addrs - Specify I2C addresses of the PD chips (Advanced) - --pd-ports - Specify I2C ports of the PD chips (Advanced) - -t, --test Run self-test to check if interaction with EC is possible - -h, --help Print help information -``` +Run without any arguments to see the help. Many actions require root. First build with cargo and then run the binary with sudo: ```sh cargo build && sudo ./target/debug/framework_tool ``` - -###### Running on Windows - -On newly released systems since 2025 the Framework driver installer includes the EC driver. -This includes Framework 12, Framework 13 AMD Ryzen AI 300, Framework Desktop. - -Previous platforms will be enabled next. - -Installing: `winget install FrameworkComputer.framework_tool` - -##### Running on ChromeOS - -The application can run on ChromeOS but most commands rely on custom host -commands that we built into the EC firmware of non-Chromebook Framework laptops. -In theory you could add those patches to the Chromebook platform, build your -own EC firmware and flash it. - -## Tests - -- [x] Basic unit tests -- [x] Test parsing real binaries - -## Version Check - -Check if the firmware version is what you expect, returns exit code 0 on -succcess, 1 on failure. - -``` -# Check which devices it's available for -> ./framework_tool --device - [possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right] - -For more information try '--help' - -# Successful compare -> ./framework_tool --device bios --compare-version 03.01 -Target Version "03.01" -Comparing BIOS version "03.01" -Compared version: 0 -> echo $? -0 - -# Failed compare -> ./framework_tool --device bios --compare-version 03.00 - Finished dev [unoptimized + debuginfo] target(s) in 0.05s -Target Version "03.00" -Comparing BIOS version "03.01" -Compared version: 1 -Error: "Fail" - -> echo $? -1 -``` - -On UEFI Shell: - -``` -# Check if AC is attached on left side -Shell> fs0:framework_tool.efi --device ac-left --compare-version 1 -Target Version "1" -Comparing AcLeft "1" -Comparison Result: 0 -# It is -Shell> echo %lasterror% -0x0 - -# Check if AC is attached on right side -Shell> fs0:framework_tool.efi --device ac-right --compare-version 1 -Target Version "1" -Comparing AcLeft "0" -Comparison Result: 1 - -# It is not -Shell> echo %lasterror% -0x1 -``` - -## Debugging - -To debug, increase the verbosity from the commandline with `-v`. -The verbosity levels are: - -| Commandline | Level | -|-------------|--------| -| `-q` | No log | -| None | Error | -| `-v` | Warn | -| `-vv` | Info | -| `-vvv` | Debug | -| `-vvvv` | Trace | - -For example it is useful to check which EC driver is used: - -``` -> framework_tool --kblight -vvv -[DEBUG] Chromium EC Driver: CrosEc -[DEBUG] send_command(command=0x22, ver=0, data_len=0) -Keyboard backlight: 0% - -> framework_tool --driver portio --kblight -vvv -[DEBUG] Chromium EC Driver: Portio -[DEBUG] send_command(command=0x22, ver=0, data_len=0) -Keyboard backlight: 0% -``` - -## FreeBSD - -``` -sudo pkg install hidapi - -# Build the library and tool -cargo build - -# Running the tool -cargo run -``` diff --git a/devenv.nix b/devenv.nix index 413d6a6..e84d152 100644 --- a/devenv.nix +++ b/devenv.nix @@ -3,9 +3,16 @@ { packages = with pkgs; [ systemd # libudev + # For UEFI building and testing + parted + gnumake + qemu ]; - languages.rust.enable = true; - # https://devenv.sh/reference/options/#languagesrustchannel - languages.rust.channel = "stable"; + languages.rust = { + enable = true; + targets = [ "x86_64-unknown-uefi" ]; + # https://devenv.sh/reference/options/#languagesrustchannel + channel = "stable"; + }; } diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index 001dbcc..62e0e5d 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_lib" -version = "0.4.4" +version = "0.4.5" description = "Library to control Framework Computer systems" homepage = "https://github.com/FrameworkComputer/framework-system" repository = "https://github.com/FrameworkComputer/framework-system" @@ -34,7 +34,7 @@ spin = { version = "0.9.8" } no-std-compat = { version = "0.4.1", features = [ "alloc" ] } hidapi = { version = "2.6.3", features = [ "windows-native" ], optional = true } rusb = { version = "0.9.4", optional = true } -guid-create = { git = "https://github.com/FrameworkComputer/guid-create", branch = "no-rand", default-features = false } +guid-create = { version = "0.5.0", default-features = false } [target.'cfg(target_os = "uefi")'.dependencies] uefi = { version = "0.20", features = ["alloc"] } @@ -50,6 +50,7 @@ env_logger = "0.11" clap = { version = "4.5", features = ["derive", "cargo"] } clap-num = { version = "1.2.0" } clap-verbosity-flag = { version = "2.2.1" } +windows-version = "0.1.4" [target.'cfg(unix)'.dependencies] libc = "0.2.155" diff --git a/framework_lib/src/capsule.rs b/framework_lib/src/capsule.rs index e2dff32..8ded649 100644 --- a/framework_lib/src/capsule.rs +++ b/framework_lib/src/capsule.rs @@ -11,7 +11,7 @@ use std::prelude::v1::*; use core::prelude::rust_2021::derive; -use guid_create::Guid; +use guid_create::CGuid; #[cfg(not(feature = "uefi"))] use std::fs::File; #[cfg(not(feature = "uefi"))] @@ -21,7 +21,7 @@ use std::io::prelude::*; #[repr(C)] pub struct EfiCapsuleHeader { /// A GUID that defines the contents of a capsule. - pub capsule_guid: Guid, + pub capsule_guid: CGuid, /// The size of the capsule header. This may be larger than the size of /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply @@ -205,14 +205,14 @@ mod tests { let data = fs::read(capsule_path).unwrap(); let cap = parse_capsule_header(&data).unwrap(); let expected_header = EfiCapsuleHeader { - capsule_guid: Guid::from(esrt::WINUX_GUID), + capsule_guid: CGuid::from(esrt::WINUX_GUID), header_size: 28, flags: 65536, capsule_image_size: 676898, }; assert_eq!(cap, expected_header); - assert_eq!(cap.capsule_guid, Guid::from(esrt::WINUX_GUID)); + assert_eq!(cap.capsule_guid, CGuid::from(esrt::WINUX_GUID)); let ux_header = parse_ux_header(&data); assert_eq!( ux_header, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 9447558..e56d348 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -7,7 +7,7 @@ use alloc::format; use alloc::string::String; use alloc::string::ToString; use alloc::vec::Vec; -use guid_create::{Guid, GUID}; +use guid_create::{CGuid, GUID}; use log::Level; use num_traits::FromPrimitive; @@ -49,6 +49,7 @@ use crate::ec_binary; use crate::esrt; #[cfg(feature = "rusb")] use crate::inputmodule::check_inputmodule_version; +use crate::os_specific; use crate::power; use crate::smbios; use crate::smbios::ConfigDigit0; @@ -59,6 +60,8 @@ use crate::touchpad::print_touchpad_fw_ver; use crate::touchscreen; #[cfg(feature = "uefi")] use crate::uefi::enable_page_break; +#[cfg(feature = "rusb")] +use crate::usbhub::check_usbhub_version; use crate::util::{self, Config, Platform, PlatformFamily}; #[cfg(feature = "hidapi")] use hidapi::HidApi; @@ -235,16 +238,22 @@ pub fn parse(args: &[String]) -> Cli { verbosity: cli.verbosity, versions: cli.versions, version: cli.version, + features: cli.features, esrt: cli.esrt, device: cli.device, + compare_version: cli.compare_version, power: cli.power, thermal: cli.thermal, sensors: cli.sensors, // fansetduty // fansetrpm // autofanctrl + pdports: cli.pdports, privacy: cli.privacy, pd_info: cli.version, + // pd_reset + // pd_disable + // pd_enable dp_hdmi_info: cli.dp_hdmi_info, // dp_hdmi_update audio_card_info: cli.audio_card_info, @@ -256,19 +265,25 @@ pub fn parse(args: &[String]) -> Cli { // dump_ec_flash // flash_ec // flash_ro_ec + // flash_rw_ec driver: cli.driver, test: cli.test, + dry_run: cli.dry_run, + // force intrusion: cli.intrusion, inputdeck: cli.inputdeck, inputdeck_mode: cli.inputdeck_mode, expansion_bay: cli.expansion_bay, // charge_limit // charge_current_limit + // charge_rate_limit get_gpio: cli.get_gpio, fp_led_level: cli.fp_led_level, fp_brightness: cli.fp_brightness, kblight: cli.kblight, + remap_key: cli.remap_key, rgbkbd: cli.rgbkbd, + ps2_enable: cli.ps2_enable, // tablet_mode // touchscreen_enable stylus_battery: cli.stylus_battery, @@ -280,6 +295,8 @@ pub fn parse(args: &[String]) -> Cli { pd_ports: cli.pd_ports, help: cli.help, info: cli.info, + // flash_gpu_descriptor + // flash_gpu_descriptor_file // allupdate paginate: cli.paginate, // raw_command @@ -447,6 +464,8 @@ fn print_stylus_battery_level() { } fn print_versions(ec: &CrosEc) { + println!("Tool Version: {}", built_info::PKG_VERSION); + println!("OS Version: {}", os_specific::get_os_version()); println!("Mainboard Hardware"); if let Some(ver) = smbios::get_product_name() { println!(" Type: {}", ver); @@ -688,6 +707,9 @@ fn print_versions(ec: &CrosEc) { #[cfg(feature = "rusb")] let _ignore_err = check_camera_version(); + #[cfg(feature = "rusb")] + let _ignore_err = check_usbhub_version(); + #[cfg(feature = "rusb")] let _ignore_err = check_inputmodule_version(); @@ -966,7 +988,16 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { Some(PlatformFamily::Framework12) => ec.print_fw12_inputdeck_status(), Some(PlatformFamily::Framework13) => ec.print_fw13_inputdeck_status(), Some(PlatformFamily::Framework16) => ec.print_fw16_inputdeck_status(), - _ => Ok(()), + // If we don't know which platform it is, we can use some heuristics + _ => { + // Only Framework 16 has this GPIO + if ec.get_gpio("sleep_l").is_ok() { + ec.print_fw16_inputdeck_status() + } else { + println!(" Unable to tell"); + Ok(()) + } + } }; print_err(res); } else if let Some(mode) = &args.inputdeck_mode { @@ -1244,7 +1275,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { println!(" Size: {:>20} B", data.len()); println!(" Size: {:>20} KB", data.len() / 1024); if let Some(header) = analyze_capsule(&data) { - if header.capsule_guid == Guid::from(esrt::WINUX_GUID) { + if header.capsule_guid == CGuid::from(esrt::WINUX_GUID) { let ux_header = capsule::parse_ux_header(&data); if let Some(dump_path) = &args.dump { // TODO: Better error handling, rather than just panicking @@ -1657,7 +1688,6 @@ fn analyze_ccgx_pd_fw(data: &[u8]) { println!("FW 2"); ccgx::binary::print_fw(&versions.main_fw); - return; } else if let Some(versions) = ccgx::binary::read_versions(data, Ccg6) { println!("Detected CCG6 firmware"); println!("FW 1 (Backup)"); @@ -1665,7 +1695,6 @@ fn analyze_ccgx_pd_fw(data: &[u8]) { println!("FW 2 (Main)"); ccgx::binary::print_fw(&versions.main_fw); - return; } else { println!("Failed to read PD versions") } diff --git a/framework_lib/src/esrt/mod.rs b/framework_lib/src/esrt/mod.rs index aa517bf..77ecbf7 100644 --- a/framework_lib/src/esrt/mod.rs +++ b/framework_lib/src/esrt/mod.rs @@ -15,7 +15,7 @@ use log::{debug, error, info, trace}; use std::prelude::v1::*; use core::prelude::v1::derive; -use guid_create::{Guid, GUID}; +use guid_create::{CGuid, GUID}; #[cfg(target_os = "linux")] use std::fs; @@ -193,7 +193,7 @@ pub enum FrameworkGuidKind { Unknown, } -pub fn match_guid_kind(guid: &Guid) -> FrameworkGuidKind { +pub fn match_guid_kind(guid: &CGuid) -> FrameworkGuidKind { match GUID::from(*guid) { TGL_BIOS_GUID => FrameworkGuidKind::TglBios, ADL_BIOS_GUID => FrameworkGuidKind::AdlBios, @@ -292,7 +292,7 @@ impl UpdateStatus { // TODO: Decode into proper Rust types #[derive(Clone)] pub struct EsrtResourceEntry { - pub fw_class: Guid, + pub fw_class: CGuid, pub fw_type: u32, // ResourceType pub fw_version: u32, pub lowest_supported_fw_version: u32, @@ -364,7 +364,7 @@ fn esrt_from_sysfs(dir: &Path) -> io::Result { let last_attempt_version = fs::read_to_string(path.join("last_attempt_version"))?; let last_attempt_status = fs::read_to_string(path.join("last_attempt_status"))?; let esrt = EsrtResourceEntry { - fw_class: Guid::from( + fw_class: CGuid::from( GUID::parse(fw_class.trim()).expect("Kernel provided wrong value"), ), fw_type: fw_type @@ -436,7 +436,7 @@ pub fn get_esrt() -> Option { let ver_str = caps.get(2).unwrap().as_str().to_string(); let guid = GUID::parse(guid_str.trim()).expect("Kernel provided wrong value"); - let guid_kind = match_guid_kind(&Guid::from(guid)); + let guid_kind = match_guid_kind(&CGuid::from(guid)); let ver = u32::from_str_radix(&ver_str, 16).unwrap(); debug!("ESRT Entry {}", i); debug!(" Name: {:?}", guid_kind); @@ -456,7 +456,7 @@ pub fn get_esrt() -> Option { // TODO: The missing fields are present in Device Manager // So there must be a way to get at them let esrt = EsrtResourceEntry { - fw_class: Guid::from(guid), + fw_class: CGuid::from(guid), fw_type, fw_version: ver, // TODO: Not exposed by windows @@ -543,7 +543,7 @@ pub fn get_esrt() -> Option { for table in config_tables { // TODO: Why aren't they the same type? //debug!("Table: {:?}", table); - let table_guid: Guid = unsafe { std::mem::transmute(table.guid) }; + let table_guid: CGuid = unsafe { std::mem::transmute(table.guid) }; let table_guid = GUID::from(table_guid); match table_guid { SYSTEM_RESOURCE_TABLE_GUID => unsafe { diff --git a/framework_lib/src/inputmodule.rs b/framework_lib/src/inputmodule.rs index 4e28006..f9e6cc0 100644 --- a/framework_lib/src/inputmodule.rs +++ b/framework_lib/src/inputmodule.rs @@ -1,11 +1,12 @@ pub const FRAMEWORK_VID: u16 = 0x32AC; pub const LEDMATRIX_PID: u16 = 0x0020; -pub const FRAMEWORK16_INPUTMODULE_PIDS: [u16; 6] = [ +pub const FRAMEWORK16_INPUTMODULE_PIDS: [u16; 7] = [ 0x0012, // Keyboard White Backlight ANSI 0x0013, // Keyboard RGB Backlight Numpad 0x0014, // Keyboard White Backlight Numpad 0x0018, // Keyboard White Backlight ISO 0x0019, // Keyboard White Backlight JIS + 0x0030, LEDMATRIX_PID, ]; diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 05adf8f..f205403 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -25,6 +25,8 @@ pub mod touchpad; pub mod touchscreen; #[cfg(all(feature = "hidapi", windows))] pub mod touchscreen_win; +#[cfg(feature = "rusb")] +pub mod usbhub; #[cfg(feature = "uefi")] #[macro_use] diff --git a/framework_lib/src/os_specific.rs b/framework_lib/src/os_specific.rs index 83ae2f3..b77deb8 100644 --- a/framework_lib/src/os_specific.rs +++ b/framework_lib/src/os_specific.rs @@ -3,6 +3,39 @@ #[cfg(not(feature = "uefi"))] use std::{thread, time}; +#[cfg(feature = "uefi")] +use alloc::string::{String, ToString}; + +// Could report the implemented UEFI spec version +// But that's not very useful. Just look at the BIOS version +// But at least it's useful to see that the tool was run on UEFI +#[cfg(feature = "uefi")] +pub fn get_os_version() -> String { + "UEFI".to_string() +} + +#[cfg(target_family = "windows")] +pub fn get_os_version() -> String { + let ver = windows_version::OsVersion::current(); + format!("{}.{}.{}.{}", ver.major, ver.minor, ver.pack, ver.build) +} + +#[cfg(target_family = "unix")] +pub fn get_os_version() -> String { + if let Ok(uts) = nix::sys::utsname::uname() { + // uname -a without hostname + format!( + "{} {} {} {}", + uts.sysname().to_string_lossy(), + uts.release().to_string_lossy(), + uts.version().to_string_lossy(), + uts.machine().to_string_lossy(), + ) + } else { + "Unknown".to_string() + } +} + /// Sleep a number of microseconds pub fn sleep(micros: u64) { #[cfg(not(feature = "uefi"))] diff --git a/framework_lib/src/usbhub.rs b/framework_lib/src/usbhub.rs new file mode 100644 index 0000000..53f2557 --- /dev/null +++ b/framework_lib/src/usbhub.rs @@ -0,0 +1,26 @@ +pub const REALTEK_VID: u16 = 0x0BDA; +pub const RTL5432_PID: u16 = 0x5432; +pub const RTL5424_PID: u16 = 0x5424; + +/// Get and print the firmware version of the usbhub +pub fn check_usbhub_version() -> Result<(), rusb::Error> { + for dev in rusb::devices().unwrap().iter() { + let dev_descriptor = dev.device_descriptor().unwrap(); + if dev_descriptor.vendor_id() != REALTEK_VID + || (dev_descriptor.product_id() != RTL5432_PID + && dev_descriptor.product_id() != RTL5424_PID) + { + debug!( + "Skipping {:04X}:{:04X}", + dev_descriptor.vendor_id(), + dev_descriptor.product_id() + ); + continue; + } + + let dev_descriptor = dev.device_descriptor()?; + println!("USB Hub RTL{:04X}", dev_descriptor.product_id()); + println!(" Firmware Version: {}", dev_descriptor.device_version()); + } + Ok(()) +} diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index fa240e3..6dceeab 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_tool" -version = "0.4.4" +version = "0.4.5" description = "Tool to control Framework Computer systems" homepage = "https://github.com/FrameworkComputer/framework-system" repository = "https://github.com/FrameworkComputer/framework-system" diff --git a/framework_uefi/Cargo.toml b/framework_uefi/Cargo.toml index 6c73a81..1995042 100644 --- a/framework_uefi/Cargo.toml +++ b/framework_uefi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "framework_uefi" -version = "0.4.4" +version = "0.4.5" description = "UEFI Tool to control Framework Computer systems" homepage = "https://github.com/FrameworkComputer/framework-system" repository = "https://github.com/FrameworkComputer/framework-system"