From 80591104d606ab366c6b408ba98db847fd15c560 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 2 Nov 2024 18:21:42 -0400 Subject: [PATCH] fwk: add option to emit HID display toggle from F9 display key By default, this key emits Win+P, which is not portable to non-QWERTY keyboard layouts and non-Windows OSes. This adds an option (off by default, set with 0x3E16 flag) to emit the HID display toggle key instead. This should be exposed in the BIOS settings. Signed-off-by: Jules Bertholet --- board/hx20/host_command_customization.c | 10 +++++++ board/hx20/host_command_customization.h | 8 +++++ board/hx20/i2c_hid_mediakeys.c | 39 +++++++++++++++++++++++-- board/hx20/i2c_hid_mediakeys.h | 2 +- board/hx20/keyboard_customization.c | 17 +++++++---- board/hx20/keyboard_customization.h | 2 ++ board/hx30/host_command_customization.c | 10 +++++++ board/hx30/host_command_customization.h | 8 +++++ board/hx30/i2c_hid_mediakeys.c | 39 +++++++++++++++++++++++-- board/hx30/i2c_hid_mediakeys.h | 1 + board/hx30/keyboard_customization.c | 17 +++++++---- board/hx30/keyboard_customization.h | 2 ++ 12 files changed, 140 insertions(+), 15 deletions(-) diff --git a/board/hx20/host_command_customization.c b/board/hx20/host_command_customization.c index a98f8eb8bf..2b90d445ec 100644 --- a/board/hx20/host_command_customization.c +++ b/board/hx20/host_command_customization.c @@ -290,3 +290,13 @@ static enum ec_status standalone_mode(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_STANDALONE_MODE, standalone_mode, EC_VER_MASK(0)); + +static enum ec_status display_toggle_key_hid(struct host_cmd_handler_args *args) +{ + const struct ec_params_display_toggle_key_hid *p = args->params; + + set_display_toggle_key_hid(p->enable); + return EC_RES_SUCCESS; + +} +DECLARE_HOST_COMMAND(EC_CMD_DISPLAY_TOGGLE_KEY_HID, display_toggle_key_hid, EC_VER_MASK(0)); diff --git a/board/hx20/host_command_customization.h b/board/hx20/host_command_customization.h index 12ceaa81a7..5f8a44bb3f 100644 --- a/board/hx20/host_command_customization.h +++ b/board/hx20/host_command_customization.h @@ -203,4 +203,12 @@ struct ec_params_standalone_mode { uint8_t enable; } __ec_align1; +/* If enabled, display key emits HID System Display Toggle Int/Ext Mode; + otherwise emits Win+P */ +#define EC_CMD_DISPLAY_TOGGLE_KEY_HID 0x3E16 + +struct ec_params_display_toggle_key_hid { + uint8_t enable; +} __ec_align1; + #endif /* __HOST_COMMAND_CUSTOMIZATION_H */ diff --git a/board/hx20/i2c_hid_mediakeys.c b/board/hx20/i2c_hid_mediakeys.c index bf0cd7576f..f7a3466a53 100644 --- a/board/hx20/i2c_hid_mediakeys.c +++ b/board/hx20/i2c_hid_mediakeys.c @@ -23,6 +23,7 @@ #define REPORT_ID_RADIO 0x01 #define REPORT_ID_CONSUMER 0x02 +#define REPORT_ID_DISPLAY 0x04 /* * See hid usage tables for consumer page @@ -49,8 +50,13 @@ struct consumer_button_report { uint16_t button_id; } __packed; +struct display_report { + uint8_t state; +} __packed; + static struct radio_report radio_button; static struct consumer_button_report consumer_button; +static struct display_report display_button; int update_hid_key(enum media_key key, bool pressed) @@ -58,7 +64,7 @@ int update_hid_key(enum media_key key, bool pressed) if (key >= HID_KEY_MAX) { return EC_ERROR_INVAL; } - if (key == HID_KEY_AIRPLANE_MODE) { + if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) { key_states[key] = pressed; if (pressed) task_set_event(TASK_ID_HID, 1 << key, 0); @@ -121,6 +127,20 @@ static const uint8_t report_desc[] = { 0x81, 0x00, /* Input (Data,Arr,Abs) */ 0xC0, /* END_COLLECTION */ + /* Display Toggle Collection */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x80, /* USAGE (System Control) */ + 0xA1, 0x01, /* COLLECTION (Application) */ + 0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ + 0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ + 0x75, 0x07, /* REPORT_SIZE (7) */ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ + 0xC0, /* END_COLLECTION */ }; @@ -220,6 +240,12 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer) &consumer_button, sizeof(struct consumer_button_report)); break; + case REPORT_ID_DISPLAY: + response_len = + fill_report(buffer, report_id, + &display_button, + sizeof(struct display_report)); + break; default: response_len = 2; buffer[0] = response_len; @@ -297,11 +323,16 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer) fill_report(buffer, REPORT_ID_RADIO, &radio_button, sizeof(struct radio_report)); - } else { + } else if (input_mode == REPORT_ID_CONSUMER) { response_len = fill_report(buffer, REPORT_ID_CONSUMER, &consumer_button, sizeof(struct consumer_button_report)); + } else if (input_mode == REPORT_ID_DISPLAY) { + response_len = + fill_report(buffer, REPORT_ID_DISPLAY, + &display_button, + sizeof(struct display_report)); } break; case I2C_HID_COMMAND_REGISTER: @@ -399,6 +430,10 @@ void hid_handler_task(void *p) input_mode = REPORT_ID_RADIO; radio_button.state = key_states[i] ? 1 : 0; break; + case HID_KEY_DISPLAY_TOGGLE: + input_mode = REPORT_ID_DISPLAY; + display_button.state = key_states[i] ? 1 : 0; + break; } hid_irq_to_host(); } diff --git a/board/hx20/i2c_hid_mediakeys.h b/board/hx20/i2c_hid_mediakeys.h index 50a60a5a2e..52797647ef 100644 --- a/board/hx20/i2c_hid_mediakeys.h +++ b/board/hx20/i2c_hid_mediakeys.h @@ -28,7 +28,7 @@ enum media_key { HID_KEY_DISPLAY_BRIGHTNESS_UP, HID_KEY_DISPLAY_BRIGHTNESS_DN, HID_KEY_AIRPLANE_MODE, - + HID_KEY_DISPLAY_TOGGLE, HID_KEY_MAX }; /*HID_KEY_MAX cannot be > TASK_EVENT_CUSTOM_BIT*/ diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c index 2b91f2e0c1..32bebb7b7d 100644 --- a/board/hx20/keyboard_customization.c +++ b/board/hx20/keyboard_customization.c @@ -216,6 +216,14 @@ void board_kblight_init(void) } #endif +uint8_t display_toggle_key_hid = 0; + +void set_display_toggle_key_hid(uint8_t enable) +{ + CPRINTS("set display_toggle_key_hid = %hhd", enable); + display_toggle_key_hid = enable; +} + #ifdef CONFIG_KEYBOARD_CUSTOMIZATION_COMBINATION_KEY #define FN_PRESSED BIT(0) #define FN_LOCKED BIT(1) @@ -329,12 +337,11 @@ int hotkey_F1_F12(uint16_t *key_code, uint16_t fn, int8_t pressed) break; case SCANCODE_F9: /* EXTERNAL_DISPLAY */ if (fn_table_media_set(pressed, KB_FN_F9)) { - if (pressed) { - simulate_keyboard(SCANCODE_LEFT_WIN, 1); - simulate_keyboard(SCANCODE_P, 1); + if (display_toggle_key_hid) { + update_hid_key(HID_KEY_DISPLAY_TOGGLE, pressed); } else { - simulate_keyboard(SCANCODE_P, 0); - simulate_keyboard(SCANCODE_LEFT_WIN, 0); + simulate_keyboard(SCANCODE_LEFT_WIN, pressed); + simulate_keyboard(SCANCODE_P, pressed); } return EC_ERROR_UNIMPLEMENTED; } diff --git a/board/hx20/keyboard_customization.h b/board/hx20/keyboard_customization.h index bda89c4d8c..b173eeff24 100644 --- a/board/hx20/keyboard_customization.h +++ b/board/hx20/keyboard_customization.h @@ -112,4 +112,6 @@ int factory_status(void); void hx20_8042_led_control(int data); #endif +void set_display_toggle_key_hid(uint8_t enable); + #endif /* __KEYBOARD_CUSTOMIZATION_H */ diff --git a/board/hx30/host_command_customization.c b/board/hx30/host_command_customization.c index 8dcf1fc761..394e5c0822 100644 --- a/board/hx30/host_command_customization.c +++ b/board/hx30/host_command_customization.c @@ -353,3 +353,13 @@ static enum ec_status standalone_mode(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_STANDALONE_MODE, standalone_mode, EC_VER_MASK(0)); +static enum ec_status display_toggle_key_hid(struct host_cmd_handler_args *args) +{ + const struct ec_params_display_toggle_key_hid *p = args->params; + + set_display_toggle_key_hid(p->enable); + return EC_RES_SUCCESS; + +} +DECLARE_HOST_COMMAND(EC_CMD_DISPLAY_TOGGLE_KEY_HID, display_toggle_key_hid, EC_VER_MASK(0)); + diff --git a/board/hx30/host_command_customization.h b/board/hx30/host_command_customization.h index aae3345efb..1f9744ca03 100644 --- a/board/hx30/host_command_customization.h +++ b/board/hx30/host_command_customization.h @@ -229,4 +229,12 @@ struct ec_response_chassis_counter { uint8_t press_counter; } __ec_align1; +/* If enabled, display key emits HID System Display Toggle Int/Ext Mode; + otherwise emits Win+P */ +#define EC_CMD_DISPLAY_TOGGLE_KEY_HID 0x3E16 + +struct ec_params_display_toggle_key_hid { + uint8_t enable; +} __ec_align1; + #endif /* __HOST_COMMAND_CUSTOMIZATION_H */ diff --git a/board/hx30/i2c_hid_mediakeys.c b/board/hx30/i2c_hid_mediakeys.c index 57dfe34f65..4580fb9c44 100644 --- a/board/hx30/i2c_hid_mediakeys.c +++ b/board/hx30/i2c_hid_mediakeys.c @@ -25,6 +25,7 @@ #define REPORT_ID_RADIO 0x01 #define REPORT_ID_CONSUMER 0x02 #define REPORT_ID_SENSOR 0x03 +#define REPORT_ID_DISPLAY 0x04 #define ALS_REPORT_STOP 0x00 #define ALS_REPORT_POLLING 0x01 @@ -74,18 +75,22 @@ struct als_feature_report { uint16_t minimum; } __packed; +struct display_report { + uint8_t state; +} __packed; static struct radio_report radio_button; static struct consumer_button_report consumer_button; static struct als_input_report als_sensor; static struct als_feature_report als_feature; +static struct display_report display_button; int update_hid_key(enum media_key key, bool pressed) { if (key >= HID_KEY_MAX) { return EC_ERROR_INVAL; } - if (key == HID_KEY_AIRPLANE_MODE) { + if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) { key_states[key] = pressed; if (pressed) task_set_event(TASK_ID_HID, 1 << key, 0); @@ -285,6 +290,21 @@ static const uint8_t report_desc[] = { 0x95, 0x01, /* Report Count (1) */ 0x81, 0x02, /* Input (Data,Arr,Abs) */ 0xC0, /* END_COLLECTION */ + + /* Display Toggle Collection */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x80, /* USAGE (System Control) */ + 0xA1, 0x01, /* COLLECTION (Application) */ + 0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */ + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ + 0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x75, 0x01, /* REPORT_SIZE (1) */ + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ + 0x75, 0x07, /* REPORT_SIZE (7) */ + 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ + 0xC0, /* END_COLLECTION */ }; @@ -478,6 +498,12 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer) sizeof(struct als_feature_report)); } break; + case REPORT_ID_DISPLAY: + response_len = + fill_report(buffer, report_id, + &display_button, + sizeof(struct display_report)); + break; default: response_len = 2; buffer[0] = response_len; @@ -564,7 +590,12 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer) fill_report(buffer, REPORT_ID_SENSOR, &als_sensor, sizeof(struct als_input_report)); - } + } else if (input_mode == REPORT_ID_DISPLAY) { + response_len = + fill_report(buffer, REPORT_ID_DISPLAY, + &display_button, + sizeof(struct display_report)); + } break; case I2C_HID_COMMAND_REGISTER: response_len = i2c_hid_touchpad_command_process(len, buffer); @@ -673,6 +704,10 @@ void hid_handler_task(void *p) input_mode = REPORT_ID_RADIO; radio_button.state = key_states[i] ? 1 : 0; break; + case HID_KEY_DISPLAY_TOGGLE: + input_mode = REPORT_ID_DISPLAY; + display_button.state = key_states[i] ? 1 : 0; + break; case HID_ALS_REPORT_LUX: input_mode = REPORT_ID_SENSOR; diff --git a/board/hx30/i2c_hid_mediakeys.h b/board/hx30/i2c_hid_mediakeys.h index 9635890dce..02b4f41cb5 100644 --- a/board/hx30/i2c_hid_mediakeys.h +++ b/board/hx30/i2c_hid_mediakeys.h @@ -81,6 +81,7 @@ enum media_key { HID_KEY_DISPLAY_BRIGHTNESS_UP, HID_KEY_DISPLAY_BRIGHTNESS_DN, HID_KEY_AIRPLANE_MODE, + HID_KEY_DISPLAY_TOGGLE, HID_ALS_REPORT_LUX, HID_KEY_MAX }; diff --git a/board/hx30/keyboard_customization.c b/board/hx30/keyboard_customization.c index 2b91f2e0c1..32bebb7b7d 100644 --- a/board/hx30/keyboard_customization.c +++ b/board/hx30/keyboard_customization.c @@ -216,6 +216,14 @@ void board_kblight_init(void) } #endif +uint8_t display_toggle_key_hid = 0; + +void set_display_toggle_key_hid(uint8_t enable) +{ + CPRINTS("set display_toggle_key_hid = %hhd", enable); + display_toggle_key_hid = enable; +} + #ifdef CONFIG_KEYBOARD_CUSTOMIZATION_COMBINATION_KEY #define FN_PRESSED BIT(0) #define FN_LOCKED BIT(1) @@ -329,12 +337,11 @@ int hotkey_F1_F12(uint16_t *key_code, uint16_t fn, int8_t pressed) break; case SCANCODE_F9: /* EXTERNAL_DISPLAY */ if (fn_table_media_set(pressed, KB_FN_F9)) { - if (pressed) { - simulate_keyboard(SCANCODE_LEFT_WIN, 1); - simulate_keyboard(SCANCODE_P, 1); + if (display_toggle_key_hid) { + update_hid_key(HID_KEY_DISPLAY_TOGGLE, pressed); } else { - simulate_keyboard(SCANCODE_P, 0); - simulate_keyboard(SCANCODE_LEFT_WIN, 0); + simulate_keyboard(SCANCODE_LEFT_WIN, pressed); + simulate_keyboard(SCANCODE_P, pressed); } return EC_ERROR_UNIMPLEMENTED; } diff --git a/board/hx30/keyboard_customization.h b/board/hx30/keyboard_customization.h index 8b8bdcc145..d120d93a7a 100644 --- a/board/hx30/keyboard_customization.h +++ b/board/hx30/keyboard_customization.h @@ -112,4 +112,6 @@ int factory_status(void); void hx20_8042_led_control(int data); #endif +void set_display_toggle_key_hid(uint8_t enable); + #endif /* __KEYBOARD_CUSTOMIZATION_H */