From d49393b339c47733c2eda207b8ba03d61db0a5a3 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 23 Jul 2022 14:39:44 +0200 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- libgamepad_open_superdevice.c | 149 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 libgamepad_open_superdevice.c (limited to 'libgamepad_open_superdevice.c') diff --git a/libgamepad_open_superdevice.c b/libgamepad_open_superdevice.c new file mode 100644 index 0000000..b6b975f --- /dev/null +++ b/libgamepad_open_superdevice.c @@ -0,0 +1,149 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libgamepad_open_superdevice(struct libgamepad_superdevice *devicep, const char *syspath) +{ + struct libgamepad_subdevice *subdev; + int dirfd = -1, dirfd2, dirfd3; + DIR *dir = NULL, *dir2 = NULL; + struct dirent *f, *f2; + enum libgamepad_type type; + size_t first = 0, len; + void *new; + int saved_errno; + + devicep->ndevices = 0; + devicep->devices = NULL; + devicep->nleds = 0; + devicep->leds = NULL; + devicep->npower_supplies = 0; + devicep->power_supplies = NULL; + + devicep->syspath = strdup(syspath); + if (!devicep->syspath) + return -1; + + dirfd = open(syspath, O_DIRECTORY); + if (dirfd < 0) + goto fail; + + dirfd2 = openat(dirfd, "input", O_DIRECTORY); + if (dirfd2 < 0) + goto fail; + dir = fdopendir(dirfd2); + if (!dir) + goto fail; + while (errno = 0, (f = readdir(dir))) { + if (!strncmp(f->d_name, "input", 5) && isdigit(f->d_name[5])) { + dirfd3 = openat(dirfd2, f->d_name, O_DIRECTORY); + if (dirfd3 < 0) + goto fail; + dir2 = fdopendir(dirfd3); + if (!dir2) + goto fail; + type = 0; + while (errno = 0, (f2 = readdir(dir2))) { + if (!strncmp(f2->d_name, "event", 5) && isdigit(f2->d_name[5])) { + new = realloc(devicep->devices, (devicep->ndevices + 1) * sizeof(*devicep->devices)); + if (!new) + goto fail; + devicep->devices = new; + len = sizeof("/dev/input/") + strlen(f2->d_name); + subdev = malloc(offsetof(struct libgamepad_subdevice, path) + len); + if (!subdev) + goto fail; + stpcpy(stpcpy(subdev->path, "/dev/input/"), f2->d_name); + devicep->devices[devicep->ndevices++] = subdev; + } else if (!strncmp(f2->d_name, "js", 2) && isdigit(f2->d_name[2])) { + type |= LIBGAMEPAD_GAMEPAD; + } else if (!strncmp(f2->d_name, "mouse", 5) && isdigit(f2->d_name[5])) { + type |= LIBGAMEPAD_MOUSE; + } + } + while (first < devicep->ndevices) + devicep->devices[first++]->type = type; + closedir(dir2); + dir2 = NULL; + } + } + if (errno) + goto fail; + closedir(dir); + dir = NULL; + + dirfd2 = openat(dirfd, "leds", O_DIRECTORY); + if (dirfd2 >= 0) { + dir = fdopendir(dirfd2); + if (!dir) + goto fail; + len = strlen(syspath) + sizeof("/leds/"); + while (errno = 0, (f = readdir(dir))) { + if (f->d_name[0] != '.') { + new = realloc(devicep->leds, (devicep->nleds + 1) * sizeof(*devicep->leds)); + if (!new) + goto fail; + devicep->leds = new; + devicep->leds[devicep->nleds] = malloc(len + strlen(f->d_name)); + if (!devicep->leds[devicep->nleds]) + goto fail; + stpcpy(stpcpy(stpcpy(devicep->leds[devicep->nleds], syspath), "/leds/"), f->d_name); + devicep->nleds += 1; + } + } + if (errno) + goto fail; + closedir(dir); + dir = NULL; + } + + dirfd2 = openat(dirfd, "power_supply", O_DIRECTORY); + if (dirfd2 >= 0) { + dir = fdopendir(dirfd2); + if (!dir) + goto fail; + len = strlen(syspath) + sizeof("/power_supply/"); + while (errno = 0, (f = readdir(dir))) { + if (f->d_name[0] != '.') { + new = realloc(devicep->power_supplies, + (devicep->npower_supplies + 1) * sizeof(*devicep->power_supplies)); + if (!new) + goto fail; + devicep->power_supplies = new; + devicep->power_supplies[devicep->npower_supplies] = malloc(len + strlen(f->d_name)); + if (!devicep->power_supplies[devicep->npower_supplies]) + goto fail; + stpcpy(stpcpy(stpcpy(devicep->power_supplies[devicep->npower_supplies], syspath), + "/power_supply/"), f->d_name); + devicep->npower_supplies += 1; + } + } + if (errno) + goto fail; + closedir(dir); + dir = NULL; + } + + close(dirfd); + return 0; + +fail: + saved_errno = errno; + if (dir2) + closedir(dir2); + if (dir) + closedir(dir); + if (dirfd >= 0) + close(dirfd); + libgamepad_close_superdevice(devicep); + devicep->syspath = NULL; + devicep->ndevices = 0; + devicep->devices = NULL; + devicep->nleds = 0; + devicep->leds = NULL; + devicep->npower_supplies = 0; + devicep->power_supplies = NULL; + errno = saved_errno; + return -1; +} -- cgit v1.2.3-70-g09d2