aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier S. Pedro <dev.git@javispedro.com>2014-07-05 22:29:59 +0200
committerJavier S. Pedro <dev.git@javispedro.com>2014-07-05 22:29:59 +0200
commita34e43f038c5a8051ea84c2ee9e1655a7478dc9a (patch)
treecffa47a27d499297a3a018db74e9d567d773583a
downloadhidptp-a34e43f038c5a8051ea84c2ee9e1655a7478dc9a.tar.gz
hidptp-a34e43f038c5a8051ea84c2ee9e1655a7478dc9a.zip
initial import
-rw-r--r--Makefile6
-rw-r--r--README23
-rw-r--r--hidptp.c134
3 files changed, 163 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..036f476
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+CFLAGS?=-Wall -Os -ggdb
+
+all: hidptp
+
+clean:
+ rm -f hidptp *.o
diff --git a/README b/README
new file mode 100644
index 0000000..781ba33
--- /dev/null
+++ b/README
@@ -0,0 +1,23 @@
+hidptp -- a quick and dirty utility to debug Precision Touchpad (PTP) devices
+
+Build hidptp by typing "make".
+
+Use the utility as follows:
+
+./hidptp <hiddev device node> <enable or disable PTP mode>
+
+For example,
+./hidptp /dev/usb/hiddev0 0
+
+will disable PTP mode in device hiddev0. It is hard to know which physical device
+"hiddev0" represents, but on my Surface Pro 2 it is the Type Cover v2. You may
+need to test hiddev1, hiddev2, etc.
+
+The utility will print the name of the device (so for a Type/Touch Cover 1/2 it
+should be "MICROSOFT SAM"), and then enable or disable PTP mode as requested.
+
+Current Linux versions can't work when the touchpad is configured in PTP mode.
+So in most scenarios you want to disable PTP mode.
+
+As an additional feature the tool will start listening and dumping events from
+the selected device. Stop with Ctrl+C.
diff --git a/hidptp.c b/hidptp.c
new file mode 100644
index 0000000..9cf9918
--- /dev/null
+++ b/hidptp.c
@@ -0,0 +1,134 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <linux/ioctl.h>
+#include <linux/hiddev.h>
+
+static int devfd;
+
+static char *get_device_name()
+{
+ static char buf[1024];
+
+ if (ioctl(devfd, HIDIOCGNAME(sizeof(buf)), buf) >= 0) {
+ return buf;
+ }
+
+ return NULL;
+}
+
+static void process_event(struct hiddev_usage_ref *ev)
+{
+ printf("0x%x (0x%x): %d\n", ev->usage_code, ev->report_id, ev->value);
+}
+
+static bool send_report(unsigned int report_type, unsigned int report_id)
+{
+ struct hiddev_report_info rinfo;
+ rinfo.report_type = report_type;
+ rinfo.report_id = report_id;
+ rinfo.num_fields = 0;
+
+ if (ioctl(devfd, HIDIOCSREPORT, &rinfo) < 0) {
+ perror("HIDIOCSREPORT");
+ return false;
+ }
+
+ printf("Report 0x%x sent\n", rinfo.report_id);
+
+ return true;
+}
+
+static __s32 read_usage(unsigned int report_type, unsigned int usage_code)
+{
+ struct hiddev_usage_ref uref;
+ uref.report_type = report_type;
+ uref.report_id = HID_REPORT_ID_UNKNOWN;
+ uref.usage_code = usage_code;
+
+ if (ioctl(devfd, HIDIOCGUSAGE, &uref) < 0) {
+ perror("HIDIOCGUSAGE");
+ return -1;
+ }
+
+ printf("0x%x: %d\n", uref.usage_code, uref.value);
+
+ return uref.value;
+}
+
+static void write_usage(unsigned int report_type, unsigned int usage_code, __s32 value)
+{
+ struct hiddev_usage_ref uref;
+ uref.report_type = report_type;
+ uref.report_id = HID_REPORT_ID_UNKNOWN;
+ uref.usage_code = usage_code;
+
+ if (ioctl(devfd, HIDIOCGUSAGE, &uref) < 0) {
+ perror("HIDIOCGUSAGE");
+ return;
+ }
+
+ uref.value = value;
+ if (ioctl(devfd, HIDIOCSUSAGE, &uref) < 0)
+ {
+ perror("HIDIOCSUSAGE");
+ return;
+ }
+
+ printf("0x%x := %d\n", uref.usage_code, uref.value);
+
+ send_report(uref.report_type, uref.report_id);
+}
+
+int main(int argc, const char *argv[])
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <device> <0|1>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ const char *device = argv[1];
+ const bool enable_ptp = strtol(argv[2], NULL, 10);
+
+ printf("Opening %s...\n", device);
+ devfd = open(device, O_RDONLY);
+
+ if (devfd == -1) {
+ perror("Could not open device");
+ return EXIT_FAILURE;
+ }
+
+ printf("Found '%s'\n", get_device_name());
+
+ // Setup flags
+ int flags = HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT;
+ if (ioctl(devfd, HIDIOCSFLAG, &flags) < 0) {
+ perror("HIDIOCSFLAG");
+ return EXIT_FAILURE;
+ }
+
+ write_usage(HID_REPORT_TYPE_FEATURE, 0x0d0052, enable_ptp ? 3 : 0);
+
+ int rc;
+ do {
+ struct hiddev_usage_ref ev;
+ rc = read(devfd, &ev, sizeof(ev));
+ if (rc < 0) {
+ perror("Could not read events from device");
+ return EXIT_FAILURE;
+ } else if (rc == 0) {
+ }
+
+ process_event(&ev);
+ } while (rc > 0);
+
+ return EXIT_SUCCESS;
+}