--- /dev/null
+/*
+ * PASS
+ *
+ * Copyright (c) 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.
+ */
+
+
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include <libudev.h>
+#include <glib-unix.h>
+
+void init_timer(void);
+void exit_timer(void);
+
+int add_timer_handler(unsigned int interval,
+ gboolean (*timer_func)(gpointer data), void *user_data);
+void delete_timer_handler(int timer_id);
+
+struct udev_monitor *add_uevent_handler(
+ const char *uevent_subsystem[],
+ const char *uevent_devtype[],
+ const int number_of_uevent,
+ gboolean (*uevent_func)(gint fd, GIOCondition cond, void *data),
+ void *user_data);
+void delete_uevent_handler(struct udev_monitor *udev_monitor);
+
+#endif
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2017 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 <glib.h>
+#include <stdio.h>
+#include <libudev.h>
+#include <glib-unix.h>
+
+#include <util/common.h>
+#include <util/log.h>
+#include <util/timer.h>
+
+#define TYPE_TIMER 0
+#define TYPE_UEVENT 1
+
+static struct udev *g_udev;
+
+static GList *g_timer_list;
+static GList *g_uevent_list;
+
+struct uevent_data {
+ struct udev_monitor *udev_monitor;
+ int fd;
+};
+
+static gint __compare_timer_id(gconstpointer data, gconstpointer input)
+{
+ guint id= *(guint *)data;
+ guint input_id = *(guint *)input;
+
+ return (id == input_id) ? 0 : -1;
+}
+
+static bool find_timer(int id)
+{
+ GList *node;
+
+ node = g_list_find_custom(g_timer_list, &id, __compare_timer_id);
+
+ if (!node)
+ return false;
+ return true;
+}
+
+static gint __compare_uevent_data(gconstpointer data, gconstpointer input)
+{
+ struct uevent_data *uevent_data = (struct uevent_data *)data;
+ struct udev_monitor *udev_monitor = (struct udev_monitor *)input;
+
+ if (uevent_data->udev_monitor == udev_monitor)
+ return 0;
+ return -1;
+}
+
+static struct uevent_data *find_uevent_data(struct udev_monitor *udev_monitor)
+{
+ GList *node;
+
+ node = g_list_find_custom(g_uevent_list, udev_monitor,
+ __compare_uevent_data);
+
+ if (!node)
+ return NULL;
+ return (struct uevent_data *)node->data;
+}
+
+int add_timer_handler(unsigned int interval,
+ gboolean (*timer_func)(gpointer data), void *user_data)
+{
+ guint timer_id;
+
+ timer_id = g_timeout_add((guint)interval, (GSourceFunc)timer_func,
+ (gpointer)user_data);
+ if (!timer_id)
+ return -EPERM;
+
+ g_timer_list = g_list_append(g_timer_list,
+ (gpointer)&timer_id);
+
+ return timer_id;
+}
+
+void delete_timer_handler(int timer_id)
+{
+ if (!find_timer(timer_id))
+ return;
+
+ g_source_remove(timer_id);
+ g_timer_list = g_list_remove(g_timer_list,
+ (gpointer)&timer_id);
+}
+
+struct udev_monitor *add_uevent_handler(
+ const char *uevent_subsystem[],
+ const char *uevent_devtype[],
+ const int number_of_uevent,
+ gboolean (*uevent_func)(gint fd, GIOCondition cond, void *data),
+ void *user_data)
+{
+ struct uevent_data *uevent_data;
+ struct udev_monitor *udev_monitor;
+ guint gfd;
+ int ret;
+ int fd;
+ int i;
+
+ /* Initialize the udev-monitor instance and set buffer size */
+ udev_monitor = udev_monitor_new_from_netlink(g_udev, "kernel");
+ if (!udev_monitor) {
+ _E("failed to create the udev monitor\n");
+ return NULL;
+ }
+
+ /*
+ * Number of uevent subsystem must be more than 0 at least.
+ */
+ if (number_of_uevent <= 0) {
+ _E("failed to add filter due to subsystem/devtype are NULL\n");
+ ret = -EINVAL;
+ goto err_udev_monitor;
+ }
+
+ /* Update the kernel's subsystem and devtype for filtering */
+ for (i = 0; i < number_of_uevent; i++) {
+ ret = udev_monitor_filter_add_match_subsystem_devtype(
+ udev_monitor,
+ uevent_subsystem[i],
+ uevent_devtype[i]);
+ if (ret < 0) {
+ _E("failed to add filter with subsystem(%s)/devtype(%s)\n",
+ uevent_subsystem[i], uevent_devtype[i]);
+ goto err_udev_monitor;
+ }
+ }
+
+ ret = udev_monitor_filter_update(udev_monitor);
+ if (ret < 0) {
+ for (i = 0; i < number_of_uevent; i++) {
+ _E("failed to update filter with subsystem(%s)/devtype(%s)\n",
+ uevent_subsystem[i], uevent_devtype[i]);
+ }
+ goto err_udev_monitor;
+ }
+
+ /* Register callback to subscribe the event */
+ fd = udev_monitor_get_fd(udev_monitor);
+ if (fd <= 0) {
+ _E("failed to get file descriptor of udev monitor\n");
+ ret = -EINVAL;
+ goto err_udev_monitor;
+ }
+
+ gfd = g_unix_fd_add(fd, G_IO_IN, uevent_func, user_data);
+ if (gfd <= 0) {
+ _E("failed to add uevent-based callback function\n");
+ ret = -EINVAL;
+ goto err_udev_monitor;
+ }
+
+ /* Bind udev-monitor to enable the udev monitoring */
+ ret = udev_monitor_enable_receiving(udev_monitor);
+ if (ret < 0) {
+ _E("failed to bind udev monitor for receiving the event\n");
+ ret = -EAGAIN;
+ goto err_udev_monitor_fd;
+ }
+
+ /* Add new uevent-based handler to uevent_list */
+ uevent_data = calloc(1, sizeof(*uevent_data));
+ uevent_data->udev_monitor = udev_monitor;
+ uevent_data->fd = gfd;
+ g_uevent_list = g_list_append(g_uevent_list, (gpointer)uevent_data);
+
+ return udev_monitor;
+
+err_udev_monitor_fd:
+ g_source_remove(gfd);
+ gfd = -1;
+err_udev_monitor:
+ udev_monitor_unref(udev_monitor);
+ udev_monitor = NULL;
+
+ return NULL;
+}
+
+void delete_uevent_handler(struct udev_monitor *udev_monitor)
+{
+ struct uevent_data *uevent_data;
+
+ if (!udev_monitor)
+ return;
+
+ uevent_data = find_uevent_data(udev_monitor);
+ if (!uevent_data)
+ return;
+
+ g_uevent_list = g_list_remove(g_uevent_list, (gpointer)uevent_data->udev_monitor);
+ udev_monitor_unref(uevent_data->udev_monitor);
+ uevent_data->udev_monitor = NULL;
+
+ g_source_remove(uevent_data->fd);
+ uevent_data->fd = -1;
+}
+
+void init_timer(void)
+{
+ g_timer_list = NULL;
+ g_uevent_list = NULL;
+
+ g_udev = udev_new();
+ if (!g_udev)
+ _E("failed to create udev for uevent-based monitor\n");
+}
+
+void exit_timer(void)
+{
+ /*
+ * FIXME: Need to iterate the g_timer_list, g_uevent_list
+ * in order to release memory
+ */
+
+ g_list_free(g_timer_list);
+ g_list_free(g_uevent_list);
+
+ g_timer_list = NULL;
+ g_uevent_list = NULL;
+
+ udev_unref(g_udev);
+}