/* * Copyright (C) 2014 Paul Kocialkowski * * 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 3 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, see . */ #include #include #include #include #include #include #include #include #include #define LOG_TAG "gta04_vibrator" #include /* * Globals */ const char rumble_input[] = "twl4030:vibrator"; int rumble_fd = -1; int rumble_id = -1; /* * Input */ void input_event_set(struct input_event *event, int type, int code, int value) { if (event == NULL) return; memset(event, 0, sizeof(struct input_event)); event->type = type, event->code = code; event->value = value; gettimeofday(&event->time, NULL); } int input_open(const char *name) { DIR *d; struct dirent *di; char input_name[80] = { 0 }; char path[PATH_MAX]; char *c; int fd; int rc; if (name == NULL) return -EINVAL; d = opendir("/dev/input"); if (d == NULL) return -1; while ((di = readdir(d))) { if (di == NULL || strcmp(di->d_name, ".") == 0 || strcmp(di->d_name, "..") == 0) continue; snprintf(path, PATH_MAX, "/dev/input/%s", di->d_name); fd = open(path, O_RDWR | O_NONBLOCK); if (fd < 0) continue; rc = ioctl(fd, EVIOCGNAME(sizeof(input_name) - 1), &input_name); if (rc < 0) continue; c = strstr((char *) &input_name, "\n"); if (c != NULL) *c = '\0'; if (strcmp(input_name, name) == 0) return fd; else close(fd); } return -1; } /* * Vibrator */ int vibrator_exists(void) { int fd; fd = input_open(rumble_input); if (fd < 0) return 0; close(fd); return 1; } int sendit(int duration) { struct input_event event; struct ff_effect effect; int rc; if (rumble_fd < 0) rumble_fd = input_open(rumble_input); if (rumble_fd < 0) goto error; if (rumble_id >= 0) { input_event_set(&event, EV_FF, rumble_id, 0); rc = write(rumble_fd, &event, sizeof(event)); if (rc < (int) sizeof(event)) goto error; ioctl(rumble_fd, EVIOCRMFF, &rumble_id); rumble_id = -1; } // Previous code should have removed the effect already if (duration == 0) { rc = 0; goto complete; } memset(&effect, 0, sizeof(effect)); effect.type = FF_RUMBLE; effect.id = -1; effect.replay.length = duration; effect.replay.delay = 0; effect.u.rumble.strong_magnitude = 0xffff; rc = ioctl(rumble_fd, EVIOCSFF, &effect); if (rc < 0) goto error; rumble_id = effect.id; input_event_set(&event, EV_FF, rumble_id, 1); rc = write(rumble_fd, &event, sizeof(event)); if (rc < (int) sizeof(event)) goto error; rc = 0; goto complete; error: if (rumble_fd >= 0) { if (rumble_id >= 0) { input_event_set(&event, EV_FF, rumble_id, 0); write(rumble_fd, &event, sizeof(event)); ioctl(rumble_fd, EVIOCRMFF, &rumble_id); rumble_id = -1; } close(rumble_fd); rumble_fd = -1; } rc = -1; complete: return rc; }