From: Mateusz Majewski Date: Thu, 22 Jul 2021 06:53:42 +0000 (+0200) Subject: gpio: encapsulate legacy kernel API usage X-Git-Tag: accepted/tizen/unified/20210816.122834~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F80%2F261580%2F7;p=platform%2Fcore%2Fapi%2Fperipheral-io.git gpio: encapsulate legacy kernel API usage Not useful by itself, but allows us to move to the new kernel API step by step. Change-Id: I23f224b091dbc600172fb38da4d55ab2bbc17636 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a4ec4d..ec2ba1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ IF("${GCOV}" STREQUAL "1") ENDIF() SET(SOURCES src/peripheral_gpio.c + src/peripheral_gpio_legacy_api.c src/peripheral_i2c.c src/peripheral_pwm.c src/peripheral_adc.c diff --git a/src/common.h b/src/common.h index 17bacaa..544bb67 100644 --- a/src/common.h +++ b/src/common.h @@ -80,6 +80,11 @@ static inline int close_fd(int fd) { return -1; } +static inline void cleanup_fd(int *fd) { + close_fd(*fd); + *fd = -1; +} + #define PERIPHERAL_FEATURE_UNKNOWN -1 #define PERIPHERAL_FEATURE_FALSE 0 #define PERIPHERAL_FEATURE_TRUE 1 diff --git a/src/peripheral_gpio.c b/src/peripheral_gpio.c index b36f384..c451594 100644 --- a/src/peripheral_gpio.c +++ b/src/peripheral_gpio.c @@ -23,24 +23,12 @@ #include #include "peripheral_io.h" +#include "peripheral_gpio_legacy_api.h" #include "common.h" #include "log.h" FEATURE("http://tizen.org/feature/peripheral_io.gpio") -/* Path format for device file */ -#define DEV_PATH_BASE(pin, file) ("/sys/class/gpio/gpio" pin "/" file) -/* direction is the longest file name of all accesses in the device directory. - The other are: edge and value. - */ -#define DEV_PATH_FMT_MAX_SIZE sizeof(DEV_PATH_BASE(MAX_d_FMT, "direction")) -#define DEV_PATH_FMT(file) DEV_PATH_BASE("%d", file) - -/* Format for gpio name */ -#define GPIO_NAME_BASE "gpio" -#define GPIO_NAME_FMT_MAX_SIZE sizeof(GPIO_NAME_BASE MAX_d_FMT) -#define GPIO_NAME_FMT (GPIO_NAME_BASE "%d") - #define GPIO_STRUCTURE_VERMAGIC 13712 #define GPIO_CALLBACK_STRUCTURE_VERMAGIC 14469 @@ -49,8 +37,6 @@ FEATURE("http://tizen.org/feature/peripheral_io.gpio") #define GPIO_INTERRUPTED_CALLBACK_CHECK_SET_INTERVAL_MILISECONDS 3000 -#define GPIO_BUFFER_MAX 64 - typedef struct _peripheral_gpio_interrupted_cb_info_s { // vermagic value is used to verify structure inside csapi // do not move it and value field to different place inside structure @@ -73,164 +59,17 @@ struct _peripheral_gpio_s { // otherwise update csapi accordingly int vermagic; interrupted_cb_info_s cb_info; - int pin; - int fd_direction; - int fd_edge; - int fd_value; + struct gpio_legacy_data legacy_data; peripheral_gpio_direction_e direction; peripheral_gpio_edge_e edge; }; -#define GPIO_BASE "gpio" - -typedef struct FilterData { - char gpio_name[GPIO_NAME_FMT_MAX_SIZE]; -} FilterData; - -static bool __filter_device(struct udev_device *device, void *data) -{ - FilterData *filter = data; - - if (strcmp(udev_device_get_sysname(device), filter->gpio_name) == 0) { - _D("udev for %s is initialized", filter->gpio_name); - return true; - } - return false; -} - -static int peripheral_gpio_export(int pin) -{ - RETVM_IF(pin < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid gpio pin"); - - int ret; - struct udev *udev = NULL; - struct udev_monitor *monitor = NULL; - - ret = peripheral_create_udev_monitor(&udev, &monitor, "gpio"); - if (ret != 0) { - _E("Failed to create udev monitor"); - ret = PERIPHERAL_ERROR_IO_ERROR; - goto out; - }; - - ret = peripheral_write_pin_to_file("/sys/class/gpio/export", pin); - if (ret != 0) { - /* If export fails with EBUSY, then it means - this pin has been already exported. - That's fine for us. - */ - if (ret != EBUSY) { - _E("gpio: export pin %d: failed with error %d", pin, ret); - goto out; - } - } - - FilterData filter; - snprintf(filter.gpio_name, sizeof filter.gpio_name, GPIO_NAME_FMT, pin); - - ret = peripheral_wait_for_udev(monitor, __filter_device, &filter); - if (ret < 0) { - _E("device nodes are not writable"); - ret = PERIPHERAL_ERROR_IO_ERROR; - goto out; - } - -out: - udev_monitor_unref(monitor); - udev_unref(udev); - - return ret; -} - -static int peripheral_gpio_lock_export(void) -{ - return peripheral_lock("/sys/class/gpio/export"); -} - -static inline int cleanup_handle(peripheral_gpio_h handle) { - if (handle == NULL) - return PERIPHERAL_ERROR_NONE; - - __attribute__ ((cleanup(peripheral_unlockp))) int lock = peripheral_gpio_lock_export(); - int pin = handle->pin; - - close_fd(handle->fd_edge); - close_fd(handle->fd_value); - close_fd(handle->fd_direction); /* this also closes pin flock() */ - free(handle); - - if (pin < 0) - return PERIPHERAL_ERROR_NONE; - - int ret = peripheral_write_pin_to_file("/sys/class/gpio/unexport", pin); - if (ret != 0) { - _E("gpio: unexport pin %d: failed with error %d", pin, ret); - return PERIPHERAL_ERROR_IO_ERROR; - } - - return PERIPHERAL_ERROR_NONE; -} - -static inline void cleanup_handlep(peripheral_gpio_h *handle) { - cleanup_handle(*handle); -} - -static int peripheral_gpio_set_initial_direction_into_handle(peripheral_gpio_h gpio) -{ - static predefined_type_s types[2] = { - {"in", 2}, - {"out", 3}, - }; - - char gpio_buf[GPIO_BUFFER_MAX] = {0, }; - - int ret = read(gpio->fd_direction, &gpio_buf, sizeof gpio_buf); - CHECK_ERROR(ret <= 0); - - for (size_t index = 0; index < ARRAY_SIZE(types); index++) { - if (strncmp(gpio_buf, types[index].type, types[index].len)) - continue; - - // PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_HIGH and PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW : out type - gpio->direction = (peripheral_gpio_direction_e)index; - - /* - * Also write to direction for the very first time after boot - * to ensure that the pin is fully initialized. - * Without this, writing to 'edge' is not possible. - */ - ret = write(gpio->fd_direction, types[index].type, types[index].len); - CHECK_ERROR(ret != types[index].len); - - return PERIPHERAL_ERROR_NONE; - } - - return PERIPHERAL_ERROR_IO_ERROR; -} - -static int peripheral_gpio_set_initial_edge_into_handle(peripheral_gpio_h gpio) -{ - static const predefined_type_s types[4] = { - {"none", 4}, - {"rising", 6}, - {"falling", 7}, - {"both", 4} - }; - - char gpio_buf[GPIO_BUFFER_MAX] = {0, }; - - int ret = read(gpio->fd_edge, &gpio_buf, sizeof gpio_buf); - CHECK_ERROR(ret <= 0); - - for (size_t index = 0; index < ARRAY_SIZE(types); index++) { - if (strncmp(gpio_buf, types[index].type, types[index].len)) - continue; - - gpio->edge = (peripheral_gpio_edge_e)index; - return PERIPHERAL_ERROR_NONE; - } - - return PERIPHERAL_ERROR_IO_ERROR; +static inline void free_gpio(peripheral_gpio_h *handle) { + /* NB: This is, on purpose, *not* peripheral_gpio_close. + * This is because this function is only used as a cleanup function in peripheral_gpio_open, + * where most of the structure is not initialized yet and we just want to free the memory. */ + free(*handle); + *handle = NULL; } /** @@ -245,7 +84,7 @@ int peripheral_gpio_open(int gpio_pin, peripheral_gpio_h *gpio) RETVM_IF(gpio_pin < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid gpio pin number"); /* Initialize */ - __attribute__ ((cleanup(cleanup_handlep))) peripheral_gpio_h handle = (peripheral_gpio_h)calloc(1, sizeof *handle); + __attribute__ ((cleanup(free_gpio))) peripheral_gpio_h handle = (peripheral_gpio_h)calloc(1, sizeof *handle); if (handle == NULL) { _E("Failed to allocate peripheral_gpio_h"); return PERIPHERAL_ERROR_OUT_OF_MEMORY; @@ -254,53 +93,12 @@ int peripheral_gpio_open(int gpio_pin, peripheral_gpio_h *gpio) // set gpio_s_vermagic and callback vermagic so csapi can verify structure handle->vermagic = GPIO_STRUCTURE_VERMAGIC; handle->cb_info.vermagic = GPIO_CALLBACK_STRUCTURE_VERMAGIC; - handle->fd_direction = -1; - handle->fd_edge = -1; - handle->fd_value = -1; - handle->pin = -1; - - __attribute__ ((cleanup(peripheral_unlockp))) int lock = peripheral_gpio_lock_export(); - RETVM_IF(lock == -1, PERIPHERAL_ERROR_IO_ERROR, "Failed to lock 'export'"); - ret = peripheral_gpio_export(gpio_pin); - RETVM_IF(ret != 0, PERIPHERAL_ERROR_IO_ERROR, "Failed to export the gpio pin, ret : %d", ret); - - handle->pin = gpio_pin; - - /* space for /sys/class/gpio/gpio%d/direction, - which is larger than /sys/class/gpio/gpio%d/edge and /sys/class/gpio/gpio%d/value - */ - char path[DEV_PATH_FMT_MAX_SIZE] = {0, }; - snprintf(path, sizeof path, DEV_PATH_FMT("direction"), handle->pin); - handle->fd_direction = open(path, O_RDWR | O_CLOEXEC); - CHECK_ERROR(handle->fd_direction < 0); + handle->cb_info.thread = NULL; - TRY_FLOCK(ret, handle->fd_direction, LOCK_EX | LOCK_NB, "gpio pin %d", gpio_pin); + ret = gpio_legacy_open(&handle->legacy_data, gpio_pin, &handle->direction, &handle->edge); CHECK_ERROR(ret != PERIPHERAL_ERROR_NONE); - snprintf(path, sizeof path, DEV_PATH_FMT("edge"), handle->pin); - handle->fd_edge = open(path, O_RDWR | O_CLOEXEC); - CHECK_ERROR(handle->fd_edge < 0); - - snprintf(path, sizeof path, DEV_PATH_FMT("value"), handle->pin); - handle->fd_value = open(path, O_RDWR | O_CLOEXEC); - CHECK_ERROR(handle->fd_value < 0); - - lock = peripheral_unlock(lock); - - ret = peripheral_gpio_set_initial_direction_into_handle(handle); - if (ret != PERIPHERAL_ERROR_NONE) { - _E("Failed to peripheral_gpio_set_initial_direction_into_handle()"); - return ret; - } - - ret = peripheral_gpio_set_initial_edge_into_handle(handle); - if (ret != PERIPHERAL_ERROR_NONE) { - _E("Failed to peripheral_gpio_set_initial_edge_into_handle()"); - return ret; - } - - handle->cb_info.thread = NULL; *gpio = handle; handle = NULL; @@ -318,9 +116,11 @@ int peripheral_gpio_close(peripheral_gpio_h gpio) peripheral_gpio_unset_interrupted_cb(gpio); - cleanup_handlep(&gpio); + int ret = gpio_legacy_cleanup(&gpio->legacy_data); - return PERIPHERAL_ERROR_NONE; + free(gpio); + + return ret; } /** @@ -347,17 +147,11 @@ int peripheral_gpio_set_direction(peripheral_gpio_h gpio, peripheral_gpio_direct RETVM_IF(gpio->cb_info.status != GPIO_INTERRUPTED_CALLBACK_UNSET, PERIPHERAL_ERROR_IO_ERROR, "Can't change direction to OUT while 'interrupted_cb' is set"); - static const predefined_type_s types[3] = { - {"in", 2}, - {"high", 4}, - {"low", 3} - }; - - int ret = write(gpio->fd_direction, types[direction].type, types[direction].len); - CHECK_ERROR(ret != types[direction].len); + int ret = gpio_legacy_set_direction(&gpio->legacy_data, direction); + if (ret != PERIPHERAL_ERROR_NONE) + return ret; gpio->direction = direction; - return PERIPHERAL_ERROR_NONE; } @@ -382,18 +176,11 @@ int peripheral_gpio_set_edge_mode(peripheral_gpio_h gpio, peripheral_gpio_edge_e RETV_IF(gpio->edge == edge, PERIPHERAL_ERROR_NONE); RETV_IF(gpio->direction != PERIPHERAL_GPIO_DIRECTION_IN, PERIPHERAL_ERROR_IO_ERROR); - static const predefined_type_s types[4] = { - {"none", 4}, - {"rising", 6}, - {"falling", 7}, - {"both", 4} - }; - - int ret = write(gpio->fd_edge, types[edge].type, types[edge].len); - CHECK_ERROR(ret != types[edge].len); + int ret = gpio_legacy_set_edge_mode(&gpio->legacy_data, edge); + if (ret != PERIPHERAL_ERROR_NONE) + return ret; gpio->edge = edge; - return PERIPHERAL_ERROR_NONE; } @@ -412,7 +199,7 @@ static gpointer __peripheral_gpio_poll(void *data) struct pollfd poll_fd; - poll_fd.fd = gpio->fd_value; + poll_fd.fd = gpio_legacy_get_poll_fd(&gpio->legacy_data); poll_fd.events = POLLPRI; uint32_t value; @@ -517,23 +304,8 @@ int peripheral_gpio_read(peripheral_gpio_h gpio, uint32_t *value) * in ---------> read (O) * out --------> read (O) */ - int ret; - int length = 1; - char gpio_buf[GPIO_BUFFER_MAX] = {0, }; - - ret = pread(gpio->fd_value, &gpio_buf, length, 0); - CHECK_ERROR(ret != length); - - if (gpio_buf[0] == '0') { - *value = 0; - } else if (gpio_buf[0] == '1') { - *value = 1; - } else { - _E("Error: gpio value is error \n"); - return PERIPHERAL_ERROR_IO_ERROR; - } - return PERIPHERAL_ERROR_NONE; + return gpio_legacy_read(&gpio->legacy_data, value); } /** @@ -552,13 +324,5 @@ int peripheral_gpio_write(peripheral_gpio_h gpio, uint32_t value) */ RETV_IF(gpio->direction == PERIPHERAL_GPIO_DIRECTION_IN, PERIPHERAL_ERROR_IO_ERROR); - static const predefined_type_s types[2] = { - {"0", 1}, - {"1", 1} - }; - - int ret = write(gpio->fd_value, types[value].type, types[value].len); - CHECK_ERROR(ret != types[value].len); - - return PERIPHERAL_ERROR_NONE; + return gpio_legacy_write(&gpio->legacy_data, value); } diff --git a/src/peripheral_gpio_legacy_api.c b/src/peripheral_gpio_legacy_api.c new file mode 100644 index 0000000..278909a --- /dev/null +++ b/src/peripheral_gpio_legacy_api.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2016-2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "peripheral_io.h" +#include "peripheral_gpio_legacy_api.h" +#include "common.h" +#include "log.h" + +/* Path format for device file */ +#define DEV_PATH_BASE(pin, file) ("/sys/class/gpio/gpio" pin "/" file) +/* direction is the longest file name of all accesses in the device directory. + The other are: edge and value. + */ +#define DEV_PATH_FMT_MAX_SIZE sizeof(DEV_PATH_BASE(MAX_d_FMT, "direction")) +#define DEV_PATH_FMT(file) DEV_PATH_BASE("%d", file) + +/* Format for gpio name */ +#define GPIO_NAME_BASE "gpio" +#define GPIO_NAME_FMT_MAX_SIZE sizeof(GPIO_NAME_BASE MAX_d_FMT) +#define GPIO_NAME_FMT (GPIO_NAME_BASE "%d") + +#define GPIO_BUFFER_MAX 64 + +#define GPIO_BASE "gpio" + +typedef struct FilterData { + char gpio_name[GPIO_NAME_FMT_MAX_SIZE]; +} FilterData; + +static bool __filter_device(struct udev_device *device, void *data) +{ + assert(device); + assert(data); + + FilterData *filter = data; + + if (strcmp(udev_device_get_sysname(device), filter->gpio_name) == 0) { + _D("udev for %s is initialized", filter->gpio_name); + return true; + } + return false; +} + +static int gpio_legacy_export(int pin) +{ + RETVM_IF(pin < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid gpio pin"); + + int ret; + struct udev *udev = NULL; + struct udev_monitor *monitor = NULL; + + ret = peripheral_create_udev_monitor(&udev, &monitor, "gpio"); + if (ret != 0) { + _E("Failed to create udev monitor"); + ret = PERIPHERAL_ERROR_IO_ERROR; + goto out; + }; + + ret = peripheral_write_pin_to_file("/sys/class/gpio/export", pin); + if (ret != 0) { + /* If export fails with EBUSY, then it means + this pin has been already exported. + That's fine for us. + */ + if (ret != EBUSY) { + _E("gpio: export pin %d: failed with error %d", pin, ret); + goto out; + } + } + + FilterData filter; + snprintf(filter.gpio_name, sizeof filter.gpio_name, GPIO_NAME_FMT, pin); + + ret = peripheral_wait_for_udev(monitor, __filter_device, &filter); + if (ret < 0) { + _E("device nodes are not writable"); + ret = PERIPHERAL_ERROR_IO_ERROR; + goto out; + } + +out: + udev_monitor_unref(monitor); + udev_unref(udev); + + return ret; +} + +static int gpio_legacy_lock_export(void) +{ + return peripheral_lock("/sys/class/gpio/export"); +} + +int gpio_legacy_cleanup(struct gpio_legacy_data *ldata) +{ + assert(ldata); + + __attribute__ ((cleanup(peripheral_unlockp))) int lock = gpio_legacy_lock_export(); + int pin = ldata->pin; + + close_fd(ldata->fd_edge); + close_fd(ldata->fd_value); + close_fd(ldata->fd_direction); /* this also closes pin flock() */ + + if (pin < 0) + return PERIPHERAL_ERROR_NONE; + + int ret = peripheral_write_pin_to_file("/sys/class/gpio/unexport", pin); + if (ret != 0) { + _E("gpio: unexport pin %d: failed with error %d", pin, ret); + return PERIPHERAL_ERROR_IO_ERROR; + } + + return PERIPHERAL_ERROR_NONE; +} + +static int gpio_legacy_set_initial_direction_into_handle(int fd_direction, peripheral_gpio_direction_e *direction_out) +{ + assert(direction_out); + + static predefined_type_s types[2] = { + {"in", 2}, + {"out", 3}, + }; + + char gpio_buf[GPIO_BUFFER_MAX] = {0, }; + + int ret = read(fd_direction, &gpio_buf, sizeof gpio_buf); + CHECK_ERROR(ret <= 0); + + for (size_t index = 0; index < ARRAY_SIZE(types); index++) { + if (strncmp(gpio_buf, types[index].type, types[index].len)) + continue; + + // PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_HIGH and PERIPHERAL_GPIO_DIRECTION_OUT_INITIALLY_LOW : out type + *direction_out = (peripheral_gpio_direction_e)index; + + /* + * Also write to direction for the very first time after boot + * to ensure that the pin is fully initialized. + * Without this, writing to 'edge' is not possible. + */ + ret = write(fd_direction, types[index].type, types[index].len); + CHECK_ERROR(ret != types[index].len); + + return PERIPHERAL_ERROR_NONE; + } + + return PERIPHERAL_ERROR_IO_ERROR; +} + +static int gpio_legacy_set_initial_edge_into_handle(int fd_edge, peripheral_gpio_edge_e *edge_out) +{ + assert(edge_out); + + static const predefined_type_s types[4] = { + {"none", 4}, + {"rising", 6}, + {"falling", 7}, + {"both", 4} + }; + + char gpio_buf[GPIO_BUFFER_MAX] = {0, }; + + int ret = read(fd_edge, &gpio_buf, sizeof gpio_buf); + CHECK_ERROR(ret <= 0); + + for (size_t index = 0; index < ARRAY_SIZE(types); index++) { + if (strncmp(gpio_buf, types[index].type, types[index].len)) + continue; + + *edge_out = (peripheral_gpio_edge_e)index; + return PERIPHERAL_ERROR_NONE; + } + + return PERIPHERAL_ERROR_IO_ERROR; +} + +int gpio_legacy_open(struct gpio_legacy_data *ldata, int gpio_pin, peripheral_gpio_direction_e *direction_out, peripheral_gpio_edge_e *edge_out) +{ + assert(ldata); + assert(direction_out); + assert(edge_out); + + int ret = PERIPHERAL_ERROR_NONE; + + __attribute__((cleanup(cleanup_fd))) int fd_direction = -1; + __attribute__((cleanup(cleanup_fd))) int fd_edge = -1; + __attribute__((cleanup(cleanup_fd))) int fd_value = -1; + + __attribute__ ((cleanup(peripheral_unlockp))) int lock = gpio_legacy_lock_export(); + RETVM_IF(lock == -1, PERIPHERAL_ERROR_IO_ERROR, "Failed to lock 'export'"); + + ret = gpio_legacy_export(gpio_pin); + RETVM_IF(ret != 0, PERIPHERAL_ERROR_IO_ERROR, "Failed to export the gpio pin, ret : %d", ret); + + /* space for /sys/class/gpio/gpio%d/direction, + which is larger than /sys/class/gpio/gpio%d/edge and /sys/class/gpio/gpio%d/value + */ + char path[DEV_PATH_FMT_MAX_SIZE] = {0, }; + snprintf(path, sizeof path, DEV_PATH_FMT("direction"), gpio_pin); + fd_direction = open(path, O_RDWR | O_CLOEXEC); + CHECK_ERROR(fd_direction < 0); + + TRY_FLOCK(ret, fd_direction, LOCK_EX | LOCK_NB, "gpio pin %d", gpio_pin); + CHECK_ERROR(ret != PERIPHERAL_ERROR_NONE); + + snprintf(path, sizeof path, DEV_PATH_FMT("edge"), gpio_pin); + fd_edge = open(path, O_RDWR | O_CLOEXEC); + CHECK_ERROR(fd_edge < 0); + + snprintf(path, sizeof path, DEV_PATH_FMT("value"), gpio_pin); + fd_value = open(path, O_RDWR | O_CLOEXEC); + CHECK_ERROR(fd_value < 0); + + lock = peripheral_unlock(lock); + + ret = gpio_legacy_set_initial_direction_into_handle(fd_direction, direction_out); + if (ret != PERIPHERAL_ERROR_NONE) { + _E("Failed to gpio_legacy_set_initial_direction_into_data()"); + return ret; + } + + ret = gpio_legacy_set_initial_edge_into_handle(fd_edge, edge_out); + if (ret != PERIPHERAL_ERROR_NONE) { + _E("Failed to gpio_legacy_set_initial_edge_into_data()"); + return ret; + } + + ldata->fd_direction = fd_direction; + ldata->fd_edge = fd_edge; + ldata->fd_value = fd_value; + ldata->pin = gpio_pin; + + fd_direction = -1; + fd_edge = -1; + fd_value = -1; + + return PERIPHERAL_ERROR_NONE; +} + +int gpio_legacy_set_direction(struct gpio_legacy_data *ldata, peripheral_gpio_direction_e direction) +{ + assert(ldata); + + static const predefined_type_s types[3] = { + {"in", 2}, + {"high", 4}, + {"low", 3} + }; + + int ret = write(ldata->fd_direction, types[direction].type, types[direction].len); + CHECK_ERROR(ret != types[direction].len); + + return PERIPHERAL_ERROR_NONE; +} + +int gpio_legacy_set_edge_mode(struct gpio_legacy_data *ldata, peripheral_gpio_edge_e edge) +{ + assert(ldata); + + static const predefined_type_s types[4] = { + {"none", 4}, + {"rising", 6}, + {"falling", 7}, + {"both", 4} + }; + + int ret = write(ldata->fd_edge, types[edge].type, types[edge].len); + CHECK_ERROR(ret != types[edge].len); + + return PERIPHERAL_ERROR_NONE; +} + +int gpio_legacy_read(struct gpio_legacy_data *ldata, uint32_t *value) +{ + assert(ldata); + assert(value); + + int ret; + int length = 1; + char gpio_buf[GPIO_BUFFER_MAX] = {0, }; + + ret = pread(ldata->fd_value, &gpio_buf, length, 0); + CHECK_ERROR(ret != length); + + if (gpio_buf[0] == '0') { + *value = 0; + } else if (gpio_buf[0] == '1') { + *value = 1; + } else { + _E("Error: gpio value is error \n"); + return PERIPHERAL_ERROR_IO_ERROR; + } + + return PERIPHERAL_ERROR_NONE; +} + +int gpio_legacy_write(struct gpio_legacy_data *ldata, uint32_t value) +{ + assert(ldata); + + static const predefined_type_s types[2] = { + {"0", 1}, + {"1", 1} + }; + + int ret = write(ldata->fd_value, types[value].type, types[value].len); + CHECK_ERROR(ret != types[value].len); + + return PERIPHERAL_ERROR_NONE; +} + +int gpio_legacy_get_poll_fd(struct gpio_legacy_data *ldata) +{ + assert(ldata); + + return ldata->fd_value; +} diff --git a/src/peripheral_gpio_legacy_api.h b/src/peripheral_gpio_legacy_api.h new file mode 100644 index 0000000..b807eb7 --- /dev/null +++ b/src/peripheral_gpio_legacy_api.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016-2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "peripheral_io.h" + +/* NB: This struct should really be an opaque one, i.e. should be defined + * in the corresponding .c file instead and should be only used elsewhere + * via the functions defined below. Alas, in _peripheral_gpio_s, we want + * to have an instance of this struct as a field. If this struct were opaque, + * we could only put an ugly pointer there. */ +struct gpio_legacy_data { + int pin; + int fd_direction; + int fd_edge; + int fd_value; +}; + +int gpio_legacy_open(struct gpio_legacy_data *ldata, int gpio_pin, peripheral_gpio_direction_e *direction_out, peripheral_gpio_edge_e *edge_out); +int gpio_legacy_read(struct gpio_legacy_data *ldata, uint32_t *value); +int gpio_legacy_write(struct gpio_legacy_data *ldata, uint32_t value); +int gpio_legacy_set_direction(struct gpio_legacy_data *ldata, peripheral_gpio_direction_e direction); +int gpio_legacy_set_edge_mode(struct gpio_legacy_data *ldata, peripheral_gpio_edge_e edge); +int gpio_legacy_cleanup(struct gpio_legacy_data *ldata); +int gpio_legacy_get_poll_fd(struct gpio_legacy_data *ldata);