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

Input: extract ChromeOS vivaldi physmap show function

Let's introduce a common library file for the physmap show function
duplicated between three different keyboard drivers. This largely copies
the code from cros_ec_keyb.c which has the most recent version of the
show function, while using the vivaldi_data struct from the hid-vivaldi
driver. This saves a small amount of space in an allyesconfig build.

$ ./scripts/bloat-o-meter vmlinux.before vmlinux.after

add/remove: 3/0 grow/shrink: 2/3 up/down: 412/-720 (-308)
Function old new delta
vivaldi_function_row_physmap_show - 292 +292
_sub_I_65535_1 1057564 1057616 +52
_sub_D_65535_0 1057564 1057616 +52
e843419@49f2_00062737_9b04 - 8 +8
e843419@20f6_0002a34d_35bc - 8 +8
atkbd_parse_fwnode_data 480 472 -8
atkbd_do_show_function_row_physmap 316 76 -240
function_row_physmap_show 620 148 -472
Total: Before=285581925, After=285581617, chg -0.00%

Signed-off-by: Stephen Boyd <swboyd@chromium.org>
Tested-by: Stephen Boyd <swboyd@chromium.org> # coachz, wormdingler
Link: https://lore.kernel.org/r/20220228075446.466016-3-dmitry.torokhov@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Stephen Boyd and committed by
Dmitry Torokhov
45ceaf14 d950db3f

+108 -66
+1
drivers/hid/Kconfig
··· 411 411 412 412 config HID_VIVALDI 413 413 tristate "Vivaldi Keyboard" 414 + select INPUT_VIVALDIFMAP 414 415 depends on HID 415 416 help 416 417 Say Y here if you want to enable support for Vivaldi keyboards.
+7 -20
drivers/hid/hid-vivaldi.c
··· 8 8 9 9 #include <linux/device.h> 10 10 #include <linux/hid.h> 11 + #include <linux/input/vivaldi-fmap.h> 11 12 #include <linux/kernel.h> 12 13 #include <linux/module.h> 13 14 #include <linux/sysfs.h> 14 15 15 - #define MIN_FN_ROW_KEY 1 16 - #define MAX_FN_ROW_KEY 24 16 + #define MIN_FN_ROW_KEY 1 17 + #define MAX_FN_ROW_KEY VIVALDI_MAX_FUNCTION_ROW_KEYS 17 18 #define HID_VD_FN_ROW_PHYSMAP 0x00000001 18 19 #define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) 19 - 20 - struct vivaldi_data { 21 - u32 function_row_physmap[MAX_FN_ROW_KEY - MIN_FN_ROW_KEY + 1]; 22 - int max_function_row_key; 23 - }; 24 20 25 21 static ssize_t function_row_physmap_show(struct device *dev, 26 22 struct device_attribute *attr, ··· 24 28 { 25 29 struct hid_device *hdev = to_hid_device(dev); 26 30 struct vivaldi_data *drvdata = hid_get_drvdata(hdev); 27 - ssize_t size = 0; 28 - int i; 29 31 30 - if (!drvdata->max_function_row_key) 31 - return 0; 32 - 33 - for (i = 0; i < drvdata->max_function_row_key; i++) 34 - size += sprintf(buf + size, "%02X ", 35 - drvdata->function_row_physmap[i]); 36 - size += sprintf(buf + size, "\n"); 37 - return size; 32 + return vivaldi_function_row_physmap_show(drvdata, buf); 38 33 } 39 34 40 35 static DEVICE_ATTR_RO(function_row_physmap); ··· 72 85 (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) 73 86 return; 74 87 75 - fn_key = (usage->hid & HID_USAGE); 88 + fn_key = usage->hid & HID_USAGE; 76 89 if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY) 77 90 return; 78 - if (fn_key > drvdata->max_function_row_key) 79 - drvdata->max_function_row_key = fn_key; 91 + if (fn_key > drvdata->num_function_row_keys) 92 + drvdata->num_function_row_keys = fn_key; 80 93 81 94 report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL); 82 95 if (!report_data)
+7
drivers/input/Kconfig
··· 77 77 To compile this driver as a module, choose M here: the 78 78 module will be called matrix-keymap. 79 79 80 + config INPUT_VIVALDIFMAP 81 + tristate 82 + help 83 + ChromeOS Vivaldi keymap support library. This is a hidden 84 + option so that drivers can use common code to parse and 85 + expose the vivaldi function row keymap. 86 + 80 87 comment "Userland interfaces" 81 88 82 89 config INPUT_MOUSEDEV
+1
drivers/input/Makefile
··· 12 12 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o 13 13 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o 14 14 obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o 15 + obj-$(CONFIG_INPUT_VIVALDIFMAP) += vivaldi-fmap.o 15 16 16 17 obj-$(CONFIG_INPUT_LEDS) += input-leds.o 17 18 obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
+2
drivers/input/keyboard/Kconfig
··· 103 103 select SERIO_LIBPS2 104 104 select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO 105 105 select SERIO_GSCPS2 if GSC 106 + select INPUT_VIVALDIFMAP 106 107 help 107 108 Say Y here if you want to use a standard AT or PS/2 keyboard. Usually 108 109 you'll need this, unless you have a different type keyboard (USB, ADB ··· 750 749 config KEYBOARD_CROS_EC 751 750 tristate "ChromeOS EC keyboard" 752 751 select INPUT_MATRIXKMAP 752 + select INPUT_VIVALDIFMAP 753 753 depends on CROS_EC 754 754 help 755 755 Say Y here to enable the matrix keyboard used by ChromeOS devices
+8 -19
drivers/input/keyboard/atkbd.c
··· 19 19 #include <linux/interrupt.h> 20 20 #include <linux/init.h> 21 21 #include <linux/input.h> 22 + #include <linux/input/vivaldi-fmap.h> 22 23 #include <linux/serio.h> 23 24 #include <linux/workqueue.h> 24 25 #include <linux/libps2.h> ··· 64 63 static bool atkbd_terminal; 65 64 module_param_named(terminal, atkbd_terminal, bool, 0); 66 65 MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2"); 67 - 68 - #define MAX_FUNCTION_ROW_KEYS 24 69 66 70 67 #define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) 71 68 #define KEYCODE(keymap) (keymap & 0xFFFF) ··· 236 237 /* Serializes reconnect(), attr->set() and event work */ 237 238 struct mutex mutex; 238 239 239 - u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS]; 240 - int num_function_row_keys; 240 + struct vivaldi_data vdata; 241 241 }; 242 242 243 243 /* ··· 306 308 307 309 static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf) 308 310 { 309 - ssize_t size = 0; 310 - int i; 311 - 312 - if (!atkbd->num_function_row_keys) 313 - return 0; 314 - 315 - for (i = 0; i < atkbd->num_function_row_keys; i++) 316 - size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ", 317 - atkbd->function_row_physmap[i]); 318 - size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); 319 - return size; 311 + return vivaldi_function_row_physmap_show(&atkbd->vdata, buf); 320 312 } 321 313 322 314 static umode_t atkbd_attr_is_visible(struct kobject *kobj, ··· 317 329 struct atkbd *atkbd = serio_get_drvdata(serio); 318 330 319 331 if (attr == &atkbd_attr_function_row_physmap.attr && 320 - !atkbd->num_function_row_keys) 332 + !atkbd->vdata.num_function_row_keys) 321 333 return 0; 322 334 323 335 return attr->mode; ··· 1194 1206 1195 1207 /* Parse "function-row-physmap" property */ 1196 1208 n = device_property_count_u32(dev, "function-row-physmap"); 1197 - if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS && 1209 + if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS && 1198 1210 !device_property_read_u32_array(dev, "function-row-physmap", 1199 - atkbd->function_row_physmap, n)) { 1200 - atkbd->num_function_row_keys = n; 1211 + atkbd->vdata.function_row_physmap, 1212 + n)) { 1213 + atkbd->vdata.num_function_row_keys = n; 1201 1214 dev_dbg(dev, "FW reported %d function-row key locations\n", n); 1202 1215 } 1203 1216 }
+16 -27
drivers/input/keyboard/cros_ec_keyb.c
··· 15 15 #include <linux/bitops.h> 16 16 #include <linux/i2c.h> 17 17 #include <linux/input.h> 18 + #include <linux/input/vivaldi-fmap.h> 18 19 #include <linux/interrupt.h> 19 20 #include <linux/kernel.h> 20 21 #include <linux/notifier.h> ··· 27 26 #include <linux/platform_data/cros_ec_proto.h> 28 27 29 28 #include <asm/unaligned.h> 30 - 31 - #define MAX_NUM_TOP_ROW_KEYS 15 32 29 33 30 /** 34 31 * struct cros_ec_keyb - Structure representing EC keyboard device ··· 43 44 * @idev: The input device for the matrix keys. 44 45 * @bs_idev: The input device for non-matrix buttons and switches (or NULL). 45 46 * @notifier: interrupt event notifier for transport devices 46 - * @function_row_physmap: An array of the encoded rows/columns for the top 47 - * row function keys, in an order from left to right 48 - * @num_function_row_keys: The number of top row keys in a custom keyboard 47 + * @vdata: vivaldi function row data 49 48 */ 50 49 struct cros_ec_keyb { 51 50 unsigned int rows; ··· 61 64 struct input_dev *bs_idev; 62 65 struct notifier_block notifier; 63 66 64 - u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS]; 65 - size_t num_function_row_keys; 67 + struct vivaldi_data vdata; 66 68 }; 67 69 68 70 /** ··· 533 537 int err; 534 538 struct property *prop; 535 539 const __be32 *p; 536 - u16 *physmap; 540 + u32 *physmap; 537 541 u32 key_pos; 538 - int row, col; 542 + unsigned int row, col, scancode, n_physmap; 539 543 540 544 err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols); 541 545 if (err) ··· 587 591 ckdev->idev = idev; 588 592 cros_ec_keyb_compute_valid_keys(ckdev); 589 593 590 - physmap = ckdev->function_row_physmap; 594 + physmap = ckdev->vdata.function_row_physmap; 595 + n_physmap = 0; 591 596 of_property_for_each_u32(dev->of_node, "function-row-physmap", 592 597 prop, p, key_pos) { 593 - if (ckdev->num_function_row_keys == MAX_NUM_TOP_ROW_KEYS) { 598 + if (n_physmap == VIVALDI_MAX_FUNCTION_ROW_KEYS) { 594 599 dev_warn(dev, "Only support up to %d top row keys\n", 595 - MAX_NUM_TOP_ROW_KEYS); 600 + VIVALDI_MAX_FUNCTION_ROW_KEYS); 596 601 break; 597 602 } 598 603 row = KEY_ROW(key_pos); 599 604 col = KEY_COL(key_pos); 600 - *physmap = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); 601 - physmap++; 602 - ckdev->num_function_row_keys++; 605 + scancode = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); 606 + physmap[n_physmap++] = scancode; 603 607 } 608 + ckdev->vdata.num_function_row_keys = n_physmap; 604 609 605 610 err = input_register_device(ckdev->idev); 606 611 if (err) { ··· 616 619 struct device_attribute *attr, 617 620 char *buf) 618 621 { 619 - ssize_t size = 0; 620 - int i; 621 - struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); 622 - u16 *physmap = ckdev->function_row_physmap; 622 + const struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); 623 + const struct vivaldi_data *data = &ckdev->vdata; 623 624 624 - for (i = 0; i < ckdev->num_function_row_keys; i++) 625 - size += scnprintf(buf + size, PAGE_SIZE - size, 626 - "%s%02X", size ? " " : "", physmap[i]); 627 - if (size) 628 - size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); 629 - 630 - return size; 625 + return vivaldi_function_row_physmap_show(data, buf); 631 626 } 632 627 633 628 static DEVICE_ATTR_RO(function_row_physmap); ··· 637 648 struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); 638 649 639 650 if (attr == &dev_attr_function_row_physmap.attr && 640 - !ckdev->num_function_row_keys) 651 + !ckdev->vdata.num_function_row_keys) 641 652 return 0; 642 653 643 654 return attr->mode;
+39
drivers/input/vivaldi-fmap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Helpers for ChromeOS Vivaldi keyboard function row mapping 4 + * 5 + * Copyright (C) 2022 Google, Inc 6 + */ 7 + 8 + #include <linux/export.h> 9 + #include <linux/input/vivaldi-fmap.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/types.h> 13 + 14 + /** 15 + * vivaldi_function_row_physmap_show - Print vivaldi function row physmap attribute 16 + * @data: The vivaldi function row map 17 + * @buf: Buffer to print the function row phsymap to 18 + */ 19 + ssize_t vivaldi_function_row_physmap_show(const struct vivaldi_data *data, 20 + char *buf) 21 + { 22 + ssize_t size = 0; 23 + int i; 24 + const u32 *physmap = data->function_row_physmap; 25 + 26 + if (!data->num_function_row_keys) 27 + return 0; 28 + 29 + for (i = 0; i < data->num_function_row_keys; i++) 30 + size += scnprintf(buf + size, PAGE_SIZE - size, 31 + "%s%02X", size ? " " : "", physmap[i]); 32 + if (size) 33 + size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); 34 + 35 + return size; 36 + } 37 + EXPORT_SYMBOL_GPL(vivaldi_function_row_physmap_show); 38 + 39 + MODULE_LICENSE("GPL");
+27
include/linux/input/vivaldi-fmap.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _VIVALDI_FMAP_H 3 + #define _VIVALDI_FMAP_H 4 + 5 + #include <linux/types.h> 6 + 7 + #define VIVALDI_MAX_FUNCTION_ROW_KEYS 24 8 + 9 + /** 10 + * struct vivaldi_data - Function row map data for ChromeOS Vivaldi keyboards 11 + * @function_row_physmap: An array of scancodes or their equivalent (HID usage 12 + * codes, encoded rows/columns, etc) for the top 13 + * row function keys, in an order from left to right 14 + * @num_function_row_keys: The number of top row keys in a custom keyboard 15 + * 16 + * This structure is supposed to be used by ChromeOS keyboards using 17 + * the Vivaldi keyboard function row design. 18 + */ 19 + struct vivaldi_data { 20 + u32 function_row_physmap[VIVALDI_MAX_FUNCTION_ROW_KEYS]; 21 + unsigned int num_function_row_keys; 22 + }; 23 + 24 + ssize_t vivaldi_function_row_physmap_show(const struct vivaldi_data *data, 25 + char *buf); 26 + 27 + #endif /* _VIVALDI_FMAP_H */