Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,26 @@ Positions:
Pos 4: GenericC
```

### Checking board ID

Most inputdeck checking is implemented by Board ID. To read those directly for
debugging low level issues, use the `--boardid` command.
This host command was added recently is not available on every system yet.

```
# Example on Framework Laptop 13
# Touchpad Board ID is only present on Laptop 12
# dGPU Board IDs are only present on Laptop 16
> framework_tool --boardid
Board IDs
Mainboard: Ok(Some(6))
PowerButton: Err(Response(InvalidResponse))
Touchpad: Ok(Some(7))
AudioBoard: Ok(Some(7))
dGPU0: Err(Response(InvalidCommand))
dGPU1: Err(Response(InvalidCommand))
```

## Check temperatures and fan speed

```
Expand Down
2 changes: 2 additions & 0 deletions framework_lib/src/chromium_ec/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ pub enum EcCommands {
GetGpuPcie = 0x3E1E,
/// Set gpu bay serial and program structure
ProgramGpuEeprom = 0x3E1F,
/// Read board ID of specific ADC channel
ReadBoardId = 0x3E26,
}

pub trait EcRequest<R> {
Expand Down
36 changes: 36 additions & 0 deletions framework_lib/src/chromium_ec/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1658,3 +1658,39 @@ impl EcRequest<EcResponseSetGpuSerial> for EcRequestSetGpuSerial {
EcCommands::ProgramGpuEeprom
}
}

#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum BoardIdType {
/// Mainboard - any system
Mainboard = 0,
/// Power button board - Framework 12
PowerButtonBoard = 1,
/// Touchpad - Framework 12, 13, 16
Touchpad = 2,
/// Audio Board - Framework 12, 13
AudioBoard = 3,
/// dGPU board - Framework 16
DGpu0 = 4,
/// dGPU board - Framework 16
DGpu1 = 5,
}

#[repr(C, packed)]
pub struct EcRequestReadBoardId {
/// See BoardIdType
pub board_id_type: u8,
}

#[repr(C, packed)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EcResponseReadBoardId {
/// Board ID: -1 invalid, 0–14 valid, 15 not present
pub board_id: i8,
}

impl EcRequest<EcResponseReadBoardId> for EcRequestReadBoardId {
fn command_id() -> EcCommands {
EcCommands::ReadBoardId
}
}
16 changes: 16 additions & 0 deletions framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,22 @@ impl CrosEc {
Ok(())
}

pub fn read_board_id_hc(&self, board_id_type: BoardIdType) -> EcResult<Option<u8>> {
let res = EcRequestReadBoardId {
board_id_type: board_id_type as u8,
}
.send_command(self)?;
match res.board_id {
-1 => Err(EcError::DeviceError(format!(
"Failed to read Board ID {:?}",
board_id_type
))),
15 => Ok(None),
0..=14 => Ok(Some(res.board_id as u8)),
Comment on lines +1743 to +1754
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The magic numbers -1 and 15 should be defined as named constants to improve code clarity. Consider defining constants like BOARD_ID_INVALID = -1 and BOARD_ID_NOT_PRESENT = 15 near the function or in the BoardIdType enum implementation.

Suggested change
pub fn read_board_id_hc(&self, board_id_type: BoardIdType) -> EcResult<Option<u8>> {
let res = EcRequestReadBoardId {
board_id_type: board_id_type as u8,
}
.send_command(self)?;
match res.board_id {
-1 => Err(EcError::DeviceError(format!(
"Failed to read Board ID {:?}",
board_id_type
))),
15 => Ok(None),
0..=14 => Ok(Some(res.board_id as u8)),
const BOARD_ID_INVALID: i32 = -1;
const BOARD_ID_NOT_PRESENT: i32 = 15;
const BOARD_ID_MAX_VALID: i32 = BOARD_ID_NOT_PRESENT - 1;
pub fn read_board_id_hc(&self, board_id_type: BoardIdType) -> EcResult<Option<u8>> {
let res = EcRequestReadBoardId {
board_id_type: board_id_type as u8,
}
.send_command(self)?;
match res.board_id {
BOARD_ID_INVALID => Err(EcError::DeviceError(format!(
"Failed to read Board ID {:?}",
board_id_type
))),
BOARD_ID_NOT_PRESENT => Ok(None),
0..=BOARD_ID_MAX_VALID => Ok(Some(res.board_id as u8)),

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm let's not do that for now

n => Err(EcError::DeviceError(format!("Invalid Board ID {}", n))),
}
}

pub fn get_uptime_info(&self) -> EcResult<()> {
let res = EcRequestGetUptimeInfo {}.send_command(self)?;
let t_since_boot = Duration::from_millis(res.time_since_ec_boot.into());
Expand Down
5 changes: 5 additions & 0 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ struct ClapCli {
#[arg(long)]
test_retimer: bool,

/// Print all board IDs
#[arg(long)]
boardid: bool,

/// Force execution of an unsafe command - may render your hardware unbootable!
#[arg(long, short)]
force: bool,
Expand Down Expand Up @@ -472,6 +476,7 @@ pub fn parse(args: &[String]) -> Cli {
pd_ports,
test: args.test,
test_retimer: args.test_retimer,
boardid: args.boardid,
dry_run: args.dry_run,
force: args.force,
// TODO: Set help. Not very important because Clap handles this by itself
Expand Down
33 changes: 33 additions & 0 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::ccgx::device::{FwMode, PdController, PdPort};
use crate::ccgx::hid::{check_ccg_fw_version, find_devices, DP_CARD_PID, HDMI_CARD_PID};
use crate::ccgx::{self, MainPdVersions, PdVersions, SiliconId::*};
use crate::chromium_ec;
use crate::chromium_ec::commands::BoardIdType;
use crate::chromium_ec::commands::DeckStateMode;
use crate::chromium_ec::commands::FpLedBrightnessLevel;
use crate::chromium_ec::commands::RebootEcCmd;
Expand Down Expand Up @@ -192,6 +193,7 @@ pub struct Cli {
pub driver: Option<CrosEcDriverType>,
pub test: bool,
pub test_retimer: bool,
pub boardid: bool,
pub dry_run: bool,
pub force: bool,
pub intrusion: bool,
Expand Down Expand Up @@ -279,6 +281,7 @@ pub fn parse(args: &[String]) -> Cli {
driver: cli.driver,
test: cli.test,
test_retimer: cli.test_retimer,
boardid: cli.boardid,
dry_run: cli.dry_run,
// force
intrusion: cli.intrusion,
Expand Down Expand Up @@ -1487,6 +1490,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
if let Err(err) = selftest_retimer(&ec) {
println!(" Failed: {:?}", err);
}
} else if args.boardid {
print_board_ids(&ec);
} else if args.power {
return power::get_and_print_power_info(&ec);
} else if args.thermal {
Expand Down Expand Up @@ -1850,6 +1855,34 @@ fn hash(data: &[u8]) {
util::print_buffer(sha512);
}

fn print_board_ids(ec: &CrosEc) {
println!("Board IDs");
println!(
" Mainboard: {:?}",
ec.read_board_id_hc(BoardIdType::Mainboard)
);
println!(
" PowerButton: {:?}",
ec.read_board_id_hc(BoardIdType::PowerButtonBoard)
);
println!(
" Touchpad: {:?}",
ec.read_board_id_hc(BoardIdType::Touchpad)
);
println!(
" AudioBoard: {:?}",
ec.read_board_id_hc(BoardIdType::AudioBoard)
);
println!(
" dGPU0: {:?}",
ec.read_board_id_hc(BoardIdType::DGpu0)
);
println!(
" dGPU1: {:?}",
ec.read_board_id_hc(BoardIdType::DGpu1)
);
}

fn selftest(ec: &CrosEc) -> Option<()> {
if let Some(platform) = smbios::get_platform() {
println!(" SMBIOS Platform: {:?}", platform);
Expand Down
4 changes: 4 additions & 0 deletions framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub fn parse(args: &[String]) -> Cli {
pd_ports: None,
test: false,
test_retimer: false,
boardid: false,
dry_run: false,
force: false,
help: false,
Expand Down Expand Up @@ -511,6 +512,9 @@ pub fn parse(args: &[String]) -> Cli {
} else if arg == "-t" || arg == "--test-retimer" {
cli.test_retimer = true;
found_an_option = true;
} else if arg == "--boardid" {
cli.boardid = true;
found_an_option = true;
} else if arg == "-f" || arg == "--force" {
cli.force = true;
found_an_option = true;
Expand Down