Enhance getevent to print event labels.

Added -l argument to print labels for event types, codes and values.
Added -i argument to print all device info.
Added support for printing input properties.

Change-Id: I3cacb716dbc38f50217b9dfc24ba44d08f352603
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 256720d..f0a6c24 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -8,9 +8,11 @@
 #include <sys/inotify.h>
 #include <sys/limits.h>
 #include <sys/poll.h>
-#include <linux/input.h> // this does not compile
+#include <linux/input.h>
 #include <errno.h>
 
+#include "getevent.h"
+
 static struct pollfd *ufds;
 static char **device_names;
 static int nfds;
@@ -22,16 +24,63 @@
     PRINT_DEVICE_INFO       = 1U << 3,
     PRINT_VERSION           = 1U << 4,
     PRINT_POSSIBLE_EVENTS   = 1U << 5,
+    PRINT_INPUT_PROPS       = 1U << 6,
+
+    PRINT_ALL_INFO          = (1U << 7) - 1,
+
+    PRINT_LABELS            = 1U << 16,
 };
 
-static int print_possible_events(int fd)
+static const char *get_label(const struct label *labels, int value)
+{
+    while(labels->name && value != labels->value) {
+        labels++;
+    }
+    return labels->name;
+}
+
+static int print_input_props(int fd)
+{
+    uint8_t bits[INPUT_PROP_CNT / 8];
+    int i, j;
+    int res;
+    int count;
+    const char *bit_label;
+
+    printf("  input props:\n");
+    res = ioctl(fd, EVIOCGPROP(sizeof(bits)), bits);
+    if(res < 0) {
+        printf("    <not available\n");
+        return 1;
+    }
+    count = 0;
+    for(i = 0; i < res; i++) {
+        for(j = 0; j < 8; j++) {
+            if (bits[i] & 1 << j) {
+                bit_label = get_label(input_prop_labels, i * 8 + j);
+                if(bit_label)
+                    printf("    %s\n", bit_label);
+                else
+                    printf("    %04x\n", i * 8 + j);
+                count++;
+            }
+        }
+    }
+    if (!count)
+        printf("    <none>\n");
+    return 0;
+}
+
+static int print_possible_events(int fd, int print_flags)
 {
     uint8_t *bits = NULL;
     ssize_t bits_size = 0;
     const char* label;
     int i, j, k;
     int res, res2;
-    
+    struct label* bit_labels;
+    const char *bit_label;
+
     printf("  events:\n");
     for(i = 0; i <= EV_MAX; i++) {
         int count = 0;
@@ -42,7 +91,7 @@
             bits_size = res + 16;
             bits = realloc(bits, bits_size * 2);
             if(bits == NULL) {
-                fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size);
+                fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
                 return 1;
             }
         }
@@ -50,44 +99,60 @@
         switch(i) {
             case EV_SYN:
                 label = "SYN";
+                bit_labels = syn_labels;
                 break;
             case EV_KEY:
                 res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
                 label = "KEY";
+                bit_labels = key_labels;
                 break;
             case EV_REL:
                 label = "REL";
+                bit_labels = rel_labels;
                 break;
             case EV_ABS:
                 label = "ABS";
+                bit_labels = abs_labels;
                 break;
             case EV_MSC:
                 label = "MSC";
+                bit_labels = msc_labels;
                 break;
             case EV_LED:
                 res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
                 label = "LED";
+                bit_labels = led_labels;
                 break;
             case EV_SND:
                 res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
                 label = "SND";
+                bit_labels = snd_labels;
                 break;
             case EV_SW:
                 res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
                 label = "SW ";
+                bit_labels = sw_labels;
                 break;
             case EV_REP:
                 label = "REP";
+                bit_labels = rep_labels;
                 break;
             case EV_FF:
                 label = "FF ";
+                bit_labels = ff_labels;
                 break;
             case EV_PWR:
                 label = "PWR";
+                bit_labels = NULL;
+                break;
+            case EV_FF_STATUS:
+                label = "FFS";
+                bit_labels = ff_status_labels;
                 break;
             default:
                 res2 = 0;
                 label = "???";
+                bit_labels = NULL;
         }
         for(j = 0; j < res; j++) {
             for(k = 0; k < 8; k++)
@@ -99,13 +164,21 @@
                         down = ' ';
                     if(count == 0)
                         printf("    %s (%04x):", label, i);
-                    else if((count & 0x7) == 0 || i == EV_ABS)
+                    else if((count & (print_flags & PRINT_LABELS ? 0x3 : 0x7)) == 0 || i == EV_ABS)
                         printf("\n               ");
-                    printf(" %04x%c", j * 8 + k, down);
+                    if(bit_labels && (print_flags & PRINT_LABELS)) {
+                        bit_label = get_label(bit_labels, j * 8 + k);
+                        if(bit_label)
+                            printf(" %.20s%c%*s", bit_label, down, 20 - strlen(bit_label), "");
+                        else
+                            printf(" %04x%c                ", j * 8 + k, down);
+                    } else {
+                        printf(" %04x%c", j * 8 + k, down);
+                    }
                     if(i == EV_ABS) {
                         struct input_absinfo abs;
                         if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
-                            printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
+                            printf(" : value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
                         }
                     }
                     count++;
@@ -118,6 +191,73 @@
     return 0;
 }
 
+static void print_event(int type, int code, int value, int print_flags)
+{
+    const char *type_label, *code_label, *value_label;
+
+    if (print_flags & PRINT_LABELS) {
+        type_label = get_label(ev_labels, type);
+        code_label = NULL;
+        value_label = NULL;
+
+        switch(type) {
+            case EV_SYN:
+                code_label = get_label(syn_labels, code);
+                break;
+            case EV_KEY:
+                code_label = get_label(key_labels, code);
+                value_label = get_label(key_value_labels, value);
+                break;
+            case EV_REL:
+                code_label = get_label(rel_labels, code);
+                break;
+            case EV_ABS:
+                code_label = get_label(abs_labels, code);
+                switch(code) {
+                    case ABS_MT_TOOL_TYPE:
+                        value_label = get_label(mt_tool_labels, value);
+                }
+                break;
+            case EV_MSC:
+                code_label = get_label(msc_labels, code);
+                break;
+            case EV_LED:
+                code_label = get_label(led_labels, code);
+                break;
+            case EV_SND:
+                code_label = get_label(snd_labels, code);
+                break;
+            case EV_SW:
+                code_label = get_label(sw_labels, code);
+                break;
+            case EV_REP:
+                code_label = get_label(rep_labels, code);
+                break;
+            case EV_FF:
+                code_label = get_label(ff_labels, code);
+                break;
+            case EV_FF_STATUS:
+                code_label = get_label(ff_status_labels, code);
+                break;
+        }
+
+        if (type_label)
+            printf("%-12.12s", type_label);
+        else
+            printf("%04x        ", type);
+        if (code_label)
+            printf(" %-20.20s", code_label);
+        else
+            printf(" %04x                ", code);
+        if (value_label)
+            printf(" %-20.20s", value_label);
+        else
+            printf(" %08x            ", code);
+    } else {
+        printf("%04x %04x %08x", type, code, value);
+    }
+}
+
 static int open_device(const char *device, int print_flags)
 {
     int version;
@@ -193,7 +333,11 @@
                version >> 16, (version >> 8) & 0xff, version & 0xff);
 
     if(print_flags & PRINT_POSSIBLE_EVENTS) {
-        print_possible_events(fd);
+        print_possible_events(fd, print_flags);
+    }
+
+    if(print_flags & PRINT_INPUT_PROPS) {
+        print_input_props(fd);
     }
 
     ufds[nfds].fd = fd;
@@ -292,13 +436,15 @@
 
 static void usage(int argc, char *argv[])
 {
-    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]\n", argv[0]);
+    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
     fprintf(stderr, "    -t: show time stamps\n");
     fprintf(stderr, "    -n: don't print newlines\n");
     fprintf(stderr, "    -s: print switch states for given bits\n");
     fprintf(stderr, "    -S: print all switch states\n");
-    fprintf(stderr, "    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)\n");
+    fprintf(stderr, "    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
     fprintf(stderr, "    -p: show possible events (errs, dev, name, pos. events)\n");
+    fprintf(stderr, "    -i: show all device info and possible events\n");
+    fprintf(stderr, "    -l: label event types and names in plain text\n");
     fprintf(stderr, "    -q: quiet (clear verbosity mask)\n");
     fprintf(stderr, "    -c: print given number of events then exit\n");
     fprintf(stderr, "    -r: print rate events are received\n");
@@ -316,7 +462,7 @@
     uint16_t get_switch = 0;
     struct input_event event;
     int version;
-    int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
+    int print_flags = 0;
     int print_flags_set = 0;
     int dont_block = -1;
     int event_count = 0;
@@ -327,7 +473,7 @@
 
     opterr = 0;
     do {
-        c = getopt(argc, argv, "tns:Sv::pqc:rh");
+        c = getopt(argc, argv, "tns:Sv::pilqc:rh");
         if (c == EOF)
             break;
         switch (c) {
@@ -349,19 +495,27 @@
             break;
         case 'v':
             if(optarg)
-                print_flags =  strtoul(optarg, NULL, 0);
+                print_flags |= strtoul(optarg, NULL, 0);
             else
                 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
             print_flags_set = 1;
             break;
         case 'p':
-            print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
+            print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
             print_flags_set = 1;
             if(dont_block == -1)
                 dont_block = 1;
             break;
+        case 'i':
+            print_flags |= PRINT_ALL_INFO;
+            print_flags_set = 1;
+            if(dont_block == -1)
+                dont_block = 1;
+            break;
+        case 'l':
+            print_flags |= PRINT_LABELS;
+            break;
         case 'q':
-            print_flags = 0;
             print_flags_set = 1;
             break;
         case 'c':
@@ -396,13 +550,14 @@
     ufds[0].events = POLLIN;
     if(device) {
         if(!print_flags_set)
-            print_flags = PRINT_DEVICE_ERRORS;
+            print_flags |= PRINT_DEVICE_ERRORS;
         res = open_device(device, print_flags);
         if(res < 0) {
             return 1;
         }
-    }
-    else {
+    } else {
+        if(!print_flags_set)
+            print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
         print_device = 1;
 		res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
         if(res < 0) {
@@ -451,7 +606,7 @@
                     }
                     if(print_device)
                         printf("%s: ", device_names[i]);
-                    printf("%04x %04x %08x", event.type, event.code, event.value);
+                    print_event(event.type, event.code, event.value, print_flags);
                     if(sync_rate && event.type == 0 && event.code == 0) {
                         int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
                         if(last_sync_time)