diff options
36 files changed, 1364 insertions, 333 deletions
diff --git a/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml new file mode 100644 index 000000000000..b1770640f94b --- /dev/null +++ b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/mediatek,mt6779-keypad.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek's Keypad Controller device tree bindings + +maintainers: + - Fengping Yu <fengping.yu@mediatek.com> + +allOf: + - $ref: "/schemas/input/matrix-keymap.yaml#" + +description: | + Mediatek's Keypad controller is used to interface a SoC with a matrix-type + keypad device. The keypad controller supports multiple row and column lines. + A key can be placed at each intersection of a unique row and a unique column. + The keypad controller can sense a key-press and key-release and report the + event using a interrupt to the cpu. + +properties: + compatible: + oneOf: + - const: mediatek,mt6779-keypad + - items: + - enum: + - mediatek,mt6873-keypad + - const: mediatek,mt6779-keypad + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: kpd + + wakeup-source: + description: use any event on keypad as wakeup event + type: boolean + + debounce-delay-ms: + maximum: 256 + default: 16 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/input/input.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + soc { + #address-cells = <2>; + #size-cells = <2>; + + keyboard@10010000 { + compatible = "mediatek,mt6779-keypad"; + reg = <0 0x10010000 0 0x1000>; + interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_FALLING>; + clocks = <&clk26m>; + clock-names = "kpd"; + }; + }; diff --git a/Documentation/devicetree/bindings/input/mtk-pmic-keys.txt b/Documentation/devicetree/bindings/input/mtk-pmic-keys.txt index 535d92885372..9d00f2a8e13a 100644 --- a/Documentation/devicetree/bindings/input/mtk-pmic-keys.txt +++ b/Documentation/devicetree/bindings/input/mtk-pmic-keys.txt @@ -9,7 +9,10 @@ For MT6397/MT6323 MFD bindings see: Documentation/devicetree/bindings/mfd/mt6397.txt Required properties: -- compatible: "mediatek,mt6397-keys" or "mediatek,mt6323-keys" +- compatible: Should be one of: + - "mediatek,mt6397-keys" + - "mediatek,mt6323-keys" + - "mediatek,mt6358-keys" - linux,keycodes: See Documentation/devicetree/bindings/input/input.yaml Optional Properties: diff --git a/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml new file mode 100644 index 000000000000..e3a2b871e50c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/imagis,ist3038c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagis IST30XXC family touchscreen controller bindings + +maintainers: + - Markuss Broks <markuss.broks@gmail.com> + +allOf: + - $ref: touchscreen.yaml# + +properties: + $nodename: + pattern: "^touchscreen@[0-9a-f]+$" + + compatible: + enum: + - imagis,ist3038c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: + description: Power supply regulator for the chip + + vddio-supply: + description: Power supply regulator for the I2C bus + + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-fuzz-x: true + touchscreen-fuzz-y: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-swapped-x-y: true + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - touchscreen-size-x + - touchscreen-size-y + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@50 { + compatible = "imagis,ist3038c"; + reg = <0x50>; + interrupt-parent = <&gpio>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&ldo1_reg>; + vddio-supply = <&ldo2_reg>; + touchscreen-size-x = <720>; + touchscreen-size-y = <1280>; + touchscreen-fuzz-x = <10>; + touchscreen-fuzz-y = <10>; + touchscreen-inverted-x; + touchscreen-inverted-y; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 8fe2d934f949..01430973ecec 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -560,6 +560,8 @@ patternProperties: description: Ingenieurburo Fur Ic-Technologie (I/F/I) "^ilitek,.*": description: ILI Technology Corporation (ILITEK) + "^imagis,.*": + description: Imagis Technologies Co., Ltd. "^img,.*": description: Imagination Technologies Ltd. "^imi,.*": diff --git a/MAINTAINERS b/MAINTAINERS index 1f6f4a509d6a..4b73a79ffb7f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9517,6 +9517,12 @@ M: Stanislaw Gruszka <stf_xl@wp.pl> S: Maintained F: drivers/usb/atm/ueagle-atm.c +IMAGIS TOUCHSCREEN DRIVER +M: Markuss Broks <markuss.broks@gmail.com> +S: Maintained +F: Documentation/devicetree/bindings/input/touchscreen/imagis,ist3038c.yaml +F: drivers/input/touchscreen/imagis.c + IMGTEC ASCII LCD DRIVER M: Paul Burton <paulburton@kernel.org> S: Maintained diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7a674873d794..a95a7cbc4a59 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -405,14 +405,25 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_VIVALDI_COMMON + tristate + help + ChromeOS Vivaldi HID parsing support library. This is a hidden + option so that drivers can use common code to parse the HID + descriptors for vivaldi function row keymap. + config HID_GOOGLE_HAMMER tristate "Google Hammer Keyboard" + select HID_VIVALDI_COMMON + select INPUT_VIVALDIFMAP depends on USB_HID && LEDS_CLASS && CROS_EC help Say Y here if you have a Google Hammer device. config HID_VIVALDI tristate "Vivaldi Keyboard" + select HID_VIVALDI_COMMON + select INPUT_VIVALDIFMAP depends on HID help Say Y here if you want to enable support for Vivaldi keyboards. diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index d5ce8d747b14..345ac5581bd8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_HID_FT260) += hid-ft260.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o +obj-$(CONFIG_HID_VIVALDI_COMMON) += hid-vivaldi-common.o obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index ddbe0de177e2..ff40f1e55c21 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -15,6 +15,7 @@ #include <linux/acpi.h> #include <linux/hid.h> +#include <linux/input/vivaldi-fmap.h> #include <linux/leds.h> #include <linux/module.h> #include <linux/of.h> @@ -25,6 +26,7 @@ #include <asm/unaligned.h> #include "hid-ids.h" +#include "hid-vivaldi-common.h" /* * C(hrome)B(ase)A(ttached)S(witch) - switch exported by Chrome EC and reporting @@ -340,9 +342,9 @@ static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev, static int hammer_register_leds(struct hid_device *hdev) { struct hammer_kbd_leds *kbd_backlight; - int error; - kbd_backlight = kzalloc(sizeof(*kbd_backlight), GFP_KERNEL); + kbd_backlight = devm_kzalloc(&hdev->dev, sizeof(*kbd_backlight), + GFP_KERNEL); if (!kbd_backlight) return -ENOMEM; @@ -356,26 +358,7 @@ static int hammer_register_leds(struct hid_device *hdev) /* Set backlight to 0% initially. */ hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0); - error = led_classdev_register(&hdev->dev, &kbd_backlight->cdev); - if (error) - goto err_free_mem; - - hid_set_drvdata(hdev, kbd_backlight); - return 0; - -err_free_mem: - kfree(kbd_backlight); - return error; -} - -static void hammer_unregister_leds(struct hid_device *hdev) -{ - struct hammer_kbd_leds *kbd_backlight = hid_get_drvdata(hdev); - - if (kbd_backlight) { - led_classdev_unregister(&kbd_backlight->cdev); - kfree(kbd_backlight); - } + return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev); } #define HID_UP_GOOGLEVENDOR 0xffd10000 @@ -512,11 +495,23 @@ out: kfree(buf); } +static void hammer_stop(void *hdev) +{ + hid_hw_stop(hdev); +} + static int hammer_probe(struct hid_device *hdev, const struct hid_device_id *id) { + struct vivaldi_data *vdata; int error; + vdata = devm_kzalloc(&hdev->dev, sizeof(*vdata), GFP_KERNEL); + if (!vdata) + return -ENOMEM; + + hid_set_drvdata(hdev, vdata); + error = hid_parse(hdev); if (error) return error; @@ -525,6 +520,10 @@ static int hammer_probe(struct hid_device *hdev, if (error) return error; + error = devm_add_action(&hdev->dev, hammer_stop, hdev); + if (error) + return error; + /* * We always want to poll for, and handle tablet mode events from * devices that have folded usage, even when nobody has opened the input @@ -577,15 +576,13 @@ static void hammer_remove(struct hid_device *hdev) spin_unlock_irqrestore(&cbas_ec_lock, flags); } - hammer_unregister_leds(hdev); - - hid_hw_stop(hdev); + /* Unregistering LEDs and stopping the hardware is done via devm */ } static const struct hid_device_id hammer_devices[] = { { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) }, - { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + { HID_DEVICE(BUS_USB, HID_GROUP_VIVALDI, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_EEL) }, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) }, @@ -610,6 +607,8 @@ static struct hid_driver hammer_driver = { .id_table = hammer_devices, .probe = hammer_probe, .remove = hammer_remove, + .feature_mapping = vivaldi_feature_mapping, + .input_configured = vivaldi_input_configured, .input_mapping = hammer_input_mapping, .event = hammer_event, }; diff --git a/drivers/hid/hid-vivaldi-common.c b/drivers/hid/hid-vivaldi-common.c new file mode 100644 index 000000000000..8b3e515d0f06 --- /dev/null +++ b/drivers/hid/hid-vivaldi-common.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Helpers for ChromeOS HID Vivaldi keyboards + * + * Copyright (C) 2022 Google, Inc + */ + +#include <linux/export.h> +#include <linux/hid.h> +#include <linux/input/vivaldi-fmap.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> + +#include "hid-vivaldi-common.h" + +#define MIN_FN_ROW_KEY 1 +#define MAX_FN_ROW_KEY VIVALDI_MAX_FUNCTION_ROW_KEYS +#define HID_VD_FN_ROW_PHYSMAP 0x00000001 +#define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) + +/** + * vivaldi_feature_mapping - Fill out vivaldi keymap data exposed via HID + * @hdev: HID device to parse + * @field: HID field to parse + * @usage: HID usage to parse + * + * Note: this function assumes that driver data attached to @hdev contains an + * instance of &struct vivaldi_data at the very beginning. + */ +void vivaldi_feature_mapping(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage) +{ + struct vivaldi_data *data = hid_get_drvdata(hdev); + struct hid_report *report = field->report; + u8 *report_data, *buf; + u32 report_len; + unsigned int fn_key; + int ret; + + if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || + (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) + return; + + fn_key = usage->hid & HID_USAGE; + if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY) + return; + + if (fn_key > data->num_function_row_keys) + data->num_function_row_keys = fn_key; + + report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL); + if (!report_data) + return; + + report_len = hid_report_len(report); + if (!report->id) { + /* + * hid_hw_raw_request() will stuff report ID (which will be 0) + * into the first byte of the buffer even for unnumbered + * reports, so we need to account for this to avoid getting + * -EOVERFLOW in return. + * Note that hid_alloc_report_buf() adds 7 bytes to the size + * so we can safely say that we have space for an extra byte. + */ + report_len++; + } + + ret = hid_hw_raw_request(hdev, report->id, report_data, + report_len, HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) { + dev_warn(&hdev->dev, "failed to fetch feature %d\n", + field->report->id); + goto out; + } + + if (!report->id) { + /* + * Undo the damage from hid_hw_raw_request() for unnumbered + * reports. + */ + report_data++; + report_len--; + } + + ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data, + report_len, 0); + if (ret) { + dev_warn(&hdev->dev, "failed to report feature %d\n", + field->report->id); + goto out; + } + + data->function_row_physmap[fn_key - MIN_FN_ROW_KEY] = + field->value[usage->usage_index]; + +out: + kfree(buf); +} +EXPORT_SYMBOL_GPL(vivaldi_feature_mapping); + +static ssize_t function_row_physmap_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = to_hid_device(dev); + struct vivaldi_data *data = hid_get_drvdata(hdev); + + return vivaldi_function_row_physmap_show(data, buf); +} + +static DEVICE_ATTR_RO(function_row_physmap); +static struct attribute *vivaldi_sysfs_attrs[] = { + &dev_attr_function_row_physmap.attr, + NULL +}; + +static const struct attribute_group vivaldi_attribute_group = { + .attrs = vivaldi_sysfs_attrs, +}; + +/** + * vivaldi_input_configured - Complete initialization of device using vivaldi map + * @hdev: HID device to which vivaldi attributes should be attached + * @hidinput: HID input device (unused) + */ +int vivaldi_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) +{ + struct vivaldi_data *data = hid_get_drvdata(hdev); + + if (!data->num_function_row_keys) + return 0; + + return devm_device_add_group(&hdev->dev, &vivaldi_attribute_group); +} +EXPORT_SYMBOL_GPL(vivaldi_input_configured); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-vivaldi-common.h b/drivers/hid/hid-vivaldi-common.h new file mode 100644 index 000000000000..d42e82d77825 --- /dev/null +++ b/drivers/hid/hid-vivaldi-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _HID_VIVALDI_COMMON_H +#define _HID_VIVALDI_COMMON_H + +struct hid_device; +struct hid_field; +struct hid_input; +struct hid_usage; + +void vivaldi_feature_mapping(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage); + +int vivaldi_input_configured(struct hid_device *hdev, + struct hid_input *hidinput); + +#endif /* _HID_VIVALDI_COMMON_H */ diff --git a/drivers/hid/hid-vivaldi.c b/drivers/hid/hid-vivaldi.c index 42ceb2058a09..3a979123e7d3 100644 --- a/drivers/hid/hid-vivaldi.c +++ b/drivers/hid/hid-vivaldi.c @@ -8,48 +8,11 @@ #include <linux/device.h> #include <linux/hid.h> +#include <linux/input/vivaldi-fmap.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/sysfs.h> -#define MIN_FN_ROW_KEY 1 -#define MAX_FN_ROW_KEY 24 -#define HID_VD_FN_ROW_PHYSMAP 0x00000001 -#define HID_USAGE_FN_ROW_PHYSMAP (HID_UP_GOOGLEVENDOR | HID_VD_FN_ROW_PHYSMAP) - -struct vivaldi_data { - u32 function_row_physmap[MAX_FN_ROW_KEY - MIN_FN_ROW_KEY + 1]; - int max_function_row_key; -}; - -static ssize_t function_row_physmap_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - struct vivaldi_data *drvdata = hid_get_drvdata(hdev); - ssize_t size = 0; - int i; - - if (!drvdata->max_function_row_key) - return 0; - - for (i = 0; i < drvdata->max_function_row_key; i++) - size += sprintf(buf + size, "%02X ", - drvdata->function_row_physmap[i]); - size += sprintf(buf + size, "\n"); - return size; -} - -static DEVICE_ATTR_RO(function_row_physmap); -static struct attribute *sysfs_attrs[] = { - &dev_attr_function_row_physmap.attr, - NULL -}; - -static const struct attribute_group input_attribute_group = { - .attrs = sysfs_attrs -}; +#include "hid-vivaldi-common.h" static int vivaldi_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -70,86 +33,8 @@ static int vivaldi_probe(struct hid_device *hdev, return hid_hw_start(hdev, HID_CONNECT_DEFAULT); } -static void vivaldi_feature_mapping(struct hid_device *hdev, - struct hid_field *field, - struct hid_usage *usage) -{ - struct vivaldi_data *drvdata = hid_get_drvdata(hdev); - struct hid_report *report = field->report; - int fn_key; - int ret; - u32 report_len; - u8 *report_data, *buf; - - if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || - (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) - return; - - fn_key = (usage->hid & HID_USAGE); - if (fn_key < MIN_FN_ROW_KEY || fn_key > MAX_FN_ROW_KEY) - return; - if (fn_key > drvdata->max_function_row_key) - drvdata->max_function_row_key = fn_key; - - report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL); - if (!report_data) - return; - - report_len = hid_report_len(report); - if (!report->id) { - /* - * hid_hw_raw_request() will stuff report ID (which will be 0) - * into the first byte of the buffer even for unnumbered - * reports, so we need to account for this to avoid getting - * -EOVERFLOW in return. - * Note that hid_alloc_report_buf() adds 7 bytes to the size - * so we can safely say that we have space for an extra byte. - */ - report_len++; - } - - ret = hid_hw_raw_request(hdev, report->id, report_data, - report_len, HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); - if (ret < 0) { - dev_warn(&hdev->dev, "failed to fetch feature %d\n", - field->report->id); - goto out; - } - - if (!report->id) { - /* - * Undo the damage from hid_hw_raw_request() for unnumbered - * reports. - */ - report_data++; - report_len--; - } - - ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data, - report_len, 0); - if (ret) { - dev_warn(&hdev->dev, "failed to report feature %d\n", - field->report->id); - goto out; - } - - drvdata->function_row_physmap[fn_key - MIN_FN_ROW_KEY] = - field->value[usage->usage_index]; - -out: - kfree(buf); -} - -static int vivaldi_input_configured(struct hid_device *hdev, - struct hid_input *hidinput) -{ - return devm_device_add_group(&hdev->dev, &input_attribute_group); -} - static const struct hid_device_id vivaldi_table[] = { - { HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID, - HID_ANY_ID) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_VIVALDI, HID_ANY_ID, HID_ANY_ID) }, { } }; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 5baebf62df33..e2752f7364bc 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -77,6 +77,13 @@ config INPUT_MATRIXKMAP To compile this driver as a module, choose M here: the module will be called matrix-keymap. +config INPUT_VIVALDIFMAP + tristate + help + ChromeOS Vivaldi keymap support library. This is a hidden + option so that drivers can use common code to parse and + expose the vivaldi function row keymap. + comment "Userland interfaces" config INPUT_MOUSEDEV diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 037cc595106c..2266c7d010ef 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -12,6 +12,7 @@ input-core-y += touchscreen.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o +obj-$(CONFIG_INPUT_VIVALDIFMAP) += vivaldi-fmap.o obj-$(CONFIG_INPUT_LEDS) += input-leds.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o diff --git a/drivers/input/input.c b/drivers/input/input.c index c3139bc2aa0d..e5a668ce884d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -47,6 +47,17 @@ static DEFINE_MUTEX(input_mutex); static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; +static const unsigned int input_max_code[EV_CNT] = { + [EV_KEY] = KEY_MAX, + [EV_REL] = REL_MAX, + [EV_ABS] = ABS_MAX, + [EV_MSC] = MSC_MAX, + [EV_SW] = SW_MAX, + [EV_LED] = LED_MAX, + [EV_SND] = SND_MAX, + [EV_FF] = FF_MAX, +}; + static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max) { @@ -511,6 +522,9 @@ void input_set_abs_params(struct input_dev *dev, unsigned int axis, { struct input_absinfo *absinfo; + __set_bit(EV_ABS, dev->evbit); + __set_bit(axis, dev->absbit); + input_alloc_absinfo(dev); if (!dev->absinfo) return; @@ -520,12 +534,45 @@ void input_set_abs_params(struct input_dev *dev, unsigned int axis, absinfo->maximum = max; absinfo->fuzz = fuzz; absinfo->flat = flat; - - __set_bit(EV_ABS, dev->evbit); - __set_bit(axis, dev->absbit); } EXPORT_SYMBOL(input_set_abs_params); +/** + * input_copy_abs - Copy absinfo from one input_dev to another + * @dst: Destination input device to copy the abs settings to + * @dst_axis: ABS_* value selecting the destination axis + * @src: Source input device to copy the abs settings from + * @src_axis: ABS_* value selecting the source axis + * + * Set absinfo for the selected destination axis by copying it from + * the specified source input device's source axis. + * This is useful to e.g. setup a pen/stylus input-device for combined + * touchscreen/pen hardware where the pen uses the same coordinates as + * the touchscreen. + */ +void input_copy_abs(struct input_dev *dst, unsigned int dst_axis, + const struct input_dev *src, unsigned int src_axis) +{ + /* src must have EV_ABS and src_axis set */ + if (WARN_ON(!(test_bit(EV_ABS, src->evbit) && + test_bit(src_axis, src->absbit)))) + return; + + /* + * input_alloc_absinfo() may have failed for the source. Our caller is + * expected to catch this when registering the input devices, which may + * happen after the input_copy_abs() call. + */ + if (!src->absinfo) + return; + + input_set_capability(dst, EV_ABS, dst_axis); + if (!dst->absinfo) + return; + + dst->absinfo[dst_axis] = src->absinfo[src_axis]; +} +EXPORT_SYMBOL(input_copy_abs); /** * input_grab_device - grabs device for exclusive use @@ -2074,6 +2121,14 @@ EXPORT_SYMBOL(input_get_timestamp); */ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) { + if (type < EV_CNT && input_max_code[type] && + code > input_max_code[type]) { + pr_err("%s: invalid code %u for type %u\n", __func__, code, + type); + dump_stack(); + return; + } + switch (type) { case EV_KEY: __set_bit(code, dev->keybit); @@ -2085,9 +2140,6 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int case EV_ABS: input_alloc_absinfo(dev); - if (!dev->absinfo) - return; - __set_bit(code, dev->absbit); break; @@ -2285,12 +2337,6 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); - /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */ - if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) { |
