Sync with kernel about slot info when started

When mtplot is started, the slot info is initialized to be 0,
including x, y, pressure, and the current slot number. Sometimes,
this may result in a problem. For example, if the last tap
occurs at

  (x, y) = (1020, 500)

And then a new tap occurs at

  (x, y) = (1000, 500)

The kernel will only report x value but not y value. Since y is
initialized to be 0, the tap position is mistakenly interpreted by
mtplot as

  (x, y) = (1000, 0)

This patch fixes this problem by sync-ing with kernel about the last
slot info.

BUG=chromium:307817
TEST=Perform the following tests on a link chromebook.
It is easier to verify it using a host opening two terminals and do
ssh-ing to the chromebook.

On terminal 1:
--------------
Step 1:
Download the test raw data file, one_finger_tap.link.dat,from
Issue 307817 Comment #5 to /tmp of the chromebook.

Step 2:
Then login to the chromebook:
$ ssh root@${MACHINE_IP}

Step 3:
Launch mtplot on the chromebook.
$ DISPLAY=:0 DISPLAY=:0 /usr/bin/mtplot
Choose the appropriate device number on the prompt. Press Enter.

On terminal 2:
--------------
Login to the chromebook too as root by following the instruction at step 2.

Step 4:
Replay the raw data file.
(Assume that the device you choose at Step 3 is /dev/input/event8)
$ evemu-play --insert-slot0 /dev/input/event8 < /tmp/one_finger_tap.link.dat

You could observe two dots around the center of the screen.

Step 5:
Press ctrl-c to quit mtplot on terminal 1.

Step 6:
Perform Step 3 on terminal 1, and Step 4 on terminal 2 again.
You could still observe two dots around the center of the screen.

Further Optional tests:
Perform all the steps above with an old-version mtplot. You could
observe that the two dots shown on the top edge of the screen. This
is the problem this patch attempts to fix.

Change-Id: I59caaf129489b8cfaf8576a221d748ff1b9386fc
Reviewed-on: https://chromium-review.googlesource.com/174878
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
Tested-by: Shyh-In Hwang <josephsih@chromium.org>
Commit-Queue: Shyh-In Hwang <josephsih@chromium.org>
diff --git a/mtplot.c b/mtplot.c
index fad9192..185c4d3 100644
--- a/mtplot.c
+++ b/mtplot.c
@@ -16,6 +16,7 @@
 #include <getopt.h>
 #include <limits.h>
 #include <linux/input.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -53,6 +54,8 @@
 #define ABS_MT_SLOT 47
 #endif
 
+#define MAX_SLOT_COUNT 64
+
 /* Set clockid to be used for timestamps */
 #ifndef EVIOCSCLOCKID
 #define EVIOCSCLOCKID  _IOW('E', 0xa0, int)
@@ -440,6 +443,12 @@
   struct mt_slot *slot;
 };
 
+typedef struct {
+  uint32_t code;
+  int32_t values[MAX_SLOT_COUNT];
+} MTSlotInfo, *MTSlotInfoPtr;
+
+
 // Program Options
 bool clickclear = true;
 bool monotonic = true;
@@ -489,6 +498,7 @@
 static unsigned int w_width;
 static unsigned int w_height;
 
+
 static Display *InitDisplay(const char *displayname, const char *geometry) {
   Window root;
   int x, y;
@@ -606,12 +616,51 @@
   XFillArc(dpy, w, gc, x_pixel, y_pixel, width, height, 0, 360 * 64);
 }
 
-static void MtStateInit(struct mt_state *s) {
+int ProbeAbsInfo(int fd, struct input_absinfo *absinfo, size_t key) {
+  if (ioctl(fd, EVIOCGABS(key), absinfo) < 0) {
+    perror("Error in getting info in ProbeAbsInfo");
+    return false;
+  }
+  return true;
+}
+
+int ProbeMTSlot(int fd, MTSlotInfoPtr req, uint32_t code) {
+  req->code = code;
+  if (ioctl(fd, EVIOCGMTSLOTS((sizeof(*req))), req) < 0) {
+    perror("Error in getting info in ProbeMTSlot");
+    return false;
+  }
+  return true;
+}
+
+static void MtStateInit(struct mt_state *s, char *filename) {
   int i;
+  int fd = open(filename, O_RDWR | O_NONBLOCK, 0);
+  struct input_absinfo absinfo;
+  struct mt_slot *current_slot;
+  MTSlotInfo req;
+
   s->current = 0;
   s->slot = calloc(slot_max - slot_min + 1, sizeof(struct mt_slot));
   for (i = slot_min; i <= slot_max; i++)
     MtSlotInit(&s->slot[i - slot_min]);
+
+  // Synchronize the last slot number with the kernel evdev driver.
+  if (ProbeAbsInfo(fd, &absinfo, ABS_MT_SLOT))
+    s->current = absinfo.value;
+  current_slot = &s->slot[s->current];
+
+  // Synchronize last X with the kernel evdev driver.
+  if (ProbeMTSlot(fd, &req, ABS_MT_POSITION_X))
+    current_slot->x = req.values[s->current];
+
+  // Synchronize last Y with the kernel evdev driver.
+  if (ProbeMTSlot(fd, &req, ABS_MT_POSITION_Y))
+    current_slot->y = req.values[s->current];
+
+  // Synchronize last PRESSURE with the kernel evdev driver.
+  if (ProbeMTSlot(fd, &req, ABS_MT_PRESSURE))
+    current_slot->pressure  = req.values[s->current];
 }
 
 static void MtStatePaint(struct mt_state *s) {
@@ -1133,8 +1182,6 @@
     return EXIT_FAILURE;
   }
 
-  free(filename);
-
   if (!isatty(fileno(stdout)))
     setbuf(stdout, NULL);
 
@@ -1165,8 +1212,9 @@
     return EXIT_FAILURE;
   }
 
-  MtStateInit(&mt_state);
+  MtStateInit(&mt_state, filename);
   InitPreserveRatio();
+  free(filename);
 
   x11_fd = ConnectionNumber(dpy);
   max_fd = (x11_fd > fd) ? x11_fd : fd;