aboutsummaryrefslogtreecommitdiffstats
path: root/libgamepad_open_superdevice.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2022-07-23 14:39:44 +0200
committerMattias Andrée <maandree@kth.se>2022-07-23 14:40:11 +0200
commitd49393b339c47733c2eda207b8ba03d61db0a5a3 (patch)
treebc609622c3cabe1dc6b59970cb8a9a8364a561a7 /libgamepad_open_superdevice.c
downloadlibgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.gz
libgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.bz2
libgamepad-d49393b339c47733c2eda207b8ba03d61db0a5a3.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libgamepad_open_superdevice.c')
-rw-r--r--libgamepad_open_superdevice.c149
1 files changed, 149 insertions, 0 deletions
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;
+}