gpio: encapsulate legacy kernel API usage 80/261580/7
authorMateusz Majewski <m.majewski2@samsung.com>
Thu, 22 Jul 2021 06:53:42 +0000 (08:53 +0200)
committerMateusz Majewski <m.majewski2@samsung.com>
Wed, 11 Aug 2021 10:14:00 +0000 (12:14 +0200)
Not useful by itself, but allows us to move to the new kernel API step
by step.

Change-Id: I23f224b091dbc600172fb38da4d55ab2bbc17636

CMakeLists.txt
src/common.h
src/peripheral_gpio.c
src/peripheral_gpio_legacy_api.c [new file with mode: 0644]
src/peripheral_gpio_legacy_api.h [new file with mode: 0644]

index 7a4ec4d..ec2ba1a 100644 (file)
@@ -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
index 17bacaa..544bb67 100644 (file)
@@ -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
index b36f384..c451594 100644 (file)
 #include <unistd.h>
 
 #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 (file)
index 0000000..278909a
--- /dev/null
@@ -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 <assert.h>
+#include <glib.h>
+#include <libudev.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..b807eb7
--- /dev/null
@@ -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);