Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Input: cros_ec_keyb - add function key support

Add support for handling an Fn button and sending separate keycodes for
a subset of keys in the matrix defined in the upper half of the keymap.

Signed-off-by: Fabio Baltieri <fabiobaltieri@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org>
Link: https://patch.msgid.link/20260222003717.471977-2-dmitry.torokhov@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Fabio Baltieri and committed by
Dmitry Torokhov
d8df8990 3d35d411

+165 -15
+165 -15
drivers/input/keyboard/cros_ec_keyb.c
··· 29 29 30 30 #include <linux/unaligned.h> 31 31 32 + /* 33 + * Maximum size of the normal key matrix, this is limited by the host command 34 + * key_matrix field defined in ec_response_get_next_data_v3 35 + */ 36 + #define CROS_EC_KEYBOARD_COLS_MAX 18 37 + 32 38 /** 33 39 * struct cros_ec_keyb - Structure representing EC keyboard device 34 40 * ··· 50 44 * @bs_idev: The input device for non-matrix buttons and switches (or NULL). 51 45 * @notifier: interrupt event notifier for transport devices 52 46 * @vdata: vivaldi function row data 47 + * @has_fn_map: whether the driver uses an fn function-map layer 48 + * @fn_active: tracks whether the function key is currently pressed 49 + * @fn_combo_active: tracks whether another key was pressed while fn is active 53 50 */ 54 51 struct cros_ec_keyb { 55 52 unsigned int rows; ··· 70 61 struct notifier_block notifier; 71 62 72 63 struct vivaldi_data vdata; 64 + 65 + bool has_fn_map; 66 + bool fn_active; 67 + bool fn_combo_active; 73 68 }; 74 69 75 70 /** ··· 179 166 return false; 180 167 } 181 168 169 + static void cros_ec_emit_fn_key(struct input_dev *input, unsigned int pos) 170 + { 171 + input_event(input, EV_MSC, MSC_SCAN, pos); 172 + input_report_key(input, KEY_FN, true); 173 + input_sync(input); 174 + 175 + input_event(input, EV_MSC, MSC_SCAN, pos); 176 + input_report_key(input, KEY_FN, false); 177 + } 178 + 179 + static void cros_ec_keyb_process_key_plain(struct cros_ec_keyb *ckdev, 180 + int row, int col, bool state) 181 + { 182 + struct input_dev *idev = ckdev->idev; 183 + const unsigned short *keycodes = idev->keycode; 184 + int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); 185 + 186 + input_event(idev, EV_MSC, MSC_SCAN, pos); 187 + input_report_key(idev, keycodes[pos], state); 188 + } 189 + 190 + static void cros_ec_keyb_process_key_fn_map(struct cros_ec_keyb *ckdev, 191 + int row, int col, bool state) 192 + { 193 + struct input_dev *idev = ckdev->idev; 194 + const unsigned short *keycodes = idev->keycode; 195 + unsigned int pos, fn_pos; 196 + unsigned int code, fn_code; 197 + 198 + pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); 199 + code = keycodes[pos]; 200 + 201 + if (code == KEY_FN) { 202 + ckdev->fn_active = state; 203 + if (state) { 204 + ckdev->fn_combo_active = false; 205 + } else if (!ckdev->fn_combo_active) { 206 + /* 207 + * Send both Fn press and release events if nothing 208 + * else has been pressed together with Fn. 209 + */ 210 + cros_ec_emit_fn_key(idev, pos); 211 + } 212 + return; 213 + } 214 + 215 + fn_pos = MATRIX_SCAN_CODE(row + ckdev->rows, col, ckdev->row_shift); 216 + fn_code = keycodes[fn_pos]; 217 + 218 + if (state) { 219 + if (ckdev->fn_active) { 220 + ckdev->fn_combo_active = true; 221 + if (!fn_code) 222 + return; /* Discard if no Fn mapping exists */ 223 + 224 + pos = fn_pos; 225 + code = fn_code; 226 + } 227 + } else { 228 + /* 229 + * If the Fn-remapped code is currently pressed, release it. 230 + * Otherwise, release the standard code (if it was pressed). 231 + */ 232 + if (fn_code && test_bit(fn_code, idev->key)) { 233 + pos = fn_pos; 234 + code = fn_code; 235 + } else if (!test_bit(code, idev->key)) { 236 + return; /* Discard, key press code was not sent */ 237 + } 238 + } 239 + 240 + input_event(idev, EV_MSC, MSC_SCAN, pos); 241 + input_report_key(idev, code, state); 242 + } 182 243 183 244 /* 184 245 * Compares the new keyboard state to the old one and produces key 185 - * press/release events accordingly. The keyboard state is 13 bytes (one byte 186 - * per column) 246 + * press/release events accordingly. The keyboard state is one byte 247 + * per column. 187 248 */ 188 249 static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, 189 250 uint8_t *kb_state, int len) 190 251 { 191 - struct input_dev *idev = ckdev->idev; 192 252 int col, row; 193 253 int new_state; 194 254 int old_state; ··· 278 192 279 193 for (col = 0; col < ckdev->cols; col++) { 280 194 for (row = 0; row < ckdev->rows; row++) { 281 - int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); 282 - const unsigned short *keycodes = idev->keycode; 283 - 284 195 new_state = kb_state[col] & (1 << row); 285 196 old_state = ckdev->old_kb_state[col] & (1 << row); 286 - if (new_state != old_state) { 287 - dev_dbg(ckdev->dev, 288 - "changed: [r%d c%d]: byte %02x\n", 289 - row, col, new_state); 290 197 291 - input_event(idev, EV_MSC, MSC_SCAN, pos); 292 - input_report_key(idev, keycodes[pos], 293 - new_state); 294 - } 198 + if (new_state == old_state) 199 + continue; 200 + 201 + dev_dbg(ckdev->dev, "changed: [r%d c%d]: byte %02x\n", 202 + row, col, new_state); 203 + 204 + if (ckdev->has_fn_map) 205 + cros_ec_keyb_process_key_fn_map(ckdev, row, col, new_state); 206 + else 207 + cros_ec_keyb_process_key_plain(ckdev, row, col, new_state); 295 208 } 296 209 ckdev->old_kb_state[col] = kb_state[col]; 297 210 } ··· 668 583 ckdev->vdata.num_function_row_keys = n_physmap; 669 584 } 670 585 586 + /* Returns true if there is a KEY_FN code defined in the normal keymap */ 587 + static bool cros_ec_keyb_has_fn_key(struct cros_ec_keyb *ckdev) 588 + { 589 + const unsigned short *keycodes = ckdev->idev->keycode; 590 + int i; 591 + 592 + for (i = 0; i < MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); i++) { 593 + if (keycodes[i] == KEY_FN) 594 + return true; 595 + } 596 + 597 + return false; 598 + } 599 + 600 + /* 601 + * Returns true if there is a KEY_FN defined and at least one key in the fn 602 + * layer keymap 603 + */ 604 + static bool cros_ec_keyb_has_fn_map(struct cros_ec_keyb *ckdev) 605 + { 606 + struct input_dev *idev = ckdev->idev; 607 + const unsigned short *keycodes = ckdev->idev->keycode; 608 + int i; 609 + 610 + if (!cros_ec_keyb_has_fn_key(ckdev)) 611 + return false; 612 + 613 + for (i = MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); 614 + i < idev->keycodemax; i++) { 615 + if (keycodes[i] != KEY_RESERVED) 616 + return true; 617 + } 618 + 619 + return false; 620 + } 621 + 622 + /* 623 + * Custom handler for the set keycode ioctl, calls the default handler and 624 + * recomputes has_fn_map. 625 + */ 626 + static int cros_ec_keyb_setkeycode(struct input_dev *idev, 627 + const struct input_keymap_entry *ke, 628 + unsigned int *old_keycode) 629 + { 630 + struct cros_ec_keyb *ckdev = input_get_drvdata(idev); 631 + int ret; 632 + 633 + ret = input_default_setkeycode(idev, ke, old_keycode); 634 + if (ret) 635 + return ret; 636 + 637 + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); 638 + 639 + return 0; 640 + } 641 + 671 642 /** 672 643 * cros_ec_keyb_register_matrix - Register matrix keys 673 644 * ··· 744 603 err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols); 745 604 if (err) 746 605 return err; 606 + 607 + if (ckdev->cols > CROS_EC_KEYBOARD_COLS_MAX) { 608 + dev_err(dev, "keypad,num-columns too large: %d (max: %d)\n", 609 + ckdev->cols, CROS_EC_KEYBOARD_COLS_MAX); 610 + return -EINVAL; 611 + } 747 612 748 613 ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); 749 614 if (!ckdev->valid_keys) ··· 779 632 idev->id.version = 1; 780 633 idev->id.product = 0; 781 634 idev->dev.parent = dev; 635 + idev->setkeycode = cros_ec_keyb_setkeycode; 782 636 783 637 ckdev->ghost_filter = device_property_read_bool(dev, 784 638 "google,needs-ghost-filter"); 785 639 786 - err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, 640 + err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows * 2, ckdev->cols, 787 641 NULL, idev); 788 642 if (err) { 789 643 dev_err(dev, "cannot build key matrix\n"); ··· 798 650 ckdev->idev = idev; 799 651 cros_ec_keyb_compute_valid_keys(ckdev); 800 652 cros_ec_keyb_parse_vivaldi_physmap(ckdev); 653 + 654 + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); 801 655 802 656 err = input_register_device(ckdev->idev); 803 657 if (err) {