Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Options:
--dump <DUMP> Dump extracted UX capsule bitmap image to a file
--h2o-capsule <H2O_CAPSULE> Parse UEFI Capsule information from binary file
--intrusion Show status of intrusion switch
--inputmodules Show status of the input modules (Framework 16 only)
--inputdeck Show status of the input deck
--input-deck-mode <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)
Expand Down
10 changes: 5 additions & 5 deletions completions/bash/framework_tool
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ _framework_tool() {
"--flash-ro-ec"
"--flash-rw-ec"
"--intrusion"
"--inputmodules"
"--input-deck-mode"
"--inputdeck"
"--inputdeck-mode"
"--charge-limit"
"--get-gpio"
"--fp-led-level"
Expand All @@ -56,7 +56,7 @@ _framework_tool() {
)

local devices=("bios" "ec" "pd0" "pd1" "rtm01" "rtm23" "ac-left" "ac-right")
local input_deck_modes=("auto" "off" "on")
local inputdeck_modes=("auto" "off" "on")
local console_modes=("recent" "follow")
local drivers=("portio" "cros-ec" "windows")
local has_mec_options=("true" "false")
Expand All @@ -71,8 +71,8 @@ _framework_tool() {
COMPREPLY=( $(compgen -W "${options[*]}" -- "$current_word") )
elif [[ $prev_word == "--device" ]]; then
COMPREPLY=( $(compgen -W "${devices[*]}" -- "$current_word") )
elif [[ $prev_word == "--input-deck-mode" ]]; then
COMPREPLY=( $(compgen -W "${input_deck_modes[*]}" -- "$current_word") )
elif [[ $prev_word == "--inputdeck-mode" ]]; then
COMPREPLY=( $(compgen -W "${inputdeck_modes[*]}" -- "$current_word") )
elif [[ $prev_word == "--console" ]]; then
COMPREPLY=( $(compgen -W "${console_modes[*]}" -- "$current_word") )
elif [[ $prev_word == "--driver" ]]; then
Expand Down
4 changes: 2 additions & 2 deletions completions/zsh/_framework_tool
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ options=(
'--flash-ro-ec[Flash EC with new RO firmware from file]:flash_ro_ec'
'--flash-rw-ec[Flash EC with new RW firmware from file]:flash_rw_ec'
'--intrusion[Show status of intrusion switch]'
'--inputmodules[Show status of the input modules (Framework 16 only)]'
'--input-deck-mode[Set input deck power mode]:input_deck_mode:(auto off on)'
'--inputdeck[Show status of the input deck]'
'--inputdeck-mode[Set input deck power mode]:inputdeck_mode:(auto off on)'
'--charge-limit[Get or set max charge limit]:charge_limit'
'--get-gpio[Get GPIO value by name]:get_gpio'
'--fp-led-level-gpio[Get or set fingerprint LED brightness level]:fp_led_level:(high medium low ultra-low auto)'
Expand Down
178 changes: 178 additions & 0 deletions framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,86 @@ pub enum EcResponseStatus {
Busy = 16,
}

#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum Framework12Adc {
MainboardBoardId,
PowerButtonBoardId,
Psys,
AdapterCurrent,
TouchpadBoardId,
AudioBoardId,
}

#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum FrameworkHx20Hx30Adc {
AdapterCurrent,
Psys,
BattTemp,
TouchpadBoardId,
MainboardBoardId,
AudioBoardId,
}

/// So far on all Nuvoton/Zephyr EC based platforms
/// Until at least Framework 13 AMD Ryzen AI 300
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum Framework13Adc {
MainboardBoardId,
Psys,
AdapterCurrent,
TouchpadBoardId,
AudioBoardId,
BattTemp,
}

#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum Framework16Adc {
MainboardBoardId,
HubBoardId,
GpuBoardId0,
GpuBoardId1,
AdapterCurrent,
Psys,
}

/*
* PLATFORM_EC_ADC_RESOLUTION default 10 bit
*
* +------------------+-----------+----------+-------------+---------+----------------------+
* | BOARD VERSION | voltage | NPC DB V | main board | GPU | Input module |
* +------------------+-----------+----------|-------------+---------+----------------------+
* | BOARD_VERSION_0 | 0 mV | 100 mV | Unused | | Reserved |
* | BOARD_VERSION_1 | 173 mV | 310 mV | Unused | | Reserved |
* | BOARD_VERSION_2 | 300 mV | 520 mV | Unused | | Reserved |
* | BOARD_VERSION_3 | 430 mV | 720 mV | Unused | | Reserved |
* | BOARD_VERSION_4 | 588 mV | 930 mV | EVT1 | | Reserved |
* | BOARD_VERSION_5 | 783 mV | 1130 mV | Unused | | Reserved |
* | BOARD_VERSION_6 | 905 mV | 1340 mV | Unused | | Reserved |
* | BOARD_VERSION_7 | 1033 mV | 1550 mV | DVT1 | | Reserved |
* | BOARD_VERSION_8 | 1320 mV | 1750 mV | DVT2 | | Generic A size |
* | BOARD_VERSION_9 | 1500 mV | 1960 mV | PVT | | Generic B size |
* | BOARD_VERSION_10 | 1650 mV | 2170 mV | MP | | Generic C size |
* | BOARD_VERSION_11 | 1980 mV | 2370 mV | Unused | RID_0 | 10 Key B size |
* | BOARD_VERSION_12 | 2135 mV | 2580 mV | Unused | RID_0,1 | Keyboard |
* | BOARD_VERSION_13 | 2500 mV | 2780 mV | Unused | RID_0 | Touchpad |
* | BOARD_VERSION_14 | 2706 mV | 2990 mV | Unused | | Reserved |
* | BOARD_VERSION_15 | 2813 mV | 3200 mV | Unused | | Not installed |
* +------------------+-----------+----------+-------------+---------+----------------------+
*/

const BOARD_VERSION_COUNT: usize = 16;
const BOARD_VERSION: [i32; BOARD_VERSION_COUNT] = [
85, 233, 360, 492, 649, 844, 965, 1094, 1380, 1562, 1710, 2040, 2197, 2557, 2766, 2814,
];

const BOARD_VERSION_NPC_DB: [i32; BOARD_VERSION_COUNT] = [
100, 311, 521, 721, 931, 1131, 1341, 1551, 1751, 1961, 2171, 2370, 2580, 2780, 2990, 3200,
];

pub fn has_mec() -> bool {
let platform = smbios::get_platform().unwrap();
if let Platform::GenericFramework(_, _, has_mec) = platform {
Expand Down Expand Up @@ -394,6 +474,65 @@ impl CrosEc {
Ok(InputDeckStatus::from(status))
}

pub fn print_fw12_inputdeck_status(&self) -> EcResult<()> {
let intrusion = self.get_intrusion_status()?;
let pwrbtn = self.read_board_id(Framework12Adc::PowerButtonBoardId as u8)?;
let audio = self.read_board_id(Framework12Adc::AudioBoardId as u8)?;
let tp = self.read_board_id(Framework12Adc::TouchpadBoardId as u8)?;

let is_present = |p| if p { "Present" } else { "Missing" };

println!("Input Deck");
println!(" Chassis Open: {}", intrusion.currently_open);
println!(" Power Button Board: {}", is_present(pwrbtn.is_some()));
println!(" Audio Daughterboard: {}", is_present(audio.is_some()));
println!(" Touchpad: {}", is_present(tp.is_some()));

Ok(())
}

pub fn print_fw13_inputdeck_status(&self) -> EcResult<()> {
let intrusion = self.get_intrusion_status()?;

let (audio, tp) = match smbios::get_platform() {
Some(Platform::IntelGen11)
| Some(Platform::IntelGen12)
| Some(Platform::IntelGen13) => (
self.read_board_id(FrameworkHx20Hx30Adc::AudioBoardId as u8)?,
self.read_board_id(FrameworkHx20Hx30Adc::TouchpadBoardId as u8)?,
),

_ => (
self.read_board_id_npc_db(Framework13Adc::AudioBoardId as u8)?,
self.read_board_id_npc_db(Framework13Adc::TouchpadBoardId as u8)?,
),
};

let is_present = |p| if p { "Present" } else { "Missing" };

println!("Input Deck");
println!(" Chassis Open: {}", intrusion.currently_open);
println!(" Audio Daughterboard: {}", is_present(audio.is_some()));
println!(" Touchpad: {}", is_present(tp.is_some()));

Ok(())
}

pub fn print_fw16_inputdeck_status(&self) -> EcResult<()> {
let intrusion = self.get_intrusion_status()?;
let status = self.get_input_deck_status()?;
println!("Chassis Open: {}", intrusion.currently_open);
println!("Input Deck State: {:?}", status.state);
println!("Touchpad present: {}", status.touchpad_present);
println!("Positions:");
println!(" Pos 0: {:?}", status.top_row.pos0);
println!(" Pos 1: {:?}", status.top_row.pos1);
println!(" Pos 2: {:?}", status.top_row.pos2);
println!(" Pos 3: {:?}", status.top_row.pos3);
println!(" Pos 4: {:?}", status.top_row.pos4);
Ok(())
}

pub fn set_input_deck_mode(&self, mode: DeckStateMode) -> EcResult<InputDeckStatus> {
let status = EcRequestDeckState { mode }.send_command(self)?;

Expand Down Expand Up @@ -1025,6 +1164,45 @@ impl CrosEc {
Ok(res.adc_value)
}

fn read_board_id(&self, channel: u8) -> EcResult<Option<u8>> {
self.read_board_id_raw(channel, BOARD_VERSION)
}
fn read_board_id_npc_db(&self, channel: u8) -> EcResult<Option<u8>> {
self.read_board_id_raw(channel, BOARD_VERSION_NPC_DB)
}

fn read_board_id_raw(
&self,
channel: u8,
table: [i32; BOARD_VERSION_COUNT],
) -> EcResult<Option<u8>> {
let mv = self.adc_read(channel)?;
if mv < 0 {
return Err(EcError::DeviceError(format!(
"Failed to read ADC channel {}",
channel
)));
}

debug!("ADC Channel {} - Measured {}mv", channel, mv);
for (board_id, board_id_res) in table.iter().enumerate() {
if mv < *board_id_res {
debug!("ADC Channel {} - Board ID {}", channel, board_id);
// 15 is not present, less than 2 is undefined
return Ok(if board_id == 15 || board_id < 2 {
None
} else {
Some(board_id as u8)
});
}
}

Err(EcError::DeviceError(format!(
"Unknown board id. ADC mv: {}",
mv
)))
}

pub fn rgbkbd_set_color(&self, start_key: u8, colors: Vec<RgbS>) -> EcResult<()> {
for (chunk, colors) in colors.chunks(EC_RGBKBD_MAX_KEY_COUNT).enumerate() {
let mut request = EcRequestRgbKbdSetColor {
Expand Down
8 changes: 4 additions & 4 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ struct ClapCli {

/// Show status of the input modules (Framework 16 only)
#[arg(long)]
inputmodules: bool,
inputdeck: bool,

/// Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
#[arg(long)]
input_deck_mode: Option<InputDeckModeArg>,
inputdeck_mode: Option<InputDeckModeArg>,

/// Show status of the expansion bay (Framework 16 only)
#[arg(long)]
Expand Down Expand Up @@ -354,8 +354,8 @@ pub fn parse(args: &[String]) -> Cli {
.flash_rw_ec
.map(|x| x.into_os_string().into_string().unwrap()),
intrusion: args.intrusion,
inputmodules: args.inputmodules,
input_deck_mode: args.input_deck_mode,
inputdeck: args.inputdeck,
inputdeck_mode: args.inputdeck_mode,
expansion_bay: args.expansion_bay,
charge_limit: args.charge_limit,
get_gpio: args.get_gpio,
Expand Down
34 changes: 14 additions & 20 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use crate::touchscreen;
#[cfg(feature = "uefi")]
use crate::uefi::enable_page_break;
use crate::util;
use crate::util::{Config, Platform};
use crate::util::{Config, Platform, PlatformFamily};
#[cfg(feature = "hidapi")]
use hidapi::HidApi;
use sha2::{Digest, Sha256, Sha384, Sha512};
Expand Down Expand Up @@ -171,8 +171,8 @@ pub struct Cli {
pub driver: Option<CrosEcDriverType>,
pub test: bool,
pub intrusion: bool,
pub inputmodules: bool,
pub input_deck_mode: Option<InputDeckModeArg>,
pub inputdeck: bool,
pub inputdeck_mode: Option<InputDeckModeArg>,
pub expansion_bay: bool,
pub charge_limit: Option<Option<u8>>,
pub get_gpio: Option<String>,
Expand Down Expand Up @@ -745,21 +745,15 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
} else {
println!(" Unable to tell");
}
} else if args.inputmodules {
println!("Input Module Status:");
if let Some(status) = print_err(ec.get_input_deck_status()) {
println!("Input Deck State: {:?}", status.state);
println!("Touchpad present: {:?}", status.touchpad_present);
println!("Positions:");
println!(" Pos 0: {:?}", status.top_row.pos0);
println!(" Pos 1: {:?}", status.top_row.pos1);
println!(" Pos 2: {:?}", status.top_row.pos2);
println!(" Pos 3: {:?}", status.top_row.pos3);
println!(" Pos 4: {:?}", status.top_row.pos4);
} else {
println!(" Unable to tell");
}
} else if let Some(mode) = &args.input_deck_mode {
} else if args.inputdeck {
let res = match smbios::get_platform().and_then(Platform::which_family) {
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(()),
};
print_err(res);
} else if let Some(mode) = &args.inputdeck_mode {
println!("Set mode to: {:?}", mode);
ec.set_input_deck_mode((*mode).into()).unwrap();
} else if args.expansion_bay {
Expand Down Expand Up @@ -1083,8 +1077,8 @@ Options:
--flash-rw-ec <FLASH_EC> Flash EC with new firmware from file
--reboot-ec Control EC RO/RW jump [possible values: reboot, jump-ro, jump-rw, cancel-jump, disable-jump]
--intrusion Show status of intrusion switch
--inputmodules Show status of the input modules (Framework 16 only)
--input-deck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
--inputdeck Show status of the input deck
--inputdeck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
--expansion-bay Show status of the expansion bay (Framework 16 only)
--charge-limit [<VAL>] Get or set battery charge limit (Percentage number as arg, e.g. '100')
--get-gpio <GET_GPIO> Get GPIO value by name
Expand Down
24 changes: 12 additions & 12 deletions framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ pub fn parse(args: &[String]) -> Cli {
dump: None,
h2o_capsule: None,
intrusion: false,
inputmodules: false,
input_deck_mode: None,
inputdeck: false,
inputdeck_mode: None,
expansion_bay: false,
charge_limit: None,
get_gpio: None,
Expand Down Expand Up @@ -225,25 +225,25 @@ pub fn parse(args: &[String]) -> Cli {
} else if arg == "--intrusion" {
cli.intrusion = true;
found_an_option = true;
} else if arg == "--inputmodules" {
cli.inputmodules = true;
} else if arg == "--inputdeck" {
cli.inputdeck = true;
found_an_option = true;
} else if arg == "--input-deck-mode" {
cli.input_deck_mode = if args.len() > i + 1 {
let input_deck_mode = &args[i + 1];
if input_deck_mode == "auto" {
} else if arg == "--inputdeck-mode" {
cli.inputdeck_mode = if args.len() > i + 1 {
let inputdeck_mode = &args[i + 1];
if inputdeck_mode == "auto" {
Some(InputDeckModeArg::Auto)
} else if input_deck_mode == "off" {
} else if inputdeck_mode == "off" {
Some(InputDeckModeArg::Off)
} else if input_deck_mode == "on" {
} else if inputdeck_mode == "on" {
Some(InputDeckModeArg::On)
} else {
println!("Invalid value for --input-deck-mode: {}", input_deck_mode);
println!("Invalid value for --inputdeck-mode: {}", inputdeck_mode);
None
}
} else {
println!(
"Need to provide a value for --input-deck-mode. Either `auto`, `off`, or `on`"
"Need to provide a value for --inputdeck-mode. Either `auto`, `off`, or `on`"
);
None
};
Expand Down
Loading