Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 1/1 FROM FIXED] Revert "HID: fix unit exponent parsing"
From: Nikolai Kondrashov @ 2013-10-09 19:04 UTC (permalink / raw)
  To: Benjamin Tissoires; +Cc: Jiri Kosina, linux-input
In-Reply-To: <5255A391.6040501@gmail.com>

On 10/09/2013 09:42 PM, Nikolai Kondrashov wrote:
>> I would say that the current approach (without the revert) is exactly this:
>> - if the data is stored on only 1 byte ( if (!(raw_value&
>> 0xfffffff0))), do the two's complement -> any value less than 7 will
>> be the same, above are considered as negative.
>> - if not, then use the raw value.
>
> It is not exactly what I suggested. It also considers anything above 15 to be
> a normal integer. However, it might be a cleaner way.
>
> All-in-all, I'd say that the relevant hid-core.c code should have its comment
> fixed, and the hid-input.c (hidinput_calc_abs_res) change needs to be reverted
> as it (incorrectly) takes the component unit power into account for resolution
> calculation and makes the "unit" item value handling harder to comprehend.

On a second glance at the test data, hid-core.c needs to be fixed as well, as
for the non-nibble case it loses the sign by reading the item value as
unsigned. So a perfectly valid 1 byte 0xFD value becomes 253, instead of -3.

I'll include that into the patch.

Sincerely,
Nick

^ permalink raw reply

* Re: [PATCH 1/1 FROM FIXED] Revert "HID: fix unit exponent parsing"
From: Nikolai Kondrashov @ 2013-10-09 21:13 UTC (permalink / raw)
  To: Benjamin Tissoires; +Cc: Jiri Kosina, linux-input
In-Reply-To: <5255A391.6040501@gmail.com>

On 10/09/2013 09:42 PM, Nikolai Kondrashov wrote:
>> So definitely, Microsoft considers that the unit exponent is a 4 bits
>> two's complement, otherwise, the firmware will not get a Windows 8
>> certification.
>
> I think this is due to their use of the "HID Descriptor Tool". Maybe
> assuming it is a reference implementation, which it is not, but more likely
> just not noticing the discrepancy.
>
> I'll try to reach Microsoft on this and maybe make them correct their
> specification.

I've started my attempts with a post on Microsoft's official hardware
development forums:

http://social.msdn.microsoft.com/Forums/windowshardware/en-US/e87d0db1-486e-42ae-bf95-d1ac5ffc0b02/unit-exponent-item-value-encoding-in-hid-report-descriptors?forum=whck

Let's see how it goes.

Sincerely,
Nick

^ permalink raw reply

* [PATCH 1/2] Input: twl4030_keypad - add device tree support
From: Sebastian Reichel @ 2013-10-09 21:17 UTC (permalink / raw)
  To: Sebastian Reichel, linux-input
  Cc: 'Benoît Cousson', Tony Lindgren, Rob Herring,
	Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
	Rob Landley, Russell King, Dmitry Torokhov, Grant Likely,
	devicetree, linux-doc, linux-kernel, linux-arm-kernel, linux-omap,
	Sebastian Reichel

Add device tree support for twl4030 keypad driver and update the
Documentation with twl4030 keypad device tree binding information.

This patch also adds a twl4030 keypad node to the twl4030.dtsi file,
so that board files can just add the keymap.

Tested on Nokia N900.

Signed-off-by: Sebastian Reichel <sre@debian.org>
---
 .../devicetree/bindings/input/twl4030-keypad.txt   | 31 ++++++++
 arch/arm/boot/dts/twl4030.dtsi                     |  7 ++
 drivers/input/keyboard/twl4030_keypad.c            | 91 ++++++++++++++++++----
 3 files changed, 112 insertions(+), 17 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/twl4030-keypad.txt

diff --git a/Documentation/devicetree/bindings/input/twl4030-keypad.txt b/Documentation/devicetree/bindings/input/twl4030-keypad.txt
new file mode 100644
index 0000000..2b4bd7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/twl4030-keypad.txt
@@ -0,0 +1,31 @@
+* TWL4030's Keypad Controller device tree bindings
+
+TWL4030's Keypad controller is used to interface a SoC with a matrix-type
+keypad device. The keypad controller supports multiple row and column lines.
+A key can be placed at each intersection of a unique row and a unique column.
+The keypad controller can sense a key-press and key-release and report the
+event using a interrupt to the cpu.
+
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+ * keypad,num-rows and keypad,num-columns are required.
+
+Required SoC Specific Properties:
+- compatible: should be one of the following
+   - "ti,twl4030-keypad": For controllers compatible with twl4030 keypad
+      controller.
+- interrupt: should be one of the following
+   - <1>: For controllers compatible with twl4030 keypad controller.
+
+Optional Properties specific to linux:
+- linux,keypad-no-autorepeat: do no enable autorepeat feature.
+
+Example:
+	twl_keypad: keypad {
+		compatible = "ti,twl4030-keypad";
+		interrupts = <1>;
+		keypad,num-rows = <8>;
+		keypad,num-columns = <8>;
+		linux,keypad-no-autorepeat;
+	};
diff --git a/arch/arm/boot/dts/twl4030.dtsi b/arch/arm/boot/dts/twl4030.dtsi
index ae6a17a..773c94c 100644
--- a/arch/arm/boot/dts/twl4030.dtsi
+++ b/arch/arm/boot/dts/twl4030.dtsi
@@ -97,4 +97,11 @@
 		compatible = "ti,twl4030-pwmled";
 		#pwm-cells = <2>;
 	};
+
+	twl_keypad: keypad {
+		compatible = "ti,twl4030-keypad";
+		interrupts = <1>;
+		keypad,num-rows = <8>;
+		keypad,num-columns = <8>;
+	};
 };
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index d2d178c..3cd8090 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -33,6 +33,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c/twl.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 /*
  * The TWL4030 family chips include a keypad controller that supports
@@ -60,6 +61,7 @@
 struct twl4030_keypad {
 	unsigned short	keymap[TWL4030_KEYMAP_SIZE];
 	u16		kp_state[TWL4030_MAX_ROWS];
+	bool		no_autorepeat;
 	unsigned	n_rows;
 	unsigned	n_cols;
 	unsigned	irq;
@@ -324,6 +326,31 @@ static int twl4030_kp_program(struct twl4030_keypad *kp)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static int twl4030_keypad_parse_dt(struct device *dev,
+				 struct twl4030_keypad *keypad_data)
+{
+	struct device_node *np = dev->of_node;
+	int err;
+
+	err = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
+					    &keypad_data->n_cols);
+	if (err)
+		return err;
+
+	if (of_get_property(np, "linux,input-no-autorepeat", NULL))
+		keypad_data->no_autorepeat = true;
+
+	return 0;
+}
+#else
+static inline int twl4030_keypad_parse_dt(struct device *dev,
+					struct twl4030_keypad *keypad_data)
+{
+	return -ENOSYS;
+}
+#endif
+
 /*
  * Registers keypad device with input subsystem
  * and configures TWL4030 keypad registers
@@ -331,20 +358,12 @@ static int twl4030_kp_program(struct twl4030_keypad *kp)
 static int twl4030_kp_probe(struct platform_device *pdev)
 {
 	struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
-	const struct matrix_keymap_data *keymap_data;
+	const struct matrix_keymap_data *keymap_data = NULL;
 	struct twl4030_keypad *kp;
 	struct input_dev *input;
 	u8 reg;
 	int error;
 
-	if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data ||
-	    pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) {
-		dev_err(&pdev->dev, "Invalid platform_data\n");
-		return -EINVAL;
-	}
-
-	keymap_data = pdata->keymap_data;
-
 	kp = kzalloc(sizeof(*kp), GFP_KERNEL);
 	input = input_allocate_device();
 	if (!kp || !input) {
@@ -352,13 +371,9 @@ static int twl4030_kp_probe(struct platform_device *pdev)
 		goto err1;
 	}
 
-	/* Get the debug Device */
-	kp->dbg_dev = &pdev->dev;
-	kp->input = input;
-
-	kp->n_rows = pdata->rows;
-	kp->n_cols = pdata->cols;
-	kp->irq = platform_get_irq(pdev, 0);
+	/* get the debug device */
+	kp->dbg_dev		= &pdev->dev;
+	kp->input		= input;
 
 	/* setup input device */
 	input->name		= "TWL4030 Keypad";
@@ -370,6 +385,36 @@ static int twl4030_kp_probe(struct platform_device *pdev)
 	input->id.product	= 0x0001;
 	input->id.version	= 0x0003;
 
+	if (pdata) {
+		if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
+			dev_err(&pdev->dev, "Missing platform_data\n");
+			error = -EINVAL;
+			goto err1;
+		}
+
+		kp->n_rows = pdata->rows;
+		kp->n_cols = pdata->cols;
+		kp->no_autorepeat = !pdata->rep;
+		keymap_data = pdata->keymap_data;
+	} else {
+		error = twl4030_keypad_parse_dt(&pdev->dev, kp);
+		if (error)
+			goto err1;
+	}
+
+	if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) {
+		dev_err(&pdev->dev, "Invalid rows/cols amount specified in platform/devicetree data\n");
+		error = -EINVAL;
+		goto err1;
+	}
+
+	kp->irq = platform_get_irq(pdev, 0);
+	if (!kp->irq) {
+		dev_err(&pdev->dev, "no keyboard irq assigned\n");
+		error = -EINVAL;
+		goto err1;
+	}
+
 	error = matrix_keypad_build_keymap(keymap_data, NULL,
 					   TWL4030_MAX_ROWS,
 					   1 << TWL4030_ROW_SHIFT,
@@ -381,7 +426,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
 
 	input_set_capability(input, EV_MSC, MSC_SCAN);
 	/* Enable auto repeat feature of Linux input subsystem */
-	if (pdata->rep)
+	if (!kp->no_autorepeat)
 		__set_bit(EV_REP, input->evbit);
 
 	error = input_register_device(input);
@@ -443,6 +488,17 @@ static int twl4030_kp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_keypad_dt_match_table[] = {
+	{ .compatible = "ti,twl4030-keypad" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, twl4030_keypad_dt_match_table);
+#define twl4030_keypad_dt_match of_match_ptr(twl4030_keypad_dt_match_table)
+#else
+#define twl4030_keypad_dt_match NULL
+#endif
+
 /*
  * NOTE: twl4030 are multi-function devices connected via I2C.
  * So this device is a child of an I2C parent, thus it needs to
@@ -455,6 +511,7 @@ static struct platform_driver twl4030_kp_driver = {
 	.driver		= {
 		.name	= "twl4030_keypad",
 		.owner	= THIS_MODULE,
+		.of_match_table = twl4030_keypad_dt_match,
 	},
 };
 module_platform_driver(twl4030_kp_driver);
-- 
1.8.4.rc3


^ permalink raw reply related

* [PATCH 2/2] ARM: dts: N900: TWL4030 Keypad Matrix definition
From: Sebastian Reichel @ 2013-10-09 21:17 UTC (permalink / raw)
  To: Sebastian Reichel, linux-input
  Cc: 'Benoît Cousson', Tony Lindgren, Rob Herring,
	Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
	Rob Landley, Russell King, Dmitry Torokhov, Grant Likely,
	devicetree, linux-doc, linux-kernel, linux-arm-kernel, linux-omap,
	Sebastian Reichel
In-Reply-To: <1381353447-32708-1-git-send-email-sre@debian.org>

Add Keyboard Matrix information to N900's DTS file.
This patch maps the keys exactly as the original
board code.

Signed-off-by: Sebastian Reichel <sre@debian.org>
---
 arch/arm/boot/dts/omap3-n900.dts | 55 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 0fbb77e..d11ff6e 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -120,6 +120,61 @@
 #include "twl4030.dtsi"
 #include "twl4030_omap3.dtsi"
 
+&twl_keypad {
+	linux,keymap = < 0x00000010 /* KEY_Q */
+			 0x00010018 /* KEY_O */
+			 0x00020019 /* KEY_P */
+			 0x00030033 /* KEY_COMMA */
+			 0x0004000e /* KEY_BACKSPACE */
+			 0x0006001e /* KEY_A */
+			 0x0007001f /* KEY_S */
+
+			 0x01000011 /* KEY_W */
+			 0x01010020 /* KEY_D */
+			 0x01020021 /* KEY_F */
+			 0x01030022 /* KEY_G */
+			 0x01040023 /* KEY_H */
+			 0x01050024 /* KEY_J */
+			 0x01060025 /* KEY_K */
+			 0x01070026 /* KEY_L */
+
+			 0x02000012 /* KEY_E */
+			 0x02010034 /* KEY_DOT */
+			 0x02020067 /* KEY_UP */
+			 0x0203001c /* KEY_ENTER */
+			 0x0205002c /* KEY_Z */
+			 0x0206002d /* KEY_X */
+			 0x0207002e /* KEY_C */
+			 0x02080043 /* KEY_F9 */
+
+			 0x03000013 /* KEY_R */
+			 0x0301002f /* KEY_V */
+			 0x03020030 /* KEY_B */
+			 0x03030031 /* KEY_N */
+			 0x03040032 /* KEY_M */
+			 0x03050039 /* KEY_SPACE */
+			 0x03060039 /* KEY_SPACE */
+			 0x03070069 /* KEY_LEFT */
+
+			 0x04000014 /* KEY_T */
+			 0x0401006c /* KEY_DOWN */
+			 0x0402006a /* KEY_RIGHT */
+			 0x0404001d /* KEY_LEFTCTRL */
+			 0x04050064 /* KEY_RIGHTALT */
+			 0x0406002a /* KEY_LEFTSHIFT */
+			 0x04080044 /* KEY_F10 */
+
+			 0x05000015 /* KEY_Y */
+			 0x05080057 /* KEY_F11 */
+
+			 0x06000016 /* KEY_U */
+
+			 0x07000017 /* KEY_I */
+			 0x07010041 /* KEY_F7 */
+			 0x07020042 /* KEY_F8 */
+			 >;
+};
+
 &twl_gpio {
 	ti,pullups	= <0x0>;
 	ti,pulldowns	= <0x03ff3f>; /* BIT(0..5) | BIT(8..17) */
-- 
1.8.4.rc3

^ permalink raw reply related

* [PATCH 1/3] HID:hid-lg: Fixed ReportDescriptor for Logitech Formular Vibration to split Accel/Brake into seperate axis
From: Simon Wood @ 2013-10-10  0:04 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý

Requires https://patchwork.kernel.org/patch/2998241/

Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/hid-lg.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c2c7dab..c6efdae 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -45,6 +45,7 @@
 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
 #define DF_RDESC_ORIG_SIZE	130
 #define DFP_RDESC_ORIG_SIZE	97
+#define FV_RDESC_ORIG_SIZE	130
 #define MOMO_RDESC_ORIG_SIZE	87
 
 /* Fixed report descriptors for Logitech Driving Force (and Pro)
@@ -170,6 +171,73 @@ static __u8 dfp_rdesc_fixed[] = {
 0xC0                /*  End Collection                          */
 };
 
+static __u8 fv_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop),                   */
+0x09, 0x04,         /*  Usage (Joystik),                        */
+0xA1, 0x01,         /*  Collection (Application),               */
+0xA1, 0x02,         /*      Collection (Logical),               */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x0A,         /*          Report Size (10),               */
+0x15, 0x00,         /*          Logical Minimum (0),            */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
+0x35, 0x00,         /*          Physical Minimum (0),           */
+0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
+0x09, 0x30,         /*          Usage (X),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0x95, 0x0C,         /*          Report Count (12),              */
+0x75, 0x01,         /*          Report Size (1),                */
+0x25, 0x01,         /*          Logical Maximum (1),            */
+0x45, 0x01,         /*          Physical Maximum (1),           */
+0x05, 0x09,         /*          Usage Page (Button),            */
+0x19, 0x01,         /*          Usage Minimum (01h),            */
+0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
+0x81, 0x02,         /*          Input (Variable),               */
+0x95, 0x02,         /*          Report Count (2),               */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
+0x09, 0x01,         /*          Usage (01h),                    */
+0x81, 0x02,         /*          Input (Variable),               */
+0x09, 0x02,         /*          Usage (02h),                    */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x81, 0x02,         /*          Input (Variable),               */
+0x05, 0x01,         /*          Usage Page (Desktop),           */
+0x25, 0x07,         /*          Logical Maximum (7),            */
+0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
+0x75, 0x04,         /*          Report Size (4),                */
+0x65, 0x14,         /*          Unit (Degrees),                 */
+0x09, 0x39,         /*          Usage (Hat Switch),             */
+0x81, 0x42,         /*          Input (Variable, Null State),   */
+0x75, 0x01,         /*          Report Size (1),                */
+0x95, 0x04,         /*          Report Count (4),               */
+0x65, 0x00,         /*          Unit,                           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
+0x09, 0x01,         /*          Usage (01h),                    */
+0x25, 0x01,         /*          Logical Maximum (1),            */
+0x45, 0x01,         /*          Physical Maximum (1),           */
+0x81, 0x02,         /*          Input (Variable),               */
+0x05, 0x01,         /*          Usage Page (Desktop),           */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x09, 0x31,         /*          Usage (Y),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0x09, 0x32,         /*          Usage (Z),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0xC0,               /*      End Collection,                     */
+0xA1, 0x02,         /*      Collection (Logical),               */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x95, 0x07,         /*          Report Count (7),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x09, 0x03,         /*          Usage (03h),                    */
+0x91, 0x02,         /*          Output (Variable),              */
+0xC0,               /*      End Collection,                     */
+0xC0                /*  End Collection                          */
+};
+
 static __u8 momo_rdesc_fixed[] = {
 0x05, 0x01,         /*  Usage Page (Desktop),               */
 0x09, 0x04,         /*  Usage (Joystik),                    */
@@ -275,6 +343,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		}
 		break;
 
+	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
+		if (*rsize == FV_RDESC_ORIG_SIZE) {
+			hid_info(hdev,
+				"fixing up Logitech Formula Vibration report descriptor\n");
+			rdesc = fv_rdesc_fixed;
+			*rsize = sizeof(fv_rdesc_fixed);
+		}
+		break;
+
 	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 		if (*rsize == DFP_RDESC_ORIG_SIZE) {
 			hid_info(hdev,
-- 
1.8.1.2


^ permalink raw reply related

* [PATCH 2/3] HID:hid-lg: Fixed Report Descriptor for Logitech MOMO Force (Black) to split Accel/Brake into seperate axis
From: Simon Wood @ 2013-10-10  0:04 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý
In-Reply-To: <1381363487-2167-1-git-send-email-simon@mungewell.org>


Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/hid-lg.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c6efdae..545da44 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -47,6 +47,7 @@
 #define DFP_RDESC_ORIG_SIZE	97
 #define FV_RDESC_ORIG_SIZE	130
 #define MOMO_RDESC_ORIG_SIZE	87
+#define MOMO2_RDESC_ORIG_SIZE	87
 
 /* Fixed report descriptors for Logitech Driving Force (and Pro)
  * wheel controllers
@@ -284,6 +285,54 @@ static __u8 momo_rdesc_fixed[] = {
 0xC0                /*  End Collection                      */
 };
 
+static __u8 momo2_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop),               */
+0x09, 0x04,         /*  Usage (Joystik),                    */
+0xA1, 0x01,         /*  Collection (Application),           */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x75, 0x0A,         /*          Report Size (10),           */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x35, 0x00,         /*          Physical Minimum (0),       */
+0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
+0x09, 0x30,         /*          Usage (X),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x95, 0x0A,         /*          Report Count (10),          */
+0x75, 0x01,         /*          Report Size (1),            */
+0x25, 0x01,         /*          Logical Maximum (1),        */
+0x45, 0x01,         /*          Physical Maximum (1),       */
+0x05, 0x09,         /*          Usage Page (Button),        */
+0x19, 0x01,         /*          Usage Minimum (01h),        */
+0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
+0x81, 0x02,         /*          Input (Variable),           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x00,         /*          Usage (00h),                */
+0x95, 0x04,         /*          Report Count (4),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x75, 0x08,         /*          Report Size (8),            */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
+0x09, 0x01,         /*          Usage (01h),                */
+0x81, 0x02,         /*          Input (Variable),           */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x31,         /*          Usage (Y),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x32,         /*          Usage (Z),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x00,         /*          Usage (00h),                */
+0x81, 0x02,         /*          Input (Variable),           */
+0xC0,               /*      End Collection,                 */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x09, 0x02,         /*          Usage (02h),                */
+0x95, 0x07,         /*          Report Count (7),           */
+0x91, 0x02,         /*          Output (Variable),          */
+0xC0,               /*      End Collection,                 */
+0xC0                /*  End Collection                      */
+};
+
 /*
  * Certain Logitech keyboards send in report #3 keys which are far
  * above the logical maximum described in descriptor. This extends
@@ -343,6 +392,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		}
 		break;
 
+	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
+		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
+			hid_info(hdev,
+				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
+			rdesc = momo2_rdesc_fixed;
+			*rsize = sizeof(momo2_rdesc_fixed);
+		}
+		break;
+
 	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 		if (*rsize == FV_RDESC_ORIG_SIZE) {
 			hid_info(hdev,
-- 
1.8.1.2


^ permalink raw reply related

* [PATCH 3/3] HID:Kconfig: Correct MOMO description in wrong place (handled by LG4FF).
From: Simon Wood @ 2013-10-10  0:04 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý
In-Reply-To: <1381363487-2167-1-git-send-email-simon@mungewell.org>


Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/Kconfig | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 46fd27f..aee7182 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -362,7 +362,6 @@ config LOGITECH_FF
 	  - Logitech WingMan Force 3D
 	  - Logitech Formula Force EX
 	  - Logitech WingMan Formula Force GP
-	  - Logitech MOMO Force wheel
 
 	  and if you want to enable force feedback for them.
 	  Note: if you say N here, this device will still be supported, but without
-- 
1.8.1.2


^ permalink raw reply related

* Re: [PATCH 2/3] HID:hid-lg: Fixed Report Descriptor for Logitech MOMO Force (Black) to split Accel/Brake into seperate axis
From: Jiri Kosina @ 2013-10-10  8:02 UTC (permalink / raw)
  To: Simon Wood
  Cc: linux-input, linux-kernel, Elias Vanderstuyft, Michal Malý
In-Reply-To: <1381363487-2167-2-git-send-email-simon@mungewell.org>

On Wed, 9 Oct 2013, Simon Wood wrote:

> 
> Signed-off-by: Simon Wood <simon@mungewell.org>

Simon,

thanks for the series. I however very much dislike commits without a 
single line of changelog ... could you please resend the series with a few 
sentences as a patch description (i.e. what, why, how).

Thanks a lot.

> ---
>  drivers/hid/hid-lg.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
> index c6efdae..545da44 100644
> --- a/drivers/hid/hid-lg.c
> +++ b/drivers/hid/hid-lg.c
> @@ -47,6 +47,7 @@
>  #define DFP_RDESC_ORIG_SIZE	97
>  #define FV_RDESC_ORIG_SIZE	130
>  #define MOMO_RDESC_ORIG_SIZE	87
> +#define MOMO2_RDESC_ORIG_SIZE	87
>  
>  /* Fixed report descriptors for Logitech Driving Force (and Pro)
>   * wheel controllers
> @@ -284,6 +285,54 @@ static __u8 momo_rdesc_fixed[] = {
>  0xC0                /*  End Collection                      */
>  };
>  
> +static __u8 momo2_rdesc_fixed[] = {
> +0x05, 0x01,         /*  Usage Page (Desktop),               */
> +0x09, 0x04,         /*  Usage (Joystik),                    */
> +0xA1, 0x01,         /*  Collection (Application),           */
> +0xA1, 0x02,         /*      Collection (Logical),           */
> +0x95, 0x01,         /*          Report Count (1),           */
> +0x75, 0x0A,         /*          Report Size (10),           */
> +0x15, 0x00,         /*          Logical Minimum (0),        */
> +0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
> +0x35, 0x00,         /*          Physical Minimum (0),       */
> +0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
> +0x09, 0x30,         /*          Usage (X),                  */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x95, 0x0A,         /*          Report Count (10),          */
> +0x75, 0x01,         /*          Report Size (1),            */
> +0x25, 0x01,         /*          Logical Maximum (1),        */
> +0x45, 0x01,         /*          Physical Maximum (1),       */
> +0x05, 0x09,         /*          Usage Page (Button),        */
> +0x19, 0x01,         /*          Usage Minimum (01h),        */
> +0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
> +0x09, 0x00,         /*          Usage (00h),                */
> +0x95, 0x04,         /*          Report Count (4),           */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x95, 0x01,         /*          Report Count (1),           */
> +0x75, 0x08,         /*          Report Size (8),            */
> +0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
> +0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
> +0x09, 0x01,         /*          Usage (01h),                */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x05, 0x01,         /*          Usage Page (Desktop),       */
> +0x09, 0x31,         /*          Usage (Y),                  */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x09, 0x32,         /*          Usage (Z),                  */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
> +0x09, 0x00,         /*          Usage (00h),                */
> +0x81, 0x02,         /*          Input (Variable),           */
> +0xC0,               /*      End Collection,                 */
> +0xA1, 0x02,         /*      Collection (Logical),           */
> +0x09, 0x02,         /*          Usage (02h),                */
> +0x95, 0x07,         /*          Report Count (7),           */
> +0x91, 0x02,         /*          Output (Variable),          */
> +0xC0,               /*      End Collection,                 */
> +0xC0                /*  End Collection                      */
> +};
> +
>  /*
>   * Certain Logitech keyboards send in report #3 keys which are far
>   * above the logical maximum described in descriptor. This extends
> @@ -343,6 +392,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
>  		}
>  		break;
>  
> +	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
> +		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
> +			hid_info(hdev,
> +				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
> +			rdesc = momo2_rdesc_fixed;
> +			*rsize = sizeof(momo2_rdesc_fixed);
> +		}
> +		break;
> +
>  	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
>  		if (*rsize == FV_RDESC_ORIG_SIZE) {
>  			hid_info(hdev,
> -- 
> 1.8.1.2
> 

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH 1/1] HID: wiimote: invert Y-Axis and add automatic calibration for Wii U Pro Controller
From: David Herrmann @ 2013-10-10  9:16 UTC (permalink / raw)
  To: Rafael Brune; +Cc: open list:HID CORE LAYER
In-Reply-To: <1381085096-4511-1-git-send-email-mail@rbrune.de>

Hi

On Sun, Oct 6, 2013 at 8:44 PM, Rafael Brune <mail@rbrune.de> wrote:
> With these changes the Wii U Pro Controller fully complies
> to the gamepad-API and with the calibration is fully usable
> out-of-the-box without any user-space tools. This potentially
> breaks compatibility with software that relies on the two
> inverted Y-Axis but since current bluez 4.x and 5.x versions
> don't even support pairing with the controller yet the amount
> of people affected should be rather small.

Did anyone try to read the calibration values from the EEPROM? Doing
calibration in the kernel is fine, but I'd rather have the
hardware-calibration values instead. Even if we cannot figure it out
now, we should try to stay as compatible to the real values as we can.

So how about keeping the min/max and neutral point as we have it know
and instead adjusting the reported values by scaling/moving them?

> Signed-off-by: Rafael Brune <mail@rbrune.de>
> ---
>  drivers/hid/hid-wiimote-modules.c | 45 +++++++++++++++++++++++++++++++++++----
>  1 file changed, 41 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
> index 2e7d644..1422b0b 100644
> --- a/drivers/hid/hid-wiimote-modules.c
> +++ b/drivers/hid/hid-wiimote-modules.c
> @@ -1640,10 +1640,41 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
>         ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
>         ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
>
> -       input_report_abs(wdata->extension.input, ABS_X, lx - 0x800);
> -       input_report_abs(wdata->extension.input, ABS_Y, ly - 0x800);
> -       input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800);
> -       input_report_abs(wdata->extension.input, ABS_RY, ry - 0x800);
> +       /* Calibrating the sticks by saving the global min/max per axis */
> +       if (lx < wdata->state.calib_bboard[0][0])
> +               wdata->state.calib_bboard[0][0] = lx;
> +       if (lx > wdata->state.calib_bboard[0][1])
> +               wdata->state.calib_bboard[0][1] = lx;
> +
> +       if (ly < wdata->state.calib_bboard[1][0])
> +               wdata->state.calib_bboard[1][0] = ly;
> +       if (ly > wdata->state.calib_bboard[1][1])
> +               wdata->state.calib_bboard[1][1] = ly;
> +
> +       if (rx < wdata->state.calib_bboard[2][0])
> +               wdata->state.calib_bboard[2][0] = rx;
> +       if (rx > wdata->state.calib_bboard[2][1])
> +               wdata->state.calib_bboard[2][1] = rx;
> +
> +       if (ry < wdata->state.calib_bboard[3][0])
> +               wdata->state.calib_bboard[3][0] = ry;
> +       if (ry > wdata->state.calib_bboard[3][1])
> +               wdata->state.calib_bboard[3][1] = ry;
> +
> +       /* Normalize using int math to prevent conversion to/from float */
> +       lx = -2048 + (((__s32)(lx - wdata->state.calib_bboard[0][0]) * 4096)/
> +          (wdata->state.calib_bboard[0][1]-wdata->state.calib_bboard[0][0]));
> +       ly = -2048 + (((__s32)(ly - wdata->state.calib_bboard[1][0]) * 4096)/
> +          (wdata->state.calib_bboard[1][1]-wdata->state.calib_bboard[1][0]));
> +       rx = -2048 + (((__s32)(rx - wdata->state.calib_bboard[2][0]) * 4096)/
> +          (wdata->state.calib_bboard[2][1]-wdata->state.calib_bboard[2][0]));
> +       ry = -2048 + (((__s32)(ry - wdata->state.calib_bboard[3][0]) * 4096)/
> +          (wdata->state.calib_bboard[3][1]-wdata->state.calib_bboard[3][0]));

Don't use calib_bboard. Add a new array (or use a union). This is confusing.

> +
> +       input_report_abs(wdata->extension.input, ABS_X,  lx);
> +       input_report_abs(wdata->extension.input, ABS_Y, -ly);
> +       input_report_abs(wdata->extension.input, ABS_RX,  rx);
> +       input_report_abs(wdata->extension.input, ABS_RY, -ry);
>
>         input_report_key(wdata->extension.input,
>                          wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
> @@ -1760,6 +1791,12 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
>         if (!wdata->extension.input)
>                 return -ENOMEM;
>
> +       /* Initialize min/max values for all Axis with reasonable values */
> +       for (i = 0; i < 4; ++i) {
> +               wdata->state.calib_bboard[i][0] = 0x780;
> +               wdata->state.calib_bboard[i][1] = 0x880;

Ugh, these values look weird. We have a reported range of -0x400 to
+0x400 but you limit it to a virtual range of 0x100. That's a loss of
precision of 80%. Where are these values from?

> +       }
> +
>         set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
>         input_set_drvdata(wdata->extension.input, wdata);

Thanks for hacking this up. Could you give me some values from your
device so I can see how big the deviation is? My device reports:

Range: 0-4095 (0x0fff)
Neutral-Point: 2048 (0x800)

I haven't seen any big deviations from these values. I can try to take
this over if you want, just let me know.

Thanks
David

^ permalink raw reply

* Re: Q: weird hidraw behaviour
From: David Herrmann @ 2013-10-10  9:26 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: Jiri Kosina, Manoj Chourasia, open list:HID CORE LAYER
In-Reply-To: <20130924085606.GI28875@intel.com>

Hi

On Tue, Sep 24, 2013 at 10:56 AM, Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> Hi,
>
> I noticed that after commit 212a871a393 (HID: hidraw: correctly deallocate
> memory on device disconnect) hidraw doesn't close the underlying hid device
> when the device node is closed last time.
>
> For example I have a touch panel (HID over I2C) device with added debug
> prints in i2c_hid_open()/i2c_hid_close():
>
>         # od -x /dev/hidraw0
>         [   41.363813] i2c_hid 1-004c: i2c_hid_power lvl:32
>         [   41.368464] i2c_hid 1-004c: i2c_hid_set_power
>         [   41.372831] i2c_hid 1-004c: __i2c_hid_command: cmd=54 01 00 08
>         [   41.451455] i2c_hid 1-004c: i2c_hid_open
>         ^C
>
>         # od -x /dev/hidraw0
>         [   58.420928] i2c_hid 1-004c: i2c_hid_power lvl:32
>         [   58.425577] i2c_hid 1-004c: i2c_hid_set_power
>         [   58.429945] i2c_hid 1-004c: __i2c_hid_command: cmd=54 01 00 08
>         [   58.525276] i2c_hid 1-004c: i2c_hid_open
>         ^C
>
> i2c_hid_close() is never called. Is this intended or am I missing
> something?

I don't know whether it's intentional, but it is hardcoded this way
now. Logic is, ->close() is called on hidraw_disconnect() that is,
when hidraw is unloaded on a device. It no longer depends on
user-space processes.

Any reason to change it back? It's no bug, so if no-one cares I'd
leave it as it is now. Otherwise, we can try to change it again.

Regards
David

^ permalink raw reply

* Re: Q: weird hidraw behaviour
From: Mika Westerberg @ 2013-10-10  9:39 UTC (permalink / raw)
  To: David Herrmann; +Cc: Jiri Kosina, Manoj Chourasia, open list:HID CORE LAYER
In-Reply-To: <CANq1E4TxGS4NSc3BOon2+zVwkvY2LQTmQowHxOJnypf860+-jw@mail.gmail.com>

On Thu, Oct 10, 2013 at 11:26:45AM +0200, David Herrmann wrote:
> Hi
> 
> On Tue, Sep 24, 2013 at 10:56 AM, Mika Westerberg
> <mika.westerberg@linux.intel.com> wrote:
> > Hi,
> >
> > I noticed that after commit 212a871a393 (HID: hidraw: correctly deallocate
> > memory on device disconnect) hidraw doesn't close the underlying hid device
> > when the device node is closed last time.
> >
> > For example I have a touch panel (HID over I2C) device with added debug
> > prints in i2c_hid_open()/i2c_hid_close():
> >
> >         # od -x /dev/hidraw0
> >         [   41.363813] i2c_hid 1-004c: i2c_hid_power lvl:32
> >         [   41.368464] i2c_hid 1-004c: i2c_hid_set_power
> >         [   41.372831] i2c_hid 1-004c: __i2c_hid_command: cmd=54 01 00 08
> >         [   41.451455] i2c_hid 1-004c: i2c_hid_open
> >         ^C
> >
> >         # od -x /dev/hidraw0
> >         [   58.420928] i2c_hid 1-004c: i2c_hid_power lvl:32
> >         [   58.425577] i2c_hid 1-004c: i2c_hid_set_power
> >         [   58.429945] i2c_hid 1-004c: __i2c_hid_command: cmd=54 01 00 08
> >         [   58.525276] i2c_hid 1-004c: i2c_hid_open
> >         ^C
> >
> > i2c_hid_close() is never called. Is this intended or am I missing
> > something?
> 
> I don't know whether it's intentional, but it is hardcoded this way
> now. Logic is, ->close() is called on hidraw_disconnect() that is,
> when hidraw is unloaded on a device. It no longer depends on
> user-space processes.
> 
> Any reason to change it back? It's no bug, so if no-one cares I'd
> leave it as it is now. Otherwise, we can try to change it again.

Well, if you open the device and close it from userspace, the device stays
opened forever. I'm not sure if that's the intention.

I think that fix for this was already merged.

^ permalink raw reply

* Re: Q: weird hidraw behaviour
From: David Herrmann @ 2013-10-10  9:41 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: Jiri Kosina, Manoj Chourasia, open list:HID CORE LAYER
In-Reply-To: <20131010093939.GH3521@intel.com>

Hi

On Thu, Oct 10, 2013 at 11:39 AM, Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> On Thu, Oct 10, 2013 at 11:26:45AM +0200, David Herrmann wrote:
>> I don't know whether it's intentional, but it is hardcoded this way
>> now. Logic is, ->close() is called on hidraw_disconnect() that is,
>> when hidraw is unloaded on a device. It no longer depends on
>> user-space processes.
>>
>> Any reason to change it back? It's no bug, so if no-one cares I'd
>> leave it as it is now. Otherwise, we can try to change it again.
>
> Well, if you open the device and close it from userspace, the device stays
> opened forever. I'm not sure if that's the intention.
>
> I think that fix for this was already merged.

Indeed, fixed upstream in:
http://git.kernel.org/cgit/linux/kernel/git/jikos/hid.git/commit/?h=for-3.12/upstream-fixes&id=0f5a24c6602063e014ee48892ebf56093241106e

Thanks
David

^ permalink raw reply

* Re: [PATCH v2 2/2] input: rotary-encoder: Add 'on-each-step' to binding documentation
From: Ezequiel García @ 2013-10-10 13:55 UTC (permalink / raw)
  To: linux-input, devicetree
  Cc: Mark Rutland, linux-kernel@vger.kernel.org, Daniel Mack,
	Dmitry Torokhov, rob.herring@calxeda.com
In-Reply-To: <20131004140925.GA27809@localhost>

On 4 October 2013 11:09, Ezequiel Garcia
<ezequiel.garcia@free-electrons.com> wrote:
> On Fri, Oct 04, 2013 at 02:19:56PM +0100, Mark Rutland wrote:
>> On Fri, Oct 04, 2013 at 01:53:23PM +0100, Ezequiel Garcia wrote:
>> > The driver now supports a new mode to handle the interruptions generated
>> > by the device: on this new mode an input event is generated on each step
>> > (i.e. on each IRQ). Therefore, add a new DT property, to select the
>> > mode: 'rotary-encoder,on-each-step'.
>> >
>> > Cc: Daniel Mack <zonque@gmail.com>
>> > Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> > Cc: Rob Herring <rob.herring@calxeda.com>
>> > Cc: devicetree@vger.kernel.org
>> > Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
>> > ---
>> > I'm not at all happy with this DT binding as it's way to customized
>> > for the current driver. For instance, if we want to support mapping
>> > key events (or better arbitrary linux-input event types) it seems
>> > there's no easy way to fix the binding.
>> >
>> > Maybe a better way of handling the different 'modes' is through
>> > compatible strings?
>>
>> I'd prefer not to have more pseudo-devices in DT, and would prefer not
>> to have compatible strings that boil down to driver options. We end up
>> just embedding a tonne of Linux-specific driver configuration in the DT
>> rather than describing hardware.
>>
>> That said, I'm not sure what the best solution is here.
>>
>> >
>> > I'm not really sure, so I hope the DT guys have some comment on this.
>> >
>> >  Documentation/devicetree/bindings/input/rotary-encoder.txt | 1 +
>> >  1 file changed, 1 insertion(+)
>> >
>> > diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt
>> > index 3315495..b89e38d 100644
>> > --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt
>> > +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt
>> > @@ -15,6 +15,7 @@ Optional properties:
>> >  - 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,half-period: Makes the driver work on half-period mode.
>> > +- rotary-encoder,on-each-step: Makes the driver send an event on each step.
>>
>> Could this not be something requested at runtime?
>>
>
> Sure. The different modes:
>
> * default (no option)
> * rotary-encoder,half-period
> * rotary-encoder,on-each-step
>
> Just map to different interruption handlers. I don't have any other
> rotary-encoder device, so I'm not at all sure what's the use of the
> other two cases.
> My particular device is detented, and produces a 'stable' event on each
> step (i.e on each IRQ).
>
> Regarding the runtime specification: you mean as a module parameter?
> That should be trivial to add, no?
>
>> Could you explain what you want to achieve with this? -- what events do
>> you want to occur when, to be handled in what way?
>>
>
> Hm.. maybe I should have added the binding to the 1/2 patch and CCed
> everybody involved for better context.
>
> Anyway, I hope the above is clearer, I'm not really sure how to specify
> the details in the DT binding, since it's a specific interruption handler
> for this class of encoder devices (stable on each step).
>
> That said, I really hope I'm crafting a generic solution and not some
> tailor-made implementation that just happens to match my use case.
>
> The input maintainer's opinion on this would be valuable.

Any insights on this binding?

If nobody objects, then I'd like to get this change accepted,
together with the driver change.

Thanks!
-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCHv2 2/3] HID:hid-lg: Fixed Report Descriptor for Logitech MOMO Force (Black) to split Accel/Brake into seperate axis
From: Simon Wood @ 2013-10-10 14:20 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý
In-Reply-To: <1381414814-2107-1-git-send-email-simon@mungewell.org>

By default the Logitech MOMO Force (Black) presents a combined accel/brake
axis ('Y'). This patch modifies the HID descriptor to present seperate 
accel/brake axes ('Y' and 'Z').

Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/hid-lg.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c6efdae..545da44 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -47,6 +47,7 @@
 #define DFP_RDESC_ORIG_SIZE	97
 #define FV_RDESC_ORIG_SIZE	130
 #define MOMO_RDESC_ORIG_SIZE	87
+#define MOMO2_RDESC_ORIG_SIZE	87
 
 /* Fixed report descriptors for Logitech Driving Force (and Pro)
  * wheel controllers
@@ -284,6 +285,54 @@ static __u8 momo_rdesc_fixed[] = {
 0xC0                /*  End Collection                      */
 };
 
+static __u8 momo2_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop),               */
+0x09, 0x04,         /*  Usage (Joystik),                    */
+0xA1, 0x01,         /*  Collection (Application),           */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x75, 0x0A,         /*          Report Size (10),           */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x35, 0x00,         /*          Physical Minimum (0),       */
+0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
+0x09, 0x30,         /*          Usage (X),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x95, 0x0A,         /*          Report Count (10),          */
+0x75, 0x01,         /*          Report Size (1),            */
+0x25, 0x01,         /*          Logical Maximum (1),        */
+0x45, 0x01,         /*          Physical Maximum (1),       */
+0x05, 0x09,         /*          Usage Page (Button),        */
+0x19, 0x01,         /*          Usage Minimum (01h),        */
+0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
+0x81, 0x02,         /*          Input (Variable),           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x00,         /*          Usage (00h),                */
+0x95, 0x04,         /*          Report Count (4),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x75, 0x08,         /*          Report Size (8),            */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
+0x09, 0x01,         /*          Usage (01h),                */
+0x81, 0x02,         /*          Input (Variable),           */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x31,         /*          Usage (Y),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x32,         /*          Usage (Z),                  */
+0x81, 0x02,         /*          Input (Variable),           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x00,         /*          Usage (00h),                */
+0x81, 0x02,         /*          Input (Variable),           */
+0xC0,               /*      End Collection,                 */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x09, 0x02,         /*          Usage (02h),                */
+0x95, 0x07,         /*          Report Count (7),           */
+0x91, 0x02,         /*          Output (Variable),          */
+0xC0,               /*      End Collection,                 */
+0xC0                /*  End Collection                      */
+};
+
 /*
  * Certain Logitech keyboards send in report #3 keys which are far
  * above the logical maximum described in descriptor. This extends
@@ -343,6 +392,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		}
 		break;
 
+	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
+		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
+			hid_info(hdev,
+				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
+			rdesc = momo2_rdesc_fixed;
+			*rsize = sizeof(momo2_rdesc_fixed);
+		}
+		break;
+
 	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 		if (*rsize == FV_RDESC_ORIG_SIZE) {
 			hid_info(hdev,
-- 
1.8.1.2

^ permalink raw reply related

* [PATCHv2 1/3] HID:hid-lg: Fixed ReportDescriptor for Logitech Formula Vibration to split Accel/Brake into seperate axis
From: Simon Wood @ 2013-10-10 14:20 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý
In-Reply-To: <alpine.LNX.2.00.1310101002120.13289@pobox.suse.cz>

Requires https://patchwork.kernel.org/patch/2998241/

By default the Logitech Formula Vibration presents a combined accel/brake
axis ('Y'). This patch modifies the HID descriptor to present seperate    
accel/brake axes ('Y' and 'Z').

Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/hid-lg.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c2c7dab..c6efdae 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -45,6 +45,7 @@
 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
 #define DF_RDESC_ORIG_SIZE	130
 #define DFP_RDESC_ORIG_SIZE	97
+#define FV_RDESC_ORIG_SIZE	130
 #define MOMO_RDESC_ORIG_SIZE	87
 
 /* Fixed report descriptors for Logitech Driving Force (and Pro)
@@ -170,6 +171,73 @@ static __u8 dfp_rdesc_fixed[] = {
 0xC0                /*  End Collection                          */
 };
 
+static __u8 fv_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop),                   */
+0x09, 0x04,         /*  Usage (Joystik),                        */
+0xA1, 0x01,         /*  Collection (Application),               */
+0xA1, 0x02,         /*      Collection (Logical),               */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x0A,         /*          Report Size (10),               */
+0x15, 0x00,         /*          Logical Minimum (0),            */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
+0x35, 0x00,         /*          Physical Minimum (0),           */
+0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
+0x09, 0x30,         /*          Usage (X),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0x95, 0x0C,         /*          Report Count (12),              */
+0x75, 0x01,         /*          Report Size (1),                */
+0x25, 0x01,         /*          Logical Maximum (1),            */
+0x45, 0x01,         /*          Physical Maximum (1),           */
+0x05, 0x09,         /*          Usage Page (Button),            */
+0x19, 0x01,         /*          Usage Minimum (01h),            */
+0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
+0x81, 0x02,         /*          Input (Variable),               */
+0x95, 0x02,         /*          Report Count (2),               */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
+0x09, 0x01,         /*          Usage (01h),                    */
+0x81, 0x02,         /*          Input (Variable),               */
+0x09, 0x02,         /*          Usage (02h),                    */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x81, 0x02,         /*          Input (Variable),               */
+0x05, 0x01,         /*          Usage Page (Desktop),           */
+0x25, 0x07,         /*          Logical Maximum (7),            */
+0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
+0x75, 0x04,         /*          Report Size (4),                */
+0x65, 0x14,         /*          Unit (Degrees),                 */
+0x09, 0x39,         /*          Usage (Hat Switch),             */
+0x81, 0x42,         /*          Input (Variable, Null State),   */
+0x75, 0x01,         /*          Report Size (1),                */
+0x95, 0x04,         /*          Report Count (4),               */
+0x65, 0x00,         /*          Unit,                           */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
+0x09, 0x01,         /*          Usage (01h),                    */
+0x25, 0x01,         /*          Logical Maximum (1),            */
+0x45, 0x01,         /*          Physical Maximum (1),           */
+0x81, 0x02,         /*          Input (Variable),               */
+0x05, 0x01,         /*          Usage Page (Desktop),           */
+0x95, 0x01,         /*          Report Count (1),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x09, 0x31,         /*          Usage (Y),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0x09, 0x32,         /*          Usage (Z),                      */
+0x81, 0x02,         /*          Input (Variable),               */
+0xC0,               /*      End Collection,                     */
+0xA1, 0x02,         /*      Collection (Logical),               */
+0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
+0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
+0x95, 0x07,         /*          Report Count (7),               */
+0x75, 0x08,         /*          Report Size (8),                */
+0x09, 0x03,         /*          Usage (03h),                    */
+0x91, 0x02,         /*          Output (Variable),              */
+0xC0,               /*      End Collection,                     */
+0xC0                /*  End Collection                          */
+};
+
 static __u8 momo_rdesc_fixed[] = {
 0x05, 0x01,         /*  Usage Page (Desktop),               */
 0x09, 0x04,         /*  Usage (Joystik),                    */
@@ -275,6 +343,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		}
 		break;
 
+	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
+		if (*rsize == FV_RDESC_ORIG_SIZE) {
+			hid_info(hdev,
+				"fixing up Logitech Formula Vibration report descriptor\n");
+			rdesc = fv_rdesc_fixed;
+			*rsize = sizeof(fv_rdesc_fixed);
+		}
+		break;
+
 	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 		if (*rsize == DFP_RDESC_ORIG_SIZE) {
 			hid_info(hdev,
-- 
1.8.1.2


^ permalink raw reply related

* [PATCHv2 3/3] HID:Kconfig: Correct MOMO description in wrong place (handled by LG4FF).
From: Simon Wood @ 2013-10-10 14:20 UTC (permalink / raw)
  To: linux-input
  Cc: Jiri Kosina, linux-kernel, simon, Elias Vanderstuyft,
	Michal Malý
In-Reply-To: <1381414814-2107-1-git-send-email-simon@mungewell.org>

Minor correction to the description in Kconfig.

The Logitect MOMO wheel is actually handled by the LOGITECH_WHEELS (hid-lg4ff) 
section, not by the LOGITECH_FF (hid-lgff).

Signed-off-by: Simon Wood <simon@mungewell.org>
---
 drivers/hid/Kconfig | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 46fd27f..aee7182 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -362,7 +362,6 @@ config LOGITECH_FF
 	  - Logitech WingMan Force 3D
 	  - Logitech Formula Force EX
 	  - Logitech WingMan Formula Force GP
-	  - Logitech MOMO Force wheel
 
 	  and if you want to enable force feedback for them.
 	  Note: if you say N here, this device will still be supported, but without
-- 
1.8.1.2


^ permalink raw reply related

* Re: [PATCH 1/1] HID: wiimote: invert Y-Axis and add automatic calibration for Wii U Pro Controller
From: Rafael Brune @ 2013-10-10 15:46 UTC (permalink / raw)
  To: David Herrmann; +Cc: open list:HID CORE LAYER
In-Reply-To: <CANq1E4ToCfOCe9Fe0iDdJGJv_D4rOT6gB5g=7neTaHj9_esiLA@mail.gmail.com>

Hi

On Oct 10, 2013, at 11:16 AM, David Herrmann wrote:

> Hi
> 
> On Sun, Oct 6, 2013 at 8:44 PM, Rafael Brune <mail@rbrune.de> wrote:
>> With these changes the Wii U Pro Controller fully complies
>> to the gamepad-API and with the calibration is fully usable
>> out-of-the-box without any user-space tools. This potentially
>> breaks compatibility with software that relies on the two
>> inverted Y-Axis but since current bluez 4.x and 5.x versions
>> don't even support pairing with the controller yet the amount
>> of people affected should be rather small.
> 
> Did anyone try to read the calibration values from the EEPROM? Doing
> calibration in the kernel is fine, but I'd rather have the
> hardware-calibration values instead. Even if we cannot figure it out
> now, we should try to stay as compatible to the real values as we can.
> 
> So how about keeping the min/max and neutral point as we have it know
> and instead adjusting the reported values by scaling/moving them?
> 

After googling a little bit it seems like their might actually be no
calibration data for the Classic Controller and Wii U Pro Controller. The
midpoint is supposedly just detected when the device connects.
http://wiibrew.org/wiki/Classic_Controller

My code did not change what we output as the min/max/mid values it's
still -0x800,0x000,0x800. As you suggest it scales/moves the raw values
so that the reported values fall into that range.


>> Signed-off-by: Rafael Brune <mail@rbrune.de>
>> ---
>> drivers/hid/hid-wiimote-modules.c | 45 +++++++++++++++++++++++++++++++++++----
>> 1 file changed, 41 insertions(+), 4 deletions(-)
>> 
>> diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
>> index 2e7d644..1422b0b 100644
>> --- a/drivers/hid/hid-wiimote-modules.c
>> +++ b/drivers/hid/hid-wiimote-modules.c
>> @@ -1640,10 +1640,41 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
>>        ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
>>        ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
>> 
>> -       input_report_abs(wdata->extension.input, ABS_X, lx - 0x800);
>> -       input_report_abs(wdata->extension.input, ABS_Y, ly - 0x800);
>> -       input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800);
>> -       input_report_abs(wdata->extension.input, ABS_RY, ry - 0x800);
>> +       /* Calibrating the sticks by saving the global min/max per axis */
>> +       if (lx < wdata->state.calib_bboard[0][0])
>> +               wdata->state.calib_bboard[0][0] = lx;
>> +       if (lx > wdata->state.calib_bboard[0][1])
>> +               wdata->state.calib_bboard[0][1] = lx;
>> +
>> +       if (ly < wdata->state.calib_bboard[1][0])
>> +               wdata->state.calib_bboard[1][0] = ly;
>> +       if (ly > wdata->state.calib_bboard[1][1])
>> +               wdata->state.calib_bboard[1][1] = ly;
>> +
>> +       if (rx < wdata->state.calib_bboard[2][0])
>> +               wdata->state.calib_bboard[2][0] = rx;
>> +       if (rx > wdata->state.calib_bboard[2][1])
>> +               wdata->state.calib_bboard[2][1] = rx;
>> +
>> +       if (ry < wdata->state.calib_bboard[3][0])
>> +               wdata->state.calib_bboard[3][0] = ry;
>> +       if (ry > wdata->state.calib_bboard[3][1])
>> +               wdata->state.calib_bboard[3][1] = ry;
>> +
>> +       /* Normalize using int math to prevent conversion to/from float */
>> +       lx = -2048 + (((__s32)(lx - wdata->state.calib_bboard[0][0]) * 4096)/
>> +          (wdata->state.calib_bboard[0][1]-wdata->state.calib_bboard[0][0]));
>> +       ly = -2048 + (((__s32)(ly - wdata->state.calib_bboard[1][0]) * 4096)/
>> +          (wdata->state.calib_bboard[1][1]-wdata->state.calib_bboard[1][0]));
>> +       rx = -2048 + (((__s32)(rx - wdata->state.calib_bboard[2][0]) * 4096)/
>> +          (wdata->state.calib_bboard[2][1]-wdata->state.calib_bboard[2][0]));
>> +       ry = -2048 + (((__s32)(ry - wdata->state.calib_bboard[3][0]) * 4096)/
>> +          (wdata->state.calib_bboard[3][1]-wdata->state.calib_bboard[3][0]));
> 
> Don't use calib_bboard. Add a new array (or use a union). This is confusing.

I agree, will do that.


>> +
>> +       input_report_abs(wdata->extension.input, ABS_X,  lx);
>> +       input_report_abs(wdata->extension.input, ABS_Y, -ly);
>> +       input_report_abs(wdata->extension.input, ABS_RX,  rx);
>> +       input_report_abs(wdata->extension.input, ABS_RY, -ry);
>> 
>>        input_report_key(wdata->extension.input,
>>                         wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
>> @@ -1760,6 +1791,12 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
>>        if (!wdata->extension.input)
>>                return -ENOMEM;
>> 
>> +       /* Initialize min/max values for all Axis with reasonable values */
>> +       for (i = 0; i < 4; ++i) {
>> +               wdata->state.calib_bboard[i][0] = 0x780;
>> +               wdata->state.calib_bboard[i][1] = 0x880;
> 
> Ugh, these values look weird. We have a reported range of -0x400 to
> +0x400 but you limit it to a virtual range of 0x100. That's a loss of
> precision of 80%. Where are these values from?

I picked these values arbitrarily as starting points since they will update
during use of the gamepad as soon as lower/higher values are observed.
As soon as the sticks have been moved to their extreme positions once
everything is perfect.

We could also set those values in a similar fashion as to what Nintendo
seems to be doing. Wait for a first report of raw values, use them as the
mid point and set these min/max values as midpoint +/- ~0x800.


>> +       }
>> +
>>        set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
>>        input_set_drvdata(wdata->extension.input, wdata);
> 
> Thanks for hacking this up. Could you give me some values from your
> device so I can see how big the deviation is? My device reports:
> 
> Range: 0-4095 (0x0fff)
> Neutral-Point: 2048 (0x800)
> 
> I haven't seen any big deviations from these values. I can try to take
> this over if you want, just let me know.
> 
> Thanks
> David


When I write out the observed raw min/max values of all Axis I get these:
LX: 1033 - 3326 (center~=2179 (0x883))
LY:  857 - 3211 (center~=2034 (0x7F2))
RX: 944 - 3176 (center~=2060 (0x80C))
RY: 853 - 3159 (center~=2006 (0x7D6))

So not really the whole range of 0x0FFF is actually used and offsets due
to manufacturing differences are present.


Regards,
 Rafael






^ permalink raw reply

* [PATCH v2 1/2] Input - wacom: Not all multi-interface devices support touch
From: Ping Cheng @ 2013-10-10 21:17 UTC (permalink / raw)
  To: linux-input; +Cc: dmitry.torokhov, peter.hutterer, chris, Ping Cheng

Some multi-interface devices support expresskeys on a separate interface,
such as Bamboo; some multi-interface devices do not support touch at all,
such as Pen only Intuos5. Make sure we report the right device names.

Tested-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
 drivers/input/tablet/wacom_sys.c | 58 +++++++++++++++++++++++++---------------
 drivers/input/tablet/wacom_wac.h |  4 ++-
 2 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 63971b8..7bdb5e9 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -1188,34 +1188,47 @@ static void wacom_wireless_work(struct work_struct *work)
 		wacom_wac1->features =
 			*((struct wacom_features *)id->driver_info);
 		wacom_wac1->features.device_type = BTN_TOOL_PEN;
+		snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
+			 wacom_wac1->features.name);
 		error = wacom_register_input(wacom1);
 		if (error)
-			goto fail1;
+			goto fail;
 
 		/* Touch interface */
-		wacom_wac2->features =
-			*((struct wacom_features *)id->driver_info);
-		wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
-		wacom_wac2->features.device_type = BTN_TOOL_FINGER;
-		wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
-		error = wacom_register_input(wacom2);
-		if (error)
-			goto fail2;
+		if (wacom_wac1->features.touch_max) {
+			wacom_wac2->features =
+				*((struct wacom_features *)id->driver_info);
+			wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+			wacom_wac2->features.device_type = BTN_TOOL_FINGER;
+			wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
+			if (wacom_wac2->features.touch_max)
+				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
+					 "%s (WL) Finger",wacom_wac2->features.name);
+			else
+				snprintf(wacom_wac2->name, WACOM_NAME_MAX,
+					 "%s (WL) Pad",wacom_wac2->features.name);
+			error = wacom_register_input(wacom2);
+			if (error)
+				goto fail;
+		}
 
 		error = wacom_initialize_battery(wacom);
 		if (error)
-			goto fail3;
+			goto fail;
 	}
 
 	return;
 
-fail3:
-	input_unregister_device(wacom_wac2->input);
-	wacom_wac2->input = NULL;
-fail2:
-	input_unregister_device(wacom_wac1->input);
-	wacom_wac1->input = NULL;
-fail1:
+fail:
+	if (wacom_wac2->input) {
+		input_unregister_device(wacom_wac2->input);
+		wacom_wac2->input = NULL;
+	}
+	if (wacom_wac1->input) {
+
+		input_unregister_device(wacom_wac1->input);
+		wacom_wac1->input = NULL;
+	}
 	return;
 }
 
@@ -1332,10 +1345,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 		struct usb_device *other_dev;
 
 		/* Append the device type to the name */
-		strlcat(wacom_wac->name,
-			features->device_type == BTN_TOOL_PEN ?
-				" Pen" : " Finger",
-			sizeof(wacom_wac->name));
+		if (features->device_type == BTN_TOOL_FINGER) {
+			if (features->touch_max)
+				strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
+			else
+				strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
+		} else
+			strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
 
 		other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
 		if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 2a432e6..fd23a37 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -14,6 +14,8 @@
 /* maximum packet length for USB devices */
 #define WACOM_PKGLEN_MAX	64
 
+#define WACOM_NAME_MAX		64
+
 /* packet length for individual models */
 #define WACOM_PKGLEN_PENPRTN	 7
 #define WACOM_PKGLEN_GRAPHIRE	 8
@@ -130,7 +132,7 @@ struct wacom_shared {
 };
 
 struct wacom_wac {
-	char name[64];
+	char name[WACOM_NAME_MAX];
 	unsigned char *data;
 	int tool[2];
 	int id[2];
-- 
1.8.1.2


^ permalink raw reply related

* [PATCH v2 2/2] Input: wacom - add support for three new Intuos devices
From: Ping Cheng @ 2013-10-10 21:17 UTC (permalink / raw)
  To: linux-input; +Cc: dmitry.torokhov, peter.hutterer, chris, Ping Cheng

This series of models added a hardware switch to turn touch
data on/off. To report the state of the switch, SW_TOUCH
is added in include/uapi/linux/input.h.

The driver is also updated to process wireless devices that do
not support touch interface.

Tested-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
v2: Change SW_TOUCH_ENABLED to SW_TOUCH and clear BTN_TOUCH bit 
for button only interfaces as suggested by Peter Hutterer.
---
 drivers/input/tablet/wacom_sys.c | 16 +++++++-
 drivers/input/tablet/wacom_wac.c | 87 ++++++++++++++++++++++++++++++++--------
 drivers/input/tablet/wacom_wac.h |  7 ++++
 include/uapi/linux/input.h       |  1 +
 4 files changed, 93 insertions(+), 18 deletions(-)

diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 7bdb5e9..efd9729 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -1190,12 +1190,15 @@ static void wacom_wireless_work(struct work_struct *work)
 		wacom_wac1->features.device_type = BTN_TOOL_PEN;
 		snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
 			 wacom_wac1->features.name);
+		wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
+		wacom_wac1->shared->type = wacom_wac1->features.type;
 		error = wacom_register_input(wacom1);
 		if (error)
 			goto fail;
 
 		/* Touch interface */
-		if (wacom_wac1->features.touch_max) {
+		if (wacom_wac1->features.touch_max ||
+		    wacom_wac1->features.type == INTUOS_HT) {
 			wacom_wac2->features =
 				*((struct wacom_features *)id->driver_info);
 			wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
@@ -1210,6 +1213,10 @@ static void wacom_wireless_work(struct work_struct *work)
 			error = wacom_register_input(wacom2);
 			if (error)
 				goto fail;
+
+			if (wacom_wac1->features.type == INTUOS_HT &&
+			    wacom_wac1->features.touch_max)
+				wacom_wac->shared->touch_input = wacom_wac2->input;
 		}
 
 		error = wacom_initialize_battery(wacom);
@@ -1318,7 +1325,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 	 * HID descriptor. If this is the touch interface (wMaxPacketSize
 	 * of WACOM_PKGLEN_BBTOUCH3), override the table values.
 	 */
-	if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
+	if (features->type >= INTUOS5S && features->type <= INTUOS_HT) {
 		if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
 			features->device_type = BTN_TOOL_FINGER;
 			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
@@ -1390,6 +1397,11 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 		}
 	}
 
+	if (wacom_wac->features.type == INTUOS_HT && wacom_wac->features.touch_max) {
+		if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
+			wacom_wac->shared->touch_input = wacom_wac->input;
+	}
+
 	return 0;
 
  fail5: wacom_destroy_leds(wacom);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 9c8eded..4cbea85 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1176,10 +1176,17 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
 {
 	struct input_dev *input = wacom->input;
+	struct wacom_features *features = &wacom->features;
 
-	input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
+	if (features->type == INTUOS_HT) {
+		input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
+		input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
+	} else {
+
+		input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
+		input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
+	}
 	input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
-	input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
 	input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
 }
 
@@ -1213,13 +1220,23 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
 
 static int wacom_bpt_pen(struct wacom_wac *wacom)
 {
+	struct wacom_features *features = &wacom->features;
 	struct input_dev *input = wacom->input;
 	unsigned char *data = wacom->data;
 	int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
 
-	if (data[0] != 0x02)
+	if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_USB_MODE)
 	    return 0;
 
+	if (data[0] == WACOM_REPORT_USB_MODE) {
+		if ((features->type == INTUOS_HT) && features->touch_max) {
+			input_report_switch(wacom->shared->touch_input,
+					    SW_TOUCH, data[8] & 0x40);
+			input_sync(wacom->shared->touch_input);
+		}
+		return 0;
+	}
+
 	prox = (data[1] & 0x20) == 0x20;
 
 	/*
@@ -1297,13 +1314,20 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
 	unsigned char *data = wacom->data;
 	int connected;
 
-	if (len != WACOM_PKGLEN_WIRELESS || data[0] != 0x80)
+	if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL_MODE)
 		return 0;
 
 	connected = data[1] & 0x01;
 	if (connected) {
 		int pid, battery;
 
+		if ((wacom->shared->type == INTUOS_HT) &&
+				wacom->shared->touch_max) {
+			input_report_switch(wacom->shared->touch_input,
+					SW_TOUCH, data[5] & 0x40);
+			input_sync(wacom->shared->touch_input);
+		}
+
 		pid = get_unaligned_be16(&data[6]);
 		battery = data[5] & 0x3f;
 		if (wacom->pid != pid) {
@@ -1391,6 +1415,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 		break;
 
 	case BAMBOO_PT:
+	case INTUOS_HT:
 		sync = wacom_bpt_irq(wacom_wac, len);
 		break;
 
@@ -1459,7 +1484,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 
 	/* these device have multiple inputs */
 	if (features->type >= WIRELESS ||
-	    (features->type >= INTUOS5S && features->type <= INTUOSPL) ||
+	    (features->type >= INTUOS5S && features->type <= INTUOS_HT) ||
 	    (features->oVid && features->oPid))
 		features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
@@ -1531,7 +1556,8 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 	struct wacom_features *features = &wacom_wac->features;
 	int i;
 
-	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+			       BIT_MASK(EV_SW);
 
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(ABS_MISC, input_dev->absbit);
@@ -1771,33 +1797,48 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 		break;
 
+	case INTUOS_HT:
+		if (features->touch_max &&
+		    (features->device_type == BTN_TOOL_FINGER))
+			__set_bit(SW_TOUCH, input_dev->swbit);
+		/* fall through */
+
 	case BAMBOO_PT:
 		__clear_bit(ABS_MISC, input_dev->absbit);
 
-		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
-
 		if (features->device_type == BTN_TOOL_FINGER) {
-			unsigned int flags = INPUT_MT_POINTER;
 
 			__set_bit(BTN_LEFT, input_dev->keybit);
 			__set_bit(BTN_FORWARD, input_dev->keybit);
 			__set_bit(BTN_BACK, input_dev->keybit);
 			__set_bit(BTN_RIGHT, input_dev->keybit);
 
-			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
-				input_set_abs_params(input_dev,
+			if (features->touch_max) {
+				/* touch interface */
+				unsigned int flags = INPUT_MT_POINTER;
+
+				__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+				if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
+					input_set_abs_params(input_dev,
 						     ABS_MT_TOUCH_MAJOR,
 						     0, features->x_max, 0, 0);
-				input_set_abs_params(input_dev,
+					input_set_abs_params(input_dev,
 						     ABS_MT_TOUCH_MINOR,
 						     0, features->y_max, 0, 0);
+				} else {
+					__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+					__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+					flags = 0;
+				}
+				input_mt_init_slots(input_dev, features->touch_max, flags);
 			} else {
-				__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-				__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-				flags = 0;
+				/* buttons/keys only interface */
+				__clear_bit(ABS_X, input_dev->absbit);
+				__clear_bit(ABS_Y, input_dev->absbit);
+				__clear_bit(BTN_TOUCH, input_dev->keybit);
 			}
-			input_mt_init_slots(input_dev, features->touch_max, flags);
 		} else if (features->device_type == BTN_TOOL_PEN) {
+			__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
 			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
 			__set_bit(BTN_STYLUS, input_dev->keybit);
@@ -2194,6 +2235,17 @@ static const struct wacom_features wacom_features_0x300 =
 static const struct wacom_features wacom_features_0x301 =
 	{ "Wacom Bamboo One M",    WACOM_PKGLEN_BBPEN,    21648, 13530, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x302 =
+	{ "Wacom Intuos PT S",     WACOM_PKGLEN_BBPEN,    15200,  9500, 1023,
+	  31, INTUOS_HT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x303 =
+	{ "Wacom Intuos PT M",     WACOM_PKGLEN_BBPEN,    21600, 13500, 1023,
+	  31, INTUOS_HT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x30E =
+	{ "Wacom Intuos S",        WACOM_PKGLEN_BBPEN,    15200,  9500, 1023,
+	  31, INTUOS_HT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x6004 =
 	{ "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
 	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2329,6 +2381,9 @@ const struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0x10D) },
 	{ USB_DEVICE_WACOM(0x300) },
 	{ USB_DEVICE_WACOM(0x301) },
+	{ USB_DEVICE_WACOM(0x302) },
+	{ USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) },
+	{ USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) },
 	{ USB_DEVICE_WACOM(0x304) },
 	{ USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) },
 	{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index fd23a37..ba9e335 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -54,6 +54,8 @@
 #define WACOM_REPORT_TPCST		16
 #define WACOM_REPORT_TPC1FGE		18
 #define WACOM_REPORT_24HDT		1
+#define WACOM_REPORT_WL_MODE		128
+#define WACOM_REPORT_USB_MODE		192
 
 /* device quirks */
 #define WACOM_QUIRK_MULTI_INPUT		0x0001
@@ -81,6 +83,7 @@ enum {
 	INTUOSPS,
 	INTUOSPM,
 	INTUOSPL,
+	INTUOS_HT,
 	WACOM_21UX2,
 	WACOM_22HD,
 	DTK,
@@ -129,6 +132,10 @@ struct wacom_features {
 struct wacom_shared {
 	bool stylus_in_proximity;
 	bool touch_down;
+	/* for wireless device to access USB interfaces */
+	unsigned touch_max;
+	int type;
+	struct input_dev *touch_input;
 };
 
 struct wacom_wac {
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index d08abf9..70e53e8 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -855,6 +855,7 @@ struct input_keymap_entry {
 #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_TOUCH		0x0e  /* set = touch switch turned on (touch events off) */
 #define SW_MAX			0x0f
 #define SW_CNT			(SW_MAX+1)
 
-- 
1.8.1.2


^ permalink raw reply related

* [PATCH] Input: add regulator haptic driver
From: hyunhee.kim @ 2013-10-11  2:22 UTC (permalink / raw)
  To: dmitry.torokhov, broonie, peter.ujfalusi, wfp5p, linux-input,
	linux-kernel, akpm

From: Hyunhee Kim <hyunhee.kim@samsung.com>
Date: Wed, 9 Oct 2013 16:21:36 +0900
Subject: [PATCH] Input: add regulator haptic driver

The regulator haptic driver function can be used to control motor by on/off
regulator.
User can control the haptic driver by using force feedback framework.

Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/input/misc/Kconfig            |    6 ++
 drivers/input/misc/Makefile           |    1 +
 drivers/input/misc/regulator-haptic.c |  185
+++++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 drivers/input/misc/regulator-haptic.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index bb698e1..f391cd7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -82,6 +82,12 @@ config INPUT_ARIZONA_HAPTICS
 	  To compile this driver as a module, choose M here: the
 	  module will be called arizona-haptics.
 
+config INPUT_REGULATOR_HAPTIC
+	tristate "regulator haptics support"
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y to enable support for the haptics module for regulator.
+
 config INPUT_BMA150
 	tristate "BMA150/SMB380 acceleration sensor support"
 	depends on I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d7fc17f..106f0bc 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X_I2C)		+=
adxl34x-i2c.o
 obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
 obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)	+= arizona-haptics.o
+obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)	+= regulator-haptic.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)		+= bfin_rotary.o
diff --git a/drivers/input/misc/regulator-haptic.c
b/drivers/input/misc/regulator-haptic.c
new file mode 100644
index 0000000..29f57ea
--- /dev/null
+++ b/drivers/input/misc/regulator-haptic.c
@@ -0,0 +1,185 @@
+/*
+ * Regulator haptic driver
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Author: Hyunhee Kim <hyunhee.kim@samsung.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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+
+struct regulator_haptic {
+	struct device *dev;
+	struct input_dev *input_dev;
+	struct work_struct work;
+	bool enabled;
+	struct regulator *regulator;
+	struct mutex mutex;
+	int level;
+};
+
+static void regulator_haptic_enable(struct regulator_haptic *haptic, bool
enable)
+{
+	int ret;
+
+	mutex_lock(&haptic->mutex);
+	if (enable && !haptic->enabled) {
+		haptic->enabled = true;
+		ret = regulator_enable(haptic->regulator);
+		if (ret)
+			pr_err("haptic: %s failed to enable regulator\n",
+				__func__);
+	} else if (!enable && haptic->enabled) {
+		haptic->enabled = false;
+		ret = regulator_disable(haptic->regulator);
+		if (ret)
+			pr_err("haptic: %s failed to disable regulator\n",
+				__func__);
+	}
+	mutex_unlock(&haptic->mutex);
+}
+
+static void regulator_haptic_work(struct work_struct *work)
+{
+	struct regulator_haptic *haptic = container_of(work,
+						       struct
regulator_haptic,
+						       work);
+	if (haptic->level)
+		regulator_haptic_enable(haptic, true);
+	else
+		regulator_haptic_enable(haptic, false);
+
+}
+
+static int regulator_haptic_play(struct input_dev *input, void *data,
+				struct ff_effect *effect)
+{
+	struct regulator_haptic *haptic = input_get_drvdata(input);
+
+	haptic->level = effect->u.rumble.strong_magnitude;
+	if (!haptic->level)
+		haptic->level = effect->u.rumble.weak_magnitude;
+	schedule_work(&haptic->work);
+
+	return 0;
+}
+
+static void regulator_haptic_close(struct input_dev *input)
+{
+	struct regulator_haptic *haptic = input_get_drvdata(input);
+
+	cancel_work_sync(&haptic->work);
+	regulator_haptic_enable(haptic, false);
+}
+
+static int regulator_haptic_probe(struct platform_device *pdev)
+{
+	struct regulator_haptic *haptic;
+	struct input_dev *input_dev;
+	int error;
+
+	haptic = kzalloc(sizeof(*haptic), GFP_KERNEL);
+	if (!haptic) {
+		dev_err(&pdev->dev, "unable to allocate memory for
haptic\n");
+		return -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+
+	if (!input_dev) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		error =  -ENOMEM;
+		goto err_kfree_mem;
+	}
+
+	INIT_WORK(&haptic->work, regulator_haptic_work);
+	mutex_init(&haptic->mutex);
+	haptic->input_dev = input_dev;
+	haptic->dev = &pdev->dev;
+	haptic->regulator = regulator_get(&pdev->dev, "haptic");
+
+	if (IS_ERR(haptic->regulator)) {
+		error = PTR_ERR(haptic->regulator);
+		dev_err(&pdev->dev, "unable to get regulator, err: %d\n",
+			error);
+		goto err_ifree_mem;
+	}
+
+	haptic->input_dev->name = "regulator:haptic";
+	haptic->input_dev->dev.parent = &pdev->dev;
+	haptic->input_dev->close = regulator_haptic_close;
+	haptic->enabled = false;
+	input_set_drvdata(haptic->input_dev, haptic);
+	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(input_dev, NULL,
+				      regulator_haptic_play);
+	if (error) {
+		dev_err(&pdev->dev,
+			"input_ff_create_memless() failed: %d\n",
+			error);
+		goto err_put_regulator;
+	}
+
+	error = input_register_device(haptic->input_dev);
+	if (error) {
+		dev_err(&pdev->dev,
+			"couldn't register input device: %d\n",
+			error);
+		goto err_destroy_ff;
+	}
+
+	platform_set_drvdata(pdev, haptic);
+
+	return 0;
+
+err_destroy_ff:
+	input_ff_destroy(haptic->input_dev);
+err_put_regulator:
+	regulator_put(haptic->regulator);
+err_ifree_mem:
+	input_free_device(haptic->input_dev);
+err_kfree_mem:
+	kfree(haptic);
+
+	return error;
+}
+
+static int regulator_haptic_remove(struct platform_device *pdev)
+{
+	struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+
+	input_unregister_device(haptic->input_dev);
+
+	return 0;
+}
+
+static struct of_device_id regulator_haptic_dt_match[] = {
+	{ .compatible = "linux,regulator-haptic" },
+	{},
+};
+
+static struct platform_driver regulator_haptic_driver = {
+	.driver		= {
+		.name	= "regulator-haptic",
+		.owner	= THIS_MODULE,
+		.of_match_table = regulator_haptic_dt_match,
+	},
+
+	.probe		= regulator_haptic_probe,
+	.remove		= regulator_haptic_remove,
+};
+module_platform_driver(regulator_haptic_driver);
+
+MODULE_ALIAS("platform:regulator-haptic");
+MODULE_DESCRIPTION("Regulator haptic driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
-- 
1.7.9.5



^ permalink raw reply related

* [PATCH] Input: add regulator haptic driver
From: hyunhee.kim @ 2013-10-11  2:26 UTC (permalink / raw)
  To: dmitry.torokhov, broonie, peter.ujfalusi, wfp5p, linux-input,
	linux-kernel, akpm
  Cc: 'hyunhee.kim', kyungmin.park

From: Hyunhee Kim <hyunhee.kim@samsung.com>
Date: Wed, 9 Oct 2013 16:21:36 +0900
Subject: [PATCH] Input: add regulator haptic driver

The regulator haptic driver function can be used to control motor by on/off
regulator.
User can control the haptic driver by using force feedback framework.

Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/input/misc/Kconfig            |    6 ++
 drivers/input/misc/Makefile           |    1 +
 drivers/input/misc/regulator-haptic.c |  185
+++++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 drivers/input/misc/regulator-haptic.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index bb698e1..f391cd7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -82,6 +82,12 @@ config INPUT_ARIZONA_HAPTICS
 	  To compile this driver as a module, choose M here: the
 	  module will be called arizona-haptics.
 
+config INPUT_REGULATOR_HAPTIC
+	tristate "regulator haptics support"
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y to enable support for the haptics module for regulator.
+
 config INPUT_BMA150
 	tristate "BMA150/SMB380 acceleration sensor support"
 	depends on I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d7fc17f..106f0bc 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X_I2C)		+=
adxl34x-i2c.o
 obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
 obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)	+= arizona-haptics.o
+obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)	+= regulator-haptic.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)		+= bfin_rotary.o
diff --git a/drivers/input/misc/regulator-haptic.c
b/drivers/input/misc/regulator-haptic.c
new file mode 100644
index 0000000..29f57ea
--- /dev/null
+++ b/drivers/input/misc/regulator-haptic.c
@@ -0,0 +1,185 @@
+/*
+ * Regulator haptic driver
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Author: Hyunhee Kim <hyunhee.kim@samsung.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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+
+struct regulator_haptic {
+	struct device *dev;
+	struct input_dev *input_dev;
+	struct work_struct work;
+	bool enabled;
+	struct regulator *regulator;
+	struct mutex mutex;
+	int level;
+};
+
+static void regulator_haptic_enable(struct regulator_haptic *haptic, bool
enable)
+{
+	int ret;
+
+	mutex_lock(&haptic->mutex);
+	if (enable && !haptic->enabled) {
+		haptic->enabled = true;
+		ret = regulator_enable(haptic->regulator);
+		if (ret)
+			pr_err("haptic: %s failed to enable regulator\n",
+				__func__);
+	} else if (!enable && haptic->enabled) {
+		haptic->enabled = false;
+		ret = regulator_disable(haptic->regulator);
+		if (ret)
+			pr_err("haptic: %s failed to disable regulator\n",
+				__func__);
+	}
+	mutex_unlock(&haptic->mutex);
+}
+
+static void regulator_haptic_work(struct work_struct *work)
+{
+	struct regulator_haptic *haptic = container_of(work,
+						       struct
regulator_haptic,
+						       work);
+	if (haptic->level)
+		regulator_haptic_enable(haptic, true);
+	else
+		regulator_haptic_enable(haptic, false);
+
+}
+
+static int regulator_haptic_play(struct input_dev *input, void *data,
+				struct ff_effect *effect)
+{
+	struct regulator_haptic *haptic = input_get_drvdata(input);
+
+	haptic->level = effect->u.rumble.strong_magnitude;
+	if (!haptic->level)
+		haptic->level = effect->u.rumble.weak_magnitude;
+	schedule_work(&haptic->work);
+
+	return 0;
+}
+
+static void regulator_haptic_close(struct input_dev *input)
+{
+	struct regulator_haptic *haptic = input_get_drvdata(input);
+
+	cancel_work_sync(&haptic->work);
+	regulator_haptic_enable(haptic, false);
+}
+
+static int regulator_haptic_probe(struct platform_device *pdev)
+{
+	struct regulator_haptic *haptic;
+	struct input_dev *input_dev;
+	int error;
+
+	haptic = kzalloc(sizeof(*haptic), GFP_KERNEL);
+	if (!haptic) {
+		dev_err(&pdev->dev, "unable to allocate memory for
haptic\n");
+		return -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+
+	if (!input_dev) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		error =  -ENOMEM;
+		goto err_kfree_mem;
+	}
+
+	INIT_WORK(&haptic->work, regulator_haptic_work);
+	mutex_init(&haptic->mutex);
+	haptic->input_dev = input_dev;
+	haptic->dev = &pdev->dev;
+	haptic->regulator = regulator_get(&pdev->dev, "haptic");
+
+	if (IS_ERR(haptic->regulator)) {
+		error = PTR_ERR(haptic->regulator);
+		dev_err(&pdev->dev, "unable to get regulator, err: %d\n",
+			error);
+		goto err_ifree_mem;
+	}
+
+	haptic->input_dev->name = "regulator:haptic";
+	haptic->input_dev->dev.parent = &pdev->dev;
+	haptic->input_dev->close = regulator_haptic_close;
+	haptic->enabled = false;
+	input_set_drvdata(haptic->input_dev, haptic);
+	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
+
+	error = input_ff_create_memless(input_dev, NULL,
+				      regulator_haptic_play);
+	if (error) {
+		dev_err(&pdev->dev,
+			"input_ff_create_memless() failed: %d\n",
+			error);
+		goto err_put_regulator;
+	}
+
+	error = input_register_device(haptic->input_dev);
+	if (error) {
+		dev_err(&pdev->dev,
+			"couldn't register input device: %d\n",
+			error);
+		goto err_destroy_ff;
+	}
+
+	platform_set_drvdata(pdev, haptic);
+
+	return 0;
+
+err_destroy_ff:
+	input_ff_destroy(haptic->input_dev);
+err_put_regulator:
+	regulator_put(haptic->regulator);
+err_ifree_mem:
+	input_free_device(haptic->input_dev);
+err_kfree_mem:
+	kfree(haptic);
+
+	return error;
+}
+
+static int regulator_haptic_remove(struct platform_device *pdev)
+{
+	struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+
+	input_unregister_device(haptic->input_dev);
+
+	return 0;
+}
+
+static struct of_device_id regulator_haptic_dt_match[] = {
+	{ .compatible = "linux,regulator-haptic" },
+	{},
+};
+
+static struct platform_driver regulator_haptic_driver = {
+	.driver		= {
+		.name	= "regulator-haptic",
+		.owner	= THIS_MODULE,
+		.of_match_table = regulator_haptic_dt_match,
+	},
+
+	.probe		= regulator_haptic_probe,
+	.remove		= regulator_haptic_remove,
+};
+module_platform_driver(regulator_haptic_driver);
+
+MODULE_ALIAS("platform:regulator-haptic");
+MODULE_DESCRIPTION("Regulator haptic driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
-- 
1.7.9.5



^ permalink raw reply related

* Re: [PATCH] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Florian Echtler @ 2013-10-11  9:22 UTC (permalink / raw)
  To: David Herrmann, HID CORE LAYER
  Cc: Henrik Rydberg, Benjamin Tissoires, Dmitry Torokhov
In-Reply-To: <CANq1E4R5-WEx_e1vYOmY-xGL0w669Qj54SGLU_tb8h97=5zH=A@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1872 bytes --]

On 02.10.2013 15:59, David Herrmann wrote:
>>> Or maybe even replace it by "u32 angle;". That should always be safe.
>>> Once you make use of this field, you can reconsider whether it's worth
>>> doing FP in the kernel. But as long as it's unused, I'd vote for
>>> avoiding "float" entirely.
>>
>> I was indeed planning to use this for orientation (as intended) in the
>> next iteration, what macros would I have to use for proper float handling?
> 
> Archived from 2003 but afaik his last paragraph still applies today:
>   http://yarchive.net/comp/linux/kernel_fp.html
> 
> So what you should do is forward the raw angle data to user-space and
> let them deal with it. We usually don't apply policy in the kernel but
> instead forward the given data to the user and let them do the
> orientation computations. Any specific reason why you want to do that
> in the kernel?
I think it would be more consistent to have an EV_ABS value for
orientation, ranging e.g. from 0 to 359 (or rather from 0 to e.g. 90, as
described in multi-touch-protocol.txt). For pass-through to work, I
would probably have to set min and max to 0 and __UINT32_MAX__?

Alternatively, I think it should be possible to perform the required
conversion using integer arithmetic and bit operations alone.

However, for the time being, I'd suggest to simply leave the float
alone, use just a 0/1 value for orientation and deal with this in a
later patch, agreed?

One additional question: is there any provision in the multitouch
protocol for differentiation between various types of objects, e.g.
"finger" and "palm"?

BTW, what's the best practice for resubmitting a patch? I've used "git
commit --amend" on my previous commit, and would now just use "git
send-email" again, creating a new thread?

Best regards, Florian
-- 
SENT FROM MY DEC VT50 TERMINAL




[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* [RFC] usbtouchscreen: stuck BTN_TOUCH release events
From: Christian Engelmayer @ 2013-10-11 11:42 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, linux-usb, christian.engelmayer

Hello,

We are using the usbtouchscreen driver for a 0eef:0001 eGalax based device and
have observed cases were BTN_TOUCH seems to be stuck as release events are not
reported promptly. In those situations the release event is reported after
arbitrary time when the next touch event is triggered.

An usbmon trace shows that the problem occurs reproducible when the final 5
byte report containing the liftoff event finishes at an 8 byte boundary:

   ceb81c80 1241543630 C Ii:1:002:1 0:4 16 = 81097c0a 5b81097c 0a5a8109 7b0a5a81
   ceb81c80 1241543964 S Ii:1:002:1 -115:4 16 <
   ceb81c80 1241555630 C Ii:1:002:1 0:4 16 = 097a0a5a 8109780a 59810975 0a578109
   ceb81c80 1241555988 S Ii:1:002:1 -115:4 16 <

   ---[abort - urb gets unlinked]---

   ceb81c80 1250629867 C Ii:1:002:1 -2:4 8 = 730a5380 09730a53

The usbtouchscreen driver is aware of both the report and diagnostic packets
supported by the controller. It enables multi frame support and defines the
report size for the eGalax to the 16 byte maximum diagnostic packet size
opposed to the 5 byte coordinate report.

In my opinion the situation described above is caused because the same size
definition is used for buffer allocation and interrupt endpoint requests to
the USB subsystem. The ehci-hcd will split the 16 byte request into up to 2
accesses according to the wMaxPacketSize of 8 byte for this endpoint. In case
the first transfer is answered by the eGalax with not less than the full 8 byte
requested, the host controller has got no way of knowing that the touch
controller will not have additional queued data until the next touch event.

As I am normally not involved into input drivers, please give me a hint to a
solution to this issue that would be acceptable for the maintainers and I can
prepare a tested patch accordingly.

Regards,
Christian

---

Bus 001 Device 002: ID 0eef:0001 D-WAV Scientific Co., Ltd eGalax TouchScreen
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x0eef D-WAV Scientific Co., Ltd
  idProduct          0x0001 eGalax TouchScreen
  bcdDevice            1.00
  iManufacturer           1 eGalax Inc.
  iProduct                2 USB TouchController
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           25
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 USB TouchScreen
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               5
Device Status:     0x0002
  (Bus Powered)
  Remote Wakeup Enabled

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         1 Single TT
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0002 2.0 root hub
  bcdDevice            3.04
  iManufacturer           3 Linux 3.4.61-rel_4_4002_0-svn216359 ehci_hcd
  iProduct                2 Freescale On-Chip EHCI Host Controller
  iSerial                 1 fsl-ehci.0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           25
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         9 Hub
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      0 Full speed (or root) hub
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0004  1x 4 bytes
        bInterval              12
Hub Descriptor:
  bLength               9
  bDescriptorType      41
  nNbrPorts             1
  wHubCharacteristic 0x0009
    Per-port power switching
    Per-port overcurrent protection
    TT think time 8 FS bits
  bPwrOn2PwrGood       10 * 2 milli seconds
  bHubContrCurrent      0 milli Ampere
  DeviceRemovable    0x00
  PortPwrCtrlMask    0xff
 Hub Port Status:
   Port 1: 0000.0303 lowspeed power enable connect
Device Status:     0x0001
  Self Powered

^ permalink raw reply

* [PATCH 1/1][Resend] Input: cypress_ps2 - Return zero finger count if palm is detected.
From: Joseph Salisbury @ 2013-10-11 16:30 UTC (permalink / raw)
  To: dmitry.torokhov, rydberg
  Cc: Kamal Mostafa, linux-kernel, dudl, git, tim.gardner, linux-input
In-Reply-To: <1380571922.15513.29.camel@fourier>

On 09/30/2013 04:12 PM, Kamal Mostafa wrote:
> On Tue, 2013-09-24 at 11:44 -0400, Joseph Salisbury wrote:
>> BugLink: http://bugs.launchpad.net/bugs/1229361
>>
>> This patch sets the finger count to 0 in the case of palm contact.
>>
>> Signed-off-by: Joseph Salisbury <joseph.salisbury@canonical.com>
>> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> (maintainer:INPUT (KEYBOARD,...,commit_signer:2/2=100%)
>> Cc: Henrik Rydberg <rydberg@euromail.se> (maintainer:INPUT MULTITOUCH...)
>> Cc: Kamal Mostafa <kamal@canonical.com> (commit_signer:2/2=100%)
>> Cc: Dudley Du <dudl@cypress.com> (commit_signer:2/2=100%)
>> Cc: Kyle Fazzari <git@status.e4ward.com> (commit_signer:1/2=50%)
>> Cc: Tim Gardner <tim.gardner@canonical.com> (commit_signer:1/2=50%)
>> Cc: linux-input@vger.kernel.org (open list:INPUT (KEYBOARD,...)
>> Cc: linux-kernel@vger.kernel.org (open list)
>> Cc: stable@vger.kernel.org
> This patch works fine: eliminates stream of junk driver messages with no
> ill effects.
>
> Tested-by: Kamal Mostafa <kamal@canonical.com>
>
>  -Kamal
>
>
>> ---
>>  drivers/input/mouse/cypress_ps2.c |    4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
>> index 45b3eda..95b2c40 100644
>> --- a/drivers/input/mouse/cypress_ps2.c
>> +++ b/drivers/input/mouse/cypress_ps2.c
>> @@ -441,7 +441,7 @@ static int cypress_get_finger_count(unsigned char header_byte)
>>  			case 2: return 5;
>>  			default:
>>  				/* Invalid contact (e.g. palm). Ignore it. */
>> -				return -1;
>> +				return 0;
>>  		}
>>  	}
>>  
>> @@ -460,7 +460,7 @@ static int cypress_parse_packet(struct psmouse *psmouse,
>>  
>>  	contact_cnt = cypress_get_finger_count(header_byte);
>>  
>> -	if (contact_cnt < 0) /* e.g. palm detect */
>> +	if (contact_cnt < 0)
>>  		return -EINVAL;
>>  
>>  	report_data->contact_cnt = contact_cnt;
Hi Dmitry and Henrik,

Have you had a chance to review this patch to consider it for inclusion
in mainline?

Thanks,

Joe


^ permalink raw reply

* Disabling the tsc2005 driver at runtime
From: Phil Carmody @ 2013-10-11 16:38 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: freemangordon, linux-input, wfp5p, broonie, linux-kernel, pc+n900

Greetings, Dmitry,

I'm looking for some advice regarding locally restoring a feature into
the tsc2005 driver that was removed back in:
  http://www.spinics.net/lists/linux-input/msg14575.html
  commit 5cb81d1: Input: tsc2005 - remove 'disable' sysfs attribute

Given the prior patch in the patchset:
  commit 0b950d3: Input: tsc2005 - add open/close
  "Introduce open and close methods for the input device 
   to keep the device powered down when it is not in use."
it seems you were expecting the device node to only have one reader, and
that reader would be the entity who decided when it was time to disable
and power down the device.

However, in the Nokia N900, the device node has at least 3 readers, 2 of
which I believe are closed source components, and therefore cannot be
modified to follow kernel changes. And even then, forcing 3 userspace
programs to now have to actively participate in the disabling of the
device seems excessively wasteful, compared with the ultimate simplicity
of the clients not even having to know about such things, which is how
it was before the change.

Back then you mentioned a generic interface that should replace this
device-specific one, but I can see no documentation for such an
interface in the kernel Documentation/ABI. Can you elaborate?

At the moment, as we can't break userspace, it seems that if we want to
run a more modern kernel on the N900 or another tsc2005-based device
running Fremantle, we should just locally revert that patch, and take 
the maintenance hit ourselves for the implications of that. (Here 'we'
= the volunteer community still supporting the device because of its
longevity.)

Cheers,
Phil
-- 
People generally seem to want software to be free as in speech and/or
free as in beer. Unfortunately rather too much of it is free as in jazz.
-- Janet McKnight, on a private newsgroup

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox