mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-28 13:55:08 +03:00
ctxless: drop all context-less interfaces
The context-less family of functions seems to be largely unused. Drop this part of the codebase and convert tools to using the regular low-level API. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
406
include/gpiod.h
406
include/gpiod.h
@@ -74,412 +74,6 @@ struct gpiod_line_bulk_iter;
|
||||
*/
|
||||
#define GPIOD_BIT(nr) (1UL << (nr))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
* @defgroup high_level High-level API
|
||||
* @{
|
||||
*
|
||||
* Simple high-level routines for straightforward GPIO manipulation without
|
||||
* the need to use the gpiod_* structures or to keep track of resources.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Miscellaneous GPIO flags.
|
||||
*/
|
||||
enum {
|
||||
GPIOD_CTXLESS_FLAG_OPEN_DRAIN = GPIOD_BIT(0),
|
||||
/**< The line is an open-drain port. */
|
||||
GPIOD_CTXLESS_FLAG_OPEN_SOURCE = GPIOD_BIT(1),
|
||||
/**< The line is an open-source port. */
|
||||
GPIOD_CTXLESS_FLAG_BIAS_DISABLE = GPIOD_BIT(2),
|
||||
/**< The line has neither either pull-up nor pull-down resistor */
|
||||
GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN = GPIOD_BIT(3),
|
||||
/**< The line has pull-down resistor enabled */
|
||||
GPIOD_CTXLESS_FLAG_BIAS_PULL_UP = GPIOD_BIT(4),
|
||||
/**< The line has pull-up resistor enabled */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Read current value from a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offset Offset of the GPIO line.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_get_value(const char *device, unsigned int offset,
|
||||
bool active_low, const char *consumer) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Read current value from a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offset Offset of the GPIO line.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param flags The flags for the line.
|
||||
* @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
|
||||
bool active_low, const char *consumer,
|
||||
int flags) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Read current values from a set of GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offsets Array of offsets of lines whose values should be read.
|
||||
* @param values Buffer in which the values will be stored.
|
||||
* @param num_lines Number of lines, must be > 0.
|
||||
* @param active_low The active state of the lines - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_get_value_multiple(const char *device,
|
||||
const unsigned int *offsets, int *values,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Read current values from a set of GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offsets Array of offsets of lines whose values should be read.
|
||||
* @param values Buffer in which the values will be stored.
|
||||
* @param num_lines Number of lines, must be > 0.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param flags The flags for the lines.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_get_value_multiple_ext(const char *device,
|
||||
const unsigned int *offsets,
|
||||
int *values, unsigned int num_lines,
|
||||
bool active_low, const char *consumer,
|
||||
int flags) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Simple set value callback signature.
|
||||
*/
|
||||
typedef void (*gpiod_ctxless_set_value_cb)(void *);
|
||||
|
||||
/**
|
||||
* @brief Set value of a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offset The offset of the GPIO line.
|
||||
* @param value New value (0 or 1).
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param cb Optional callback function that will be called right after setting
|
||||
* the value. Users can use this, for example, to pause the execution
|
||||
* after toggling a GPIO.
|
||||
* @param data Optional user data that will be passed to the callback function.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
|
||||
bool active_low, const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb,
|
||||
void *data) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Set value of a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offset The offset of the GPIO line.
|
||||
* @param value New value (0 or 1).
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param cb Optional callback function that will be called right after setting
|
||||
* the value. Users can use this, for example, to pause the execution
|
||||
* after toggling a GPIO.
|
||||
* @param data Optional user data that will be passed to the callback function.
|
||||
* @param flags The flags for the line.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
|
||||
int value, bool active_low,
|
||||
const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb,
|
||||
void *data, int flags) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Set values of multiple GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offsets Array of offsets of lines the values of which should be set.
|
||||
* @param values Array of integers containing new values.
|
||||
* @param num_lines Number of lines, must be > 0.
|
||||
* @param active_low The active state of the lines - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param cb Optional callback function that will be called right after setting
|
||||
* all values. Works the same as in ::gpiod_ctxless_set_value.
|
||||
* @param data Optional user data that will be passed to the callback function.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_set_value_multiple(const char *device,
|
||||
const unsigned int *offsets,
|
||||
const int *values, unsigned int num_lines,
|
||||
bool active_low, const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb,
|
||||
void *data) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Set values of multiple GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param offsets Array of offsets of lines the values of which should be set.
|
||||
* @param values Array of integers containing new values.
|
||||
* @param num_lines Number of lines, must be > 0.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param cb Optional callback function that will be called right after setting
|
||||
* all values. Works the same as in ::gpiod_ctxless_set_value.
|
||||
* @param data Optional user data that will be passed to the callback function.
|
||||
* @param flags The flags for the lines.
|
||||
* @return 0 if the operation succeeds, -1 on error.
|
||||
*/
|
||||
int gpiod_ctxless_set_value_multiple_ext(const char *device,
|
||||
const unsigned int *offsets,
|
||||
const int *values,
|
||||
unsigned int num_lines,
|
||||
bool active_low,
|
||||
const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb,
|
||||
void *data, int flags) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Event types that the ctxless event monitor can wait for.
|
||||
*/
|
||||
enum {
|
||||
/**< Wait for rising edge events only. */
|
||||
GPIOD_CTXLESS_EVENT_RISING_EDGE = 1,
|
||||
/**< Wait for falling edge events only. */
|
||||
GPIOD_CTXLESS_EVENT_FALLING_EDGE,
|
||||
/**< Wait for both types of events. */
|
||||
GPIOD_CTXLESS_EVENT_BOTH_EDGES,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event types that can be passed to the ctxless event callback.
|
||||
*/
|
||||
enum {
|
||||
GPIOD_CTXLESS_EVENT_CB_TIMEOUT = 1,
|
||||
/**< Waiting for events timed out. */
|
||||
GPIOD_CTXLESS_EVENT_CB_RISING_EDGE,
|
||||
/**< Rising edge event occured. */
|
||||
GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE,
|
||||
/**< Falling edge event occured. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return status values that the ctxless event callback can return.
|
||||
*/
|
||||
enum {
|
||||
GPIOD_CTXLESS_EVENT_CB_RET_ERR = -1,
|
||||
/**< Stop processing events and indicate an error. */
|
||||
GPIOD_CTXLESS_EVENT_CB_RET_OK = 0,
|
||||
/**< Continue processing events. */
|
||||
GPIOD_CTXLESS_EVENT_CB_RET_STOP = 1,
|
||||
/**< Stop processing events. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple event callback signature.
|
||||
*
|
||||
* The callback function takes the following arguments: event type (int),
|
||||
* GPIO line offset (unsigned int), event timestamp (const struct timespec *)
|
||||
* and a pointer to user data (void *).
|
||||
*
|
||||
* This callback is called by the ctxless event loop functions for each GPIO
|
||||
* event. If the callback returns ::GPIOD_CTXLESS_EVENT_CB_RET_ERR, it should
|
||||
* also set errno.
|
||||
*/
|
||||
typedef int (*gpiod_ctxless_event_handle_cb)(int, unsigned int,
|
||||
const struct timespec *, void *);
|
||||
|
||||
/**
|
||||
* @brief Return status values that the ctxless event poll callback can return.
|
||||
*
|
||||
* Positive value returned from the polling callback indicates the number of
|
||||
* events that occurred on the set of monitored lines.
|
||||
*/
|
||||
enum {
|
||||
GPIOD_CTXLESS_EVENT_POLL_RET_STOP = -2,
|
||||
/**< The event loop should stop processing events. */
|
||||
GPIOD_CTXLESS_EVENT_POLL_RET_ERR = -1,
|
||||
/**< Polling error occurred (the polling function should set errno). */
|
||||
GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT = 0,
|
||||
/**< Poll timed out. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper structure for the ctxless event loop poll callback.
|
||||
*/
|
||||
struct gpiod_ctxless_event_poll_fd {
|
||||
int fd;
|
||||
/**< File descriptor number. */
|
||||
bool event;
|
||||
/**< Indicates whether an event occurred on this file descriptor. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple event poll callback signature.
|
||||
*
|
||||
* The poll callback function takes the following arguments: number of lines
|
||||
* (unsigned int), an array of file descriptors on which input events should
|
||||
* be monitored (struct gpiod_ctxless_event_poll_fd *), poll timeout
|
||||
* (const struct timespec *) and a pointer to user data (void *).
|
||||
*
|
||||
* The callback should poll for input events on the set of descriptors and
|
||||
* return an appropriate value that can be interpreted by the event loop
|
||||
* routine.
|
||||
*/
|
||||
typedef int (*gpiod_ctxless_event_poll_cb)(unsigned int,
|
||||
struct gpiod_ctxless_event_poll_fd *,
|
||||
const struct timespec *, void *);
|
||||
|
||||
/**
|
||||
* @brief Wait for events on a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param event_type Type of events to listen for.
|
||||
* @param offset GPIO line offset to monitor.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param timeout Maximum wait time for each iteration.
|
||||
* @param poll_cb Callback function to call when waiting for events.
|
||||
* @param event_cb Callback function to call for each line event.
|
||||
* @param data User data passed to the callback.
|
||||
* @return 0 if no errors were encountered, -1 if an error occurred.
|
||||
* @note The way the ctxless event loop works is described in detail in
|
||||
* ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
|
||||
* this routine which calls it for a single GPIO line.
|
||||
*/
|
||||
int gpiod_ctxless_event_monitor(const char *device, int event_type,
|
||||
unsigned int offset, bool active_low,
|
||||
const char *consumer,
|
||||
const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Wait for events on a single GPIO line.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param event_type Type of events to listen for.
|
||||
* @param offset GPIO line offset to monitor.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param timeout Maximum wait time for each iteration.
|
||||
* @param poll_cb Callback function to call when waiting for events.
|
||||
* @param event_cb Callback function to call for each line event.
|
||||
* @param data User data passed to the callback.
|
||||
* @param flags The flags for the line.
|
||||
* @return 0 if no errors were encountered, -1 if an error occurred.
|
||||
* @note The way the ctxless event loop works is described in detail in
|
||||
* ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
|
||||
* this routine which calls it for a single GPIO line.
|
||||
*/
|
||||
int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
|
||||
unsigned int offset, bool active_low,
|
||||
const char *consumer,
|
||||
const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data, int flags) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Wait for events on multiple GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param event_type Type of events to listen for.
|
||||
* @param offsets Array of GPIO line offsets to monitor.
|
||||
* @param num_lines Number of lines to monitor.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param timeout Maximum wait time for each iteration.
|
||||
* @param poll_cb Callback function to call when waiting for events. Can
|
||||
* be NULL.
|
||||
* @param event_cb Callback function to call on event occurrence.
|
||||
* @param data User data passed to the callback.
|
||||
* @return 0 no errors were encountered, -1 if an error occurred.
|
||||
* @note The poll callback can be NULL in which case the routine will fall
|
||||
* back to a basic, ppoll() based callback.
|
||||
*
|
||||
* Internally this routine opens the GPIO chip, requests the set of lines for
|
||||
* the type of events specified in the event_type parameter and calls the
|
||||
* polling callback in a loop. The role of the polling callback is to detect
|
||||
* input events on a set of file descriptors and notify the caller about the
|
||||
* fds ready for reading.
|
||||
*
|
||||
* The ctxless event loop then reads each queued event from marked descriptors
|
||||
* and calls the event callback. Both callbacks can stop the loop at any
|
||||
* point.
|
||||
*
|
||||
* The poll_cb argument can be NULL in which case the function falls back to
|
||||
* a default, ppoll() based callback.
|
||||
*/
|
||||
int gpiod_ctxless_event_monitor_multiple(
|
||||
const char *device, int event_type,
|
||||
const unsigned int *offsets,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer, const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @brief Wait for events on multiple GPIO lines.
|
||||
* @param device Name, path, number or label of the gpiochip.
|
||||
* @param event_type Type of events to listen for.
|
||||
* @param offsets Array of GPIO line offsets to monitor.
|
||||
* @param num_lines Number of lines to monitor.
|
||||
* @param active_low The active state of this line - true if low.
|
||||
* @param consumer Name of the consumer.
|
||||
* @param timeout Maximum wait time for each iteration.
|
||||
* @param poll_cb Callback function to call when waiting for events. Can
|
||||
* be NULL.
|
||||
* @param event_cb Callback function to call on event occurrence.
|
||||
* @param data User data passed to the callback.
|
||||
* @param flags The flags for the lines.
|
||||
* @return 0 no errors were encountered, -1 if an error occurred.
|
||||
* @note The poll callback can be NULL in which case the routine will fall
|
||||
* back to a basic, ppoll() based callback.
|
||||
*
|
||||
* Internally this routine opens the GPIO chip, requests the set of lines for
|
||||
* the type of events specified in the event_type parameter and calls the
|
||||
* polling callback in a loop. The role of the polling callback is to detect
|
||||
* input events on a set of file descriptors and notify the caller about the
|
||||
* fds ready for reading.
|
||||
*
|
||||
* The ctxless event loop then reads each queued event from marked descriptors
|
||||
* and calls the event callback. Both callbacks can stop the loop at any
|
||||
* point.
|
||||
*
|
||||
* The poll_cb argument can be NULL in which case the function falls back to
|
||||
* a default, ppoll() based callback.
|
||||
*/
|
||||
int gpiod_ctxless_event_monitor_multiple_ext(
|
||||
const char *device, int event_type,
|
||||
const unsigned int *offsets,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer, const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data, int flags) GPIOD_API;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Determine the chip name and line offset of a line with given name.
|
||||
* @param name The name of the GPIO line to lookup.
|
||||
* @param chipname Buffer in which the name of the GPIO chip will be stored.
|
||||
* @param chipname_size Size of the chip name buffer.
|
||||
* @param offset Pointer to an integer in which the line offset will be stored.
|
||||
* @return -1 on error, 0 if the line with given name doesn't exist and 1 if
|
||||
* the line was found. In the first two cases the contents of chipname
|
||||
* and offset remain unchanged.
|
||||
* @note The chip name is truncated if the buffer can't hold its entire size.
|
||||
* @attention GPIO line names are not unique in the linux kernel, neither
|
||||
* globally nor within a single chip. This function finds the first
|
||||
* line with given name.
|
||||
*/
|
||||
int gpiod_ctxless_find_line(const char *name, char *chipname,
|
||||
size_t chipname_size,
|
||||
unsigned int *offset) GPIOD_API;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
|
||||
lib_LTLIBRARIES = libgpiod.la
|
||||
libgpiod_la_SOURCES = core.c ctxless.c helpers.c iter.c misc.c
|
||||
libgpiod_la_SOURCES = core.c helpers.c iter.c misc.c
|
||||
libgpiod_la_CFLAGS = -Wall -Wextra -g -std=gnu89
|
||||
libgpiod_la_CFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/
|
||||
libgpiod_la_CFLAGS += -include $(top_builddir)/config.h
|
||||
|
||||
456
lib/ctxless.c
456
lib/ctxless.c
@@ -1,456 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*/
|
||||
|
||||
/* Implementation of the high-level API. */
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <gpiod.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int ctxless_flags_to_line_request_flags(bool active_low, int flags)
|
||||
{
|
||||
int req_flags = 0;
|
||||
|
||||
if (active_low)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
|
||||
if (flags & GPIOD_CTXLESS_FLAG_OPEN_DRAIN)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
|
||||
if (flags & GPIOD_CTXLESS_FLAG_OPEN_SOURCE)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
|
||||
if (flags & GPIOD_CTXLESS_FLAG_BIAS_DISABLE)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
|
||||
if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_UP)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
|
||||
if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN)
|
||||
req_flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
|
||||
|
||||
return req_flags;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_get_value(const char *device, unsigned int offset,
|
||||
bool active_low, const char *consumer)
|
||||
{
|
||||
int value, rv;
|
||||
|
||||
rv = gpiod_ctxless_get_value_multiple(device, &offset, &value,
|
||||
1, active_low, consumer);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
|
||||
bool active_low, const char *consumer,
|
||||
int flags)
|
||||
{
|
||||
int value, rv;
|
||||
|
||||
rv = gpiod_ctxless_get_value_multiple_ext(device, &offset, &value, 1,
|
||||
active_low, consumer, flags);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_get_value_multiple(const char *device,
|
||||
const unsigned int *offsets, int *values,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
|
||||
num_lines, active_low,
|
||||
consumer, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_get_value_multiple_ext(const char *device,
|
||||
const unsigned int *offsets,
|
||||
int *values, unsigned int num_lines,
|
||||
bool active_low,
|
||||
const char *consumer, int flags)
|
||||
{
|
||||
struct gpiod_line_bulk *bulk;
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line *line;
|
||||
unsigned int i;
|
||||
int rv, req_flags;
|
||||
|
||||
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chip = gpiod_chip_open_lookup(device);
|
||||
if (!chip)
|
||||
return -1;
|
||||
|
||||
bulk = gpiod_line_bulk_new(num_lines);
|
||||
if (!bulk) {
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
line = gpiod_chip_get_line(chip, offsets[i]);
|
||||
if (!line) {
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpiod_line_bulk_add_line(bulk, line);
|
||||
}
|
||||
|
||||
req_flags = ctxless_flags_to_line_request_flags(active_low, flags);
|
||||
rv = gpiod_line_request_bulk_input_flags(bulk, consumer, req_flags);
|
||||
if (rv < 0) {
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(values, 0, sizeof(*values) * num_lines);
|
||||
rv = gpiod_line_get_value_bulk(bulk, values);
|
||||
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
|
||||
bool active_low, const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb, void *data)
|
||||
{
|
||||
return gpiod_ctxless_set_value_multiple(device, &offset, &value, 1,
|
||||
active_low, consumer, cb, data);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
|
||||
int value, bool active_low,
|
||||
const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb,
|
||||
void *data, int flags)
|
||||
{
|
||||
return gpiod_ctxless_set_value_multiple_ext(device, &offset, &value,
|
||||
1, active_low, consumer,
|
||||
cb, data, flags);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_set_value_multiple(const char *device,
|
||||
const unsigned int *offsets,
|
||||
const int *values, unsigned int num_lines,
|
||||
bool active_low, const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb, void *data)
|
||||
{
|
||||
return gpiod_ctxless_set_value_multiple_ext(device, offsets, values,
|
||||
num_lines, active_low,
|
||||
consumer, cb, data, 0);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_set_value_multiple_ext(
|
||||
const char *device, const unsigned int *offsets,
|
||||
const int *values, unsigned int num_lines,
|
||||
bool active_low, const char *consumer,
|
||||
gpiod_ctxless_set_value_cb cb, void *data, int flags)
|
||||
{
|
||||
struct gpiod_line_bulk *bulk;
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line *line;
|
||||
unsigned int i;
|
||||
int rv, req_flags;
|
||||
|
||||
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chip = gpiod_chip_open_lookup(device);
|
||||
if (!chip)
|
||||
return -1;
|
||||
|
||||
bulk = gpiod_line_bulk_new(num_lines);
|
||||
if (!bulk) {
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
line = gpiod_chip_get_line(chip, offsets[i]);
|
||||
if (!line) {
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpiod_line_bulk_add_line(bulk, line);
|
||||
}
|
||||
|
||||
req_flags = ctxless_flags_to_line_request_flags(active_low, flags);
|
||||
rv = gpiod_line_request_bulk_output_flags(bulk, consumer,
|
||||
req_flags, values);
|
||||
if (rv < 0) {
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cb)
|
||||
cb(data);
|
||||
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int basic_event_poll(unsigned int num_lines,
|
||||
struct gpiod_ctxless_event_poll_fd *fds,
|
||||
const struct timespec *timeout,
|
||||
void *data GPIOD_UNUSED)
|
||||
{
|
||||
struct pollfd poll_fds[GPIOD_LINE_BULK_MAX_LINES];
|
||||
unsigned int i;
|
||||
int rv, ret;
|
||||
|
||||
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES)
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_ERR;
|
||||
|
||||
memset(poll_fds, 0, sizeof(poll_fds));
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
poll_fds[i].fd = fds[i].fd;
|
||||
poll_fds[i].events = POLLIN | POLLPRI;
|
||||
}
|
||||
|
||||
rv = ppoll(poll_fds, num_lines, timeout, NULL);
|
||||
if (rv < 0) {
|
||||
if (errno == EINTR)
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT;
|
||||
else
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_ERR;
|
||||
} else if (rv == 0) {
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT;
|
||||
}
|
||||
|
||||
ret = rv;
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
if (poll_fds[i].revents) {
|
||||
fds[i].event = true;
|
||||
if (!--rv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_event_monitor(const char *device, int event_type,
|
||||
unsigned int offset, bool active_low,
|
||||
const char *consumer,
|
||||
const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data)
|
||||
{
|
||||
return gpiod_ctxless_event_monitor_multiple(device, event_type,
|
||||
&offset, 1, active_low,
|
||||
consumer, timeout,
|
||||
poll_cb, event_cb, data);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
|
||||
unsigned int offset, bool active_low,
|
||||
const char *consumer,
|
||||
const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data, int flags)
|
||||
{
|
||||
return gpiod_ctxless_event_monitor_multiple_ext(
|
||||
device, event_type, &offset, 1, active_low,
|
||||
consumer, timeout, poll_cb, event_cb, data, flags);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_event_monitor_multiple(
|
||||
const char *device, int event_type,
|
||||
const unsigned int *offsets,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer,
|
||||
const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data)
|
||||
{
|
||||
return gpiod_ctxless_event_monitor_multiple_ext(
|
||||
device, event_type, offsets,
|
||||
num_lines, active_low, consumer, timeout,
|
||||
poll_cb, event_cb, data, 0);
|
||||
}
|
||||
|
||||
int gpiod_ctxless_event_monitor_multiple_ext(
|
||||
const char *device, int event_type,
|
||||
const unsigned int *offsets,
|
||||
unsigned int num_lines, bool active_low,
|
||||
const char *consumer, const struct timespec *timeout,
|
||||
gpiod_ctxless_event_poll_cb poll_cb,
|
||||
gpiod_ctxless_event_handle_cb event_cb,
|
||||
void *data, int flags)
|
||||
{
|
||||
struct gpiod_ctxless_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES];
|
||||
struct gpiod_line_request_config conf;
|
||||
struct gpiod_line_event event;
|
||||
struct gpiod_line_bulk *bulk;
|
||||
int rv, ret, evtype, cnt;
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line *line;
|
||||
unsigned int i;
|
||||
|
||||
if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!poll_cb)
|
||||
poll_cb = basic_event_poll;
|
||||
|
||||
chip = gpiod_chip_open_lookup(device);
|
||||
if (!chip)
|
||||
return -1;
|
||||
|
||||
bulk = gpiod_line_bulk_new(num_lines);
|
||||
if (!bulk) {
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
line = gpiod_chip_get_line(chip, offsets[i]);
|
||||
if (!line) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gpiod_line_bulk_add_line(bulk, line);
|
||||
}
|
||||
|
||||
conf.flags = ctxless_flags_to_line_request_flags(active_low, flags);
|
||||
conf.consumer = consumer;
|
||||
|
||||
if (event_type == GPIOD_CTXLESS_EVENT_RISING_EDGE) {
|
||||
conf.request_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE;
|
||||
} else if (event_type == GPIOD_CTXLESS_EVENT_FALLING_EDGE) {
|
||||
conf.request_type = GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE;
|
||||
} else if (event_type == GPIOD_CTXLESS_EVENT_BOTH_EDGES) {
|
||||
conf.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
|
||||
} else {
|
||||
errno = -EINVAL;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = gpiod_line_request_bulk(bulk, &conf, NULL);
|
||||
if (rv) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(fds, 0, sizeof(fds));
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
line = gpiod_line_bulk_get_line(bulk, i);
|
||||
fds[i].fd = gpiod_line_event_get_fd(line);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (i = 0; i < num_lines; i++)
|
||||
fds[i].event = false;
|
||||
|
||||
cnt = poll_cb(num_lines, fds, timeout, data);
|
||||
if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_ERR) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
} else if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT) {
|
||||
rv = event_cb(GPIOD_CTXLESS_EVENT_CB_TIMEOUT,
|
||||
0, &event.ts, data);
|
||||
if (rv == GPIOD_CTXLESS_EVENT_CB_RET_ERR) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
} else if (rv == GPIOD_CTXLESS_EVENT_CB_RET_STOP) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
} else if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_STOP) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
if (!fds[i].event)
|
||||
continue;
|
||||
|
||||
line = gpiod_line_bulk_get_line(bulk, i);
|
||||
rv = gpiod_line_event_read(line, &event);
|
||||
if (rv < 0) {
|
||||
ret = rv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
|
||||
evtype = GPIOD_CTXLESS_EVENT_CB_RISING_EDGE;
|
||||
else
|
||||
evtype = GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE;
|
||||
|
||||
rv = event_cb(evtype, gpiod_line_offset(line),
|
||||
&event.ts, data);
|
||||
if (rv == GPIOD_CTXLESS_EVENT_CB_RET_ERR) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
} else if (rv == GPIOD_CTXLESS_EVENT_CB_RET_STOP) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!--cnt)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
gpiod_line_bulk_free(bulk);
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpiod_ctxless_find_line(const char *name, char *chipname,
|
||||
size_t chipname_size, unsigned int *offset)
|
||||
{
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line *line;
|
||||
|
||||
line = gpiod_line_find(name);
|
||||
if (!line) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
chip = gpiod_line_get_chip(line);
|
||||
snprintf(chipname, chipname_size, "%s", gpiod_chip_name(chip));
|
||||
*offset = gpiod_line_offset(line);
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -24,7 +24,6 @@ gpiod_test_SOURCES = \
|
||||
gpiod-test.h \
|
||||
tests-bulk.c \
|
||||
tests-chip.c \
|
||||
tests-ctxless.c \
|
||||
tests-event.c \
|
||||
tests-iter.c \
|
||||
tests-line.c \
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/*
|
||||
* This file is part of libgpiod.
|
||||
*
|
||||
* Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "gpiod-test.h"
|
||||
|
||||
#define GPIOD_TEST_GROUP "ctxless"
|
||||
|
||||
GPIOD_TEST_CASE(get_value, 0, { 8 })
|
||||
{
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_get_value(gpiod_test_chip_name(0), 3,
|
||||
false, GPIOD_TEST_CONSUMER);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
gpiod_test_chip_set_pull(0, 3, 1);
|
||||
|
||||
ret = gpiod_ctxless_get_value(gpiod_test_chip_name(0), 3,
|
||||
false, GPIOD_TEST_CONSUMER);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
|
||||
{
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
|
||||
false, GPIOD_TEST_CONSUMER,
|
||||
GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
|
||||
false, GPIOD_TEST_CONSUMER,
|
||||
GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
|
||||
ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
|
||||
true, GPIOD_TEST_CONSUMER
|
||||
, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
|
||||
ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
|
||||
true, GPIOD_TEST_CONSUMER,
|
||||
GPIOD_CTXLESS_FLAG_BIAS_PULL_UP);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
}
|
||||
|
||||
static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
|
||||
}
|
||||
|
||||
static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(set_value, 0, { 8 })
|
||||
{
|
||||
gint ret;
|
||||
|
||||
gpiod_test_chip_set_pull(0, 3, 0);
|
||||
|
||||
ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
|
||||
false, GPIOD_TEST_CONSUMER,
|
||||
set_value_check_hi, NULL);
|
||||
gpiod_test_return_if_failed();
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
|
||||
{
|
||||
gint ret;
|
||||
|
||||
gpiod_test_chip_set_pull(0, 3, 0);
|
||||
|
||||
ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
|
||||
false, GPIOD_TEST_CONSUMER,
|
||||
set_value_check_hi, NULL, 0);
|
||||
gpiod_test_return_if_failed();
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
|
||||
|
||||
/* test drive flags by checking that sets are caught by emulation */
|
||||
ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
|
||||
false, GPIOD_TEST_CONSUMER, set_value_check_lo,
|
||||
NULL, GPIOD_CTXLESS_FLAG_OPEN_DRAIN);
|
||||
gpiod_test_return_if_failed();
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
|
||||
|
||||
gpiod_test_chip_set_pull(0, 3, 1);
|
||||
ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 0,
|
||||
false, GPIOD_TEST_CONSUMER, set_value_check_hi,
|
||||
NULL, GPIOD_CTXLESS_FLAG_OPEN_SOURCE);
|
||||
gpiod_test_return_if_failed();
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
|
||||
}
|
||||
|
||||
static const guint get_value_multiple_offsets[] = {
|
||||
1, 3, 4, 5, 6, 7, 8, 9, 13, 14
|
||||
};
|
||||
|
||||
static const gint get_value_multiple_expected[] = {
|
||||
1, 1, 1, 0, 0, 0, 1, 0, 1, 1
|
||||
};
|
||||
|
||||
GPIOD_TEST_CASE(get_value_multiple, 0, { 16 })
|
||||
{
|
||||
gint ret, values[10];
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(get_value_multiple_offsets); i++)
|
||||
gpiod_test_chip_set_pull(0, get_value_multiple_offsets[i],
|
||||
get_value_multiple_expected[i]);
|
||||
|
||||
ret = gpiod_ctxless_get_value_multiple(gpiod_test_chip_name(0),
|
||||
get_value_multiple_offsets,
|
||||
values, 10, false,
|
||||
GPIOD_TEST_CONSUMER);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(get_value_multiple_offsets); i++)
|
||||
g_assert_cmpint(values[i], ==, get_value_multiple_expected[i]);
|
||||
}
|
||||
|
||||
static const guint set_value_multiple_offsets[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 12, 13, 15
|
||||
};
|
||||
|
||||
static const gint set_value_multiple_values[] = {
|
||||
1, 1, 1, 0, 0, 1, 0, 1, 0, 0
|
||||
};
|
||||
|
||||
static void set_value_multiple_check(gpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
guint i, offset;
|
||||
gint val, exp;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(set_value_multiple_values); i++) {
|
||||
offset = set_value_multiple_offsets[i];
|
||||
exp = set_value_multiple_values[i];
|
||||
val = gpiod_test_chip_get_value(0, offset);
|
||||
|
||||
g_assert_cmpint(val, ==, exp);
|
||||
}
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(set_value_multiple, 0, { 16 })
|
||||
{
|
||||
gint values[10], ret;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(set_value_multiple_offsets); i++)
|
||||
values[i] = set_value_multiple_values[i];
|
||||
|
||||
ret = gpiod_ctxless_set_value_multiple(gpiod_test_chip_name(0),
|
||||
set_value_multiple_offsets, values, 10, false,
|
||||
GPIOD_TEST_CONSUMER, set_value_multiple_check, NULL);
|
||||
gpiod_test_return_if_failed();
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(get_value_multiple_max_lines, 0, { 128 })
|
||||
{
|
||||
gint values[GPIOD_LINE_BULK_MAX_LINES + 1], ret;
|
||||
guint offsets[GPIOD_LINE_BULK_MAX_LINES + 1];
|
||||
|
||||
ret = gpiod_ctxless_get_value_multiple(gpiod_test_chip_name(0),
|
||||
offsets, values,
|
||||
GPIOD_LINE_BULK_MAX_LINES + 1,
|
||||
false, GPIOD_TEST_CONSUMER);
|
||||
g_assert_cmpint(ret, ==, -1);
|
||||
g_assert_cmpint(errno, ==, EINVAL);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(set_value_multiple_max_lines, 0, { 128 })
|
||||
{
|
||||
gint values[GPIOD_LINE_BULK_MAX_LINES + 1], ret;
|
||||
guint offsets[GPIOD_LINE_BULK_MAX_LINES + 1];
|
||||
|
||||
ret = gpiod_ctxless_set_value_multiple(gpiod_test_chip_name(0),
|
||||
offsets, values, GPIOD_LINE_BULK_MAX_LINES + 1,
|
||||
false, GPIOD_TEST_CONSUMER, NULL, NULL);
|
||||
g_assert_cmpint(ret, ==, -1);
|
||||
g_assert_cmpint(errno, ==, EINVAL);
|
||||
}
|
||||
|
||||
struct ctxless_event_data {
|
||||
gboolean got_rising_edge;
|
||||
gboolean got_falling_edge;
|
||||
guint offset;
|
||||
guint count;
|
||||
};
|
||||
|
||||
static int ctxless_event_cb(gint evtype, guint offset,
|
||||
const struct timespec *ts G_GNUC_UNUSED,
|
||||
gpointer data)
|
||||
{
|
||||
struct ctxless_event_data *evdata = data;
|
||||
|
||||
if (evtype == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE)
|
||||
evdata->got_rising_edge = TRUE;
|
||||
else if (evtype == GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE)
|
||||
evdata->got_falling_edge = TRUE;
|
||||
|
||||
evdata->offset = offset;
|
||||
|
||||
return ++evdata->count == 2 ? GPIOD_CTXLESS_EVENT_CB_RET_STOP
|
||||
: GPIOD_CTXLESS_EVENT_CB_RET_OK;
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(event_monitor, 0, { 8 })
|
||||
{
|
||||
g_autoptr(GpiodTestEventThread) ev_thread = NULL;
|
||||
struct ctxless_event_data evdata = { false, false, 0, 0 };
|
||||
struct timespec ts = { 1, 0 };
|
||||
gint ret;
|
||||
|
||||
ev_thread = gpiod_test_start_event_thread(0, 3, 100);
|
||||
|
||||
ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0),
|
||||
GPIOD_CTXLESS_EVENT_BOTH_EDGES,
|
||||
3, false, GPIOD_TEST_CONSUMER, &ts,
|
||||
NULL, ctxless_event_cb, &evdata);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_true(evdata.got_rising_edge);
|
||||
g_assert_true(evdata.got_falling_edge);
|
||||
g_assert_cmpuint(evdata.count, ==, 2);
|
||||
g_assert_cmpuint(evdata.offset, ==, 3);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(event_monitor_single_event_type, 0, { 8 })
|
||||
{
|
||||
g_autoptr(GpiodTestEventThread) ev_thread = NULL;
|
||||
struct ctxless_event_data evdata = { false, false, 0, 0 };
|
||||
struct timespec ts = { 1, 0 };
|
||||
gint ret;
|
||||
|
||||
ev_thread = gpiod_test_start_event_thread(0, 3, 100);
|
||||
|
||||
ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0),
|
||||
GPIOD_CTXLESS_EVENT_FALLING_EDGE,
|
||||
3, false, GPIOD_TEST_CONSUMER, &ts,
|
||||
NULL, ctxless_event_cb, &evdata);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_false(evdata.got_rising_edge);
|
||||
g_assert_true(evdata.got_falling_edge);
|
||||
g_assert_cmpuint(evdata.count, ==, 2);
|
||||
g_assert_cmpuint(evdata.offset, ==, 3);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(event_monitor_multiple, 0, { 8 })
|
||||
{
|
||||
g_autoptr(GpiodTestEventThread) ev_thread = NULL;
|
||||
struct ctxless_event_data evdata = { false, false, 0, 0 };
|
||||
struct timespec ts = { 1, 0 };
|
||||
guint offsets[4];
|
||||
gint ret;
|
||||
|
||||
offsets[0] = 2;
|
||||
offsets[1] = 3;
|
||||
offsets[2] = 5;
|
||||
offsets[3] = 6;
|
||||
|
||||
ev_thread = gpiod_test_start_event_thread(0, 3, 100);
|
||||
|
||||
ret = gpiod_ctxless_event_monitor_multiple(gpiod_test_chip_name(0),
|
||||
GPIOD_CTXLESS_EVENT_BOTH_EDGES, offsets, 4, false,
|
||||
GPIOD_TEST_CONSUMER, &ts, NULL, ctxless_event_cb, &evdata);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
g_assert_true(evdata.got_rising_edge);
|
||||
g_assert_true(evdata.got_falling_edge);
|
||||
g_assert_cmpuint(evdata.count, ==, 2);
|
||||
g_assert_cmpuint(evdata.offset, ==, 3);
|
||||
}
|
||||
|
||||
static int error_event_cb(gint evtype G_GNUC_UNUSED,
|
||||
guint offset G_GNUC_UNUSED,
|
||||
const struct timespec *ts G_GNUC_UNUSED,
|
||||
gpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
errno = ENOTBLK;
|
||||
|
||||
return GPIOD_CTXLESS_EVENT_CB_RET_ERR;
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(event_monitor_indicate_error, 0, { 8 })
|
||||
{
|
||||
g_autoptr(GpiodTestEventThread) ev_thread = NULL;
|
||||
struct timespec ts = { 1, 0 };
|
||||
gint ret;
|
||||
|
||||
ev_thread = gpiod_test_start_event_thread(0, 3, 100);
|
||||
|
||||
ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0),
|
||||
GPIOD_CTXLESS_EVENT_BOTH_EDGES,
|
||||
3, false, GPIOD_TEST_CONSUMER, &ts,
|
||||
NULL, error_event_cb, NULL);
|
||||
g_assert_cmpint(ret, ==, -1);
|
||||
g_assert_cmpint(errno, ==, ENOTBLK);
|
||||
}
|
||||
|
||||
static int error_event_cb_timeout(gint evtype,
|
||||
guint offset G_GNUC_UNUSED,
|
||||
const struct timespec *ts G_GNUC_UNUSED,
|
||||
gpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
errno = ENOTBLK;
|
||||
|
||||
g_assert_cmpint(evtype, ==, GPIOD_CTXLESS_EVENT_CB_TIMEOUT);
|
||||
|
||||
return GPIOD_CTXLESS_EVENT_CB_RET_ERR;
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(event_monitor_indicate_error_timeout, 0, { 8 })
|
||||
{
|
||||
struct timespec ts = { 0, 100000 };
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0),
|
||||
GPIOD_CTXLESS_EVENT_BOTH_EDGES,
|
||||
3, false, GPIOD_TEST_CONSUMER, &ts,
|
||||
NULL, error_event_cb_timeout, NULL);
|
||||
g_assert_cmpint(ret, ==, -1);
|
||||
g_assert_cmpint(errno, ==, ENOTBLK);
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(find_line, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 })
|
||||
{
|
||||
gchar chip[32];
|
||||
guint offset;
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_find_line("gpio-mockup-C-14", chip,
|
||||
sizeof(chip), &offset);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
g_assert_cmpuint(offset, ==, 14);
|
||||
g_assert_cmpstr(chip, ==, gpiod_test_chip_name(2));
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(find_line_truncated,
|
||||
GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 })
|
||||
{
|
||||
gchar chip[6];
|
||||
guint offset;
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_find_line("gpio-mockup-C-14", chip,
|
||||
sizeof(chip), &offset);
|
||||
g_assert_cmpint(ret, ==, 1);
|
||||
g_assert_cmpuint(offset, ==, 14);
|
||||
g_assert_cmpstr(chip, ==, "gpioc");
|
||||
}
|
||||
|
||||
GPIOD_TEST_CASE(find_line_not_found,
|
||||
GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 })
|
||||
{
|
||||
gchar chip[32];
|
||||
guint offset;
|
||||
gint ret;
|
||||
|
||||
ret = gpiod_ctxless_find_line("nonexistent", chip,
|
||||
sizeof(chip), &offset);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
}
|
||||
@@ -375,7 +375,7 @@ teardown() {
|
||||
run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 1 2 3 4
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error reading GPIO values"
|
||||
output_regex_match ".*unable to retrieve GPIO lines from chip"
|
||||
}
|
||||
|
||||
@test "gpioget: same line twice" {
|
||||
@@ -384,7 +384,7 @@ teardown() {
|
||||
run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 0
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error reading GPIO values.*"
|
||||
output_regex_match ".*unable to request lines.*"
|
||||
}
|
||||
|
||||
@test "gpioget: invalid bias" {
|
||||
@@ -583,7 +583,7 @@ teardown() {
|
||||
run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=1 1=1 2=1 3=1 4=1 5=1
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error setting the GPIO line values"
|
||||
output_regex_match ".*unable to retrieve GPIO lines from chip"
|
||||
}
|
||||
|
||||
@test "gpioset: use --sec without --mode=time" {
|
||||
@@ -664,7 +664,7 @@ teardown() {
|
||||
run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=1 0=1
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error setting the GPIO line values.*"
|
||||
output_regex_match ".*unable to request lines.*"
|
||||
}
|
||||
|
||||
#
|
||||
@@ -884,7 +884,7 @@ teardown() {
|
||||
run_tool gpiomon "$(gpio_mockup_chip_name 1)" 0 0
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error waiting for events.*"
|
||||
output_regex_match ".*unable to request GPIO lines for events"
|
||||
}
|
||||
|
||||
@test "gpiomon: no arguments" {
|
||||
@@ -909,7 +909,7 @@ teardown() {
|
||||
run_tool gpiomon "$(gpio_mockup_chip_name 0)" 5
|
||||
|
||||
test "$status" -eq "1"
|
||||
output_regex_match ".*error waiting for events"
|
||||
output_regex_match ".*unable to retrieve GPIO lines from chip"
|
||||
}
|
||||
|
||||
@test "gpiomon: invalid bias" {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <gpiod.h>
|
||||
#include <stdio.h>
|
||||
@@ -33,9 +34,9 @@ static void print_help(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int offset;
|
||||
int optc, opti, rv;
|
||||
char chip[32];
|
||||
int optc, opti, ret = EXIT_SUCCESS;
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line *line;
|
||||
|
||||
for (;;) {
|
||||
optc = getopt_long(argc, argv, shortopts, longopts, &opti);
|
||||
@@ -62,13 +63,19 @@ int main(int argc, char **argv)
|
||||
if (argc != 1)
|
||||
die("exactly one GPIO line name must be specified");
|
||||
|
||||
rv = gpiod_ctxless_find_line(argv[0], chip, sizeof(chip), &offset);
|
||||
if (rv < 0)
|
||||
line = gpiod_line_find(argv[0]);
|
||||
if (!line) {
|
||||
if (errno == ENOENT)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
die_perror("error performing the line lookup");
|
||||
else if (rv == 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("%s %u\n", chip, offset);
|
||||
chip = gpiod_line_get_chip(line);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
printf("%s %u\n", gpiod_chip_name(chip), gpiod_line_offset(line));
|
||||
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -42,10 +42,11 @@ static void print_help(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct gpiod_line_request_config config;
|
||||
int *values, optc, opti, rv, flags = 0;
|
||||
unsigned int *offsets, i, num_lines;
|
||||
int *values, optc, opti, rv;
|
||||
bool active_low = false;
|
||||
int flags = 0;
|
||||
struct gpiod_line_bulk *lines;
|
||||
struct gpiod_chip *chip;
|
||||
char *device, *end;
|
||||
|
||||
for (;;) {
|
||||
@@ -61,10 +62,10 @@ int main(int argc, char **argv)
|
||||
print_version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'l':
|
||||
active_low = true;
|
||||
flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
|
||||
break;
|
||||
case 'B':
|
||||
flags = bias_flags(optarg);
|
||||
flags |= bias_flags(optarg);
|
||||
break;
|
||||
case '?':
|
||||
die("try %s --help", get_progname());
|
||||
@@ -96,9 +97,25 @@ int main(int argc, char **argv)
|
||||
die("invalid GPIO offset: %s", argv[i + 1]);
|
||||
}
|
||||
|
||||
rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
|
||||
num_lines, active_low,
|
||||
"gpioget", flags);
|
||||
chip = gpiod_chip_open_lookup(device);
|
||||
if (!chip)
|
||||
die_perror("unable to open %s", device);
|
||||
|
||||
lines = gpiod_chip_get_lines(chip, offsets, num_lines);
|
||||
if (!lines)
|
||||
die_perror("unable to retrieve GPIO lines from chip");
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.consumer = "gpioget";
|
||||
config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
|
||||
config.flags = flags;
|
||||
|
||||
rv = gpiod_line_request_bulk(lines, &config, NULL);
|
||||
if (rv)
|
||||
die_perror("unable to request lines");
|
||||
|
||||
rv = gpiod_line_get_value_bulk(lines, values);
|
||||
if (rv < 0)
|
||||
die_perror("error reading GPIO values");
|
||||
|
||||
@@ -109,6 +126,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
gpiod_line_release_bulk(lines);
|
||||
gpiod_chip_close(chip);
|
||||
gpiod_line_bulk_free(lines);
|
||||
free(values);
|
||||
free(offsets);
|
||||
|
||||
|
||||
177
tools/gpiomon.c
177
tools/gpiomon.c
@@ -10,6 +10,7 @@
|
||||
#include <gpiod.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -63,13 +64,8 @@ static void print_help(void)
|
||||
|
||||
struct mon_ctx {
|
||||
unsigned int offset;
|
||||
unsigned int events_wanted;
|
||||
unsigned int events_done;
|
||||
|
||||
bool silent;
|
||||
char *fmt;
|
||||
|
||||
int sigfd;
|
||||
};
|
||||
|
||||
static void event_print_custom(unsigned int offset,
|
||||
@@ -96,7 +92,7 @@ static void event_print_custom(unsigned int offset,
|
||||
printf("%u", offset);
|
||||
break;
|
||||
case 'e':
|
||||
if (event_type == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE)
|
||||
if (event_type == GPIOD_LINE_EVENT_RISING_EDGE)
|
||||
fputc('1', stdout);
|
||||
else
|
||||
fputc('0', stdout);
|
||||
@@ -132,7 +128,7 @@ static void event_print_human_readable(unsigned int offset,
|
||||
{
|
||||
char *evname;
|
||||
|
||||
if (event_type == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE)
|
||||
if (event_type == GPIOD_LINE_EVENT_RISING_EDGE)
|
||||
evname = " RISING EDGE";
|
||||
else
|
||||
evname = "FALLING EDGE";
|
||||
@@ -141,52 +137,8 @@ static void event_print_human_readable(unsigned int offset,
|
||||
evname, offset, ts->tv_sec, ts->tv_nsec);
|
||||
}
|
||||
|
||||
static int poll_callback(unsigned int num_lines,
|
||||
struct gpiod_ctxless_event_poll_fd *fds,
|
||||
const struct timespec *timeout, void *data)
|
||||
{
|
||||
struct pollfd pfds[GPIOD_LINE_BULK_MAX_LINES + 1];
|
||||
struct mon_ctx *ctx = data;
|
||||
int cnt, ts, rv;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
pfds[i].fd = fds[i].fd;
|
||||
pfds[i].events = POLLIN | POLLPRI;
|
||||
}
|
||||
|
||||
pfds[i].fd = ctx->sigfd;
|
||||
pfds[i].events = POLLIN | POLLPRI;
|
||||
|
||||
ts = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000;
|
||||
|
||||
cnt = poll(pfds, num_lines + 1, ts);
|
||||
if (cnt < 0)
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_ERR;
|
||||
else if (cnt == 0)
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT;
|
||||
|
||||
rv = cnt;
|
||||
for (i = 0; i < num_lines; i++) {
|
||||
if (pfds[i].revents) {
|
||||
fds[i].event = true;
|
||||
if (!--cnt)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're here, then there's a signal pending. No need to read it,
|
||||
* we know we should quit now.
|
||||
*/
|
||||
close(ctx->sigfd);
|
||||
|
||||
return GPIOD_CTXLESS_EVENT_POLL_RET_STOP;
|
||||
}
|
||||
|
||||
static void handle_event(struct mon_ctx *ctx, int event_type,
|
||||
unsigned int line_offset,
|
||||
const struct timespec *timestamp)
|
||||
static void handle_event(unsigned int line_offset, unsigned int event_type,
|
||||
struct timespec *timestamp, struct mon_ctx *ctx)
|
||||
{
|
||||
if (!ctx->silent) {
|
||||
if (ctx->fmt)
|
||||
@@ -196,43 +148,35 @@ static void handle_event(struct mon_ctx *ctx, int event_type,
|
||||
event_print_human_readable(line_offset,
|
||||
timestamp, event_type);
|
||||
}
|
||||
|
||||
ctx->events_done++;
|
||||
}
|
||||
|
||||
static int event_callback(int event_type, unsigned int line_offset,
|
||||
const struct timespec *timestamp, void *data)
|
||||
static void handle_signal(int signum GPIOD_UNUSED)
|
||||
{
|
||||
struct mon_ctx *ctx = data;
|
||||
|
||||
switch (event_type) {
|
||||
case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE:
|
||||
case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE:
|
||||
handle_event(ctx, event_type, line_offset, timestamp);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* REVISIT: This happening would indicate a problem in the
|
||||
* library.
|
||||
*/
|
||||
return GPIOD_CTXLESS_EVENT_CB_RET_OK;
|
||||
}
|
||||
|
||||
if (ctx->events_wanted && ctx->events_done >= ctx->events_wanted)
|
||||
return GPIOD_CTXLESS_EVENT_CB_RET_STOP;
|
||||
|
||||
return GPIOD_CTXLESS_EVENT_CB_RET_OK;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset;
|
||||
bool active_low = false, watch_rising = false, watch_falling = false;
|
||||
unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset,
|
||||
events_wanted = 0, events_done = 0, x;
|
||||
bool watch_rising = false, watch_falling = false;
|
||||
int flags = 0;
|
||||
struct timespec timeout = { 10, 0 };
|
||||
int optc, opti, rv, i, event_type;
|
||||
int optc, opti, rv, i, y, event_type;
|
||||
struct mon_ctx ctx;
|
||||
struct gpiod_chip *chip;
|
||||
struct gpiod_line_bulk *lines, *evlines;
|
||||
char *end;
|
||||
struct gpiod_line_request_config config;
|
||||
struct gpiod_line *line;
|
||||
struct gpiod_line_event events[16];
|
||||
|
||||
/*
|
||||
* FIXME: use signalfd once the API has been converted to using a single file
|
||||
* descriptor as provided by uAPI v2.
|
||||
*/
|
||||
signal(SIGINT, handle_signal);
|
||||
signal(SIGTERM, handle_signal);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
||||
@@ -249,13 +193,13 @@ int main(int argc, char **argv)
|
||||
print_version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'l':
|
||||
active_low = true;
|
||||
flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
|
||||
break;
|
||||
case 'B':
|
||||
flags = bias_flags(optarg);
|
||||
flags |= bias_flags(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
ctx.events_wanted = strtoul(optarg, &end, 10);
|
||||
events_wanted = strtoul(optarg, &end, 10);
|
||||
if (*end != '\0')
|
||||
die("invalid number: %s", optarg);
|
||||
break;
|
||||
@@ -285,11 +229,11 @@ int main(int argc, char **argv)
|
||||
argv += optind;
|
||||
|
||||
if (watch_rising && !watch_falling)
|
||||
event_type = GPIOD_CTXLESS_EVENT_RISING_EDGE;
|
||||
event_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE;
|
||||
else if (watch_falling && !watch_rising)
|
||||
event_type = GPIOD_CTXLESS_EVENT_FALLING_EDGE;
|
||||
event_type = GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE;
|
||||
else
|
||||
event_type = GPIOD_CTXLESS_EVENT_BOTH_EDGES;
|
||||
event_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
|
||||
|
||||
if (argc < 1)
|
||||
die("gpiochip must be specified");
|
||||
@@ -306,15 +250,64 @@ int main(int argc, char **argv)
|
||||
num_lines++;
|
||||
}
|
||||
|
||||
ctx.sigfd = make_signalfd();
|
||||
chip = gpiod_chip_open_lookup(argv[0]);
|
||||
if (!chip)
|
||||
die_perror("unable to open %s", argv[0]);
|
||||
|
||||
rv = gpiod_ctxless_event_monitor_multiple_ext(
|
||||
argv[0], event_type, offsets,
|
||||
num_lines, active_low, "gpiomon",
|
||||
&timeout, poll_callback,
|
||||
event_callback, &ctx, flags);
|
||||
lines = gpiod_chip_get_lines(chip, offsets, num_lines);
|
||||
if (!lines)
|
||||
die_perror("unable to retrieve GPIO lines from chip");
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.consumer = "gpiomon";
|
||||
config.request_type = event_type;
|
||||
config.flags = flags;
|
||||
|
||||
rv = gpiod_line_request_bulk(lines, &config, NULL);
|
||||
if (rv)
|
||||
die_perror("error waiting for events");
|
||||
die_perror("unable to request GPIO lines for events");
|
||||
|
||||
evlines = gpiod_line_bulk_new(num_lines);
|
||||
if (!evlines)
|
||||
die("out of memory");
|
||||
|
||||
for (;;) {
|
||||
gpiod_line_bulk_reset(evlines);
|
||||
rv = gpiod_line_event_wait_bulk(lines, &timeout, evlines);
|
||||
if (rv < 0)
|
||||
die_perror("error waiting for events");
|
||||
if (rv == 0)
|
||||
continue;
|
||||
|
||||
num_lines = gpiod_line_bulk_num_lines(evlines);
|
||||
|
||||
for (x = 0; x < num_lines; x++) {
|
||||
line = gpiod_line_bulk_get_line(evlines, x);
|
||||
|
||||
rv = gpiod_line_event_read_multiple(line, events,
|
||||
ARRAY_SIZE(events));
|
||||
if (rv < 0)
|
||||
die_perror("error reading line events");
|
||||
|
||||
for (y = 0; y < rv; y++) {
|
||||
handle_event(gpiod_line_offset(line),
|
||||
events[y].event_type,
|
||||
&events[y].ts, &ctx);
|
||||
events_done++;
|
||||
|
||||
if (events_wanted &&
|
||||
events_done >= events_wanted)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
gpiod_line_release_bulk(lines);
|
||||
gpiod_line_bulk_free(lines);
|
||||
gpiod_line_bulk_free(evlines);
|
||||
gpiod_chip_close(chip);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ enum {
|
||||
struct mode_mapping {
|
||||
int id;
|
||||
const char *name;
|
||||
gpiod_ctxless_set_value_cb callback;
|
||||
void (*callback)(void *);
|
||||
};
|
||||
|
||||
static const struct mode_mapping modes[] = {
|
||||
@@ -182,9 +182,9 @@ static const struct mode_mapping *parse_mode(const char *mode)
|
||||
static int drive_flags(const char *option)
|
||||
{
|
||||
if (strcmp(option, "open-drain") == 0)
|
||||
return GPIOD_CTXLESS_FLAG_OPEN_DRAIN;
|
||||
return GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
|
||||
if (strcmp(option, "open-source") == 0)
|
||||
return GPIOD_CTXLESS_FLAG_OPEN_SOURCE;
|
||||
return GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
|
||||
if (strcmp(option, "push-pull") != 0)
|
||||
die("invalid drive: %s", option);
|
||||
return 0;
|
||||
@@ -193,10 +193,12 @@ static int drive_flags(const char *option)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const struct mode_mapping *mode = &modes[MODE_EXIT];
|
||||
unsigned int *offsets, num_lines, i;
|
||||
struct gpiod_line_request_config config;
|
||||
int *values, rv, optc, opti, flags = 0;
|
||||
unsigned int *offsets, num_lines, i;
|
||||
struct gpiod_line_bulk *lines;
|
||||
struct callback_data cbdata;
|
||||
bool active_low = false;
|
||||
struct gpiod_chip *chip;
|
||||
char *device, *end;
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
@@ -214,7 +216,7 @@ int main(int argc, char **argv)
|
||||
print_version();
|
||||
return EXIT_SUCCESS;
|
||||
case 'l':
|
||||
active_low = true;
|
||||
flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
|
||||
break;
|
||||
case 'B':
|
||||
flags |= bias_flags(optarg);
|
||||
@@ -286,13 +288,29 @@ int main(int argc, char **argv)
|
||||
die("invalid offset: %s", argv[i + 1]);
|
||||
}
|
||||
|
||||
rv = gpiod_ctxless_set_value_multiple_ext(
|
||||
device, offsets, values,
|
||||
num_lines, active_low, "gpioset",
|
||||
mode->callback, &cbdata, flags);
|
||||
if (rv < 0)
|
||||
die_perror("error setting the GPIO line values");
|
||||
chip = gpiod_chip_open_lookup(device);
|
||||
if (!chip)
|
||||
die_perror("unable to open %s", device);
|
||||
|
||||
lines = gpiod_chip_get_lines(chip, offsets, num_lines);
|
||||
if (!lines)
|
||||
die_perror("unable to retrieve GPIO lines from chip");
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.consumer = "gpioset";
|
||||
config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
|
||||
config.flags = flags;
|
||||
|
||||
rv = gpiod_line_request_bulk(lines, &config, values);
|
||||
if (rv)
|
||||
die_perror("unable to request lines");
|
||||
|
||||
mode->callback(&cbdata);
|
||||
|
||||
gpiod_line_release_bulk(lines);
|
||||
gpiod_chip_close(chip);
|
||||
gpiod_line_bulk_free(lines);
|
||||
free(offsets);
|
||||
free(values);
|
||||
|
||||
|
||||
@@ -63,11 +63,11 @@ void print_version(void)
|
||||
int bias_flags(const char *option)
|
||||
{
|
||||
if (strcmp(option, "pull-down") == 0)
|
||||
return GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN;
|
||||
return GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
|
||||
if (strcmp(option, "pull-up") == 0)
|
||||
return GPIOD_CTXLESS_FLAG_BIAS_PULL_UP;
|
||||
return GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
|
||||
if (strcmp(option, "disable") == 0)
|
||||
return GPIOD_CTXLESS_FLAG_BIAS_DISABLE;
|
||||
return GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
|
||||
if (strcmp(option, "as-is") != 0)
|
||||
die("invalid bias: %s", option);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user