/* * multi ir daemon for android - * Copyright (C) 2015-2018 AllwinnerTech * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "multiir.h" #include "virtual_input.h" #define uinput_debug(fmt, arg...) \ do { \ if (print_flags & PRINT_DEBUG) \ fprintf(stdout, "[D] " fmt"\n", ##arg); \ } while(0) #define uinput_warning(fmt, arg...) \ do { \ if (print_flags & PRINT_WARN) \ fprintf(stdout, "[W] " fmt"\n", ##arg); \ } while(0) #define uinput_error(fmt, arg...) \ do { \ if (print_flags & PRINT_ERROR) \ fprintf(stderr, "[E] " fmt"\n", ##arg); \ } while(0) enum { PRINT_ERROR = 1U << 0, PRINT_WARN = 1U << 1, PRINT_DEBUG = 1U << 2, }; #define UINPUT_NAME "/dev/uinput" static int g_uinputfd = -1; int g_mousefd = -1; static int print_flags = 0; static struct uinput_user_dev virtual_inputdev; static struct uinput_user_dev virtual_mousedev; int nfds = 0; static int is_devname_match(const char *devpath, const char *tname) { int fd; char name[80]; if (!devpath || !tname) return 0; fd = open(devpath, O_RDWR); if (fd<0) { uinput_error("could not open '%s', %s", devpath, strerror(errno)); return 0; } name[sizeof(name)-1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { uinput_error("could not get device name for '%s', %s", devpath, strerror(errno)); name[0] = '\0'; goto notmatch; } if (!strcmp(name, tname)) { uinput_debug("find match device '%s'", devpath); close(fd); return 1; } notmatch: close(fd); uinput_debug("device not match or ioctl error, %s(%s)", devpath, name); return 0; } int try_to_find_device(const char *devname, char *path) { const char *dirname = "/dev/input"; char devpath[PATH_MAX]; char *p; DIR *dir; struct dirent *de; if (!devname || !path) return -1; path[0] = '\0'; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devpath, dirname); p = devpath + strlen(devpath); *p++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(p, de->d_name); if (is_devname_match(devpath, devname)) { strcpy(path, devpath); break; } } closedir(dir); return 0; } struct inputdev_info *open_device(const char *devpath, struct pollfd *ufds) { struct inputdev_info *info; if (!devpath) goto errout; info = (inputdev_info *)calloc(sizeof(*info), sizeof(char)); if (!info) { uinput_error("could not malloc, %s", strerror(errno)); goto errout; } info->fd = open(devpath, O_RDWR); if (info->fd < 0) { uinput_error("could not open device '%s', %s", devpath, strerror(errno)); free(info); goto errout; } strcpy(info->devpath, devpath); if (ioctl(info->fd, EVIOCGVERSION, &info->version)) { uinput_warning("could not get driver version for '%s', %s", devpath, strerror(errno)); } if (ioctl(info->fd, EVIOCGID, &info->id)) { uinput_warning("could not get driver id for '%s', %s", devpath, strerror(errno)); } if (ioctl(info->fd, EVIOCGNAME(sizeof(info->name)-1), info->name) < 1) { uinput_warning("could not get device name for %s, %s", devpath, strerror(errno)); } if (ioctl(info->fd, EVIOCGPHYS(sizeof(info->location)-1), info->location) < 1) { uinput_warning("could not get location for %s, %s", devpath, strerror(errno)); } if (ioctl(info->fd, EVIOCGUNIQ(sizeof(info->idstr) - 1), info->idstr) < 1) { uinput_warning("could not get idstring for %s, %s", devpath, strerror(errno)); } if (print_flags & PRINT_DEBUG) { fprintf(stdout, " devpath: %s\n", info->devpath); fprintf(stdout, " bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", info->id.bustype, info->id.vendor, info->id.product, info->id.version); fprintf(stdout, " name: \"%s\"\n", info->name); fprintf(stdout, " location: \"%s\"\n" " id: \"%s\"\n", info->location, info->idstr); fprintf(stdout, " version: %d.%d.%d\n", info->version >> 16, (info->version >> 8) & 0xff, info->version & 0xff); } ufds[INPUT_FD_INDEX].fd = info->fd; ufds[INPUT_FD_INDEX].events = POLLIN; nfds++; uinput_debug("add device '%s' to poll", devpath); return info; errout: uinput_error("could open device '%s'!", devpath); return NULL; } static void close_device(struct inputdev_info * sourcedev, const char *devpath, struct pollfd *ufds) { if (!sourcedev) return; if (!strcmp(sourcedev->devpath, devpath)) { close(sourcedev->fd); free(sourcedev); sourcedev = NULL; nfds--; ufds[nfds].fd = -1; ufds[nfds].events = 0; uinput_debug("close device '%s'", devpath); } else { uinput_debug("device '%s' not open, ignore", devpath); } } int notify_process(struct inputdev_info * sourcedev, char *device_name, const char *dirname, int nfd, struct pollfd *ufds) { int res; char devpath[PATH_MAX]; char *p; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; res = read(nfd, event_buf, sizeof(event_buf)); if (res < (int)sizeof(*event)) { if (errno == EINTR) return 0; uinput_error("could not get event, %s", strerror(errno)); return 1; } uinput_debug("got %d bytes of event information", res); strcpy(devpath, dirname); p = devpath + strlen(devpath); *p++ = '/'; while(res >= (int)sizeof(*event)) { event = (struct inotify_event *)(event_buf + event_pos); uinput_debug("%d: %08x \"%s\"", event->wd, event->mask, event->len ? event->name : ""); if (event->len) { strcpy(p, event->name); if (event->mask & IN_CREATE) { if (!sourcedev && is_devname_match(devpath, device_name)) { uinput_debug("find target device, path=%s", devpath); sourcedev = open_device(devpath, ufds); } } else { close_device(sourcedev, devpath, ufds); } } event_size = sizeof(*event) + event->len; res -= event_size; event_pos += event_size; } return 0; } int input_event_process(int nfd, struct input_event *event) { int res; res = read(nfd, event, sizeof(struct input_event)); if (res < (int)sizeof(struct input_event)) { uinput_error("could not get event"); return -1; } // ALOGD("%04x %04x %08x", event->type, event->code, event->value); return 0; } int create_virtual_mouse_dev(char *mouse_dev) { int uinputfd = -1; if (g_mousefd >= 0) { ALOGD("multiir had enter mouse mode"); return 0; } ALOGD("multi_ir open uinput dev"); uinputfd = open(UINPUT_NAME, O_WRONLY | O_NDELAY); if (uinputfd <= 0) { ALOGE("could not open '%s', %s\n", UINPUT_NAME, strerror(errno)); return uinputfd; } memset(&virtual_mousedev, 0, sizeof(virtual_mousedev)); strncpy(virtual_mousedev.name, mouse_dev, UINPUT_MAX_NAME_SIZE); virtual_mousedev.id.version = 0x0111; virtual_mousedev.id.bustype = BUS_USB; virtual_mousedev.id.vendor = 0x093a; virtual_mousedev.id.product = 0x2521; /* setup mouse coordinate event */ if (ioctl(uinputfd, UI_SET_EVBIT, EV_REL) < 0) ALOGE("set evbit rel fail : %s", strerror(errno)); if (ioctl(uinputfd, UI_SET_EVBIT, EV_KEY) < 0) ALOGE("set evbit key fail : %s", strerror(errno)); if (ioctl(uinputfd, UI_SET_RELBIT, REL_X) < 0) ALOGE("set relbit x fail : %s", strerror(errno)); if (ioctl(uinputfd, UI_SET_RELBIT, REL_Y) < 0) ALOGE("set relbit y fail : %s", strerror(errno)); /* setup mouse button event */ if (ioctl(uinputfd, UI_SET_KEYBIT, BTN_MOUSE) < 0) ALOGE("set keybit mouse fail : %s", strerror(errno)); /* create input device into input subsystem */ write(uinputfd, &virtual_mousedev, sizeof(virtual_mousedev)); if (ioctl(uinputfd, UI_DEV_CREATE)) { ALOGE("could not create uinput device, %s\n", strerror(errno)); close(uinputfd); uinputfd = -1; return uinputfd; } g_mousefd = uinputfd; setMouseMode(1); return 0; } int destory_virtual_mouse_dev(void) { if (g_mousefd == -1) { ALOGD("multiir had exit mouse mode"); return 0; } if (ioctl(g_mousefd, UI_DEV_DESTROY)) { ALOGD("could not destory virtual mouse: %s", strerror(errno)); close(g_mousefd); g_mousefd = -1; return -1; } close(g_mousefd); g_mousefd = -1; setMouseMode(0); return 0; } int setup_virtual_input_dev(char *inputdev_name) { int i; int uinputfd = -1; ALOGD("multi_ir open uinput dev"); uinputfd = open(UINPUT_NAME, O_WRONLY | O_NDELAY); if (uinputfd <= 0) { ALOGE("could not open '%s', %s\n", UINPUT_NAME, strerror(errno)); return uinputfd; } memset(&virtual_inputdev, 0, sizeof(virtual_inputdev)); strncpy(virtual_inputdev.name, inputdev_name, UINPUT_MAX_NAME_SIZE); virtual_inputdev.id.version = 4; virtual_inputdev.id.bustype = BUS_HOST; ioctl(uinputfd, UI_SET_EVBIT, EV_KEY); ioctl(uinputfd, UI_SET_EVBIT, EV_MSC); ioctl(uinputfd, UI_SET_EVBIT, EV_REP); /* register a cursor device */ ioctl(uinputfd, UI_SET_KEYBIT, BTN_MOUSE); ioctl(uinputfd, UI_SET_RELBIT, REL_X); ioctl(uinputfd, UI_SET_RELBIT, REL_Y); ioctl(uinputfd, UI_SET_EVBIT, EV_REL); #if 0 /* setup mouse coordinate event */ ioctl(uinputfd, UI_SET_EVBIT, EV_REL); ioctl(uinputfd, UI_SET_RELBIT, REL_X); ioctl(uinputfd, UI_SET_RELBIT, REL_Y); /* setup mouse button event */ ioctl(uinputfd, UI_SET_KEYBIT, BTN_MOUSE); ioctl(uinputfd, UI_SET_KEYBIT, BTN_TOUCH); ioctl(uinputfd, UI_SET_KEYBIT, BTN_LEFT); ioctl(uinputfd, UI_SET_KEYBIT, BTN_RIGHT); ioctl(uinputfd, UI_SET_KEYBIT, BTN_MIDDLE); #endif for (i = KEYCODE_MIN; i < KEYCODE_CNT; i++) ioctl(uinputfd, UI_SET_KEYBIT, i); /* create input device into input subsystem */ write(uinputfd, &virtual_inputdev, sizeof(virtual_inputdev)); if (ioctl(uinputfd, UI_DEV_CREATE)) { ALOGE("could not create uinput device, %s\n", strerror(errno)); close(uinputfd); uinputfd = -1; return uinputfd; } g_uinputfd = uinputfd; return uinputfd; } void report_key_event(int uinputfd, struct input_event *event, int sync) { struct input_event temp_event; write(uinputfd, event, sizeof(struct input_event)); if (sync) { memset(&temp_event, 0, sizeof(struct input_event)); temp_event.type = EV_SYN; temp_event.code = SYN_REPORT; temp_event.value = 0; write(uinputfd, &temp_event, sizeof(struct input_event)); } } #define POWER_KEY (0x74) void report_standby_request(void) { int uinputfd = g_uinputfd; struct input_event event; if (uinputfd<0) return; memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = POWER_KEY; event.value = 1; write(uinputfd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinputfd, &event, sizeof(event)); memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = POWER_KEY; event.value = 0; write(uinputfd, &event, sizeof(event)); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinputfd, &event, sizeof(event)); }