Home | History | Annotate | Download | only in minui
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <fcntl.h>
     20 #include <dirent.h>
     21 #include <sys/epoll.h>
     22 
     23 #include <linux/input.h>
     24 
     25 #include "minui.h"
     26 
     27 #define MAX_DEVICES 16
     28 #define MAX_MISC_FDS 16
     29 
     30 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
     31 #define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
     32 
     33 #define test_bit(bit, array) \
     34     ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
     35 
     36 struct fd_info {
     37     int fd;
     38     ev_callback cb;
     39     void *data;
     40 };
     41 
     42 static int epollfd;
     43 static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
     44 static int npolledevents;
     45 
     46 static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
     47 
     48 static unsigned ev_count = 0;
     49 static unsigned ev_dev_count = 0;
     50 static unsigned ev_misc_count = 0;
     51 
     52 int ev_init(ev_callback input_cb, void *data)
     53 {
     54     DIR *dir;
     55     struct dirent *de;
     56     int fd;
     57     struct epoll_event ev;
     58     bool epollctlfail = false;
     59 
     60     epollfd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
     61     if (epollfd == -1)
     62         return -1;
     63 
     64     dir = opendir("/dev/input");
     65     if(dir != 0) {
     66         while((de = readdir(dir))) {
     67             unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
     68 
     69 //            fprintf(stderr,"/dev/input/%s\n", de->d_name);
     70             if(strncmp(de->d_name,"event",5)) continue;
     71             fd = openat(dirfd(dir), de->d_name, O_RDONLY);
     72             if(fd < 0) continue;
     73 
     74             /* read the evbits of the input device */
     75             if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
     76                 close(fd);
     77                 continue;
     78             }
     79 
     80             /* TODO: add ability to specify event masks. For now, just assume
     81              * that only EV_KEY and EV_REL event types are ever needed. */
     82             if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
     83                 close(fd);
     84                 continue;
     85             }
     86 
     87             ev.events = EPOLLIN | EPOLLWAKEUP;
     88             ev.data.ptr = (void *)&ev_fdinfo[ev_count];
     89             if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
     90                 close(fd);
     91                 epollctlfail = true;
     92                 continue;
     93             }
     94 
     95             ev_fdinfo[ev_count].fd = fd;
     96             ev_fdinfo[ev_count].cb = input_cb;
     97             ev_fdinfo[ev_count].data = data;
     98             ev_count++;
     99             ev_dev_count++;
    100             if(ev_dev_count == MAX_DEVICES) break;
    101         }
    102     }
    103 
    104     if (epollctlfail && !ev_count) {
    105         close(epollfd);
    106         epollfd = -1;
    107         return -1;
    108     }
    109 
    110     return 0;
    111 }
    112 
    113 int ev_add_fd(int fd, ev_callback cb, void *data)
    114 {
    115     struct epoll_event ev;
    116     int ret;
    117 
    118     if (ev_misc_count == MAX_MISC_FDS || cb == NULL)
    119         return -1;
    120 
    121     ev.events = EPOLLIN | EPOLLWAKEUP;
    122     ev.data.ptr = (void *)&ev_fdinfo[ev_count];
    123     ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
    124     if (!ret) {
    125         ev_fdinfo[ev_count].fd = fd;
    126         ev_fdinfo[ev_count].cb = cb;
    127         ev_fdinfo[ev_count].data = data;
    128         ev_count++;
    129         ev_misc_count++;
    130     }
    131 
    132     return ret;
    133 }
    134 
    135 int ev_get_epollfd(void)
    136 {
    137     return epollfd;
    138 }
    139 
    140 void ev_exit(void)
    141 {
    142     while (ev_count > 0) {
    143         close(ev_fdinfo[--ev_count].fd);
    144     }
    145     ev_misc_count = 0;
    146     ev_dev_count = 0;
    147     close(epollfd);
    148 }
    149 
    150 int ev_wait(int timeout)
    151 {
    152     npolledevents = epoll_wait(epollfd, polledevents, ev_count, timeout);
    153     if (npolledevents <= 0)
    154         return -1;
    155     return 0;
    156 }
    157 
    158 void ev_dispatch(void)
    159 {
    160     int n;
    161     int ret;
    162 
    163     for (n = 0; n < npolledevents; n++) {
    164         struct fd_info *fdi = polledevents[n].data.ptr;
    165         ev_callback cb = fdi->cb;
    166         if (cb)
    167             cb(fdi->fd, polledevents[n].events, fdi->data);
    168     }
    169 }
    170 
    171 int ev_get_input(int fd, uint32_t epevents, struct input_event *ev)
    172 {
    173     int r;
    174 
    175     if (epevents & EPOLLIN) {
    176         r = read(fd, ev, sizeof(*ev));
    177         if (r == sizeof(*ev))
    178             return 0;
    179     }
    180     return -1;
    181 }
    182 
    183 int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)
    184 {
    185     unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
    186     unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
    187     unsigned i;
    188     int ret;
    189 
    190     for (i = 0; i < ev_dev_count; i++) {
    191         int code;
    192 
    193         memset(key_bits, 0, sizeof(key_bits));
    194         memset(ev_bits, 0, sizeof(ev_bits));
    195 
    196         ret = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
    197         if (ret < 0 || !test_bit(EV_KEY, ev_bits))
    198             continue;
    199 
    200         ret = ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
    201         if (ret < 0)
    202             continue;
    203 
    204         for (code = 0; code <= KEY_MAX; code++) {
    205             if (test_bit(code, key_bits))
    206                 set_key_cb(code, 1, data);
    207         }
    208     }
    209 
    210     return 0;
    211 }
    212