#include <stdio.h>
#include <errno.h>
#include <assert.h>
+#include <glib.h>
#include <device-node.h>
#include <Ecore.h>
#include <vconf.h>
#include <hw/led.h>
#include "core/log.h"
+#include "core/list.h"
#include "core/common.h"
#include "core/edbus-handler.h"
#include "core/devices.h"
#include "core/device-notifier.h"
+struct rgb_request {
+ pid_t pid;
+ struct led_state state;
+};
+
/* enum values defined in capi-system-device */
typedef enum {
LED_CUSTOM_DUTY_ON = 1 << 0, /**< blink LED */
LED_CUSTOM_DEFAULT = (LED_CUSTOM_DUTY_ON), /**< Default flag */
} led_custom_flags;
-struct led_device *rgb_dev;
+static struct led_device *rgb_dev;
+static dd_list *rgb_list;
+static struct rgb_request *top;
+static guint timer;
+
+static int find_rgb_req(pid_t pid, struct rgb_request **request)
+{
+ dd_list *l;
+ struct rgb_request *req;
+
+ DD_LIST_FOREACH(rgb_list, l, req) {
+ if (req->pid == pid) {
+ *request = req;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+static int remove_req_from_list(pid_t pid)
+{
+ dd_list *l;
+ struct rgb_request *req;
+
+ DD_LIST_FOREACH(rgb_list, l, req) {
+ if (req->pid == pid) {
+ _I("remove rgb play request from pid (%d)", pid);
+ if (req == top)
+ top = NULL;
+ DD_LIST_REMOVE(rgb_list, req);
+ free(req);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int add_req_to_list(pid_t pid, struct led_state *state)
+{
+ int ret;
+ struct rgb_request *req;
+
+ if (!state)
+ return -EINVAL;
+
+ ret = find_rgb_req(pid, &req);
+ if (ret < 0) {
+ req = calloc(1, sizeof(struct rgb_request));
+ if (!req) {
+ _E("calloc() failed");
+ return -ENOMEM;
+ }
+ req->pid = pid;
+ DD_LIST_APPEND(rgb_list, req);
+ }
+
+ req->state.color = state->color;
+ req->state.duty_on = state->duty_on;
+ req->state.duty_off = state->duty_off;
+ req->state.type = state->type;
+
+ top = req;
+
+ return 0;
+}
static int rgb_play(struct led_state *state)
{
+ struct led_state off = { 0, };
+
if (!rgb_dev) {
_E("There is NO HAL");
return -ENODEV;
return -ENOTSUP;
}
- return rgb_dev->set_state(state);
+ if (state)
+ return rgb_dev->set_state(state);
+
+ return rgb_dev->set_state(&off);
+}
+
+static gboolean remove_not_handled_req(gpointer data)
+{
+ dd_list *l;
+ int ret = 0;
+ struct rgb_request *req;
+
+ DD_LIST_FOREACH(rgb_list, l, req) {
+ if (kill(req->pid, 0) == -1) {
+ ret = remove_req_from_list(req->pid);
+ if (ret < 0)
+ _E("Failed to remove rgb request (%d)", ret);
+ }
+ }
+
+ if (!top) {
+ ret = rgb_play(NULL);
+ if (ret < 0)
+ _E("Failed to turn off removed request (%d)", ret);
+ }
+
+ if (DD_LIST_LENGTH(rgb_list) == 0) {
+ timer = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void add_timer_to_check_invalid_req(void)
+{
+ if (timer > 0)
+ return;
+
+ timer = g_timeout_add(5000, remove_not_handled_req, NULL);
+ if (timer == 0)
+ _E("Failed to add timer");
}
static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
state.type = LED_TYPE_MANUAL;
ret = rgb_play(&state);
- if (ret < 0)
+ if (ret < 0) {
_E("Failed to play LED notification (%d)", ret);
+ goto out;
+ }
+
+ add_req_to_list(pid, &state);
+ add_timer_to_check_invalid_req();
out:
return make_reply_message(msg, ret);
static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
{
- struct led_state state = { 0, };
int ret;
pid_t pid;
_I("pid %d led stop custom", pid);
- ret = rgb_play(&state);
- if (ret < 0)
- _E("Failed to play LED notification (%d)", ret);
+ ret = remove_req_from_list(pid);
+ if (ret < 0) {
+ _E("There is no request from pid (%d) to remove", pid);
+ goto out;
+ }
+ if (!top) {
+ ret = rgb_play(NULL);
+ if (ret < 0) {
+ _E("Failed to play LED notification (%d)", ret);
+ goto out;
+ }
+ }
+
+out:
return make_reply_message(msg, ret);
}