2 * Copyright (c) 2016-2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include <peripheral_io.h>
27 #include "peripheral_bus.h"
28 #include "peripheral_bus_gdbus_gpio.h"
29 #include "peripheral_common.h"
30 #include "peripheral_bus_util.h"
32 static bool peripheral_bus_gpio_is_available(int pin, peripheral_bus_s *pb_data)
34 pb_board_dev_s *gpio = NULL;
38 RETV_IF(pb_data == NULL, false);
39 RETV_IF(pb_data->board == NULL, false);
41 gpio = peripheral_bus_board_find_device(PB_BOARD_DEV_GPIO, pb_data->board, pin);
43 _E("Not supported GPIO pin : %d", pin);
47 link = pb_data->gpio_list;
49 handle = (pb_data_h)link->data;
50 if (handle->dev.gpio.pin == pin) {
51 _E("gpio %d is busy", pin);
54 link = g_list_next(link);
60 static int gpio_wait_for_udev(int gpiopin)
62 #define GPIO_NAME_LEN 8
64 struct udev_monitor *monitor;
65 struct udev_device *dev;
67 char gpio_name[GPIO_NAME_LEN];
72 _E("Cannot create udev");
76 monitor = udev_monitor_new_from_netlink(udev, "udev");
78 _E("Cannot create udev monitor");
83 ret = udev_monitor_filter_add_match_subsystem_devtype(monitor, "gpio", NULL);
85 _E("Failed to add monitor filter");
89 ret = udev_monitor_enable_receiving(monitor);
91 _E("Failed to enable udev receiving");
95 pfd.fd = udev_monitor_get_fd(monitor);
98 snprintf(gpio_name, GPIO_NAME_LEN, "gpio%d", gpiopin);
100 for (int cnt = 0; cnt < 10; cnt++) {
101 if (poll(&pfd, 1, 100) < 0) {
102 _E("Failed to watch udev monitor");
106 dev = udev_monitor_receive_device(monitor);
108 if (strcmp(udev_device_get_sysname(dev), gpio_name) == 0) {
109 _D("udev for %s is initialized", gpio_name);
118 udev_monitor_unref(monitor);
125 int peripheral_bus_gpio_open(gint pin, pb_data_h *handle, gpointer user_data)
127 peripheral_bus_s *pb_data = (peripheral_bus_s*)user_data;
128 pb_data_h gpio_handle;
132 if (!peripheral_bus_gpio_is_available(pin, pb_data)) {
133 _E("gpio %d is not available", pin);
134 return PERIPHERAL_ERROR_RESOURCE_BUSY;
137 if ((ret = gpio_open(pin)) < 0) {
138 _E("gpio_open error (%d)", ret);
142 if ((ret = gpio_get_edge_mode(pin, (gpio_edge_e*)&edge)) < 0) {
143 _E("gpio_get_edge_mode error (%d)", ret);
147 if ((ret = gpio_get_direction(pin, (gpio_direction_e*)&direction)) < 0) {
148 _E("gpio_get_direction error (%d)", ret);
152 gpio_handle = peripheral_bus_data_new(&pb_data->gpio_list);
154 _E("peripheral_bus_data_new error");
155 ret = PERIPHERAL_ERROR_UNKNOWN;
159 if (gpio_wait_for_udev(pin) < 0) {
160 _E("device nodes are not writable");
161 ret = PERIPHERAL_ERROR_UNKNOWN;
165 gpio_handle->type = PERIPHERAL_BUS_TYPE_GPIO;
166 gpio_handle->list = &pb_data->gpio_list;
167 gpio_handle->dev.gpio.pin = pin;
168 gpio_handle->dev.gpio.edge = edge;
169 gpio_handle->dev.gpio.direction = direction;
170 gpio_handle->dev.gpio.gpio_skeleton = pb_data->gpio_skeleton;
172 *handle = gpio_handle;
174 return PERIPHERAL_ERROR_NONE;
183 int peripheral_bus_gpio_set_direction(pb_data_h handle, gint direction)
185 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
188 gpio->direction = direction;
190 if ((ret = gpio_set_direction(gpio->pin, (gpio_direction_e)direction)) < 0) {
191 _E("gpio_set_direction error (%d)", ret);
195 return PERIPHERAL_ERROR_NONE;
198 int peripheral_bus_gpio_get_direction(pb_data_h handle, gint *direction)
200 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
204 if ((ret = gpio_get_direction(gpio->pin, (gpio_direction_e*)direction)) < 0) {
205 _E("gpio_get_direction error (%d)", ret);
209 if (*direction == GPIO_DIRECTION_OUT) {
210 if ((ret = gpio_read(gpio->pin, &value)) < 0)
212 /* Update direction state with the current value */
213 *direction = GPIO_DIRECTION_OUT + value;
216 gpio->direction = *direction;
218 return PERIPHERAL_ERROR_NONE;
221 int peripheral_bus_gpio_set_edge(pb_data_h handle, gint edge)
223 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
226 if ((ret = gpio_set_edge_mode(gpio->pin, (gpio_edge_e)edge)) < 0) {
227 _E("gpio_set_edge_mode error (%d)", ret);
233 return PERIPHERAL_ERROR_NONE;
236 int peripheral_bus_gpio_get_edge(pb_data_h handle, gint *edge)
238 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
241 if ((ret = gpio_get_edge_mode(gpio->pin, (gpio_edge_e*)edge)) < 0) {
242 _E("gpio_get_edge_mode error (%d)", ret);
248 return PERIPHERAL_ERROR_NONE;
251 int peripheral_bus_gpio_write(pb_data_h handle, gint value)
253 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
256 /* Return error if direction of the pin is input mode */
257 if (gpio->direction == GPIO_DIRECTION_IN) {
258 _E("The direction of the pin is INPUT mode, Cannot write");
259 return PERIPHERAL_ERROR_INVALID_OPERATION;
262 if ((ret = gpio_write(gpio->pin, value)) < 0) {
263 _E("gpio_write error (%d)", ret);
266 /* Update direction state along with the value */
267 gpio->direction = GPIO_DIRECTION_OUT + ((value > 0) ? 1 : 0);
269 return PERIPHERAL_ERROR_NONE;
272 int peripheral_bus_gpio_read(pb_data_h handle, gint *value)
274 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
277 if ((ret = gpio_read(gpio->pin, value)) < 0) {
278 _E("gpio_read error (%d)", ret);
282 return PERIPHERAL_ERROR_NONE;
285 static gboolean peripheral_bus_gpio_cb(GIOChannel *io, GIOCondition condition, gpointer data)
287 peripheral_bus_gpio_s *gpio_data = (peripheral_bus_gpio_s *)data;
289 unsigned long long timestamp;
294 if (!gpio_data->irq_en)
297 if (gpio_data->direction != PERIPHERAL_GPIO_DIRECTION_IN
298 || gpio_data->edge == PERIPHERAL_GPIO_EDGE_NONE)
301 gettimeofday(&time, NULL);
303 g_io_channel_seek_position(io, 0, G_SEEK_SET, NULL);
304 status = g_io_channel_read_line(io, &strval, NULL, NULL, NULL);
305 if (status != G_IO_STATUS_NORMAL) {
306 _E("Unable to read gpio value (%d)", status);
311 _D("gpio = %d, data = %s", gpio_data->pin, strval);
313 if (g_ascii_strcasecmp(strval, "1") == 0)
315 else if (g_ascii_strcasecmp(strval, "0") == 0)
319 _E("Error: gpio value is error");
324 if (gpio_data->edge == PERIPHERAL_GPIO_EDGE_RISING && value == 0)
326 else if (gpio_data->edge == PERIPHERAL_GPIO_EDGE_FALLING && value == 1)
329 timestamp = (unsigned long long)time.tv_sec * 1000000 + time.tv_usec;
330 peripheral_bus_emit_gpio_changed(gpio_data->gpio_skeleton, gpio_data->pin, value, timestamp);
335 int peripheral_bus_gpio_register_irq(pb_data_h handle)
337 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
341 if ((gpio->value_fd = gpio_open_isr(gpio->pin)) < 0)
344 gpio->io = g_io_channel_unix_new(gpio->value_fd);
345 if (gpio->io == NULL) {
346 _E("g_io_channel_unix_new error (%d)", gpio->value_fd);
347 goto err_io_channel_new;
350 g_io_channel_seek_position(gpio->io, 0, G_SEEK_SET, NULL);
351 status = g_io_channel_read_line(gpio->io, &strval, NULL, NULL, NULL);
352 if (status != G_IO_STATUS_NORMAL) {
353 _E("Unable to read gpio value (%d)", status);
354 goto err_io_channel_read;
358 gpio->io_id = g_io_add_watch(gpio->io, G_IO_PRI, peripheral_bus_gpio_cb, gpio);
359 if (gpio->io_id == 0) {
360 _E("g_io_add_watch error (%d)", gpio->io);
361 goto err_io_add_watch;
363 g_io_channel_unref(gpio->io);
366 return PERIPHERAL_ERROR_NONE;
370 g_io_channel_unref(gpio->io);
373 gpio_close_isr(gpio->value_fd);
378 return PERIPHERAL_ERROR_UNKNOWN;
381 int peripheral_bus_gpio_unregister_irq(pb_data_h handle)
383 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
387 g_source_remove(gpio->io_id);
389 g_io_channel_unref(gpio->io);
391 gpio_close_isr(gpio->value_fd);
395 return PERIPHERAL_ERROR_NONE;
398 int peripheral_bus_gpio_close(pb_data_h handle)
400 peripheral_bus_gpio_s *gpio = &handle->dev.gpio;
401 int ret = PERIPHERAL_ERROR_NONE;
403 if ((ret = gpio_close(gpio->pin)) < 0)
406 if (peripheral_bus_data_free(handle) < 0) {
407 _E("Failed to free gpio data");
408 ret = PERIPHERAL_ERROR_UNKNOWN;