Skip to content

Commit b795c8a

Browse files
committed
Add --host-command to send raw EC host commands
Useful for debugging new host commands Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent d415421 commit b795c8a

File tree

7 files changed

+141
-12
lines changed

7 files changed

+141
-12
lines changed

EXAMPLES_ADVANCED.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,38 @@ Capsule Header
278278
Type: Framework Retimer23 (Right)
279279
```
280280

281+
## Raw EC Host Commands
282+
283+
Send an arbitrary EC host command by specifying a command ID, version, and
284+
optional payload bytes. The response is displayed in xxd-style hex+ASCII format.
285+
286+
```
287+
# Send EC_CMD_GET_VERSION (0x0002) with version 0, no payload
288+
> sudo framework_tool --host-command 0x0002 0
289+
Response (120 bytes):
290+
00000000: 7375 6e66 6c6f 7765 722d 332e 302e 332d sunflower-3.0.3-
291+
00000010: 3838 6664 6135 3400 0000 0000 0000 0000 88fda54.........
292+
00000020: 7375 6e66 6c6f 7765 722d 332e 302e 332d sunflower-3.0.3-
293+
00000030: 3838 6664 6135 3400 0000 0000 0000 0000 88fda54.........
294+
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
295+
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
296+
00000060: 0100 0000 0000 0000 0000 0000 0000 0000 ................
297+
00000070: 0000 0000 0000 0000 ........
298+
299+
# Query supported versions of EC_CMD_GET_VERSION (0x0002)
300+
# EC_CMD_GET_CMD_VERSIONS (0x0008), version 0, payload: command ID byte
301+
# Command 2 supports version 0 and 1 (0b11 = 3)
302+
> framework_tool --host-command 0x0008 0 2
303+
Response (24 bytes):
304+
00000000: 0300 0000 0000 0000 0000 0000 0000 0000 ................
305+
00000010: 0000 0000 0000 0000 ........
306+
# Command 1 only supports version 0 (0b01 = 1)
307+
> framework_tool --host-command 0x0008 0 1
308+
Response (24 bytes):
309+
00000000: 0100 0000 0000 0000 0000 0000 0000 0000 ................
310+
00000010: 0000 0000 0000 0000 ........
311+
```
312+
281313
## Version Check
282314

283315
Check if the firmware version is what you expect, returns exit code 0 on

completions/bash/framework_tool

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ _framework_tool() {
2323

2424
case "${cmd}" in
2525
framework_tool)
26-
opts="-v -q -t -f -h --flash-gpu-descriptor --verbose --quiet --versions --version --features --esrt --device --compare-version --power --thermal --sensors --fansetduty --fansetrpm --autofanctrl --pdports --info --meinfo --pd-info --pd-reset --pd-disable --pd-enable --dp-hdmi-info --dp-hdmi-update --audio-card-info --privacy --pd-bin --ec-bin --capsule --dump --h2o-capsule --dump-ec-flash --flash-ec --flash-ro-ec --flash-rw-ec --intrusion --inputdeck --inputdeck-mode --expansion-bay --charge-limit --charge-current-limit --charge-rate-limit --get-gpio --fp-led-level --fp-brightness --kblight --remap-key --rgbkbd --ps2-enable --tablet-mode --touchscreen-enable --stylus-battery --console --reboot-ec --ec-hib-delay --uptimeinfo --s0ix-counter --hash --driver --pd-addrs --pd-ports --test --test-retimer --boardid --force --dry-run --flash-gpu-descriptor-file --dump-gpu-descriptor-file --nvidia --generate-completions --help"
26+
opts="-v -q -t -f -h --flash-gpu-descriptor --verbose --quiet --versions --version --features --esrt --device --compare-version --power --thermal --sensors --fansetduty --fansetrpm --autofanctrl --pdports --info --meinfo --pd-info --pd-reset --pd-disable --pd-enable --dp-hdmi-info --dp-hdmi-update --audio-card-info --privacy --pd-bin --ec-bin --capsule --dump --h2o-capsule --dump-ec-flash --flash-ec --flash-ro-ec --flash-rw-ec --intrusion --inputdeck --inputdeck-mode --expansion-bay --charge-limit --charge-current-limit --charge-rate-limit --get-gpio --fp-led-level --fp-brightness --kblight --remap-key --rgbkbd --ps2-enable --tablet-mode --touchscreen-enable --stylus-battery --console --reboot-ec --ec-hib-delay --uptimeinfo --s0ix-counter --hash --driver --pd-addrs --pd-ports --test --test-retimer --boardid --force --dry-run --flash-gpu-descriptor-file --dump-gpu-descriptor-file --nvidia --host-command --generate-completions --help"
2727
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
2828
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
2929
return 0
@@ -197,6 +197,10 @@ _framework_tool() {
197197
COMPREPLY=($(compgen -f "${cur}"))
198198
return 0
199199
;;
200+
--host-command)
201+
COMPREPLY=()
202+
return 0
203+
;;
200204
--generate-completions)
201205
COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}"))
202206
return 0

completions/fish/framework_tool.fish

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ complete -c framework_tool -l pd-addrs -d 'Specify I2C addresses of the PD chips
6464
complete -c framework_tool -l pd-ports -d 'Specify I2C ports of the PD chips (Advanced)' -r
6565
complete -c framework_tool -l flash-gpu-descriptor-file -d 'File to write to the gpu EEPROM' -r -F
6666
complete -c framework_tool -l dump-gpu-descriptor-file -d 'File to dump the gpu EEPROM to' -r -F
67+
complete -c framework_tool -l host-command -d 'Send an EC host command. Args: <CMD_ID> <VERSION> [DATA...]' -r
6768
complete -c framework_tool -l generate-completions -d 'Generate shell completions and print to stdout' -r -f -a "bash\t''
6869
elvish\t''
6970
fish\t''

completions/zsh/_framework_tool

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ _framework_tool() {
5757
'*--pd-ports=[Specify I2C ports of the PD chips (Advanced)]:PD_PORTS:_default:PD_PORTS:_default:PD_PORTS:_default' \
5858
'--flash-gpu-descriptor-file=[File to write to the gpu EEPROM]:FLASH_GPU_DESCRIPTOR_FILE:_files' \
5959
'--dump-gpu-descriptor-file=[File to dump the gpu EEPROM to]:DUMP_GPU_DESCRIPTOR_FILE:_files' \
60+
'*--host-command=[Send an EC host command. Args\: <CMD_ID> <VERSION> \[DATA...\]]:HOST_COMMAND:_default:HOST_COMMAND:_default' \
6061
'--generate-completions=[Generate shell completions and print to stdout]:SHELL:(bash elvish fish powershell zsh)' \
6162
'*-v[Increase logging verbosity]' \
6263
'*--verbose[Increase logging verbosity]' \

framework_lib/src/commandline/clap_std.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ struct ClapCli {
305305
#[arg(long)]
306306
nvidia: bool,
307307

308+
/// Send an EC host command. Args: <CMD_ID> <VERSION> [DATA...]
309+
#[arg(long, value_parser=maybe_hex::<u16>)]
310+
#[clap(num_args = 2..)]
311+
host_command: Vec<u16>,
312+
308313
/// Generate shell completions and print to stdout
309314
#[arg(long, value_name = "SHELL", hide = true)]
310315
generate_completions: Option<Shell>,
@@ -419,6 +424,37 @@ pub fn parse(args: &[String]) -> Cli {
419424
)),
420425
_ => None,
421426
};
427+
let host_command = if args.host_command.len() >= 2 {
428+
let cmd_ver = if let Ok(cmd_ver) = u8::try_from(args.host_command[1]) {
429+
cmd_ver
430+
} else {
431+
cli.error(
432+
ErrorKind::InvalidValue,
433+
"Second argument of --host-command must be a one byte command version",
434+
)
435+
.exit();
436+
};
437+
Some((
438+
args.host_command[0],
439+
cmd_ver as u8,
440+
args.host_command[2..]
441+
.iter()
442+
.map(|&x| {
443+
if let Ok(x) = u8::try_from(x) {
444+
x
445+
} else {
446+
cli.error(
447+
ErrorKind::InvalidValue,
448+
"All payload values of --host-command must be one byte each",
449+
)
450+
.exit();
451+
}
452+
})
453+
.collect(),
454+
))
455+
} else {
456+
None
457+
};
422458

423459
Cli {
424460
verbosity: LogLevel(args.verbosity.log_level_filter()),
@@ -517,6 +553,6 @@ pub fn parse(args: &[String]) -> Cli {
517553
.dump_gpu_descriptor_file
518554
.map(|x| x.into_os_string().into_string().unwrap()),
519555
nvidia: args.nvidia,
520-
raw_command: vec![],
556+
host_command,
521557
}
522558
}

framework_lib/src/commandline/mod.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use crate::chromium_ec::commands::RgbS;
4343
use crate::chromium_ec::commands::TabletModeOverride;
4444
use crate::chromium_ec::EcResponseStatus;
4545
use crate::chromium_ec::{print_err, EcFlashType};
46-
use crate::chromium_ec::{EcError, EcResult};
46+
use crate::chromium_ec::{CrosEcDriver, EcError, EcResult};
4747
use crate::csme;
4848
use crate::ec_binary;
4949
use crate::esrt::{self, ResourceType};
@@ -230,8 +230,7 @@ pub struct Cli {
230230
// UEFI only
231231
pub allupdate: bool,
232232
pub paginate: bool,
233-
// TODO: This is not actually implemented yet
234-
pub raw_command: Vec<String>,
233+
pub host_command: Option<(u16, u8, Vec<u8>)>,
235234
}
236235

237236
pub fn parse(args: &[String]) -> Cli {
@@ -316,7 +315,7 @@ pub fn parse(args: &[String]) -> Cli {
316315
nvidia: cli.nvidia,
317316
// allupdate
318317
paginate: cli.paginate,
319-
// raw_command
318+
// host_command
320319
..Default::default()
321320
}
322321
} else {
@@ -1603,9 +1602,18 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
16031602
} else {
16041603
println!("Not all EC versions support this comand.")
16051604
};
1606-
// TODO:
1607-
//} else if arg == "-raw-command" {
1608-
// raw_command(&args[1..]);
1605+
} else if let Some((command_id, command_version, ref data)) = args.host_command {
1606+
match ec.send_command(command_id, command_version, data) {
1607+
Ok(response) => {
1608+
println!("Response ({} bytes):", response.len());
1609+
if response.is_empty() {
1610+
println!(" (empty)");
1611+
} else {
1612+
util::print_multiline_buffer(&response, 0);
1613+
}
1614+
}
1615+
Err(e) => println!("EC command failed: {:?}", e),
1616+
}
16091617
} else if let Some(pd_bin_path) = &args.pd_bin {
16101618
#[cfg(feature = "uefi")]
16111619
let data: Option<Vec<u8>> = crate::uefi::fs::shell_read_file(pd_bin_path);

framework_lib/src/commandline/uefi.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub fn parse(args: &[String]) -> Cli {
9898
info: false,
9999
meinfo: None,
100100
nvidia: false,
101-
raw_command: vec![],
101+
host_command: None,
102102
};
103103

104104
if args.len() == 0 {
@@ -708,8 +708,39 @@ pub fn parse(args: &[String]) -> Cli {
708708
None
709709
};
710710
found_an_option = true;
711-
} else if arg == "--raw-command" {
712-
cli.raw_command = args[1..].to_vec();
711+
} else if arg == "--host-command" {
712+
cli.host_command = if args.len() > i + 2 {
713+
let cmd_id = parse_hex_or_dec_u16(&args[i + 1]);
714+
let version = parse_hex_or_dec_u8(&args[i + 2]);
715+
if let (Some(cmd_id), Some(version)) = (cmd_id, version) {
716+
let mut data = Vec::new();
717+
let mut parse_error = false;
718+
for j in (i + 3)..args.len() {
719+
if args[j].starts_with('-') {
720+
break;
721+
}
722+
if let Some(byte) = parse_hex_or_dec_u8(&args[j]) {
723+
data.push(byte);
724+
} else {
725+
println!("Invalid data byte for --host-command: '{}'", args[j]);
726+
parse_error = true;
727+
break;
728+
}
729+
}
730+
if parse_error {
731+
None
732+
} else {
733+
Some((cmd_id, version, data))
734+
}
735+
} else {
736+
println!("Invalid values for --host-command. Usage: --host-command <CMD_ID> <VERSION> [DATA...]");
737+
None
738+
}
739+
} else {
740+
println!("--host-command requires at least two arguments: <CMD_ID> <VERSION>");
741+
None
742+
};
743+
found_an_option = true;
713744
} else if arg == "--compare-version" {
714745
cli.compare_version = if args.len() > i + 1 {
715746
Some(args[i + 1].clone())
@@ -817,3 +848,19 @@ pub fn parse(args: &[String]) -> Cli {
817848

818849
cli
819850
}
851+
852+
fn parse_hex_or_dec_u16(s: &str) -> Option<u16> {
853+
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
854+
u16::from_str_radix(hex, 16).ok()
855+
} else {
856+
s.parse::<u16>().ok()
857+
}
858+
}
859+
860+
fn parse_hex_or_dec_u8(s: &str) -> Option<u8> {
861+
if let Some(hex) = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")) {
862+
u8::from_str_radix(hex, 16).ok()
863+
} else {
864+
s.parse::<u8>().ok()
865+
}
866+
}

0 commit comments

Comments
 (0)