Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH 02/13] Input: introduce ABS_MAX2/CNT2 and friends
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann
In-Reply-To: <1383336984-26601-1-git-send-email-dh.herrmann@gmail.com>

As we painfully noticed during the 3.12 merge-window our
EVIOCGABS/EVIOCSABS API is limited to ABS_MAX<=0x3f. We tried several
hacks to work around it but if we ever decide to increase ABS_MAX, the
EVIOCSABS ioctl ABI might overflow into the next byte causing horrible
misinterpretations in the kernel that we cannot catch.

Therefore, we decided to go with ABS_MAX2/CNT2 and introduce two new
ioctls to get/set abs-params. They no longer encode the ABS code in the
ioctl number and thus allow up to 4 billion ABS codes.

The new API also allows to query multiple ABS values with one call. To
allow EVIOCSABS2(code = 0, cnt = ABS_CNT2) we need to silently ignore
writes to ABS_MT_SLOT. Other than that, semantics are the same as for the
legacy API.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/hid/hid-debug.c                  |  2 +-
 drivers/hid/hid-input.c                  |  2 +-
 drivers/input/evdev.c                    | 88 +++++++++++++++++++++++++++++++-
 drivers/input/input.c                    | 14 ++---
 drivers/input/keyboard/goldfish_events.c |  6 +--
 drivers/input/keyboard/hil_kbd.c         |  2 +-
 drivers/input/misc/uinput.c              |  6 +--
 include/linux/hid.h                      |  2 +-
 include/linux/input.h                    |  6 +--
 include/uapi/linux/input.h               | 37 +++++++++++++-
 include/uapi/linux/uinput.h              |  2 +-
 11 files changed, 144 insertions(+), 23 deletions(-)

diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 8453214..d32fa30 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -862,7 +862,7 @@ static const char *relatives[REL_MAX + 1] = {
 	[REL_WHEEL] = "Wheel",		[REL_MISC] = "Misc",
 };
 
-static const char *absolutes[ABS_CNT] = {
+static const char *absolutes[ABS_CNT2] = {
 	[ABS_X] = "X",			[ABS_Y] = "Y",
 	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
 	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d97f232..a02721c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1300,7 +1300,7 @@ static bool hidinput_has_been_populated(struct hid_input *hidinput)
 	for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
 		r |= hidinput->input->relbit[i];
 
-	for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
+	for (i = 0; i < BITS_TO_LONGS(ABS_CNT2); i++)
 		r |= hidinput->input->absbit[i];
 
 	for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index b6ded17..ffe65fd 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -635,7 +635,7 @@ static int handle_eviocgbit(struct input_dev *dev,
 	case      0: bits = dev->evbit;  len = EV_MAX;  break;
 	case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
 	case EV_REL: bits = dev->relbit; len = REL_MAX; break;
-	case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+	case EV_ABS: bits = dev->absbit; len = ABS_MAX2; break;
 	case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
 	case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 	case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
@@ -663,6 +663,86 @@ static int handle_eviocgbit(struct input_dev *dev,
 }
 #undef OLD_KEY_MAX
 
+static int evdev_handle_get_abs2(struct input_dev *dev, void __user *p)
+{
+	u32 code, cnt, i;
+	struct input_absinfo2 __user *pinfo = p;
+	struct input_absinfo abs;
+
+	if (!dev->absinfo)
+		return -EINVAL;
+
+	if (copy_from_user(&code, &pinfo->code, sizeof(code)))
+		return -EFAULT;
+	if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
+		return -EFAULT;
+
+	if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
+		return -EINVAL;
+	if (code + cnt > ABS_MAX2)
+		return -EINVAL;
+
+	for (i = 0; i < cnt; ++i) {
+		/*
+		 * Take event lock to ensure that we are not
+		 * copying data while EVIOCSABS2 changes it.
+		 * Might be inconsistent, otherwise.
+		 */
+		spin_lock_irq(&dev->event_lock);
+		abs = dev->absinfo[code + i];
+		spin_unlock_irq(&dev->event_lock);
+
+		if (copy_to_user(&pinfo->info[i], &abs, sizeof(abs)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int evdev_handle_set_abs2(struct input_dev *dev, void __user *p)
+{
+	struct input_absinfo2 __user *pinfo = p;
+	struct input_absinfo *abs;
+	u32 code, cnt, i;
+	size_t size;
+
+	if (!dev->absinfo)
+		return -EINVAL;
+
+	if (copy_from_user(&code, &pinfo->code, sizeof(code)))
+		return -EFAULT;
+	if (copy_from_user(&cnt, &pinfo->cnt, sizeof(cnt)))
+		return -EFAULT;
+
+	if (!cnt || code > ABS_MAX2 || cnt > ABS_CNT2)
+		return -EINVAL;
+	if (code + cnt > ABS_MAX2)
+		return -EINVAL;
+
+	size = cnt * sizeof(*abs);
+	abs = memdup_user(&pinfo->info[0], size);
+	if (IS_ERR(abs))
+		return PTR_ERR(abs);
+
+	/*
+	 * Take event lock to ensure that we are not
+	 * changing device parameters in the middle
+	 * of event.
+	 */
+	spin_lock_irq(&dev->event_lock);
+	for (i = 0; i < cnt; ++i) {
+		/* silently drop ABS_MT_SLOT */
+		if (code + i == ABS_MT_SLOT)
+			continue;
+
+		dev->absinfo[code + i] = abs[i];
+	}
+	spin_unlock_irq(&dev->event_lock);
+
+	kfree(abs);
+	return 0;
+}
+
 static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
 {
 	struct input_keymap_entry ke = {
@@ -890,6 +970,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 		client->clkid = i;
 		return 0;
 
+	case EVIOCGABS2:
+		return evdev_handle_get_abs2(dev, p);
+
+	case EVIOCSABS2:
+		return evdev_handle_set_abs2(dev, p);
+
 	case EVIOCGKEYCODE:
 		return evdev_handle_get_keycode(dev, p);
 
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c044699..bc88f17 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -305,7 +305,7 @@ static int input_get_disposition(struct input_dev *dev,
 		break;
 
 	case EV_ABS:
-		if (is_event_supported(code, dev->absbit, ABS_MAX))
+		if (is_event_supported(code, dev->absbit, ABS_MAX2))
 			disposition = input_handle_abs_event(dev, code, &value);
 
 		break;
@@ -474,7 +474,7 @@ EXPORT_SYMBOL(input_inject_event);
 void input_alloc_absinfo(struct input_dev *dev)
 {
 	if (!dev->absinfo)
-		dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo),
+		dev->absinfo = kcalloc(ABS_CNT2, sizeof(struct input_absinfo),
 					GFP_KERNEL);
 
 	WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
@@ -954,7 +954,7 @@ static const struct input_device_id *input_match_device(struct input_handler *ha
 		if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
 			continue;
 
-		if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
+		if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX2))
 			continue;
 
 		if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
@@ -1147,7 +1147,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
 	if (test_bit(EV_REL, dev->evbit))
 		input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
 	if (test_bit(EV_ABS, dev->evbit))
-		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
+		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX2);
 	if (test_bit(EV_MSC, dev->evbit))
 		input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
 	if (test_bit(EV_LED, dev->evbit))
@@ -1333,7 +1333,7 @@ static int input_print_modalias(char *buf, int size, struct input_dev *id,
 	len += input_print_modalias_bits(buf + len, size - len,
 				'r', id->relbit, 0, REL_MAX);
 	len += input_print_modalias_bits(buf + len, size - len,
-				'a', id->absbit, 0, ABS_MAX);
+				'a', id->absbit, 0, ABS_MAX2);
 	len += input_print_modalias_bits(buf + len, size - len,
 				'm', id->mscbit, 0, MSC_MAX);
 	len += input_print_modalias_bits(buf + len, size - len,
@@ -1592,7 +1592,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 	if (test_bit(EV_REL, dev->evbit))
 		INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX);
 	if (test_bit(EV_ABS, dev->evbit))
-		INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX);
+		INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX2);
 	if (test_bit(EV_MSC, dev->evbit))
 		INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX);
 	if (test_bit(EV_LED, dev->evbit))
@@ -1924,7 +1924,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
 
 	events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */
 
-	for (i = 0; i < ABS_CNT; i++) {
+	for (i = 0; i < ABS_CNT2; i++) {
 		if (test_bit(i, dev->absbit)) {
 			if (input_is_mt_axis(i))
 				events += mt_slots;
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
index 9f60a2e..9999cea 100644
--- a/drivers/input/keyboard/goldfish_events.c
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -90,8 +90,8 @@ static void events_import_abs_params(struct event_dev *edev)
 	__raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
 
 	count = __raw_readl(addr + REG_LEN) / sizeof(val);
-	if (count > ABS_MAX)
-		count = ABS_MAX;
+	if (count > ABS_MAX2)
+		count = ABS_MAX2;
 
 	for (i = 0; i < count; i++) {
 		if (!test_bit(i, input_dev->absbit))
@@ -158,7 +158,7 @@ static int events_probe(struct platform_device *pdev)
 	events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
 	events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
 	events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
-	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
+	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX2);
 	events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
 	events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
 	events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 589e3c2..4e4e010 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -387,7 +387,7 @@ static void hil_dev_pointer_setup(struct hil_dev *ptr)
 					0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
 
 #ifdef TABLET_AUTOADJUST
-		for (i = 0; i < ABS_MAX; i++) {
+		for (i = 0; i < ABS_MAX2; i++) {
 			int diff = input_abs_get_max(input_dev, ABS_X + i) / 10;
 			input_abs_set_min(input_dev, ABS_X + i,
 				input_abs_get_min(input_dev, ABS_X + i) + diff);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 3cd84d2..2f7355e 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -311,7 +311,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
 	unsigned int cnt;
 	int retval = 0;
 
-	for (cnt = 0; cnt < ABS_CNT; cnt++) {
+	for (cnt = 0; cnt < ABS_CNT2; cnt++) {
 		int min, max;
 		if (!test_bit(cnt, dev->absbit))
 			continue;
@@ -474,7 +474,7 @@ static int uinput_setup_device2(struct uinput_device *udev,
 		return -EINVAL;
 
 	/* rough check to avoid huge kernel space allocations */
-	max = ABS_CNT * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
+	max = ABS_CNT2 * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
 	if (count > max)
 		return -EINVAL;
 
@@ -770,7 +770,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 			break;
 
 		case UI_SET_ABSBIT:
-			retval = uinput_set_bit(arg, absbit, ABS_MAX);
+			retval = uinput_set_bit(arg, absbit, ABS_MAX2);
 			break;
 
 		case UI_SET_MSCBIT:
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 31b9d29..c21d8bb 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -828,7 +828,7 @@ static inline void hid_map_usage(struct hid_input *hidinput,
 	switch (type) {
 	case EV_ABS:
 		*bit = input->absbit;
-		*max = ABS_MAX;
+		*max = ABS_MAX2;
 		break;
 	case EV_REL:
 		*bit = input->relbit;
diff --git a/include/linux/input.h b/include/linux/input.h
index 82ce323..c6add6f 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -129,7 +129,7 @@ struct input_dev {
 	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
 	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
 	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
-	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
+	unsigned long absbit[BITS_TO_LONGS(ABS_CNT2)];
 	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
 	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
 	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
@@ -210,8 +210,8 @@ struct input_dev {
 #error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match"
 #endif
 
-#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX
-#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match"
+#if ABS_MAX2 != INPUT_DEVICE_ID_ABS_MAX
+#error "ABS_MAX2 and INPUT_DEVICE_ID_ABS_MAX do not match"
 #endif
 
 #if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index a372627..9e525f9 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -74,6 +74,27 @@ struct input_absinfo {
 };
 
 /**
+ * struct input_absinfo2 - used by EVIOC[G/S]ABS2 ioctls
+ * @code: First ABS code to query
+ * @cnt: Number of ABS codes to query starting at @code
+ * @info: #@cnt absinfo structures to get/set abs parameters for all codes
+ *
+ * This structure is used by the new EVIOC[G/S]ABS2 ioctls which
+ * do the same as the old EVIOC[G/S]ABS ioctls but avoid encoding
+ * the ABS code in the ioctl number. This allows a much wider
+ * range of ABS codes. Furthermore, it allows to query multiple codes with a
+ * single call.
+ *
+ * Note that this silently drops any requests to set ABS_MT_SLOT. Hence, it is
+ * allowed to call this with code=0 cnt=ABS_CNT2.
+ */
+struct input_absinfo2 {
+	__u32 code;
+	__u32 cnt;
+	struct input_absinfo info[1];
+};
+
+/**
  * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
  * @scancode: scancode represented in machine-endian form.
  * @len: length of the scancode that resides in @scancode buffer.
@@ -153,6 +174,8 @@ struct input_keymap_entry {
 
 #define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
 #define EVIOCREVOKE		_IOW('E', 0x91, int)			/* Revoke device access */
+#define EVIOCGABS2		_IOR('E', 0x92, struct input_absinfo2)	/* get abs value/limits */
+#define EVIOCSABS2		_IOW('E', 0x93, struct input_absinfo2)	/* set abs value/limits */
 
 #define EVIOCSCLOCKID		_IOW('E', 0xa0, int)			/* Set clockid to be used for timestamps */
 
@@ -832,11 +855,23 @@ struct input_keymap_entry {
 #define ABS_MT_TOOL_X		0x3c	/* Center X tool position */
 #define ABS_MT_TOOL_Y		0x3d	/* Center Y tool position */
 
-
+/*
+ * ABS_MAX/CNT is limited to a maximum of 0x3f due to the design of EVIOCGABS
+ * and EVIOCSABS ioctls. Other kernel APIs like uinput also hardcoded it. Do
+ * not modify this value and instead use the extended ABS_MAX2/CNT2 API.
+ */
 #define ABS_MAX			0x3f
 #define ABS_CNT			(ABS_MAX+1)
 
 /*
+ * Due to API restrictions the legacy evdev API only supports ABS values up to
+ * ABS_MAX/CNT. Use the extended *ABS2 ioctls to operate on any ABS values in
+ * between ABS_MAX and ABS_MAX2.
+ */
+#define ABS_MAX2		0x3f
+#define ABS_CNT2		(ABS_MAX2+1)
+
+/*
  * Switch events
  */
 
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index c2e8710..27ee521 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -140,7 +140,7 @@ struct uinput_user_dev2 {
 	char name[UINPUT_MAX_NAME_SIZE];
 	struct input_id id;
 	__u32 ff_effects_max;
-	struct input_absinfo abs[ABS_CNT];
+	struct input_absinfo abs[ABS_CNT2];
 };
 
 #endif /* _UAPI__UINPUT_H_ */
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH 01/13] Input: uinput: add full absinfo support
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann
In-Reply-To: <1383336984-26601-1-git-send-email-dh.herrmann@gmail.com>

We currently lack support for abs-resolution and abs-value parameters
during uinput ABS initialization. Furthermore, our parsers don't allow
growing ABS_CNT values. Therefore, introduce uinput_user_dev2.

User-space is free to write uinput_user_dev2 objects instead of
uinput_user_dev legacy objects now. If the kernel lacks support for it,
our comparison for "count != sizeof(struct uinput_user_dev)" will catch
this and return EINVAL. User-space shall retry with the legacy mode then.

Internally, we transform the legacy object into uinput_user_dev2 and then
handle both the same way.

The new uinput_user_dev2 object has multiple new features:
 - abs payload now has "value" and "resolution" parameters as part of the
   switch to "struct input_absinfo". We simply copy these over.
 - Our parser allows growing ABS_CNT. We automatically detect the payload
   size of the caller, thus, calculating the ABS_CNT the program was
   compiled with.
 - A "version" field to denote the uinput-version used. This is required
   to properly support changing "struct input_user_dev2" changes in the
   future. Due to the dynamic ABS_CNT support, we cannot simply add new
   fields, as we cannot deduce the structure size from the user-space
   given size. Thus, we need the "version" field to allow changing the
   object and properly detecting it in our write() handler.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/input/misc/uinput.c | 142 ++++++++++++++++++++++++++++++++------------
 include/uapi/linux/uinput.h |   9 +++
 2 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index a0a4bba..3cd84d2 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -358,14 +358,16 @@ static int uinput_allocate_device(struct uinput_device *udev)
 }
 
 static int uinput_setup_device(struct uinput_device *udev,
-			       const char __user *buffer, size_t count)
+			       struct uinput_user_dev2 *user_dev2,
+			       size_t abscnt)
 {
-	struct uinput_user_dev	*user_dev;
 	struct input_dev	*dev;
 	int			i;
 	int			retval;
+	struct input_absinfo	*abs;
 
-	if (count != sizeof(struct uinput_user_dev))
+	/* Ensure name is filled in */
+	if (!user_dev2->name[0])
 		return -EINVAL;
 
 	if (!udev->dev) {
@@ -375,37 +377,27 @@ static int uinput_setup_device(struct uinput_device *udev,
 	}
 
 	dev = udev->dev;
-
-	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
-	if (IS_ERR(user_dev))
-		return PTR_ERR(user_dev);
-
-	udev->ff_effects_max = user_dev->ff_effects_max;
-
-	/* Ensure name is filled in */
-	if (!user_dev->name[0]) {
-		retval = -EINVAL;
-		goto exit;
-	}
+	udev->ff_effects_max = user_dev2->ff_effects_max;
 
 	kfree(dev->name);
-	dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
+	dev->name = kstrndup(user_dev2->name, UINPUT_MAX_NAME_SIZE,
 			     GFP_KERNEL);
-	if (!dev->name) {
-		retval = -ENOMEM;
-		goto exit;
-	}
-
-	dev->id.bustype	= user_dev->id.bustype;
-	dev->id.vendor	= user_dev->id.vendor;
-	dev->id.product	= user_dev->id.product;
-	dev->id.version	= user_dev->id.version;
+	if (!dev->name)
+		return -ENOMEM;
 
-	for (i = 0; i < ABS_CNT; i++) {
-		input_abs_set_max(dev, i, user_dev->absmax[i]);
-		input_abs_set_min(dev, i, user_dev->absmin[i]);
-		input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]);
-		input_abs_set_flat(dev, i, user_dev->absflat[i]);
+	dev->id.bustype = user_dev2->id.bustype;
+	dev->id.vendor = user_dev2->id.vendor;
+	dev->id.product = user_dev2->id.product;
+	dev->id.version = user_dev2->id.version;
+
+	for (i = 0; i < abscnt; i++) {
+		abs = &user_dev2->abs[i];
+		input_abs_set_val(dev, i, abs->value);
+		input_abs_set_max(dev, i, abs->maximum);
+		input_abs_set_min(dev, i, abs->minimum);
+		input_abs_set_fuzz(dev, i, abs->fuzz);
+		input_abs_set_flat(dev, i, abs->flat);
+		input_abs_set_res(dev, i, abs->resolution);
 	}
 
 	/* check if absmin/absmax/absfuzz/absflat are filled as
@@ -413,7 +405,7 @@ static int uinput_setup_device(struct uinput_device *udev,
 	if (test_bit(EV_ABS, dev->evbit)) {
 		retval = uinput_validate_absbits(dev);
 		if (retval < 0)
-			goto exit;
+			return retval;
 		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
 			int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
 			input_mt_init_slots(dev, nslot, 0);
@@ -423,11 +415,84 @@ static int uinput_setup_device(struct uinput_device *udev,
 	}
 
 	udev->state = UIST_SETUP_COMPLETE;
-	retval = count;
+	return 0;
+}
+
+static int uinput_setup_device1(struct uinput_device *udev,
+				const char __user *buffer, size_t count)
+{
+	struct uinput_user_dev	*user_dev;
+	struct uinput_user_dev2	*user_dev2;
+	int			i;
+	int			retval;
+
+	if (count != sizeof(struct uinput_user_dev))
+		return -EINVAL;
+
+	user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
+	if (IS_ERR(user_dev))
+		return PTR_ERR(user_dev);
+
+	user_dev2 = kmalloc(sizeof(*user_dev2), GFP_KERNEL);
+	if (!user_dev2) {
+		kfree(user_dev);
+		return -ENOMEM;
+	}
+
+	user_dev2->version = UINPUT_VERSION;
+	memcpy(user_dev2->name, user_dev->name, UINPUT_MAX_NAME_SIZE);
+	memcpy(&user_dev2->id, &user_dev->id, sizeof(struct input_id));
+	user_dev2->ff_effects_max = user_dev->ff_effects_max;
+
+	for (i = 0; i < ABS_CNT; ++i) {
+		user_dev2->abs[i].value = 0;
+		user_dev2->abs[i].maximum = user_dev->absmax[i];
+		user_dev2->abs[i].minimum = user_dev->absmin[i];
+		user_dev2->abs[i].fuzz = user_dev->absfuzz[i];
+		user_dev2->abs[i].flat = user_dev->absflat[i];
+		user_dev2->abs[i].resolution = 0;
+	}
+
+	retval = uinput_setup_device(udev, user_dev2, ABS_CNT);
 
- exit:
 	kfree(user_dev);
-	return retval;
+	kfree(user_dev2);
+
+	return retval ? retval : count;
+}
+
+static int uinput_setup_device2(struct uinput_device *udev,
+			       const char __user *buffer, size_t count)
+{
+	struct uinput_user_dev2	*user_dev2;
+	int			retval;
+	size_t			off, abscnt, max;
+
+	/* The first revision of "uinput_user_dev2" is bigger than
+	 * "uinput_user_dev" and growing. Disallow any smaller payloads. */
+	if (count <= sizeof(struct uinput_user_dev))
+		return -EINVAL;
+
+	/* rough check to avoid huge kernel space allocations */
+	max = ABS_CNT * sizeof(*user_dev2->abs) + sizeof(*user_dev2);
+	if (count > max)
+		return -EINVAL;
+
+	user_dev2 = memdup_user(buffer, count);
+	if (IS_ERR(user_dev2))
+		return PTR_ERR(user_dev2);
+
+	if (user_dev2->version > UINPUT_VERSION) {
+		retval = -EINVAL;
+	} else {
+		off = offsetof(struct uinput_user_dev2, abs);
+		abscnt = (count - off) / sizeof(*user_dev2->abs);
+		retval = uinput_setup_device(udev, user_dev2, abscnt);
+	}
+
+	kfree(user_dev2);
+
+	return retval ? retval : count;
 }
 
 static ssize_t uinput_inject_event(struct uinput_device *udev,
@@ -459,9 +524,12 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
 	if (retval)
 		return retval;
 
-	retval = udev->state == UIST_CREATED ?
-			uinput_inject_event(udev, buffer, count) :
-			uinput_setup_device(udev, buffer, count);
+	if (udev->state == UIST_CREATED)
+		retval = uinput_inject_event(udev, buffer, count);
+	else if (count <= sizeof(struct uinput_user_dev))
+		retval = uinput_setup_device1(udev, buffer, count);
+	else
+		retval = uinput_setup_device2(udev, buffer, count);
 
 	mutex_unlock(&udev->mutex);
 
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index fe46431..c2e8710 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -134,4 +134,13 @@ struct uinput_user_dev {
 	__s32 absfuzz[ABS_CNT];
 	__s32 absflat[ABS_CNT];
 };
+
+struct uinput_user_dev2 {
+	__u8 version;
+	char name[UINPUT_MAX_NAME_SIZE];
+	struct input_id id;
+	__u32 ff_effects_max;
+	struct input_absinfo abs[ABS_CNT];
+};
+
 #endif /* _UAPI__UINPUT_H_ */
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH 00/13] Input/HID: Bits and Pieces
From: David Herrmann @ 2013-11-01 20:16 UTC (permalink / raw)
  To: linux-input
  Cc: Dmitry Torokhov, Jiri Kosina, Peter Hutterer, Benjamin Tissoires,
	David Herrmann

Hi

My backlog kept growing and most of the stuff depends on the ABS_* fixes, so I
gave it another try. The first 2 patches introduce EVIOC[GS]ABS2 and friends.
The rest is wiimote stuff that was laying around for some time and just needs
new ABS bits. So once the ABS stuff is in, I see no reason to delay the wiimote
patches (as they're even tested already). Hence, I put it all in a single
series.

Jiri, Dmitry, feel free to bribe me to split / not split the series so the
other one has to take it through their tree. Highest bid wins!

And I am still running tests, so please don't merge, yet. I will report back my
results. Besides, it's probably too late for 3.13, anyway and we should put it
into -next for 3.14 for some while.

Comments welcome!
David

David Herrmann (12):
  Input: uinput: add full absinfo support
  Input: introduce ABS_MAX2/CNT2 and friends
  Input: remove ambigious gamepad comment
  Input: add motion-tracking ABS_* bits and docs
  HID: wiimote: add hid_wiimote.legacy parameter
  HID: wiimote: adjust button-mapping to gamepad rules
  HID: wiimote: map nunchuk as real gamepad
  HID: wiimote: map classic controller as gamepad
  HID: wiimote: use ABS_ACCEL_* for accelerometer
  HID: wiimote: use ABS_GYRO_* bits for MP
  Input: introduce BTN/ABS bits for drums and guitars
  HID: wiimote: add support for Guitar-Hero drums

Nicolas Adenis-Lamarre (1):
  HID: wiimote: add support for Guitar-Hero guitars

 Documentation/input/gamepad.txt          |   9 +-
 Documentation/input/motion-tracking.txt  | 149 ++++++
 drivers/hid/hid-debug.c                  |   2 +-
 drivers/hid/hid-input.c                  |   2 +-
 drivers/hid/hid-wiimote-core.c           |  23 +
 drivers/hid/hid-wiimote-modules.c        | 761 ++++++++++++++++++++++++++-----
 drivers/hid/hid-wiimote.h                |   4 +
 drivers/input/evdev.c                    |  88 +++-
 drivers/input/input.c                    |  14 +-
 drivers/input/keyboard/goldfish_events.c |   6 +-
 drivers/input/keyboard/hil_kbd.c         |   2 +-
 drivers/input/misc/uinput.c              | 146 ++++--
 include/linux/hid.h                      |   2 +-
 include/linux/input.h                    |   6 +-
 include/linux/mod_devicetable.h          |   2 +-
 include/uapi/linux/input.h               |  66 ++-
 include/uapi/linux/uinput.h              |   9 +
 17 files changed, 1125 insertions(+), 166 deletions(-)
 create mode 100644 Documentation/input/motion-tracking.txt

-- 
1.8.4.1


^ permalink raw reply

* Re: [PATCH 4/5] input: tc3589x-keypad: support probing from device tree
From: Linus Walleij @ 2013-11-01 16:08 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Dmitry Torokhov, linux-input@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Samuel Ortiz, Lee Jones
In-Reply-To: <20131101005840.GB8413@kartoffel>

On Thu, Oct 31, 2013 at 5:58 PM, Mark Rutland <mark.rutland@arm.com> wrote:

>> +     plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
>> +     if (!plat)
>> +             return ERR_PTR(-ENOMEM);
>> +
>> +     of_property_read_u8(np, "keypad,num-columns", &plat->kcol);
>> +     of_property_read_u8(np, "keypad,num-rows", &plat->krow);
>
> These look wrong to me, as almost every single use of of_property_read_u8 (or
> of_property_read_u16) do. They read _packed_ values out of the dt, and do not
> read (u32) cells as u8s or u16s.

Yes...

> The matrix-keymap binding doesn't define these as 8-bit, and the example
> binding they are u32 cells. Either the binding document or this code is wrong.

The biding is in patch titled:
"mfd: tc3589x: Add device tree bindings"
and yes, you are right, this seems wrong. (The example in that patch
is wrong too.)

> I'm confused as to how this can work. Are you using /bits/ 8 in your dts?

Yes indeed I do. So it was working fine...

I'll adjust this to use u32:s, even if it seems odd supporting keypads
with 255+ columns and rows... well it's in there.

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH v4 1/1] Input: Improve the performance of alps v5-protocol's touchpad
From: Tommy Will @ 2013-11-01  6:00 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Niels de Vos, Yunkang Tang, david turvene,
	Kevin Cernekee
In-Reply-To: <1382355711-3211-1-git-send-email-yunkang.tang@cn.alps.com>

Hi Dmitry,

Could you please share me your opinion of below patch. Thanks


2013/10/21 Yunkang Tang <tommywill2011@gmail.com>:
> Hi all,
>
> Here is the 4th version of supporting ALPS v5 protocol's device.
>
> Change since v3:
> - Fix the bug that Finger1's coordinate data will always be (0,0) when finger
>   number is more than 1.
>
> Change since v2:
> - Merge two patches into one patch because they're all for improving v5 device.
> - Modify the source code according to Kevin's suggestions.
>   1) Simplify the alps_process_bitmap() function by using ffs() and fls().
>   2) Simplify the alps_decode_dolphin() function by using u64 for the palm data.
>   3) Reuse the alps_process_touchpad_packet_v3() for v5 device.
>   4) Add an sample for calculating touchpad's x_max&y_max by using sensor line number.
>
> Self test with v5 device:
> - Checked on both 32-bit & 64-bit environment.
> - Cursor moves correctly.
> - 1Finger Tap/Drag works well.
> - 2Finger Tap works well.
> - 2Finger Scroll works well.
> - L/R Buttons do function
>
> Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
> ---
>  drivers/input/mouse/alps.c | 217 ++++++++++++++++++++++++++++++++++++---------
>  drivers/input/mouse/alps.h |   7 +-
>  2 files changed, 183 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index ca7a26f..93f412d 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -257,6 +257,50 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
>  }
>
>  /*
> + * Process bitmap data for V5 protocols. Return value is null.
> + *
> + * The bitmaps don't have enough data to track fingers, so this function
> + * only generates points representing a bounding box of at most two contacts.
> + * These two points are returned in x1, y1, x2, and y2.
> + */
> +static void alps_process_bitmap_dolphin(struct alps_data *priv,
> +                                       struct alps_fields *fields,
> +                                       int *x1, int *y1, int *x2, int *y2)
> +{
> +       int box_middle_x, box_middle_y;
> +       unsigned int x_map, y_map;
> +       unsigned char start_bit, end_bit;
> +
> +       x_map = fields->x_map;
> +       y_map = fields->y_map;
> +
> +       if (!x_map || !y_map)
> +               return;
> +
> +       /* Most-significant bit should never exceed max sensor line number */
> +       if (fls(x_map) > priv->x_bits || fls(y_map) > priv->y_bits)
> +               return;
> +
> +       *x1 = *y1 = *x2 = *y2 = 0;
> +
> +       if (fields->fingers > 1) {
> +               start_bit = priv->x_bits - fls(x_map);
> +               end_bit = priv->x_bits - ffs(x_map);
> +               box_middle_x = (priv->x_max * (start_bit + end_bit)) /
> +                               (2 * (priv->x_bits - 1));
> +
> +               start_bit = ffs(y_map) - 1;
> +               end_bit = fls(y_map) - 1;
> +               box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> +                               (2 * (priv->y_bits - 1));
> +               *x1 = fields->x;
> +               *y1 = fields->y;
> +               *x2 = 2 * box_middle_x - *x1;
> +               *y2 = 2 * box_middle_y - *y1;
> +       }
> +}
> +
> +/*
>   * Process bitmap data from v3 and v4 protocols. Returns the number of
>   * fingers detected. A return value of 0 means at least one of the
>   * bitmaps was empty.
> @@ -461,7 +505,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
>         f->ts_middle = !!(p[3] & 0x40);
>  }
>
> -static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> +                                struct psmouse *psmouse)
>  {
>         f->first_mp = !!(p[4] & 0x40);
>         f->is_mp = !!(p[0] & 0x40);
> @@ -482,48 +527,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
>         alps_decode_buttons_v3(f, p);
>  }
>
> -static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
> +                                struct psmouse *psmouse)
>  {
> -       alps_decode_pinnacle(f, p);
> +       alps_decode_pinnacle(f, p, psmouse);
>
>         f->x_map |= (p[5] & 0x10) << 11;
>         f->y_map |= (p[5] & 0x20) << 6;
>  }
>
> -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
> +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> +                               struct psmouse *psmouse)
>  {
> +       u64 palm_data = 0;
> +       struct alps_data *priv = psmouse->private;
> +
>         f->first_mp = !!(p[0] & 0x02);
>         f->is_mp = !!(p[0] & 0x20);
>
> -       f->fingers = ((p[0] & 0x6) >> 1 |
> +       if (!f->is_mp) {
> +               f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> +               f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> +               f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> +               alps_decode_buttons_v3(f, p);
> +       } else {
> +               f->fingers = ((p[0] & 0x6) >> 1 |
>                      (p[0] & 0x10) >> 2);
> -       f->x_map = ((p[2] & 0x60) >> 5) |
> -                  ((p[4] & 0x7f) << 2) |
> -                  ((p[5] & 0x7f) << 9) |
> -                  ((p[3] & 0x07) << 16) |
> -                  ((p[3] & 0x70) << 15) |
> -                  ((p[0] & 0x01) << 22);
> -       f->y_map = (p[1] & 0x7f) |
> -                  ((p[2] & 0x1f) << 7);
> -
> -       f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> -       f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> -       f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>
> -       alps_decode_buttons_v3(f, p);
> +               palm_data = (p[1] & 0x7f) |
> +                           ((p[2] & 0x7f) << 7) |
> +                           ((p[4] & 0x7f) << 14) |
> +                           ((p[5] & 0x7f) << 21) |
> +                           ((p[3] & 0x07) << 28) |
> +                           (((u64)p[3] & 0x70) << 27) |
> +                           (((u64)p[0] & 0x01) << 34);
> +
> +               /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
> +               f->y_map = palm_data & (BIT(priv->y_bits) - 1);
> +
> +               /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
> +               f->x_map = (palm_data >> priv->y_bits) &
> +                          (BIT(priv->x_bits) - 1);
> +       }
>  }
>
> -static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
> +static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>  {
>         struct alps_data *priv = psmouse->private;
>         unsigned char *packet = psmouse->packet;
>         struct input_dev *dev = psmouse->dev;
>         struct input_dev *dev2 = priv->dev2;
>         int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> -       int fingers = 0, bmap_fingers;
> -       struct alps_fields f;
> +       int fingers = 0, bmap_fn;
> +       struct alps_fields f = {0};
>
> -       priv->decode_fields(&f, packet);
> +       priv->decode_fields(&f, packet, psmouse);
>
>         /*
>          * There's no single feature of touchpad position and bitmap packets
> @@ -540,19 +598,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
>                  */
>                 if (f.is_mp) {
>                         fingers = f.fingers;
> -                       bmap_fingers = alps_process_bitmap(priv,
> -                                                          f.x_map, f.y_map,
> -                                                          &x1, &y1, &x2, &y2);
> -
> -                       /*
> -                        * We shouldn't report more than one finger if
> -                        * we don't have two coordinates.
> -                        */
> -                       if (fingers > 1 && bmap_fingers < 2)
> -                               fingers = bmap_fingers;
> -
> -                       /* Now process position packet */
> -                       priv->decode_fields(&f, priv->multi_data);
> +                       if (priv->proto_version == ALPS_PROTO_V3) {
> +                               bmap_fn = alps_process_bitmap(priv, f.x_map,
> +                                                             f.y_map, &x1, &y1,
> +                                                             &x2, &y2);
> +
> +                               /*
> +                                * We shouldn't report more than one finger if
> +                                * we don't have two coordinates.
> +                                */
> +                               if (fingers > 1 && bmap_fn < 2)
> +                                       fingers = bmap_fn;
> +
> +                               /* Now process position packet */
> +                               priv->decode_fields(&f, priv->multi_data,
> +                                                   psmouse);
> +                       } else {
> +                               /*
> +                                * Because Dolphin uses position packet's
> +                                * coordinate data as Pt1 and uses it to
> +                                * calculate Pt2, so we need to do position
> +                                * packet decode first.
> +                                */
> +                               priv->decode_fields(&f, priv->multi_data,
> +                                                   psmouse);
> +
> +                               /*
> +                                * Since Dolphin's finger number is reliable,
> +                                * there is no need to compare with bmap_fn.
> +                                */
> +                               alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
> +                                                           &x2, &y2);
> +                       }
>                 } else {
>                         priv->multi_packet = 0;
>                 }
> @@ -642,7 +719,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
>                 return;
>         }
>
> -       alps_process_touchpad_packet_v3(psmouse);
> +       alps_process_touchpad_packet_v3_v5(psmouse);
>  }
>
>  static void alps_process_packet_v4(struct psmouse *psmouse)
> @@ -742,6 +819,17 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
>         input_sync(dev);
>  }
>
> +static void alps_process_packet_v5(struct psmouse *psmouse)
> +{
> +       unsigned char *packet = psmouse->packet;
> +
> +       /* Ignore stick point data */
> +       if (packet[0] == 0xD8)
> +               return;
> +
> +       alps_process_touchpad_packet_v3_v5(psmouse);
> +}
> +
>  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>                                         unsigned char packet[],
>                                         bool report_buttons)
> @@ -1519,6 +1607,53 @@ error:
>         return -1;
>  }
>
> +static int alps_dolphin_get_device_area(struct psmouse *psmouse,
> +                                       struct alps_data *priv)
> +{
> +       struct ps2dev *ps2dev = &psmouse->ps2dev;
> +       unsigned char param[4] = {0};
> +       int num_x_electrode, num_y_electrode;
> +
> +       if (alps_enter_command_mode(psmouse))
> +               return -1;
> +
> +       if (ps2_command(ps2dev, NULL, 0x00EC) ||
> +           ps2_command(ps2dev, NULL, 0x00F0) ||
> +           ps2_command(ps2dev, NULL, 0x00F0) ||
> +           ps2_command(ps2dev, NULL, 0x00F3) ||
> +           ps2_command(ps2dev, NULL, 0x000A) ||
> +           ps2_command(ps2dev, NULL, 0x00F3) ||
> +           ps2_command(ps2dev, NULL, 0x000A))
> +               return -1;
> +
> +       if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
> +               return -1;
> +
> +       /*
> +        * Dolphin's sensor line number is not fixed. It can be calculated
> +        * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
> +        * Further more, we can get device's x_max and y_max by multiplying
> +        * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
> +        *
> +        * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
> +        *      real sensor line number X = 11 + 8 = 19, and
> +        *      real sensor line number Y = 8 + 1 = 9.
> +        *      So, x_max = (19 - 1) * 64 = 1152, and
> +        *          y_max = (9 - 1) * 64 = 512.
> +        */
> +       num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
> +       num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
> +       priv->x_bits = num_x_electrode;
> +       priv->y_bits = num_y_electrode;
> +       priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> +       priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> +
> +       if (alps_exit_command_mode(psmouse))
> +               return -1;
> +
> +       return 0;
> +}
> +
>  static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
>  {
>         struct ps2dev *ps2dev = &psmouse->ps2dev;
> @@ -1571,7 +1706,7 @@ static void alps_set_defaults(struct alps_data *priv)
>                 break;
>         case ALPS_PROTO_V5:
>                 priv->hw_init = alps_hw_init_dolphin_v1;
> -               priv->process_packet = alps_process_packet_v3;
> +               priv->process_packet = alps_process_packet_v5;
>                 priv->decode_fields = alps_decode_dolphin;
>                 priv->set_abs_params = alps_set_abs_params_mt;
>                 priv->nibble_commands = alps_v3_nibble_commands;
> @@ -1645,11 +1780,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
>         if (alps_match_table(psmouse, priv, e7, ec) == 0) {
>                 return 0;
>         } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
> -                  ec[0] == 0x73 && ec[1] == 0x01) {
> +                  ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
>                 priv->proto_version = ALPS_PROTO_V5;
>                 alps_set_defaults(priv);
> -
> -               return 0;
> +               if (alps_dolphin_get_device_area(psmouse, priv))
> +                       return -EIO;
> +               else
> +                       return 0;
>         } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>                 priv->proto_version = ALPS_PROTO_V3;
>                 alps_set_defaults(priv);
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index eee5985..c5c53f4 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,6 +18,10 @@
>  #define ALPS_PROTO_V4  4
>  #define ALPS_PROTO_V5  5
>
> +#define DOLPHIN_COUNT_PER_ELECTRODE    64
> +#define DOLPHIN_PROFILE_XOFFSET                8       /* x-electrode offset */
> +#define DOLPHIN_PROFILE_YOFFSET                1       /* y-electrode offset */
> +
>  /**
>   * struct alps_model_info - touchpad ID table
>   * @signature: E7 response string to match.
> @@ -145,7 +149,8 @@ struct alps_data {
>
>         int (*hw_init)(struct psmouse *psmouse);
>         void (*process_packet)(struct psmouse *psmouse);
> -       void (*decode_fields)(struct alps_fields *f, unsigned char *p);
> +       void (*decode_fields)(struct alps_fields *f, unsigned char *p,
> +                             struct psmouse *psmouse);
>         void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
>
>         int prev_fin;
> --
> 1.8.1.2
>



-- 
Best Regards,
Tommy

^ permalink raw reply

* Re: [PATCH 4/5] input: tc3589x-keypad: support probing from device tree
From: Mark Rutland @ 2013-11-01  0:58 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Dmitry Torokhov, linux-input@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Samuel Ortiz, Lee Jones
In-Reply-To: <1381872071-23455-1-git-send-email-linus.walleij@linaro.org>

On Tue, Oct 15, 2013 at 10:21:11PM +0100, Linus Walleij wrote:
> Implement device tree probing for the tc3589x keypad driver.
> This is modeled on the STMPE keypad driver and tested on the
> Ux500 TVK1281618 UIB.
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
>  drivers/input/keyboard/tc3589x-keypad.c | 63 +++++++++++++++++++++++++++++++--
>  1 file changed, 61 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
> index 208de7c..f6ec0d7 100644
> --- a/drivers/input/keyboard/tc3589x-keypad.c
> +++ b/drivers/input/keyboard/tc3589x-keypad.c
> @@ -297,6 +297,62 @@ static void tc3589x_keypad_close(struct input_dev *input)
>  	tc3589x_keypad_disable(keypad);
>  }
>  
> +#ifdef CONFIG_OF
> +static const struct tc3589x_keypad_platform_data *
> +tc3589x_keypad_of_probe(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct tc3589x_keypad_platform_data *plat;
> +	u32 debounce_ms;
> +	int proplen;
> +
> +	if (!np)
> +		return ERR_PTR(-ENODEV);
> +
> +	plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
> +	if (!plat)
> +		return ERR_PTR(-ENOMEM);
> +
> +	of_property_read_u8(np, "keypad,num-columns", &plat->kcol);
> +	of_property_read_u8(np, "keypad,num-rows", &plat->krow);

These look wrong to me, as almost every single use of of_property_read_u8 (or
of_property_read_u16) do. They read _packed_ values out of the dt, and do not
read (u32) cells as u8s or u16s.

The matrix-keymap binding doesn't define these as 8-bit, and the example
binding they are u32 cells. Either the binding document or this code is wrong.

I'm confused as to how this can work. Are you using /bits/ 8 in your dts?

Thanks,
Mark.

^ permalink raw reply

* changes to ati_remote to support ATI Remote Wonder Plus RF Remote Control
From: Stephen Oberski @ 2013-10-31 14:07 UTC (permalink / raw)
  To: linux-input; +Cc: sfo

Below is a description of proposed changes to the ati_remote kernel module to support
the ATI Remote Wonder Plus RF Remote Control.

I've forwarded these proposed changes to the listed authors of the module for review (Anssi
Hannula <anssi.hannula@XXX.YYY> and Torrey Hoffman <thoffman@XXX.YYY>) and have not heard back
from Anssi Hannul and I include Torrey Hoffman's response below.

Thanks,

-- 
Stephen Oberski sfo@cargocult.ca
289 430 5076
http://ca.linkedin.com/in/stephenoberski/


---------------------------------------- Original Message ----------------------------------------
Subject: Re: [Fwd: changes to ati_remote to support ATI Remote Wonder Plus RF Remote Control]
From:    "Torrey Hoffman" <thoffman@XXX.YYY>
Date:    Mon, October 21, 2013 12:21 pm
To:      sfo@cargocult.ca
--------------------------------------------------------------------------------------------------

Thanks for the heads up, and for working on this.

Unfortunately I no longer have any relevant hardware to test with.  If you would like to be the
official maintainer of this module, that would be excellent.

Best wishes,

Torrey

Proposed changes to the ati_remote kernel loadable module (drivers/media/rc/ati_remote.c) to support the ATI Remote Wonder Plus RF Remote Control
-------------------------------------------------------------------------------------------------------------------------------------------------

Date: Thu Oct 10 10:53:59 EDT 2013

By: Stephen Oberski (sfo@cargocult.ca)

Overview
========

The ati_remote.c USB ATI Remote support loadable kernel module (Version 2.2.0, Linux 3.8.0-31-generic) 
supports the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 receiver (FF receiver) with the Firefly RF Remote Control Model R1000 (FF remote).

It also supports the ATI USB RF Wireless Remote Receiver Part # 5000027000G receiver (ATI receiver) with the Firefly RF Remote Control Model R1000.

However neither the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 receiver nor the ATI USB RF Wireless Remote Receiver Part # 5000027000G receiver
are supported with the ATI Remote Wonder Plus RF Remote Control Part # 5000026900G (ATI remote).

A simple change to the ati_remote.c module results in the support of all combinations of the FF and ATI RF receivers and remotes.

The RF receiver initialization sequence is modified and the processing of the 4 byte remote inputs by the driver is modified to support a leading byte value of 0x15 as well as the current 0x14.

These changes appear to be backward compatible and do no seem to impact the existing behaviour of the module when presented with data from currently supported RF receiver and remote combinations
while allowing currently unsupported combinations to be used.

Problem Scope
=============

It appears that data generated by the ATI remote is never being received by the ati_remote kernel module:

============================== CUT HERE ==============================
# terminal window 1
# modprobe usbmon
# cd /sys/kernel/debug/usb/usbmon
# lsusb
...
Bus 004 Device 008: ID 0bc7:0004 X10 Wireless Technology, Inc. X10 Receiver
...
# rmmod ati_remote
# modprobe ati_remote

# terminal window 2
# grep --line-buffered '4:008' 4u
ffff88018a00d3c0 1361036384 C Ii:4:008:1 -108:8 0
ffff88018a00d240 1385420709 S Io:4:008:2 -115:8 5 = 80010020 14
ffff88018a00d240 1385424393 C Io:4:008:2 0:8 5 >
ffff88018a00d240 1385424401 S Io:4:008:2 -115:8 8 = 80010020 14202020
ffff88018a00d240 1385432392 C Io:4:008:2 0:8 8 >
ffff88018a00da80 1385432519 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1385440394 C Ii:4:008:1 0:8 1 = ff
ffff88018a00da80 1385440399 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415136406 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415136432 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415176406 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415176413 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415216405 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415216411 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415256404 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415256410 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415296405 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415296412 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415336404 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415336410 S Ii:4:008:1 -115:8 8 <
============================== CUT HERE ==============================

We log USB data for the RF receiver in window 2.

In window 1 we enable USB monitoring and unload and reload the ati_remote module.

We can see the 2 initialization strings being sent to the RF receiver via the interrupt out (Io) lines
and then when we press the Firefly key on the FF remote we see the repeated USB packets sent by the RF remote (14658010).

However when we press any keys on the ATI remote no data is logged by usbmon.

This indicates that the RF receiver is ignoring data sent by the ATI remote when initialized by the ati_remote modules.

However when we load the modified version of the ati_remote module we see:

============================== CUT HERE ==============================
# rmmod ati_remote
# insmod ./ati_remote_plus.ko
# grep --line-buffered '4:008' 4u
ffff88018a00da80 2183228699 C Ii:4:008:1 -108:8 0
ffff880181305a80 2197203596 S Io:4:008:2 -115:8 9 = 8080051b 15142024 15
ffff880181305a80 2197216703 C Io:4:008:2 0:8 9 >
ffff880181305a80 2197216761 S Io:4:008:2 -115:8 3 = 808303
ffff880181305a80 2197224702 C Io:4:008:2 0:8 3 >
ffff880181305a80 2197224714 S Io:4:008:2 -115:8 4 = 8084d720
ffff880181305a80 2197232701 C Io:4:008:2 0:8 4 >
ffff8801813050c0 2197232835 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2197240704 C Ii:4:008:1 0:8 1 = 00
ffff8801813050c0 2197240711 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219904713 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219904740 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219944712 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219944720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219984712 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219984718 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2220024715 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2220024722 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2220064715 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2220064721 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2221952713 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2221952740 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2221992712 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2221992720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222032713 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222032720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222072715 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222072721 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222120710 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222120716 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222160714 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222160720 S Ii:4:008:1 -115:8 8 <
============================== CUT HERE ==============================

Here we can see the modified initialization sequence being sent to the RF remote and when we press the Firefly key on the FF remote we see the repeated USB packets sent by the FF remote (14658010)
and when we press the ATI key on the ATI remote we see the repeated USB packets sent by the ATI remote (15222d20).

The conclusion is that the RF receiver initialization must be changed in the ati_remote module in order to support the ATI remote.

History
=======

The changes made to the ati_remote.c module are based on changes made to the LIRC lirc_atiusb.c code [1] 
by Cymen Vig in Feb 2006, who used a USB packet snooping program on Windows, these changes now seems to have disappeared from the current version of LIRC (0.9.0)
and a patch made to the drivers/media/rc/ati_remote.c file for the 2.6.31 kernel [2] which was never committed into the Linux source tree.

Hardware
========

- ATI USB RF Wireless Remote Receiver Part # 5000027000G:

Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.752080] usb 2-2: new low-speed USB device number 4 using uhci_hcd
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929218] usb 2-2: New USB device found, idVendor=0bc7, idProduct=0004
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929227] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929233] usb 2-2: Product: USB Receiver
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929239] usb 2-2: Manufacturer: X10 Wireless Technology Inc
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695613.044063] Registered IR keymap rc-ati-x10

- SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1:

Oct 10 19:14:59 OptiPlex-755 kernel: [534490.804065] usb 4-1: new low-speed USB device number 6 using uhci_hcd
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974451] usb 4-1: New USB device found, idVendor=0bc7, idProduct=0008
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974455] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974458] usb 4-1: Product: USB Receiver
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974461] usb 4-1: Manufacturer: X10 Wireless Technology Inc
Oct 10 19:15:00 OptiPlex-755 kernel: [534491.032019] Registered IR keymap rc-snapstream-firefly

- Firefly RF Remote Control Model R1000

- ATI Remote Wonder Plus RF Remote Control Part # 5000026900G

Product ID Test Coverage
========================

+--------------------------+------+-----+------+-----------------------+---------------------+
|Product Name              +ID    +FF RC+ATI RC+3.8.0-31-generic/x86_64+3.8.0-31-generic/i686|
+--------------------------+------+-----+------+-----------------------+---------------------+
|LOLA_REMOTE_PRODUCT_ID    |0x0002|No   |No    |No                     |No                   |
|LOLA2_REMOTE_PRODUCT_ID   |0x0003|No   |No    |No                     |No                   |
|ATI_REMOTE_PRODUCT_ID     |0x0004|Yes  |Yes   |Yes                    |Yes                  |
|NVIDIA_REMOTE_PRODUCT_ID  |0x0005|No   |No    |No                     |No                   |
|MEDION_REMOTE_PRODUCT_ID  |0x0006|No   |No    |No                     |No                   |
|FIREFLY_REMOTE_PRODUCT_ID |0x0008|Yes  |Yes   |Yes                    |Yes                  |
+--------------------------+------+-----+------+-----------------------+---------------------+

FF RC: Firefly Remote Control
ATI RC: ATI Remote Control
3.8.0-31-generic/x86_64: 64 bit kernel
3.8.0-31-generic/i686: 32 bit kernel
Yes: Successful test
No: Not tested

Userspace Test
==============

A userspace test program [3] was developed to test the Remote receiver and remote control combinations.
It locates the X10 receiver by searching the USB devices for a Vendor ID of 0xbc7, any Product ID is allowed.
It then initializes the X10 receiver via interrupt writes using the new initialization strings discovered by Cymen Vig [1]:

static char init1[] = { 0x80, 0x05, 0x1b, 0x15, 0x14, 0x20, 0x24, 0x15 };
static char init2[] = { 0x83, 0x03 };
static char init3[] = { 0x84, 0xd7, 0x020 };

It then enters a loop and displays all packets received via interrupt reads, along with the computed checksum.

It is assumed that the libusb-dev: "userspace USB programming library development files" package is installed.

Compile and link as follows:

$ gcc -c testlibusb1.c
$ gcc testlibusb1.o -o testlibusb1 -lusb

Unload the "ati_remote" module if loaded:

$ sudo rmmod ati_remote

Run the test program:

$ sudo ./testlibusb1
...
found X10 0xbc7:0x8
found 1 interfaces
found 2 endpoints
endpoint 0 direction IN 0x81
endpoint 1 direction OUT 0x2
X10 open() OK
X10 set configuration OK
X10 claim interface 0 OK
X10 write 8 bytes to endpoint 0x2 OK with 8 bytes written
X10 write 2 bytes to endpoint 0x2 OK with 2 bytes written
X10 write 3 bytes to endpoint 0x2 OK with 3 bytes written
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2
...
^C

In the sample output above the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 was connected as can be seen by the Vendor ID value of 0x8.
Each remote key press generates 4 usb packets, each USB packet is always 4 bytes in length.

The first 4 packets were from the Firefly button on the Firefly RF Remote Control Model R1000, byte 0 is always 0x14 for this remote.

The second 4 packets were from the ATI button on the ATI Remote Wonder Plus RF Remote Control Part # 5000026900G, byte 0 is always 0x15 for this remote.

Other than the value of byte 0 the format of the the USB packets generated by the Firefly and ATI remotes are identical, including the channel mask (byte 3) and checksum calculation.

Exactly the same results are obtained when the ATI USB RF Wireless Remote Receiver Part # 5000027000G is used.

Conclusions
===========

The modified version of the ati_remote driver [4] and the corresponding patch file [5] are provided.

The untested Product ID and remote control combinations need to be tested.
I have no access to the untested RF receivers corresponding to the Product IDs so perhaps users on the linux-input and linux-media 
could test this patch using other RF receiver and remote combinations.

References
==========

[1] http://www.mythtv.org/pipermail/mythtv-users/2006-February/121861.html
[2] http://www.mythtv.org/wiki/ATI_Remote_Wonder_Plus
[3] http://cargocult.ca/testlibusb1.c
[4] http://cargocult.ca/ati_remote_plus.c
[5] http://cargocult.ca/ati_remote.patch

^ permalink raw reply

* Re: [PATCH RESEND v2] Input: add driver for Neonode zForce based touchscreens
From: Dmitry Torokhov @ 2013-10-31  8:30 UTC (permalink / raw)
  To: Heiko Stübner; +Cc: Henrik Rydberg, linux-kernel, linux-input
In-Reply-To: <201310301718.48650.heiko@sntech.de>

On Wed, Oct 30, 2013 at 05:18:47PM +0100, Heiko Stübner wrote:
> This adds a driver for touchscreens using the zforce infrared
> technology from Neonode connected via i2c to the host system.
> 
> It supports multitouch with up to two fingers and tracking of the
> contacts in hardware.


Applied, thank you.

-- 
Dmitry
--
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

* [git pull] Input updates for 3.12-rc7
From: Dmitry Torokhov @ 2013-10-31  8:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, linux-input

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

Hi Linus,

Please pull from:

	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git for-linus
or
	master.kernel.org:/pub/scm/linux/kernel/git/dtor/input.git for-linus

to receive updates for the input subsystem. A bit late than I would
want, but the changes are very minor - a few new device IDs for new
hardware in existing drivers, fix for battery in Wacom devices not be
considered system battery and cause emergency hibernations, and a couple
of other bug fixes.

Changelog:
---------

Andrey Moiseev (1):
      Input: i8042 - i8042_flush fix for a full 8042 buffer

Bastien Nocera (1):
      Input: wacom - export battery scope

David Herrmann (1):
      Input: move name/timer init to input_alloc_dev()

Jason Gerecke (2):
      Input: wacom - add support for ISDv4 0x10F sensor
      Input: wacom - add support for ISDv4 0x10E sensor

Mike Dunn (1):
      Input: pxa27x_keypad - fix NULL pointer dereference

Tim Gardner (1):
      Input: cm109 - convert high volume dev_err() to dev_err_ratelimited()

Yunkang Tang (1):
      Input: ALPS - add support for model found on Dell XT2


Diffstat:
--------

 drivers/input/input.c                  | 10 +++++-----
 drivers/input/keyboard/pxa27x_keypad.c | 11 +++++++++--
 drivers/input/misc/cm109.c             | 14 ++++++++++----
 drivers/input/mouse/alps.c             |  1 +
 drivers/input/serio/i8042.c            | 23 ++++++++++++++---------
 drivers/input/tablet/wacom_sys.c       |  4 ++++
 drivers/input/tablet/wacom_wac.c       |  8 ++++++++
 7 files changed, 51 insertions(+), 20 deletions(-)

-- 
Dmitry


[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCHv8][ 4/4] ARM: imx_v6_v7_defconfig: Enable tsc2007 support.
From: Shawn Guo @ 2013-10-31  8:00 UTC (permalink / raw)
  To: Denis Carikli
  Cc: Eric Bénard, linux-arm-kernel, Sascha Hauer, Rob Herring,
	Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
	devicetree, Dmitry Torokhov, linux-input, Lothar Waßmann,
	Fabio Estevam
In-Reply-To: <1383155923-24076-4-git-send-email-denis@eukrea.com>

On Wed, Oct 30, 2013 at 06:58:43PM +0100, Denis Carikli wrote:
> The eukrea cpuimx35 and cpuimx51 have a tsc2007 touchscreen controller,
>   so we turn it on.
> 
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Stephen Warren <swarren@wwwdotorg.org>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: devicetree@vger.kernel.org
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: linux-input@vger.kernel.org
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: Lothar Waßmann <LW@KARO-electronics.de>
> Cc: Fabio Estevam <fabio.estevam@freescale.com>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Eric Bénard <eric@eukrea.com>
> Signed-off-by: Denis Carikli <denis@eukrea.com>

Applied this one.

Shawn

--
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

* Re: [PATCH] Input: Adding support for touchpad on Dell XT2 model
From: Dmitry Torokhov @ 2013-10-31  7:56 UTC (permalink / raw)
  To: Yunkang Tang
  Cc: cernekee, dturvene, linux-input, ndevos, gaspard, jclift,
	yunkang.tang
In-Reply-To: <1382715581-2584-1-git-send-email-yunkang.tang@cn.alps.com>

On Fri, Oct 25, 2013 at 11:39:41PM +0800, Yunkang Tang wrote:
> Hi all,
> 
> This patch adding the support for touchpad on Dell XT2 model.
> It's a dual device with device ID: 73, 00, 14, that comply with "ALPS_PROTO_V2".
> 
> 
> Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>

Applied, thank you.

> ---
>  drivers/input/mouse/alps.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index ca7a26f..24b3626 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -103,6 +103,7 @@ static const struct alps_model_info alps_model_data[] = {
>  	/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
>  	{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
>  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
> +	{ { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_DUALPOINT },		/* Dell XT2 */
>  	{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },		/* Dell Vostro 1400 */
>  	{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
>  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },				/* Toshiba Tecra A11-11L */
> -- 
> 1.8.1.2
> 

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2 04/19] input: sh_keysc: Enable the driver on all ARM platforms
From: Dmitry Torokhov @ 2013-10-31  7:54 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-sh, linux-arm-kernel, linux-input
In-Reply-To: <1383086274-11049-5-git-send-email-laurent.pinchart+renesas@ideasonboard.com>

On Tue, Oct 29, 2013 at 11:37:39PM +0100, Laurent Pinchart wrote:
> Renesas ARM platforms are transitioning from single-platform to
> multi-platform kernels using the new ARCH_SHMOBILE_MULTI. Make the
> driver available on all ARM platforms to enable it on both ARCH_SHMOBILE
> and ARCH_SHMOBILE_MULTI, and increase build testing coverage with
> COMPILE_TEST.
> 
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: linux-input@vger.kernel.org
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

Applied, thank you.

> ---
>  drivers/input/keyboard/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index c1edd39..28d75c7 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -525,7 +525,7 @@ config KEYBOARD_SUNKBD
>  
>  config KEYBOARD_SH_KEYSC
>  	tristate "SuperH KEYSC keypad support"
> -	depends on SUPERH || ARCH_SHMOBILE
> +	depends on SUPERH || ARM || COMPILE_TEST
>  	help
>  	  Say Y here if you want to use a keypad attached to the KEYSC block
>  	  on SuperH processors such as sh7722 and sh7343.
> -- 
> 1.8.1.5
> 

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 1/1] Input: remove a redundant max() call.
From: Dmitry Torokhov @ 2013-10-31  7:48 UTC (permalink / raw)
  To: Kang Hu; +Cc: linux-input, linux-kernel
In-Reply-To: <1383204394-15399-1-git-send-email-hukangustc@gmail.com>

On Thu, Oct 31, 2013 at 03:26:34PM +0800, Kang Hu wrote:
> dev->hint_events_per_packet is guaranteed to be >= packet_size.
> so an extra max() call is not needed.


Applied, thank you.

> 
> Signed-off-by: Kang Hu <hukangustc@gmail.com>
> ---
>  drivers/input/input.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/input/input.c b/drivers/input/input.c
> index c044699..fb513da 100644
> --- a/drivers/input/input.c
> +++ b/drivers/input/input.c
> @@ -2048,7 +2048,7 @@ int input_register_device(struct input_dev *dev)
>  	if (dev->hint_events_per_packet < packet_size)
>  		dev->hint_events_per_packet = packet_size;
>  
> -	dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
> +	dev->max_vals = dev->hint_events_per_packet + 2;
>  	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
>  	if (!dev->vals) {
>  		error = -ENOMEM;
> -- 
> 1.8.3.1
> 

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] input: i8042 - add PNP modaliases
From: Dmitry Torokhov @ 2013-10-31  7:44 UTC (permalink / raw)
  To: Tom Gundersen; +Cc: linux-input, linux-kernel, Matthew Garrett
In-Reply-To: <1378286856-6384-1-git-send-email-teg@jklm.no>

On Wed, Sep 04, 2013 at 11:27:36AM +0200, Tom Gundersen wrote:
> This allows the module to be autoloaded in the common case.
> 
> In order to work on non-PnP systems the module should be compiled in or loaded
> unconditionally at boot (c.f. modules-load.d(5)), as before.
> 
> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Tom Gundersen <teg@jklm.no>

Applied, thank you.

-- 
Dmitry

^ permalink raw reply

* [PATCH 1/1] Input: remove a redundant max() call.
From: Kang Hu @ 2013-10-31  7:26 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Kang Hu

dev->hint_events_per_packet is guaranteed to be >= packet_size.
so an extra max() call is not needed.

Signed-off-by: Kang Hu <hukangustc@gmail.com>
---
 drivers/input/input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/input/input.c b/drivers/input/input.c
index c044699..fb513da 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -2048,7 +2048,7 @@ int input_register_device(struct input_dev *dev)
 	if (dev->hint_events_per_packet < packet_size)
 		dev->hint_events_per_packet = packet_size;
 
-	dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
+	dev->max_vals = dev->hint_events_per_packet + 2;
 	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
 	if (!dev->vals) {
 		error = -ENOMEM;
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH] Input: evdev: Fall back to vmalloc for client event buffer
From: Dmitry Torokhov @ 2013-10-31  7:26 UTC (permalink / raw)
  To: Daniel Stone; +Cc: linux-input, Henrik Rydberg
In-Reply-To: <1381151213-32690-1-git-send-email-daniels@collabora.com>

On Mon, Oct 07, 2013 at 02:06:53PM +0100, Daniel Stone wrote:
> evdev always tries to allocate the event buffer for clients using
> kzalloc rather than vmalloc, presumably to avoid mapping overhead where
> possible.  However, drivers like bcm5974, which claims support for
> reporting 16 fingers simultaneously, can have an extraordinarily large
> buffer.  The resultant contiguous order-4 allocation attempt fails due
> to fragmentation, and the device is thus unusable until reboot.
> 
> Try kzalloc if we can to avoid the mapping overhead, but if that fails,
> fall back to vzalloc.
> 
> Signed-off-by: Daniel Stone <daniels@collabora.com>

Applied, thank you Daniel.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2 00/19] Enable various Renesas drivers on all ARM platforms
From: Simon Horman @ 2013-10-31  5:52 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-fbdev, Wolfram Sang, Linus Walleij, Guennadi Liakhovetski,
	Thierry Reding, linux-mtd, linux-i2c, Vinod Koul, Joerg Roedel,
	linux-sh, Magnus Damm, Eduardo Valentin, Tomi Valkeinen,
	linux-serial, linux-input, Zhang Rui, Chris Ball,
	Jean-Christophe Plagniol-Villard, linux-media, linux-pwm,
	Samuel Ortiz, linux-pm, Ian Molton, Mark Brown, linux-arm-kernel,
	Ser
In-Reply-To: <1383086274-11049-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com>

On Tue, Oct 29, 2013 at 11:37:35PM +0100, Laurent Pinchart wrote:
> Hello,
> 
> This patch series, based on v3.12-rc7, prepares various Renesas drivers
> for migration to multiplatform kernels by enabling their compilation or
> otherwise fixing them on all ARM platforms. The patches are pretty
> straightforward and are described in their commit message.
> 
> Changes since v1:
> 
> - The drivers can also be selected when COMPILE_TEST is enabled, regardless of
>   the architecture. This should provide a good compromise between wide build
>   test coverage and not clobbering configuration with drivers useless on
>   non-SuperH, non-ARM platforms.
> 
> - DMA configuration is now unconditional in patch 08/19
> 
> I'd like to get all these patches merged in v3.14. As they will need to go
> through their respective subsystems' trees, I would appreciate if all
> maintainers involved could notify me when they merge patches from this series
> in their tree to help me tracking the merge status. I don't plan to send pull
> requests individually for these patches, and I will repost patches
> individually if changes are requested during review.
> 
> If you believe the issue should be solved in a different way please reply to
> the cover letter to let other maintainers chime in.

All patches, including the v3 ones present in the thread at this time:

Acked-by: Simon Horman <horms@verge.net.au>

> Cc: Chris Ball <cjb@laptop.org>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: Eduardo Valentin <eduardo.valentin@ti.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com>
> Cc: Ian Molton <ian@mnementh.co.uk>
> Cc: iommu@lists.linux-foundation.org
> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Magnus Damm <magnus.damm@gmail.com>
> Cc: Mark Brown <broonie@kernel.org>
> Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
> Cc: Samuel Ortiz <samuel@sortiz.org>
> Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> Cc: Vinod Koul <vinod.koul@intel.com>
> Cc: Wolfram Sang <wsa@the-dreams.de>
> Cc: Zhang Rui <rui.zhang@intel.com>
> Cc: dmaengine@vger.kernel.org
> Cc: linux-fbdev@vger.kernel.org
> Cc: linux-i2c@vger.kernel.org
> Cc: linux-input@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-media@vger.kernel.org
> Cc: linux-mmc@vger.kernel.org
> Cc: linux-mtd@lists.infradead.org
> Cc: linux-pm@vger.kernel.org
> Cc: linux-pwm@vger.kernel.org
> Cc: linux-serial@vger.kernel.org
> Cc: linux-spi@vger.kernel.org
> Cc: netdev@vger.kernel.org
> 
> Laurent Pinchart (19):
>   serial: sh-sci: Enable the driver on all ARM platforms
>   DMA: shdma: Enable the driver on all ARM platforms
>   i2c: sh_mobile: Enable the driver on all ARM platforms
>   input: sh_keysc: Enable the driver on all ARM platforms
>   iommu: shmobile: Enable the driver on all ARM platforms
>   i2c: rcar: Enable the driver on all ARM platforms
>   v4l: sh_vou: Enable the driver on all ARM platforms
>   mmc: sdhi: Enable the driver on all ARM platforms
>   mmc: sh_mmcif: Enable the driver on all ARM platforms
>   mtd: sh_flctl: Enable the driver on all ARM platforms
>   net: sh_eth: Set receive alignment correctly on all ARM platforms
>   irda: sh_irda: Enable the driver on all ARM platforms
>   pinctrl: sh-pfc: Enable the driver on all ARM platforms
>   pwm: pwm-renesas-tpu: Enable the driver on all ARM platforms
>   sh: intc: Enable the driver on all ARM platforms
>   spi: sh_msiof: Enable the driver on all ARM platforms
>   spi: sh_hspi: Enable the driver on all ARM platforms
>   thermal: rcar-thermal: Enable the driver on all ARM platforms
>   fbdev: sh-mobile-lcdcfb: Enable the driver on all ARM platforms
> 
>  drivers/dma/sh/Kconfig                | 2 +-
>  drivers/dma/sh/shdmac.c               | 6 +++---
>  drivers/i2c/busses/Kconfig            | 4 ++--
>  drivers/input/keyboard/Kconfig        | 2 +-
>  drivers/iommu/Kconfig                 | 2 +-
>  drivers/media/platform/Kconfig        | 2 +-
>  drivers/mmc/host/Kconfig              | 4 ++--
>  drivers/mmc/host/tmio_mmc_dma.c       | 4 +---
>  drivers/mtd/nand/Kconfig              | 2 +-
>  drivers/net/ethernet/renesas/sh_eth.c | 2 +-
>  drivers/net/ethernet/renesas/sh_eth.h | 2 +-
>  drivers/net/irda/Kconfig              | 2 +-
>  drivers/pinctrl/Makefile              | 2 +-
>  drivers/pinctrl/sh-pfc/Kconfig        | 2 +-
>  drivers/pwm/Kconfig                   | 2 +-
>  drivers/sh/intc/Kconfig               | 2 +-
>  drivers/spi/Kconfig                   | 4 ++--
>  drivers/thermal/Kconfig               | 2 +-
>  drivers/tty/serial/Kconfig            | 2 +-
>  drivers/video/Kconfig                 | 6 +++---
>  20 files changed, 27 insertions(+), 29 deletions(-)
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply

* changes to ati_remote to support ATI Remote Wonder Plus RF Remote Control
From: Stephen Oberski @ 2013-10-30 20:31 UTC (permalink / raw)
  To: linux-input; +Cc: sfo

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


Attached is a text document describing proposed changes to the ati_remote kernel module to support
the ATI Remote Wonder Plus RF Remote Control.

I've forwarded these proposed changes to the listed authors of the module for review (Anssi
Hannula <anssi.hannula@XXX.YYY> and Torrey Hoffman <thoffman@XXX.YYY>) and have not heard back
from Anssi Hannul and I include Torrey Hoffman's response below.

Thanks,

-- 
Stephen Oberski sfo@cargocult.ca
289 430 5076
http://ca.linkedin.com/in/stephenoberski/


---------------------------------------- Original Message ----------------------------------------
Subject: Re: [Fwd: changes to ati_remote to support ATI Remote Wonder Plus RF Remote Control]
From:    "Torrey Hoffman" <thoffman@XXX.YYY>
Date:    Mon, October 21, 2013 12:21 pm
To:      sfo@cargocult.ca
--------------------------------------------------------------------------------------------------

Thanks for the heads up, and for working on this.

Unfortunately I no longer have any relevant hardware to test with.  If you would like to be the
official maintainer of this module, that would be excellent.

Best wishes,

Torrey


[-- Attachment #2: linux-input_ati_remote-problem.txt --]
[-- Type: text/plain, Size: 12888 bytes --]

Proposed changes to the ati_remote kernel loadable module (drivers/media/rc/ati_remote.c) to support the ATI Remote Wonder Plus RF Remote Control
-------------------------------------------------------------------------------------------------------------------------------------------------

Date: Thu Oct 10 10:53:59 EDT 2013

By: Stephen Oberski (sfo@cargocult.ca)

Overview
========

The ati_remote.c USB ATI Remote support loadable kernel module (Version 2.2.0, Linux 3.8.0-31-generic) 
supports the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 receiver (FF receiver) with the Firefly RF Remote Control Model R1000 (FF remote).

It also supports the ATI USB RF Wireless Remote Receiver Part # 5000027000G receiver (ATI receiver) with the Firefly RF Remote Control Model R1000.

However neither the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 receiver nor the ATI USB RF Wireless Remote Receiver Part # 5000027000G receiver
are supported with the ATI Remote Wonder Plus RF Remote Control Part # 5000026900G (ATI remote).

A simple change to the ati_remote.c module results in the support of all combinations of the FF and ATI RF receivers and remotes.

The RF receiver initialization sequence is modified and the processing of the 4 byte remote inputs by the driver is modified to support a leading byte value of 0x15 as well as the current 0x14.

These changes appear to be backward compatible and do no seem to impact the existing behaviour of the module when presented with data from currently supported RF receiver and remote combinations
while allowing currently unsupported combinations to be used.

Problem Scope
=============

It appears that data generated by the ATI remote is never being received by the ati_remote kernel module:

============================== CUT HERE ==============================
# terminal window 1
# modprobe usbmon
# cd /sys/kernel/debug/usb/usbmon
# lsusb
...
Bus 004 Device 008: ID 0bc7:0004 X10 Wireless Technology, Inc. X10 Receiver
...
# rmmod ati_remote
# modprobe ati_remote

# terminal window 2
# grep --line-buffered '4:008' 4u
ffff88018a00d3c0 1361036384 C Ii:4:008:1 -108:8 0
ffff88018a00d240 1385420709 S Io:4:008:2 -115:8 5 = 80010020 14
ffff88018a00d240 1385424393 C Io:4:008:2 0:8 5 >
ffff88018a00d240 1385424401 S Io:4:008:2 -115:8 8 = 80010020 14202020
ffff88018a00d240 1385432392 C Io:4:008:2 0:8 8 >
ffff88018a00da80 1385432519 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1385440394 C Ii:4:008:1 0:8 1 = ff
ffff88018a00da80 1385440399 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415136406 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415136432 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415176406 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415176413 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415216405 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415216411 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415256404 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415256410 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415296405 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415296412 S Ii:4:008:1 -115:8 8 <
ffff88018a00da80 1415336404 C Ii:4:008:1 0:8 4 = 14658010
ffff88018a00da80 1415336410 S Ii:4:008:1 -115:8 8 <
============================== CUT HERE ==============================

We log USB data for the RF receiver in window 2.

In window 1 we enable USB monitoring and unload and reload the ati_remote module.

We can see the 2 initialization strings being sent to the RF receiver via the interrupt out (Io) lines
and then when we press the Firefly key on the FF remote we see the repeated USB packets sent by the RF remote (14658010).

However when we press any keys on the ATI remote no data is logged by usbmon.

This indicates that the RF receiver is ignoring data sent by the ATI remote when initialized by the ati_remote modules.

However when we load the modified version of the ati_remote module we see:

============================== CUT HERE ==============================
# rmmod ati_remote
# insmod ./ati_remote_plus.ko
# grep --line-buffered '4:008' 4u
ffff88018a00da80 2183228699 C Ii:4:008:1 -108:8 0
ffff880181305a80 2197203596 S Io:4:008:2 -115:8 9 = 8080051b 15142024 15
ffff880181305a80 2197216703 C Io:4:008:2 0:8 9 >
ffff880181305a80 2197216761 S Io:4:008:2 -115:8 3 = 808303
ffff880181305a80 2197224702 C Io:4:008:2 0:8 3 >
ffff880181305a80 2197224714 S Io:4:008:2 -115:8 4 = 8084d720
ffff880181305a80 2197232701 C Io:4:008:2 0:8 4 >
ffff8801813050c0 2197232835 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2197240704 C Ii:4:008:1 0:8 1 = 00
ffff8801813050c0 2197240711 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219904713 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219904740 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219944712 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219944720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2219984712 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2219984718 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2220024715 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2220024722 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2220064715 C Ii:4:008:1 0:8 4 = 14658010
ffff8801813050c0 2220064721 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2221952713 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2221952740 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2221992712 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2221992720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222032713 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222032720 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222072715 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222072721 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222120710 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222120716 S Ii:4:008:1 -115:8 8 <
ffff8801813050c0 2222160714 C Ii:4:008:1 0:8 4 = 15222d20
ffff8801813050c0 2222160720 S Ii:4:008:1 -115:8 8 <
============================== CUT HERE ==============================

Here we can see the modified initialization sequence being sent to the RF remote and when we press the Firefly key on the FF remote we see the repeated USB packets sent by the FF remote (14658010)
and when we press the ATI key on the ATI remote we see the repeated USB packets sent by the ATI remote (15222d20).

The conclusion is that the RF receiver initialization must be changed in the ati_remote module in order to support the ATI remote.

History
=======

The changes made to the ati_remote.c module are based on changes made to the LIRC lirc_atiusb.c code [1] 
by Cymen Vig in Feb 2006, who used a USB packet snooping program on Windows, these changes now seems to have disappeared from the current version of LIRC (0.9.0)
and a patch made to the drivers/media/rc/ati_remote.c file for the 2.6.31 kernel [2] which was never committed into the Linux source tree.

Hardware
========

- ATI USB RF Wireless Remote Receiver Part # 5000027000G:

Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.752080] usb 2-2: new low-speed USB device number 4 using uhci_hcd
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929218] usb 2-2: New USB device found, idVendor=0bc7, idProduct=0004
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929227] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929233] usb 2-2: Product: USB Receiver
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695612.929239] usb 2-2: Manufacturer: X10 Wireless Technology Inc
Oct 10 16:07:08 acer-Veriton-N282G kernel: [695613.044063] Registered IR keymap rc-ati-x10

- SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1:

Oct 10 19:14:59 OptiPlex-755 kernel: [534490.804065] usb 4-1: new low-speed USB device number 6 using uhci_hcd
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974451] usb 4-1: New USB device found, idVendor=0bc7, idProduct=0008
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974455] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974458] usb 4-1: Product: USB Receiver
Oct 10 19:14:59 OptiPlex-755 kernel: [534490.974461] usb 4-1: Manufacturer: X10 Wireless Technology Inc
Oct 10 19:15:00 OptiPlex-755 kernel: [534491.032019] Registered IR keymap rc-snapstream-firefly

- Firefly RF Remote Control Model R1000

- ATI Remote Wonder Plus RF Remote Control Part # 5000026900G

Product ID Test Coverage
========================

+--------------------------+------+-----+------+-----------------------+---------------------+
|Product Name              +ID    +FF RC+ATI RC+3.8.0-31-generic/x86_64+3.8.0-31-generic/i686|
+--------------------------+------+-----+------+-----------------------+---------------------+
|LOLA_REMOTE_PRODUCT_ID    |0x0002|No   |No    |No                     |No                   |
|LOLA2_REMOTE_PRODUCT_ID   |0x0003|No   |No    |No                     |No                   |
|ATI_REMOTE_PRODUCT_ID     |0x0004|Yes  |Yes   |Yes                    |Yes                  |
|NVIDIA_REMOTE_PRODUCT_ID  |0x0005|No   |No    |No                     |No                   |
|MEDION_REMOTE_PRODUCT_ID  |0x0006|No   |No    |No                     |No                   |
|FIREFLY_REMOTE_PRODUCT_ID |0x0008|Yes  |Yes   |Yes                    |Yes                  |
+--------------------------+------+-----+------+-----------------------+---------------------+

FF RC: Firefly Remote Control
ATI RC: ATI Remote Control
3.8.0-31-generic/x86_64: 64 bit kernel
3.8.0-31-generic/i686: 32 bit kernel
Yes: Successful test
No: Not tested

Userspace Test
==============

A userspace test program [3] was developed to test the Remote receiver and remote control combinations.
It locates the X10 receiver by searching the USB devices for a Vendor ID of 0xbc7, any Product ID is allowed.
It then initializes the X10 receiver via interrupt writes using the new initialization strings discovered by Cymen Vig [1]:

static char init1[] = { 0x80, 0x05, 0x1b, 0x15, 0x14, 0x20, 0x24, 0x15 };
static char init2[] = { 0x83, 0x03 };
static char init3[] = { 0x84, 0xd7, 0x020 };

It then enters a loop and displays all packets received via interrupt reads, along with the computed checksum.

It is assumed that the libusb-dev: "userspace USB programming library development files" package is installed.

Compile and link as follows:

$ gcc -c testlibusb1.c
$ gcc testlibusb1.o -o testlibusb1 -lusb

Unload the "ati_remote" module if loaded:

$ sudo rmmod ati_remote

Run the test program:

$ sudo ./testlibusb1
...
found X10 0xbc7:0x8
found 1 interfaces
found 2 endpoints
endpoint 0 direction IN 0x81
endpoint 1 direction OUT 0x2
X10 open() OK
X10 set configuration OK
X10 claim interface 0 OK
X10 write 8 bytes to endpoint 0x2 OK with 8 bytes written
X10 write 2 bytes to endpoint 0x2 OK with 2 bytes written
X10 write 3 bytes to endpoint 0x2 OK with 3 bytes written
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
 0:14  1:e5  2:00  3:10 checksum e5 
X10 read from endpoint 0x1 returned 4
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2 
X10 read from endpoint 0x1 returned 4
 0:15  1:a2  2:ad  3:20 checksum a2
...
^C

In the sample output above the SnapStream Media Firefly PC Remote Wireless Receiver Model R1000-1 was connected as can be seen by the Vendor ID value of 0x8.
Each remote key press generates 4 usb packets, each USB packet is always 4 bytes in length.

The first 4 packets were from the Firefly button on the Firefly RF Remote Control Model R1000, byte 0 is always 0x14 for this remote.

The second 4 packets were from the ATI button on the ATI Remote Wonder Plus RF Remote Control Part # 5000026900G, byte 0 is always 0x15 for this remote.

Other than the value of byte 0 the format of the the USB packets generated by the Firefly and ATI remotes are identical, including the channel mask (byte 3) and checksum calculation.

Exactly the same results are obtained when the ATI USB RF Wireless Remote Receiver Part # 5000027000G is used.

Conclusions
===========

The modified version of the ati_remote driver [4] and the corresponding patch file [5] are provided.

The untested Product ID and remote control combinations need to be tested.
I have no access to the untested RF receivers corresponding to the Product IDs so perhaps users on the linux-input and linux-media 
could test this patch using other RF receiver and remote combinations.

References
==========

[1] http://www.mythtv.org/pipermail/mythtv-users/2006-February/121861.html
[2] http://www.mythtv.org/wiki/ATI_Remote_Wonder_Plus
[3] http://cargocult.ca/testlibusb1.c
[4] http://cargocult.ca/ati_remote_plus.c
[5] http://cargocult.ca/ati_remote.patch

^ permalink raw reply

* [PATCHv8][ 4/4] ARM: imx_v6_v7_defconfig: Enable tsc2007 support.
From: Denis Carikli @ 2013-10-30 17:58 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Eric Bénard, linux-arm-kernel, Sascha Hauer, Denis Carikli,
	Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
	Ian Campbell, devicetree, Dmitry Torokhov, linux-input,
	Lothar Waßmann, Fabio Estevam
In-Reply-To: <1383155923-24076-1-git-send-email-denis@eukrea.com>

The eukrea cpuimx35 and cpuimx51 have a tsc2007 touchscreen controller,
  so we turn it on.

Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
 arch/arm/configs/imx_v6_v7_defconfig |    1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 1a0e3d9..53e854a 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -130,6 +130,7 @@ CONFIG_MOUSE_PS2_ELANTECH=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_EGALAX=y
 CONFIG_TOUCHSCREEN_MC13783=y
+CONFIG_TOUCHSCREEN_TSC2007=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_MMA8450=y
 CONFIG_SERIO_SERPORT=m
-- 
1.7.9.5

--
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 related

* [PATCHv8][ 3/4] ARM: dts: cpuimx51 Add touchscreen support.
From: Denis Carikli @ 2013-10-30 17:58 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Eric Bénard, linux-arm-kernel, Sascha Hauer, Denis Carikli,
	Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
	Ian Campbell, devicetree, Dmitry Torokhov, linux-input,
	Lothar Waßmann
In-Reply-To: <1383155923-24076-1-git-send-email-denis@eukrea.com>

Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v7->v8:
- Added Shawn Guo in the cc list.
---
 arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
index 8638656..34ca8d3a 100644
--- a/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
+++ b/arch/arm/boot/dts/imx51-eukrea-cpuimx51.dtsi
@@ -42,6 +42,17 @@
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 	};
+
+	tsc2007: tsc2007@49 {
+		compatible = "ti,tsc2007";
+		reg = <0x49>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_tsc2007_1>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <0x0 0x8>;
+		gpios = <&gpio4 0 0>;
+		ti,x-plate-ohms = <180>;
+	};
 };
 
 &iomuxc {
-- 
1.7.9.5

--
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 related

* [PATCHv8][ 2/4] ARM: dts: cpuimx35 Add touchscreen support.
From: Denis Carikli @ 2013-10-30 17:58 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Eric Bénard, linux-arm-kernel, Sascha Hauer, Denis Carikli,
	Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
	Ian Campbell, devicetree, Dmitry Torokhov, linux-input,
	Lothar Waßmann
In-Reply-To: <1383155923-24076-1-git-send-email-denis@eukrea.com>

Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v7->v8:
- Added Shawn Guo in the cc list.
---
 arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
index 2c2d4cd..a22230b 100644
--- a/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
+++ b/arch/arm/boot/dts/imx35-eukrea-cpuimx35.dtsi
@@ -41,6 +41,17 @@
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 	};
+
+	tsc2007: tsc2007@48 {
+		compatible = "ti,tsc2007";
+		reg = <0x48>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_tsc2007_1>;
+		interrupt-parent = <&gpio3>;
+		interrupts = <0x2 0x8>;
+		gpios = <&gpio3 2 0>;
+		ti,x-plate-ohms = <180>;
+	};
 };
 
 &iomuxc {
-- 
1.7.9.5

--
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 related

* [PATCHv8][ 1/4] Input: tsc2007: Add device tree support.
From: Denis Carikli @ 2013-10-30 17:58 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Eric Bénard, linux-arm-kernel, Sascha Hauer, Denis Carikli,
	Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
	Ian Campbell, devicetree, Dmitry Torokhov, linux-input,
	Lothar Waßmann

Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Lothar Waßmann <LW@KARO-electronics.de>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v7->v8:
- Fixed the lack of x and z fuzz properties.
- The pendown gpio is better documented.
- Added Shawn Guo in the cc list.
---
 .../bindings/input/touchscreen/tsc2007.txt         |   48 +++++
 drivers/input/touchscreen/tsc2007.c                |  204 ++++++++++++++++----
 2 files changed, 211 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
new file mode 100644
index 0000000..0b5c3a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
@@ -0,0 +1,48 @@
+* Texas Instruments tsc2007 touchscreen controller
+
+Required properties:
+- compatible: must be "ti,tsc2007".
+- reg: I2C address of the chip.
+- ti,x-plate-ohms: X-plate resistance in ohms.
+
+Optional properties:
+- gpios: the interrupt gpio the chip is connected to (trough the penirq pin).
+  The penirq pin goes to low when the panel is touched.
+  (see GPIO binding[2] for more details).
+- interrupt-parent: the phandle for the gpio controller
+  (see interrupt binding[1]).
+- interrupts: (gpio) interrupt to which the chip is connected
+  (see interrupt binding[1]).
+- pinctrl-0: Should specify pin control groups used for the gpio
+  (see pinctrl bindings[0]).
+- pinctrl-names: Should contain only one value - "default"
+  (see pinctrl bindings[0]).
+- ti,max-rt: maximum pressure.
+- ti,fuzzx: specifies the absolute input fuzz x value.
+  If set, it will permit noise in the data up to +- the value given to the fuzz
+  parameter, that is used to filter noise from the event stream.
+- ti,fuzzy: specifies the absolute input fuzz y value.
+- ti,fuzzz: specifies the absolute input fuzz z value.
+- ti,poll-period: how much time to wait(in millisecond) before reading again the
+  values from the tsc2007.
+
+[0]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+[1]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[2]: Documentation/devicetree/bindings/gpio/gpio.txt
+
+Example:
+	&i2c1 {
+		/* ... */
+		tsc2007@49 {
+			compatible = "ti,tsc2007";
+			reg = <0x49>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_tsc2007_1>;
+			interrupt-parent = <&gpio4>;
+			interrupts = <0x0 0x8>;
+			gpios = <&gpio4 0 0>;
+			ti,x-plate-ohms = <180>;
+		};
+
+		/* ... */
+	};
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 0b67ba4..3168a99 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -26,6 +26,9 @@
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #define TSC2007_MEASURE_TEMP0		(0x0 << 4)
 #define TSC2007_MEASURE_AUX		(0x2 << 4)
@@ -74,7 +77,12 @@ struct tsc2007 {
 	u16			max_rt;
 	unsigned long		poll_delay;
 	unsigned long		poll_period;
+	int			fuzzx;
+	int			fuzzy;
+	int			fuzzz;
+	char			of;
 
+	unsigned		gpio;
 	int			irq;
 
 	wait_queue_head_t	wait;
@@ -84,6 +92,11 @@ struct tsc2007 {
 	void			(*clear_penirq)(void);
 };
 
+static int tsc2007_get_pendown_state_dt(struct tsc2007 *ts)
+{
+	return !gpio_get_value(ts->gpio);
+}
+
 static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
 {
 	s32 data;
@@ -142,6 +155,14 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
 	return rt;
 }
 
+static bool tsc2007_is_pen_down_valid(struct tsc2007 *ts)
+{
+	if (ts->of)
+		return gpio_is_valid(ts->gpio);
+	else
+		return ts->get_pendown_state ? true : false;
+}
+
 static bool tsc2007_is_pen_down(struct tsc2007 *ts)
 {
 	/*
@@ -158,10 +179,13 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
 	 * to fall back on the pressure reading.
 	 */
 
-	if (!ts->get_pendown_state)
+	if (!tsc2007_is_pen_down_valid(ts))
 		return true;
 
-	return ts->get_pendown_state();
+	if (ts->of)
+		return tsc2007_get_pendown_state_dt(ts);
+	else
+		return ts->get_pendown_state();
 }
 
 static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
@@ -178,7 +202,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
 
 		rt = tsc2007_calculate_pressure(ts, &tc);
 
-		if (rt == 0 && !ts->get_pendown_state) {
+		if (!rt && !tsc2007_is_pen_down_valid(ts)) {
 			/*
 			 * If pressure reported is 0 and we don't have
 			 * callback to check pendown state, we have to
@@ -228,7 +252,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
 {
 	struct tsc2007 *ts = handle;
 
-	if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
+	if (tsc2007_is_pen_down(ts))
 		return IRQ_WAKE_THREAD;
 
 	if (ts->clear_penirq)
@@ -273,34 +297,71 @@ static void tsc2007_close(struct input_dev *input_dev)
 	tsc2007_stop(ts);
 }
 
-static int tsc2007_probe(struct i2c_client *client,
-				   const struct i2c_device_id *id)
+#ifdef CONFIG_OF
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+			    struct device_node *np)
 {
-	struct tsc2007 *ts;
-	struct tsc2007_platform_data *pdata = client->dev.platform_data;
-	struct input_dev *input_dev;
-	int err;
-
-	if (!pdata) {
-		dev_err(&client->dev, "platform data is required!\n");
+	int err = 0;
+	u32 val32;
+	u64 val64;
+
+	if (!of_property_read_u32(np, "ti,max-rt", &val32))
+		ts->max_rt = val32;
+	else
+		ts->max_rt = MAX_12BIT;
+
+	if (!of_property_read_u32(np, "ti,fuzzx", &val32))
+		ts->fuzzx = val32;
+
+	if (!of_property_read_u32(np, "ti,fuzzy", &val32))
+		ts->fuzzy = val32;
+
+	if (!of_property_read_u32(np, "ti,fuzzz", &val32))
+		ts->fuzzz = val32;
+
+	if (!of_property_read_u64(np, "ti,poll-period", &val64))
+		ts->poll_period = val64;
+	else
+		ts->poll_period = 1;
+
+	if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) {
+		ts->x_plate_ohms = val32;
+	} else {
+		dev_err(&client->dev,
+			"Error: lacking ti,x-plate-ohms devicetree property. (err %d).",
+			err);
 		return -EINVAL;
 	}
 
-	if (!i2c_check_functionality(client->adapter,
-				     I2C_FUNC_SMBUS_READ_WORD_DATA))
-		return -EIO;
+	ts->gpio = of_get_gpio(np, 0);
+	if (!gpio_is_valid(ts->gpio))
+		dev_err(&client->dev,
+			"GPIO not found (of_get_gpio returned %d)\n",
+			ts->gpio);
 
-	ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!ts || !input_dev) {
-		err = -ENOMEM;
-		goto err_free_mem;
-	}
+	/* Used to detect if it is probed trough the device tree,
+	 * in order to be able to use that information in the IRQ handler.
+	 */
+	ts->of = 1;
 
-	ts->client = client;
-	ts->irq = client->irq;
-	ts->input = input_dev;
-	init_waitqueue_head(&ts->wait);
+	return 0;
+}
+#else
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+			    struct device_node *np)
+{
+	return -ENODEV;
+}
+#endif
+
+static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts,
+			      struct tsc2007_platform_data *pdata,
+			      const struct i2c_device_id *id)
+{
+	if (!pdata) {
+		dev_err(&client->dev, "platform data is required!\n");
+		return -EINVAL;
+	}
 
 	ts->model             = pdata->model;
 	ts->x_plate_ohms      = pdata->x_plate_ohms;
@@ -309,13 +370,59 @@ static int tsc2007_probe(struct i2c_client *client,
 	ts->poll_period       = pdata->poll_period ? : 1;
 	ts->get_pendown_state = pdata->get_pendown_state;
 	ts->clear_penirq      = pdata->clear_penirq;
+	ts->fuzzx             = pdata->fuzzx;
+	ts->fuzzy             = pdata->fuzzy;
+	ts->fuzzz             = pdata->fuzzz;
 
 	if (pdata->x_plate_ohms == 0) {
 		dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
-		err = -EINVAL;
-		goto err_free_mem;
+		return -EINVAL;
 	}
 
+	/* Used to detect if it is probed trough the device tree,
+	 * in order to be able to use that information in the IRQ handler.
+	 */
+	ts->of = 0;
+
+	return 0;
+}
+
+static int tsc2007_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device_node *np = client->dev.of_node;
+	struct tsc2007_platform_data *pdata = client->dev.platform_data;
+	struct tsc2007 *ts;
+	struct input_dev *input_dev;
+	int err = 0;
+
+	ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	if (np)
+		err = tsc2007_probe_dt(client, ts, np);
+	else
+		err = tsc2007_probe_pdev(client, ts, pdata, id);
+
+	if (err)
+		return err;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		err = -ENOMEM;
+		goto err_free_input;
+	};
+
+	ts->client = client;
+	ts->irq = client->irq;
+	ts->input = input_dev;
+	init_waitqueue_head(&ts->wait);
+
 	snprintf(ts->phys, sizeof(ts->phys),
 		 "%s/input0", dev_name(&client->dev));
 
@@ -331,19 +438,21 @@ static int tsc2007_probe(struct i2c_client *client,
 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
-			pdata->fuzzz, 0);
+			     ts->fuzzz, 0);
 
-	if (pdata->init_platform_hw)
-		pdata->init_platform_hw();
+	if (!np) {
+		if (pdata->init_platform_hw)
+			pdata->init_platform_hw();
+	}
 
 	err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
 				   IRQF_ONESHOT, client->dev.driver->name, ts);
 	if (err < 0) {
 		dev_err(&client->dev, "irq %d busy?\n", ts->irq);
-		goto err_free_mem;
+		goto err_free_input;
 	}
 
 	tsc2007_stop(ts);
@@ -358,23 +467,27 @@ static int tsc2007_probe(struct i2c_client *client,
 
  err_free_irq:
 	free_irq(ts->irq, ts);
-	if (pdata->exit_platform_hw)
-		pdata->exit_platform_hw();
- err_free_mem:
+	if (!np) {
+		if (pdata->exit_platform_hw)
+			pdata->exit_platform_hw();
+	}
+ err_free_input:
 	input_free_device(input_dev);
-	kfree(ts);
 	return err;
 }
 
 static int tsc2007_remove(struct i2c_client *client)
 {
+	struct device_node *np = client->dev.of_node;
 	struct tsc2007	*ts = i2c_get_clientdata(client);
 	struct tsc2007_platform_data *pdata = client->dev.platform_data;
 
 	free_irq(ts->irq, ts);
 
-	if (pdata->exit_platform_hw)
-		pdata->exit_platform_hw();
+	if (!np) {
+		if (pdata->exit_platform_hw)
+			pdata->exit_platform_hw();
+	}
 
 	input_unregister_device(ts->input);
 	kfree(ts);
@@ -389,10 +502,19 @@ static const struct i2c_device_id tsc2007_idtable[] = {
 
 MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
 
+#ifdef CONFIG_OF
+static const struct of_device_id tsc2007_of_match[] = {
+	{ .compatible = "ti,tsc2007" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tsc2007_of_match);
+#endif
+
 static struct i2c_driver tsc2007_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "tsc2007"
+		.name	= "tsc2007",
+		.of_match_table = of_match_ptr(tsc2007_of_match),
 	},
 	.id_table	= tsc2007_idtable,
 	.probe		= tsc2007_probe,
-- 
1.7.9.5

--
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 related

* [PATCH RESEND v2] Input: add driver for Neonode zForce based touchscreens
From: Heiko Stübner @ 2013-10-30 16:18 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Henrik Rydberg, linux-kernel, linux-input

This adds a driver for touchscreens using the zforce infrared
technology from Neonode connected via i2c to the host system.

It supports multitouch with up to two fingers and tracking of the
contacts in hardware.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
changes since v1:
- address comments from Dmitry Torokhov
  but I kept the access_mutex due to the possible race I described in the mail:
  - touch -> interrupt
  - isr reads first packet
  - user closes device -> stop command sent
  - isr reads payload
- address comments from Henrik Rydberg, letting the input system collect
  singletouch from the multitouch data using the appropriate functions

 drivers/input/touchscreen/Kconfig       |   13 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/zforce_ts.c   |  826 +++++++++++++++++++++++++++++++
 include/linux/platform_data/zforce_ts.h |   26 +
 4 files changed, 866 insertions(+)
 create mode 100644 drivers/input/touchscreen/zforce_ts.c
 create mode 100644 include/linux/platform_data/zforce_ts.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9758b..ade11b7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -919,4 +919,17 @@ config TOUCHSCREEN_TPS6507X
 	  To compile this driver as a module, choose M here: the
 	  module will be called tps6507x_ts.
 
+config TOUCHSCREEN_ZFORCE
+	tristate "Neonode zForce infrared touchscreens"
+	depends on I2C
+	depends on GPIOLIB
+	help
+	  Say Y here if you have a touchscreen using the zforce
+	  infraread technology from Neonode.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zforce_ts.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f5216c1..7587883 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -75,3 +75,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
new file mode 100644
index 0000000..f4cfd4d
--- /dev/null
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2012-2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * based in parts on Nook zforce driver
+ *
+ * Copyright (C) 2010 Barnes & Noble, Inc.
+ * Author: Pieter Truter<ptruter@intrinsyc.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/input/mt.h>
+#include <linux/platform_data/zforce_ts.h>
+
+#define WAIT_TIMEOUT		msecs_to_jiffies(1000)
+
+#define FRAME_START		0xee
+
+/* Offsets of the different parts of the payload the controller sends */
+#define PAYLOAD_HEADER		0
+#define PAYLOAD_LENGTH		1
+#define PAYLOAD_BODY		2
+
+/* Response offsets */
+#define RESPONSE_ID		0
+#define RESPONSE_DATA		1
+
+/* Commands */
+#define COMMAND_DEACTIVATE	0x00
+#define COMMAND_INITIALIZE	0x01
+#define COMMAND_RESOLUTION	0x02
+#define COMMAND_SETCONFIG	0x03
+#define COMMAND_DATAREQUEST	0x04
+#define COMMAND_SCANFREQ	0x08
+#define COMMAND_STATUS		0X1e
+
+/*
+ * Responses the controller sends as a result of
+ * command requests
+ */
+#define RESPONSE_DEACTIVATE	0x00
+#define RESPONSE_INITIALIZE	0x01
+#define RESPONSE_RESOLUTION	0x02
+#define RESPONSE_SETCONFIG	0x03
+#define RESPONSE_SCANFREQ	0x08
+#define RESPONSE_STATUS		0X1e
+
+/*
+ * Notifications are send by the touch controller without
+ * being requested by the driver and include for example
+ * touch indications
+ */
+#define NOTIFICATION_TOUCH		0x04
+#define NOTIFICATION_BOOTCOMPLETE	0x07
+#define NOTIFICATION_OVERRUN		0x25
+#define NOTIFICATION_PROXIMITY		0x26
+#define NOTIFICATION_INVALID_COMMAND	0xfe
+
+#define ZFORCE_REPORT_POINTS		2
+#define ZFORCE_MAX_AREA			0xff
+
+#define STATE_DOWN			0
+#define STATE_MOVE			1
+#define STATE_UP			2
+
+#define SETCONFIG_DUALTOUCH		(1 << 0)
+
+struct zforce_point {
+	int coord_x;
+	int coord_y;
+	int state;
+	int id;
+	int area_major;
+	int area_minor;
+	int orientation;
+	int pressure;
+	int prblty;
+};
+
+/*
+ * @client		the i2c_client
+ * @input		the input device
+ * @suspending		in the process of going to suspend (don't emit wakeup
+ *			events for commands executed to suspend the device)
+ * @suspended		device suspended
+ * @access_mutex	serialize i2c-access, to keep multipart reads together
+ * @command_done	completion to wait for the command result
+ * @command_mutex	serialize commands send to the ic
+ * @command_waiting	the id of the command that that is currently waiting
+ *			for a result
+ * @command_result	returned result of the command
+ */
+struct zforce_ts {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	const struct zforce_ts_platdata *pdata;
+	char			phys[32];
+
+	bool			suspending;
+	bool			suspended;
+	bool			boot_complete;
+
+	/* Firmware version information */
+	u16			version_major;
+	u16			version_minor;
+	u16			version_build;
+	u16			version_rev;
+
+	struct mutex		access_mutex;
+
+	struct completion	command_done;
+	struct mutex		command_mutex;
+	int			command_waiting;
+	int			command_result;
+};
+
+static int zforce_command(struct zforce_ts *ts, u8 cmd)
+{
+	struct i2c_client *client = ts->client;
+	char buf[3];
+	int ret;
+
+	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd);
+
+	buf[0] = FRAME_START;
+	buf[1] = 1; /* data size, command only */
+	buf[2] = cmd;
+
+	mutex_lock(&ts->access_mutex);
+	ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf));
+	mutex_unlock(&ts->access_mutex);
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c send data request error: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = mutex_trylock(&ts->command_mutex);
+	if (!ret) {
+		dev_err(&client->dev, "already waiting for a command\n");
+		return -EBUSY;
+	}
+
+	dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n",
+		buf[1], buf[2]);
+
+	ts->command_waiting = buf[2];
+
+	mutex_lock(&ts->access_mutex);
+	ret = i2c_master_send(client, buf, len);
+	mutex_unlock(&ts->access_mutex);
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c send data request error: %d\n", ret);
+		goto unlock;
+	}
+
+	dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]);
+
+	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) {
+		ret = -ETIME;
+		goto unlock;
+	}
+
+	ret = ts->command_result;
+
+unlock:
+	mutex_unlock(&ts->command_mutex);
+	return ret;
+}
+
+static int zforce_command_wait(struct zforce_ts *ts, u8 cmd)
+{
+	struct i2c_client *client = ts->client;
+	char buf[3];
+	int ret;
+
+	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd);
+
+	buf[0] = FRAME_START;
+	buf[1] = 1; /* data size, command only */
+	buf[2] = cmd;
+
+	ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c send data request error: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y)
+{
+	struct i2c_client *client = ts->client;
+	char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION,
+			(x & 0xff), ((x >> 8) & 0xff),
+			(y & 0xff), ((y >> 8) & 0xff) };
+
+	dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y);
+
+	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+}
+
+static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger,
+				 u16 stylus)
+{
+	struct i2c_client *client = ts->client;
+	char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ,
+			(idle & 0xff), ((idle >> 8) & 0xff),
+			(finger & 0xff), ((finger >> 8) & 0xff),
+			(stylus & 0xff), ((stylus >> 8) & 0xff) };
+
+	dev_dbg(&client->dev, "set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",
+		idle, finger, stylus);
+
+	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+}
+
+static int zforce_setconfig(struct zforce_ts *ts, char b1)
+{
+	struct i2c_client *client = ts->client;
+	char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG,
+			b1, 0, 0, 0 };
+
+	dev_dbg(&client->dev, "set config to (%d)\n", b1);
+
+	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+}
+
+static int zforce_start(struct zforce_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+	int ret;
+
+	dev_dbg(&client->dev, "starting device\n");
+
+	ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
+	if (ret) {
+		dev_err(&client->dev, "Unable to initialize, %d\n", ret);
+		return ret;
+	}
+
+	ret = zforce_resolution(ts, pdata->x_max, pdata->y_max);
+	if (ret) {
+		dev_err(&client->dev, "Unable to set resolution, %d\n", ret);
+		goto error;
+	}
+
+	ret = zforce_scan_frequency(ts, 10, 50, 50);
+	if (ret) {
+		dev_err(&client->dev, "Unable to set scan frequency, %d\n",
+			ret);
+		goto error;
+	}
+
+	if (zforce_setconfig(ts, SETCONFIG_DUALTOUCH)) {
+		dev_err(&client->dev, "Unable to set config\n");
+		goto error;
+	}
+
+	/* start sending touch events */
+	ret = zforce_command(ts, COMMAND_DATAREQUEST);
+	if (ret) {
+		dev_err(&client->dev, "Unable to request data\n");
+		goto error;
+	}
+
+	/* Per NN, initial cal. take max. of 200msec.
+	 * Allow time to complete this calibration
+	 */
+	msleep(200);
+
+	return 0;
+
+error:
+	zforce_command_wait(ts, COMMAND_DEACTIVATE);
+	return ret;
+}
+
+static int zforce_stop(struct zforce_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	dev_dbg(&client->dev, "stopping device\n");
+
+	/* deactivates touch sensing and puts the device into sleep */
+	ret = zforce_command_wait(ts, COMMAND_DEACTIVATE);
+	if (ret != 0) {
+		dev_err(&client->dev, "could not deactivate device, %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
+{
+	struct i2c_client *client = ts->client;
+	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+	struct zforce_point point;
+	int count, i, num = 0;
+
+	count = payload[0];
+	if (count > ZFORCE_REPORT_POINTS) {
+		dev_warn(&client->dev, "to many coordinates %d, expected max %d\n",
+			 count, ZFORCE_REPORT_POINTS);
+		count = ZFORCE_REPORT_POINTS;
+	}
+
+	for (i = 0; i < count; i++) {
+		point.coord_x =
+			payload[9 * i + 2] << 8 | payload[9 * i + 1];
+		point.coord_y =
+			payload[9 * i + 4] << 8 | payload[9 * i + 3];
+
+		if (point.coord_x > pdata->x_max ||
+		    point.coord_y > pdata->y_max) {
+			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
+				point.coord_x, point.coord_y);
+			point.coord_x = point.coord_y = 0;
+		}
+
+		point.state = payload[9 * i + 5] & 0x03;
+		point.id = (payload[9 * i + 5] & 0xfc) >> 2;
+
+		/* determine touch major, minor and orientation */
+		point.area_major = max(payload[9 * i + 6],
+					  payload[9 * i + 7]);
+		point.area_minor = min(payload[9 * i + 6],
+					  payload[9 * i + 7]);
+		point.orientation = payload[9 * i + 6] > payload[9 * i + 7];
+
+		point.pressure = payload[9 * i + 8];
+		point.prblty = payload[9 * i + 9];
+
+		dev_dbg(&client->dev, "point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n",
+			i, count, point.state, point.id,
+			point.pressure, point.prblty,
+			point.coord_x, point.coord_y,
+			point.area_major, point.area_minor,
+			point.orientation);
+
+		/* the zforce id starts with "1", so needs to be decreased */
+		input_mt_slot(ts->input, point.id - 1);
+
+		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,
+						point.state != STATE_UP);
+
+		if (point.state != STATE_UP) {
+			input_report_abs(ts->input, ABS_MT_POSITION_X,
+					 point.coord_x);
+			input_report_abs(ts->input, ABS_MT_POSITION_Y,
+					 point.coord_y);
+			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+					 point.area_major);
+			input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
+					 point.area_minor);
+			input_report_abs(ts->input, ABS_MT_ORIENTATION,
+					 point.orientation);
+			num++;
+		}
+	}
+
+	input_mt_sync_frame(ts->input);
+
+	input_mt_report_finger_count(ts->input, num);
+
+	input_sync(ts->input);
+
+	return 0;
+}
+
+static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	mutex_lock(&ts->access_mutex);
+
+	/* read 2 byte message header */
+	ret = i2c_master_recv(client, buf, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "error reading header: %d\n", ret);
+		goto unlock;
+	}
+
+	if (buf[PAYLOAD_HEADER] != FRAME_START) {
+		dev_err(&client->dev, "invalid frame start: %d\n", buf[0]);
+		ret = -EIO;
+		goto unlock;
+	}
+
+	if (buf[PAYLOAD_LENGTH] <= 0 || buf[PAYLOAD_LENGTH] > 255) {
+		dev_err(&client->dev, "invalid payload length: %d\n",
+			buf[PAYLOAD_LENGTH]);
+		ret = -EIO;
+		goto unlock;
+	}
+
+	/* read the message */
+	ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]);
+	if (ret < 0) {
+		dev_err(&client->dev, "error reading payload: %d\n", ret);
+		goto unlock;
+	}
+
+	dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n",
+		buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]);
+
+unlock:
+	mutex_unlock(&ts->access_mutex);
+	return ret;
+}
+
+static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
+{
+	struct i2c_client *client = ts->client;
+
+	if (ts->command_waiting == cmd) {
+		dev_dbg(&client->dev, "completing command 0x%x\n", cmd);
+		ts->command_result = result;
+		complete(&ts->command_done);
+	} else {
+		dev_dbg(&client->dev, "command %d not for us\n", cmd);
+	}
+}
+
+static irqreturn_t zforce_interrupt(int irq, void *dev_id)
+{
+	struct zforce_ts *ts = dev_id;
+	struct i2c_client *client = ts->client;
+	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+	int ret;
+	u8 payload_buffer[512];
+	u8 *payload;
+
+	/*
+	 * When suspended, emit a wakeup signal if necessary and return.
+	 * Due to the level-interrupt we will get re-triggered later.
+	 */
+	if (ts->suspended) {
+		if (device_may_wakeup(&client->dev))
+			pm_wakeup_event(&client->dev, 500);
+		msleep(20);
+		return IRQ_HANDLED;
+	}
+
+	dev_dbg(&client->dev, "handling interrupt\n");
+
+	/* Don't emit wakeup events from commands run by zforce_suspend */
+	if (!ts->suspending && device_may_wakeup(&client->dev))
+		pm_stay_awake(&client->dev);
+
+	while (!gpio_get_value(pdata->gpio_int)) {
+		ret = zforce_read_packet(ts, payload_buffer);
+		if (ret < 0) {
+			dev_err(&client->dev, "could not read packet, ret: %d\n",
+				ret);
+			break;
+		}
+
+		payload =  &payload_buffer[PAYLOAD_BODY];
+
+		switch (payload[RESPONSE_ID]) {
+		case NOTIFICATION_TOUCH:
+			/* Always report touch-events received while
+			 * suspending, when being a wakeup source
+			 */
+			if (ts->suspending && device_may_wakeup(&client->dev))
+				pm_wakeup_event(&client->dev, 500);
+			zforce_touch_event(ts, &payload[RESPONSE_DATA]);
+			break;
+		case NOTIFICATION_BOOTCOMPLETE:
+			ts->boot_complete = payload[RESPONSE_DATA];
+			zforce_complete(ts, payload[RESPONSE_ID], 0);
+			break;
+		case RESPONSE_INITIALIZE:
+		case RESPONSE_DEACTIVATE:
+		case RESPONSE_SETCONFIG:
+		case RESPONSE_RESOLUTION:
+		case RESPONSE_SCANFREQ:
+			zforce_complete(ts, payload[RESPONSE_ID],
+					payload[RESPONSE_DATA]);
+			break;
+		case RESPONSE_STATUS:
+			/* Version Payload Results
+			 * [2:major] [2:minor] [2:build] [2:rev]
+			 */
+			ts->version_major = (payload[RESPONSE_DATA + 1] << 8) |
+						payload[RESPONSE_DATA];
+			ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) |
+						payload[RESPONSE_DATA + 2];
+			ts->version_build = (payload[RESPONSE_DATA + 5] << 8) |
+						payload[RESPONSE_DATA + 4];
+			ts->version_rev   = (payload[RESPONSE_DATA + 7] << 8) |
+						payload[RESPONSE_DATA + 6];
+			dev_dbg(&ts->client->dev, "Firmware Version %04x:%04x %04x:%04x\n",
+				ts->version_major, ts->version_minor,
+				ts->version_build, ts->version_rev);
+
+			zforce_complete(ts, payload[RESPONSE_ID], 0);
+			break;
+		case NOTIFICATION_INVALID_COMMAND:
+			dev_err(&ts->client->dev, "invalid command: 0x%x\n",
+				payload[RESPONSE_DATA]);
+			break;
+		default:
+			dev_err(&ts->client->dev, "unrecognized response id: 0x%x\n",
+				payload[RESPONSE_ID]);
+			break;
+		}
+	}
+
+	if (!ts->suspending && device_may_wakeup(&client->dev))
+		pm_relax(&client->dev);
+
+	dev_dbg(&client->dev, "finished interrupt\n");
+
+	return IRQ_HANDLED;
+}
+
+static int zforce_input_open(struct input_dev *dev)
+{
+	struct zforce_ts *ts = input_get_drvdata(dev);
+	int ret;
+
+	ret = zforce_start(ts);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void zforce_input_close(struct input_dev *dev)
+{
+	struct zforce_ts *ts = input_get_drvdata(dev);
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = zforce_stop(ts);
+	if (ret)
+		dev_warn(&client->dev, "stopping zforce failed\n");
+
+	return;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int zforce_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct zforce_ts *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+	ts->suspending = true;
+
+	/* when configured as wakeup source, device should always wake system
+	 * therefore start device if necessary
+	 */
+	if (device_may_wakeup(&client->dev)) {
+		dev_dbg(&client->dev, "suspend while being a wakeup source\n");
+
+		/* need to start device if not open, to be wakeup source */
+		if (!input->users) {
+			ret = zforce_start(ts);
+			if (ret)
+				goto unlock;
+		}
+
+		enable_irq_wake(client->irq);
+	} else if (input->users) {
+		dev_dbg(&client->dev, "suspend without being a wakeup source\n");
+
+		ret = zforce_stop(ts);
+		if (ret)
+			goto unlock;
+
+		disable_irq(client->irq);
+	}
+
+	ts->suspended = true;
+
+unlock:
+	ts->suspending = false;
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+
+static int zforce_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct zforce_ts *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	ts->suspended = false;
+
+	if (device_may_wakeup(&client->dev)) {
+		dev_dbg(&client->dev, "resume from being a wakeup source\n");
+
+		disable_irq_wake(client->irq);
+
+		/* need to stop device if it was not open on suspend */
+		if (!input->users) {
+			ret = zforce_stop(ts);
+			if (ret)
+				goto unlock;
+		}
+	} else if (input->users) {
+		dev_dbg(&client->dev, "resume without being a wakeup source\n");
+
+		enable_irq(client->irq);
+
+		ret = zforce_start(ts);
+		if (ret < 0)
+			goto unlock;
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
+
+static void zforce_reset(void *data)
+{
+	struct zforce_ts *ts = data;
+
+	gpio_set_value(ts->pdata->gpio_rst, 0);
+}
+
+static int zforce_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
+	struct zforce_ts *ts;
+	struct input_dev *input_dev;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN,
+				    "zforce_ts_int");
+	if (ret) {
+		dev_err(&client->dev, "request of gpio %d failed, %d\n",
+			pdata->gpio_int, ret);
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst,
+				    GPIOF_OUT_INIT_LOW, "zforce_ts_rst");
+	if (ret) {
+		dev_err(&client->dev, "request of gpio %d failed, %d\n",
+			pdata->gpio_rst, ret);
+		return ret;
+	}
+
+	ret = devm_add_action(&client->dev, zforce_reset, ts);
+	if (ret) {
+		dev_err(&client->dev, "failed to register reset action, %d\n",
+			ret);
+		return ret;
+	}
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev = devm_input_allocate_device(&client->dev);
+	if (!input_dev) {
+		dev_err(&client->dev, "could not allocate input device\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&ts->access_mutex);
+	mutex_init(&ts->command_mutex);
+
+	ts->pdata = pdata;
+	ts->client = client;
+	ts->input = input_dev;
+
+	input_dev->name = "Neonode zForce touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_dev->open = zforce_input_open;
+	input_dev->close = zforce_input_close;
+
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(EV_SYN, input_dev->evbit);
+	set_bit(EV_ABS, input_dev->evbit);
+
+	/* For multi touch */
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+			     pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+			     pdata->y_max, 0, 0);
+
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
+			     ZFORCE_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
+			     ZFORCE_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+	input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT);
+
+	input_set_drvdata(ts->input, ts);
+
+	init_completion(&ts->command_done);
+
+	/* The zforce pulls the interrupt low when it has data ready.
+	 * After it is triggered the isr thread runs until all the available
+	 * packets have been read and the interrupt is high again.
+	 * Therefore we can trigger the interrupt anytime it is low and do
+	 * not need to limit it to the interrupt edge.
+	 */
+	ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+					zforce_interrupt,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					input_dev->name, ts);
+	if (ret) {
+		dev_err(&client->dev, "irq %d request failed\n", client->irq);
+		return ret;
+	}
+
+	i2c_set_clientdata(client, ts);
+
+	/* let the controller boot */
+	gpio_set_value(pdata->gpio_rst, 1);
+
+	ts->command_waiting = NOTIFICATION_BOOTCOMPLETE;
+	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
+		dev_warn(&client->dev, "bootcomplete timed out\n");
+
+	/* need to start device to get version information */
+	ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
+	if (ret) {
+		dev_err(&client->dev, "unable to initialize, %d\n", ret);
+		return ret;
+	}
+
+	/* this gets the firmware version among other informations */
+	ret = zforce_command_wait(ts, COMMAND_STATUS);
+	if (ret < 0) {
+		dev_err(&client->dev, "couldn't get status, %d\n", ret);
+		zforce_stop(ts);
+		return ret;
+	}
+
+	/* stop device and put it into sleep until it is opened */
+	ret = zforce_stop(ts);
+	if (ret < 0)
+		return ret;
+
+	device_set_wakeup_capable(&client->dev, true);
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		dev_err(&client->dev, "could not register input device, %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct i2c_device_id zforce_idtable[] = {
+	{ "zforce-ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, zforce_idtable);
+
+static struct i2c_driver zforce_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "zforce-ts",
+		.pm	= &zforce_pm_ops,
+	},
+	.probe		= zforce_probe,
+	.id_table	= zforce_idtable,
+};
+
+module_i2c_driver(zforce_driver);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("zForce TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/zforce_ts.h b/include/linux/platform_data/zforce_ts.h
new file mode 100644
index 0000000..0472ab2
--- /dev/null
+++ b/include/linux/platform_data/zforce_ts.h
@@ -0,0 +1,26 @@
+/* drivers/input/touchscreen/zforce.c
+ *
+ * Copyright (C) 2012-2013 MundoReader S.L.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_INPUT_ZFORCE_TS_H
+#define _LINUX_INPUT_ZFORCE_TS_H
+
+struct zforce_ts_platdata {
+	int gpio_int;
+	int gpio_rst;
+
+	unsigned int x_max;
+	unsigned int y_max;
+};
+
+#endif /* _LINUX_INPUT_ZFORCE_TS_H */
-- 
1.7.10.4

--
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 related

* Re: [PATCH] input: i8042 - add PNP modaliases
From: Tom Gundersen @ 2013-10-30 14:30 UTC (permalink / raw)
  To: linux-input@vger.kernel.org
  Cc: LKML, Tom Gundersen, Matthew Garrett, Dmitry Torokhov
In-Reply-To: <CAG-2HqUhZdYgYcDGJaFUJV-AqgbbFh55HMcw6nRppiUyeHGjcw@mail.gmail.com>

On Fri, Oct 4, 2013 at 2:26 PM, Tom Gundersen <teg@jklm.no> wrote:
> On Wed, Sep 4, 2013 at 11:27 AM, Tom Gundersen <teg@jklm.no> wrote:
>> This allows the module to be autoloaded in the common case.
>>
>> In order to work on non-PnP systems the module should be compiled in or loaded
>> unconditionally at boot (c.f. modules-load.d(5)), as before.
>>
>> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
>> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> Signed-off-by: Tom Gundersen <teg@jklm.no>
>> --
>
>
> Hi Dmitry,
>
> Any comments on this? Any chance of having this (and the two patches
> dropping EXPERT=y requirements) included for 3.13 (or even 3.12 if it
> is not too late for this kind of stuff)? Let me know if I should
> resend the three patches.

Ping? Any chance of seeing this in 3.13?

Cheers,

Tom

^ permalink raw reply

* Re: [PATCHv2 1/3] Input: twl4030-keypad - add device tree support
From: Pavel Machek @ 2013-10-30 13:59 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-input, 'Beno?t Cousson', Tony Lindgren, Rob Herring,
	Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
	Rob Landley, Russell King, Dmitry Torokhov, devicetree, linux-doc,
	linux-kernel, linux-arm-kernel, linux-omap
In-Reply-To: <20131030135307.D8CE1C402A0@trevor.secretlab.ca>

On Wed 2013-10-30 06:53:07, Grant Likely wrote:
> On Sun, 27 Oct 2013 12:47:53 +0100, Pavel Machek <pavel@ucw.cz> wrote:
> > > > > +#if IS_ENABLED(CONFIG_OF)
> > > > I'm probably missing something here, but why not #ifdef CONFIG_OF?
> > > 
> > > I have been told for other drivers, that IS_ENABLED() is
> > > the prefered way to check for configuration these days.
> > 
> > CONFIG_OF can not be module, using IS_ENABLED() on it is just wrong.
> 
> That makes no sense. There is absolutely nothing wrong with using
> IS_ENABLED() for CONFIG_OF.

Besides being too long, confusing for a reader, and testing for an
option that can't exist?

include/linux/kconfig.h-/*
include/linux/kconfig.h: * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
include/linux/kconfig.h- * 0 otherwise.
include/linux/kconfig.h- *
include/linux/kconfig.h- */
include/linux/kconfig.h:#define IS_ENABLED(option) \
include/linux/kconfig.h-	(config_enabled(option) || config_enabled(option##_MODULE))
include/linux/kconfig.h-
include/linux/kconfig.h-/*
include/linux/kconfig.h- * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
include/linux/kconfig.h- * otherwise. For boolean options, this is
equivalent to
include/linux/kconfig.h: * IS_ENABLED(CONFIG_FOO).
include/linux/kconfig.h- */
include/linux/kconfig.h-#define IS_BUILTIN(option) config_enabled(option)
include/linux/kconfig.h-

Oops. And I made a mistake of looking up config_enabled(). Obfuscated
C code contest.

Just use #ifdef CONFIG_foo.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ 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