diff options
78 files changed, 4547 insertions, 2282 deletions
diff --git a/Documentation/devicetree/bindings/input/da9062-onkey.txt b/Documentation/devicetree/bindings/input/da9062-onkey.txt new file mode 100644 index 000000000000..ab0e0488fe92 --- /dev/null +++ b/Documentation/devicetree/bindings/input/da9062-onkey.txt @@ -0,0 +1,32 @@ +* Dialog DA9062/63 OnKey Module + +This module is part of the DA9062/DA9063. For more details about entire +chips see Documentation/devicetree/bindings/mfd/da9062.txt and +Documentation/devicetree/bindings/mfd/da9063.txt + +This module provides KEY_POWER, KEY_SLEEP and events. + +Required properties: + +- compatible: should be one of: + dlg,da9062-onkey + dlg,da9063-onkey + +Optional properties: + + - dlg,disable-key-power : Disable power-down using a long key-press. If this + entry exists the OnKey driver will remove support for the KEY_POWER key + press. If this entry does not exist then by default the key-press + triggered power down is enabled and the OnKey will support both KEY_POWER + and KEY_SLEEP. + +Example: + + pmic0: da9062@58 { + + onkey { + compatible = "dlg,da9063-onkey"; + dlg,disable-key-power; + }; + + }; diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt index 5b91f5a3bd5c..97e2467181e9 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt @@ -13,11 +13,18 @@ Subnode properties: - gpios: OF device-tree gpio specification. - label: Descriptive name of the key. - - linux,code: Keycode to emit. + - linux,code: Key / Axis code to emit. Optional subnode-properties: - linux,input-type: Specify event type this button/key generates. If not specified defaults to <1> == EV_KEY. + - linux,input-value: If linux,input-type is EV_ABS or EV_REL then this + value is sent for events this button generates when pressed. + EV_ABS/EV_REL axis will generate an event with a value of 0 when + all buttons with linux,input-type == type and linux,code == axis + are released. This value is interpreted as a signed 32 bit value, + e.g. to make a button generate a value of -1 use: + linux,input-value = <0xffffffff>; /* -1 */ - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - wakeup-source: Boolean, button can wake-up the system. diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index 331549593ed5..de99cbbbf6da 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -14,7 +14,17 @@ Optional properties: device, hence no steps need to be passed. - rotary-encoder,rollover: Automatic rollove when the rotary value becomes greater than the specified steps or smaller than 0. For absolute axis only. +- rotary-encoder,steps-per-period: Number of steps (stable states) per period. + The values have the following meaning: + 1: Full-period mode (default) + 2: Half-period mode + 4: Quarter-period mode +- wakeup-source: Boolean, rotary encoder can wake up the system. + +Deprecated properties: - rotary-encoder,half-period: Makes the driver work on half-period mode. + This property is deprecated. Instead, a 'steps-per-period ' value should + be used, such as "rotary-encoder,steps-per-period = <2>". See Documentation/input/rotary-encoder.txt for more information. diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt index 76db96704a60..f99528da1b1d 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt @@ -5,6 +5,7 @@ There are 3 variants of the chip for various touch panel sizes FT5206GE1 2.8" .. 3.8" FT5306DE4 4.3" .. 7" FT5406EE8 7" .. 8.9" +FT5506EEG 7" .. 8.9" The software interface is identical for all those chips, so that currently there is no need for the driver to distinguish between the @@ -17,6 +18,7 @@ Required properties: - compatible: "edt,edt-ft5206" or: "edt,edt-ft5306" or: "edt,edt-ft5406" + or: "edt,edt-ft5506" - reg: I2C slave address of the chip (0x38) - interrupt-parent: a phandle pointing to the interrupt controller @@ -49,7 +51,7 @@ Example: pinctrl-names = "default"; pinctrl-0 = <&edt_ft5x06_pins>; interrupt-parent = <&gpio2>; - interrupts = <5 0>; - reset-gpios = <&gpio2 6 1>; - wake-gpios = <&gpio4 9 0>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; + wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt new file mode 100644 index 000000000000..777521da3da5 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt @@ -0,0 +1,35 @@ +* FocalTech FT6236 I2C touchscreen controller + +Required properties: + - compatible : "focaltech,ft6236" + - reg : I2C slave address of the chip (0x38) + - interrupt-parent : a phandle pointing to the interrupt controller + serving the interrupt for this chip + - interrupts : interrupt specification for the touch controller + interrupt + - reset-gpios : GPIO specification for the RSTN input + - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen (in pixels) + +Optional properties: + - touchscreen-fuzz-x : horizontal noise value of the absolute input + device (in pixels) + - touchscreen-fuzz-y : vertical noise value of the absolute input + device (in pixels) + - touchscreen-inverted-x : X axis is inverted (boolean) + - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y: X and Y axis are swapped (boolean) + Swapping is done after inverting the axis + +Example: + + ft6x06@38 { + compatible = "focaltech,ft6236"; + reg = <0x38>; + interrupt-parent = <&gpio>; + interrupts = <23 2>; + touchscreen-size-x = <320>; + touchscreen-size-y = <480>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 13e54a0e78b9..a79185f78ccd 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -82,6 +82,7 @@ everspin Everspin Technologies, Inc. excito Excito fcs Fairchild Semiconductor firefly Firefly +focaltech FocalTech Systems Co.,Ltd fsl Freescale Semiconductor GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 5737e3590adb..46a74f0c551a 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt @@ -9,8 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees and by triggering on falling and rising edges, the turn direction can be determined. -Some encoders have both outputs low in stable states, whereas others also have -a stable state with both outputs high (half-period mode). +Some encoders have both outputs low in stable states, others also have +a stable state with both outputs high (half-period mode) and some have +a stable state in all steps (quarter-period mode). The phase diagram of these two outputs look like this: @@ -32,6 +33,9 @@ The phase diagram of these two outputs look like this: |<-->| one step (half-period mode) + |<>| + one step (quarter-period mode) + For more information, please see https://en.wikipedia.org/wiki/Rotary_encoder @@ -109,6 +113,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = { .inverted_a = 0, .inverted_b = 0, .half_period = false, + .wakeup_source = false, }; static struct platform_device rotary_encoder_device = { diff --git a/Documentation/input/userio.txt b/Documentation/input/userio.txt new file mode 100644 index 000000000000..0880c0f447a6 --- /dev/null +++ b/Documentation/input/userio.txt @@ -0,0 +1,70 @@ + The userio Protocol + (c) 2015 Stephen Chandler Paul <thatslyude@gmail.com> + Sponsored by Red Hat +-------------------------------------------------------------------------------- + +1. Introduction +~~~~~~~~~~~~~~~ + This module is intended to try to make the lives of input driver developers +easier by allowing them to test various serio devices (mainly the various +touchpads found on laptops) without having to have the physical device in front +of them. userio accomplishes this by allowing any privileged userspace program +to directly interact with the kernel's serio driver and control a virtual serio +port from there. + +2. Usage overview +~~~~~~~~~~~~~~~~~ + In order to interact with the userio kernel module, one simply opens the +/dev/userio character device in their applications. Commands are sent to the +kernel module by writing to the device, and any data received from the serio +driver is read as-is from the /dev/userio device. All of the structures and +macros you need to interact with the device are defined in <linux/userio.h> and +<linux/serio.h>. + +3. Command Structure +~~~~~~~~~~~~~~~~~~~~ + The struct used for sending commands to /dev/userio is as follows: + + struct userio_cmd { + __u8 type; + __u8 data; + }; + + "type" describes the type of command that is being sent. This can be any one +of the USERIO_CMD macros defined in <linux/userio.h>. "data" is the argument +that goes along with the command. In the event that the command doesn't have an +argument, this field can be left untouched and will be ignored by the kernel. +Each command should be sent by writing the struct directly to the character +device. In the event that the command you send is invalid, an error will be +returned by the character device and a more descriptive error will be printed +to the kernel log. Only one command can be sent at a time, any additional data +written to the character device after the initial command will be ignored. + To close the virtual serio port, just close /dev/userio. + +4. Commands +~~~~~~~~~~~ + +4.1 USERIO_CMD_REGISTER +~~~~~~~~~~~~~~~~~~~~~~~ + Registers the port with the serio driver and begins transmitting data back and +forth. Registration can only be performed once a port type is set with +USERIO_CMD_SET_PORT_TYPE. Has no argument. + +4.2 USERIO_CMD_SET_PORT_TYPE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Sets the type of port we're emulating, where "data" is the port type being +set. Can be any of the macros from <linux/serio.h>. For example: SERIO_8042 +would set the port type to be a normal PS/2 port. + +4.3 USERIO_CMD_SEND_INTERRUPT +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Sends an interrupt through the virtual serio port to the serio driver, where +"data" is the interrupt data being sent. + +5. Userspace tools +~~~~~~~~~~~~~~~~~~ + The userio userspace tools are able to record PS/2 devices using some of the +debugging information from i8042, and play back the devices on /dev/userio. The +latest version of these tools can be found at: + + https://github.com/Lyude/ps2emu diff --git a/MAINTAINERS b/MAINTAINERS index 0f327cce301e..e2b8cbbfcd8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11306,6 +11306,12 @@ S: Maintained F: drivers/media/v4l2-core/videobuf2-* F: include/media/videobuf2-* +VIRTUAL SERIO DEVICE DRIVER +M: Stephen Chandler Paul <thatslyude@gmail.com> +S: Maintained +F: drivers/input/serio/userio.c +F: include/uapi/linux/userio.h + VIRTIO CONSOLE DRIVER M: Amit Shah <amit.shah@redhat.com> L: virtualization@lists.linux-foundation.org diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 7da7c2da4af1..0bb36e9af936 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -502,7 +502,7 @@ reg = <0x38>; interrupt-parent = <&gpio0>; - interrupts = <31 0>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/imx28-tx28.dts b/arch/arm/boot/dts/imx28-tx28.dts index a5b27c85a91c..4ea89344a5ff 100644 --- a/arch/arm/boot/dts/imx28-tx28.dts +++ b/arch/arm/boot/dts/imx28-tx28.dts @@ -13,6 +13,7 @@ /dts-v1/; #include "imx28.dtsi" #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> / { model = "Ka-Ro electronics TX28 module"; @@ -324,7 +325,7 @@ pinctrl-names = "default"; pinctrl-0 = <&tx28_edt_ft5x06_pins>; interrupt-parent = <&gpio2>; - interrupts = <5 0>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/imx53-tx53-x03x.dts b/arch/arm/boot/dts/imx53-tx53-x03x.dts index 3b73e81dc3f0..13e842b0c785 100644 --- a/arch/arm/boot/dts/imx53-tx53-x03x.dts +++ b/arch/arm/boot/dts/imx53-tx53-x03x.dts @@ -12,6 +12,7 @@ /dts-v1/; #include "imx53-tx53.dtsi" #include <dt-bindings/input/input.h> +#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/pwm/pwm.h> / { @@ -216,7 +217,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_edt_ft5x06_1>; interrupt-parent = <&gpio6>; - interrupts = <15 0>; + interrupts = <15 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/imx6qdl-tx6.dtsi b/arch/arm/boot/dts/imx6qdl-tx6.dtsi index da08de324e9e..13cb7ccfea44 100644 --- a/arch/arm/boot/dts/imx6qdl-tx6.dtsi +++ b/arch/arm/boot/dts/imx6qdl-tx6.dtsi @@ -11,6 +11,7 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> +#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/pwm/pwm.h> / { @@ -272,7 +273,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_edt_ft5x06>; interrupt-parent = <&gpio6>; - interrupts = <15 0>; + interrupts = <15 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; wake-gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>; linux,wakeup; diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 6ab51ae3c39d..7245b7f8767f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -257,6 +257,12 @@ config HID_GEMBIRD ---help--- Support for Gembird JPD-DualForce 2. +config HID_GFRM + tristate "Google Fiber TV Box remote control support" + depends on HID + ---help--- + Support for Google Fiber TV Box remote controls + config HID_HOLTEK tristate "Holtek HID devices" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e6441bc7dae4..571d176d22df 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o +obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c index 0e6a42d37eb6..07cbc70f00e7 100644 --- a/drivers/hid/hid-appleir.c +++ b/drivers/hid/hid-appleir.c @@ -256,7 +256,7 @@ out: return 0; } -static void appleir_input_configured(struct hid_device *hid, +static int appleir_input_configured(struct hid_device *hid, struct hid_input *hidinput) { struct input_dev *input_dev = hidinput->input; @@ -275,6 +275,8 @@ static void appleir_input_configured(struct hid_device *hid, for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++) set_bit(appleir->keymap[i], input_dev->keybit); clear_bit(KEY_RESERVED, input_dev->keybit); + + return 0; } static int appleir_input_mapping(struct hid_device *hid, diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 4e49462870ab..aad8c162a825 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -37,7 +37,7 @@ static bool use_fw_quirk = true; module_param(use_fw_quirk, bool, S_IRUGO); MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)"); -static void elo_input_configured(struct hid_device *hdev, +static int elo_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { struct input_dev *input = hidinput->input; @@ -45,6 +45,8 @@ static void elo_input_configured(struct hid_device *hdev, set_bit(BTN_TOUCH, input->keybit); set_bit(ABS_PRESSURE, input->absbit); input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0); + + return 0; } static void elo_process_data(struct input_dev *input, const u8 *data, int size) diff --git a/drivers/hid/hid-gfrm.c b/drivers/hid/hid-gfrm.c new file mode 100644 index 000000000000..075b1c020846 --- /dev/null +++ b/drivers/hid/hid-gfrm.c @@ -0,0 +1,159 @@ +/* + * HID driver for Google Fiber TV Box remote controls + * + * Copyright (c) 2014-2015 Google Inc. + * + * Author: Petri Gynther <pgynther@google.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/input.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GFRM100 1 /* Google Fiber GFRM100 (Bluetooth classic) */ +#define GFRM200 2 /* Google Fiber GFRM200 (Bluetooth LE) */ + +#define GFRM100_SEARCH_KEY_REPORT_ID 0xF7 +#define GFRM100_SEARCH_KEY_DOWN 0x0 +#define GFRM100_SEARCH_KEY_AUDIO_DATA 0x1 +#define GFRM100_SEARCH_KEY_UP 0x2 + +static u8 search_key_dn[3] = {0x40, 0x21, 0x02}; +static u8 search_key_up[3] = {0x40, 0x00, 0x00}; + +static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev); + + if (hdev_type == GFRM100) { + if (usage->hid == (HID_UP_CONSUMER | 0x4)) { + /* Consumer.0004 -> KEY_INFO */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_INFO); + return 1; + } + + if (usage->hid == (HID_UP_CONSUMER | 0x41)) { + /* Consumer.0041 -> KEY_OK */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_OK); + return 1; + } + } + + return 0; +} + +static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev); + int ret = 0; + + if (hdev_type != GFRM100) + return 0; + + if (size < 2 || data[0] != GFRM100_SEARCH_KEY_REPORT_ID) + return 0; + + /* + * Convert GFRM100 Search key reports into Consumer.0221 (Key.Search) + * reports. Ignore audio data. + */ + switch (data[1]) { + case GFRM100_SEARCH_KEY_DOWN: + ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn, + sizeof(search_key_dn), 1); + break; + + case GFRM100_SEARCH_KEY_AUDIO_DATA: + break; + + case GFRM100_SEARCH_KEY_UP: + ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up, + sizeof(search_key_up), 1); + break; + + default: + break; + } + + return (ret < 0) ? ret : -1; +} + +static int gfrm_input_configured(struct hid_device *hid, struct hid_input *hidinput) +{ + /* + * Enable software autorepeat with: + * - repeat delay: 400 msec + * - repeat period: 100 msec + */ + input_enable_softrepeat(hidinput->input, 400, 100); + return 0; +} + +static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hid_set_drvdata(hdev, (void *) id->driver_data); + + ret = hid_parse(hdev); + if (ret) + goto done; + + if (id->driver_data == GFRM100) { + /* + * GFRM100 HID Report Descriptor does not describe the Search + * key reports. Thus, we need to add it manually here, so that + * those reports reach gfrm_raw_event() from hid_input_report(). + */ + if (!hid_register_report(hdev, HID_INPUT_REPORT, + GFRM100_SEARCH_KEY_REPORT_ID)) { + ret = -ENOMEM; + goto done; + } + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +done: + return ret; +} + +static void gfrm_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id gfrm_devices[] = { + { HID_BLUETOOTH_DEVICE(0x58, 0x2000), + .driver_data = GFRM100 }, + { HID_BLUETOOTH_DEVICE(0x471, 0x2210), + .driver_data = GFRM200 }, + { } +}; +MODULE_DEVICE_TABLE(hid, gfrm_devices); + +static struct hid_driver gfrm_driver = { + .name = "gfrm", + .id_table = gfrm_devices, + .probe = gfrm_probe, + .remove = gfrm_remove, + .input_mapping = gfrm_input_mapping, + .raw_event = gfrm_raw_event, + .input_configured = gfrm_input_configured, +}; + +module_hid_driver(gfrm_driver); + +MODULE_AUTHOR("Petri Gynther <pgynther@google.com>"); +MODULE_DESCRIPTION("Google Fiber TV Box remote control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 53aeaf6252c7..2ba6bf69b7d0 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1510,8 +1510,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; - if (drv->input_configured) - drv->input_configured(hid, hidinput); + if (drv->input_configured && + drv->input_configured(hid, hidinput)) + goto out_cleanup; if (input_register_device(hidinput->input)) goto out_cleanup; hidinput = NULL; @@ -1532,8 +1533,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } if (hidinput) { - if (drv->input_configured) - drv->input_configured(hid, hidinput); + if (drv->input_configured && + drv->input_configured(hid, hidinput)) + goto out_cleanup; if (input_register_device(hidinput->input)) goto out_cleanup; } diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index e4bc6cb6d7fa..8979f1fd5208 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -848,7 +848,7 @@ static void lenovo_remove(struct hid_device *hdev) hid_hw_stop(hdev); } -static void lenovo_input_configured(struct hid_device *hdev, +static int lenovo_input_configured(struct hid_device *hdev, struct hid_input *hi) { switch (hdev->product) { @@ -863,6 +863,8 @@ static void lenovo_input_configured(struct hid_device *hdev, } break; } + + return 0; } diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 484196459305..a25f562f2d7b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1160,13 +1160,15 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, m560_populate_input(hidpp, input, origin_is_hid_core); } -static void hidpp_input_configured(struct hid_device *hdev, +static int hidpp_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct input_dev *input = hidinput->input; hidpp_populate_input(hidpp, input, true); + + return 0; } static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 29a74c1efcb8..d6fa496d0ca2 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -471,18 +471,22 @@ static int magicmouse_input_mapping(struct hid_device *hdev, return 0; } -static void magicmouse_input_configured(struct hid_device *hdev, +static int magicmouse_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); + int ret; - int ret = magicmouse_setup_input(msc->input, hdev); + ret = magicmouse_setup_input(msc->input, hdev); if (ret) { hid_err(hdev, "magicmouse setup input failed (%d)\n", ret); /* clean msc->input to notify probe() of the failure */ msc->input = NULL; + return ret; } + + return 0; } diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 426b2f1a3450..2ed42d8f805b 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -725,12 +725,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) mt_sync_frame(td, report->field[0]->hidinput->input); } -static void mt_touch_input_configured(struct hid_device *hdev, +static int mt_touch_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; struct input_dev *input = hi->input; + int ret; if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; @@ -752,9 +753,12 @@ static void mt_touch_input_configured(struct hid_device *hdev, if (td->is_buttonpad) __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - input_mt_init_slots(input, td->maxcontacts, td->mt_flags); + ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags); + if (ret) + return ret; td->mt_flags = 0; + return 0; } static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -930,15 +934,19 @@ static void mt_post_parse(struct mt_device *td) cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } -static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) +static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); char *name; const char *suffix = NULL; struct hid_field *field = hi->report->field[0]; + int ret; - if (hi->report->id == td->mt_report_id) - mt_touch_input_configured(hdev, hi); + if (hi->report->id == td->mt_report_id) { + ret = mt_touch_input_configured(hdev, hi); + if (ret) + return ret; + } /* * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" @@ -989,6 +997,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) hi->input->name = name; } } + + return 0; } static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 600f2075512f..756d1ef9bd99 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -859,14 +859,14 @@ not_claimed_input: return 1; } -static void ntrig_input_configured(struct hid_device *hid, +static int ntrig_input_configured(struct hid_device *hid, struct hid_input *hidinput) { struct input_dev *input = hidinput->input; if (hidinput->report->maxfield < 1) - return; + return 0; switch (hidinput->report->field[0]->application) { case HID_DG_PEN: @@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid, "N-Trig MultiTouch"; break; } + + return 0; } static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 2c148129beb2..67cd059a8f46 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1173,7 +1173,7 @@ static int rmi_populate(struct hid_device *hdev) return 0; } -static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) +static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct rmi_data *data = hid_get_drvdata(hdev); struct input_dev *input = hi->input; @@ -1185,10 +1185,10 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) hid_dbg(hdev, "Opening low level driver\n"); ret = hid_hw_open(hdev); if (ret) - return; + return ret; if (!(data->device_flags & RMI_DEVICE)) - return; + return 0; /* Allow incoming hid reports */ hid_device_io_start(hdev); @@ -1228,7 +1228,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); - input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); + ret = input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); + if (ret < 0) + goto exit; if (data->button_count) { __set_bit(EV_KEY, input->evbit); @@ -1244,6 +1246,7 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) exit: hid_device_io_stop(hdev); hid_hw_close(hdev); + return ret; } static int rmi_input_mapping(struct hid_device *hdev, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 661f94f8ab8b..774cd2210566 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1360,20 +1360,27 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count, return 0; } -static void sony_input_configured(struct hid_device *hdev, +static int sony_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { struct sony_sc *sc = hid_get_drvdata(hdev); + int ret; /* * The Dualshock 4 touchpad supports 2 touches and has a * resolution of 1920x942 (44.86 dots/mm). */ if (sc->quirks & DUALSHOCK4_CONTROLLER) { - if (sony_register_touchpad(hidinput, 2, 1920, 942) != 0) + ret = sony_register_touchpad(hidinput, 2, 1920, 942); + if (ret) { hid_err(sc->hdev, - "Unable to initialize multi-touch slots\n"); + "Unable to initialize multi-touch slots: %d\n", + ret); + return ret; + } } + + return 0; } /* diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index b905d501e752..85ac43517e3f 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -731,7 +731,7 @@ static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 0; } -static void uclogic_input_configured(struct hid_device *hdev, +static int uclogic_input_configured(struct hid_device *hdev, struct hid_input *hi) { char *name; @@ -741,7 +741,7 @@ static void uclogic_input_configured(struct hid_device *hdev, /* no report associated (HID_QUIRK_MULTI_INPUT not set) */ if (!hi->report) - return; + return 0; field = hi->report->field[0]; @@ -774,6 +774,8 @@ static void uclogic_input_configured(struct hid_device *hdev, hi->input->name = name; } } + + return 0; } /** diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 08d496411f75..e9ae3d500a55 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -56,12 +56,57 @@ struct evdev_client { struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int clk_type; + unsigned int clk_type; bool revoked; + unsigned long *evmasks[EV_CNT]; unsigned int bufsize; struct input_event buffer[]; }; +static size_t evdev_get_mask_cnt(unsigned int type) +{ + static const size_t counts[EV_CNT] = { + /* EV_SYN==0 is EV_CNT, _not_ SYN_CNT, see EVIOCGBIT */ + [EV_SYN] = EV_CNT, + [EV_KEY] = KEY_CNT, + [EV_REL] = REL_CNT, + [EV_ABS] = ABS_CNT, + [EV_MSC] = MSC_CNT, + [EV_SW] = SW_CNT, + [EV_LED] = LED_CNT, + [EV_SND] = SND_CNT, + [EV_FF] = FF_CNT, + }; + + return (type < EV_CNT) ? counts[type] : 0; +} + +/* requires the buffer lock to be held */ +static bool __evdev_is_filtered(struct evdev_client *client, + unsigned int type, + unsigned int code) +{ + unsigned long *mask; + size_t cnt; + + /* EV_SYN and unknown codes are never filtered */ + if (type == EV_SYN || type >= EV_CNT) + return false; + + /* first test whether the type is filtered */ + mask = client->evmasks[0]; + if (mask && !test_bit(type, mask)) + return true; + + /* unknown values are never filtered */ + cnt = evdev_get_mask_cnt(type); + if (!cnt || code >= cnt) + return false; + + mask = client->evmasks[type]; + return mask && !test_bit(code, mask); +} + /* flush queued events of type @type, caller must hold client->buffer_lock */ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) { @@ -146,37 +191,39 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) { unsigned long flags; - - if (client->clk_type == clkid) - return 0; + unsigned int clk_type; switch (clkid) { case CLOCK_REALTIME: - client->clk_type = EV_CLK_REAL; + clk_type = EV_CLK_REAL; break; case CLOCK_MONOTONIC: - client->clk_type = EV_CLK_MONO; + clk_type = EV_CLK_MONO; break; case CLOCK_BOOTTIME: - client->clk_type = EV_CLK_BOOT; + clk_type = EV_CLK_BOOT; break; default: return -EINVAL; } - /* - * Flush pending events and queue SYN_DROPPED event, - * but only if the queue is not empty. - */ - spin_lock_irqsave(&client->buffer_lock, flags); + if (client->clk_type != clk_type) { + client->clk_type = clk_type; - if (client->head != client->tail) { - client->packet_head = client->head = client->tail; - __evdev_queue_syn_dropped(client); - } + /* + * Flush pending events and queue SYN_DROPPED event, + * but only if the queue is not empty. + */ + spin_lock_irqsave(&client->buffer_lock, flags); - spin_unlock_irqrestore(&client->buffer_lock, flags); + if (client->head != client->tail) { + client->packet_head = client->head = client->tail; + __evdev_queue_syn_dropped(client); + } + + spin_unlock_irqrestore(&client->buffer_lock, flags); + } return 0; } @@ -226,12 +273,21 @@ static void evdev_pass_values(struct evdev_client *client, spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { + if (__evdev_is_filtered(client, v->type, v->code)) + continue; + + if (v->type == EV_SYN && v->code == SYN_REPORT) { + /* drop empty SYN_REPORT */ + if (client->packet_head == client->head) + continue; + + wakeup = true; + } + event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); - if (v->type == EV_SYN && v->code == SYN_REPORT) - wakeup = true; } spin_unlock(&client->buffer_lock); @@ -410,6 +466,7 @@ static int evdev_release(struct inode *inode, struct file *file) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; + unsigned int i; mutex_lock(&evdev->mutex); evdev_ungrab(evdev, client); @@ -417,6 +474,9 @@ static int evdev_release(struct inode *inode, struct file *file) evdev_detach_client(evdev, client); + for (i = 0; i < EV_CNT; ++i) + kfree(client->evmasks[i]); + kvfree(client); evdev_close_device(evdev); @@ -627,7 +687,46 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit, return len; } + +static int bits_from_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, const void __user *p, int compat) +{ + int len, i; + + if (compat) { + if (maxlen % sizeof(compat_long_t)) + return -EINVAL; + + len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t); + if (len > maxlen) + len = maxlen; + + for (i = 0; i < len / sizeof(compat_long_t); i++) + if (copy_from_user((compat_long_t *) bits + + i + 1 - ((i % 2) << 1), + (compat_long_t __user *) p + i, + sizeof(compat_long_t))) + return -EFAULT; + if (i % 2) + *((compat_long_t *) bits + i - 1) = 0; + + } else { + if (maxlen % sizeof(long)) + return -EINVAL; + + len = BITS_TO_LONGS(maxbit) * sizeof(long); + if (len > maxlen) + len = maxlen; + + if (copy_from_user(bits, p, len)) + return -EFAULT; + } + + return len; +} + #else + static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { @@ -640,6 +739,24 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit, return copy_to_user(p, bits, len) ? -EFAULT : len; } + +static int bits_from_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, const void __user *p, int compat) +{ + size_t chunk_size = compat ? sizeof(compat_long_t) : sizeof(long); + int len; + + if (maxlen % chunk_size) + return -EINVAL; + + len = compat ? BITS_TO_LONGS_COMPAT(maxbit) : BITS_TO_LONGS(maxbit); + len *= chunk_size; + if (len > maxlen) + len = maxlen; + + return copy_from_user(bits, p, len) ? -EFAULT : len; +} + #endif /* __BIG_ENDIAN */ #else @@ -655,6 +772,21 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit, return copy_to_user(p, bits, len) ? -EFAULT : len; } +static int bits_from_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, const void __user *p, int compat) +{ + int len; + + if (maxlen % sizeof(long)) + return -EINVAL; + + len = BITS_TO_LONGS(maxbit) * sizeof(long); + if (len > maxlen) + len = maxlen; + + return copy_from_user(bits, p, len) ? -EFAULT : len; +} + #endif /* CONFIG_COMPAT */ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) @@ -849,6 +981,81 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, return 0; } +/* must be called with evdev-mutex held */ +static int evdev_set_mask(struct evdev_client *client, + unsigned int type, + const void __user *codes, + u32 codes_size, + int compat) +{ + unsigned long flags, *mask, *oldmask; + size_t cnt; + int error; + + /* we allow unknown types and 'codes_size > size' for forward-compat */ + cnt = evdev_get_mask_cnt(type); + if (!cnt) + return 0; + + mask = kcalloc(sizeof(unsigned long), BITS_TO_LONGS(cnt), GFP_KERNEL); + if (!mask) + return -ENOMEM; + + error = bits_from_user(mask, cnt - 1, codes_size, codes, compat); + if (error < 0) { + kfree(mask); + return error; + } + + spin_lock_irqsave(&client->buffer_lock, flags); + oldmask = client->evmasks[type]; + client->evmasks[type] = mask; + spin_unlock_irqrestore(&client->buffer_lock, flags); + + kfree(oldmask); + + return 0; +} + +/* must be called with evdev-mutex held */ +static int evdev_get_mask(struct evdev_client *client, + unsigned int type, + void __user *codes, + u32 codes_size, + int compat) +{ + unsigned long *mask; + size_t cnt, size, xfer_size; + int i; + int error; + + /* we allow unknown types and 'codes_size > size' for forward-compat */ + cnt = evdev_get_mask_cnt(type); + size = sizeof(unsigned long) * BITS_TO_LONGS(cnt); + xfer_size = min_t(size_t, codes_size, size); + + if (cnt > 0) { + mask = client->evmasks[type]; + if (mask) { + error = bits_to_user(mask, cnt - 1, + xfer_size, codes, compat); + if (error < 0) + return error; + } else { + /* fake mask with all bits set */ + for (i = 0; i < xfer_size; i++) + if (put_user(0xffU, (u8 __user *)codes + i)) + return -EFAULT; + } + } + + if (xfer_size < codes_size) + if (clear_user(codes + xfer_size, codes_size - xfer_size)) + return -EFAULT; + + return 0; +} + static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) { @@ -856,6 +1063,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, struct evdev *evdev = client->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; + struct input_mask mask; struct ff_effect effect; int __user *ip = (int __user *)p; unsigned int i, t, u, v; @@ -917,6 +1125,30 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, else return evdev_revoke(evdev, client, file); + case EVIOCGMASK: { + void __user *codes_ptr; + + if (copy_from_user(&mask, p, sizeof(mask))) + return -EFAULT; + + codes_ptr = (void __user *)(unsigned long)mask.codes_ptr; + return evdev_get_mask(client, + mask.type, codes_ptr, mask.codes_size, + compat_mode); + } + + case EVIOCSMASK: { + const void __user *codes_ptr; + + if (copy_from_user(&mask, p, sizeof(mask))) + return -EFAULT; + + codes_ptr = (const void __user *)(unsigned long)mask.codes_ptr; + return evdev_set_mask(client, + mask.type, codes_ptr, mask.codes_size, + compat_mode); + } + case EVIOCSCLOCKID: if (copy_from_user(&i, p, sizeof(unsigned int))) return -EFAULT; diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index c64208267198..8f2042432c85 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -273,14 +273,14 @@ int input_ff_event(struct input_dev *dev, unsigned int type, switch (code) { case FF_GAIN: - if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff) + if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffffU) break; ff->set_gain(dev, value); break; case FF_AUTOCENTER: - if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff) + if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffffU) break; ff->set_autocenter(dev, value); @@ -318,6 +318,11 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) return -EINVAL; } + if (max_effects > FF_MAX_EFFECTS) { + dev_err(&dev->dev, "cannot allocate more than FF_MAX_EFFECTS effects\n"); + return -EINVAL; + } + ff_dev_size = sizeof(struct ff_device) + max_effects * sizeof(struct file *); if (ff_dev_size < max_effects) /* overflow */ diff --git a/drivers/input/input.c b/drivers/input/input.c index 5391abd28b27..880605959aa6 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2045,6 +2045,23 @@ static void devm_input_device_unregister(struct device *dev, void *res) } /** + * input_enable_softrepeat - enable software autorepeat + * @dev: input device + * @delay: repeat delay + * @period: repeat period + * + * Enable software autorepeat on the input device. + */ +void input_enable_softrepeat(struct input_dev *dev, int delay, int period) +{ + dev->timer.data = (unsigned long) dev; + dev->timer.function = input_repeat_key; + dev->rep[REP_DELAY] = delay; + dev->rep[REP_PERIOD] = period; +} +EXPORT_SYMBOL(input_enable_softrepeat); + +/** * input_register_device - register device with input core * @dev: device to be registered * @@ -2108,12 +2125,8 @@ int input_register_device(struct input_dev *dev) * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. */ - if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { - dev->timer.data = (long) dev; - dev->timer.function = input_repeat_key; - dev->rep[REP_DELAY] = 250; - dev->rep[REP_PERIOD] = 33; - } + if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) + input_enable_softrepeat(dev, 250, 33); if (!dev->getkeycode) dev->getkeycode = input_default_getkeycode; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 6cb5a3e5f9a1..5d11fea3c8ec 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -444,14 +444,9 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev, len = min(len, sizeof(joydev->abspam)); /* Validate the map. */ - abspam = kmalloc(len, GFP_KERNEL); - if (!abspam) - return -ENOMEM; - - if (copy_from_user(abspam, argp, len)) { - retval = -EFAULT; - goto out; - } + abspam = memdup_user(argp, len); + if (IS_ERR(abspam)) + return PTR_ERR(abspam); for (i = 0; i < joydev->nabs; i++) { if (abspam[i] > ABS_MAX) { @@ -480,14 +475,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev, len = min(len, sizeof(joydev->keypam)); /* Validate the map. */ - keypam = kmalloc(len, GFP_KERNEL); - if (!keypam) - return -ENOMEM; - - if (copy_from_user(keypam, argp, len)) { - retval = -EFAULT; - goto out; - } + keypam = memdup_user(argp, len); + if (IS_ERR(keypam)) + return PTR_ERR(keypam); for (i = 0; i < joydev->nkey; i++) { if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) { diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 8e7de5c7754f..932d07307454 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -48,7 +48,7 @@ struct db9_config { }; #define DB9_MAX_PORTS 3 -static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata; +static struct db9_config db9_cfg[DB9_MAX_PORTS]; module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0); MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)"); @@ -106,6 +106,7 @@ struct db9 { struct pardevice *pd; int mode; int used; + int parportno; struct mutex mutex; char phys[DB9_MAX_DEVICES][32]; }; @@ -553,54 +554,60 @@ static void db9_close(struct input_dev *dev) mutex_unlock(&db9->mutex); } -static struct db9 __init *db9_probe(int parport, int mode) +static void db9_attach(struct parport *pp) { struct db9 *db9; const struct db9_mode_data *db9_mode; - struct parport *pp; struct pardevice *pd; struct input_dev *input_dev; - int i, j; - int err; + int i, j, port_idx; + int mode; + struct pardev_cb db9_parport_cb; + + for (port_idx = 0; port_idx < DB9_MAX_PORTS; port_idx++) { + if (db9_cfg[port_idx].nargs == 0 || + db9_cfg[port_idx].args[DB9_ARG_PARPORT] < 0) + continue; + + if (db9_cfg[port_idx].args[DB9_ARG_PARPORT] == pp->number) + break; + } + + if (port_idx == DB9_MAX_PORTS) { + pr_debug("Not using parport%d.\n", pp->number); + return; + } + + mode = db9_cfg[port_idx].args[DB9_ARG_MODE]; if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) { printk(KERN_ERR "db9.c: Bad device type %d\n", mode); - err = -EINVAL; - goto err_out; + return; } db9_mode = &db9_modes[mode]; - pp = parport_find_number(parport); - if (!pp) { - printk(KERN_ERR "db9.c: no such parport\n"); - err = -ENODEV; - goto err_out; - } - if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) { printk(KERN_ERR "db9.c: specified parport is not bidirectional\n"); - err = -EINVAL; - goto err_put_pp; + return; } - pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + db9_parport_cb.flags = PARPORT_FLAG_EXCL; + + pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx); if (!pd) { printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n"); - err = -EBUSY; - goto err_put_pp; + return; } db9 = kzalloc(sizeof(struct db9), GFP_KERNEL); - if (!db9) { - printk(KERN_ERR "db9.c: Not enough memory\n"); - err = -ENOMEM; + if (!db9) goto err_unreg_pardev; - } mutex_init(&db9->mutex); db9->pd = pd; db9->mode = mode; + db9->parportno = pp->number; init_timer(&db9->timer); db9->timer.data = (long) db9; db9->timer.function = db9_timer; @@ -610,7 +617,6 @@ static struct db9 __init *db9_probe(int parport, int mode) db9->dev[i] = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "db9.c: Not enough memory for input device\n"); - err = -ENOMEM; goto err_unreg_devs; } @@ -639,13 +645,12 @@ static struct db9 __init *db9_probe(int parport, int mode) input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0); } - err = input_register_device(input_dev); - if (err) + if (input_register_device(input_dev)) goto err_free_dev; } - parport_put_port(pp); - return db9; + db9_base[port_idx] = db9; + return; err_free_dev: input_free_device(db9->dev[i]); @@ -655,15 +660,23 @@ static struct db9 __init *db9_probe(int parport, int mode) kfree(db9); err_unreg_pardev: parport_unregister_device(pd); - err_put_pp: - parport_put_port(pp); - err_out: - return ERR_PTR(err); } -static void db9_remove(struct db9 *db9) +static void db9_detach(struct parport *port) { int i; + struct db9 *db9; + + for (i = 0; i < DB9_MAX_PORTS; i++) { + if (db9_base[i] && db9_base[i]->parportno == port->number) + break; + } + + if (i == DB9_MAX_PORTS) + return; + + db9 = db9_base[i]; + db9_base[i] = NULL; for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++) input_unregister_device(db9->dev[i]); @@ -671,11 +684,17 @@ static void db9_remove(struct db9 *db9) kfree(db9); } +static struct parport_driver db9_parport_driver = { + .name = "db9", + .match_port = db9_attach, + .detach = db9_detach, + .devmodel = true, +}; + static int __init db9_init(void) { int i; int have_dev = 0; - int err = 0; for (i = 0; i < DB9_MAX_PORTS; i++) { if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0) @@ -683,37 +702,21 @@ static int __init db9_init(void) if (db9_cfg[i].nargs < 2) { printk(KERN_ERR "db9.c: Device type must be specified.\n"); - err = -EINVAL; - break; - } - - db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT], - db9_cfg[i].args[DB9_ARG_MODE]); - if (IS_ERR(db9_base[i])) { - err = PTR_ERR(db9_base[i]); - break; + return -EINVAL; } have_dev = 1; } - if (err) { - while (--i >= 0) - if (db9_base[i]) - db9_remove(db9_base[i]); - return err; - } + if (!have_dev) + return -ENODEV; - return have_dev ? 0 : -ENODEV; + return parport_register_driver(&db9_parport_driver); } static void __exit db9_exit(void) { - int i; - - for (i = 0; i < DB9_MAX_PORTS; i++) - if (db9_base[i]) - db9_remove(db9_base[i]); + parport_unregister_driver(&db9_parport_driver); } module_init(db9_init); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index e68e49786483..5a672dcac0d8 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -53,7 +53,7 @@ struct gc_config { unsigned int nargs; }; -static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata; +static struct gc_config gc_cfg[GC_MAX_PORTS]; module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0); MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)"); @@ -92,6 +92,7 @@ struct gc { struct timer_list timer; int pad_count[GC_MAX]; int used; + int parportno; struct mutex mutex; }; @@ -304,7 +305,7 @@ static int gc_n64_play_effect(struct input_dev *dev, void *data, return 0; } -static int __init gc_n64_init_ff(struct input_dev *dev, int i) +static int gc_n64_init_ff(struct input_dev *dev, int i) { struct gc_subdev *sdev; int err; @@ -811,7 +812,7 @@ static void gc_close(struct input_dev *dev) mutex_unlock(&gc->mutex); } -static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) +static int gc_setup_pad(struct gc *gc, int idx, int pad_type) { struct gc_pad *pad = &gc->pads[idx]; struct input_dev *input_dev; @@ -926,46 +927,55 @@ err_free_dev: return err; } -static struct gc __init *gc_probe(int parport, int *pads, int n_pads) +static void gc_attach(struct parport *pp) { struct gc *gc; - struct parport *pp; struct pardevice *pd; - int i; + int i, port_idx; int count = 0; - int err; + int *pads, n_pads; + struct pardev_cb gc_parport_cb; + + for (port_idx = 0; port_idx < GC_MAX_PORTS; port_idx++) { + if (gc_cfg[port_idx].nargs == 0 || gc_cfg[port_idx].args[0] < 0) + continue; + + if (gc_cfg[port_idx].args[0] == pp->number) + break; + } - pp = parport_find_number(parport); - if (!pp) { - pr_err("no such parport %d\n", parport); - err = -EINVAL; - goto err_out; + if (port_idx == GC_MAX_PORTS) { + pr_debug("Not using parport%d.\n", pp->number); + return; } + pads = gc_cfg[port_idx].args + 1; + n_pads = gc_cfg[port_idx].nargs - 1; - pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + gc_parport_cb.flags = PARPORT_FLAG_EXCL; + + pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb, + port_idx); if (!pd) { pr_err("parport busy already - lp.o loaded?\n"); - err = -EBUSY; - goto err_put_pp; + return; } gc = kzalloc(sizeof(struct gc), GFP_KERNEL); if (!gc) { pr_err("Not enough memory\n"); - err = -ENOMEM; goto err_unreg_pardev; } mutex_init(&gc->mutex); gc->pd = pd; + gc->parportno = pp->number; setup_timer(&gc->timer, gc_timer, (long) gc); for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) { if (!pads[i]) continue; - err = gc_setup_pad(gc, i, pads[i]); - if (err) + if (gc_setup_pad(gc, i, pads[i])) goto err_unreg_devs; count++; @@ -973,12 +983,11 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) if (count == 0) { pr_err("No valid devices specified\n"); - err = -EINVAL; goto err_free_gc; } - parport_put_port(pp); - return gc; + gc_base[port_idx] = gc; + return; err_unreg_devs: while (--i >= 0) @@ -988,15 +997,23 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) kfree(gc); err_unreg_pardev: parport_unregister_device(pd); - err_put_pp: - parport_put_port(pp); - err_out: - return ERR_PTR(err); } -static void gc_remove(struct gc *gc) +static void gc_detach(struct parport *port) { int i; + struct gc *gc; + + for (i = 0; i < GC_MAX_PORTS; i++) { + if (gc_base[i] && gc_base[i]->parportno == port->number) + break; + } + + if (i == GC_MAX_PORTS) + return; + + gc = gc_base[i]; + gc_base[i] = NULL; for (i = 0; i < GC_MAX_DEVICES; i++) if (gc->pads[i].dev) @@ -1005,11 +1022,17 @@ static void gc_remove(struct gc *gc) kfree(gc); } +static struct parport_driver gc_parport_driver = { + .name = "gamecon", + .match_port = gc_attach, + .detach = gc_detach, + .devmodel = true, +}; + static int __init gc_init(void) { int i; int have_dev = 0; - int err = 0; for (i = 0; i < GC_MAX_PORTS; i++) { if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0) @@ -1017,37 +1040,21 @@ static int __init gc_init(void) if (gc_cfg[i].nargs < 2) { pr_err("at least one device must be specified\n"); - err = -EINVAL; - break; - } - - gc_base[i] = gc_probe(gc_cfg[i].args[0], - gc_cfg[i].args + 1, gc_cfg[i].nargs - 1); - if (IS_ERR(gc_base[i])) { - err = PTR_ERR(gc_base[i]); - break; + return -EINVAL; } have_dev = 1; } - if (err) { - while (--i >= 0) - if (gc_base[i]) - gc_remove(gc_base[i]); - return err; - } + if (!have_dev) + return -ENODEV; - return have_dev ? 0 : -ENODEV; + return parport_register_driver(&gc_parport_driver); } static void __exit gc_exit(void) { - int i; - - for (i = 0; i < GC_MAX_PORTS; i++) - if (gc_base[i]) - gc_remove(gc_base[i]); + parport_unregister_driver(&gc_parport_driver); } module_init(gc_init); diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 891797ad76bc..9f5bca26bd2f 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -49,7 +49,7 @@ struct tgfx_config { unsigned int nargs; }; -static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata; +static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS]; module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0); MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>"); @@ -81,6 +81,7 @@ static struct tgfx { char phys[TGFX_MAX_DEVICES][32]; int sticks; int used; + int parportno; struct mutex sem; } *tgfx_base[TGFX_MAX_PORTS]; @@ -156,38 +157,48 @@ static void tgfx_close(struct input_dev *dev) * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) +static void tgfx_attach(struct parport *pp) { struct tgfx *tgfx; struct input_dev *input_dev; - struct parport *pp; struct pardevice *pd; - int i, j; - int err; + int i, j, port_idx; + int *n_buttons, n_devs; + struct pardev_cb tgfx_parport_cb; + + for (port_idx = 0; port_idx < TGFX_MAX_PORTS; port_idx++) { + if (tgfx_cfg[port_idx].nargs == 0 || + tgfx_cfg[port_idx].args[0] < 0) + continue; + if (tgfx_cfg[port_idx].args[0] == pp->number) + break; + } - pp = parport_find_number(parport); - if (!pp) { - printk(KERN_ERR "turbografx.c: no such parport\n"); - err = -EINVAL; - goto err_out; + if (port_idx == TGFX_MAX_PORTS) { + pr_debug("Not using parport%d.\n", pp->number); + return; } + n_buttons = tgfx_cfg[port_idx].args + 1; + n_devs = tgfx_cfg[port_idx].nargs - 1; + + tgfx_parport_cb.flags = PARPORT_FLAG_EXCL; - pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb, + port_idx); if (!pd) { - printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n"); - err = -EBUSY; - goto err_put_pp; + pr_err("parport busy already - lp.o loaded?\n"); + return; } tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL); if (!tgfx) { printk(KERN_ERR "turbografx.c: Not enough memory\n"); - err = -ENOMEM; goto err_unreg_pardev; } mutex_init(&tgfx->sem); tgfx->pd = pd; + tgfx->parportno = pp->number; init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; tgfx->timer.function = tgfx_timer; @@ -198,14 +209,12 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) { printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]); - err = -EINVAL; goto err_unreg_devs; } tgfx->dev[i] = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "turbografx.c: Not enough memory for input device\n"); - err = -ENOMEM; goto err_unreg_devs; } @@ -234,19 +243,17 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) for (j = 0; j < n_buttons[i]; j++) set_bit(tgfx_buttons[j], input_dev->keybit); - err = input_register_device(tgfx->dev[i]); - if (err) + if (input_register_device(tgfx->dev[i])) goto err_free_dev; } if (!tgfx->sticks) { printk(KERN_ERR "turbografx.c: No valid devices specified\n"); - err = -EINVAL; goto err_free_tgfx; } - parport_put_port(pp); - return tgfx; + tgfx_base[port_idx] = tgfx; + return; err_free_dev: input_free_device(tgfx->dev[i]); @@ -258,15 +265,23 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) kfree(tgfx); err_unreg_pardev: parport_unregister_device(pd); - err_put_pp: - parport_put_port(pp); - err_out: - return ERR_PTR(err); } -static void tgfx_remove(struct tgfx *tgfx) +static void tgfx_detach(struct parport *port) { int i; + struct tgfx *tgfx; + + for (i = 0; i < TGFX_MAX_PORTS; i++) { + if (tgfx_base[i] && tgfx_base[i]->parportno == port->number) + break; + } + + if (i == TGFX_MAX_PORTS) + return; + + tgfx = tgfx_base[i]; + tgfx_base[i] = NULL; for (i = 0; i < TGFX_MAX_DEVICES; i++) if (tgfx->dev[i]) @@ -275,11 +290,17 @@ static void tgfx_remove(struct tgfx *tgfx) kfree(tgfx); } +static struct parport_driver tgfx_parport_driver = { + .name = "turbografx", + .match_port = tgfx_attach, + .detach = tgfx_detach, + .devmodel = true, +}; + static int __init tgfx_init(void) { int i; int have_dev = 0; - int err = 0; for (i = 0; i < TGFX_MAX_PORTS; i++) { if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0) @@ -287,38 +308,21 @@ static int __init tgfx_init(void) if (tgfx_cfg[i].nargs < 2) { printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); - err = -EINVAL; - break; - } - - tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0], - tgfx_cfg[i].args + 1, - tgfx_cfg[i].nargs - 1); - if (IS_ERR(tgfx_base[i])) { - err = PTR_ERR(tgfx_base[i]); - break; + return -EINVAL; } have_dev = 1; } - if (err) { - while (--i >= 0) - if (tgfx_base[i]) - tgfx_remove(tgfx_base[i]); - return err; - } + if (!have_dev) + return -ENODEV; - return have_dev ? 0 : -ENODEV; + return parport_register_driver(&tgfx_parport_driver); } static void __exit tgfx_exit(void) { - int i; - - for (i = 0; i < TGFX_MAX_PORTS; i++) - if (tgfx_base[i]) - tgfx_remove(tgfx_base[i]); + parport_unregister_driver(&tgfx_parport_driver); } module_init(tgfx_init); diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index a8bc2fe170dd..d88f5dd3c9d9 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -200,35 +200,38 @@ static void walkera0701_close(struct input_dev *dev) parport_release(w->pardevice); } -static int walkera0701_connect(struct walkera_dev *w, int parport) +static void walkera0701_attach(struct parport *pp) { - int error; + struct pardev_cb walkera0701_parport_cb; + struct walkera_dev *w = &w_dev; - w->parport = parport_find_number(parport); - if (!w->parport) { - pr_err("parport %d does not exist\n", parport); - return -ENODEV; + if (pp->number != walkera0701_pp_no) { + pr_debug("Not using parport%d.\n", pp->number); + return; } - if (w->parport->irq == -1) { + if (pp->irq == -1) { pr_err("parport %d does not have interrupt assigned\n", - parport); - error = -EINVAL; - goto err_put_parport; + pp->number); + return; } - w->pardevice = parport_register_device(w->parport, "walkera0701", - NULL, NULL, walkera0701_irq_handler, - PARPORT_DEV_EXCL, w); + w->parport = pp; + + walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL; + walkera0701_parport_cb.irq_func = walkera0701_irq_handler; + walkera0701_parport_cb.private = w; + + w->pardevice = parport_register_dev_model(pp, "walkera0701", + &walkera0701_parport_cb, 0); + if (!w->pardevice) { pr_err("failed to register parport device\n"); - error = -EIO; - goto err_put_parport; + return; } if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) { pr_err("failed to negotiate parport mode\n"); - error = -EIO; goto err_unregister_device; } @@ -238,7 +241,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport) w->input_dev = input_allocate_device(); if (!w->input_dev) { pr_err("failed to allocate input device\n"); - error = -ENOMEM; goto err_unregister_device; } @@ -265,38 +267,46 @@ static int walkera0701_connect(struct walkera_dev *w, int parport) input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0); input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0); - error = input_register_device(w->input_dev); - if (error) { + if (input_register_device(w->input_dev)) { pr_err("failed to register input device\n"); goto err_free_input_dev; } - return 0; + return; err_free_input_dev: input_free_device(w->input_dev); err_unregister_device: parport_unregister_device(w->pardevice); -err_put_parport: - parport_put_port(w->parport); - return error; } -static void walkera0701_disconnect(struct walkera_dev *w) +static void walkera0701_detach(struct parport *port) { + struct walkera_dev *w = &w_dev; + + if (!w->pardevice || w->parport->number != port->number) + return; + input_unregister_device(w->input_dev); parport_unregister_device(w->pardevice); - parport_put_port(w->parport); + w->parport = NULL; } +static struct parport_driver walkera0701_parport_driver = { + .name = "walkera0701", + .match_port = walkera0701_attach, + .detach = walkera0701_detach, + .devmodel = true, +}; + static int __init walkera0701_init(void) { - return walkera0701_connect(&w_dev, walkera0701_pp_no); + return parport_register_driver(&walkera0701_parport_driver); } static void __exit walkera0701_exit(void) { - walkera0701_disconnect(&w_dev); + parport_unregister_driver(&walkera0701_parport_driver); } module_init(walkera0701_init); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f8850f9cb331..fd4100d56d8c 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -125,6 +125,7 @@ static const struct xpad_device { { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, + { 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -204,7 +205,7 @@ static const struct xpad_device { { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, - { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 }, @@ -242,7 +243,6 @@ static const signed short xpad_btn_triggers[] = { -1 }; - static const signed short xpad360_btn[] = { /* buttons for x360 controller */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X button */ @@ -328,9 +328,6 @@ struct usb_xpad { unsigned char *idata; /* input data */ dma_addr_t idata_dma; - struct urb *bulk_out; - unsigned char *bdata; - struct urb *irq_out; /* urb for interrupt out report */ unsigned char *odata; /* output data */ dma_addr_t odata_dma; @@ -344,7 +341,8 @@ struct usb_xpad { int mapping; /* map d-pad to buttons or to axes */ int xtype; /* type of xbox device */ - unsigned long led_no; /* led to lit on xbox360 controllers */ + int pad_nr; /* the order x360 pads were attached */ + const char *name; /* name of the device */ }; /* @@ -356,7 +354,6 @@ struct usb_xpad { * The used report descriptor was taken from ITO Takayukis website: * http://euc.jp/periphs/xbox-controller.ja.html */ - static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { struct input_dev *dev = xpad->dev; @@ -439,7 +436,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08); input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01); input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02); - } else { + } + + /* + * This should be a simple else block. However historically + * xbox360w has mapped DPAD to buttons while xbox360 did not. This + * made no sense, but now we can not just switch back and have to + * support both behaviors. + */ + if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) || + xpad->xtype == XTYPE_XBOX360W) { input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); input_report_abs(dev, ABS_HAT0Y, @@ -505,14 +511,12 @@ static void xpad_identify_controller(struct usb_xpad *xpad); * 01.1 - Pad state (Bytes 4+) valid * */ - static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { /* Presence change */ if (data[0] & 0x08) { if (data[1] & 0x80) { xpad->pad_present = 1; - usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); /* * Light up the segment corresponding to * controller number. @@ -674,28 +678,6 @@ exit: __func__, retval); } -static void xpad_bulk_out(struct urb *urb) -{ - struct usb_xpad *xpad = urb->context; - struct device *dev = &xpad->intf->dev; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(dev, "%s - urb shutting down with status: %d\n", - __func__, urb->status); - break; - default: - dev_dbg(dev, "%s - nonzero urb status received: %d\n", - __func__, urb->status); - } -} - static void xpad_irq_out(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -786,84 +768,109 @@ static void xpad_deinit_output(struct usb_xpad *xpad) } } +static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) +{ + int retval; + + mutex_lock(&xpad->odata_mutex); + + xpad->odata[0] = 0x08; + xpad->odata[1] = 0x00; + xpad->odata[2] = 0x0F; + xpad->odata[3] = 0xC0; + xpad->odata[4] = 0x00; + xpad->odata[5] = 0x00; + xpad->odata[6] = 0x00; + xpad->odata[7] = 0x00; + xpad->odata[8] = 0x00; + xpad->odata[9] = 0x00; + xpad->odata[10] = 0x00; + xpad->odata[11] = 0x00; + xpad->irq_out->transfer_buffer_length = 12; + + retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); + + mutex_unlock(&xpad->odata_mutex); + + return retval; +} + #ifdef CONFIG_JOYSTICK_XPAD_FF static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { struct usb_xpad *xpad = input_get_drvdata(dev); + __u16 strong; + __u16 weak; - if (effect->type == FF_RUMBLE) { - __u16 strong = effect->u.rumble.strong_magnitude; - __u16 weak = effect->u.rumble.weak_magnitude; - - switch (xpad->xtype) { - - case XTYPE_XBOX: - xpad->odata[0] = 0x00; - xpad->odata[1] = 0x06; - xpad->odata[2] = 0x00; - xpad->odata[3] = strong / 256; /* left actuator */ - xpad->odata[4] = 0x00; - xpad->odata[5] = weak / 256; /* right actuator */ - xpad->irq_out->transfer_buffer_length = 6; - - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - - case XTYPE_XBOX360: - xpad->odata[0] = 0x00; - xpad->odata[1] = 0x08; - xpad->odata[2] = 0x00; - xpad->odata[3] = strong / 256; /* left actuator? */ - xpad->odata[4] = weak / 256; /* right actuator? */ - xpad->odata[5] = 0x00; - xpad->odata[6] = 0x00; - xpad->odata[7] = 0x00; - xpad->irq_out->transfer_buffer_length = 8; - - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - - case XTYPE_XBOX360W: - xpad->odata[0] = 0x00; - xpad->odata[1] = 0x01; - xpad->odata[2] = 0x0F; - xpad->odata[3] = 0xC0; - xpad->odata[4] = 0x00; - xpad->odata[5] = strong / 256; - xpad->odata[6] = weak / 256; - xpad->odata[7] = 0x00; - xpad->odata[8] = 0x00; - xpad->odata[9] = 0x00; - xpad->odata[10] = 0x00; - xpad->odata[11] = 0x00; - xpad->irq_out->transfer_buffer_length = 12; - - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - - case XTYPE_XBOXONE: - xpad->odata[0] = 0x09; /* activate rumble */ - xpad->odata[1] = 0x08; - xpad->odata[2] = 0x00; - xpad->odata[3] = 0x08; /* continuous effect */ - xpad->odata[4] = 0x00; /* simple rumble mode */ - xpad->odata[5] = 0x03; /* L and R actuator only */ - xpad->odata[6] = 0x00; /* TODO: LT actuator */ - xpad->odata[7] = 0x00; /* TODO: RT actuator */ - xpad->odata[8] = strong / 256; /* left actuator */ - xpad->odata[9] = weak / 256; /* right actuator */ - xpad->odata[10] = 0x80; /* length of pulse */ - xpad->odata[11] = 0x00; /* stop period of pulse */ - xpad->irq_out->transfer_buffer_length = 12; - - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - - default: - dev_dbg(&xpad->dev->dev, - "%s - rumble command sent to unsupported xpad type: %d\n", - __func__, xpad->xtype); - return -1; - } + if (effect->type != FF_RUMBLE) + return 0; + + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + + switch (xpad->xtype) { + case XTYPE_XBOX: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x06; + xpad->odata[2] = 0x00; + xpad->odata[3] = strong / 256; /* left actuator */ + xpad->odata[4] = 0x00; + xpad->odata[5] = weak / 256; /* right actuator */ + xpad->irq_out->transfer_buffer_length = 6; + break; + + case XTYPE_XBOX360: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x08; + xpad->odata[2] = 0x00; + xpad->odata[3] = strong / 256; /* left actuator? */ + xpad->odata[4] = weak / 256; /* right actuator? */ + xpad->odata[5] = 0x00; + xpad->odata[6] = 0x00; + xpad->odata[7] = 0x00; + xpad->irq_out->transfer_buffer_length = 8; + break; + + case XTYPE_XBOX360W: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x01; + xpad->odata[2] = 0x0F; + xpad->odata[3] = 0xC0; + xpad->odata[4] = 0x00; + xpad->odata[5] = strong / 256; + xpad->odata[6] = weak / 256; + xpad->odata[7] = 0x00; + xpad->odata[8] = 0x00; + xpad->odata[9] = 0x00; + xpad->odata[10] = 0x00; + xpad->odata[11] = 0x00; + xpad->irq_out->transfer_buffer_length = 12; + break; + + case XTYPE_XBOXONE: + xpad->odata[0] = 0x09; /* activate rumble */ + xpad->odata[1] = 0x08; + xpad->odata[2] = 0x00; + xpad->odata[3] = 0x08; /* continuous effect */ + xpad->odata[4] = 0x00; /* simple rumble mode */ + xpad->odata[5] = 0x03; /* L and R actuator only */ + xpad->odata[6] = 0x00; /* TODO: LT actuator */ + xpad->odata[7] = 0x00; /* TODO: RT actuator */ + xpad->odata[8] = strong / 256; /* left actuator */ + xpad->odata[9] = weak / 256; /* right actuator */ + xpad->odata[10] = 0x80; /* length of pulse */ + xpad->odata[11] = 0x00; /* stop period of pulse */ + xpad->irq_out->transfer_buffer_length = 12; + break; + + default: + dev_dbg(&xpad->dev->dev, + "%s - rumble command sent to unsupported xpad type: %d\n", + __func__, xpad->xtype); + return -EINVAL; } - return 0; + return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); } static int xpad_init_ff(struct usb_xpad *xpad) @@ -882,6 +889,9 @@ static int xpad_init_ff(struct usb_xpad *xpad) { return 0; } #if defined(CONFIG_JOYSTICK_XPAD_LEDS) #include <linux/leds.h> +#include <linux/idr.h> + +static DEFINE_IDA(xpad_pad_seq); struct xpad_led { char name[16]; @@ -890,6 +900,7 @@ struct xpad_led { }; /** + * set the LEDs on Xbox360 / Wireless Controllers * @param command * 0: off * 1: all blink, then previous setting @@ -942,10 +953,13 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) mutex_unlock(&xpad->odata_mutex); } +/* + * Light up the segment corresponding to the pad number on + * Xbox 360 Controllers. + */ static void xpad_identify_controller(struct usb_xpad *xpad) { - /* Light up the segment corresponding to controller number */ - xpad_send_led_command(xpad, (xpad->led_no % 4) + 2); + xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2); } static void xpad_led_set(struct led_classdev *led_cdev, @@ -959,7 +973,6 @@ static void xpad_led_set(struct led_classdev *led_cdev, static int xpad_led_probe(struct usb_xpad *xpad) { - static atomic_t led_seq = ATOMIC_INIT(-1); struct xpad_led *led; struct led_classdev *led_cdev; int error; @@ -971,9 +984,13 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (!led) return -ENOMEM; - xpad->led_no = atomic_inc_return(&led_seq); + xpad->pad_nr = ida_simple_get(&xpad_pad_seq, 0, 0, GFP_KERNEL); + if (xpad->pad_nr < 0) { + error = xpad->pad_nr; + goto err_free_mem; + } - snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no); + snprintf(led->name, sizeof(led->name), "xpad%d", xpad->pad_nr); led->xpad = xpad; led_cdev = &led->led_cdev; @@ -981,16 +998,26 @@ static int xpad_led_probe(struct usb_xpad *xpad) led_cdev->brightness_set = xpad_led_set; error = led_classdev_register(&xpad->udev->dev, led_cdev); - if (error) { - kfree(led); - xpad->led = NULL; - return error; - } + if (error) + goto err_free_id; - /* Light up the segment corresponding to controller number */ - xpad_identify_controller(xpad); + if (xpad->xtype == XTYPE_XBOX360) { + /* + * Light up the segment corresponding to controller + * number on wired devices. On wireless we'll do that + * when they respond to "presence" packet. + */ + xpad_identify_controller(xpad); + } return 0; + +err_free_id: + ida_simple_remove(&xpad_pad_seq, xpad->pad_nr); +err_free_mem: + kfree(led); + xpad->led = NULL; + return error; } static void xpad_led_disconnect(struct usb_xpad *xpad) @@ -999,6 +1026,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) if (xpad_led) { led_classdev_unregister(&xpad_led->led_cdev); + ida_simple_remove(&xpad_pad_seq, xpad->pad_nr); kfree(xpad_led); } } @@ -1008,7 +1036,6 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { } static void xpad_identify_controller(struct usb_xpad *xpad) { } #endif - static int xpad_open(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); @@ -1068,11 +1095,107 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) } } +static void xpad_deinit_input(struct usb_xpad *xpad) +{ + xpad_led_disconnect(xpad); + input_unregister_device(xpad->dev); +} + +static int xpad_init_input(struct usb_xpad *xpad) +{ + struct input_dev *input_dev; + int i, error; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + xpad->dev = input_dev; + input_dev->name = xpad->name; + input_dev->phys = xpad->phys; + usb_to_input_id(xpad->udev, &input_dev->id); + input_dev->dev.parent = &xpad->intf->dev; + + input_set_drvdata(input_dev, xpad); + + input_dev->open = xpad_open; + input_dev->close = xpad_close; + + __set_bit(EV_KEY, input_dev->evbit); + + if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { + __set_bit(EV_ABS, input_dev->evbit); + /* set up axes */ + for (i = 0; xpad_abs[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs[i]); + } + + /* set up standard buttons */ + for (i = 0; xpad_common_btn[i] >= 0; i++) + __set_bit(xpad_common_btn[i], input_dev->keybit); + + /* set up model-specific ones */ + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W || + xpad->xtype == XTYPE_XBOXONE) { + for (i = 0; xpad360_btn[i] >= 0; i++) + __set_bit(xpad360_btn[i], input_dev->keybit); + } else { + for (i = 0; xpad_btn[i] >= 0; i++) + __set_bit(xpad_btn[i], input_dev->keybit); + } + + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { + for (i = 0; xpad_btn_pad[i] >= 0; i++) + __set_bit(xpad_btn_pad[i], input_dev->keybit); + } + + /* + * This should be a simple else block. However historically + * xbox360w has mapped DPAD to buttons while xbox360 did not. This + * made no sense, but now we can not just switch back and have to + * support both behaviors. + */ + if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) || + xpad->xtype == XTYPE_XBOX360W) { + for (i = 0; xpad_abs_pad[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_pad[i]); + } + + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + for (i = 0; xpad_btn_triggers[i] >= 0; i++) + __set_bit(xpad_btn_triggers[i], input_dev->keybit); + } else { + for (i = 0; xpad_abs_triggers[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); + } + + error = xpad_init_ff(xpad); + if (error) + goto err_free_input; + + error = xpad_led_probe(xpad); + if (error) + goto err_destroy_ff; + + error = input_register_device(xpad->dev); + if (error) + goto err_disconnect_led; + + return 0; + +err_disconnect_led: + xpad_led_disconnect(xpad); +err_destroy_ff: + input_ff_destroy(input_dev); +err_free_input: + input_free_device(input_dev); + return error; +} + static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_xpad *xpad; - struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; int ep_irq_in_idx; int i, error; @@ -1094,29 +1217,30 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id } xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!xpad || !input_dev) { - error = -ENOMEM; - goto fail1; - } + if (!xpad) + return -ENOMEM; + + usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); + strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, GFP_KERNEL, &xpad->idata_dma); if (!xpad->idata) { error = -ENOMEM; - goto fail1; + goto err_free_mem; } xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) { error = -ENOMEM; - goto fail2; + goto err_free_idata; } xpad->udev = udev; xpad->intf = intf; xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; + xpad->name = xpad_device[i].name; if (xpad->xtype == XTYPE_UNKNOWN) { if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { @@ -1124,8 +1248,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->xtype = XTYPE_XBOX360W; else xpad->xtype = XTYPE_XBOX360; - } else + } else { xpad->xtype = XTYPE_XBOX; + } if (dpad_to_buttons) xpad->mapping |= MAP_DPAD_TO_BUTTONS; @@ -1135,70 +1260,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->mapping |= MAP_STICKS_TO_NULL; } - xpad->dev = input_dev; - usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); - strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); - - input_dev->name = xpad_device[i].name; - input_dev->phys = xpad->phys; - usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &intf->dev; - - input_set_drvdata(input_dev, xpad); - - input_dev->open = xpad_open; - input_dev->close = xpad_close; - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - - if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { - input_dev->evbit[0] |= BIT_MASK(EV_ABS); - /* set up axes */ - for (i = 0; xpad_abs[i] >= 0; i++) - xpad_set_up_abs(input_dev, xpad_abs[i]); - } - - /* set up standard buttons */ - for (i = 0; xpad_common_btn[i] >= 0; i++) - __set_bit(xpad_common_btn[i], input_dev->keybit); - - /* set up model-specific ones */ - if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W || - xpad->xtype == XTYPE_XBOXONE) { - for (i = 0; xpad360_btn[i] >= 0; i++) - __set_bit(xpad360_btn[i], input_dev->keybit); - } else { - for (i = 0; xpad_btn[i] >= 0; i++) - __set_bit(xpad_btn[i], input_dev->keybit); - } - - if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { - for (i = 0; xpad_btn_pad[i] >= 0; i++) - __set_bit(xpad_btn_pad[i], input_dev->keybit); - } else { - for (i = 0; xpad_abs_pad[i] >= 0; i++) - xpad_set_up_abs(input_dev, xpad_abs_pad[i]); - } - - if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { - for (i = 0; xpad_btn_triggers[i] >= 0; i++) - __set_bit(xpad_btn_triggers[i], input_dev->keybit); - } else { - for (i = 0; xpad_abs_triggers[i] >= 0; i++) - xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); - } - error = xpad_init_output(intf, xpad); if (error) - goto fail3; - - error = xpad_init_ff(xpad); - if (error) - goto fail4; - - error = xpad_led_probe(xpad); - if (error) - goto fail5; + goto err_free_in_urb; /* Xbox One controller has in/out endpoints swapped. */ ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0; @@ -1211,59 +1275,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - error = input_register_device(xpad->dev); - if (error) - goto fail6; - usb_set_intfdata(intf, xpad); - if (xpad->xtype == XTYPE_XBOX360W) { - /* - * Setup the message to set the LEDs on the - * controller when it shows up - */ - xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); - if (!xpad->bulk_out) { - error = -ENOMEM; - goto fail7; - } - - xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); - if (!xpad->bdata) { - error = -ENOMEM; - goto fail8; - } - - xpad->bdata[2] = 0x08; - switch (intf->cur_altsetting->desc.bInterfaceNumber) { - case 0: - xpad->bdata[3] = 0x42; - break; - case 2: - xpad->bdata[3] = 0x43; - break; - case 4: - xpad->bdata[3] = 0x44; - break; - case 6: - xpad->bdata[3] = 0x45; - } - - ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; - if (usb_endpoint_is_bulk_out(ep_irq_in)) { - usb_fill_bulk_urb(xpad->bulk_out, udev, - usb_sndbulkpipe(udev, - ep_irq_in->bEndpointAddress), - xpad->bdata, XPAD_PKT_LEN, - xpad_bulk_out, xpad); - } else { - usb_fill_int_urb(xpad->bulk_out, udev, - usb_sndintpipe(udev, - ep_irq_in->bEndpointAddress), - xpad->bdata, XPAD_PKT_LEN, - xpad_bulk_out, xpad, 0); - } + error = xpad_init_input(xpad); + if (error) + goto err_deinit_output; + if (xpad->xtype == XTYPE_XBOX360W) { /* * Submit the int URB immediately rather than waiting for open * because we get status messages from the device whether @@ -1274,22 +1292,32 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->irq_in->dev = xpad->udev; error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); if (error) - goto fail9; - } + goto err_deinit_input; + /* + * Send presence packet. + * This will force the controller to resend connection packets. + * This is useful in the case we activate the module after the + * adapter has been plugged in, as it won't automatically + * send us info about the controllers. + */ + error = xpad_inquiry_pad_presence(xpad); + if (error) + goto err_kill_in_urb; + } return 0; - fail9: kfree(xpad->bdata); - fail8: usb_free_urb(xpad->bulk_out); - fail7: input_unregister_device(input_dev); - input_dev = NULL; - fail6: xpad_led_disconnect(xpad); - fail5: if (input_dev) - input_ff_destroy(input_dev); - fail4: xpad_deinit_output(xpad); - fail3: usb_free_urb(xpad->irq_in); - fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); - fail1: input_free_device(input_dev); +err_kill_in_urb: + usb_kill_urb(xpad->irq_in); +err_deinit_input: + xpad_deinit_input(xpad); +err_deinit_output: + xpad_deinit_output(xpad); +err_free_in_urb: + usb_free_urb(xpad->irq_in); +err_free_idata: + usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +err_free_mem: kfree(xpad); return error; @@ -1299,13 +1327,10 @@ static void xpad_disconnect(struct usb_interface *intf) { struct usb_xpad *xpad = usb_get_intfdata (intf); - xpad_led_disconnect(xpad); - input_unregister_device(xpad->dev); + xpad_deinit_input(xpad); xpad_deinit_output(xpad); if (xpad->xtype == XTYPE_XBOX360W) { - usb_kill_urb(xpad->bulk_out); - usb_free_urb(xpad->bulk_out); usb_kill_urb(xpad->irq_in); } @@ -1313,7 +1338,6 @@ static void xpad_disconnect(struct usb_interface *intf) usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); - kfree(xpad->bdata); kfree(xpad); usb_set_intfdata(intf, NULL); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 2e80107ff630..ddd8148d51d7 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -516,7 +516,7 @@ config KEYBOARD_SAMSUNG module will be called samsung-keypad. config KEYBOARD_GOLDFISH_EVENTS - depends on GOLDFISH + depends on GOLDFISH || COMPILE_TEST tristate "Generic Input Event device for Goldfish" help Say Y here to get an input event device for the Goldfish virtual diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 9d517ca7eb5a..bef317ff7352 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -341,8 +341,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) const struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; + int state = gpio_get_value_cansleep(button->gpio); + if (state < 0) { + dev_err(input->dev.parent, "failed to get gpio state\n"); + return; + } + + state = (state ? 1 : 0) ^ button->active_low; if (type == EV_ABS) { if (state) input_event(input, type, button->code, button->value); diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 870cfa6e2c44..62bdb1d48c49 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -40,10 +40,36 @@ struct gpio_keys_polled_dev { struct input_polled_dev *poll_dev; struct device *dev; const struct gpio_keys_platform_data *pdata; + unsigned long rel_axis_seen[BITS_TO_LONGS(REL_CNT)]; + unsigned long abs_axis_seen[BITS_TO_LONGS(ABS_CNT)]; struct gpio_keys_button_data data[0]; }; -static void gpio_keys_polled_check_state(struct input_dev *input, +static void gpio_keys_button_event(struct input_polled_dev *dev, + struct gpio_keys_button *button, + int state) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct input_dev *input = dev->input; + unsigned int type = button->type ?: EV_KEY; + + if (type == EV_REL) { + if (state) { + input_event(input, type, button->code, button->value); + __set_bit(button->code, bdev->rel_axis_seen); + } + } else if (type == EV_ABS) { + if (state) { + input_event(input, type, button->code, button->value); + __set_bit(button->code, bdev->abs_axis_seen); + } + } else { + input_event(input, type, button->code, state); + input_sync(input); + } +} + +static void gpio_keys_polled_check_state(struct input_polled_dev *dev, struct gpio_keys_button *button, struct gpio_keys_button_data *bdata) { @@ -54,11 +80,9 @@ static void gpio_keys_polled_check_state(struct input_dev *input, else state = !!gpiod_get_value(button->gpiod); - if (state != bdata->last_state) { - unsigned int type = button->type ?: EV_KEY; + gpio_keys_button_event(dev, button, state); - input_event(input, type, button->code, state); - input_sync(input); + if (state != bdata->last_state) { bdata->count = 0; bdata->last_state = state; } @@ -71,15 +95,33 @@ static void gpio_keys_polled_poll(struct input_polled_dev *dev) struct input_dev *input = dev->input; int i; + memset(bdev->rel_axis_seen, 0, sizeof(bdev->rel_axis_seen)); + memset(bdev->abs_axis_seen, 0, sizeof(bdev->abs_axis_seen)); + for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button_data *bdata = &bdev->data[i]; - if (bdata->count < bdata->threshold) + if (bdata->count < bdata->threshold) { bdata->count++; - else - gpio_keys_polled_check_state(input, &pdata->buttons[i], + gpio_keys_button_event(dev, &pdata->buttons[i], + bdata->last_state); + } else { + gpio_keys_polled_check_state(dev, &pdata->buttons[i], bdata); + } + } + + for_each_set_bit(i, input->relbit, REL_CNT) { + if (!test_bit(i, bdev->rel_axis_seen)) + input_event(input, EV_REL, i, 0); + } + + for_each_set_bit(i, input->absbit, ABS_CNT) { + if (!test_bit(i, bdev->abs_axis_seen)) + input_event(input, EV_ABS, i, 0); } + + input_sync(input); } static void gpio_keys_polled_open(struct input_polled_dev *dev) @@ -152,6 +194,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct &button->type)) button->type = EV_KEY; + if (fwnode_property_read_u32(child, "linux,input-value", + (u32 *)&button->value)) + button->value = 1; + button->wakeup = fwnode_property_read_bool(child, "wakeup-source") || /* legacy name */ @@ -168,6 +214,25 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct return pdata; } +static void gpio_keys_polled_set_abs_params(struct input_dev *input, + const struct gpio_keys_platform_data *pdata, unsigned int code) +{ + int i, min = 0, max = 0; + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + + if (button->type != EV_ABS || button->code != code) + continue; + + if (button->value < min) + min = button->value; + if (button->value > max) + max = button->value; + } + input_set_abs_params(input, code, min, max, 0, 0); +} + static const struct of_device_id gpio_keys_polled_of_match[] = { { .compatible = "gpio-keys-polled", }, { }, @@ -274,6 +339,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) pdata->poll_interval); input_set_capability(input, type, button->code); + if (type == EV_ABS) + gpio_keys_polled_set_abs_params(input, pdata, + button->code); } bdev->poll_dev = poll_dev; @@ -290,9 +358,11 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) /* report initial state of the buttons */ for (i = 0; i < pdata->nbuttons; i++) - gpio_keys_polled_check_state(input, &pdata->buttons[i], + gpio_keys_polled_check_state(poll_dev, &pdata->buttons[i], &bdev->data[i]); + input_sync(input); + return 0; } diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index c7d5b1666fc3..8567ee47761e 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -54,7 +54,7 @@ /** * struct ske_keypad - data structure used by keypad driver * @irq: irq no - * @reg_base: ske regsiters base address + * @reg_base: ske registers base address * @input: pointer to input device object * @board: keypad platform device * @keymap: matrix scan code table for keycodes diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 78fd24ca3813..9adf13a5864a 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -110,8 +110,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; - pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");; - + pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap"); if (!pdata->snvs) { dev_err(&pdev->dev, "Can't get snvs syscon\n"); return -ENODEV; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index f97c73bd14f8..acc5394afb03 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -517,7 +517,8 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) if (of_find_property(np, "nvidia,needs-ghost-filter", NULL)) kbc->use_ghost_filter = true; - if (of_find_property(np, "nvidia,wakeup-source", NULL)) + if (of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */ kbc->wakeup = true; if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) { @@ -705,7 +706,7 @@ static int tegra_kbc_probe(struct platform_device *pdev) input_set_drvdata(kbc->idev, kbc); err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr, - IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc); + IRQF_TRIGGER_HIGH, pdev->name, kbc); if (err) { dev_err(&pdev->dev, "failed to request keyboard IRQ\n"); return err; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 906dd1b25e41..d6d16fa78281 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -94,11 +94,11 @@ config INPUT_BMA150 module will be called bma150. config INPUT_E3X0_BUTTON - tristate "NI Ettus Research USRP E3x0 Button support." + tristate "NI Ettus Research USRP E3xx Button support." default n help Say Y here to enable support for the NI Ettus Research - USRP E3x0 Button. + USRP E3xx Button. To compile this driver as a module, choose M here: the module will be called e3x0_button. @@ -599,11 +599,11 @@ config INPUT_DA9055_ONKEY will be called da9055_onkey. config INPUT_DA9063_ONKEY - tristate "Dialog DA9063 OnKey" - depends on MFD_DA9063 + tristate "Dialog DA9062/63 OnKey" + depends on MFD_DA9063 || MFD_DA9062 help - Support the ONKEY of Dialog DA9063 Power Management IC as an - input device reporting power button statue. + Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs + as an input device capable of reporting the power button status. To compile this driver as a module, choose M here: the module will be called da9063_onkey. diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 189bdc8e91a5..2f047738bc0b 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -85,15 +85,6 @@ static int ad714x_i2c_probe(struct i2c_client *client, return 0; } -static int ad714x_i2c_remove(struct i2c_client *client) -{ - struct ad714x_chip *chip = i2c_get_clientdata(client); - - ad714x_remove(chip); - - return 0; -} - static const struct i2c_device_id ad714x_id[] = { { "ad7142_captouch", 0 }, { "ad7143_captouch", 0 }, @@ -110,7 +101,6 @@ static struct i2c_driver ad714x_i2c_driver = { .pm = &ad714x_i2c_pm, }, .probe = ad714x_i2c_probe, - .remove = ad714x_i2c_remove, .id_table = ad714x_id, }; diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index fea315e76bc8..aac910326447 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -101,22 +101,12 @@ static int ad714x_spi_probe(struct spi_device *spi) return 0; } -static int ad714x_spi_remove(struct spi_device *spi) -{ - struct ad714x_chip *chip = spi_get_drvdata(spi); - - ad714x_remove(chip); - - return 0; -} - static struct spi_driver ad714x_spi_driver = { .driver = { .name = "ad714x_captouch", .pm = &ad714x_spi_pm, }, .probe = ad714x_spi_probe, - .remove = ad714x_spi_remove, }; module_spi_driver(ad714x_spi_driver); diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index 7a61e9ee682c..84b51dd51f6e 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -960,13 +960,12 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data) return IRQ_HANDLED; } -#define MAX_DEVICE_NUM 8 struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, ad714x_read_t read, ad714x_write_t write) { - int i, alloc_idx; + int i; int error; - struct input_dev *input[MAX_DEVICE_NUM]; + struct input_dev *input; struct ad714x_platform_data *plat_data = dev_get_platdata(dev); struct ad714x_chip *ad714x; @@ -982,25 +981,25 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, if (irq <= 0) { dev_err(dev, "IRQ not configured!\n"); error = -EINVAL; - goto err_out; + return ERR_PTR(error); } if (dev_get_platdata(dev) == NULL) { dev_err(dev, "platform data for ad714x doesn't exist\n"); error = -EINVAL; - goto err_out; + return ERR_PTR(error); } - ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) + - sizeof(*sd_drv) * plat_data->slider_num + - sizeof(*wl_drv) * plat_data->wheel_num + - sizeof(*tp_drv) * plat_data->touchpad_num + - sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL); + ad714x = devm_kzalloc(dev, sizeof(*ad714x) + sizeof(*ad714x->sw) + + sizeof(*sd_drv) * plat_data->slider_num + + sizeof(*wl_drv) * plat_data->wheel_num + + sizeof(*tp_drv) * plat_data->touchpad_num + + sizeof(*bt_drv) * plat_data->button_num, + GFP_KERNEL); if (!ad714x) { error = -ENOMEM; - goto err_out; + return ERR_PTR(error); } - ad714x->hw = plat_data; drv_mem = ad714x + 1; @@ -1022,47 +1021,40 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, error = ad714x_hw_detect(ad714x); if (error) - goto err_free_mem; + return ERR_PTR(error); /* initialize and request sw/hw resources */ ad714x_hw_init(ad714x); mutex_init(&ad714x->mutex); - /* - * Allocate and register AD714X input device - */ - alloc_idx = 0; - /* a slider uses one input_dev instance */ if (ad714x->hw->slider_num > 0) { struct ad714x_slider_plat *sd_plat = ad714x->hw->slider; for (i = 0; i < ad714x->hw->slider_num; i++) { - sd_drv[i].input = input[alloc_idx] = input_allocate_device(); - if (!input[alloc_idx]) { - error = -ENOMEM; - goto err_free_dev; - } - - __set_bit(EV_ABS, input[alloc_idx]->evbit); - __set_bit(EV_KEY, input[alloc_idx]->evbit); - __set_bit(ABS_X, input[alloc_idx]->absbit); - __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); - input_set_abs_params(input[alloc_idx], + input = devm_input_allocate_device(dev); + if (!input) + return ERR_PTR(-ENOMEM); + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_KEY, input->evbit); + __set_bit(ABS_X, input->absbit); + __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_X, 0, sd_plat->max_coord, 0, 0); - input[alloc_idx]->id.bustype = bus_type; - input[alloc_idx]->id.product = ad714x->product; - input[alloc_idx]->id.version = ad714x->version; - input[alloc_idx]->name = "ad714x_captouch_slider"; - input[alloc_idx]->dev.parent = dev; + input->id.bustype = bus_type; + input->id.product = ad714x->product; + input->id.version = ad714x->version; + input->name = "ad714x_captouch_slider"; + input->dev.parent = dev; - error = input_register_device(input[alloc_idx]); + error = input_register_device(input); if (error) - goto err_free_dev; + return ERR_PTR(error); - alloc_idx++; + sd_drv[i].input = input; } } @@ -1071,30 +1063,28 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel; for (i = 0; i < ad714x->hw->wheel_num; i++) { - wl_drv[i].input = input[alloc_idx] = input_allocate_device(); - if (!input[alloc_idx]) { - error = -ENOMEM; - goto err_free_dev; - } - - __set_bit(EV_KEY, input[alloc_idx]->evbit); - __set_bit(EV_ABS, input[alloc_idx]->evbit); - __set_bit(ABS_WHEEL, input[alloc_idx]->absbit); - __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); - input_set_abs_params(input[alloc_idx], + input = devm_input_allocate_device(dev); + if (!input) + return ERR_PTR(-ENOMEM); + + __set_bit(EV_KEY, input->evbit); + __set_bit(EV_ABS, input->evbit); + __set_bit(ABS_WHEEL, input->absbit); + __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_WHEEL, 0, wl_plat->max_coord, 0, 0); - input[alloc_idx]->id.bustype = bus_type; - input[alloc_idx]->id.product = ad714x->product; - input[alloc_idx]->id.version = ad714x->version; - input[alloc_idx]->name = "ad714x_captouch_wheel"; - input[alloc_idx]->dev.parent = dev; + input->id.bustype = bus_type; + input->id.product = ad714x->product; + input->id.version = ad714x->version; + input->name = "ad714x_captouch_wheel"; + input->dev.parent = dev; - error = input_register_device(input[alloc_idx]); + error = input_register_device(input); if (error) - goto err_free_dev; + return ERR_PTR(error); - alloc_idx++; + wl_drv[i].input = input; } } @@ -1103,33 +1093,31 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad; for (i = 0; i < ad714x->hw->touchpad_num; i++) { - tp_drv[i].input = input[alloc_idx] = input_allocate_device(); - if (!input[alloc_idx]) { - error = -ENOMEM; - goto err_free_dev; - } - - __set_bit(EV_ABS, input[alloc_idx]->evbit); - __set_bit(EV_KEY, input[alloc_idx]->evbit); - __set_bit(ABS_X, input[alloc_idx]->absbit); - __set_bit(ABS_Y, input[alloc_idx]->absbit); - __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); - input_set_abs_params(input[alloc_idx], + input = devm_input_allocate_device(dev); + if (!input) + return ERR_PTR(-ENOMEM); + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_KEY, input->evbit); + __set_bit(ABS_X, input->absbit); + __set_bit(ABS_Y, input->absbit); + __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_X, 0, tp_plat->x_max_coord, 0, 0); - input_set_abs_params(input[alloc_idx], + input_set_abs_params(input, ABS_Y, 0, tp_plat->y_max_coord, 0, 0); - input[alloc_idx]->id.bustype = bus_type; - input[alloc_idx]->id.product = ad714x->product; - input[alloc_idx]->id.version = ad714x->version; - input[alloc_idx]->name = "ad714x_captouch_pad"; - input[alloc_idx]->dev.parent = dev; + input->id.bustype = bus_type; + input->id.product = ad714x->product; + input->id.version = ad714x->version; + input->name = "ad714x_captouch_pad"; + input->dev.parent = dev; - error = input_register_device(input[alloc_idx]); + error = input_register_device(input); if (error) - goto err_free_dev; + return ERR_PTR(error); - alloc_idx++; + tp_drv[i].input = input; } } @@ -1137,82 +1125,44 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, if (ad714x->hw->button_num > 0) { struct ad714x_button_plat *bt_plat = ad714x->hw->button; - input[alloc_idx] = input_allocate_device(); - if (!input[alloc_idx]) { + input = devm_input_allocate_device(dev); + if (!input) { error = -ENOMEM; - goto err_free_dev; + return ERR_PTR(error); } - __set_bit(EV_KEY, input[alloc_idx]->evbit); + __set_bit(EV_KEY, input->evbit); for (i = 0; i < ad714x->hw->button_num; i++) { - bt_drv[i].input = input[alloc_idx]; - __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit); + bt_drv[i].input = input; + __set_bit(bt_plat[i].keycode, input->keybit); } - input[alloc_idx]->id.bustype = bus_type; - input[alloc_idx]->id.product = ad714x->product; - input[alloc_idx]->id.version = ad714x->version; - input[alloc_idx]->name = "ad714x_captouch_button"; - input[alloc_idx]->dev.parent = dev; + input->id.bustype = bus_type; + input->id.product = ad714x->product; + input->id.version = ad714x->version; + input->name = "ad714x_captouch_button"; + input->dev.parent = dev; - error = input_register_device(input[alloc_idx]); + error = input_register_device(input); if (error) - goto err_free_dev; - - alloc_idx++; + return ERR_PTR(error); } irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING; irqflags |= IRQF_ONESHOT; - error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread, - irqflags, "ad714x_captouch", ad714x); + error = devm_request_threaded_irq(dev, ad714x->irq, NULL, + ad714x_interrupt_thread, + irqflags, "ad714x_captouch", ad714x); if (error) { dev_err(dev, "can't allocate irq %d\n", ad714x->irq); - goto err_unreg_dev; + return ERR_PTR(error); } return ad714x; - - err_free_dev: - dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx); - input_free_device(input[alloc_idx]); - err_unreg_dev: - while (--alloc_idx >= 0) - input_unregister_device(input[alloc_idx]); - err_free_mem: - kfree(ad714x); - err_out: - return ERR_PTR(error); } EXPORT_SYMBOL(ad714x_probe); -void ad714x_remove(struct ad714x_chip *ad714x) -{ - struct ad714x_platform_data *hw = ad714x->hw; - struct ad714x_driver_data *sw = ad714x->sw; - int i; - - free_irq(ad714x->irq, ad714x); - - /* unregister and free all input devices */ - - for (i = 0; i < hw->slider_num; i++) - input_unregister_device(sw->slider[i].input); - - for (i = 0; i < hw->wheel_num; i++) - input_unregister_device(sw->wheel[i].input); - - for (i = 0; i < hw->touchpad_num; i++) - input_unregister_device(sw->touchpad[i].input); - - if (hw->button_num) - input_unregister_device(sw->button[0].input); - - kfree(ad714x); -} -EXPORT_SYMBOL(ad714x_remove); - #ifdef CONFIG_PM int ad714x_disable(struct ad714x_chip *ad714x) { diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h index 3c85455aa66d..5d65d303b9bf 100644 --- a/drivers/input/misc/ad714x.h +++ b/drivers/input/misc/ad714x.h @@ -50,6 +50,5 @@ int ad714x_disable(struct ad714x_chip *ad714x); int ad714x_enable(struct ad714x_chip *ad714x); struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, ad714x_read_t read, ad714x_write_t write); -void ad714x_remove(struct ad714x_chip *ad714x); #endif diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index f577585ef999..8eb697db82d0 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -1,5 +1,5 @@ /* - * OnKey device driver for DA9063 + * OnKey device driver for DA9063 and DA9062 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or @@ -24,36 +24,96 @@ #include <linux/mfd/da9063/core.h> #include <linux/mfd/da9063/pdata.h> #include <linux/mfd/da9063/registers.h> +#include <linux/mfd/da9062/core.h> +#include <linux/mfd/da9062/registers.h> + +struct da906x_chip_config { + /* REGS */ + int onkey_status; + int onkey_pwr_signalling; + int onkey_fault_log; + int onkey_shutdown; + /* MASKS */ + int onkey_nonkey_mask; + int onkey_nonkey_lock_mask; + int onkey_key_reset_mask; + int onkey_shutdown_mask; + /* NAMES */ + const char *name; +}; struct da9063_onkey { - struct da9063 *hw; struct delayed_work work; struct input_dev *input; struct device *dev; + struct regmap *regmap; + const struct da906x_chip_config *config; + char phys[32]; bool key_power; }; +static const struct da906x_chip_config da9063_regs = { + /* REGS */ + .onkey_status = DA9063_REG_STATUS_A, + .onkey_pwr_signalling = DA9063_REG_CONTROL_B, + .onkey_fault_log = DA9063_REG_FAULT_LOG, + .onkey_shutdown = DA9063_REG_CONTROL_F, + /* MASKS */ + .onkey_nonkey_mask = DA9063_NONKEY, + .onkey_nonkey_lock_mask = DA9063_NONKEY_LOCK, + .onkey_key_reset_mask = DA9063_KEY_RESET, + .onkey_shutdown_mask = DA9063_SHUTDOWN, + /* NAMES */ + .name = DA9063_DRVNAME_ONKEY, +}; + +static const struct da906x_chip_config da9062_regs = { + /* REGS */ + .onkey_status = DA9062AA_STATUS_A, + .onkey_pwr_signalling = DA9062AA_CONTROL_B, + .onkey_fault_log = DA9062AA_FAULT_LOG, + .onkey_shutdown = DA9062AA_CONTROL_F, + /* MASKS */ + .onkey_nonkey_mask = DA9062AA_NONKEY_MASK, + .onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK, + .onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK, + .onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK, + /* NAMES */ + .name = "da9062-onkey", +}; + +static const struct of_device_id da9063_compatible_reg_id_table[] = { + { .compatible = "dlg,da9063-onkey", .data = &da9063_regs }, + { .compatible = "dlg,da9062-onkey", .data = &da9062_regs }, + { }, +}; + static void da9063_poll_on(struct work_struct *work) { - struct da9063_onkey *onkey = container_of(work, struct da9063_onkey, - work.work); + struct da9063_onkey *onkey = container_of(work, + struct da9063_onkey, + work.work); + const struct da906x_chip_config *config = onkey->config; unsigned int val; int fault_log = 0; bool poll = true; int error; /* Poll to see when the pin is released */ - error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val); + error = regmap_read(onkey->regmap, + config->onkey_status, + &val); if (error) { dev_err(onkey->dev, "Failed to read ON status: %d\n", error); goto err_poll; } - if (!(val & DA9063_NONKEY)) { - error = regmap_update_bits(onkey->hw->regmap, - DA9063_REG_CONTROL_B, - DA9063_NONKEY_LOCK, 0); + if (!(val & config->onkey_nonkey_mask)) { + error = regmap_update_bits(onkey->regmap, + config->onkey_pwr_signalling, + config->onkey_nonkey_lock_mask, + 0); if (error) { dev_err(onkey->dev, "Failed to reset the Key Delay %d\n", error); @@ -70,15 +130,16 @@ static void da9063_poll_on(struct work_struct *work) * If the fault log KEY_RESET is detected, then clear it * and shut down the system. */ - error = regmap_read(onkey->hw->regmap, - DA9063_REG_FAULT_LOG, &fault_log); + error = regmap_read(onkey->regmap, + config->onkey_fault_log, + &fault_log); if (error) { dev_warn(&onkey->input->dev, "Cannot read FAULT_LOG: %d\n", error); - } else if (fault_log & DA9063_KEY_RESET) { - error = regmap_write(onkey->hw->regmap, - DA9063_REG_FAULT_LOG, - DA9063_KEY_RESET); + } else if (fault_log & config->onkey_key_reset_mask) { + error = regmap_write(onkey->regmap, + config->onkey_fault_log, + config->onkey_key_reset_mask); if (error) { dev_warn(&onkey->input->dev, "Cannot reset KEY_RESET fault log: %d\n", @@ -88,10 +149,10 @@ static void da9063_poll_on(struct work_struct *work) * and then send shutdown command */ dev_dbg(&onkey->input->dev, - "Sending SHUTDOWN to DA9063 ...\n"); - error = regmap_write(onkey->hw->regmap, - DA9063_REG_CONTROL_F, - DA9063_SHUTDOWN); + "Sending SHUTDOWN to DA9063 ...\n"); + error = regmap_write(onkey->regmap, + config->onkey_shutdown, + config->onkey_shutdown_mask); if (error) dev_err(&onkey->input->dev, "Cannot SHUTDOWN DA9063: %d\n", @@ -107,11 +168,14 @@ err_poll: static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) { struct da9063_onkey *onkey = data; + const struct da906x_chip_config *config = onkey->config; unsigned int val; int error; - error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val); - if (onkey->key_power && !error && (val & DA9063_NONKEY)) { + error = regmap_read(onkey->regmap, + config->onkey_status, + &val); + if (onkey->key_power && !error && (val & config->onkey_nonkey_mask)) { input_report_key(onkey->input, KEY_POWER, 1); input_sync(onkey->input); schedule_delayed_work(&onkey->work, 0); @@ -139,9 +203,15 @@ static int da9063_onkey_probe(struct platform_device *pdev) struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); struct da9063_onkey *onkey; + const struct of_device_id *match; int irq; int error; + match = of_match_node(da9063_compatible_reg_id_table, + pdev->dev.of_node); + if (!match) + return -ENXIO; + onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey), GFP_KERNEL); if (!onkey) { @@ -149,8 +219,14 @@ static int da9063_onkey_probe(struct platform_device *pdev) return -ENOMEM; } + onkey->config = match->data; onkey->dev = &pdev->dev; - onkey->hw = da9063; + + onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!onkey->regmap) { + dev_err(&pdev->dev, "Parent regmap unavailable.\n"); + return -ENXIO; + } if (pdata) onkey->key_power = pdata->key_power; @@ -165,8 +241,10 @@ static int da9063_onkey_probe(struct platform_device *pdev) return -ENOMEM; } - onkey->input->name = DA9063_DRVNAME_ONKEY; - onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0"; + onkey->input->name = onkey->config->name; + snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0", + onkey->config->name); + onkey->input->phys = onkey->phys; onkey->input->dev.parent = &pdev->dev; if (onkey->key_power) @@ -216,11 +294,12 @@ static struct platform_driver da9063_onkey_driver = { .probe = da9063_onkey_probe, .driver = { .name = DA9063_DRVNAME_ONKEY, + .of_match_table = da9063_compatible_reg_id_table, }, }; module_platform_driver(da9063_onkey_driver); MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); -MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063"); +MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY); diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 45e0e3e55de2..1c8c56efc995 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -198,7 +198,7 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) /* Read the i8042 real-time clock */ -static inline int hp_sdc_rtc_read_rt(struct timeval *res) { +static inline int hp_sdc_rtc_read_rt(struct timespec64 *res) { int64_t raw; uint32_t tenms; unsigned int days; @@ -209,15 +209,15 @@ static inline int hp_sdc_rtc_read_rt(struct timeval *res) { tenms = (uint32_t)raw & 0xffffff; days = (unsigned int)(raw >> 24) & 0xffff; - res->tv_usec = (suseconds_t)(tenms % 100) * 10000; - res->tv_sec = (time_t)(tenms / 100) + days * 86400; + res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; + res->tv_sec = (tenms / 100) + (time64_t)days * 86400; return 0; } /* Read the i8042 fast handshake timer */ -static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { +static inline int hp_sdc_rtc_read_fhs(struct timespec64 *res) { int64_t raw; unsigned int tenms; @@ -226,15 +226,15 @@ static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { tenms = (unsigned int)raw & 0xffff; - res->tv_usec = (suseconds_t)(tenms % 100) * 10000; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 match timer (a.k.a. alarm) */ -static inline int hp_sdc_rtc_read_mt(struct timeval *res) { +static inline int hp_sdc_rtc_read_mt(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -243,15 +243,15 @@ static inline int hp_sdc_rtc_read_mt(struct timeval *res) { tenms = (uint32_t)raw & 0xffffff; - res->tv_usec = (suseconds_t)(tenms % 100) * 10000; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 delay timer */ -static inline int hp_sdc_rtc_read_dt(struct timeval *res) { +static inline int hp_sdc_rtc_read_dt(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -260,15 +260,15 @@ static inline int hp_sdc_rtc_read_dt(struct timeval *res) { tenms = (uint32_t)raw & 0xffffff; - res->tv_usec = (suseconds_t)(tenms % 100) * 10000; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 cycle timer (a.k.a. periodic) */ -static inline int hp_sdc_rtc_read_ct(struct timeval *res) { +static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -277,8 +277,8 @@ static inline int hp_sdc_rtc_read_ct(struct timeval *res) { tenms = (uint32_t)raw & 0xffffff; - res->tv_usec = (suseconds_t)(tenms % 100) * 10000; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } @@ -433,7 +433,7 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) #define YN(bit) ("no") #define NY(bit) ("yes") struct rtc_time tm; - struct timeval tv; + struct timespec64 tv; memset(&tm, 0, sizeof(struct rtc_time)); @@ -452,36 +452,36 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) if (hp_sdc_rtc_read_rt(&tv)) { seq_puts(m, "i8042 rtc\t: READ FAILED!\n"); } else { - seq_printf(m, "i8042 rtc\t: %ld.%02d seconds\n", - tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "i8042 rtc\t: %lld.%02ld seconds\n", + (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); } if (hp_sdc_rtc_read_fhs(&tv)) { seq_puts(m, "handshake\t: READ FAILED!\n"); } else { - seq_printf(m, "handshake\t: %ld.%02d seconds\n", - tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "handshake\t: %lld.%02ld seconds\n", + (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); } if (hp_sdc_rtc_read_mt(&tv)) { seq_puts(m, "alarm\t\t: READ FAILED!\n"); } else { - seq_printf(m, "alarm\t\t: %ld.%02d seconds\n", - tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "alarm\t\t: %lld.%02ld seconds\n", + (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); } if (hp_sdc_rtc_read_dt(&tv)) { seq_puts(m, "delay\t\t: READ FAILED!\n"); } else { - seq_printf(m, "delay\t\t: %ld.%02d seconds\n", - tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "delay\t\t: %lld.%02ld seconds\n", + (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); } if (hp_sdc_rtc_read_ct(&tv)) { seq_puts(m, "periodic\t: READ FAILED!\n"); } else { - seq_printf(m, "periodic\t: %ld.%02d seconds\n", - tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "periodic\t: %lld.%02ld seconds\n", + (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); } seq_printf(m, diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index e058d711256a..efaffcc57e36 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -635,7 +635,6 @@ static int __maybe_unused kxtj9_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct kxtj9_data *tj9 = i2c_get_clientdata(client); struct input_dev *input_dev = tj9->input_dev; - int retval = 0; mutex_lock(&input_dev->mutex); @@ -643,7 +642,7 @@ static int __maybe_unused kxtj9_resume(struct device *dev) kxtj9_enable(tj9); mutex_unlock(&input_dev->mutex); - return retval; + return 0; } static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index f27f81ee84ed..8aee71986430 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -26,6 +26,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/pm.h> #define DRV_NAME "rotary-encoder" @@ -142,6 +143,55 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) +{ + struct rotary_encoder *encoder = dev_id; + unsigned char sum; + int state; + + state = rotary_encoder_get_state(encoder->pdata); + + /* + * We encode the previous and the current state using a byte. + * The previous state in the MSB nibble, the current state in the LSB + * nibble. Then use a table to decide the direction of the turn. + */ + sum = (encoder->last_stable << 4) + state; + switch (sum) { + case 0x31: + case 0x10: + case 0x02: + case 0x23: + encoder->dir = 0; /* clockwise */ + break; + + case 0x13: + case 0x01: + case 0x20: + case 0x32: + encoder->dir = 1; /* counter-clockwise */ + break; + + default: + /* + * Ignore all other values. This covers the case when the + * state didn't change (a spurious interrupt) and the + * cases where the state changed by two steps, making it + * impossible to tell the direction. + * + * In either case, don't report any event and save the + * state for later. + */ + goto out; + } + + rotary_encoder_report_event(encoder); + +out: + encoder->last_stable = state; + return IRQ_HANDLED; +} + #ifdef CONFIG_OF static const struct of_device_id rotary_encoder_of_match[] = { { .compatible = "rotary-encoder", }, @@ -156,6 +206,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic struct device_node *np = dev->of_node; struct rotary_encoder_platform_data *pdata; enum of_gpio_flags flags; + int error; if (!of_id || !np) return NULL; @@ -174,12 +225,27 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; - pdata->relative_axis = !!of_get_property(np, - "rotary-encoder,relative-axis", NULL); - pdata->rollover = !!of_get_property(np, - "rotary-encoder,rollover", NULL); - pdata->half_period = !!of_get_property(np, - "rotary-encoder,half-period", NULL); + pdata->relative_axis = + of_property_read_bool(np, "rotary-encoder,relative-axis"); + pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); + + error = of_property_read_u32(np, "rotary-encoder,steps-per-period", + &pdata->steps_per_period); + if (error) { + /* + * The 'half-period' property has been deprecated, you must use + * 'steps-per-period' and set an appropriate value, but we still + * need to parse it to maintain compatibility. + */ + if (of_property_read_bool(np, "rotary-encoder,half-period")) { + pdata->steps_per_period = 2; + } else { + /* Fallback to one step per period behavior */ + pdata->steps_per_period = 1; + } + } + + pdata->wakeup_source = of_property_read_bool(np, "wakeup-source"); return pdata; } @@ -250,12 +316,23 @@ static int rotary_encoder_probe(struct platform_device *pdev) encoder->irq_a = gpio_to_irq(pdata->gpio_a); encoder->irq_b = gpio_to_irq(pdata->gpio_b); - /* request the IRQs */ - if (pdata->half_period) { + switch (pdata->steps_per_period) { + case 4: + handler = &rotary_encoder_quarter_period_irq; + encoder->last_stable = rotary_encoder_get_state(pdata); + break; + case 2: handler = &rotary_encoder_half_period_irq; encoder->last_stable = rotary_encoder_get_state(pdata); - } else { + break; + case 1: handler = &rotary_encoder_irq; + break; + default: + dev_err(dev, "'%d' is not a valid steps-per-period value\n", + pdata->steps_per_period); + err = -EINVAL; + goto exit_free_gpio_b; } err = request_irq(encoder->irq_a, handler, @@ -280,6 +357,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) goto exit_free_irq_b; } + device_init_wakeup(&pdev->dev, pdata->wakeup_source); + platform_set_drvdata(pdev, encoder); return 0; @@ -306,6 +385,8 @@ static int rotary_encoder_remove(struct platform_device *pdev) struct rotary_encoder *encoder = platform_get_drvdata(pdev); const struct rotary_encoder_platform_data *pdata = encoder->pdata; + device_init_wakeup(&pdev->dev, false); + free_irq(encoder->irq_a, encoder); free_irq(encoder->irq_b, encoder); gpio_free(pdata->gpio_a); @@ -320,11 +401,41 @@ static int rotary_encoder_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int rotary_encoder_suspend(struct device *dev) +{ + struct rotary_encoder *encoder = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) { + enable_irq_wake(encoder->irq_a); + enable_irq_wake(encoder->irq_b); + } + + return 0; +} + +static int rotary_encoder_resume(struct device *dev) +{ + struct rotary_encoder *encoder = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) { + disable_irq_wake(encoder->irq_a); + disable_irq_wake(encoder->irq_b); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops, + rotary_encoder_suspend, rotary_encoder_resume); + static struct platform_driver rotary_encoder_driver = { .probe = rotary_encoder_probe, .remove = rotary_encoder_remove, .driver = { .name = DRV_NAME, + .pm = &rotary_encoder_pm_ops, .of_match_table = of_match_ptr(rotary_encoder_of_match), } }; diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 23d0549539d4..0a9ad2cfb55c 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -129,8 +129,14 @@ static int xenkbd_probe(struct xenbus_device *dev, if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) abs = 0; - if (abs) - xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); + if (abs) { + ret = xenbus_printf(XBT_NIL, dev->nodename, + "request-abs-pointer", "1"); + if (ret) { + pr_warning("xenkbd: can't request abs-pointer"); + abs = 0; + } + } /* keyboard */ kbd = input_allocate_device(); diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 200841b77edb..c3d05b4d3118 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -292,4 +292,18 @@ config SERIO_SUN4I_PS2 To compile this driver as a module, choose M here: the module will be called sun4i-ps2. +config USERIO + tristate "User space serio port driver support" + help + Say Y here if you want to support user level drivers for serio + subsystem accessible under char device 10:240 - /dev/userio. Using + this facility userspace programs can implement serio ports that + will be used by the standard in-kernel serio consumer drivers, + such as psmouse and atkbd. + + To compile this driver as a module, choose M here: the module will be + called userio. + + If you are unsure, say N. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index c600089b7a34..2374ef9b33d7 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_SERIO_APBPS2) += apbps2.o obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o +obj-$(CONFIG_USERIO) += userio.o diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 1e8cd6f1fe9e..74bb17270255 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -141,19 +141,15 @@ static void parkbd_interrupt(void *dev_id) parkbd_last = jiffies; } -static int parkbd_getport(void) +static int parkbd_getport(struct parport *pp) { - struct parport *pp; + struct pardev_cb parkbd_parport_cb; - pp = parport_find_number(parkbd_pp_no); + parkbd_parport_cb.irq_func = parkbd_interrupt; + parkbd_parport_cb.flags = PARPORT_FLAG_EXCL; - if (pp == NULL) { - printk(KERN_ERR "parkbd: no such parport\n"); - return -ENODEV; - } - - parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL); - parport_put_port(pp); + parkbd_dev = parport_register_dev_model(pp, "parkbd", + &parkbd_parport_cb, 0); if (!parkbd_dev) return -ENODEV; @@ -183,19 +179,21 @@ static struct serio * __init parkbd_allocate_serio(void) return serio; } -static int __init parkbd_init(void) +static void parkbd_attach(struct parport *pp) { - int err; + if (pp->number != parkbd_pp_no) { + pr_debug("Not using parport%d.\n", pp->number); + return; + } - err = parkbd_getport(); - if (err) - return err; + if (parkbd_getport(pp)) + return; parkbd_port = parkbd_allocate_serio(); if (!parkbd_port) { parport_release(parkbd_dev); parport_unregister_device(parkbd_dev); - return -ENOMEM; + return; } parkbd_writelines(3); @@ -205,14 +203,35 @@ static int __init parkbd_init(void) printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); - return 0; + return; } -static void __exit parkbd_exit(void) +static void parkbd_detach(struct parport *port) { + if (!parkbd_port || port->number != parkbd_pp_no) + return; + parport_release(parkbd_dev); serio_unregister_port(parkbd_port); parport_unregister_device(parkbd_dev); + parkbd_port = NULL; +} + +static struct parport_driver parkbd_parport_driver = { + .name = "parkbd", + .match_port = parkbd_attach, + .detach = parkbd_detach, + .devmodel = true, +}; + +static int __init parkbd_init(void) +{ + return parport_register_driver(&parkbd_parport_driver); +} + +static void __exit parkbd_exit(void) +{ + parport_unregister_driver(&parkbd_parport_driver); } module_init(parkbd_init); diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c new file mode 100644 index 000000000000..df1fd41860ac --- /dev/null +++ b/drivers/input/serio/userio.c @@ -0,0 +1,285 @@ +/* + * userio kernel serio device emulation module + * Copyright (C) 2015 Red Hat + * Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * 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 Lesser + * General Public License for more details. + */ + +#include <linux/circ_buf.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/serio.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <uapi/linux/userio.h> + +#define USERIO_NAME "userio" +#define USERIO_BUFSIZE 16 + +static struct miscdevice userio_misc; + +struct userio_device { + struct serio *serio; + struct mutex mutex; + + bool running; + + u8 head; + u8 tail; + + spinlock_t buf_lock; + unsigned char buf[USERIO_BUFSIZE]; + + wait_queue_head_t waitq; +}; + +/** + * userio_device_write - Write data from serio to a userio device in userspace + * @id: The serio port for the userio device + * @val: The data to write to the device + */ +static int userio_device_write(struct serio *id, unsigned char val) +{ + struct userio_device *userio = id->port_data; + unsigned long flags; + + spin_lock_irqsave(&userio->buf_lock, flags); + + userio->buf[userio->head] = val; + userio->head = (userio->head + 1) % USERIO_BUFSIZE; + + if (userio->head == userio->tail) + dev_warn(userio_misc.this_device, + "Buffer overflowed, userio client isn't keeping up"); + + spin_unlock_irqrestore(&userio->buf_lock, flags); + + wake_up_interruptible(&userio->waitq); + + return 0; +} + +static int userio_char_open(struct inode *inode, struct file *file) +{ + struct userio_device *userio; + + userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL); + if (!userio) + return -ENOMEM; + + mutex_init(&userio->mutex); + spin_lock_init(&userio->buf_lock); + init_waitqueue_head(&userio->waitq); + + userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!userio->serio) { + kfree(userio); + return -ENOMEM; + } + + userio->serio->write = userio_device_write; + userio->serio->port_data = userio; + + file->private_data = userio; + + return 0; +} + +static int userio_char_release(struct inode *inode, struct file *file) +{ + struct userio_device *userio = file->private_data; + + if (userio->running) { + /* + * Don't free the serio port here, serio_unregister_port() + * does it for us. + */ + serio_unregister_port(userio->serio); + } else { + kfree(userio->serio); + } + + kfree(userio); + + return 0; +} + +static ssize_t userio_char_read(struct file *file, char __user *user_buffer, + size_t count, loff_t *ppos) +{ + struct userio_device *userio = file->private_data; + int error; + size_t nonwrap_len, copylen; + unsigned char buf[USERIO_BUFSIZE]; + unsigned long flags; + + /* + * By the time we get here, the data that was waiting might have + * been taken by another thread. Grab the buffer lock and check if + * there's still any data waiting, otherwise repeat this process + * until we have data (unless the file descriptor is non-blocking + * of course). + */ + for (;;) { + spin_lock_irqsave(&userio->buf_lock, flags); + + nonwrap_len = CIRC_CNT_TO_END(userio->head, + userio->tail, + USERIO_BUFSIZE); + copylen = min(nonwrap_len, count); + if (copylen) { + memcpy(buf, &userio->buf[userio->tail], copylen); + userio->tail = (userio->tail + copylen) % + USERIO_BUFSIZE; + } + + spin_unlock_irqrestore(&userio->buf_lock, flags); + + if (nonwrap_len) + break; + + /* buffer was/is empty */ + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + /* + * count == 0 is special - no IO is done but we check + * for error conditions (see above). + */ + if (count == 0) + return 0; + + error = wait_event_interruptible(userio->waitq, + userio->head != userio->tail); + if (error) + return error; + } + + if (copylen) + if (copy_to_user(user_buffer, buf, copylen)) + return -EFAULT; + + return copylen; +} + +static ssize_t userio_char_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct userio_device *userio = file->private_data; + struct userio_cmd cmd; + int error; + + if (count != sizeof(cmd)) { + dev_warn(userio_misc.this_device, "Invalid payload size\n"); + return -EINVAL; + } + + if (copy_from_user(&cmd, buffer, sizeof(cmd))) + return -EFAULT; + + error = mutex_lock_interruptible(&userio->mutex); + if (error) + return error; + + switch (cmd.type) { + case USERIO_CMD_REGISTER: + if (!userio->serio->id.type) { + dev_warn(userio_misc.this_device, + "No port type given on /dev/userio\n"); + + error = -EINVAL; + goto out; + } + + if (userio->running) { + dev_warn(userio_misc.this_device, + "Begin command sent, but we're already running\n"); + error = -EBUSY; + goto out; + } + + userio->running = true; + serio_register_port(userio->serio); + break; + + case USERIO_CMD_SET_PORT_TYPE: + if (userio->running) { + dev_warn(userio_misc.this_device, + "Can't change port type on an already running userio instance\n"); + error = -EBUSY; + goto out; + } + + userio->serio->id.type = cmd.data; + break; + + case USERIO_CMD_SEND_INTERRUPT: + if (!userio->running) { + dev_warn(userio_misc.this_device, + "The device must be registered before sending interrupts\n"); + error = -ENODEV; + goto out; + } + + serio_interrupt(userio->serio, cmd.data, 0); + break; + + default: + error = -EOPNOTSUPP; + goto out; + } + +out: + mutex_unlock(&userio->mutex); + return error ?: count; +} + +static unsigned int userio_char_poll(struct file *file, poll_table *wait) +{ + struct userio_device *userio = file->private_data; + + poll_wait(file, &userio->waitq, wait); + + if (userio->head != userio->tail) + return POLLIN | POLLRDNORM; + + return 0; +} + +static const struct file_operations userio_fops = { + .owner = THIS_MODULE, + .open = userio_char_open, + .release = userio_char_release, + .read = userio_char_read, + .write = userio_char_write, + .poll = userio_char_poll, + .llseek = no_llseek, +}; + +static struct miscdevice userio_misc = { + .fops = &userio_fops, + .minor = USERIO_MINOR, + .name = USERIO_NAME, +}; +module_driver(userio_misc, misc_register, misc_deregister); + +MODULE_ALIAS_MISCDEV(USERIO_MINOR); +MODULE_ALIAS("devname:" USERIO_NAME); + +MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>"); +MODULE_DESCRIPTION("Virtual Serio Device Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index deb14c12ae8b..80cc69897a43 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -295,6 +295,19 @@ config TOUCHSCREEN_EGALAX To compile this driver as a module, choose M here: the module will be called egalax_ts. +config TOUCHSCREEN_FT6236 + tristate "FT6236 I2C touchscreen" + depends on I2C + depends on GPIOLIB || COMPILE_TEST + help + Say Y here to enable support for the I2C connected FT6x06 and + FT6x36 family of capacitive touchscreen drivers. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ft6236. + config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO @@ -1065,4 +1078,15 @@ config TOUCHSCREEN_COLIBRI_VF50 To compile this driver as a module, choose M here: the module will be called colibri_vf50_ts. +config TOUCHSCREEN_ROHM_BU21023 + tristate "ROHM BU21023/24 Dual touch support resistive touchscreens" + depends on I2C + help + Say Y here if you have a touchscreen using ROHM BU21023/24. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called bu21023_ts. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1b79cc09744a..17435c7e97e3 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o +obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o @@ -87,3 +88,4 @@ obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o +obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e431cf63a85d..a61b2153ab8c 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -529,10 +529,8 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias, ts, ads7846_attr_groups); - if (IS_ERR(ts->hwmon)) - return PTR_ERR(ts->hwmon); - return 0; + return PTR_ERR_OR_ZERO(ts->hwmon); } static void ads784x_hwmon_unregister(struct spi_device *spi, diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 38c06f754acd..6592fc5d48b4 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -399,13 +399,8 @@ static int auo_pixcir_stop(struct auo_pixcir_ts *ts) static int auo_pixcir_input_open(struct input_dev *dev) { struct auo_pixcir_ts *ts = input_get_drvdata(dev); - int ret; - - ret = auo_pixcir_start(ts); - if (ret) - return ret; - return 0; + return auo_pixcir_start(ts); } static void auo_pixcir_input_close(struct input_dev *dev) diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index a9f95c7d3c00..564e49002d5d 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -50,10 +50,7 @@ static int cyttsp4_i2c_probe(struct i2c_client *client, ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq, CYTTSP4_I2C_DATA_SIZE); - if (IS_ERR(ts)) - return PTR_ERR(ts); - - return 0; + return PTR_ERR_OR_ZERO(ts); } static int cyttsp4_i2c_remove(struct i2c_client *client) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 48de1e8b3c93..0b0f8c17f3f7 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/ratelimit.h> +#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/i2c.h> @@ -34,13 +35,10 @@ #include <linux/delay.h> #include <linux/debugfs.h> #include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> -#include <linux/input/edt-ft5x06.h> - -#define MAX_SUPPORT_POINTS 5 +#include <linux/of_device.h> #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 @@ -91,9 +89,8 @@ struct edt_ft5x06_ts_data { u16 num_x; u16 num_y; - int reset_pin; - int irq_pin; - int wake_pin; + struct gpio_desc *reset_gpio; + struct gpio_desc *wake_gpio; #if defined(CONFIG_DEBUG_FS) struct dentry *debug_dir; @@ -107,6 +104,7 @@ struct edt_ft5x06_ts_data { int gain; int offset; int report_rate; + int max_support_points; char name[EDT_NAME_LEN]; @@ -114,6 +112,10 @@ struct edt_ft5x06_ts_data { enum edt_ver version; }; +struct edt_i2c_chip_data { + int max_support_points; +}; + static int edt_ft5x06_ts_readwrite(struct i2c_client *client, u16 wr_len, u8 *wr_buf, u16 rd_len, u8 *rd_buf) @@ -170,9 +172,9 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) struct edt_ft5x06_ts_data *tsdata = dev_id; struct device *dev = &tsdata->client->dev; u8 cmd; - u8 rdbuf[29]; + u8 rdbuf[63]; int i, type, x, y, id; - int offset, tplen, datalen; + int offset, tplen, datalen, crclen; int error; switch (tsdata->version) { @@ -180,14 +182,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) cmd = 0xf9; /* tell the controller to send touch data */ offset = 5; /* where the actual touch data starts */ tplen = 4; /* data comes in so called frames */ - datalen = 26; /* how much bytes to listen for */ + crclen = 1; /* length of the crc data */ break; case M09: - cmd = 0x02; - offset = 1; + cmd = 0x0; + offset = 3; tplen = 6; - datalen = 29; + crclen = 0; break; default: @@ -195,6 +197,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) } memset(rdbuf, 0, sizeof(rdbuf)); + datalen = tplen * tsdata->max_support_points + offset + crclen; error = edt_ft5x06_ts_readwrite(tsdata->client, sizeof(cmd), &cmd, @@ -219,7 +222,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) goto out; } - for (i = 0; i < MAX_SUPPORT_POINTS; i++) { + for (i = 0; i < tsdata->max_support_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; bool down; @@ -752,45 +755,6 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) #endif /* CONFIG_DEBUGFS */ -static int edt_ft5x06_ts_reset(struct i2c_client *client, - struct edt_ft5x06_ts_data *tsdata) -{ - int error; - - if (gpio_is_valid(tsdata->wake_pin)) { - error = devm_gpio_request_one(&client->dev, - tsdata->wake_pin, GPIOF_OUT_INIT_LOW, - "edt-ft5x06 wake"); - if (error) { - dev_err(&client->dev, - "Failed to request GPIO %d as wake pin, error %d\n", - tsdata->wake_pin, error); - return error; - } - - msleep(5); - gpio_set_value(tsdata->wake_pin, 1); - } - if (gpio_is_valid(tsdata->reset_pin)) { - /* this pulls reset down, enabling the low active reset */ - error = devm_gpio_request_one(&client->dev, - tsdata->reset_pin, GPIOF_OUT_INIT_LOW, - "edt-ft5x06 reset"); - if (error) { - dev_err(&client->dev, - "Failed to request GPIO %d as reset pin, error %d\n", - tsdata->reset_pin, error); - return error; - } - - msleep(5); - gpio_set_value(tsdata->reset_pin, 1); - msleep(300); - } - - return 0; -} - static int edt_ft5x06_ts_identify(struct i2c_client *client, struct edt_ft5x06_ts_data *tsdata, char *fw_version) @@ -850,44 +814,24 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, return 0; } -#define EDT_ATTR_CHECKSET(name, reg) \ -do { \ - if (pdata->name >= edt_ft5x06_attr_##name.limit_low && \ - pdata->name <= edt_ft5x06_attr_##name.limit_high) \ - edt_ft5x06_register_write(tsdata, reg, pdata->name); \ -} while (0) - -#define EDT_GET_PROP(name, reg) { \ - u32 val; \ - if (of_property_read_u32(np, #name, &val) == 0) \ - edt_ft5x06_register_write(tsdata, reg, val); \ -} - -static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, - struct edt_ft5x06_ts_data *tsdata) +static void edt_ft5x06_ts_get_defaults(struct device *dev, + struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + u32 val; + int error; - EDT_GET_PROP(threshold, reg_addr->reg_threshold); - EDT_GET_PROP(gain, reg_addr->reg_gain); - EDT_GET_PROP(offset, reg_addr->reg_offset); -} + error = device_property_read_u32(dev, "threshold", &val); + if (!error) + reg_addr->reg_threshold = val; -static void -edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, - const struct edt_ft5x06_platform_data *pdata) -{ - struct edt_reg_addr *reg_addr = &tsdata->reg_addr; - - if (!pdata->use_parameters) - return; + error = device_property_read_u32(dev, "gain", &val); + if (!error) + reg_addr->reg_gain = val; - /* pick up defaults from the platform data */ - EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); - EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); - EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); - if (reg_addr->reg_report_rate != NO_REGISTER) - EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate); + error = device_property_read_u32(dev, "offset", &val); + if (!error) + reg_addr->reg_offset = val; } static void @@ -931,37 +875,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) } } -#ifdef CONFIG_OF -static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, - struct edt_ft5x06_ts_data *tsdata) -{ - struct device_node *np = dev->of_node; - - /* - * irq_pin is not needed for DT setup. - * irq is associated via 'interrupts' property in DT - */ - tsdata->irq_pin = -EINVAL; - tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); - tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); - - return 0; -} -#else -static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, - struct edt_ft5x06_ts_data *tsdata) -{ - return -ENODEV; -} -#endif - static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct edt_ft5x06_platform_data *pdata = - dev_get_platdata(&client->dev); + const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; struct input_dev *input; + unsigned long irq_flags; int error; char fw_version[EDT_NAME_LEN]; @@ -973,32 +893,43 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return -ENOMEM; } - if (!pdata) { - error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); - if (error) { - dev_err(&client->dev, - "DT probe failed and no platform data present\n"); - return error; - } - } else { - tsdata->reset_pin = pdata->reset_pin; - tsdata->irq_pin = pdata->irq_pin; - tsdata->wake_pin = -EINVAL; + chip_data = of_device_get_match_data(&client->dev); + if (!chip_data) + chip_data = (const struct edt_i2c_chip_data *)id->driver_data; + if (!chip_data || !chip_data->max_support_points) { + dev_err(&client->dev, "invalid or missing chip data\n"); + return -EINVAL; } - error = edt_ft5x06_ts_reset(client, tsdata); - if (error) + tsdata->max_support_points = chip_data->max_support_points; + + tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(tsdata->reset_gpio)) { + error = PTR_ERR(tsdata->reset_gpio); + dev_err(&client->dev, + "Failed to request GPIO reset pin, error %d\n", error); + return error; + } + + tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev, + "wake", GPIOD_OUT_LOW); + if (IS_ERR(tsdata->wake_gpio)) { + error = PTR_ERR(tsdata->wake_gpio); + dev_err(&client->dev, + "Failed to request GPIO wake pin, error %d\n", error); return error; + } - if (gpio_is_valid(tsdata->irq_pin)) { - error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, - GPIOF_IN, "edt-ft5x06 irq"); - if (error) { - dev_err(&client->dev, - "Failed to request GPIO %d, error %d\n", - tsdata->irq_pin, error); - return error; - } + if (tsdata->wake_gpio) { + usleep_range(5000, 6000); + gpiod_set_value_cansleep(tsdata->wake_gpio, 1); + } + + if (tsdata->reset_gpio) { + usleep_range(5000, 6000); + gpiod_set_value_cansleep(tsdata->reset_gpio, 0); + msleep(300); } input = devm_input_allocate_device(&client->dev); @@ -1019,12 +950,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, } edt_ft5x06_ts_set_regs(tsdata); - - if (!pdata) - edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); - else - edt_ft5x06_ts_get_defaults(tsdata, pdata); - + edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); dev_dbg(&client->dev, @@ -1040,10 +966,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, input_set_abs_params(input, ABS_MT_POSITION_Y, 0, tsdata->num_y * 64 - 1, 0, 0); - if (!pdata) - touchscreen_parse_properties(input, true); + touchscreen_parse_properties(input, true); - error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); + error = input_mt_init_slots(input, tsdata->max_support_points, + INPUT_MT_DIRECT); if (error) { dev_err(&client->dev, "Unable to init MT slots.\n"); return error; @@ -1052,9 +978,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); i2c_set_clientdata(client, tsdata); - error = devm_request_threaded_irq(&client->dev, client->irq, NULL, - edt_ft5x06_ts_isr, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_flags = irq_get_trigger_type(client->irq); + if (irq_flags == IRQF_TRIGGER_NONE) + irq_flags = IRQF_TRIGGER_FALLING; + irq_flags |= IRQF_ONESHOT; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, edt_ft5x06_ts_isr, irq_flags, client->name, tsdata); if (error) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); @@ -1074,7 +1004,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, dev_dbg(&client->dev, "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", - client->irq, tsdata->wake_pin, tsdata->reset_pin); + client->irq, + tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, + tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); return 0; @@ -1116,17 +1048,27 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); +static const struct edt_i2c_chip_data edt_ft5x06_data = { + .max_support_points = 5, +}; + +static const struct edt_i2c_chip_data edt_ft5506_data = { + .max_support_points = 10, +}; + static const struct i2c_device_id edt_ft5x06_ts_id[] = { - { "edt-ft5x06", 0, }, + { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, + { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); #ifdef CONFIG_OF static const struct of_device_id edt_ft5x06_of_match[] = { - { .compatible = "edt,edt-ft5206", }, - { .compatible = "edt,edt-ft5306", }, - { .compatible = "edt,edt-ft5406", }, + { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data }, + { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, + { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, + { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c new file mode 100644 index 000000000000..d240d2e212bd --- /dev/null +++ b/drivers/input/touchscreen/ft6236.c @@ -0,0 +1,326 @@ +/* + * FocalTech FT6236 TouchScreen driver. + * + * Copyright (c) 2010 Focal tech Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/property.h> + +#define FT6236_MAX_TOUCH_POINTS 2 + +#define FT6236_REG_TH_GROUP 0x80 +#define FT6236_REG_PERIODACTIVE 0x88 +#define FT6236_REG_LIB_VER_H 0xa1 +#define FT6236_REG_LIB_VER_L 0xa2 +#define FT6236_REG_CIPHER 0xa3 +#define FT6236_REG_FIRMID 0xa6 +#define FT6236_REG_FOCALTECH_ID 0xa8 +#define FT6236_REG_RELEASE_CODE_ID 0xaf + +#define FT6236_EVENT_PRESS_DOWN 0 +#define FT6236_EVENT_LIFT_UP 1 +#define FT6236_EVENT_CONTACT 2 +#define FT6236_EVENT_NO_EVENT 3 + +struct ft6236_data { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *reset_gpio; + u32 max_x; + u32 max_y; + bool invert_x; + bool invert_y; + bool swap_xy; +}; + +/* + * This struct is a touchpoint as stored in hardware. Note that the id, + * as well as the event, are stored in the upper nybble of the hi byte. + */ +struct ft6236_touchpoint { + union { + u8 xhi; + u8 event; + }; + u8 xlo; + union { + u8 yhi; + u8 id; + }; + u8 ylo; + u8 weight; + u8 misc; +} __packed; + +/* This packet represents the register map as read from offset 0 */ +struct ft6236_packet { + u8 dev_mode; + u8 gest_id; + u8 touches; + struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; +} __packed; + +static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) +{ + int error; + + error = i2c_smbus_read_i2c_block_data(client, reg, len, data); + if (error < 0) + return error; + + if (error != len) + return -EIO; + + return 0; +} + +static irqreturn_t ft6236_interrupt(int irq, void *dev_id) +{ + struct ft6236_data *ft6236 = dev_id; + struct device *dev = &ft6236->client->dev; + struct input_dev *input = ft6236->input; + struct ft6236_packet buf; + u8 touches; + int i, error; + + error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); + if (error) { + dev_err(dev, "read touchdata failed %d\n", error); + return IRQ_HANDLED; + } + + touches = buf.touches & 0xf; + if (touches > FT6236_MAX_TOUCH_POINTS) { + dev_dbg(dev, + "%d touch points reported, only %d are supported\n", + touches, FT6236_MAX_TOUCH_POINTS); + touches = FT6236_MAX_TOUCH_POINTS; + } + + for (i = 0; i < touches; i++) { + struct ft6236_touchpoint *point = &buf.points[i]; + u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; + u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; + u8 event = point->event >> 6; + u8 id = point->id >> 4; + bool act = (event == FT6236_EVENT_PRESS_DOWN || + event == FT6236_EVENT_CONTACT); + + input_mt_slot(input, id); + input_mt_report_slot_state(input, MT_TOOL_FINGER, act); + if (!act) + continue; + + if (ft6236->invert_x) + x = ft6236->max_x - x; + + if (ft6236->invert_y) + y = ft6236->max_y - y; + + if (ft6236->swap_xy) { + input_report_abs(input, ABS_MT_POSITION_X, y); + input_report_abs(input, ABS_MT_POSITION_Y, x); + } else { + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + } + } + + input_mt_sync_frame(input); + input_sync(input); + + return IRQ_HANDLED; +} + +static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) +{ + struct i2c_client *client = ft6236->client; + u8 val = 0; + int error; + + error = ft6236_read(client, reg, 1, &val); + if (error) + dev_dbg(&client->dev, + "error reading register 0x%02x: %d\n", reg, error); + + return val; +} + +static void ft6236_debug_info(struct ft6236_data *ft6236) +{ + struct device *dev = &ft6236->client->dev; + + dev_dbg(dev, "Touch threshold is %d\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); + dev_dbg(dev, "Report rate is %dHz\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); + dev_dbg(dev, "Firmware library version 0x%02x%02x\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), + ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); + dev_dbg(dev, "Firmware version 0x%02x\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); + dev_dbg(dev, "Chip vendor ID 0x%02x\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); + dev_dbg(dev, "CTPM vendor ID 0x%02x\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); + dev_dbg(dev, "Release code version 0x%02x\n", + ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); +} + +static void ft6236_reset(struct ft6236_data *ft6236) +{ + if (!ft6236->reset_gpio) + return; + + gpiod_set_value_cansleep(ft6236->reset_gpio, 1); + usleep_range(5000, 20000); + gpiod_set_value_cansleep(ft6236->reset_gpio, 0); + msleep(300); +} + +static int ft6236_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ft6236_data *ft6236; + struct input_dev *input; + u32 fuzz_x = 0, fuzz_y = 0; + u8 val; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENXIO; + + if (!client->irq) { + dev_err(dev, "irq is missing\n"); + return -EINVAL; + } + + ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); + if (!ft6236) + return -ENOMEM; + + ft6236->client = client; + ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ft6236->reset_gpio)) { + error = PTR_ERR(ft6236->reset_gpio); + if (error != -EPROBE_DEFER) + dev_err(dev, "error getting reset gpio: %d\n", error); + return error; + } + + ft6236_reset(ft6236); + + /* verify that the controller is present */ + error = ft6236_read(client, 0x00, 1, &val); + if (error) { + dev_err(dev, "failed to read from controller: %d\n", error); + return error; + } + + ft6236_debug_info(ft6236); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + ft6236->input = input; + input->name = client->name; + input->id.bustype = BUS_I2C; + + if (device_property_read_u32(dev, "touchscreen-size-x", + &ft6236->max_x) || + device_property_read_u32(dev, "touchscreen-size-y", + &ft6236->max_y)) { + dev_err(dev, "touchscreen-size-x and/or -y missing\n"); + return -EINVAL; + } + + device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); + device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); + ft6236->invert_x = device_property_read_bool(dev, + "touchscreen-inverted-x"); + ft6236->invert_y = device_property_read_bool(dev, + "touchscreen-inverted-y"); + ft6236->swap_xy = device_property_read_bool(dev, + "touchscreen-swapped-x-y"); + + if (ft6236->swap_xy) { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + ft6236->max_y, fuzz_y, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + ft6236->max_x, fuzz_x, 0); + } else { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + ft6236->max_x, fuzz_x, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + ft6236->max_y, fuzz_y, 0); + } + + error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + error = devm_request_threaded_irq(dev, client->irq, NULL, + ft6236_interrupt, IRQF_ONESHOT, + client->name, ft6236); + if (error) { + dev_err(dev, "request irq %d failed: %d\n", client->irq, error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to register input device: %d\n", error); + return error; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id ft6236_of_match[] = { + { .compatible = "focaltech,ft6236", }, + { } +}; +MODULE_DEVICE_TABLE(of, ft6236_of_match); +#endif + +static const struct i2c_device_id ft6236_id[] = { + { "ft6236", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ft6236_id); + +static struct i2c_driver ft6236_driver = { + .driver = { + .name = "ft6236", + .of_match_table = of_match_ptr(ft6236_of_match), + }, + .probe = ft6236_probe, + .id_table = ft6236_id, +}; +module_i2c_driver(ft6236_driver); + +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); +MODULE_AUTHOR("Noralf Trønnes <noralf@tronnes.org>"); +MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 91621725bfb5..4b961ad9f0b5 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -377,8 +377,6 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) goto unlock; } } - - enable_irq_wake(client->irq); } else if (input->users) { ret = pixcir_stop(ts); } @@ -399,7 +397,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(&input->mutex); if (device_may_wakeup(&client->dev)) { - disable_irq_wake(client->irq); if (!input->users) { ret = pixcir_stop(ts); @@ -564,14 +561,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; i2c_set_clientdata(client, tsdata); - device_init_wakeup(&client->dev, 1); - - return 0; -} - -static int pixcir_i2c_ts_remove(struct i2c_client *client) -{ - device_init_wakeup(&client->dev, 0); return 0; } @@ -609,7 +598,6 @@ static struct i2c_driver pixcir_i2c_ts_driver = { .of_match_table = of_match_ptr(pixcir_of_match), }, .probe = pixcir_i2c_ts_probe, - .remove = pixcir_i2c_ts_remove, .id_table = pixcir_i2c_ts_id, }; diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c new file mode 100644 index 000000000000..ba6024f93469 --- /dev/null +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -0,0 +1,1218 @@ +/* + * ROHM BU21023/24 Dual touch support resistive touch screen driver + * Copyright (C) 2012 ROHM CO.,LTD. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/delay.h> +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/slab.h> + +#define BU21023_NAME "bu21023_ts" +#define BU21023_FIRMWARE_NAME "bu21023.bin" + +#define MAX_CONTACTS 2 + +#define AXIS_ADJUST 4 +#define AXIS_OFFSET 8 + +#define FIRMWARE_BLOCK_SIZE 32U +#define FIRMWARE_RETRY_MAX 4 + +#define SAMPLING_DELAY 12 /* msec */ + +#define CALIBRATION_RETRY_MAX 6 + +#define ROHM_TS_ABS_X_MIN 40 +#define ROHM_TS_ABS_X_MAX 990 +#define ROHM_TS_ABS_Y_MIN 160 +#define ROHM_TS_ABS_Y_MAX 920 +#define ROHM_TS_DISPLACEMENT_MAX 0 /* zero for infinite */ + +/* + * BU21023GUL/BU21023MUV/BU21024FV-M registers map + */ +#define VADOUT_YP_H 0x00 +#define VADOUT_YP_L 0x01 +#define VADOUT_XP_H 0x02 +#define VADOUT_XP_L 0x03 +#define VADOUT_YN_H 0x04 +#define VADOUT_YN_L 0x05 +#define VADOUT_XN_H 0x06 +#define VADOUT_XN_L 0x07 + +#define PRM1_X_H 0x08 +#define PRM1_X_L 0x09 +#define PRM1_Y_H 0x0a +#define PRM1_Y_L 0x0b +#define PRM2_X_H 0x0c +#define PRM2_X_L 0x0d +#define PRM2_Y_H 0x0e +#define PRM2_Y_L 0x0f + +#define MLT_PRM_MONI_X 0x10 +#define MLT_PRM_MONI_Y 0x11 + +#define DEBUG_MONI_1 0x12 +#define DEBUG_MONI_2 0x13 + +#define VADOUT_ZX_H 0x14 +#define VADOUT_ZX_L 0x15 +#define VADOUT_ZY_H 0x16 +#define VADOUT_ZY_L 0x17 + +#define Z_PARAM_H 0x18 +#define Z_PARAM_L 0x19 + +/* + * Value for VADOUT_*_L + */ +#define VADOUT_L_MASK 0x01 + +/* + * Value for PRM*_*_L + */ +#define PRM_L_MASK 0x01 + +#define POS_X1_H 0x20 +#define POS_X1_L 0x21 +#define POS_Y1_H 0x22 +#define POS_Y1_L 0x23 +#define POS_X2_H 0x24 +#define POS_X2_L 0x25 +#define POS_Y2_H 0x26 +#define POS_Y2_L 0x27 + +/* + * Value for POS_*_L + */ +#define POS_L_MASK 0x01 + +#define TOUCH 0x28 +#define TOUCH_DETECT 0x01 + +#define TOUCH_GESTURE 0x29 +#define SINGLE_TOUCH 0x01 +#define DUAL_TOUCH 0x03 +#define TOUCH_MASK 0x03 +#define CALIBRATION_REQUEST 0x04 +#define CALIBRATION_STATUS 0x08 +#define CALIBRATION_MASK 0x0c +#define GESTURE_SPREAD 0x10 +#define GESTURE_PINCH 0x20 +#define GESTURE_ROTATE_R 0x40 +#define GESTURE_ROTATE_L 0x80 + +#define INT_STATUS 0x2a +#define INT_MASK 0x3d +#define INT_CLEAR 0x3e + +/* + * Values for INT_* + */ +#define COORD_UPDATE 0x01 +#define CALIBRATION_DONE 0x02 +#define SLEEP_IN 0x04 +#define SLEEP_OUT 0x08 +#define PROGRAM_LOAD_DONE 0x10 +#define ERROR 0x80 +#define INT_ALL 0x9f + +#define ERR_STATUS 0x2b +#define ERR_MASK 0x3f + +/* + * Values for ERR_* + */ +#define ADC_TIMEOUT 0x01 +#define CPU_TIMEOUT 0x02 +#define CALIBRATION_ERR 0x04 +#define PROGRAM_LOAD_ERR 0x10 + +#define COMMON_SETUP1 0x30 +#define PROGRAM_LOAD_HOST 0x02 +#define PROGRAM_LOAD_EEPROM 0x03 +#define CENSOR_4PORT 0x04 +#define CENSOR_8PORT 0x00 /* Not supported by BU21023 */ +#define CALIBRATION_TYPE_DEFAULT 0x08 +#define CALIBRATION_TYPE_SPECIAL 0x00 +#define INT_ACTIVE_HIGH 0x10 +#define INT_ACTIVE_LOW 0x00 +#define AUTO_CALIBRATION 0x40 +#define MANUAL_CALIBRATION 0x00 +#define COMMON_SETUP1_DEFAULT 0x4e + +#define COMMON_SETUP2 0x31 +#define MAF_NONE 0x00 +#define MAF_1SAMPLE 0x01 +#define MAF_3SAMPLES 0x02 +#define MAF_5SAMPLES 0x03 +#define INV_Y 0x04 +#define INV_X 0x08 +#define SWAP_XY 0x10 + +#define COMMON_SETUP3 0x32 +#define EN_SLEEP 0x01 +#define EN_MULTI 0x02 +#define EN_GESTURE 0x04 +#define EN_INTVL 0x08 +#define SEL_STEP 0x10 +#define SEL_MULTI 0x20 +#define SEL_TBL_DEFAULT 0x40 + +#define INTERVAL_TIME 0x33 +#define INTERVAL_TIME_DEFAULT 0x10 + +#define STEP_X 0x34 +#define STEP_X_DEFAULT 0x41 + +#define STEP_Y 0x35 +#define STEP_Y_DEFAULT 0x8d + +#define OFFSET_X 0x38 +#define OFFSET_X_DEFAULT 0x0c + +#define OFFSET_Y 0x39 +#define OFFSET_Y_DEFAULT 0x0c + +#define THRESHOLD_TOUCH 0x3a +#define THRESHOLD_TOUCH_DEFAULT 0xa0 + +#define THRESHOLD_GESTURE 0x3b +#define THRESHOLD_GESTURE_DEFAULT 0x17 + +#define SYSTEM 0x40 +#define ANALOG_POWER_ON 0x01 +#define ANALOG_POWER_OFF 0x00 +#define CPU_POWER_ON 0x02 +#define CPU_POWER_OFF 0x00 + +#define FORCE_CALIBRATION 0x42 +#define FORCE_CALIBRATION_ON 0x01 +#define FORCE_CALIBRATION_OFF 0x00 + +#define CPU_FREQ 0x50 /* 10 / (reg + 1) MHz */ +#define CPU_FREQ_10MHZ 0x00 +#define CPU_FREQ_5MHZ 0x01 +#define CPU_FREQ_1MHZ 0x09 + +#define EEPROM_ADDR 0x51 + +#define CALIBRATION_ADJUST 0x52 +#define CALIBRATION_ADJUST_DEFAULT 0x00 + +#define THRESHOLD_SLEEP_IN 0x53 + +#define EVR_XY 0x56 +#define EVR_XY_DEFAULT 0x10 + +#define PRM_SWOFF_TIME 0x57 +#define PRM_SWOFF_TIME_DEFAULT 0x04 + +#define PROGRAM_VERSION 0x5f + +#define ADC_CTRL 0x60 +#define ADC_DIV_MASK 0x1f /* The minimum value is 4 */ +#define ADC_DIV_DEFAULT 0x08 + +#define ADC_WAIT 0x61 +#define ADC_WAIT_DEFAULT 0x0a + +#define SWCONT 0x62 +#define SWCONT_DEFAULT 0x0f + +#define EVR_X 0x63 +#define EVR_X_DEFAULT 0x86 + +#define EVR_Y 0x64 +#define EVR_Y_DEFAULT 0x64 + +#define TEST1 0x65 +#define DUALTOUCH_STABILIZE_ON 0x01 +#define DUALTOUCH_STABILIZE_OFF 0x00 +#define DUALTOUCH_REG_ON 0x20 +#define DUALTOUCH_REG_OFF 0x00 + +#define CALIBRATION_REG1 0x68 +#define CALIBRATION_REG1_DEFAULT 0xd9 + +#define CALIBRATION_REG2 0x69 +#define CALIBRATION_REG2_DEFAULT 0x36 + +#define CALIBRATION_REG3 0x6a +#define CALIBRATION_REG3_DEFAULT 0x32 + +#define EX_ADDR_H 0x70 +#define EX_ADDR_L 0x71 +#define EX_WDAT 0x72 +#define EX_RDAT 0x73 +#define EX_CHK_SUM1 0x74 +#define EX_CHK_SUM2 0x75 +#define EX_CHK_SUM3 0x76 + +struct rohm_ts_data { + struct i2c_client *client; + struct input_dev *input; + + bool initialized; + + unsigned int contact_count[MAX_CONTACTS + 1]; + int finger_count; + + u8 setup2; +}; + +/* + * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24 + * @client: Handle to ROHM BU21023/24 + * @start: Where to start read address from ROHM BU21023/24 + * @buf: Where to store read data from ROHM BU21023/24 + * @len: How many bytes to read + * + * Returns negative errno, else zero on success. + * + * Note + * In BU21023/24 burst read, stop condition is needed after "address write". + * Therefore, transmission is performed in 2 steps. + */ +static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, + size_t len) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg[2]; + int i, ret = 0; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = &start; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = len; + msg[1].buf = buf; + + i2c_lock_adapter(adap); + + for (i = 0; i < 2; i++) { + if (__i2c_transfer(adap, &msg[i], 1) < 0) { + ret = -EIO; + break; + } + } + + i2c_unlock_adapter(adap); + + return ret; +} + +static int rohm_ts_manual_calibration(struct rohm_ts_data *ts) +{ + struct i2c_client *client = ts->client; + struct device *dev = &client->dev; + u8 buf[33]; /* for PRM1_X_H(0x08)-TOUCH(0x28) */ + + int retry; + bool success = false; + bool first_time = true; + bool calibration_done; + + u8 reg1, reg2, reg3; + s32 reg1_orig, reg2_orig, reg3_orig; + s32 val; + + int calib_x = 0, calib_y = 0; + int reg_x, reg_y; + int err_x, err_y; + + int error, error2; + int i; + + reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1); + if (reg1_orig < 0) + return reg1_orig; + + reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2); + if (reg2_orig < 0) + return reg2_orig; + + reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3); + if (reg3_orig < 0) + return reg3_orig; + + error = i2c_smbus_write_byte_data(client, INT_MASK, + COORD_UPDATE | SLEEP_IN | SLEEP_OUT | + PROGRAM_LOAD_DONE); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, TEST1, + DUALTOUCH_STABILIZE_ON); + if (error) + goto out; + + for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) { + /* wait 2 sampling for update */ + mdelay(2 * SAMPLING_DELAY); + +#define READ_CALIB_BUF(reg) buf[((reg) - PRM1_X_H)] + + error = rohm_i2c_burst_read(client, PRM1_X_H, buf, sizeof(buf)); + if (error) + goto out; + + if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT) + continue; + + if (first_time) { + /* generate calibration parameter */ + calib_x = ((int)READ_CALIB_BUF(PRM1_X_H) << 2 | + READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET; + calib_y = ((int)READ_CALIB_BUF(PRM1_Y_H) << 2 | + READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET; + + error = i2c_smbus_write_byte_data(client, TEST1, + DUALTOUCH_STABILIZE_ON | DUALTOUCH_REG_ON); + if (error) + goto out; + + first_time = false; + } else { + /* generate adjustment parameter */ + err_x = (int)READ_CALIB_BUF(PRM1_X_H) << 2 | + READ_CALIB_BUF(PRM1_X_L); + err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 | + READ_CALIB_BUF(PRM1_Y_L); + + /* X axis ajust */ + if (err_x <= 4) + calib_x -= AXIS_ADJUST; + else if (err_x >= 60) + calib_x += AXIS_ADJUST; + + /* Y axis ajust */ + if (err_y <= 4) + calib_y -= AXIS_ADJUST; + else if (err_y >= 60) + calib_y += AXIS_ADJUST; + } + + /* generate calibration setting value */ + reg_x = calib_x + ((calib_x & 0x200) << 1); + reg_y = calib_y + ((calib_y & 0x200) << 1); + + /* convert for register format */ + reg1 = reg_x >> 3; + reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7); + reg3 = reg_y >> 3; + + error = i2c_smbus_write_byte_data(client, + CALIBRATION_REG1, reg1); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, + CALIBRATION_REG2, reg2); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, + CALIBRATION_REG3, reg3); + if (error) + goto out; + + /* + * force calibration sequcence + */ + error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, + FORCE_CALIBRATION_OFF); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, + FORCE_CALIBRATION_ON); + if (error) + goto out; + + /* clear all interrupts */ + error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + if (error) + goto out; + + /* + * Wait for the status change of calibration, max 10 sampling + */ + calibration_done = false; + + for (i = 0; i < 10; i++) { + mdelay(SAMPLING_DELAY); + + val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE); + if (!(val & CALIBRATION_MASK)) { + calibration_done = true; + break; + } else if (val < 0) { + error = val; + goto out; + } + } + + if (calibration_done) { + val = i2c_smbus_read_byte_data(client, INT_STATUS); + if (val == CALIBRATION_DONE) { + success = true; + break; + } else if (val < 0) { + error = val; + goto out; + } + } else { + dev_warn(dev, "calibration timeout\n"); + } + } + + if (!success) { + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1, + reg1_orig); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2, + reg2_orig); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3, + reg3_orig); + if (error) + goto out; + + /* calibration data enable */ + error = i2c_smbus_write_byte_data(client, TEST1, + DUALTOUCH_STABILIZE_ON | + DUALTOUCH_REG_ON); + if (error) + goto out; + + /* wait 10 sampling */ + mdelay(10 * SAMPLING_DELAY); + + error = -EBUSY; + } + +out: + error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); + if (!error2) + /* Clear all interrupts */ + error2 = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + + return error ? error : error2; +} + +static const unsigned int untouch_threshold[3] = { 0, 1, 5 }; +static const unsigned int single_touch_threshold[3] = { 0, 0, 4 }; +static const unsigned int dual_touch_threshold[3] = { 10, 8, 0 }; + +static irqreturn_t rohm_ts_soft_irq(int irq, void *dev_id) +{ + struct rohm_ts_data *ts = dev_id; + struct i2c_client *client = ts->client; + struct input_dev *input_dev = ts->input; + struct device *dev = &client->dev; + + u8 buf[10]; /* for POS_X1_H(0x20)-TOUCH_GESTURE(0x29) */ + + struct input_mt_pos pos[MAX_CONTACTS]; + int slots[MAX_CONTACTS]; + u8 touch_flags; + unsigned int threshold; + int finger_count = -1; + int prev_finger_count = ts->finger_count; + int count; + int error; + int i; + + error = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); + if (error) + return IRQ_HANDLED; + + /* Clear all interrupts */ + error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + if (error) + return IRQ_HANDLED; + +#define READ_POS_BUF(reg) buf[((reg) - POS_X1_H)] + + error = rohm_i2c_burst_read(client, POS_X1_H, buf, sizeof(buf)); + if (error) + return IRQ_HANDLED; + + touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK; + if (touch_flags) { + /* generate coordinates */ + pos[0].x = ((s16)READ_POS_BUF(POS_X1_H) << 2) | + READ_POS_BUF(POS_X1_L); + pos[0].y = ((s16)READ_POS_BUF(POS_Y1_H) << 2) | + READ_POS_BUF(POS_Y1_L); + pos[1].x = ((s16)READ_POS_BUF(POS_X2_H) << 2) | + READ_POS_BUF(POS_X2_L); + pos[1].y = ((s16)READ_POS_BUF(POS_Y2_H) << 2) | + READ_POS_BUF(POS_Y2_L); + } + + switch (touch_flags) { + case 0: + threshold = untouch_threshold[prev_finger_count]; + if (++ts->contact_count[0] >= threshold) + finger_count = 0; + break; + + case SINGLE_TOUCH: + threshold = single_touch_threshold[prev_finger_count]; + if (++ts->contact_count[1] >= threshold) + finger_count = 1; + + if (finger_count == 1) { + if (pos[1].x != 0 && pos[1].y != 0) { + pos[0].x = pos[1].x; + pos[0].y = pos[1].y; + pos[1].x = 0; + pos[1].y = 0; + } + } + break; + + case DUAL_TOUCH: + threshold = dual_touch_threshold[prev_finger_count]; + if (++ts->contact_count[2] >= threshold) + finger_count = 2; + break; + + default: + dev_dbg(dev, + "Three or more touches are not supported\n"); + return IRQ_HANDLED; + } + + if (finger_count >= 0) { + if (prev_finger_count != finger_count) { + count = ts->contact_count[finger_count]; + memset(ts->contact_count, 0, sizeof(ts->contact_count)); + ts->contact_count[finger_count] = count; + } + + input_mt_assign_slots(input_dev, slots, pos, + finger_count, ROHM_TS_DISPLACEMENT_MAX); + + for (i = 0; i < finger_count; i++) { + input_mt_slot(input_dev, slots[i]); + input_mt_report_slot_state(input_dev, + MT_TOOL_FINGER, true); + input_report_abs(input_dev, + ABS_MT_POSITION_X, pos[i].x); + input_report_abs(input_dev, + ABS_MT_POSITION_Y, pos[i].y); + } + + input_mt_sync_frame(input_dev); + input_mt_report_pointer_emulation(input_dev, true); + input_sync(input_dev); + + ts->finger_count = finger_count; + } + + if (READ_POS_BUF(TOUCH_GESTURE) & CALIBRATION_REQUEST) { + error = rohm_ts_manual_calibration(ts); + if (error) + dev_warn(dev, "manual calibration failed: %d\n", + error); + } + + i2c_smbus_write_byte_data(client, INT_MASK, + CALIBRATION_DONE | SLEEP_OUT | SLEEP_IN | + PROGRAM_LOAD_DONE); + + return IRQ_HANDLED; +} + +static int rohm_ts_load_firmware(struct i2c_client *client, + const char *firmware_name) +{ + struct device *dev = &client->dev; + const struct firmware *fw; + s32 status; + unsigned int offset, len, xfer_len; + unsigned int retry = 0; + int error, error2; + + error = request_firmware(&fw, firmware_name, dev); + if (error) { + dev_err(dev, "unable to retrieve firmware %s: %d\n", + firmware_name, error); + return error; + } + + error = i2c_smbus_write_byte_data(client, INT_MASK, + COORD_UPDATE | CALIBRATION_DONE | + SLEEP_IN | SLEEP_OUT); + if (error) + goto out; + + do { + if (retry) { + dev_warn(dev, "retrying firmware load\n"); + + /* settings for retry */ + error = i2c_smbus_write_byte_data(client, EX_WDAT, 0); + if (error) + goto out; + } + + error = i2c_smbus_write_byte_data(client, EX_ADDR_H, 0); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, EX_ADDR_L, 0); + if (error) + goto out; + + error = i2c_smbus_write_byte_data(client, COMMON_SETUP1, + COMMON_SETUP1_DEFAULT); + if (error) + goto out; + + /* firmware load to the device */ + offset = 0; + len = fw->size; + + while (len) { + xfer_len = min(FIRMWARE_BLOCK_SIZE, len); + + error = i2c_smbus_write_i2c_block_data(client, EX_WDAT, + xfer_len, &fw->data[offset]); + if (error) + goto out; + + len -= xfer_len; + offset += xfer_len; + } + + /* check firmware load result */ + status = i2c_smbus_read_byte_data(client, INT_STATUS); + if (status < 0) { + error = status; + goto out; + } + + /* clear all interrupts */ + error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + if (error) + goto out; + + if (status == PROGRAM_LOAD_DONE) + break; + + error = -EIO; + } while (++retry >= FIRMWARE_RETRY_MAX); + +out: + error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); + + release_firmware(fw); + + return error ? error : error2; +} + +static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY)); +} + +static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + unsigned int val; + int error; + + error = kstrtouint(buf, 0, &val); + if (error) + return error; + + error = mutex_lock_interruptible(&ts->input->mutex); + if (error) + return error; + + if (val) + ts->setup2 |= SWAP_XY; + else + ts->setup2 &= ~SWAP_XY; + + if (ts->initialized) + error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2, + ts->setup2); + + mutex_unlock(&ts->input->mutex); + + return error ? error : count; +} + +static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X)); +} + +static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + unsigned int val; + int error; + + error = kstrtouint(buf, 0, &val); + if (error) + return error; + + error = mutex_lock_interruptible(&ts->input->mutex); + if (error) + return error; + + if (val) + ts->setup2 |= INV_X; + else + ts->setup2 &= ~INV_X; + + if (ts->initialized) + error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2, + ts->setup2); + + mutex_unlock(&ts->input->mutex); + + return error ? error : count; +} + +static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y)); +} + +static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rohm_ts_data *ts = i2c_get_clientdata(client); + unsigned int val; + int error; + + error = kstrtouint(buf, 0, &val); + if (error) + return error; + + error = mutex_lock_interruptible(&ts->input->mutex); + if (error) + return error; + + if (val) + ts->setup2 |= INV_Y; + else + ts->setup2 &= ~INV_Y; + + if (ts->initialized) + error = i2c_smbus_write_byte_data(client, COMMON_SETUP2, + ts->setup2); + + mutex_unlock(&ts->input->mutex); + + return error ? error : count; +} + +static DEVICE_ATTR_RW(swap_xy); +static DEVICE_ATTR_RW(inv_x); +static DEVICE_ATTR_RW(inv_y); + +static struct attribute *rohm_ts_attrs[] = { + &dev_attr_swap_xy.attr, + &dev_attr_inv_x.attr, + &dev_attr_inv_y.attr, + NULL, +}; + +static const struct attribute_group rohm_ts_attr_group = { + .attrs = rohm_ts_attrs, +}; + +static int rohm_ts_device_init(struct i2c_client *client, u8 setup2) +{ + struct device *dev = &client->dev; + int error; + + disable_irq(client->irq); + + /* + * Wait 200usec for reset + */ + udelay(200); + + /* Release analog reset */ + error = i2c_smbus_write_byte_data(client, SYSTEM, + ANALOG_POWER_ON | CPU_POWER_OFF); + if (error) + return error; + + /* Waiting for the analog warm-up, max. 200usec */ + udelay(200); + + /* clear all interrupts */ + error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, EX_WDAT, 0); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, COMMON_SETUP2, setup2); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, COMMON_SETUP3, + SEL_TBL_DEFAULT | EN_MULTI); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE, + THRESHOLD_GESTURE_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, INTERVAL_TIME, + INTERVAL_TIME_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME, + PRM_SWOFF_TIME_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT); + if (error) + return error; + + /* + * Panel setup, these values change with the panel. + */ + error = i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH, + THRESHOLD_TOUCH_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT); + if (error) + return error; + + /* Fixed value settings */ + error = i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST, + CALIBRATION_ADJUST_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, TEST1, + DUALTOUCH_STABILIZE_ON | + DUALTOUCH_REG_ON); + if (error) + return error; + + error = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME); + if (error) { + dev_err(dev, "failed to load firmware: %d\n", error); + return error; + } + + /* + * Manual calibration results are not changed in same environment. + * If the force calibration is performed, + * the controller will not require calibration request interrupt + * when the typical values are set to the calibration registers. + */ + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1, + CALIBRATION_REG1_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2, + CALIBRATION_REG2_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3, + CALIBRATION_REG3_DEFAULT); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, + FORCE_CALIBRATION_OFF); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION, + FORCE_CALIBRATION_ON); + if (error) + return error; + + /* Clear all interrupts */ + error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff); + if (error) + return error; + + /* Enable coordinates update interrupt */ + error = i2c_smbus_write_byte_data(client, INT_MASK, + CALIBRATION_DONE | SLEEP_OUT | + SLEEP_IN | PROGRAM_LOAD_DONE); + if (error) + return error; + + error = i2c_smbus_write_byte_data(client, ERR_MASK, + PROGRAM_LOAD_ERR | CPU_TIMEOUT | + ADC_TIMEOUT); + if (error) + return error; + + /* controller CPU power on */ + error = i2c_smbus_write_byte_data(client, SYSTEM, + ANALOG_POWER_ON | CPU_POWER_ON); + + enable_irq(client->irq); + + return error; +} + +static int rohm_ts_power_off(struct i2c_client *client) +{ + int error; + + error = i2c_smbus_write_byte_data(client, SYSTEM, + ANALOG_POWER_ON | CPU_POWER_OFF); + if (error) { + dev_err(&client->dev, + "failed to power off device CPU: %d\n", error); + return error; + } + + error = i2c_smbus_write_byte_data(client, SYSTEM, + ANALOG_POWER_OFF | CPU_POWER_OFF); + if (error) + dev_err(&client->dev, + "failed to power off the device: %d\n", error); + + return error; +} + +static int rohm_ts_open(struct input_dev *input_dev) +{ + struct rohm_ts_data *ts = input_get_drvdata(input_dev); + struct i2c_client *client = ts->client; + int error; + + if (!ts->initialized) { + error = rohm_ts_device_init(client, ts->setup2); + if (error) { + dev_err(&client->dev, + "device initialization failed: %d\n", error); + return error; + } + + ts->initialized = true; + } + + return 0; +} + +static void rohm_ts_close(struct input_dev *input_dev) +{ + struct rohm_ts_data *ts = input_get_drvdata(input_dev); + + rohm_ts_power_off(ts->client); + + ts->initialized = false; +} + +static void rohm_ts_remove_sysfs_group(void *_dev) +{ + struct device *dev = _dev; + + sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group); +} + +static int rohm_bu21023_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct rohm_ts_data *ts; + struct input_dev *input; + int error; + + if (!client->irq) { + dev_err(dev, "IRQ is not assigned\n"); + return -EINVAL; + } + + if (!client->adapter->algo->master_xfer) { + dev_err(dev, "I2C level transfers not supported\n"); + return -EOPNOTSUPP; + } + + /* Turn off CPU just in case */ + error = rohm_ts_power_off(client); + if (error) + return error; + + ts = devm_kzalloc(dev, sizeof(struct rohm_ts_data), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + ts->client = client; + ts->setup2 = MAF_1SAMPLE; + i2c_set_clientdata(client, ts); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = BU21023_NAME; + input->id.bustype = BUS_I2C; + input->open = rohm_ts_open; + input->close = rohm_ts_close; + + ts->input = input; + input_set_drvdata(input, ts); + + input_set_abs_params(input, ABS_MT_POSITION_X, + ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0); + + error = input_mt_init_slots(input, MAX_CONTACTS, + INPUT_MT_DIRECT | INPUT_MT_TRACK | + INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(dev, "failed to multi touch slots initialization\n"); + return error; + } + + error = devm_request_threaded_irq(dev, client->irq, + NULL, rohm_ts_soft_irq, + IRQF_ONESHOT, client->name, ts); + if (error) { + dev_err(dev, "failed to request IRQ: %d\n", error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to register input device: %d\n", error); + return error; + } + + error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group); + if (error) { + dev_err(dev, "failed to create sysfs group: %d\n", error); + return error; + } + + error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev); + if (error) { + rohm_ts_remove_sysfs_group(dev); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + return error; +} + +static const struct i2c_device_id rohm_bu21023_i2c_id[] = { + { BU21023_NAME, 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id); + +static struct i2c_driver rohm_bu21023_i2c_driver = { + .driver = { + .name = BU21023_NAME, + }, + .probe = rohm_bu21023_i2c_probe, + .id_table = rohm_bu21023_i2c_id, +}; +module_i2c_driver(rohm_bu21023_i2c_driver); + +MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("ROHM Co., Ltd."); diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 4ffd829d1990..a340bfccdfb6 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -50,14 +50,7 @@ struct tps6507x_ts { static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data) { - int err; - - err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data); - - if (err) - return err; - - return 0; + return tsc->mfd->read_dev(tsc->mfd, reg, 1, data); } static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 781d0f83050a..9bbadaaf6bc3 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -599,13 +599,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) static int zforce_input_open(struct input_dev *dev) { struct zforce_ts *ts = input_get_drvdata(dev); - int ret; - ret = zforce_start(ts); - if (ret) - return ret; - - return 0; + return zforce_start(ts); } static void zforce_input_close(struct input_dev *dev) diff --git a/include/dt-bindings/input/input.h b/include/dt-bindings/input/input.h index 042e7b3b6296..a21413324a3f 100644 --- a/include/dt-bindings/input/input.h +++ b/include/dt-bindings/input/input.h @@ -9,515 +9,7 @@ #ifndef _DT_BINDINGS_INPUT_INPUT_H #define _DT_BINDINGS_INPUT_INPUT_H -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 - -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 /* SC System Power Down */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ - -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 - -#define KEY_STOP 128 /* AC Stop */ -#define KEY_AGAIN 129 -#define KEY_PROPS 130 /* AC Properties */ -#define KEY_UNDO 131 /* AC Undo */ -#define KEY_FRONT 132 -#define KEY_COPY 133 /* AC Copy */ -#define KEY_OPEN 134 /* AC Open */ -#define KEY_PASTE 135 /* AC Paste */ -#define KEY_FIND 136 /* AC Search */ -#define KEY_CUT 137 /* AC Cut */ -#define KEY_HELP 138 /* AL Integrated Help Center */ -#define KEY_MENU 139 /* Menu (show menu) */ -#define KEY_CALC 140 /* AL Calculator */ -#define KEY_SETUP 141 -#define KEY_SLEEP 142 /* SC System Sleep */ -#define KEY_WAKEUP 143 /* System Wake Up */ -#define KEY_FILE 144 /* AL Local Machine Browser */ -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 /* AL Internet Browser */ -#define KEY_MSDOS 151 -#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_DIRECTION 153 -#define KEY_CYCLEWINDOWS 154 -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 /* AC Bookmarks */ -#define KEY_COMPUTER 157 -#define KEY_BACK 158 /* AC Back */ -#define KEY_FORWARD 159 /* AC Forward */ -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 /* Media Select Telephone */ -#define KEY_ISO 170 -#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ -#define KEY_HOMEPAGE 172 /* AC Home */ -#define KEY_REFRESH 173 /* AC Refresh */ -#define KEY_EXIT 174 /* AC Exit */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 /* AC New */ -#define KEY_REDO 182 /* AC Redo/Repeat */ - -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 - -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -#define KEY_DASHBOARD 204 /* AL Dashboard */ -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 /* AC Close */ -#define KEY_PLAY 207 -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 /* AC Print */ -#define KEY_HP 211 -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 /* AL Checkbook/Finance */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 /* AC Cancel */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 - -#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video - outputs (Monitor/LCD/TV-out/etc) */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 - -#define KEY_SEND 231 /* AC Send */ -#define KEY_REPLY 232 /* AC Reply */ -#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ -#define KEY_SAVE 234 /* AC Save */ -#define KEY_DOCUMENTS 235 - -#define KEY_BATTERY 236 - -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 - -#define KEY_UNKNOWN 240 - -#define KEY_VIDEO_NEXT 241 /* drive next video source */ -#define KEY_VIDEO_PREV 242 /* drive previous video source */ -#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ -#define KEY_DISPLAY_OFF 245 /* display device to off state */ - -#define KEY_WIMAX 246 -#define KEY_RFKILL 247 /* Key that controls all radios */ - -#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ - -/* Code 255 is reserved for special needs of AT keyboard driver */ - -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 - -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -#define BTN_TASK 0x117 - -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f - -#define BTN_GAMEPAD 0x130 -#define BTN_SOUTH 0x130 -#define BTN_A BTN_SOUTH -#define BTN_EAST 0x131 -#define BTN_B BTN_EAST -#define BTN_C 0x132 -#define BTN_NORTH 0x133 -#define BTN_X BTN_NORTH -#define BTN_WEST 0x134 -#define BTN_Y BTN_WEST -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e - -#define BTN_DIGI 0x140 -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ - -#define BTN_WHEEL 0x150 -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 - -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -#define KEY_PVR 0x16e /* Media Select Home */ -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 -#define KEY_MODE 0x175 -#define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 -#define KEY_PC 0x178 /* Media Select Computer */ -#define KEY_TV 0x179 /* Media Select TV */ -#define KEY_TV2 0x17a /* Media Select Cable */ -#define KEY_VCR 0x17b /* Media Select VCR */ -#define KEY_VCR2 0x17c /* VCR Plus */ -#define KEY_SAT 0x17d /* Media Select Satellite */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f /* Media Select CD */ -#define KEY_TAPE 0x180 /* Media Select Tape */ -#define KEY_RADIO 0x181 -#define KEY_TUNER 0x182 /* Media Select Tuner */ -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 /* Media Select DVD */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 /* AL Audio Browser */ -#define KEY_VIDEO 0x189 /* AL Movie Browser */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c /* Media Select Messages */ -#define KEY_CALENDAR 0x18d -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -#define KEY_CHANNELUP 0x192 /* Channel Increment */ -#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 /* Recall Last */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ -#define KEY_GAMES 0x1a1 /* Media Select Games */ -#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ -#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ -#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ -#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ -#define KEY_EDITOR 0x1a6 /* AL Text Editor */ -#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ -#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ -#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ -#define KEY_DATABASE 0x1aa /* AL Database App */ -#define KEY_NEWS 0x1ab /* AL Newsreader */ -#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ -#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ -#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ -#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ -#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ -#define KEY_LOGOFF 0x1b1 /* AL Logoff */ - -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 - -#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ -#define KEY_FRAMEFORWARD 0x1b5 -#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ -#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ -#define KEY_IMAGES 0x1ba /* AL Image Browser */ - -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -#define KEY_DEL_LINE 0x1c3 - -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 - -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa - -#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ -#define KEY_NUMERIC_1 0x201 /* and other keypads */ -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b - -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ - -#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 - -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a - -#define KEY_ATTENDANT_ON 0x21b -#define KEY_ATTENDANT_OFF 0x21c -#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ -#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ - -#define BTN_DPAD_UP 0x220 -#define BTN_DPAD_DOWN 0x221 -#define BTN_DPAD_LEFT 0x222 -#define BTN_DPAD_RIGHT 0x223 +#include "linux-event-codes.h" #define MATRIX_KEY(row, col, code) \ ((((row) & 0xFF) << 24) | (((col) & 0xFF) << 16) | ((code) & 0xFFFF)) diff --git a/include/dt-bindings/input/linux-event-codes.h b/include/dt-bindings/input/linux-event-codes.h new file mode 120000 index 000000000000..693bbcd2670a --- /dev/null +++ b/include/dt-bindings/input/linux-event-codes.h @@ -0,0 +1 @@ +../../uapi/linux/input-event-codes.h
\ No newline at end of file diff --git a/include/linux/hid.h b/include/linux/hid.h index f17980de2662..251a1d382e23 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -698,8 +698,8 @@ struct hid_driver { int (*input_mapped)(struct hid_device *hdev, struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max); - void (*input_configured)(struct hid_device *hdev, - struct hid_input *hidinput); + int (*input_configured)(struct hid_device *hdev, + struct hid_input *hidinput); void (*feature_mapping)(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage); diff --git a/include/linux/input.h b/include/linux/input.h index 82ce323b9986..1e967694e9a5 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -469,6 +469,8 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke); int input_set_keycode(struct input_dev *dev, const struct input_keymap_entry *ke); +void input_enable_softrepeat(struct input_dev *dev, int delay, int period); + extern struct class input_class; /** diff --git a/include/linux/input/edt-ft5x06.h b/include/linux/input/edt-ft5x06.h deleted file mode 100644 index 8a1e0d1a0124..000000000000 --- a/include/linux/input/edt-ft5x06.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _EDT_FT5X06_H -#define _EDT_FT5X06_H - -/* - * Copyright (c) 2012 Simon Budig, <simon.budig@kernelconcepts.de> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -struct edt_ft5x06_platform_data { - int irq_pin; - int reset_pin; - - /* startup defaults for operational parameters */ - bool use_parameters; - u8 gain; - u8 threshold; - u8 offset; - u8 report_rate; -}; - -#endif /* _EDT_FT5X06_H */ diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 81f6e427ba6b..543037465973 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -49,6 +49,7 @@ #define LOOP_CTRL_MINOR 237 #define VHOST_NET_MINOR 238 #define UHID_MINOR 239 +#define USERIO_MINOR 240 #define MISC_DYNAMIC_MINOR 255 struct device; diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 3f594dce5716..fe3dc64e5aeb 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -8,9 +8,10 @@ struct rotary_encoder_platform_data { unsigned int gpio_b; unsigned int inverted_a; unsigned int inverted_b; + unsigned int steps_per_period; bool relative_axis; bool rollover; - bool half_period; + bool wakeup_source; }; #endif /* __ROTARY_ENCODER_H__ */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 70d89230b641..628e6e64c2fb 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -191,6 +191,7 @@ header-y += inet_diag.h header-y += in.h header-y += inotify.h header-y += input.h +header-y += input-event-codes.h header-y += in_route.h header-y += ioctl.h header-y += ip6_tunnel.h diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h new file mode 100644 index 000000000000..87cf351bab03 --- /dev/null +++ b/include/uapi/linux/input-event-codes.h @@ -0,0 +1,805 @@ +/* + * Input event codes + * + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 2015 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#ifndef _UAPI_INPUT_EVENT_CODES_H +#define _UAPI_INPUT_EVENT_CODES_H + +/* + * Device properties and quirks + */ + +#define INPUT_PROP_POINTER 0x00 /* needs a pointer */ +#define INPUT_PROP_DIRECT 0x01 /* direct input devices */ +#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ +#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ +#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ +#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ +#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ + +#define INPUT_PROP_MAX 0x1f +#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) + +/* + * Event types + */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX+1) + +/* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 +#define SYN_MAX 0xf +#define SYN_CNT (SYN_MAX+1) + +/* + * Keys and buttons + * + * Most of the keys/buttons are modeled after USB HUT 1.12 + * (see http://www.usb.org/developers/hidpage). + * Abbreviations in the comments: + * AC - Application Control + * AL - Application Launch Button + * SC - System Control + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 /* SC System Power Down */ +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ + +#define KEY_KPCOMMA 121 +#define KEY_HANGEUL 122 +#define KEY_HANGUEL KEY_HANGEUL +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 /* AC Stop */ +#define KEY_AGAIN 129 +#define KEY_PROPS 130 /* AC Properties */ +#define KEY_UNDO 131 /* AC Undo */ +#define KEY_FRONT 132 +#define KEY_COPY 133 /* AC Copy */ +#define KEY_OPEN 134 /* AC Open */ +#define KEY_PASTE 135 /* AC Paste */ +#define KEY_FIND 136 /* AC Search */ +#define KEY_CUT 137 /* AC Cut */ +#define KEY_HELP 138 /* AL Integrated Help Center */ +#define KEY_MENU 139 /* Menu (show menu) */ +#define KEY_CALC 140 /* AL Calculator */ +#define KEY_SETUP 141 +#define KEY_SLEEP 142 /* SC System Sleep */ +#define KEY_WAKEUP 143 /* System Wake Up */ +#define KEY_FILE 144 /* AL Local Machine Browser */ +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 /* AL Internet Browser */ +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ +#define KEY_SCREENLOCK KEY_COFFEE +#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ +#define KEY_DIRECTION KEY_ROTATE_DISPLAY +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 /* AC Bookmarks */ +#define KEY_COMPUTER 157 +#define KEY_BACK 158 /* AC Back */ +#define KEY_FORWARD 159 /* AC Forward */ +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 /* Media Select Telephone */ +#define KEY_ISO 170 +#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ +#define KEY_HOMEPAGE 172 /* AC Home */ +#define KEY_REFRESH 173 /* AC Refresh */ +#define KEY_EXIT 174 /* AC Exit */ +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 /* AC New */ +#define KEY_REDO 182 /* AC Redo/Repeat */ + +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_DASHBOARD 204 /* AL Dashboard */ +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 /* AC Close */ +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 /* AC Print */ +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 /* AL Checkbook/Finance */ +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 /* AC Cancel */ +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video + outputs (Monitor/LCD/TV-out/etc) */ +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 + +#define KEY_SEND 231 /* AC Send */ +#define KEY_REPLY 232 /* AC Reply */ +#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ +#define KEY_SAVE 234 /* AC Save */ +#define KEY_DOCUMENTS 235 + +#define KEY_BATTERY 236 + +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 + +#define KEY_UNKNOWN 240 + +#define KEY_VIDEO_NEXT 241 /* drive next video source */ +#define KEY_VIDEO_PREV 242 /* drive previous video source */ +#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ +#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual + brightness control is off, + rely on ambient */ +#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO +#define KEY_DISPLAY_OFF 245 /* display device to off state */ + +#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ +#define KEY_WIMAX KEY_WWAN +#define KEY_RFKILL 247 /* Key that controls all radios */ + +#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ + +/* Code 255 is reserved for special needs of AT keyboard driver */ + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_SOUTH 0x130 +#define BTN_A BTN_SOUTH +#define BTN_EAST 0x131 +#define BTN_B BTN_EAST +#define BTN_C 0x132 +#define BTN_NORTH 0x133 +#define BTN_X BTN_NORTH +#define BTN_WEST 0x134 +#define BTN_Y BTN_WEST +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e +#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e /* Media Select Home */ +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 /* Media Select Computer */ +#define KEY_TV 0x179 /* Media Select TV */ +#define KEY_TV2 0x17a /* Media Select Cable */ +#define KEY_VCR 0x17b /* Media Select VCR */ +#define KEY_VCR2 0x17c /* VCR Plus */ +#define KEY_SAT 0x17d /* Media Select Satellite */ +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f /* Media Select CD */ +#define KEY_TAPE 0x180 /* Media Select Tape */ +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 /* Media Select Tuner */ +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 /* Media Select DVD */ +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 /* AL Audio Browser */ +#define KEY_VIDEO 0x189 /* AL Movie Browser */ +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c /* Media Select Messages */ +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 /* Channel Increment */ +#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 /* Recall Last */ +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f +#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ +#define KEY_GAMES 0x1a1 /* Media Select Games */ +#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ +#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ +#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ +#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ +#define KEY_EDITOR 0x1a6 /* AL Text Editor */ +#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ +#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ +#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ +#define KEY_DATABASE 0x1aa /* AL Database App */ +#define KEY_NEWS 0x1ab /* AL Newsreader */ +#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ +#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ +#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ +#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE +#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ +#define KEY_LOGOFF 0x1b1 /* AL Logoff */ + +#define KEY_DOLLAR 0x1b2 +#define KEY_EURO 0x1b3 + +#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ +#define KEY_FRAMEFORWARD 0x1b5 +#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ +#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ +#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ +#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ +#define KEY_IMAGES 0x1ba /* AL Image Browser */ + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_FN 0x1d0 +#define KEY_FN_ESC 0x1d1 +#define KEY_FN_F1 0x1d2 +#define KEY_FN_F2 0x1d3 +#define KEY_FN_F3 0x1d4 +#define KEY_FN_F4 0x1d5 +#define KEY_FN_F5 0x1d6 +#define KEY_FN_F6 0x1d7 +#define KEY_FN_F7 0x1d8 +#define KEY_FN_F8 0x1d9 +#define KEY_FN_F9 0x1da +#define KEY_FN_F10 0x1db +#define KEY_FN_F11 0x1dc +#define KEY_FN_F12 0x1dd +#define KEY_FN_1 0x1de +#define KEY_FN_2 0x1df +#define KEY_FN_D 0x1e0 +#define KEY_FN_E 0x1e1 +#define KEY_FN_F 0x1e2 +#define KEY_FN_S 0x1e3 +#define KEY_FN_B 0x1e4 + +#define KEY_BRL_DOT1 0x1f1 +#define KEY_BRL_DOT2 0x1f2 +#define KEY_BRL_DOT3 0x1f3 +#define KEY_BRL_DOT4 0x1f4 +#define KEY_BRL_DOT5 0x1f5 +#define KEY_BRL_DOT6 0x1f6 +#define KEY_BRL_DOT7 0x1f7 +#define KEY_BRL_DOT8 0x1f8 +#define KEY_BRL_DOT9 0x1f9 +#define KEY_BRL_DOT10 0x1fa + +#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ +#define KEY_NUMERIC_1 0x201 /* and other keypads */ +#define KEY_NUMERIC_2 0x202 +#define KEY_NUMERIC_3 0x203 +#define KEY_NUMERIC_4 0x204 +#define KEY_NUMERIC_5 0x205 +#define KEY_NUMERIC_6 0x206 +#define KEY_NUMERIC_7 0x207 +#define KEY_NUMERIC_8 0x208 +#define KEY_NUMERIC_9 0x209 +#define KEY_NUMERIC_STAR 0x20a +#define KEY_NUMERIC_POUND 0x20b +#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ +#define KEY_NUMERIC_B 0x20d +#define KEY_NUMERIC_C 0x20e +#define KEY_NUMERIC_D 0x20f + +#define KEY_CAMERA_FOCUS 0x210 +#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ + +#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ +#define KEY_TOUCHPAD_ON 0x213 +#define KEY_TOUCHPAD_OFF 0x214 + +#define KEY_CAMERA_ZOOMIN 0x215 +#define KEY_CAMERA_ZOOMOUT 0x216 +#define KEY_CAMERA_UP 0x217 +#define KEY_CAMERA_DOWN 0x218 +#define KEY_CAMERA_LEFT 0x219 +#define KEY_CAMERA_RIGHT 0x21a + +#define KEY_ATTENDANT_ON 0x21b +#define KEY_ATTENDANT_OFF 0x21c +#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ +#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ + +#define BTN_DPAD_UP 0x220 +#define BTN_DPAD_DOWN 0x221 +#define BTN_DPAD_LEFT 0x222 +#define BTN_DPAD_RIGHT 0x223 + +#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ + +#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ +#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ +#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ +#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ +#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ +#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ +#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ + +#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ +#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + +#define KEY_KBDINPUTASSIST_PREV 0x260 +#define KEY_KBDINPUTASSIST_NEXT 0x261 +#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 +#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 +#define KEY_KBDINPUTASSIST_ACCEPT 0x264 +#define KEY_KBDINPUTASSIST_CANCEL 0x265 + +#define BTN_TRIGGER_HAPPY 0x2c0 +#define BTN_TRIGGER_HAPPY1 0x2c0 +#define BTN_TRIGGER_HAPPY2 0x2c1 +#define BTN_TRIGGER_HAPPY3 0x2c2 +#define BTN_TRIGGER_HAPPY4 0x2c3 +#define BTN_TRIGGER_HAPPY5 0x2c4 +#define BTN_TRIGGER_HAPPY6 0x2c5 +#define BTN_TRIGGER_HAPPY7 0x2c6 +#define BTN_TRIGGER_HAPPY8 0x2c7 +#define BTN_TRIGGER_HAPPY9 0x2c8 +#define BTN_TRIGGER_HAPPY10 0x2c9 +#define BTN_TRIGGER_HAPPY11 0x2ca +#define BTN_TRIGGER_HAPPY12 0x2cb +#define BTN_TRIGGER_HAPPY13 0x2cc +#define BTN_TRIGGER_HAPPY14 0x2cd +#define BTN_TRIGGER_HAPPY15 0x2ce +#define BTN_TRIGGER_HAPPY16 0x2cf +#define BTN_TRIGGER_HAPPY17 0x2d0 +#define BTN_TRIGGER_HAPPY18 0x2d1 +#define BTN_TRIGGER_HAPPY19 0x2d2 +#define BTN_TRIGGER_HAPPY20 0x2d3 +#define BTN_TRIGGER_HAPPY21 0x2d4 +#define BTN_TRIGGER_HAPPY22 0x2d5 +#define BTN_TRIGGER_HAPPY23 0x2d6 +#define BTN_TRIGGER_HAPPY24 0x2d7 +#define BTN_TRIGGER_HAPPY25 0x2d8 +#define BTN_TRIGGER_HAPPY26 0x2d9 +#define BTN_TRIGGER_HAPPY27 0x2da +#define BTN_TRIGGER_HAPPY28 0x2db +#define BTN_TRIGGER_HAPPY29 0x2dc +#define BTN_TRIGGER_HAPPY30 0x2dd +#define BTN_TRIGGER_HAPPY31 0x2de +#define BTN_TRIGGER_HAPPY32 0x2df +#define BTN_TRIGGER_HAPPY33 0x2e0 +#define BTN_TRIGGER_HAPPY34 0x2e1 +#define BTN_TRIGGER_HAPPY35 0x2e2 +#define BTN_TRIGGER_HAPPY36 0x2e3 +#define BTN_TRIGGER_HAPPY37 0x2e4 +#define BTN_TRIGGER_HAPPY38 0x2e5 +#define BTN_TRIGGER_HAPPY39 0x2e6 +#define BTN_TRIGGER_HAPPY40 0x2e7 + +/* We avoid low common keys in module aliases so they don't get huge. */ +#define KEY_MIN_INTERESTING KEY_MUTE +#define KEY_MAX 0x2ff +#define KEY_CNT (KEY_MAX+1) + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX+1) + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c + +#define ABS_VOLUME 0x20 + +#define ABS_MISC 0x28 + +#define ABS_MT_SLOT 0x2f /* MT slot being modified */ +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ +#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ +#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ +#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ +#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ +#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ +#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ +#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ +#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ +#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ +#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ + + +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX+1) + +/* + * Switch events + */ + +#define SW_LID 0x00 /* set = lid shut */ +#define SW_TABLET_MODE 0x01 /* set = tablet mode */ +#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ +#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" + set = radio enabled */ +#define SW_RADIO SW_RFKILL_ALL /* deprecated */ +#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ +#define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ +#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ +#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ +#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ +#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ +#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ +#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ +#define SW_LINEIN_INSERT 0x0d /* set = inserted */ +#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ +#define SW_MAX 0x0f +#define SW_CNT (SW_MAX+1) + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_TIMESTAMP 0x05 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX+1) + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAIL 0x09 +#define LED_CHARGING 0x0a +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX+1) + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX+1) + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 +#define SND_CNT (SND_MAX+1) + +#endif diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 731417c025f6..2758687300b4 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -16,6 +16,7 @@ #include <linux/types.h> #endif +#include "input-event-codes.h" /* * The event structure itself @@ -97,6 +98,12 @@ struct input_keymap_entry { __u8 scancode[32]; }; +struct input_mask { + __u32 type; + __u32 codes_size; + __u64 codes_ptr; +}; + #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ @@ -147,801 +154,68 @@ struct input_keymap_entry { #define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ #define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ -#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ +#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ #define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */ -#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ - -/* - * Device properties and quirks - */ - -#define INPUT_PROP_POINTER 0x00 /* needs a pointer */ -#define INPUT_PROP_DIRECT 0x01 /* direct input devices */ -#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ -#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ -#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ -#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ -#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ - -#define INPUT_PROP_MAX 0x1f -#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) - -/* - * Event types - */ - -#define EV_SYN 0x00 -#define EV_KEY 0x01 -#define EV_REL 0x02 -#define EV_ABS 0x03 -#define EV_MSC 0x04 -#define EV_SW 0x05 -#define EV_LED 0x11 -#define EV_SND 0x12 -#define EV_REP 0x14 -#define EV_FF 0x15 -#define EV_PWR 0x16 -#define EV_FF_STATUS 0x17 -#define EV_MAX 0x1f -#define EV_CNT (EV_MAX+1) - -/* - * Synchronization events. - */ - -#define SYN_REPORT 0 -#define SYN_CONFIG 1 -#define SYN_MT_REPORT 2 -#define SYN_DROPPED 3 -#define SYN_MAX 0xf -#define SYN_CNT (SYN_MAX+1) - -/* - * Keys and buttons +/** + * EVIOCGMASK - Retrieve current event mask * - * Most of the keys/buttons are modeled after USB HUT 1.12 - * (see http://www.usb.org/developers/hidpage). - * Abbreviations in the comments: - * AC - Application Control - * AL - Application Launch Button - * SC - System Control - */ - -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 - -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 /* SC System Power Down */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ - -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 - -#define KEY_STOP 128 /* AC Stop */ -#define KEY_AGAIN 129 -#define KEY_PROPS 130 /* AC Properties */ -#define KEY_UNDO 131 /* AC Undo */ -#define KEY_FRONT 132 -#define KEY_COPY 133 /* AC Copy */ -#define KEY_OPEN 134 /* AC Open */ -#define KEY_PASTE 135 /* AC Paste */ -#define KEY_FIND 136 /* AC Search */ -#define KEY_CUT 137 /* AC Cut */ -#define KEY_HELP 138 /* AL Integrated Help Center */ -#define KEY_MENU 139 /* Menu (show menu) */ -#define KEY_CALC 140 /* AL Calculator */ -#define KEY_SETUP 141 -#define KEY_SLEEP 142 /* SC System Sleep */ -#define KEY_WAKEUP 143 /* System Wake Up */ -#define KEY_FILE 144 /* AL Local Machine Browser */ -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 /* AL Internet Browser */ -#define KEY_MSDOS 151 -#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ -#define KEY_DIRECTION KEY_ROTATE_DISPLAY -#define KEY_CYCLEWINDOWS 154 -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 /* AC Bookmarks */ -#define KEY_COMPUTER 157 -#define KEY_BACK 158 /* AC Back */ -#define KEY_FORWARD 159 /* AC Forward */ -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 /* Media Select Telephone */ -#define KEY_ISO 170 -#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ -#define KEY_HOMEPAGE 172 /* AC Home */ -#define KEY_REFRESH 173 /* AC Refresh */ -#define KEY_EXIT 174 /* AC Exit */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 /* AC New */ -#define KEY_REDO 182 /* AC Redo/Repeat */ - -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 - -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -#define KEY_DASHBOARD 204 /* AL Dashboard */ -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 /* AC Close */ -#define KEY_PLAY 207 -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 /* AC Print */ -#define KEY_HP 211 -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 /* AL Checkbook/Finance */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 /* AC Cancel */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 - -#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video - outputs (Monitor/LCD/TV-out/etc) */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 - -#define KEY_SEND 231 /* AC Send */ -#define KEY_REPLY 232 /* AC Reply */ -#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ -#define KEY_SAVE 234 /* AC Save */ -#define KEY_DOCUMENTS 235 - -#define KEY_BATTERY 236 - -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 - -#define KEY_UNKNOWN 240 - -#define KEY_VIDEO_NEXT 241 /* drive next video source */ -#define KEY_VIDEO_PREV 242 /* drive previous video source */ -#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual - brightness control is off, - rely on ambient */ -#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO -#define KEY_DISPLAY_OFF 245 /* display device to off state */ - -#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ -#define KEY_WIMAX KEY_WWAN -#define KEY_RFKILL 247 /* Key that controls all radios */ - -#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ - -/* Code 255 is reserved for special needs of AT keyboard driver */ - -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 - -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -#define BTN_TASK 0x117 - -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f - -#define BTN_GAMEPAD 0x130 -#define BTN_SOUTH 0x130 -#define BTN_A BTN_SOUTH -#define BTN_EAST 0x131 -#define BTN_B BTN_EAST -#define BTN_C 0x132 -#define BTN_NORTH 0x133 -#define BTN_X BTN_NORTH -#define BTN_WEST 0x134 -#define BTN_Y BTN_WEST -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e - -#define BTN_DIGI 0x140 -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ - -#define BTN_WHEEL 0x150 -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 - -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -#define KEY_PVR 0x16e /* Media Select Home */ -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 -#define KEY_MODE 0x175 -#define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 -#define KEY_PC 0x178 /* Media Select Computer */ -#define KEY_TV 0x179 /* Media Select TV */ -#define KEY_TV2 0x17a /* Media Select Cable */ -#define KEY_VCR 0x17b /* Media Select VCR */ -#define KEY_VCR2 0x17c /* VCR Plus */ -#define KEY_SAT 0x17d /* Media Select Satellite */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f /* Media Select CD */ -#define KEY_TAPE 0x180 /* Media Select Tape */ -#define KEY_RADIO 0x181 -#define KEY_TUNER 0x182 /* Media Select Tuner */ -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 /* Media Select DVD */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 /* AL Audio Browser */ -#define KEY_VIDEO 0x189 /* AL Movie Browser */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c /* Media Select Messages */ -#define KEY_CALENDAR 0x18d -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -#define KEY_CHANNELUP 0x192 /* Channel Increment */ -#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 /* Recall Last */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ -#define KEY_GAMES 0x1a1 /* Media Select Games */ -#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ -#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ -#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ -#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ -#define KEY_EDITOR 0x1a6 /* AL Text Editor */ -#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ -#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ -#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ -#define KEY_DATABASE 0x1aa /* AL Database App */ -#define KEY_NEWS 0x1ab /* AL Newsreader */ -#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ -#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ -#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ -#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ -#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE -#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ -#define KEY_LOGOFF 0x1b1 /* AL Logoff */ - -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 - -#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ -#define KEY_FRAMEFORWARD 0x1b5 -#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ -#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ -#define KEY_IMAGES 0x1ba /* AL Image Browser */ - -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -#define KEY_DEL_LINE 0x1c3 - -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 - -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa - -#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ -#define KEY_NUMERIC_1 0x201 /* and other keypads */ -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ -#define KEY_NUMERIC_B 0x20d -#define KEY_NUMERIC_C 0x20e -#define KEY_NUMERIC_D 0x20f - -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ - -#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 - -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a - -#define KEY_ATTENDANT_ON 0x21b -#define KEY_ATTENDANT_OFF 0x21c -#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ -#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ - -#define BTN_DPAD_UP 0x220 -#define BTN_DPAD_DOWN 0x221 -#define BTN_DPAD_LEFT 0x222 -#define BTN_DPAD_RIGHT 0x223 - -#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ - -#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ -#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ -#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ -#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ -#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ -#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ -#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ - -#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ -#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ - -#define KEY_KBDINPUTASSIST_PREV 0x260 -#define KEY_KBDINPUTASSIST_NEXT 0x261 -#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 -#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 -#define KEY_KBDINPUTASSIST_ACCEPT 0x264 -#define KEY_KBDINPUTASSIST_CANCEL 0x265 - -#define BTN_TRIGGER_HAPPY 0x2c0 -#define BTN_TRIGGER_HAPPY1 0x2c0 -#define BTN_TRIGGER_HAPPY2 0x2c1 -#define BTN_TRIGGER_HAPPY3 0x2c2 -#define BTN_TRIGGER_HAPPY4 0x2c3 -#define BTN_TRIGGER_HAPPY5 0x2c4 -#define BTN_TRIGGER_HAPPY6 0x2c5 -#define BTN_TRIGGER_HAPPY7 0x2c6 -#define BTN_TRIGGER_HAPPY8 0x2c7 -#define BTN_TRIGGER_HAPPY9 0x2c8 -#define BTN_TRIGGER_HAPPY10 0x2c9 -#define BTN_TRIGGER_HAPPY11 0x2ca -#define BTN_TRIGGER_HAPPY12 0x2cb -#define BTN_TRIGGER_HAPPY13 0x2cc -#define BTN_TRIGGER_HAPPY14 0x2cd -#define BTN_TRIGGER_HAPPY15 0x2ce -#define BTN_TRIGGER_HAPPY16 0x2cf -#define BTN_TRIGGER_HAPPY17 0x2d0 -#define BTN_TRIGGER_HAPPY18 0x2d1 -#define BTN_TRIGGER_HAPPY19 0x2d2 -#define BTN_TRIGGER_HAPPY20 0x2d3 -#define BTN_TRIGGER_HAPPY21 0x2d4 -#define BTN_TRIGGER_HAPPY22 0x2d5 -#define BTN_TRIGGER_HAPPY23 0x2d6 -#define BTN_TRIGGER_HAPPY24 0x2d7 -#define BTN_TRIGGER_HAPPY25 0x2d8 -#define BTN_TRIGGER_HAPPY26 0x2d9 -#define BTN_TRIGGER_HAPPY27 0x2da -#define BTN_TRIGGER_HAPPY28 0x2db -#define BTN_TRIGGER_HAPPY29 0x2dc -#define BTN_TRIGGER_HAPPY30 0x2dd -#define BTN_TRIGGER_HAPPY31 0x2de -#define BTN_TRIGGER_HAPPY32 0x2df -#define BTN_TRIGGER_HAPPY33 0x2e0 -#define BTN_TRIGGER_HAPPY34 0x2e1 -#define BTN_TRIGGER_HAPPY35 0x2e2 -#define BTN_TRIGGER_HAPPY36 0x2e3 -#define BTN_TRIGGER_HAPPY37 0x2e4 -#define BTN_TRIGGER_HAPPY38 0x2e5 -#define BTN_TRIGGER_HAPPY39 0x2e6 -#define BTN_TRIGGER_HAPPY40 0x2e7 - -/* We avoid low common keys in module aliases so they don't get huge. */ -#define KEY_MIN_INTERESTING KEY_MUTE -#define KEY_MAX 0x2ff -#define KEY_CNT (KEY_MAX+1) - -/* - * Relative axes - */ - -#define REL_X 0x00 -#define REL_Y 0x01 -#define REL_Z 0x02 -#define REL_RX 0x03 -#define REL_RY 0x04 -#define REL_RZ 0x05 -#define REL_HWHEEL 0x06 -#define REL_DIAL 0x07 -#define REL_WHEEL 0x08 -#define REL_MISC 0x09 -#define REL_MAX 0x0f -#define REL_CNT (REL_MAX+1) - -/* - * Absolute axes - */ - -#define ABS_X 0x00 -#define ABS_Y 0x01 -#define ABS_Z 0x02 -#define ABS_RX 0x03 -#define ABS_RY 0x04 -#define ABS_RZ 0x05 -#define ABS_THROTTLE 0x06 -#define ABS_RUDDER 0x07 -#define ABS_WHEEL 0x08 -#define ABS_GAS 0x09 -#define ABS_BRAKE 0x0a -#define ABS_HAT0X 0x10 -#define ABS_HAT0Y 0x11 -#define ABS_HAT1X 0x12 -#define ABS_HAT1Y 0x13 -#define ABS_HAT2X 0x14 -#define ABS_HAT2Y 0x15 -#define ABS_HAT3X 0x16 -#define ABS_HAT3Y 0x17 -#define ABS_PRESSURE 0x18 -#define ABS_DISTANCE 0x19 -#define ABS_TILT_X 0x1a -#define ABS_TILT_Y 0x1b -#define ABS_TOOL_WIDTH 0x1c - -#define ABS_VOLUME 0x20 - -#define ABS_MISC 0x28 - -#define ABS_MT_SLOT 0x2f /* MT slot being modified */ -#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ -#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ -#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ -#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ -#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ -#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ -#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ -#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ -#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ -#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ -#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ -#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ -#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ -#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ - - -#define ABS_MAX 0x3f -#define ABS_CNT (ABS_MAX+1) - -/* - * Switch events - */ - -#define SW_LID 0x00 /* set = lid shut */ -#define SW_TABLET_MODE 0x01 /* set = tablet mode */ -#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ -#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" - set = radio enabled */ -#define SW_RADIO SW_RFKILL_ALL /* deprecated */ -#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ -#define SW_DOCK 0x05 /* set = plugged into dock */ -#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ -#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ -#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ -#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ -#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ -#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ -#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ -#define SW_LINEIN_INSERT 0x0d /* set = inserted */ -#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ -#define SW_MAX 0x0f -#define SW_CNT (SW_MAX+1) - -/* - * Misc events - */ - -#define MSC_SERIAL 0x00 -#define MSC_PULSELED 0x01 -#define MSC_GESTURE 0x02 -#define MSC_RAW 0x03 -#define MSC_SCAN 0x04 -#define MSC_TIMESTAMP 0x05 -#define MSC_MAX 0x07 -#define MSC_CNT (MSC_MAX+1) - -/* - * LEDs - */ - -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -#define LED_CNT (LED_MAX+1) - -/* - * Autorepeat values + * This ioctl allows user to retrieve the current event mask for specific + * event type. The argument must be of type "struct input_mask" and + * specifies the event type to query, the address of the receive buffer and + * the size of the receive buffer. + * + * The event mask is a per-client mask that specifies which events are + * forwarded to the client. Each event code is represented by a single bit + * in the event mask. If the bit is set, the event is passed to the client + * normally. Otherwise, the event is filtered and will never be queued on + * the client's receive buffer. + * + * Event masks do not affect global state of the input device. They only + * affect the file descriptor they are applied to. + * + * The default event mask for a client has all bits set, i.e. all events + * are forwarded to the client. If the kernel is queried for an unknown + * event type or if the receive buffer is larger than the number of + * event codes known to the kernel, the kernel returns all zeroes for those + * codes. + * + * At maximum, codes_size bytes are copied. + * + * This ioctl may fail with ENODEV in case the file is revoked, EFAULT + * if the receive-buffer points to invalid memory, or EINVAL if the kernel + * does not implement the ioctl. */ +#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */ -#define REP_DELAY 0x00 -#define REP_PERIOD 0x01 -#define REP_MAX 0x01 -#define REP_CNT (REP_MAX+1) - -/* - * Sounds +/** + * EVIOCSMASK - Set event mask + * + * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the + * current event mask, this changes the client's event mask for a specific + * type. See EVIOCGMASK for a description of event-masks and the + * argument-type. + * + * This ioctl provides full forward compatibility. If the passed event type + * is unknown to the kernel, or if the number of event codes specified in + * the mask is bigger than what is known to the kernel, the ioctl is still + * accepted and applied. However, any unknown codes are left untouched and + * stay cleared. That means, the kernel always filters unknown codes + * regardless of what the client requests. If the new mask doesn't cover + * all known event-codes, all remaining codes are automatically cleared and + * thus filtered. + * + * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is + * returned if the receive-buffer points to invalid memory. EINVAL is returned + * if the kernel does not implement the ioctl. */ +#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */ -#define SND_CLICK 0x00 -#define SND_BELL 0x01 -#define SND_TONE 0x02 -#define SND_MAX 0x07 -#define SND_CNT (SND_MAX+1) +#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ /* * IDs. @@ -1200,6 +474,14 @@ struct ff_effect { #define FF_GAIN 0x60 #define FF_AUTOCENTER 0x61 +/* + * ff->playback(effect_id = FF_GAIN) is the first effect_id to + * cause a collision with another ff method, in this case ff->set_gain(). + * Therefore the greatest safe value for effect_id is FF_GAIN - 1, + * and thus the total number of effects should never exceed FF_GAIN. + */ +#define FF_MAX_EFFECTS FF_GAIN + #define FF_MAX 0x7f #define FF_CNT (FF_MAX+1) diff --git a/include/uapi/linux/userio.h b/include/uapi/linux/userio.h new file mode 100644 index 000000000000..37d147f0a13a --- /dev/null +++ b/include/uapi/linux/userio.h @@ -0,0 +1,44 @@ +/* + * userio: virtual serio device support + * Copyright (C) 2015 Red Hat + * Copyright (C) 2015 Lyude (Stephen Chandler Paul) <cpaul@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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 Lesser General Public License for more + * details. + * + * This is the public header used for user-space communication with the userio + * driver. __attribute__((__packed__)) is used for all structs to keep ABI + * compatibility between all architectures. + */ + +#ifndef _USERIO_H +#define _USERIO_H + +#include <linux/types.h> + +enum userio_cmd_type { + USERIO_CMD_REGISTER = 0, + USERIO_CMD_SET_PORT_TYPE = 1, + USERIO_CMD_SEND_INTERRUPT = 2 +}; + +/* + * userio Commands + * All commands sent to /dev/userio are encoded using this structure. The type + * field should contain a USERIO_CMD* value that indicates what kind of command + * is being sent to userio. The data field should contain the accompanying + * argument for the command, if there is one. + */ +struct userio_cmd { + __u8 type; + __u8 data; +} __attribute__((__packed__)); + +#endif /* !_USERIO_H */ |