Home | History | Annotate | Download | only in debuggerd
      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 #include <cutils/log.h>
     14 
     15 static struct pollfd *ufds;
     16 static char **device_names;
     17 static int nfds;
     18 
     19 static int open_device(const char *device)
     20 {
     21     int version;
     22     int fd;
     23     struct pollfd *new_ufds;
     24     char **new_device_names;
     25     char name[80];
     26     char location[80];
     27     char idstr[80];
     28     struct input_id id;
     29 
     30     fd = open(device, O_RDWR);
     31     if(fd < 0) {
     32         return -1;
     33     }
     34 
     35     if(ioctl(fd, EVIOCGVERSION, &version)) {
     36         return -1;
     37     }
     38     if(ioctl(fd, EVIOCGID, &id)) {
     39         return -1;
     40     }
     41     name[sizeof(name) - 1] = '\0';
     42     location[sizeof(location) - 1] = '\0';
     43     idstr[sizeof(idstr) - 1] = '\0';
     44     if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
     45         //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
     46         name[0] = '\0';
     47     }
     48     if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
     49         //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
     50         location[0] = '\0';
     51     }
     52     if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
     53         //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
     54         idstr[0] = '\0';
     55     }
     56 
     57     new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
     58     if(new_ufds == NULL) {
     59         fprintf(stderr, "out of memory\n");
     60         return -1;
     61     }
     62     ufds = new_ufds;
     63     new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
     64     if(new_device_names == NULL) {
     65         fprintf(stderr, "out of memory\n");
     66         return -1;
     67     }
     68     device_names = new_device_names;
     69     ufds[nfds].fd = fd;
     70     ufds[nfds].events = POLLIN;
     71     device_names[nfds] = strdup(device);
     72     nfds++;
     73 
     74     return 0;
     75 }
     76 
     77 int close_device(const char *device)
     78 {
     79     int i;
     80     for(i = 1; i < nfds; i++) {
     81         if(strcmp(device_names[i], device) == 0) {
     82             int count = nfds - i - 1;
     83             free(device_names[i]);
     84             memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
     85             memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
     86             nfds--;
     87             return 0;
     88         }
     89     }
     90     return -1;
     91 }
     92 
     93 static int read_notify(const char *dirname, int nfd)
     94 {
     95     int res;
     96     char devname[PATH_MAX];
     97     char *filename;
     98     char event_buf[512];
     99     int event_size;
    100     int event_pos = 0;
    101     struct inotify_event *event;
    102 
    103     res = read(nfd, event_buf, sizeof(event_buf));
    104     if(res < (int)sizeof(*event)) {
    105         if(errno == EINTR)
    106             return 0;
    107         fprintf(stderr, "could not get event, %s\n", strerror(errno));
    108         return 1;
    109     }
    110     //printf("got %d bytes of event information\n", res);
    111 
    112     strcpy(devname, dirname);
    113     filename = devname + strlen(devname);
    114     *filename++ = '/';
    115 
    116     while(res >= (int)sizeof(*event)) {
    117         event = (struct inotify_event *)(event_buf + event_pos);
    118         //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
    119         if(event->len) {
    120             strcpy(filename, event->name);
    121             if(event->mask & IN_CREATE) {
    122                 open_device(devname);
    123             }
    124             else {
    125                 close_device(devname);
    126             }
    127         }
    128         event_size = sizeof(*event) + event->len;
    129         res -= event_size;
    130         event_pos += event_size;
    131     }
    132     return 0;
    133 }
    134 
    135 static int scan_dir(const char *dirname)
    136 {
    137     char devname[PATH_MAX];
    138     char *filename;
    139     DIR *dir;
    140     struct dirent *de;
    141     dir = opendir(dirname);
    142     if(dir == NULL)
    143         return -1;
    144     strcpy(devname, dirname);
    145     filename = devname + strlen(devname);
    146     *filename++ = '/';
    147     while((de = readdir(dir))) {
    148         if(de->d_name[0] == '.' &&
    149            (de->d_name[1] == '\0' ||
    150             (de->d_name[1] == '.' && de->d_name[2] == '\0')))
    151             continue;
    152         strcpy(filename, de->d_name);
    153         open_device(devname);
    154     }
    155     closedir(dir);
    156     return 0;
    157 }
    158 
    159 int init_getevent()
    160 {
    161     int res;
    162     const char *device_path = "/dev/input";
    163 
    164     nfds = 1;
    165     ufds = calloc(1, sizeof(ufds[0]));
    166     ufds[0].fd = inotify_init();
    167     ufds[0].events = POLLIN;
    168 
    169 	res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
    170     if(res < 0) {
    171         return 1;
    172     }
    173     res = scan_dir(device_path);
    174     if(res < 0) {
    175         return 1;
    176     }
    177     return 0;
    178 }
    179 
    180 void uninit_getevent()
    181 {
    182     int i;
    183     for(i = 0; i < nfds; i++) {
    184         close(ufds[i].fd);
    185     }
    186     free(ufds);
    187     ufds = 0;
    188     nfds = 0;
    189 }
    190 
    191 int get_event(struct input_event* event, int timeout)
    192 {
    193     int res;
    194     int i;
    195     int pollres;
    196     const char *device_path = "/dev/input";
    197     while(1) {
    198         pollres = poll(ufds, nfds, timeout);
    199         if (pollres == 0) {
    200             return 1;
    201         }
    202         if(ufds[0].revents & POLLIN) {
    203             read_notify(device_path, ufds[0].fd);
    204         }
    205         for(i = 1; i < nfds; i++) {
    206             if(ufds[i].revents) {
    207                 if(ufds[i].revents & POLLIN) {
    208                     res = read(ufds[i].fd, event, sizeof(*event));
    209                     if(res < (int)sizeof(event)) {
    210                         fprintf(stderr, "could not get event\n");
    211                         return -1;
    212                     }
    213                     return 0;
    214                 }
    215             }
    216         }
    217     }
    218     return 0;
    219 }
    220