// SPDX-License-Identifier: LGPL-2.1-or-later /* * This file is part of libgpiod. * * Copyright (C) 2019 Bartosz Golaszewski */ #include #include #include "gpiod-test.h" #define GPIOD_TEST_GROUP "line" GPIOD_TEST_CASE(request_output, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line0; struct gpiod_line *line1; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 2); line1 = gpiod_chip_get_line(chip, 5); g_assert_nonnull(line0); g_assert_nonnull(line1); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line0, GPIOD_TEST_CONSUMER, 0); g_assert_cmpint(ret, ==, 0); ret = gpiod_line_request_output(line1, GPIOD_TEST_CONSUMER, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1); } GPIOD_TEST_CASE(request_already_requested, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EBUSY); } GPIOD_TEST_CASE(consumer, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); g_assert_nonnull(line); gpiod_test_return_if_failed(); g_assert_null(gpiod_line_consumer(line)); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, GPIOD_TEST_CONSUMER); } GPIOD_TEST_CASE(consumer_long_string, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); g_assert_nonnull(line); gpiod_test_return_if_failed(); g_assert_null(gpiod_line_consumer(line)); ret = gpiod_line_request_input(line, "consumer string over 32 characters long"); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, "consumer string over 32 charact"); g_assert_cmpuint(strlen(gpiod_line_consumer(line)), ==, 31); } GPIOD_TEST_CASE(request_bulk_output, 0, { 8, 8 }) { g_autoptr(gpiod_chip_struct) chipA = NULL; g_autoptr(gpiod_chip_struct) chipB = NULL; struct gpiod_line_bulk bulkB = GPIOD_LINE_BULK_INITIALIZER, bulkA; struct gpiod_line *lineA0, *lineA1, *lineA2, *lineA3, *lineB0, *lineB1, *lineB2, *lineB3; gint valA[4], valB[4], ret; chipA = gpiod_chip_open(gpiod_test_chip_path(0)); chipB = gpiod_chip_open(gpiod_test_chip_path(1)); g_assert_nonnull(chipA); g_assert_nonnull(chipB); gpiod_test_return_if_failed(); lineA0 = gpiod_chip_get_line(chipA, 0); lineA1 = gpiod_chip_get_line(chipA, 1); lineA2 = gpiod_chip_get_line(chipA, 2); lineA3 = gpiod_chip_get_line(chipA, 3); lineB0 = gpiod_chip_get_line(chipB, 0); lineB1 = gpiod_chip_get_line(chipB, 1); lineB2 = gpiod_chip_get_line(chipB, 2); lineB3 = gpiod_chip_get_line(chipB, 3); g_assert_nonnull(lineA0); g_assert_nonnull(lineA1); g_assert_nonnull(lineA2); g_assert_nonnull(lineA3); g_assert_nonnull(lineB0); g_assert_nonnull(lineB1); g_assert_nonnull(lineB2); g_assert_nonnull(lineB3); gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulkA); gpiod_line_bulk_add(&bulkA, lineA0); gpiod_line_bulk_add(&bulkA, lineA1); gpiod_line_bulk_add(&bulkA, lineA2); gpiod_line_bulk_add(&bulkA, lineA3); gpiod_line_bulk_add(&bulkB, lineB0); gpiod_line_bulk_add(&bulkB, lineB1); gpiod_line_bulk_add(&bulkB, lineB2); gpiod_line_bulk_add(&bulkB, lineB3); valA[0] = 1; valA[1] = 0; valA[2] = 0; valA[3] = 1; ret = gpiod_line_request_bulk_output(&bulkA, GPIOD_TEST_CONSUMER, valA); g_assert_cmpint(ret, ==, 0); valB[0] = 0; valB[1] = 1; valB[2] = 0; valB[3] = 1; ret = gpiod_line_request_bulk_output(&bulkB, GPIOD_TEST_CONSUMER, valB); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(1, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(1, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(1, 2), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(1, 3), ==, 1); } GPIOD_TEST_CASE(request_bulk_different_chips, 0, { 8, 8 }) { g_autoptr(gpiod_chip_struct) chipA = NULL; g_autoptr(gpiod_chip_struct) chipB = NULL; struct gpiod_line *lineA0, *lineA1, *lineB0, *lineB1; struct gpiod_line_request_config req; struct gpiod_line_bulk bulk; gint ret; chipA = gpiod_chip_open(gpiod_test_chip_path(0)); chipB = gpiod_chip_open(gpiod_test_chip_path(1)); g_assert_nonnull(chipA); g_assert_nonnull(chipB); gpiod_test_return_if_failed(); lineA0 = gpiod_chip_get_line(chipA, 0); lineA1 = gpiod_chip_get_line(chipA, 1); lineB0 = gpiod_chip_get_line(chipB, 0); lineB1 = gpiod_chip_get_line(chipB, 1); g_assert_nonnull(lineA0); g_assert_nonnull(lineA1); g_assert_nonnull(lineB0); g_assert_nonnull(lineB1); gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulk); gpiod_line_bulk_add(&bulk, lineA0); gpiod_line_bulk_add(&bulk, lineA1); gpiod_line_bulk_add(&bulk, lineB0); gpiod_line_bulk_add(&bulk, lineB1); req.consumer = GPIOD_TEST_CONSUMER; req.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; req.flags = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; ret = gpiod_line_request_bulk(&bulk, &req, NULL); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); } GPIOD_TEST_CASE(request_null_default_vals_for_output, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line0, *line1, *line2; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 0); line1 = gpiod_chip_get_line(chip, 1); line2 = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line0); g_assert_nonnull(line1); g_assert_nonnull(line2); gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); gpiod_line_bulk_add(&bulk, line2); ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(set_value, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_value(line, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_value(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(set_value_bulk, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line0, *line1, *line2; int values[3]; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 0); line1 = gpiod_chip_get_line(chip, 1); line2 = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line0); g_assert_nonnull(line1); g_assert_nonnull(line2); gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); gpiod_line_bulk_add(&bulk, line2); values[0] = 0; values[1] = 1; values[2] = 2; ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, values); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); values[0] = 2; values[1] = 1; values[2] = 0; ret = gpiod_line_set_value_bulk(&bulk, values); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_value_bulk(&bulk, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(set_config_bulk_null_values, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line0, *line1, *line2; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 0); line1 = gpiod_chip_get_line(chip, 1); line2 = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line0); g_assert_nonnull(line1); g_assert_nonnull(line2); gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); gpiod_line_bulk_add(&bulk, line2); ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line0), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_line_active_state(line1), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_line_active_state(line2), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_config_bulk(&bulk, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line0), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_line_active_state(line1), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_line_active_state(line2), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_config_bulk(&bulk, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line0), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_line_active_state(line1), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_line_active_state(line2), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(set_flags_active_state, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); } GPIOD_TEST_CASE(set_flags_bias, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_DISABLE); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(set_flags_drive, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false); g_assert_cmpint(gpiod_line_is_open_source(line), ==, false); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_is_open_drain(line), ==, true); g_assert_cmpint(gpiod_line_is_open_source(line), ==, false); ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false); g_assert_cmpint(gpiod_line_is_open_source(line), ==, true); } GPIOD_TEST_CASE(set_direction, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_direction_input(line); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_INPUT); ret = gpiod_line_set_direction_output(line, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); } GPIOD_TEST_CASE(set_direction_bulk, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line0, *line1, *line2; int values[3]; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 0); line1 = gpiod_chip_get_line(chip, 1); line2 = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line0); g_assert_nonnull(line1); g_assert_nonnull(line2); gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); gpiod_line_bulk_add(&bulk, line2); values[0] = 0; values[1] = 1; values[2] = 2; ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, values); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line0), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line1), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line2), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_direction_input_bulk(&bulk); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line0), ==, GPIOD_LINE_DIRECTION_INPUT); g_assert_cmpint(gpiod_line_direction(line1), ==, GPIOD_LINE_DIRECTION_INPUT); g_assert_cmpint(gpiod_line_direction(line2), ==, GPIOD_LINE_DIRECTION_INPUT); values[0] = 2; values[1] = 1; values[2] = 0; ret = gpiod_line_set_direction_output_bulk(&bulk, values); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line0), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line1), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line2), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_direction_output_bulk(&bulk, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line0), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line1), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_line_direction(line2), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(output_value_caching, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; struct gpiod_line_bulk bulk; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); /* check cached by request... */ ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); /* ...by checking cached value applied by set_flags */ ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); /* check cached by set_value */ ret = gpiod_line_set_value(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_value(line, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); /* check cached by set_config */ ret = gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); /* check cached by set_value_bulk default */ ret = gpiod_line_set_value(line, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); gpiod_line_bulk_init(&bulk); gpiod_line_bulk_add(&bulk, line); ret = gpiod_line_set_value_bulk(&bulk, NULL); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); ret = gpiod_line_set_flags(line, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } GPIOD_TEST_CASE(get_value_different_chips, 0, { 8, 8 }) { g_autoptr(gpiod_chip_struct) chipA = NULL; g_autoptr(gpiod_chip_struct) chipB = NULL; struct gpiod_line *lineA0, *lineA1, *lineB0, *lineB1; struct gpiod_line_bulk bulkA, bulkB, bulk; gint ret, vals[4]; chipA = gpiod_chip_open(gpiod_test_chip_path(0)); chipB = gpiod_chip_open(gpiod_test_chip_path(1)); g_assert_nonnull(chipA); g_assert_nonnull(chipB); gpiod_test_return_if_failed(); lineA0 = gpiod_chip_get_line(chipA, 3); lineA1 = gpiod_chip_get_line(chipA, 4); lineB0 = gpiod_chip_get_line(chipB, 5); lineB1 = gpiod_chip_get_line(chipB, 6); g_assert_nonnull(lineA0); g_assert_nonnull(lineA1); g_assert_nonnull(lineB0); g_assert_nonnull(lineB1); gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulkA); gpiod_line_bulk_init(&bulkB); gpiod_line_bulk_init(&bulk); gpiod_line_bulk_add(&bulkA, lineA0); gpiod_line_bulk_add(&bulkA, lineA1); gpiod_line_bulk_add(&bulkB, lineB0); gpiod_line_bulk_add(&bulkB, lineB1); gpiod_line_bulk_add(&bulk, lineA0); gpiod_line_bulk_add(&bulk, lineA1); gpiod_line_bulk_add(&bulk, lineB0); gpiod_line_bulk_add(&bulk, lineB1); ret = gpiod_line_request_bulk_input(&bulkA, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); ret = gpiod_line_request_bulk_input(&bulkB, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); ret = gpiod_line_get_value_bulk(&bulk, vals); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); } GPIOD_TEST_CASE(get_line_helper, 0, { 16, 16, 32, 16 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; line = gpiod_line_get(gpiod_test_chip_name(2), 18); g_assert_nonnull(line); gpiod_test_return_if_failed(); chip = gpiod_line_get_chip(line); g_assert_cmpint(gpiod_line_offset(line), ==, 18); } GPIOD_TEST_CASE(get_line_helper_invalid_offset, 0, { 16, 16, 32, 16 }) { struct gpiod_line *line; line = gpiod_line_get(gpiod_test_chip_name(3), 18); g_assert_null(line); g_assert_cmpint(errno, ==, EINVAL); } GPIOD_TEST_CASE(find_good, GPIOD_TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; line = gpiod_line_find("gpio-mockup-C-12"); g_assert_nonnull(line); gpiod_test_return_if_failed(); chip = gpiod_line_get_chip(line); g_assert_cmpint(gpiod_line_offset(line), ==, 12); } GPIOD_TEST_CASE(find_not_found, GPIOD_TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }) { struct gpiod_line *line; line = gpiod_line_find("nonexistent"); g_assert_null(line); g_assert_cmpint(errno, ==, ENOENT); } GPIOD_TEST_CASE(find_unnamed_lines, 0, { 16, 16, 32, 16 }) { struct gpiod_line *line; line = gpiod_line_find("gpio-mockup-C-12"); g_assert_null(line); g_assert_cmpint(errno, ==, ENOENT); } GPIOD_TEST_CASE(direction, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 5); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1); gpiod_line_release(line); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_INPUT); } GPIOD_TEST_CASE(active_state, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 5); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_HIGH); gpiod_line_release(line); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_INPUT); gpiod_line_release(line); ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1); gpiod_line_release(line); ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER, 0, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 0); } GPIOD_TEST_CASE(misc_flags, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); g_assert_false(gpiod_line_is_used(line)); g_assert_false(gpiod_line_is_open_drain(line)); g_assert_false(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; config.consumer = GPIOD_TEST_CONSUMER; config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_true(gpiod_line_is_open_drain(line)); g_assert_false(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); gpiod_line_release(line); config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_false(gpiod_line_is_open_drain(line)); g_assert_true(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); gpiod_line_release(line); } GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); /* * Verify that open drain/source flags work together * with active_low. */ config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; config.consumer = GPIOD_TEST_CONSUMER; config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN | GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_true(gpiod_line_is_open_drain(line)); g_assert_false(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_OUTPUT); gpiod_line_release(line); config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE | GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_false(gpiod_line_is_open_drain(line)); g_assert_true(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_LOW); gpiod_line_release(line); /* * Verify that pull-up/down flags work together * with active_low. */ config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN | GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_false(gpiod_line_is_open_drain(line)); g_assert_false(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_INPUT); ret = gpiod_line_get_value(line); g_assert_cmpint(ret, ==, 1); gpiod_line_release(line); config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP | GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_true(gpiod_line_is_used(line)); g_assert_false(gpiod_line_is_open_drain(line)); g_assert_false(gpiod_line_is_open_source(line)); g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP); g_assert_cmpint(gpiod_line_active_state(line), ==, GPIOD_LINE_ACTIVE_STATE_LOW); g_assert_cmpint(gpiod_line_direction(line), ==, GPIOD_LINE_DIRECTION_INPUT); ret = gpiod_line_get_value(line); g_assert_cmpint(ret, ==, 0); gpiod_line_release(line); } GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); } GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE | GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, 1); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); } GPIOD_TEST_CASE(multiple_bias_flags, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE | GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE | GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN | GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE | GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN | GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EINVAL); } /* Verify that the reference counting of the line fd handle works correctly. */ GPIOD_TEST_CASE(release_one_use_another, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk; struct gpiod_line *line0; struct gpiod_line *line1; gint ret, vals[2]; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line0 = gpiod_chip_get_line(chip, 2); line1 = gpiod_chip_get_line(chip, 3); g_assert_nonnull(line0); g_assert_nonnull(line1); gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulk); gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); vals[0] = vals[1] = 1; ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, vals); g_assert_cmpint(ret, ==, 0); gpiod_line_release(line0); ret = gpiod_line_get_value(line0); g_assert_cmpint(ret, ==, -1); g_assert_cmpint(errno, ==, EPERM); } GPIOD_TEST_CASE(null_consumer, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; config.consumer = NULL; config.flags = 0; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); gpiod_line_release(line); /* * Internally we use different structures for event requests, so we * need to test that explicitly too. */ config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); } GPIOD_TEST_CASE(empty_consumer, 0, { 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; gint ret; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); g_assert_nonnull(line); gpiod_test_return_if_failed(); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; config.consumer = ""; config.flags = 0; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); gpiod_line_release(line); /* * Internally we use different structures for event requests, so we * need to test that explicitly too. */ config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; ret = gpiod_line_request(line, &config, 0); g_assert_cmpint(ret, ==, 0); g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); } GPIOD_TEST_CASE(bulk_foreach, GPIOD_TEST_FLAG_NAMED_LINES, { 8 }) { static const gchar *const line_names[] = { "gpio-mockup-A-0", "gpio-mockup-A-1", "gpio-mockup-A-2", "gpio-mockup-A-3" }; g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line, **lineptr; gint i; chip = gpiod_chip_open(gpiod_test_chip_path(0)); g_assert_nonnull(chip); gpiod_test_return_if_failed(); for (i = 0; i < 4; i++) { line = gpiod_chip_get_line(chip, i); g_assert_nonnull(line); gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line); } i = 0; gpiod_line_bulk_foreach_line(&bulk, line, lineptr) g_assert_cmpstr(gpiod_line_name(line), ==, line_names[i++]); i = 0; gpiod_line_bulk_foreach_line(&bulk, line, lineptr) { g_assert_cmpstr(gpiod_line_name(line), ==, line_names[i++]); if (i == 2) break; } }