diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | common.h | 1 | ||||
-rw-r--r-- | libgamepad.h | 9 | ||||
-rw-r--r-- | libgamepad_find_sound_devices.c | 92 | ||||
-rw-r--r-- | test-list.c | 11 |
6 files changed, 113 insertions, 2 deletions
@@ -31,6 +31,7 @@ OBJ =\ libgamepad_create_attachment_monitor.o\ libgamepad_destroy_attachment_monitor.o\ libgamepad_disable_force_feedback_autocenter.o\ + libgamepad_find_sound_devices.o\ libgamepad_get_absolute_axis_info.o\ libgamepad_get_absolute_axis_name.o\ libgamepad_get_attachment_event.o\ @@ -1,6 +1,5 @@ Add support for quirks Add support for leds -Add support for audio Add support for accelerometer Add support for creating instance from a file descriptor Add man pages @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include "libgamepad.h" +#include <sys/stat.h> #include <ctype.h> #include <dirent.h> #include <errno.h> diff --git a/libgamepad.h b/libgamepad.h index 5b6c46c..46a09e2 100644 --- a/libgamepad.h +++ b/libgamepad.h @@ -339,6 +339,15 @@ int libgamepad_open_superdevice(struct libgamepad_superdevice *, const char *); */ void libgamepad_close_superdevice(struct libgamepad_superdevice *); +/** + * Search for sound devices built into or attached a device + * + * @param syspath The superdevice's path in /sys + * @param cardsp Output parameter for a list of sound card indices + * @return The number of found sound cards, -1 on failure + */ +ssize_t libgamepad_find_sound_devices(const char *, size_t **); + /** * Create a device attachment monitor diff --git a/libgamepad_find_sound_devices.c b/libgamepad_find_sound_devices.c new file mode 100644 index 0000000..1688106 --- /dev/null +++ b/libgamepad_find_sound_devices.c @@ -0,0 +1,92 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static int +search(int dirfd, const char *file, size_t **cardsp, size_t *countp, struct stat *st_buf) +{ + int fd; + DIR *dir; + struct dirent *f; + unsigned long num; + char *end; + void *new; + + fd = openat(dirfd, file, O_DIRECTORY); + if (fd < 0) + return -1; + dir = fdopendir(fd); + if (!dir) { + close(fd); + return -1; + } + + if (!strcmp(file, "sound")) { + while (errno = 0, (f = readdir(dir))) { + if (strncmp(f->d_name, "card", 4) || !isdigit(f->d_name[4])) + continue; + num = strtoul(&f->d_name[4], &end, 10); + if (errno || *end) + continue; + if (*countp == (size_t)SSIZE_MAX) + break; + new = realloc(*cardsp, (*countp + 1) * sizeof(**cardsp)); + if (!new) + goto fail; + *cardsp = new; + (*cardsp)[(*countp)++] = (size_t)num; + } + } else { + while (errno = 0, (f = readdir(dir))) { + if (f->d_name[0] == '.') + continue; + if (fstatat(fd, f->d_name, st_buf, AT_SYMLINK_NOFOLLOW)) + goto fail; + if (S_ISLNK(st_buf->st_mode)) + continue; + search(fd, f->d_name, cardsp, countp, st_buf); + } + } + + closedir(dir); + return errno ? -1 : 0; + +fail: + closedir(dir); + return -1; +} + + +ssize_t +libgamepad_find_sound_devices(const char *syspath, size_t **cardsp) +{ + int fd, i, saved_errno = errno; + size_t count = 0; + struct stat st; + const char *p = syspath; + + *cardsp = NULL; + + if (*p != '/') + return 0; + for (i = 0; i < 5; i++) { + p = strchr(&p[1], '/'); + if (!p) + return 0; + } + + fd = open(syspath, O_DIRECTORY); + if (fd < 0) + return -1; + + if (search(fd, "../..", cardsp, &count, &st)) { + close(fd); + free(*cardsp); + *cardsp = NULL; + return -1; + } + + close(fd); + errno = saved_errno; + return (ssize_t)count; +} diff --git a/test-list.c b/test-list.c index f604dd9..51ef13b 100644 --- a/test-list.c +++ b/test-list.c @@ -9,7 +9,8 @@ int main(void) { char **devices; - size_t ndevices, i, j; + size_t ndevices, i, j, *sound_cards; + ssize_t nsound_cards; struct libgamepad_superdevice device; if (libgamepad_list_superdevices(&devices, &ndevices)) { @@ -32,6 +33,14 @@ main(void) printf("\t%s (LED)\n", device.leds[j]); for (j = 0; j < device.npower_supplies; j++) printf("\t%s (PSU)\n", device.power_supplies[j]); + nsound_cards = libgamepad_find_sound_devices(device.syspath, &sound_cards); + if (nsound_cards < 0) { + perror("libgamepad_find_sound_devices"); + } else { + for (j = 0; j < (size_t)nsound_cards; j++) + printf("\t%zu (SND)\n", sound_cards[j]); + free(sound_cards); + } libgamepad_close_superdevice(&device); } |