]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'input-current/for-linus'
authorStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 22:59:41 +0000 (09:59 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 22:59:41 +0000 (09:59 +1100)
66 files changed:
Documentation/devicetree/bindings/input/da9062-onkey.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/gpio-keys-polled.txt
Documentation/devicetree/bindings/input/rotary-encoder.txt
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/input/rotary-encoder.txt
Documentation/input/userio.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/boot/dts/am437x-sk-evm.dts
arch/arm/boot/dts/imx28-tx28.dts
arch/arm/boot/dts/imx53-tx53-x03x.dts
arch/arm/boot/dts/imx6qdl-tx6.dtsi
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-gfrm.c [new file with mode: 0644]
drivers/input/evdev.c
drivers/input/ff-core.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/db9.c
drivers/input/joystick/gamecon.c
drivers/input/joystick/turbografx.c
drivers/input/joystick/walkera0701.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/snvs_pwrkey.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/Kconfig
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/ad714x.c
drivers/input/misc/ad714x.h
drivers/input/misc/da9063_onkey.c
drivers/input/misc/hp_sdc_rtc.c
drivers/input/misc/kxtj9.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/xen-kbdfront.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/parkbd.c
drivers/input/serio/userio.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/cyttsp4_i2c.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/ft6236.c [new file with mode: 0644]
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/rohm_bu21023.c [new file with mode: 0644]
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/zforce_ts.c
include/dt-bindings/input/input.h
include/dt-bindings/input/linux-event-codes.h [new symlink]
include/linux/input.h
include/linux/input/edt-ft5x06.h [deleted file]
include/linux/miscdevice.h
include/linux/rotary_encoder.h
include/uapi/linux/Kbuild
include/uapi/linux/input-event-codes.h [new file with mode: 0644]
include/uapi/linux/input.h
include/uapi/linux/userio.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/input/da9062-onkey.txt b/Documentation/devicetree/bindings/input/da9062-onkey.txt
new file mode 100644 (file)
index 0000000..ab0e048
--- /dev/null
@@ -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;
+               };
+
+       };
index 5b91f5a3bd5c6aee02353423c3cdb8f56bd7bd22..97e2467181e94a608cb0e04846fb891b67a5d490 100644 (file)
@@ -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.
index 331549593ed5e031ec696cad610f3347763574b7..de99cbbbf6da074fee825423636a0ca164364ee7 100644 (file)
@@ -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.
 
index 76db96704a602e823fc6d09a04ddfd000a5949a7..f99528da1b1d4d7f354441d7c11e7dc2abe3c9ad 100644 (file)
@@ -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 (file)
index 0000000..777521d
--- /dev/null
@@ -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;
+       };
index 82d2ac97af74b2a8e5569576cf92f15f1236c036..3222b2ff475e9cc64425debe6db6e1fc20ae3ba5 100644 (file)
@@ -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.
index 5737e3590adb6a338d6165332fa1eff93a07d57e..46a74f0c551a1b5a1ada3dc7e3ae248df1edbbff 100644 (file)
@@ -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 (file)
index 0000000..0880c0f
--- /dev/null
@@ -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
index a17f58cb65b79ad2bcd2668ae384a8da5b85f770..cadf310dfa6da506a28b9d0c28fbba3e6b857746 100644 (file)
@@ -11175,6 +11175,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
index 7da7c2da4af13b3bc711f15a9098c10da80d56fa..0bb36e9af93623e6f3a6e4ee96ae64ce8c215e53 100644 (file)
 
                reg = <0x38>;
                interrupt-parent = <&gpio0>;
-               interrupts = <31 0>;
+               interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
 
                reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
 
index a5b27c85a91c8b14464feabd30d2af7ec03b9d8c..4ea89344a5fff51115160fad9e34b16a4a4377eb 100644 (file)
@@ -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";
                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>;
        };
index 3b73e81dc3f0df58507a7a6a3ae0556f9abee7dd..13e842b0c7857b1050c73319842113d6bf08dbb3 100644 (file)
@@ -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>
 
 / {
                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>;
        };
index da08de324e9eb595db45c7cae308327d77bd33a9..13cb7ccfea44dd653e8100669d415b88699c7831 100644 (file)
@@ -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>
 
 / {
                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;
index 6ab51ae3c39d5753f5315fd7451db737a311a24e..7245b7f8767ff36a7df4596de8fea0ffb75c28a5 100644 (file)
@@ -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
index e6441bc7dae42b9c415a00e25d61d977af475866..571d176d22dfd739373b41dbd62c9df4b256fa77 100644 (file)
@@ -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-gfrm.c b/drivers/hid/hid-gfrm.c
new file mode 100644 (file)
index 0000000..4d7b7e7
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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 void 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);
+}
+
+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");
index 08d496411f7570bf73368cdfc32b01ed98c59da8..e9ae3d500a55e368ed4f1a0b1702e7fbdec0935a 100644 (file)
@@ -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;
index c642082671987f98963ff7b07758a678aaffc480..8f2042432c85151b25fab1e885fe321e1563d641 100644 (file)
@@ -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 */
index 5391abd28b2799c6776cf1bc8a398f70ed8382d7..880605959aa6f74a87da70b24f813d2ce428af9f 100644 (file)
@@ -2044,6 +2044,23 @@ static void devm_input_device_unregister(struct device *dev, void *res)
        __input_unregister_device(input);
 }
 
+/**
+ * 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;
index 6cb5a3e5f9a106321aa73de1a4d4265df1022575..5d11fea3c8eccd10dbd892d4898d4b0ecca3aacd 100644 (file)
@@ -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) {
index 8e7de5c7754ffa98ef0fb869e7668b00b9a32be4..932d07307454bd47441da61ff06e3ef03ea93cd4 100644 (file)
@@ -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);
index e68e497864830f63a9dfa72ee7d5a4948bfb733a..5a672dcac0d8174a151254ac31b591f0189f9d91 100644 (file)
@@ -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);
index 891797ad76bccda3ae132e1fc59483b539e522ee..9f5bca26bd2fb85a90ed4fd91bbdcf1a83e84162 100644 (file)
@@ -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);
index a8bc2fe170dd83e12ff78706f97f9bc32a72e5cd..d88f5dd3c9d9e9a7080cbd9bacecb740e0791488 100644 (file)
@@ -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);
index f8850f9cb33103ccfef4d696389f2b6ddad1249d..fd4100d56d8c5509986be23e40d2af137cd840b1 100644 (file)
@@ -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);
index 2e80107ff630384739ec23d497e9d14321be25c5..ddd8148d51d70cf5994c53190110ae9c35adadfb 100644 (file)
@@ -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
index 9d517ca7eb5aad432249d34ed8a710588510bd21..bef317ff7352ffd73885ea6a11efd58efba9663d 100644 (file)
@@ -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);
index 870cfa6e2c44ed6791782401bb098096c4d052f4..62bdb1d48c49dbd990ce37f2da335ee8d60b472d 100644 (file)
@@ -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;
 }
 
index c7d5b1666fc33ba1418c35d6673b171fca8eaacf..8567ee47761e111b31f7c8270bdc6414de6668a1 100644 (file)
@@ -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
index 78fd24ca3813d988d0bc21a70469e4ed7aa6f53d..9adf13a5864adaa94052b3a01d408658e4150123 100644 (file)
@@ -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;
index f97c73bd14f8f6427534ebee8e8b502f7b527299..acc5394afb0343a62a4502f24251898d216daf09 100644 (file)
@@ -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;
index 906dd1b25e41b7efc0aa12f70e37bb977fa61c76..d6d16fa782815481e04609771b09b32e862ce679 100644 (file)
@@ -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.
index 189bdc8e91a5d2d116cda4d429ca8474eb071c26..2f047738bc0bd85f1ff21459a0b9709fa6a422b9 100644 (file)
@@ -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,
 };
 
index a79e50b58bf5d3f2c0b3f12d7eb3d62b527686a4..c8170f0829624a111f1d8a3a68ad1abe6d6b7445 100644 (file)
@@ -101,15 +101,6 @@ 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",
@@ -117,7 +108,6 @@ static struct spi_driver ad714x_spi_driver = {
                .pm     = &ad714x_spi_pm,
        },
        .probe          = ad714x_spi_probe,
-       .remove         = ad714x_spi_remove,
 };
 
 module_spi_driver(ad714x_spi_driver);
index 7a61e9ee682cff92c7b445c8fbc660f31286088b..84b51dd51f6e9147396d43bc002833e670d24764 100644 (file)
@@ -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)
 {
index 3c85455aa66d23329d3605fb367d400d320e4976..5d65d303b9bfa9d41f936ffd6908fe4f6f38ce8d 100644 (file)
@@ -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
index f577585ef999af29425531b9cc75fe494f1c62ba..8eb697db82d03606839e0002c5232513cfb80477 100644 (file)
@@ -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
 #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);
index 45e0e3e55de28dfdbdfb347ebdba74ca2e698544..1c8c56efc995d3cfa0dc5392934beeeb2150734e 100644 (file)
@@ -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,
index e058d711256a203c97f8018824cba877fbdc0f05..efaffcc57e36cb58050a009830b5953bd08cb744 100644 (file)
@@ -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);
index f27f81ee84edef53a4ed90ff150a7d096a43b2f7..8aee7198643001eb9252877b327569e4111744af 100644 (file)
@@ -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),
        }
 };
index 23d0549539d43904299c51810730f5d34955d952..0a9ad2cfb55c7fb53e39ef84e366668f5c531094 100644 (file)
@@ -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();
index 200841b77edb85b22caf110f4693443957354915..c3d05b4d3118d908434eb594659a97e0b4703b05 100644 (file)
@@ -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
index c600089b7a349f2c05a624d27b5bbaeb646c9c45..2374ef9b33d788cee5693bb52905aabcd965df61 100644 (file)
@@ -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
index 1e8cd6f1fe9e875005af95b54787890f81116a5f..74bb17270255439c6354f983676fdac121410c01 100644 (file)
@@ -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 (file)
index 0000000..df1fd41
--- /dev/null
@@ -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");
index deb14c12ae8b19a84c5ba8e0074f4bac43260ecc..80cc69897a4331105801ff3eca9339819727e3c8 100644 (file)
@@ -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
index 1b79cc09744af93b02ecabe958c24fc47bd189f3..17435c7e97e3bcbf421ce1135e9c64bec05f2c6a 100644 (file)
@@ -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
index 04edc8f7122fa77d9c043694ba8f47d0c83dab0c..6c676e41fe3c3b418223497e62cfb33e0dee0637 100644 (file)
@@ -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,
index 38c06f754acd69abeb45ff3fbba766c9e01a09d6..6592fc5d48b489ee5cc6c7ea2fe797c7e19683b4 100644 (file)
@@ -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)
index a9f95c7d3c0066cbd257b80755efdbe683340dbf..564e49002d5d61ae5632ac830a4bb0f3f05c32e2 100644 (file)
@@ -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)
index 48de1e8b3c93578cf4c1faf88c220c008a75569c..0b0f8c17f3f7e0f4df1e69144d693b46741f4025 100644 (file)
@@ -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>
 #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 (file)
index 0000000..d240d2e
--- /dev/null
@@ -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");
index 91621725bfb519b58cff540281822c635ed2948e..4b961ad9f0b51cb905e25c8f272b16378078d5c5 100644 (file)
@@ -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 (file)
index 0000000..ba6024f
--- /dev/null
@@ -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.");
index 4ffd829d1990a2d0e66d8c7fdf0fa2151f6c0504..a340bfccdfb6697fb033dca488f310559ba91fd6 100644 (file)
@@ -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)
index 781d0f83050ab005ef4917188f2df0e3995aad72..9bbadaaf6bc3723f044a9c44e8619773d242ec8f 100644 (file)
@@ -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)
index 042e7b3b629637d468029cadac9e9419f7ae295e..a21413324a3f7bbb55a0f2e002d10f7b2211a7e5 100644 (file)
@@ -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 (symlink)
index 0000000..693bbcd
--- /dev/null
@@ -0,0 +1 @@
+../../uapi/linux/input-event-codes.h
\ No newline at end of file
index 82ce323b998692b9c3d0b95b762605e51147cafd..1e967694e9a525deb811a03608ebecc91cabaab3 100644 (file)
@@ -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 (file)
index 8a1e0d1..0000000
+++ /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 */
index 81f6e427ba6bbb9b65f52a5d5937c39aee0c0125..5430374659734ae74ea27e8fb28a126976482b26 100644 (file)
@@ -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;
index 3f594dce571650c76253a785e8720490a7c0f80e..fe3dc64e5aebf95b88508644ba83a14bffa451ee 100644 (file)
@@ -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__ */
index 70d89230b6416c6e59858d6936695adf71770e85..628e6e64c2fb4ff2c858a57e0beeca3aa4fd49b6 100644 (file)
@@ -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 (file)
index 0000000..87cf351
--- /dev/null
@@ -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
index 731417c025f6feff03ea257b46abde05c7a06b7d..2758687300b474dab6d87234ea79ed4ab926ac93 100644 (file)
@@ -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 (file)
index 0000000..37d147f
--- /dev/null
@@ -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 */