Loading Documentation/devicetree/bindings/input/gen_vkeys.txt 0 → 100644 +28 −0 Original line number Diff line number Diff line Touchscreen Virtual Keys Device Generate virtual keys sysfs entry for Android Required properties: - compatible : should be "qcom,gen-vkeys" - label : name of the touch controller - qcom,disp-maxx : Maximum x-coordinate of display - qcom,disp-maxy : Maximum y-coordinate of display - qcom,panel-maxx : Maximum x-coordinate of touch panel - qcom,panel-maxy : Maximum y-coordinate of touch panel - qcom,key-codes : Array of key codes for virtual keys Optional properties: - qcom,y-offset : Offset of y-location for virtual keys, default 0 Example: gen-vkeys { compatible = "qcom,gen-vkeys"; label = "atmel_mxt_ts"; qcom,disp-maxx = <720>; qcom,disp-maxy = <1280>; qcom,panel-maxx = <760>; qcom,panel-maxy = <1424>; qcom,key-codes = <158 139 102 217>; qcom,y-offset = <35>; }; arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts +11 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,15 @@ focaltech,resume-in-workqueue; }; }; gen-vkeys { compatible = "qcom,gen-vkeys"; label = "ft5x06_ts"; qcom,disp-maxx = <720>; qcom,disp-maxy = <1280>; qcom,panel-maxx = <720>; qcom,panel-maxy = <1400>; qcom,key-codes = <139 172 158>; qcom,y-offset = <0>; }; }; drivers/input/touchscreen/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -1258,6 +1258,17 @@ config TOUCHSCREEN_FT5X06 To compile this driver as a module, choose M here: the module will be called ft5x06_ts. config TOUCHSCREEN_GEN_VKEYS tristate "Touchscreen Virtual Keys Driver" help Say Y here if you want to generate a sysfs entry for virtual keys on Android. If unsure, say N. To compile this driver as a module, choose M here: the module will be called gen_vkeys. config FT_SECURE_TOUCH bool "Secure Touch support for Focaltech Touchscreen" depends on TOUCHSCREEN_FT5X06 Loading drivers/input/touchscreen/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_FT5X06) += ft5x06_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_GEN_VKEYS) += gen_vkeys.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o Loading drivers/input/touchscreen/gen_vkeys.c 0 → 100644 +226 −0 Original line number Diff line number Diff line /* Copyright (c) 2013, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/input.h> #include <linux/input/gen_vkeys.h> #define MAX_BUF_SIZE 256 #define VKEY_VER_CODE "0x01" #define HEIGHT_SCALE_NUM 8 #define HEIGHT_SCALE_DENOM 10 #define VKEY_Y_OFFSET_DEFAULT 0 /* numerator and denomenator for border equations */ #define BORDER_ADJUST_NUM 3 #define BORDER_ADJUST_DENOM 4 static struct kobject *vkey_obj; static char *vkey_buf; static ssize_t vkey_show(struct kobject *obj, struct kobj_attribute *attr, char *buf) { strlcpy(buf, vkey_buf, MAX_BUF_SIZE); return strnlen(buf, MAX_BUF_SIZE); } static struct kobj_attribute vkey_obj_attr = { .attr = { .mode = 0444, }, .show = vkey_show, }; static struct attribute *vkey_attr[] = { &vkey_obj_attr.attr, NULL, }; static struct attribute_group vkey_grp = { .attrs = vkey_attr, }; static int vkey_parse_dt(struct device *dev, struct vkeys_platform_data *pdata) { struct device_node *np = dev->of_node; struct property *prop; int rc, val; rc = of_property_read_string(np, "label", &pdata->name); if (rc) { dev_err(dev, "Failed to read label\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,disp-maxx", &pdata->disp_maxx); if (rc) { dev_err(dev, "Failed to read display max x\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,disp-maxy", &pdata->disp_maxy); if (rc) { dev_err(dev, "Failed to read display max y\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,panel-maxx", &pdata->panel_maxx); if (rc) { dev_err(dev, "Failed to read panel max x\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,panel-maxy", &pdata->panel_maxy); if (rc) { dev_err(dev, "Failed to read panel max y\n"); return -EINVAL; } prop = of_find_property(np, "qcom,key-codes", NULL); if (prop) { pdata->num_keys = prop->length / sizeof(u32); pdata->keycodes = devm_kzalloc(dev, sizeof(u32) * pdata->num_keys, GFP_KERNEL); if (!pdata->keycodes) return -ENOMEM; rc = of_property_read_u32_array(np, "qcom,key-codes", pdata->keycodes, pdata->num_keys); if (rc) { dev_err(dev, "Failed to read key codes\n"); return -EINVAL; } } pdata->y_offset = VKEY_Y_OFFSET_DEFAULT; rc = of_property_read_u32(np, "qcom,y-offset", &val); if (!rc) pdata->y_offset = val; else if (rc != -EINVAL) { dev_err(dev, "Failed to read y position offset\n"); return rc; } return 0; } static int vkeys_probe(struct platform_device *pdev) { struct vkeys_platform_data *pdata; int width, height, center_x, center_y; int x1 = 0, x2 = 0, i, c = 0, ret, border; char *name; vkey_buf = devm_kzalloc(&pdev->dev, MAX_BUF_SIZE, GFP_KERNEL); if (!vkey_buf) return -ENOMEM; if (pdev->dev.of_node) { pdata = devm_kzalloc(&pdev->dev, sizeof(struct vkeys_platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; ret = vkey_parse_dt(&pdev->dev, pdata); if (ret) { dev_err(&pdev->dev, "Parsing DT failed(%d)", ret); return ret; } } else pdata = pdev->dev.platform_data; if (!pdata || !pdata->name || !pdata->keycodes || !pdata->num_keys || !pdata->disp_maxx || !pdata->disp_maxy || !pdata->panel_maxy) { dev_err(&pdev->dev, "pdata is invalid\n"); return -EINVAL; } border = (pdata->panel_maxx - pdata->disp_maxx) * 2; width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1))) / pdata->num_keys); height = (pdata->panel_maxy - pdata->disp_maxy); center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset; height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM; x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM; for (i = 0; i < pdata->num_keys; i++) { x1 = x2 + border; x2 = x2 + border + width; center_x = x1 + (x2 - x1) / 2; c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c, "%s:%d:%d:%d:%d:%d\n", VKEY_VER_CODE, pdata->keycodes[i], center_x, center_y, width, height); } vkey_buf[c] = '\0'; name = devm_kzalloc(&pdev->dev, sizeof(*name) * MAX_BUF_SIZE, GFP_KERNEL); if (!name) return -ENOMEM; snprintf(name, MAX_BUF_SIZE, "virtualkeys.%s", pdata->name); vkey_obj_attr.attr.name = name; vkey_obj = kobject_create_and_add("board_properties", NULL); if (!vkey_obj) { dev_err(&pdev->dev, "unable to create kobject\n"); return -ENOMEM; } ret = sysfs_create_group(vkey_obj, &vkey_grp); if (ret) { dev_err(&pdev->dev, "failed to create attributes\n"); goto destroy_kobj; } return 0; destroy_kobj: kobject_put(vkey_obj); return ret; } static int vkeys_remove(struct platform_device *pdev) { sysfs_remove_group(vkey_obj, &vkey_grp); kobject_put(vkey_obj); return 0; } static const struct of_device_id vkey_match_table[] = { { .compatible = "qcom,gen-vkeys",}, { }, }; static struct platform_driver vkeys_driver = { .probe = vkeys_probe, .remove = vkeys_remove, .driver = { .owner = THIS_MODULE, .name = "gen_vkeys", .of_match_table = vkey_match_table, }, }; module_platform_driver(vkeys_driver); MODULE_LICENSE("GPL v2"); Loading
Documentation/devicetree/bindings/input/gen_vkeys.txt 0 → 100644 +28 −0 Original line number Diff line number Diff line Touchscreen Virtual Keys Device Generate virtual keys sysfs entry for Android Required properties: - compatible : should be "qcom,gen-vkeys" - label : name of the touch controller - qcom,disp-maxx : Maximum x-coordinate of display - qcom,disp-maxy : Maximum y-coordinate of display - qcom,panel-maxx : Maximum x-coordinate of touch panel - qcom,panel-maxy : Maximum y-coordinate of touch panel - qcom,key-codes : Array of key codes for virtual keys Optional properties: - qcom,y-offset : Offset of y-location for virtual keys, default 0 Example: gen-vkeys { compatible = "qcom,gen-vkeys"; label = "atmel_mxt_ts"; qcom,disp-maxx = <720>; qcom,disp-maxy = <1280>; qcom,panel-maxx = <760>; qcom,panel-maxy = <1424>; qcom,key-codes = <158 139 102 217>; qcom,y-offset = <35>; };
arch/arm64/boot/dts/qcom/msm8917-pmi8937-qrd-sku5.dts +11 −0 Original line number Diff line number Diff line Loading @@ -103,4 +103,15 @@ focaltech,resume-in-workqueue; }; }; gen-vkeys { compatible = "qcom,gen-vkeys"; label = "ft5x06_ts"; qcom,disp-maxx = <720>; qcom,disp-maxy = <1280>; qcom,panel-maxx = <720>; qcom,panel-maxy = <1400>; qcom,key-codes = <139 172 158>; qcom,y-offset = <0>; }; };
drivers/input/touchscreen/Kconfig +11 −0 Original line number Diff line number Diff line Loading @@ -1258,6 +1258,17 @@ config TOUCHSCREEN_FT5X06 To compile this driver as a module, choose M here: the module will be called ft5x06_ts. config TOUCHSCREEN_GEN_VKEYS tristate "Touchscreen Virtual Keys Driver" help Say Y here if you want to generate a sysfs entry for virtual keys on Android. If unsure, say N. To compile this driver as a module, choose M here: the module will be called gen_vkeys. config FT_SECURE_TOUCH bool "Secure Touch support for Focaltech Touchscreen" depends on TOUCHSCREEN_FT5X06 Loading
drivers/input/touchscreen/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_FT5X06) += ft5x06_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_GEN_VKEYS) += gen_vkeys.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o Loading
drivers/input/touchscreen/gen_vkeys.c 0 → 100644 +226 −0 Original line number Diff line number Diff line /* Copyright (c) 2013, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/input.h> #include <linux/input/gen_vkeys.h> #define MAX_BUF_SIZE 256 #define VKEY_VER_CODE "0x01" #define HEIGHT_SCALE_NUM 8 #define HEIGHT_SCALE_DENOM 10 #define VKEY_Y_OFFSET_DEFAULT 0 /* numerator and denomenator for border equations */ #define BORDER_ADJUST_NUM 3 #define BORDER_ADJUST_DENOM 4 static struct kobject *vkey_obj; static char *vkey_buf; static ssize_t vkey_show(struct kobject *obj, struct kobj_attribute *attr, char *buf) { strlcpy(buf, vkey_buf, MAX_BUF_SIZE); return strnlen(buf, MAX_BUF_SIZE); } static struct kobj_attribute vkey_obj_attr = { .attr = { .mode = 0444, }, .show = vkey_show, }; static struct attribute *vkey_attr[] = { &vkey_obj_attr.attr, NULL, }; static struct attribute_group vkey_grp = { .attrs = vkey_attr, }; static int vkey_parse_dt(struct device *dev, struct vkeys_platform_data *pdata) { struct device_node *np = dev->of_node; struct property *prop; int rc, val; rc = of_property_read_string(np, "label", &pdata->name); if (rc) { dev_err(dev, "Failed to read label\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,disp-maxx", &pdata->disp_maxx); if (rc) { dev_err(dev, "Failed to read display max x\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,disp-maxy", &pdata->disp_maxy); if (rc) { dev_err(dev, "Failed to read display max y\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,panel-maxx", &pdata->panel_maxx); if (rc) { dev_err(dev, "Failed to read panel max x\n"); return -EINVAL; } rc = of_property_read_u32(np, "qcom,panel-maxy", &pdata->panel_maxy); if (rc) { dev_err(dev, "Failed to read panel max y\n"); return -EINVAL; } prop = of_find_property(np, "qcom,key-codes", NULL); if (prop) { pdata->num_keys = prop->length / sizeof(u32); pdata->keycodes = devm_kzalloc(dev, sizeof(u32) * pdata->num_keys, GFP_KERNEL); if (!pdata->keycodes) return -ENOMEM; rc = of_property_read_u32_array(np, "qcom,key-codes", pdata->keycodes, pdata->num_keys); if (rc) { dev_err(dev, "Failed to read key codes\n"); return -EINVAL; } } pdata->y_offset = VKEY_Y_OFFSET_DEFAULT; rc = of_property_read_u32(np, "qcom,y-offset", &val); if (!rc) pdata->y_offset = val; else if (rc != -EINVAL) { dev_err(dev, "Failed to read y position offset\n"); return rc; } return 0; } static int vkeys_probe(struct platform_device *pdev) { struct vkeys_platform_data *pdata; int width, height, center_x, center_y; int x1 = 0, x2 = 0, i, c = 0, ret, border; char *name; vkey_buf = devm_kzalloc(&pdev->dev, MAX_BUF_SIZE, GFP_KERNEL); if (!vkey_buf) return -ENOMEM; if (pdev->dev.of_node) { pdata = devm_kzalloc(&pdev->dev, sizeof(struct vkeys_platform_data), GFP_KERNEL); if (!pdata) return -ENOMEM; ret = vkey_parse_dt(&pdev->dev, pdata); if (ret) { dev_err(&pdev->dev, "Parsing DT failed(%d)", ret); return ret; } } else pdata = pdev->dev.platform_data; if (!pdata || !pdata->name || !pdata->keycodes || !pdata->num_keys || !pdata->disp_maxx || !pdata->disp_maxy || !pdata->panel_maxy) { dev_err(&pdev->dev, "pdata is invalid\n"); return -EINVAL; } border = (pdata->panel_maxx - pdata->disp_maxx) * 2; width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1))) / pdata->num_keys); height = (pdata->panel_maxy - pdata->disp_maxy); center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset; height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM; x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM; for (i = 0; i < pdata->num_keys; i++) { x1 = x2 + border; x2 = x2 + border + width; center_x = x1 + (x2 - x1) / 2; c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c, "%s:%d:%d:%d:%d:%d\n", VKEY_VER_CODE, pdata->keycodes[i], center_x, center_y, width, height); } vkey_buf[c] = '\0'; name = devm_kzalloc(&pdev->dev, sizeof(*name) * MAX_BUF_SIZE, GFP_KERNEL); if (!name) return -ENOMEM; snprintf(name, MAX_BUF_SIZE, "virtualkeys.%s", pdata->name); vkey_obj_attr.attr.name = name; vkey_obj = kobject_create_and_add("board_properties", NULL); if (!vkey_obj) { dev_err(&pdev->dev, "unable to create kobject\n"); return -ENOMEM; } ret = sysfs_create_group(vkey_obj, &vkey_grp); if (ret) { dev_err(&pdev->dev, "failed to create attributes\n"); goto destroy_kobj; } return 0; destroy_kobj: kobject_put(vkey_obj); return ret; } static int vkeys_remove(struct platform_device *pdev) { sysfs_remove_group(vkey_obj, &vkey_grp); kobject_put(vkey_obj); return 0; } static const struct of_device_id vkey_match_table[] = { { .compatible = "qcom,gen-vkeys",}, { }, }; static struct platform_driver vkeys_driver = { .probe = vkeys_probe, .remove = vkeys_remove, .driver = { .owner = THIS_MODULE, .name = "gen_vkeys", .of_match_table = vkey_match_table, }, }; module_platform_driver(vkeys_driver); MODULE_LICENSE("GPL v2");