blob: 479f370cfff9302a1dcc7abbff1d1d19dcd6c420 [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>
*/
/*
* More specific variants of the core API and misc functions that don't need
* access to neither the internal library data structures nor the kernel UAPI.
*/
#include <ctype.h>
#include <errno.h>
#include <gpiod.h>
#include <stdio.h>
#include <string.h>
static bool isuint(const char *str)
{
for (; *str && isdigit(*str); str++)
;
return *str == '\0';
}
struct gpiod_chip *gpiod_chip_open_by_name(const char *name)
{
struct gpiod_chip *chip;
char *path;
int rv;
rv = asprintf(&path, "/dev/%s", name);
if (rv < 0)
return NULL;
chip = gpiod_chip_open(path);
free(path);
return chip;
}
struct gpiod_chip *gpiod_chip_open_by_number(unsigned int num)
{
struct gpiod_chip *chip;
char *path;
int rv;
rv = asprintf(&path, "/dev/gpiochip%u", num);
if (!rv)
return NULL;
chip = gpiod_chip_open(path);
free(path);
return chip;
}
struct gpiod_chip *gpiod_chip_open_by_label(const char *label)
{
struct gpiod_chip_iter *iter;
struct gpiod_chip *chip;
iter = gpiod_chip_iter_new();
if (!iter)
return NULL;
gpiod_foreach_chip(iter, chip) {
if (strcmp(label, gpiod_chip_label(chip)) == 0) {
gpiod_chip_iter_free_noclose(iter);
return chip;
}
}
errno = ENOENT;
gpiod_chip_iter_free(iter);
return NULL;
}
struct gpiod_chip *gpiod_chip_open_lookup(const char *descr)
{
struct gpiod_chip *chip;
if (isuint(descr)) {
chip = gpiod_chip_open_by_number(strtoul(descr, NULL, 10));
} else {
chip = gpiod_chip_open_by_label(descr);
if (!chip) {
if (strncmp(descr, "/dev/", 5))
chip = gpiod_chip_open_by_name(descr);
else
chip = gpiod_chip_open(descr);
}
}
return chip;
}
int gpiod_chip_get_lines(struct gpiod_chip *chip, unsigned int *offsets,
unsigned int num_offsets, struct gpiod_line_bulk *bulk)
{
struct gpiod_line *line;
unsigned int i;
gpiod_line_bulk_init(bulk);
for (i = 0; i < num_offsets; i++) {
line = gpiod_chip_get_line(chip, offsets[i]);
if (!line)
return -1;
gpiod_line_bulk_add(bulk, line);
}
return 0;
}
int gpiod_chip_get_all_lines(struct gpiod_chip *chip,
struct gpiod_line_bulk *bulk)
{
struct gpiod_line_iter *iter;
struct gpiod_line *line;
gpiod_line_bulk_init(bulk);
iter = gpiod_line_iter_new(chip);
if (!iter)
return -1;
gpiod_foreach_line(iter, line)
gpiod_line_bulk_add(bulk, line);
gpiod_line_iter_free(iter);
return 0;
}
struct gpiod_line *
gpiod_chip_find_line(struct gpiod_chip *chip, const char *name)
{
struct gpiod_line_iter *iter;
struct gpiod_line *line;
const char *tmp;
iter = gpiod_line_iter_new(chip);
if (!iter)
return NULL;
gpiod_foreach_line(iter, line) {
tmp = gpiod_line_name(line);
if (tmp && strcmp(tmp, name) == 0) {
gpiod_line_iter_free(iter);
return line;
}
}
errno = ENOENT;
gpiod_line_iter_free(iter);
return NULL;
}
int gpiod_chip_find_lines(struct gpiod_chip *chip,
const char **names, struct gpiod_line_bulk *bulk)
{
struct gpiod_line *line;
int i;
gpiod_line_bulk_init(bulk);
for (i = 0; names[i]; i++) {
line = gpiod_chip_find_line(chip, names[i]);
if (!line)
return -1;
gpiod_line_bulk_add(bulk, line);
}
return 0;
}
int gpiod_line_request_input(struct gpiod_line *line, const char *consumer)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT,
};
return gpiod_line_request(line, &config, 0);
}
int gpiod_line_request_output(struct gpiod_line *line,
const char *consumer, int default_val)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
};
return gpiod_line_request(line, &config, default_val);
}
int gpiod_line_request_input_flags(struct gpiod_line *line,
const char *consumer, int flags)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT,
.flags = flags,
};
return gpiod_line_request(line, &config, 0);
}
int gpiod_line_request_output_flags(struct gpiod_line *line,
const char *consumer, int flags,
int default_val)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
.flags = flags,
};
return gpiod_line_request(line, &config, default_val);
}
static int line_event_request_type(struct gpiod_line *line,
const char *consumer, int flags, int type)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = type,
.flags = flags,
};
return gpiod_line_request(line, &config, 0);
}
int gpiod_line_request_rising_edge_events(struct gpiod_line *line,
const char *consumer)
{
return line_event_request_type(line, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_RISING_EDGE);
}
int gpiod_line_request_falling_edge_events(struct gpiod_line *line,
const char *consumer)
{
return line_event_request_type(line, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE);
}
int gpiod_line_request_both_edges_events(struct gpiod_line *line,
const char *consumer)
{
return line_event_request_type(line, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES);
}
int gpiod_line_request_rising_edge_events_flags(struct gpiod_line *line,
const char *consumer,
int flags)
{
return line_event_request_type(line, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_RISING_EDGE);
}
int gpiod_line_request_falling_edge_events_flags(struct gpiod_line *line,
const char *consumer,
int flags)
{
return line_event_request_type(line, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE);
}
int gpiod_line_request_both_edges_events_flags(struct gpiod_line *line,
const char *consumer, int flags)
{
return line_event_request_type(line, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES);
}
int gpiod_line_request_bulk_input(struct gpiod_line_bulk *bulk,
const char *consumer)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT,
};
return gpiod_line_request_bulk(bulk, &config, 0);
}
int gpiod_line_request_bulk_output(struct gpiod_line_bulk *bulk,
const char *consumer,
const int *default_vals)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
};
return gpiod_line_request_bulk(bulk, &config, default_vals);
}
static int line_event_request_type_bulk(struct gpiod_line_bulk *bulk,
const char *consumer,
int flags, int type)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = type,
.flags = flags,
};
return gpiod_line_request_bulk(bulk, &config, 0);
}
int gpiod_line_request_bulk_rising_edge_events(struct gpiod_line_bulk *bulk,
const char *consumer)
{
return line_event_request_type_bulk(bulk, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_RISING_EDGE);
}
int gpiod_line_request_bulk_falling_edge_events(struct gpiod_line_bulk *bulk,
const char *consumer)
{
return line_event_request_type_bulk(bulk, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE);
}
int gpiod_line_request_bulk_both_edges_events(struct gpiod_line_bulk *bulk,
const char *consumer)
{
return line_event_request_type_bulk(bulk, consumer, 0,
GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES);
}
int gpiod_line_request_bulk_input_flags(struct gpiod_line_bulk *bulk,
const char *consumer, int flags)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT,
.flags = flags,
};
return gpiod_line_request_bulk(bulk, &config, 0);
}
int gpiod_line_request_bulk_output_flags(struct gpiod_line_bulk *bulk,
const char *consumer, int flags,
const int *default_vals)
{
struct gpiod_line_request_config config = {
.consumer = consumer,
.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
.flags = flags,
};
return gpiod_line_request_bulk(bulk, &config, default_vals);
}
int gpiod_line_request_bulk_rising_edge_events_flags(
struct gpiod_line_bulk *bulk,
const char *consumer, int flags)
{
return line_event_request_type_bulk(bulk, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_RISING_EDGE);
}
int gpiod_line_request_bulk_falling_edge_events_flags(
struct gpiod_line_bulk *bulk,
const char *consumer, int flags)
{
return line_event_request_type_bulk(bulk, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE);
}
int gpiod_line_request_bulk_both_edges_events_flags(
struct gpiod_line_bulk *bulk,
const char *consumer, int flags)
{
return line_event_request_type_bulk(bulk, consumer, flags,
GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES);
}
struct gpiod_line *gpiod_line_get(const char *device, unsigned int offset)
{
struct gpiod_chip *chip;
struct gpiod_line *line;
chip = gpiod_chip_open_lookup(device);
if (!chip)
return NULL;
line = gpiod_chip_get_line(chip, offset);
if (!line) {
gpiod_chip_close(chip);
return NULL;
}
return line;
}
struct gpiod_line *gpiod_line_find(const char *name)
{
struct gpiod_chip_iter *iter;
struct gpiod_chip *chip;
struct gpiod_line *line;
iter = gpiod_chip_iter_new();
if (!iter)
return NULL;
gpiod_foreach_chip(iter, chip) {
line = gpiod_chip_find_line(chip, name);
if (line) {
gpiod_chip_iter_free_noclose(iter);
return line;
}
if (errno != ENOENT)
goto out;
}
errno = ENOENT;
out:
gpiod_chip_iter_free(iter);
return NULL;
}
void gpiod_line_close_chip(struct gpiod_line *line)
{
struct gpiod_chip *chip = gpiod_line_get_chip(line);
gpiod_chip_close(chip);
}