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, 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     struct pollfd *new_ufds;
    299     char **new_device_names;
    300     char name[80];
    301     char location[80];
    302     char idstr[80];
    303     struct input_id id;
    304 
    305     fd = open(device, O_RDWR);
    306     if(fd < 0) {
    307         if(print_flags & PRINT_DEVICE_ERRORS)
    308             fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
    309         return -1;
    310     }
    311 
    312     if(ioctl(fd, EVIOCGVERSION, &version)) {
    313         if(print_flags & PRINT_DEVICE_ERRORS)
    314             fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
    315         return -1;
    316     }
    317     if(ioctl(fd, EVIOCGID, &id)) {
    318         if(print_flags & PRINT_DEVICE_ERRORS)
    319             fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
    320         return -1;
    321     }
    322     name[sizeof(name) - 1] = '\0';
    323     location[sizeof(location) - 1] = '\0';
    324     idstr[sizeof(idstr) - 1] = '\0';
    325     if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
    326         //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
    327         name[0] = '\0';
    328     }
    329     if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
    330         //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
    331         location[0] = '\0';
    332     }
    333     if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
    334         //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
    335         idstr[0] = '\0';
    336     }
    337 
    338     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
    339     if(new_ufds == NULL) {
    340         fprintf(stderr, "out of memory\n");
    341         return -1;
    342     }
    343     ufds = new_ufds;
    344     new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
    345     if(new_device_names == NULL) {
    346         fprintf(stderr, "out of memory\n");
    347         return -1;
    348     }
    349     device_names = new_device_names;
    350 
    351     if(print_flags & PRINT_DEVICE)
    352         printf("add device %d: %s\n", nfds, device);
    353     if(print_flags & PRINT_DEVICE_INFO)
    354         printf("  bus:      %04x\n"
    355                "  vendor    %04x\n"
    356                "  product   %04x\n"
    357                "  version   %04x\n",
    358                id.bustype, id.vendor, id.product, id.version);
    359     if(print_flags & PRINT_DEVICE_NAME)
    360         printf("  name:     \"%s\"\n", name);
    361     if(print_flags & PRINT_DEVICE_INFO)
    362         printf("  location: \"%s\"\n"
    363                "  id:       \"%s\"\n", location, idstr);
    364     if(print_flags & PRINT_VERSION)
    365         printf("  version:  %d.%d.%d\n",
    366                version >> 16, (version >> 8) & 0xff, version & 0xff);
    367 
    368     if(print_flags & PRINT_POSSIBLE_EVENTS) {
    369         print_possible_events(fd, print_flags);
    370     }
    371 
    372     if(print_flags & PRINT_INPUT_PROPS) {
    373         print_input_props(fd);
    374     }
    375     if(print_flags & PRINT_HID_DESCRIPTOR) {
    376         print_hid_descriptor(id.bustype, id.vendor, id.product);
    377     }
    378 
    379     ufds[nfds].fd = fd;
    380     ufds[nfds].events = POLLIN;
    381     device_names[nfds] = strdup(device);
    382     nfds++;
    383 
    384     return 0;
    385 }
    386 
    387 int close_device(const char *device, int print_flags)
    388 {
    389     int i;
    390     for(i = 1; i < nfds; i++) {
    391         if(strcmp(device_names[i], device) == 0) {
    392             int count = nfds - i - 1;
    393             if(print_flags & PRINT_DEVICE)
    394                 printf("remove device %d: %s\n", i, device);
    395             free(device_names[i]);
    396             memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
    397             memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
    398             nfds--;
    399             return 0;
    400         }
    401     }
    402     if(print_flags & PRINT_DEVICE_ERRORS)
    403         fprintf(stderr, "remote device: %s not found\n", device);
    404     return -1;
    405 }
    406 
    407 static int read_notify(const char *dirname, int nfd, int print_flags)
    408 {
    409     int res;
    410     char devname[PATH_MAX];
    411     char *filename;
    412     char event_buf[512];
    413     int event_size;
    414     int event_pos = 0;
    415     struct inotify_event *event;
    416 
    417     res = read(nfd, event_buf, sizeof(event_buf));
    418     if(res < (int)sizeof(*event)) {
    419         if(errno == EINTR)
    420             return 0;
    421         fprintf(stderr, "could not get event, %s\n", strerror(errno));
    422         return 1;
    423     }
    424     //printf("got %d bytes of event information\n", res);
    425 
    426     strcpy(devname, dirname);
    427     filename = devname + strlen(devname);
    428     *filename++ = '/';
    429 
    430     while(res >= (int)sizeof(*event)) {
    431         event = (struct inotify_event *)(event_buf + event_pos);
    432         //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
    433         if(event->len) {
    434             strcpy(filename, event->name);
    435             if(event->mask & IN_CREATE) {
    436                 open_device(devname, print_flags);
    437             }
    438             else {
    439                 close_device(devname, print_flags);
    440             }
    441         }
    442         event_size = sizeof(*event) + event->len;
    443         res -= event_size;
    444         event_pos += event_size;
    445     }
    446     return 0;
    447 }
    448 
    449 static int scan_dir(const char *dirname, int print_flags)
    450 {
    451     char devname[PATH_MAX];
    452     char *filename;
    453     DIR *dir;
    454     struct dirent *de;
    455     dir = opendir(dirname);
    456     if(dir == NULL)
    457         return -1;
    458     strcpy(devname, dirname);
    459     filename = devname + strlen(devname);
    460     *filename++ = '/';
    461     while((de = readdir(dir))) {
    462         if(de->d_name[0] == '.' &&
    463            (de->d_name[1] == '\0' ||
    464             (de->d_name[1] == '.' && de->d_name[2] == '\0')))
    465             continue;
    466         strcpy(filename, de->d_name);
    467         open_device(devname, print_flags);
    468     }
    469     closedir(dir);
    470     return 0;
    471 }
    472 
    473 static void usage(int argc, char *argv[])
    474 {
    475     fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
    476     fprintf(stderr, "    -t: show time stamps\n");
    477     fprintf(stderr, "    -n: don't print newlines\n");
    478     fprintf(stderr, "    -s: print switch states for given bits\n");
    479     fprintf(stderr, "    -S: print all switch states\n");
    480     fprintf(stderr, "    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)\n");
    481     fprintf(stderr, "    -d: show HID descriptor, if available\n");
    482     fprintf(stderr, "    -p: show possible events (errs, dev, name, pos. events)\n");
    483     fprintf(stderr, "    -i: show all device info and possible events\n");
    484     fprintf(stderr, "    -l: label event types and names in plain text\n");
    485     fprintf(stderr, "    -q: quiet (clear verbosity mask)\n");
    486     fprintf(stderr, "    -c: print given number of events then exit\n");
    487     fprintf(stderr, "    -r: print rate events are received\n");
    488 }
    489 
    490 int getevent_main(int argc, char *argv[])
    491 {
    492     int c;
    493     int i;
    494     int res;
    495     int pollres;
    496     int get_time = 0;
    497     int print_device = 0;
    498     char *newline = "\n";
    499     uint16_t get_switch = 0;
    500     struct input_event event;
    501     int version;
    502     int print_flags = 0;
    503     int print_flags_set = 0;
    504     int dont_block = -1;
    505     int event_count = 0;
    506     int sync_rate = 0;
    507     int64_t last_sync_time = 0;
    508     const char *device = NULL;
    509     const char *device_path = "/dev/input";
    510 
    511     opterr = 0;
    512     do {
    513         c = getopt(argc, argv, "tns:Sv::dpilqc:rh");
    514         if (c == EOF)
    515             break;
    516         switch (c) {
    517         case 't':
    518             get_time = 1;
    519             break;
    520         case 'n':
    521             newline = "";
    522             break;
    523         case 's':
    524             get_switch = strtoul(optarg, NULL, 0);
    525             if(dont_block == -1)
    526                 dont_block = 1;
    527             break;
    528         case 'S':
    529             get_switch = ~0;
    530             if(dont_block == -1)
    531                 dont_block = 1;
    532             break;
    533         case 'v':
    534             if(optarg)
    535                 print_flags |= strtoul(optarg, NULL, 0);
    536             else
    537                 print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
    538             print_flags_set = 1;
    539             break;
    540         case 'd':
    541             print_flags |= PRINT_HID_DESCRIPTOR;
    542             break;
    543         case 'p':
    544             print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE
    545                     | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS | PRINT_INPUT_PROPS;
    546             print_flags_set = 1;
    547             if(dont_block == -1)
    548                 dont_block = 1;
    549             break;
    550         case 'i':
    551             print_flags |= PRINT_ALL_INFO;
    552             print_flags_set = 1;
    553             if(dont_block == -1)
    554                 dont_block = 1;
    555             break;
    556         case 'l':
    557             print_flags |= PRINT_LABELS;
    558             break;
    559         case 'q':
    560             print_flags_set = 1;
    561             break;
    562         case 'c':
    563             event_count = atoi(optarg);
    564             dont_block = 0;
    565             break;
    566         case 'r':
    567             sync_rate = 1;
    568             break;
    569         case '?':
    570             fprintf(stderr, "%s: invalid option -%c\n",
    571                 argv[0], optopt);
    572         case 'h':
    573             usage(argc, argv);
    574             exit(1);
    575         }
    576     } while (1);
    577     if(dont_block == -1)
    578         dont_block = 0;
    579 
    580     if (optind + 1 == argc) {
    581         device = argv[optind];
    582         optind++;
    583     }
    584     if (optind != argc) {
    585         usage(argc, argv);
    586         exit(1);
    587     }
    588     nfds = 1;
    589     ufds = calloc(1, sizeof(ufds[0]));
    590     ufds[0].fd = inotify_init();
    591     ufds[0].events = POLLIN;
    592     if(device) {
    593         if(!print_flags_set)
    594             print_flags |= PRINT_DEVICE_ERRORS;
    595         res = open_device(device, print_flags);
    596         if(res < 0) {
    597             return 1;
    598         }
    599     } else {
    600         if(!print_flags_set)
    601             print_flags |= PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
    602         print_device = 1;
    603 		res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
    604         if(res < 0) {
    605             fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
    606             return 1;
    607         }
    608         res = scan_dir(device_path, print_flags);
    609         if(res < 0) {
    610             fprintf(stderr, "scan dir failed for %s\n", device_path);
    611             return 1;
    612         }
    613     }
    614 
    615     if(get_switch) {
    616         for(i = 1; i < nfds; i++) {
    617             uint16_t sw;
    618             res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
    619             if(res < 0) {
    620                 fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
    621                 return 1;
    622             }
    623             sw &= get_switch;
    624             printf("%04x%s", sw, newline);
    625         }
    626     }
    627 
    628     if(dont_block)
    629         return 0;
    630 
    631     while(1) {
    632         pollres = poll(ufds, nfds, -1);
    633         //printf("poll %d, returned %d\n", nfds, pollres);
    634         if(ufds[0].revents & POLLIN) {
    635             read_notify(device_path, ufds[0].fd, print_flags);
    636         }
    637         for(i = 1; i < nfds; i++) {
    638             if(ufds[i].revents) {
    639                 if(ufds[i].revents & POLLIN) {
    640                     res = read(ufds[i].fd, &event, sizeof(event));
    641                     if(res < (int)sizeof(event)) {
    642                         fprintf(stderr, "could not get event\n");
    643                         return 1;
    644                     }
    645                     if(get_time) {
    646                         printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);
    647                     }
    648                     if(print_device)
    649                         printf("%s: ", device_names[i]);
    650                     print_event(event.type, event.code, event.value, print_flags);
    651                     if(sync_rate && event.type == 0 && event.code == 0) {
    652                         int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
    653                         if(last_sync_time)
    654                             printf(" rate %lld", 1000000LL / (now - last_sync_time));
    655                         last_sync_time = now;
    656                     }
    657                     printf("%s", newline);
    658                     if(event_count && --event_count == 0)
    659                         return 0;
    660                 }
    661             }
    662         }
    663     }
    664 
    665     return 0;
    666 }
    667