Home | History | Annotate | Download | only in toolbox
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <stdint.h>
      5 #include <dirent.h>
      6 #include <fcntl.h>
      7 #include <sys/ioctl.h>
      8 #include <sys/inotify.h>
      9 #include <sys/limits.h>
     10 #include <sys/poll.h>
     11 #include <linux/input.h>
     12 #include <errno.h>
     13 
     14 #include "getevent.h"
     15 
     16 static struct pollfd *ufds;
     17 static char **device_names;
     18 static int nfds;
     19 
     20 enum {
     21     PRINT_DEVICE_ERRORS     = 1U << 0,
     22     PRINT_DEVICE            = 1U << 1,
     23     PRINT_DEVICE_NAME       = 1U << 2,
     24     PRINT_DEVICE_INFO       = 1U << 3,
     25     PRINT_VERSION           = 1U << 4,
     26     PRINT_POSSIBLE_EVENTS   = 1U << 5,
     27     PRINT_INPUT_PROPS       = 1U << 6,
     28     PRINT_HID_DESCRIPTOR    = 1U << 7,
     29 
     30     PRINT_ALL_INFO          = (1U << 8) - 1,
     31 
     32     PRINT_LABELS            = 1U << 16,
     33 };
     34 
     35 static const char *get_label(const struct label *labels, int value)
     36 {
     37     while(labels->name && value != labels->value) {
     38         labels++;
     39     }
     40     return labels->name;
     41 }
     42 
     43 static int print_input_props(int fd)
     44 {
     45     uint8_t bits[INPUT_PROP_CNT / 8];
     46     int i, j;
     47     int res;
     48     int count;
     49     const char *bit_label;
     50 
     51     printf("  input props:\n");
     52     res = ioctl(fd, EVIOCGPROP(sizeof(bits)), bits);
     53     if(res < 0) {
     54         printf("    <not available\n");
     55         return 1;
     56     }
     57     count = 0;
     58     for(i = 0; i < res; i++) {
     59         for(j = 0; j < 8; j++) {
     60             if (bits[i] & 1 << j) {
     61                 bit_label = get_label(input_prop_labels, i * 8 + j);
     62                 if(bit_label)
     63                     printf("    %s\n", bit_label);
     64                 else
     65                     printf("    %04x\n", i * 8 + j);
     66                 count++;
     67             }
     68         }
     69     }
     70     if (!count)
     71         printf("    <none>\n");
     72     return 0;
     73 }
     74 
     75 static int print_possible_events(int fd, int print_flags)
     76 {
     77     uint8_t *bits = NULL;
     78     ssize_t bits_size = 0;
     79     const char* label;
     80     int i, j, k;
     81     int res, res2;
     82     struct label* bit_labels;
     83     const char *bit_label;
     84 
     85     printf("  events:\n");
     86     for(i = EV_KEY; i <= EV_MAX; i++) { // skip EV_SYN since we cannot query its available codes
     87         int count = 0;
     88         while(1) {
     89             res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
     90             if(res < bits_size)
     91                 break;
     92             bits_size = res + 16;
     93             bits = realloc(bits, bits_size * 2);
     94             if(bits == NULL) {
     95                 fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size);
     96                 return 1;
     97             }
     98         }
     99         res2 = 0;
    100         switch(i) {
    101             case EV_KEY:
    102                 res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
    103                 label = "KEY";
    104                 bit_labels = key_labels;
    105                 break;
    106             case EV_REL:
    107                 label = "REL";
    108                 bit_labels = rel_labels;
    109                 break;
    110             case EV_ABS:
    111                 label = "ABS";
    112                 bit_labels = abs_labels;
    113                 break;
    114             case EV_MSC:
    115                 label = "MSC";
    116                 bit_labels = msc_labels;
    117                 break;
    118             case EV_LED:
    119                 res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
    120                 label = "LED";
    121                 bit_labels = led_labels;
    122                 break;
    123             case EV_SND:
    124                 res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
    125                 label = "SND";
    126                 bit_labels = snd_labels;
    127                 break;
    128             case EV_SW:
    129                 res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
    130                 label = "SW ";
    131                 bit_labels = sw_labels;
    132                 break;
    133             case EV_REP:
    134                 label = "REP";
    135                 bit_labels = rep_labels;
    136                 break;
    137             case EV_FF:
    138                 label = "FF ";
    139                 bit_labels = ff_labels;
    140                 break;
    141             case EV_PWR:
    142                 label = "PWR";
    143                 bit_labels = NULL;
    144                 break;
    145             case EV_FF_STATUS:
    146                 label = "FFS";
    147                 bit_labels = ff_status_labels;
    148                 break;
    149             default:
    150                 res2 = 0;
    151                 label = "???";
    152                 bit_labels = NULL;
    153         }
    154         for(j = 0; j < res; j++) {
    155             for(k = 0; k < 8; k++)
    156                 if(bits[j] & 1 << k) {
    157                     char down;
    158                     if(j < res2 && (bits[j + bits_size] & 1 << k))
    159                         down = '*';
    160                     else
    161                         down = ' ';
    162                     if(count == 0)
    163                         printf("    %s (%04x):", label, i);
    164                     else if((count & (print_flags & PRINT_LABELS ? 0x3 : 0x7)) == 0 || i == EV_ABS)
    165                         printf("\n               ");
    166                     if(bit_labels && (print_flags & PRINT_LABELS)) {
    167                         bit_label = get_label(bit_labels, j * 8 + k);
    168                         if(bit_label)
    169                             printf(" %.20s%c%*s", bit_label, down, (int) (20 - strlen(bit_label)), "");
    170                         else
    171                             printf(" %04x%c                ", j * 8 + k, down);
    172                     } else {
    173                         printf(" %04x%c", j * 8 + k, down);
    174                     }
    175                     if(i == EV_ABS) {
    176                         struct input_absinfo abs;
    177                         if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
    178                             printf(" : value %d, min %d, max %d, fuzz %d, flat %d, resolution %d",
    179                                 abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat,
    180                                 abs.resolution);
    181                         }
    182                     }
    183                     count++;
    184                 }
    185         }
    186         if(count)
    187             printf("\n");
    188     }
    189     free(bits);
    190     return 0;
    191 }
    192 
    193 static void print_event(int type, int code, int value, int print_flags)
    194 {
    195     const char *type_label, *code_label, *value_label;
    196 
    197     if (print_flags & PRINT_LABELS) {
    198         type_label = get_label(ev_labels, type);
    199         code_label = NULL;
    200         value_label = NULL;
    201 
    202         switch(type) {
    203             case EV_SYN:
    204                 code_label = get_label(syn_labels, code);
    205                 break;
    206             case EV_KEY:
    207                 code_label = get_label(key_labels, code);
    208                 value_label = get_label(key_value_labels, value);
    209                 break;
    210             case EV_REL:
    211                 code_label = get_label(rel_labels, code);
    212                 break;
    213             case EV_ABS:
    214                 code_label = get_label(abs_labels, code);
    215                 switch(code) {
    216                     case ABS_MT_TOOL_TYPE:
    217                         value_label = get_label(mt_tool_labels, value);
    218                 }
    219                 break;
    220             case EV_MSC:
    221                 code_label = get_label(msc_labels, code);
    222                 break;
    223             case EV_LED:
    224                 code_label = get_label(led_labels, code);
    225                 break;
    226             case EV_SND:
    227                 code_label = get_label(snd_labels, code);
    228                 break;
    229             case EV_SW:
    230                 code_label = get_label(sw_labels, code);
    231                 break;
    232             case EV_REP:
    233                 code_label = get_label(rep_labels, code);
    234                 break;
    235             case EV_FF:
    236                 code_label = get_label(ff_labels, code);
    237                 break;
    238             case EV_FF_STATUS:
    239                 code_label = get_label(ff_status_labels, code);
    240                 break;
    241         }
    242 
    243         if (type_label)
    244             printf("%-12.12s", type_label);
    245         else
    246             printf("%04x        ", type);
    247         if (code_label)
    248             printf(" %-20.20s", code_label);
    249         else
    250             printf(" %04x                ", code);
    251         if (value_label)
    252             printf(" %-20.20s", value_label);
    253         else
    254             printf(" %08x            ", value);
    255     } else {
    256         printf("%04x %04x %08x", type, code, value);
    257     }
    258 }
    259 
    260 static void print_hid_descriptor(int bus, int vendor, int product)
    261 {
    262     const char *dirname = "/sys/kernel/debug/hid";
    263     char prefix[16];
    264     DIR *dir;
    265     struct dirent *de;
    266     char filename[PATH_MAX];
    267     FILE *file;
    268     char line[2048];
    269 
    270     snprintf(prefix, sizeof(prefix), "%04X:%04X:%04X.", bus, vendor, product);
    271 
    272     dir = opendir(dirname);
    273     if(dir == NULL)
    274         return;
    275     while((de = readdir(dir))) {
    276         if (strstr(de->d_name, prefix) == de->d_name) {
    277             snprintf(filename, sizeof(filename), "%s/%s/rdesc", dirname, de->d_name);
    278 
    279             file = fopen(filename, "r");
    280             if (file) {
    281                 printf("  HID descriptor: %s\n\n", de->d_name);
    282                 while (fgets(line, sizeof(line), file)) {
    283                     fputs("    ", stdout);
    284                     fputs(line, stdout);
    285                 }
    286                 fclose(file);
    287                 puts("");
    288             }
    289         }
    290     }
    291     closedir(dir);
    292 }
    293 
    294 static int open_device(const char *device, int print_flags)
    295 {
    296     int version;
    297     int fd;
    298     int clkid = CLOCK_MONOTONIC;
    299     struct pollfd *new_ufds;
    300     char **new_device_names;
    301     char name[80];
    302     char location[80];
    303     char idstr[80];
    304     struct input_id id;
    305 
    306     fd = open(device, O_RDWR);
    307     if(fd < 0) {
    308         if(print_flags & PRINT_DEVICE_ERRORS)
    309             fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
    310         return -1;
    311     }
    312 
    313     if(ioctl(fd, EVIOCGVERSION, &version)) {
    314         if(print_flags & PRINT_DEVICE_ERRORS)
    315             fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
    316         return -1;
    317     }
    318     if(ioctl(fd, EVIOCGID, &id)) {
    319         if(print_flags & PRINT_DEVICE_ERRORS)
    320             fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
    321         return -1;
    322     }
    323     name[sizeof(name) - 1] = '\0';
    324     location[sizeof(location) - 1] = '\0';
    325     idstr[sizeof(idstr) - 1] = '\0';
    326     if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
    327         //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
    328         name[0] = '\0';
    329     }
    330     if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
    331         //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
    332         location[0] = '\0';
    333     }
    334     if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
    335         //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
    336         idstr[0] = '\0';
    337     }
    338 
    339     if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
    340         fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
    341         // a non-fatal error
    342     }
    343 
    344     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
    345     if(new_ufds == NULL) {
    346         fprintf(stderr, "out of memory\n");
    347         return -1;
    348     }
    349     ufds = new_ufds;
    350     new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
    351     if(new_device_names == NULL) {
    352         fprintf(stderr, "out of memory\n");
    353         return -1;
    354     }
    355     device_names = new_device_names;
    356 
    357     if(print_flags & PRINT_DEVICE)
    358         printf("add device %d: %s\n", nfds, device);
    359     if(print_flags & PRINT_DEVICE_INFO)
    360         printf("  bus:      %04x\n"
    361                "  vendor    %04x\n"
    362                "  product   %04x\n"
    363                "  version   %04x\n",
    364                id.bustype, id.vendor, id.product, id.version);
    365     if(print_flags & PRINT_DEVICE_NAME)
    366         printf("  name:     \"%s\"\n", name);
    367     if(print_flags & PRINT_DEVICE_INFO)
    368         printf("  location: \"%s\"\n"
    369                "  id:       \"%s\"\n", location, idstr);
    370     if(print_flags & PRINT_VERSION)
    371         printf("  version:  %d.%d.%d\n",
    372                version >> 16, (version >> 8) & 0xff, version & 0xff);
    373 
    374     if(print_flags & PRINT_POSSIBLE_EVENTS) {
    375         print_possible_events(fd, print_flags);
    376     }
    377 
    378     if(print_flags & PRINT_INPUT_PROPS) {
    379         print_input_props(fd);
    380     }
    381     if(print_flags & PRINT_HID_DESCRIPTOR) {
    382         print_hid_descriptor(id.bustype, id.vendor, id.product);
    383     }
    384 
    385     ufds[nfds].fd = fd;
    386     ufds[nfds].events = POLLIN;
    387     device_names[nfds] = strdup(device);
    388     nfds++;
    389 
    390     return 0;
    391 }
    392 
    393 int close_device(const char *device, int print_flags)
    394 {
    395     int i;
    396     for(i = 1; i < nfds; i++) {
    397         if(strcmp(device_names[i], device) == 0) {
    398             int count = nfds - i - 1;
    399             if(print_flags & PRINT_DEVICE)
    400                 printf("remove device %d: %s\n", i, device);
    401             free(device_names[i]);
    402             memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
    403             memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
    404             nfds--;
    405             return 0;
    406         }
    407     }
    408     if(print_flags & PRINT_DEVICE_ERRORS)
    409         fprintf(stderr, "remote device: %s not found\n", device);
    410     return -1;
    411 }
    412 
    413 static int read_notify(const char *dirname, int nfd, int print_flags)
    414 {
    415     int res;
    416     char devname[PATH_MAX];
    417     char *filename;
    418     char event_buf[512];
    419     int event_size;
    420     int event_pos = 0;
    421     struct inotify_event *event;
    422 
    423     res = read(nfd, event_buf, sizeof(event_buf));
    424     if(res < (int)sizeof(*event)) {
    425         if(errno == EINTR)
    426             return 0;
    427         fprintf(stderr, "could not get event, %s\n", strerror(errno));
    428         return 1;
    429     }
    430     //printf("got %d bytes of event information\n", res);
    431 
    432     strcpy(devname, dirname);
    433     filename = devname + strlen(devname);
    434     *filename++ = '/';
    435 
    436     while(res >= (int)sizeof(*event)) {
    437         event = (struct inotify_event *)(event_buf + event_pos);
    438         //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
    439         if(event->len) {
    440             strcpy(filename, event->name);
    441             if(event->mask & IN_CREATE) {
    442                 open_device(devname, print_flags);
    443             }
    444             else {
    445                 close_device(devname, print_flags);
    446             }
    447         }
    448         event_size = sizeof(*event) + event->len;
    449         res -= event_size;
    450         event_pos += event_size;
    451     }
    452     return 0;
    453 }
    454 
    455 static int scan_dir(const char *dirname, int print_flags)
    456 {
    457     char devname[PATH_MAX];
    458     char *filename;
    459     DIR *dir;
    460     struct dirent *de;
    461     dir = opendir(dirname);
    462     if(dir == NULL)
    463         return -1;
    464     strcpy(devname, dirname);
    465     filename = devname + strlen(devname);
    466     *filename++ = '/';
    467     while((de = readdir(dir))) {
    468         if(de->d_name[0] == '.' &&
    469            (de->d_name[1] == '\0' ||
    470             (de->d_name[1] == '.' && de->d_name[2] == '\0')))
    471             continue;
    472         strcpy(filename, de->d_name);
    473         open_device(devname, print_flags);
    474     }
    475     closedir(dir);
    476     return 0;
    477 }
    478 
    479 static void usage(char *name)
    480 {
    481     fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
    482     fprintf(stderr, "    -t: show time stamps\n");
    483     fprintf(stderr, "    -n: don't print newlines\n");
    484     fprintf(stderr, "    -s: print switch states for given bits\n");
    485     fprintf(stderr, "    -S: print all switch states\n");
    486     fprintf(stderr, "    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
    487     fprintf(stderr, "    -d: show HID descriptor, if available\n");
    488     fprintf(stderr, "    -p: show possible events (errs, dev, name, pos. events)\n");
    489     fprintf(stderr, "    -i: show all device info and possible events\n");
    490     fprintf(stderr, "    -l: label event types and names in plain text\n");
    491     fprintf(stderr, "    -q: quiet (clear verbosity mask)\n");
    492     fprintf(stderr, "    -c: print given number of events then exit\n");
    493     fprintf(stderr, "    -r: print rate events are received\n");
    494 }
    495 
    496 int getevent_main(int argc, char *argv[])
    497 {
    498     int c;
    499     int i;
    500     int res;
    501     int get_time = 0;
    502     int print_device = 0;
    503     char *newline = "\n";
    504     uint16_t get_switch = 0;
    505     struct input_event event;
    506     int print_flags = 0;
    507     int print_flags_set = 0;
    508     int dont_block = -1;
    509     int event_count = 0;
    510     int sync_rate = 0;
    511     int64_t last_sync_time = 0;
    512     const char *device = NULL;
    513     const char *device_path = "/dev/input";
    514 
    515     opterr = 0;
    516     do {
    517         c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
    518         if (c == EOF)
    519             break;
    520         switch (c) {
    521         case 't':
    522             get_time = 1;
    523             break;
    524         case 'n':
    525             newline = "";
    526             break;
    527         case 's':
    528             get_switch = strtoul(optarg, NULL, 0);
    529             if(dont_block == -1)
    530                 dont_block = 1;
    531             break;
    532         case 'S':
    533             get_switch = ~0;
    534             if(dont_block == -1)
    535                 dont_block = 1;
    536             break;
    537         case 'v':
    538             if(optarg)
    539                 print_flags |= strtoul(optarg, NULL, 0);
    540             else
    541                 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
    542             print_flags_set = 1;
    543             break;
    544         case 'd':
    545             print_flags |= PRINT_HID_DESCRIPTOR;
    546             break;
    547         case 'p':
    548             print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE
    549                     | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS | PRINT_INPUT_PROPS;
    550             print_flags_set = 1;
    551             if(dont_block == -1)
    552                 dont_block = 1;
    553             break;
    554         case 'i':
    555             print_flags |= PRINT_ALL_INFO;
    556             print_flags_set = 1;
    557             if(dont_block == -1)
    558                 dont_block = 1;
    559             break;
    560         case 'l':
    561             print_flags |= PRINT_LABELS;
    562             break;
    563         case 'q':
    564             print_flags_set = 1;
    565             break;
    566         case 'c':
    567             event_count = atoi(optarg);
    568             dont_block = 0;
    569             break;
    570         case 'r':
    571             sync_rate = 1;
    572             break;
    573         case '?':
    574             fprintf(stderr, "%s: invalid option -%c\n",
    575                 argv[0], optopt);
    576         case 'h':
    577             usage(argv[0]);
    578             exit(1);
    579         }
    580     } while (1);
    581     if(dont_block == -1)
    582         dont_block = 0;
    583 
    584     if (optind + 1 == argc) {
    585         device = argv[optind];
    586         optind++;
    587     }
    588     if (optind != argc) {
    589         usage(argv[0]);
    590         exit(1);
    591     }
    592     nfds = 1;
    593     ufds = calloc(1, sizeof(ufds[0]));
    594     ufds[0].fd = inotify_init();
    595     ufds[0].events = POLLIN;
    596     if(device) {
    597         if(!print_flags_set)
    598             print_flags |= PRINT_DEVICE_ERRORS;
    599         res = open_device(device, print_flags);
    600         if(res < 0) {
    601             return 1;
    602         }
    603     } else {
    604         if(!print_flags_set)
    605             print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
    606         print_device = 1;
    607 		res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
    608         if(res < 0) {
    609             fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
    610             return 1;
    611         }
    612         res = scan_dir(device_path, print_flags);
    613         if(res < 0) {
    614             fprintf(stderr, "scan dir failed for %s\n", device_path);
    615             return 1;
    616         }
    617     }
    618 
    619     if(get_switch) {
    620         for(i = 1; i < nfds; i++) {
    621             uint16_t sw;
    622             res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
    623             if(res < 0) {
    624                 fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
    625                 return 1;
    626             }
    627             sw &= get_switch;
    628             printf("%04x%s", sw, newline);
    629         }
    630     }
    631 
    632     if(dont_block)
    633         return 0;
    634 
    635     while(1) {
    636         //int pollres =
    637         poll(ufds, nfds, -1);
    638         //printf("poll %d, returned %d\n", nfds, pollres);
    639         if(ufds[0].revents & POLLIN) {
    640             read_notify(device_path, ufds[0].fd, print_flags);
    641         }
    642         for(i = 1; i < nfds; i++) {
    643             if(ufds[i].revents) {
    644                 if(ufds[i].revents & POLLIN) {
    645                     res = read(ufds[i].fd, &event, sizeof(event));
    646                     if(res < (int)sizeof(event)) {
    647                         fprintf(stderr, "could not get event\n");
    648                         return 1;
    649                     }
    650                     if(get_time) {
    651                         printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
    652                     }
    653                     if(print_device)
    654                         printf("%s: ", device_names[i]);
    655                     print_event(event.type, event.code, event.value, print_flags);
    656                     if(sync_rate && event.type == 0 && event.code == 0) {
    657                         int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
    658                         if(last_sync_time)
    659                             printf(" rate %lld", 1000000LL / (now - last_sync_time));
    660                         last_sync_time = now;
    661                     }
    662                     printf("%s", newline);
    663                     if(event_count && --event_count == 0)
    664                         return 0;
    665                 }
    666             }
    667         }
    668     }
    669 
    670     return 0;
    671 }
    672