diff --git a/src/board/system76/common/smfi.c b/src/board/system76/common/smfi.c index 1fc6557..752e445 100644 --- a/src/board/system76/common/smfi.c +++ b/src/board/system76/common/smfi.c @@ -6,6 +6,7 @@ #ifndef __SCRATCH__ #include + #include #endif #include #include @@ -178,6 +179,39 @@ static enum Result cmd_fan_set(void) { // Failed if fan not found return RES_ERR; } + +static enum Result cmd_keymap_get(void) { + int layer = smfi_cmd[2]; + int output = smfi_cmd[3]; + int input = smfi_cmd[4]; + + if (layer < KM_LAY && output < KM_OUT && input < KM_IN) { + uint16_t key = KEYMAP[layer][output][input]; + smfi_cmd[5] = (uint8_t)key; + smfi_cmd[6] = (uint8_t)(key >> 8); + return RES_OK; + } + + // Failed if keyboard mapping not found + return RES_ERR; +} + +static enum Result cmd_keymap_set(void) { + int layer = smfi_cmd[2]; + int output = smfi_cmd[3]; + int input = smfi_cmd[4]; + + if (layer < KM_LAY && output < KM_OUT && input < KM_IN) { + uint16_t key = + ((uint16_t)smfi_cmd[5]) | + (((uint16_t)smfi_cmd[6]) << 8); + KEYMAP[layer][output][input] = key; + return RES_OK; + } + + // Failed if keyboard mapping not found + return RES_ERR; +} #endif // Set a watchdog timer of 10 seconds @@ -230,6 +264,12 @@ void smfi_event(void) { case CMD_FAN_SET: smfi_cmd[1] = cmd_fan_set(); break; + case CMD_KEYMAP_GET: + smfi_cmd[1] = cmd_keymap_get(); + break; + case CMD_KEYMAP_SET: + smfi_cmd[1] = cmd_keymap_set(); + break; #endif // __SCRATCH__ default: // Command not found diff --git a/src/common/include/common/command.h b/src/common/include/common/command.h index 2b8eafc..e9f442e 100644 --- a/src/common/include/common/command.h +++ b/src/common/include/common/command.h @@ -22,6 +22,10 @@ enum Command { CMD_FAN_GET = 7, // Set fan speeds CMD_FAN_SET = 8, + // Get keyboard map index + CMD_KEYMAP_GET = 9, + // Set keyboard map index + CMD_KEYMAP_SET = 10, //TODO }; diff --git a/tool/src/ec.rs b/tool/src/ec.rs index 8974739..455a31e 100644 --- a/tool/src/ec.rs +++ b/tool/src/ec.rs @@ -21,6 +21,8 @@ pub enum Cmd { Reset = 6, FanGet = 7, FanSet = 8, + KeymapGet = 9, + KeymapSet = 10, } pub const CMD_SPI_FLAG_READ: u8 = 1 << 0; @@ -195,6 +197,26 @@ impl Ec { self.write(3, duty); self.command(Cmd::FanSet) } + + pub unsafe fn keymap_get(&mut self, layer: u8, output: u8, input: u8) -> Result { + self.write(2, layer); + self.write(3, output); + self.write(4, input); + self.command(Cmd::KeymapGet)?; + Ok( + (self.read(5) as u16) | + ((self.read(6) as u16) << 8) + ) + } + + pub unsafe fn keymap_set(&mut self, layer: u8, output: u8, input: u8, value: u16) -> Result<(), Error> { + self.write(2, layer); + self.write(3, output); + self.write(4, input); + self.write(5, value as u8); + self.write(6, (value >> 8) as u8); + self.command(Cmd::KeymapSet) + } } pub struct EcSpi<'a, T: Timeout> { diff --git a/tool/src/main.rs b/tool/src/main.rs index d9c4b83..eea6100 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -12,7 +12,7 @@ use std::{ fs, io, process, - str, + str::{self, FromStr}, time::{Duration, Instant}, thread, }; @@ -296,18 +296,64 @@ unsafe fn fan_set(index: u8, duty: u8) -> Result<(), Error> { ec.fan_set(index, duty) } +unsafe fn keymap_get(layer: u8, output: u8, input: u8) -> Result<(), Error> { + iopl(); + + let mut ec = Ec::new( + StdTimeout::new(Duration::new(1, 0)), + )?; + + let value = ec.keymap_get(layer, output, input)?; + println!("{:04X}", value); + + Ok(()) +} + +unsafe fn keymap_set(layer: u8, output: u8, input: u8, value: u16) -> Result<(), Error> { + iopl(); + + let mut ec = Ec::new( + StdTimeout::new(Duration::new(1, 0)), + )?; + + ec.keymap_set(layer, output, input, value) +} + fn usage() { eprintln!(" console"); eprintln!(" flash [file]"); eprintln!(" flash_backup [file]"); eprintln!(" fan [index] "); eprintln!(" info"); + eprintln!(" keymap [layer] [output] [input] "); eprintln!(" print [message]"); } +fn parse_arg_opt, F: FromStr>(args: &mut I, name: &str) -> Option { + match args.next() { + Some(arg) => match arg.parse::() { + Ok(ok) => Some(ok), + Err(_err) => { + eprintln!("failed to parse {}: '{}'", name, arg); + process::exit(1); + }, + }, + None => None, + } +} + +fn parse_arg, F: FromStr>(args: &mut I, name: &str) -> F { + match parse_arg_opt(args, name) { + Some(some) => some, + None => { + eprintln!("no {} provided", name); + process::exit(1); + } + } +} + fn main() { let mut args = env::args().skip(1); - match args.next() { Some(arg) => match arg.as_str() { "console" => match unsafe { console() } { @@ -317,39 +363,25 @@ fn main() { process::exit(1); }, }, - "fan" => match args.next() { - Some(index_str) => match index_str.parse::() { - Ok(index) => match args.next() { - Some(duty_str) => match duty_str.parse::() { - Ok(duty) => match unsafe { fan_set(index, duty) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to set fan {} to {}: {:X?}", index, duty, err); - process::exit(1); - }, - }, - Err(err) => { - eprintln!("failed to parse '{}': {:X?}", duty_str, err); - process::exit(1); - }, - }, - None => match unsafe { fan_get(index) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to get fan {}: {:X?}", index, err); - process::exit(1); - }, + "fan" => { + let index = parse_arg(&mut args, "index"); + let duty_opt = parse_arg_opt(&mut args, "duty"); + match duty_opt { + Some(duty) => match unsafe { fan_set(index, duty) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to set fan {} to {}: {:X?}", index, duty, err); + process::exit(1); }, }, - Err(err) => { - eprintln!("failed to parse '{}': {:X?}", index_str, err); - process::exit(1); + None => match unsafe { fan_get(index) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to get fan {}: {:X?}", index, err); + process::exit(1); + }, }, - }, - None => { - eprintln!("no index provided"); - process::exit(1); - }, + } }, "flash" => match args.next() { Some(path) => match unsafe { flash(&path, SpiTarget::Main) } { @@ -384,6 +416,33 @@ fn main() { process::exit(1); }, }, + "keymap" => { + let layer = parse_arg(&mut args, "layer"); + let output = parse_arg(&mut args, "output"); + let input = parse_arg(&mut args, "input"); + match args.next() { + Some(value_str) => match u16::from_str_radix(&value_str, 16) { + Ok(value) => match unsafe { keymap_set(layer, output, input, value) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to set keymap {}, {}, {} to {}: {:X?}", layer, output, input, value, err); + process::exit(1); + }, + }, + Err(err) => { + eprintln!("failed to parse value: '{}': {}", arg, err); + process::exit(1); + } + }, + None => match unsafe { keymap_get(layer, output, input) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to get keymap {}, {}, {}: {:X?}", layer, output, input, err); + process::exit(1); + }, + }, + } + }, "print" => for mut arg in args { arg.push('\n'); match unsafe { print(&arg.as_bytes()) } {