diff mbox

[v2] Input: usbtouchscreen - add strays output via sysfs

Message ID 20180703204729.14986-1-nick@shmanahar.org (mailing list archive)
State New, archived
Headers show

Commit Message

Nick Dyer July 3, 2018, 8:47 p.m. UTC
With surface capacitance touchscreens the capacitance is measured
through readings obtained from measurements taken at the four
corners of the glass.  These measurements are accessible in the I/Q
modulation format from the the controller which becomes meaningful
data when converted to an absolute value using the pythagorean
theorem.

Signed-off-by: Nick Dyer <nick@shmanahar.org>
---
Changes in v2:
- Values read from device must be treated as signed

 drivers/input/touchscreen/usbtouchscreen.c | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)

Comments

Aleksander Morgado July 3, 2018, 8:59 p.m. UTC | #1
On Tue, Jul 3, 2018 at 10:47 PM, Nick Dyer <nick@shmanahar.org> wrote:
> With surface capacitance touchscreens the capacitance is measured
> through readings obtained from measurements taken at the four
> corners of the glass.  These measurements are accessible in the I/Q
> modulation format from the the controller which becomes meaningful
> data when converted to an absolute value using the pythagorean
> theorem.
>
> Signed-off-by: Nick Dyer <nick@shmanahar.org>
> ---
> Changes in v2:
> - Values read from device must be treated as signed
>

Numbers validated against a user-space tool that also reads stray
values from the controller.

Tested-by: Aleksander Morgado <aleksander@aleksander.es>

>  drivers/input/touchscreen/usbtouchscreen.c | 58 ++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
>
> diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
> index d61570d64ee7..af8fb1ab3a67 100644
> --- a/drivers/input/touchscreen/usbtouchscreen.c
> +++ b/drivers/input/touchscreen/usbtouchscreen.c
> @@ -55,6 +55,7 @@
>  #include <linux/usb/input.h>
>  #include <linux/hid.h>
>  #include <linux/mutex.h>
> +#include <asm/unaligned.h>
>
>  static bool swap_xy;
>  module_param(swap_xy, bool, 0644);
> @@ -437,11 +438,18 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
>  #ifdef CONFIG_TOUCHSCREEN_USB_3M
>
>  #define MTOUCHUSB_ASYNC_REPORT          1
> +#define MTOUCHUSB_GET_BLOCK            2
> +#define MTOUCHUSB_STRAYS_BLOCK_CMD     3
>  #define MTOUCHUSB_RESET                 7
>  #define MTOUCHUSB_REQ_CTRLLR_ID         10
>
>  #define MTOUCHUSB_REQ_CTRLLR_ID_LEN    16
>
> +struct mtouch_strays {
> +       u8 hdr[3];
> +       __le32 data[8];
> +} __attribute__ ((packed));
> +
>  static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
>  {
>         if (hwcalib_xy) {
> @@ -459,8 +467,22 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
>  struct mtouch_priv {
>         u8 fw_rev_major;
>         u8 fw_rev_minor;
> +       u64 strays[4];
>  };
>
> +static ssize_t mtouch_strays_show(struct device *dev,
> +                                 struct device_attribute *attr, char *output)
> +{
> +       struct usb_interface *intf = to_usb_interface(dev);
> +       struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
> +       struct mtouch_priv *priv = usbtouch->priv;
> +
> +       return scnprintf(output, PAGE_SIZE, "ul=%llu ur=%llu ll=%llu lr=%llu\n",
> +                        priv->strays[0], priv->strays[1],
> +                        priv->strays[2], priv->strays[3]);
> +}
> +static DEVICE_ATTR(strays, 0444, mtouch_strays_show, NULL);
> +
>  static ssize_t mtouch_firmware_rev_show(struct device *dev,
>                                 struct device_attribute *attr, char *output)
>  {
> @@ -475,6 +497,7 @@ static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
>
>  static struct attribute *mtouch_attrs[] = {
>         &dev_attr_firmware_rev.attr,
> +       &dev_attr_strays.attr,
>         NULL
>  };
>
> @@ -482,6 +505,39 @@ static const struct attribute_group mtouch_attr_group = {
>         .attrs = mtouch_attrs,
>  };
>
> +static void mtouch_get_strays_report(struct usbtouch_usb *usbtouch)
> +{
> +       struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
> +       struct mtouch_priv *priv = usbtouch->priv;
> +       struct mtouch_strays *sbuf;
> +       int ret;
> +       int i;
> +
> +       sbuf = kzalloc(sizeof(struct mtouch_strays), GFP_NOIO);
> +       if (!sbuf)
> +               return;
> +
> +       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +                             MTOUCHUSB_GET_BLOCK,
> +                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
> +                             MTOUCHUSB_STRAYS_BLOCK_CMD,
> +                             0, sbuf, sizeof(struct mtouch_strays),
> +                             USB_CTRL_SET_TIMEOUT);
> +       if (ret != sizeof(struct mtouch_strays))
> +               goto out_free;
> +
> +       for (i = 0; i < 4; i++) {
> +               s64 a, b;
> +
> +               a = (s32)get_unaligned_le32(&sbuf->data[i*2]);
> +               b = (s32)get_unaligned_le32(&sbuf->data[i*2 + 1]);
> +               priv->strays[i] = int_sqrt64(a * a + b * b);
> +       }
> +
> +out_free:
> +       kfree(sbuf);
> +}
> +
>  static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
>  {
>         struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
> @@ -568,6 +624,8 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
>                         return ret;
>         }
>
> +       mtouch_get_strays_report(usbtouch);
> +
>         /* Default min/max xy are the raw values, override if using hw-calib */
>         if (hwcalib_xy) {
>                 input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
> --
> 2.17.1
>
Dmitry Torokhov July 25, 2018, 11:33 p.m. UTC | #2
Hi Nick,

On Tue, Jul 03, 2018 at 09:47:29PM +0100, Nick Dyer wrote:
> With surface capacitance touchscreens the capacitance is measured
> through readings obtained from measurements taken at the four
> corners of the glass.  These measurements are accessible in the I/Q
> modulation format from the the controller which becomes meaningful
> data when converted to an absolute value using the pythagorean
> theorem.

What is the intended use of this data? Can it be fetched by an userspace
utility accessing device over usbfs?

Thanks.
Chris Healy July 25, 2018, 11:44 p.m. UTC | #3
Where I work we use this data to determine if there are broken traces
between the touchscreen and the touchscreen controller.  When a trace
is broken, the absolute value of one of the 4 corners is a small
fraction of the other three.  With our flying systems, we have a shell
script that reads the sysfs entry and writes it to the syslog on every
system boot.  With the sysfs entry, we are able to avoid dependency on
any userspace utilities for accessing this data.

On Wed, Jul 25, 2018 at 4:33 PM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Nick,
>
> On Tue, Jul 03, 2018 at 09:47:29PM +0100, Nick Dyer wrote:
>> With surface capacitance touchscreens the capacitance is measured
>> through readings obtained from measurements taken at the four
>> corners of the glass.  These measurements are accessible in the I/Q
>> modulation format from the the controller which becomes meaningful
>> data when converted to an absolute value using the pythagorean
>> theorem.
>
> What is the intended use of this data? Can it be fetched by an userspace
> utility accessing device over usbfs?
>
> Thanks.
>
> --
> 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
diff mbox

Patch

diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index d61570d64ee7..af8fb1ab3a67 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -55,6 +55,7 @@ 
 #include <linux/usb/input.h>
 #include <linux/hid.h>
 #include <linux/mutex.h>
+#include <asm/unaligned.h>
 
 static bool swap_xy;
 module_param(swap_xy, bool, 0644);
@@ -437,11 +438,18 @@  static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 #ifdef CONFIG_TOUCHSCREEN_USB_3M
 
 #define MTOUCHUSB_ASYNC_REPORT          1
+#define MTOUCHUSB_GET_BLOCK		2
+#define MTOUCHUSB_STRAYS_BLOCK_CMD	3
 #define MTOUCHUSB_RESET                 7
 #define MTOUCHUSB_REQ_CTRLLR_ID         10
 
 #define MTOUCHUSB_REQ_CTRLLR_ID_LEN	16
 
+struct mtouch_strays {
+	u8 hdr[3];
+	__le32 data[8];
+} __attribute__ ((packed));
+
 static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
 	if (hwcalib_xy) {
@@ -459,8 +467,22 @@  static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 struct mtouch_priv {
 	u8 fw_rev_major;
 	u8 fw_rev_minor;
+	u64 strays[4];
 };
 
+static ssize_t mtouch_strays_show(struct device *dev,
+				  struct device_attribute *attr, char *output)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct mtouch_priv *priv = usbtouch->priv;
+
+	return scnprintf(output, PAGE_SIZE, "ul=%llu ur=%llu ll=%llu lr=%llu\n",
+			 priv->strays[0], priv->strays[1],
+			 priv->strays[2], priv->strays[3]);
+}
+static DEVICE_ATTR(strays, 0444, mtouch_strays_show, NULL);
+
 static ssize_t mtouch_firmware_rev_show(struct device *dev,
 				struct device_attribute *attr, char *output)
 {
@@ -475,6 +497,7 @@  static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
 
 static struct attribute *mtouch_attrs[] = {
 	&dev_attr_firmware_rev.attr,
+	&dev_attr_strays.attr,
 	NULL
 };
 
@@ -482,6 +505,39 @@  static const struct attribute_group mtouch_attr_group = {
 	.attrs = mtouch_attrs,
 };
 
+static void mtouch_get_strays_report(struct usbtouch_usb *usbtouch)
+{
+	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+	struct mtouch_priv *priv = usbtouch->priv;
+	struct mtouch_strays *sbuf;
+	int ret;
+	int i;
+
+	sbuf = kzalloc(sizeof(struct mtouch_strays), GFP_NOIO);
+	if (!sbuf)
+		return;
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      MTOUCHUSB_GET_BLOCK,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      MTOUCHUSB_STRAYS_BLOCK_CMD,
+			      0, sbuf, sizeof(struct mtouch_strays),
+			      USB_CTRL_SET_TIMEOUT);
+	if (ret != sizeof(struct mtouch_strays))
+		goto out_free;
+
+	for (i = 0; i < 4; i++) {
+		s64 a, b;
+
+		a = (s32)get_unaligned_le32(&sbuf->data[i*2]);
+		b = (s32)get_unaligned_le32(&sbuf->data[i*2 + 1]);
+		priv->strays[i] = int_sqrt64(a * a + b * b);
+	}
+
+out_free:
+	kfree(sbuf);
+}
+
 static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
 {
 	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
@@ -568,6 +624,8 @@  static int mtouch_init(struct usbtouch_usb *usbtouch)
 			return ret;
 	}
 
+	mtouch_get_strays_report(usbtouch);
+
 	/* Default min/max xy are the raw values, override if using hw-calib */
 	if (hwcalib_xy) {
 		input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);