diff --git a/README.md b/README.md index db57686c..0e89f34b 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ Options: --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 - --inputmodules Show status of the input modules (Framework 16 only) + --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) diff --git a/completions/bash/framework_tool b/completions/bash/framework_tool index 24f41d46..f96fcc23 100755 --- a/completions/bash/framework_tool +++ b/completions/bash/framework_tool @@ -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" @@ -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") @@ -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 diff --git a/completions/zsh/_framework_tool b/completions/zsh/_framework_tool index 70ea7516..ad6aa668 100644 --- a/completions/zsh/_framework_tool +++ b/completions/zsh/_framework_tool @@ -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)' diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index e1a53c20..ff0327d4 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -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 { @@ -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 { let status = EcRequestDeckState { mode }.send_command(self)?; @@ -1025,6 +1164,45 @@ impl CrosEc { Ok(res.adc_value) } + fn read_board_id(&self, channel: u8) -> EcResult> { + self.read_board_id_raw(channel, BOARD_VERSION) + } + fn read_board_id_npc_db(&self, channel: u8) -> EcResult> { + self.read_board_id_raw(channel, BOARD_VERSION_NPC_DB) + } + + fn read_board_id_raw( + &self, + channel: u8, + table: [i32; BOARD_VERSION_COUNT], + ) -> EcResult> { + 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) -> EcResult<()> { for (chunk, colors) in colors.chunks(EC_RGBKBD_MAX_KEY_COUNT).enumerate() { let mut request = EcRequestRgbKbdSetColor { diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 38ef8f5f..e94a330c 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -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, + inputdeck_mode: Option, /// Show status of the expansion bay (Framework 16 only) #[arg(long)] @@ -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, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 2a88db09..75c8300a 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -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}; @@ -171,8 +171,8 @@ pub struct Cli { pub driver: Option, pub test: bool, pub intrusion: bool, - pub inputmodules: bool, - pub input_deck_mode: Option, + pub inputdeck: bool, + pub inputdeck_mode: Option, pub expansion_bay: bool, pub charge_limit: Option>, pub get_gpio: Option, @@ -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 { @@ -1083,8 +1077,8 @@ Options: --flash-rw-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 [] Get or set battery charge limit (Percentage number as arg, e.g. '100') --get-gpio Get GPIO value by name diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 9d3239a5..3c097344 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -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, @@ -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 }; diff --git a/framework_lib/src/util.rs b/framework_lib/src/util.rs index 3fa8f505..cfb97368 100644 --- a/framework_lib/src/util.rs +++ b/framework_lib/src/util.rs @@ -40,6 +40,31 @@ pub enum Platform { GenericFramework((u16, u16), (u8, u8), bool), } +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum PlatformFamily { + Framework12, + Framework13, + Framework16, + FrameworkDesktop, +} + +impl Platform { + pub fn which_family(self) -> Option { + match self { + Platform::Framework12IntelGen13 => Some(PlatformFamily::Framework12), + Platform::IntelGen11 + | Platform::IntelGen12 + | Platform::IntelGen13 + | Platform::IntelCoreUltra1 + | Platform::Framework13Amd7080 + | Platform::Framework13AmdAi300 => Some(PlatformFamily::Framework13), + Platform::Framework16Amd7080 => Some(PlatformFamily::Framework16), + Platform::FrameworkDesktopAmdAiMax300 => Some(PlatformFamily::FrameworkDesktop), + Platform::GenericFramework(..) => None, + } + } +} + #[derive(Debug)] pub struct Config { // TODO: Actually set and read this diff --git a/support-matrices.md b/support-matrices.md index 4a4396ed..6c468160 100644 --- a/support-matrices.md +++ b/support-matrices.md @@ -37,6 +37,6 @@ | `--pd-info` | PD Communication | All | | `--privacy` | EC Communication | All | | `--intrusion` | EC Communication | All | -| `--inputmodules` | EC Communication | Framework 16 | +| `--inputdeck` | EC Communication | Framework 16 | | `--console` | EC Communication | All | -| `--kblight` | EC Communication | All, except FL16 | \ No newline at end of file +| `--kblight` | EC Communication | All, except FL16 |