blob: bfd28523b8069855a5aae7b19841c4af2db52653 [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* This file is part of libgpiod.
*
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
*/
/* GPIO chip and line iterators. */
#include <dirent.h>
#include <gpiod.h>
#include <string.h>
struct gpiod_chip_iter {
struct gpiod_chip **chips;
unsigned int num_chips;
unsigned int offset;
};
struct gpiod_line_iter {
struct gpiod_line **lines;
unsigned int num_lines;
unsigned int offset;
};
static int dir_filter(const struct dirent *dir)
{
return !strncmp(dir->d_name, "gpiochip", 8);
}
static void free_dirs(struct dirent **dirs, unsigned int num_dirs)
{
unsigned int i;
for (i = 0; i < num_dirs; i++)
free(dirs[i]);
free(dirs);
}
struct gpiod_chip_iter *gpiod_chip_iter_new(void)
{
struct gpiod_chip_iter *iter;
struct dirent **dirs;
int i, num_chips;
num_chips = scandir("/dev", &dirs, dir_filter, alphasort);
if (num_chips < 0)
return NULL;
iter = malloc(sizeof(*iter));
if (!iter)
goto err_free_dirs;
iter->num_chips = num_chips;
iter->offset = 0;
if (num_chips == 0) {
iter->chips = NULL;
return iter;
}
iter->chips = calloc(num_chips, sizeof(*iter->chips));
if (!iter->chips)
goto err_free_iter;
for (i = 0; i < num_chips; i++) {
iter->chips[i] = gpiod_chip_open_by_name(dirs[i]->d_name);
if (!iter->chips[i])
goto err_close_chips;
}
free_dirs(dirs, num_chips);
return iter;
err_close_chips:
for (i = 0; i < num_chips; i++) {
if (iter->chips[i])
gpiod_chip_close(iter->chips[i]);
}
free(iter->chips);
err_free_iter:
free(iter);
err_free_dirs:
free_dirs(dirs, num_chips);
return NULL;
}
void gpiod_chip_iter_free(struct gpiod_chip_iter *iter)
{
if (iter->offset > 0 && iter->offset < iter->num_chips)
gpiod_chip_close(iter->chips[iter->offset - 1]);
gpiod_chip_iter_free_noclose(iter);
}
void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter)
{
unsigned int i;
for (i = iter->offset; i < iter->num_chips; i++) {
if (iter->chips[i])
gpiod_chip_close(iter->chips[i]);
}
if (iter->chips)
free(iter->chips);
free(iter);
}
struct gpiod_chip *gpiod_chip_iter_next(struct gpiod_chip_iter *iter)
{
if (iter->offset > 0) {
gpiod_chip_close(iter->chips[iter->offset - 1]);
iter->chips[iter->offset - 1] = NULL;
}
return gpiod_chip_iter_next_noclose(iter);
}
struct gpiod_chip *gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter)
{
return iter->offset < (iter->num_chips)
? iter->chips[iter->offset++] : NULL;
}
struct gpiod_line_iter *gpiod_line_iter_new(struct gpiod_chip *chip)
{
struct gpiod_line_iter *iter;
unsigned int i;
iter = malloc(sizeof(*iter));
if (!iter)
return NULL;
iter->num_lines = gpiod_chip_num_lines(chip);
iter->offset = 0;
iter->lines = calloc(iter->num_lines, sizeof(*iter->lines));
if (!iter->lines) {
free(iter);
return NULL;
}
for (i = 0; i < iter->num_lines; i++) {
iter->lines[i] = gpiod_chip_get_line(chip, i);
if (!iter->lines[i]) {
free(iter->lines);
free(iter);
return NULL;
}
}
return iter;
}
void gpiod_line_iter_free(struct gpiod_line_iter *iter)
{
free(iter->lines);
free(iter);
}
struct gpiod_line *gpiod_line_iter_next(struct gpiod_line_iter *iter)
{
return iter->offset < (iter->num_lines)
? iter->lines[iter->offset++] : NULL;
}