SET(SRCS
src/core/main.c
+ src/core/haptic.c
src/shared/common.c
src/shared/device-idler.c
src/shared/log.c
- src/driver/haptic.c
- src/driver/haptic-dev.c
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src)
libsyscommon
libsystemd
capi-system-device
+ hal-api-device
+ hal-api-common
)
INCLUDE(FindPkgConfig)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
ADD_DEFINITIONS("-DDEBUG")
-ADD_DEFINITIONS("-DLIBPATH=\"${LIB_INSTALL_DIR}\"")
ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs2_LDFLAGS} "-ldl" "-lm")
INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
-SET(LIB_PREFIX haptic_)
-SET(DRIVER_PKG_MODULES
- dlog
- capi-system-info
- glib-2.0
- libsyscommon
-)
-
-INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs_driver REQUIRED ${DRIVER_PKG_MODULES})
-
-FOREACH(flag_driver ${pkgs_driver_CFLAGS})
- SET(DRIVER_CFLAGS "${DRIVER_CFLAGS} ${flag_driver}")
-ENDFOREACH(flag_driver)
-
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DRIVER_CFLAGS} -fvisibility=hidden -Werror -g -fno-omit-frame-pointer -finstrument-functions -pie")
-
-ADD_LIBRARY(emul MODULE src/driver/emulator.c)
-TARGET_LINK_LIBRARIES(emul ${pkgs_driver_LDFLAGS} "-ldl")
-SET_TARGET_PROPERTIES(emul PROPERTIES PREFIX ${LIB_PREFIX})
-INSTALL(TARGETS emul DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
-
-ADD_LIBRARY(gpio MODULE src/driver/gpio_haptic.c)
-TARGET_LINK_LIBRARIES(gpio ${pkgs_driver_LDFLAGS} "-lcapi-system-peripheral-io -ldl")
-SET_TARGET_PROPERTIES(gpio PROPERTIES PREFIX ${LIB_PREFIX})
-INSTALL(TARGETS gpio DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
-
-ADD_LIBRARY(standard MODULE src/driver/standard.c)
-TARGET_LINK_LIBRARIES(standard ${pkgs_driver_LDFLAGS} "-ldl")
-SET_TARGET_PROPERTIES(standard PROPERTIES PREFIX ${LIB_PREFIX})
-INSTALL(TARGETS standard DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
-
INSTALL(FILES ${CMAKE_SOURCE_DIR}/conf/feedbackd.conf DESTINATION /etc/dbus-1/system.d)
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/system
FILES_MATCHING
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(gio-unix-2.0)
BuildRequires: pkgconfig(capi-system-info)
-BuildRequires: pkgconfig(capi-system-peripheral-io)
BuildRequires: pkgconfig(libsyscommon)
BuildRequires: pkgconfig(libsystemd)
BuildRequires: pkgconfig(capi-system-device)
+BuildRequires: pkgconfig(hal-api-device)
+BuildRequires: pkgconfig(hal-api-common)
Requires(post): /usr/bin/vconftool
%description feedbackd
feedback daemon.
-%package driver-emulator
-Summary: Haptic driver targeting emulator plugin
-Provides: %{name}-compat = %{version}-%{release}
-Conflicts: %{name}-driver-gpio
-Conflicts: %{name}-driver-standard
-%description driver-emulator
-Emulator device driver. Required by main feedbackd package.
-
-%package driver-gpio
-Summary: Haptic driver targeting emulator plugin
-Provides: %{name}-compat = %{version}-%{release}
-Conflicts: %{name}-driver-emulator
-Conflicts: %{name}-driver-standard
-%description driver-gpio
-Gpio haptic device driver. Required by main feedbackd package.
-
-%package driver-standard
-Summary: Haptic driver targeting emulator plugin
-Provides: %{name}-compat = %{version}-%{release}
-Conflicts: %{name}-driver-emulator
-Conflicts: %{name}-driver-gpio
-%description driver-standard
-Standard haptic device driver. Required by main feedbackd package.
-
%package conf-level3
Summary: Feedbackd level configuration file
Provides: configuration-compat = %{version}-%{release}
%postun
systemctl daemon-reload
-%post driver-emulator
-mkdir -p %{_libdir}/feedbackd
-mv %{_libdir}/haptic_emul.so %{_libdir}/feedbackd/haptic.so
-
-%post driver-gpio
-mkdir -p %{_libdir}/feedbackd
-mv %{_libdir}/haptic_gpio.so %{_libdir}/feedbackd/haptic.so
-
-%post driver-standard
-mkdir -p %{_libdir}/feedbackd
-mv %{_libdir}/haptic_standard.so %{_libdir}/feedbackd/haptic.so
-
%post conf-level3
mv %{_sysconfdir}/feedbackd/haptic-level3.conf %{_sysconfdir}/feedbackd/haptic.conf
%post conf-level6
mv %{_sysconfdir}/feedbackd/haptic-level6.conf %{_sysconfdir}/feedbackd/haptic.conf
-%preun driver-emulator
-mv %{_libdir}/feedbackd/haptic.so %{_libdir}/haptic_emul.so
-if [ "$1" == "0" ]; then
- systemctl stop feedbackd.service
-fi
-
-%preun driver-gpio
-mv %{_libdir}/feedbackd/haptic.so %{_libdir}/haptic_gpio.so
-if [ "$1" == "0" ]; then
- systemctl stop feedbackd.service
-fi
-
-%preun driver-standard
-mv %{_libdir}/feedbackd/haptic.so %{_libdir}/haptic_standard.so
-if [ "$1" == "0" ]; then
- systemctl stop feedbackd.service
-fi
-
%files -n feedbackd
%manifest %{name}.manifest
%license LICENSE.Apache-2.0
%{_datadir}/dbus-1/system-services/org.tizen.system.vibrator.service
%{_bindir}/feedbackd
-%files driver-emulator
-%license LICENSE.Apache-2.0
-%{_libdir}/haptic_emul.so
-
-%files driver-gpio
-%license LICENSE.Apache-2.0
-%{_libdir}/haptic_gpio.so
-
-%files driver-standard
-%license LICENSE.Apache-2.0
-%{_libdir}/haptic_standard.so
-
%files conf-level3
%license LICENSE.Apache-2.0
%manifest %{name}.manifest
--- /dev/null
+/*
+ * feedbackd
+ *
+ * Copyright (c) 2012 - 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 <stdio.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <vconf.h>
+#include <time.h>
+#include <string.h>
+#include <libsyscommon/dbus-system.h>
+#include <libsyscommon/list.h>
+#include <libsyscommon/ini-parser.h>
+#include <hal/device/hal-haptic.h>
+
+#include "shared/log.h"
+#include "shared/common.h"
+#include "shared/device-idler.h"
+#include "haptic.h"
+
+#define FEEDBACK_BASE_PATH "/usr/share/feedback/"
+#define STANDARD_FILE_PATH FEEDBACK_BASE_PATH"vibration/"
+#define VIBRATION_CONF_PATH FEEDBACK_BASE_PATH"vibration.conf"
+
+#define HAPTIC_CONF_PATH "/etc/feedbackd/haptic.conf"
+#define SIGNAL_POWEROFF_STATE "ChangeState"
+#define SIGNAL_VIBRATOR_INITIATED "InitiateVibrator"
+
+/* hardkey vibration variable */
+#define HARDKEY_VIB_ITERATION 1
+#define HARDKEY_VIB_FEEDBACK 3
+#define HARDKEY_VIB_DURATION 30
+#define HAPTIC_FEEDBACK_STEP 20
+#define DEFAULT_FEEDBACK_LEVEL 3
+#define HIGH_FEEDBACK_LEVEL 100
+#define LOW_FEEDBACK_LEVEL 0
+
+/* power on, power off vibration variable */
+#define POWER_ON_VIB_DURATION 300
+#define POWER_OFF_VIB_DURATION 300
+#define POWER_VIB_FEEDBACK 100
+
+#define MAX_EFFECT_BUFFER (64*1024)
+
+#ifndef VCONFKEY_RECORDER_STATE
+#define VCONFKEY_RECORDER_STATE "memory/recorder/state"
+#define VCONFKEY_RECORDER_STATE_RECORDING 2
+#endif
+
+#define RETRY_CNT 3
+
+#define INTENSITY_BASE_RATE (10000)
+#define VALUE_MAX_LEN 10
+#define VIB_LOCK_TIMEOUT_MAX (300000) /* 5minutes */
+
+/*
+ 1,A_W or A,A_W or 250D250W250D750W
+
+ 85,10000,
+ 90,0,
+ 105,10000,
+ 0,end
+*/
+struct vibration_config {
+ char *pattern; /* pattern name */
+ char *standard; /* assigned standard pattern name */
+ GList *data; /* duration_data list */
+ unsigned int pattern_duration;
+ int unlimit;
+};
+
+struct duration_data {
+ int duration;
+ int intensity;
+ int frequency;
+ int overdrive;
+ int wait;
+};
+
+enum poweroff_type {
+ POWER_OFF_NONE = 0,
+ POWER_OFF_POPUP,
+ POWER_OFF_DIRECT,
+ POWER_OFF_RESTART,
+};
+
+struct haptic_info {
+ char *sender;
+ GList *handle_list;
+ guint id_watch;
+};
+
+struct vibrate_pattern_info {
+ unsigned int handle;
+ char *pattern;
+ int level;
+ int priority;
+};
+
+struct vibrate_monotone_info {
+ unsigned int handle;
+ int duration;
+ int level;
+ int intensity;
+ int priority;
+};
+
+/* for playing */
+static int g_handle;
+
+/* pattern configuration list */
+static GList *vib_conf_list;
+
+static guint duration_timer;
+
+/* haptic operation variable */
+static GList *haptic_handle_list;
+
+static bool haptic_disabled;
+
+struct haptic_config {
+ int level;
+ int *level_arr;
+ int sound_capture;
+};
+
+static struct haptic_config haptic_conf;
+
+static int haptic_start(void);
+static int haptic_stop(void);
+static int remove_haptic_info(struct haptic_info *info);
+
+struct haptic_data cur_h_data;
+
+static int insert_conf_data(GList **conf_data, struct duration_data *update)
+{
+ struct duration_data *data;
+
+ data = (struct duration_data *)calloc(1, sizeof(struct duration_data));
+ if (!data) {
+ _E("Not enough memory.");
+ return -ENOMEM;
+ }
+ memcpy(data, update, sizeof(struct duration_data));
+ /* insert vibration pattern data */
+ // to debug :
+ // _D("%dD%dI%dF%dO%dW", data->duration, data->intensity, data->frequency, data->overdrive, data->wait);
+ SYS_G_LIST_APPEND(*conf_data, data);
+ return 0;
+}
+
+static void get_pattern_property(char **iter, char property, int *value)
+{
+ char *check;
+ unsigned long int val;
+
+ check = strchr(*iter, property);
+ if (!check)
+ return;
+
+ *check = '\0';
+ val = strtoul(*iter, NULL, 10);
+ if (errno == EINVAL || errno == ERANGE) {
+ val = 0;
+ _E("Failed to get value of %s: %d", *iter, errno);
+ }
+ if (val > VIB_LOCK_TIMEOUT_MAX)
+ val = VIB_LOCK_TIMEOUT_MAX;
+
+ *value = (int)val;
+
+ *iter = check + 1;
+}
+
+/* [A]xxxDxxxIxxxFxxxOxxxW format */
+static int insert_raw_data_format(GList **conf_data, char *value)
+{
+ struct duration_data update = {0, };
+ char *iter;
+ char *end;
+ int pattern_duration = 0;
+
+ if (!value)
+ return insert_conf_data(conf_data, &update);
+ if (!conf_data) {
+ _E("Invalid parameter: Configuration list is null");
+ return -EINVAL;
+ }
+
+ iter = value;
+ end = iter + strlen(iter);
+ while (iter < end) {
+ memset(&update, 0, sizeof(struct duration_data));
+
+ get_pattern_property(&iter, 'D', &update.duration);
+ get_pattern_property(&iter, 'I', &update.intensity);
+ if (update.intensity > INTENSITY_BASE_RATE)
+ update.intensity = INTENSITY_BASE_RATE;
+ get_pattern_property(&iter, 'F', &update.frequency);
+ get_pattern_property(&iter, 'W', &update.wait);
+
+ if (update.duration == 0 && update.wait == 0) {
+ _D("Pattern duration is zero.");
+ break;
+ }
+
+ pattern_duration += (update.duration + update.wait);
+ if (pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
+ _D("Max pattern duration.");
+ pattern_duration = VIB_LOCK_TIMEOUT_MAX;
+ }
+
+ if (insert_conf_data(conf_data, &update) < 0)
+ return -EINVAL;
+ }
+
+ return pattern_duration;
+}
+
+static int get_config_data(int count, bool *packed, char *val, unsigned int *pattern_duration, struct duration_data *update)
+{
+ static int duration = 0;
+ static int intensity = 0;
+ int value;
+ int ret;
+
+ if (count > 4 || count <= 0) {
+ _E("Invalid parameter: count is invalid");
+ return -EINVAL;
+ }
+
+ if (!packed || !val || !pattern_duration || !update) {
+ _E("Invalid parameter: %p %p %p %p", packed, val, pattern_duration, update);
+ return -EINVAL;
+ }
+
+ get_pattern_property(&val, 'C', &value);
+
+ ret = count;
+ switch (count) {
+ case 1: /* D */
+ duration = value;
+ *pattern_duration += duration;
+ if (*pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
+ _D("Max pattern duration.");
+ *pattern_duration = VIB_LOCK_TIMEOUT_MAX;
+ }
+ break;
+ case 2: /* I or W */
+ if (value > INTENSITY_BASE_RATE)
+ value = INTENSITY_BASE_RATE;
+ intensity = value;
+ if (*packed == false) {
+ update->duration = duration;
+ update->intensity = intensity;
+ break;
+ }
+ /* if intensity is 0, duration use for wait(off) time */
+ if (intensity == 0)
+ update->wait = duration;
+ else
+ update->wait = 0;
+ *packed = false;
+ duration = 0;
+ intensity = 0;
+ ret = -1;
+ break;
+ case 3: /* F */
+ if (intensity != 0)
+ update->frequency = value;
+ break;
+ case 4: /* O */
+ if (intensity != 0) {
+ update->overdrive = value;
+ *packed = true;
+ }
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+/*
+ duration, intensity, frequency, overdrive
+ waiting duration, intensity=0, frequency, overdrive
+ 85,10000,
+ 90,0,
+ 105,10000,
+ 0,end
+*/
+static int load_standard_format(const char *pattern)
+{
+ struct duration_data update = {0, };
+ bool packed = false;
+ struct vibration_config *conf;
+ int ret = 0, count = 0, end = 2;
+ int index = 0;
+ int fd;
+ char path[PATH_MAX], elem, val[VALUE_MAX_LEN] = {0, };
+
+ snprintf(path, sizeof(path), STANDARD_FILE_PATH"%s", pattern);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -ENOENT;
+
+ conf = (struct vibration_config *)calloc(1, sizeof(struct vibration_config));
+ if (!conf) {
+ _E("Failed to alloc.");
+ ret = -errno;
+ goto error_out;
+ }
+
+ conf->pattern = strdup(pattern);
+ if (!conf->pattern) {
+ _E("Failed to copy pattern data(%s).", pattern);
+ ret = -errno;
+ goto error_out;
+ }
+
+ /* make feedback pattern(xDxIxFxOxW) format from d,i,f,o, */
+ while (read(fd, &elem, 1) != 0) {
+ if (end == 0) {
+ if (insert_conf_data(&conf->data, &update) < 0)
+ goto error_out;
+ break;
+ }
+ if (elem == 'e' || elem == 'n' || elem == 'd') {
+ end--;
+ continue;
+ }
+ if (elem == '\n') {
+ count = 0;
+ continue;
+ }
+ if (elem == ',') {
+ count++;
+ val[index] = 'C';
+ index = 0;
+
+ ret = get_config_data(count, &packed, val, &(conf->pattern_duration), &update);
+ if (ret < 0) {
+ if (ret == -EINVAL)
+ break;
+ if (insert_conf_data(&conf->data, &update) < 0)
+ goto error_out;
+ memset(&update, 0, sizeof(struct duration_data));
+ } else
+ count = ret;
+ } else {
+ if (index < (VALUE_MAX_LEN - 2)) /* Temporal limit */
+ val[index++] = elem;
+ else
+ _E("Pattern(%s) is out of bound: %s", pattern, val);
+ }
+ }
+ close(fd);
+ SYS_G_LIST_APPEND(vib_conf_list, conf);
+ return ret;
+
+error_out:
+ if (fd >= 0)
+ close(fd);
+ if (conf) {
+ if (conf->pattern)
+ free(conf->pattern);
+ free(conf);
+ }
+ return -ENOENT;
+}
+
+static int vibration_load_config(struct parse_result *result, void *user_data)
+{
+ struct vibration_config *conf;
+ char *value;
+ char *check;
+ int len;
+ int duration;
+
+ if (!result)
+ return 0;
+
+ if (!MATCH(result->section, "Vibration"))
+ return 0;
+
+
+ if (!result->name || !result->value)
+ return 0;
+
+ conf = (struct vibration_config *)calloc(1, sizeof(struct vibration_config));
+ if (!conf) {
+ _E("Failed to alloc.");
+ return -ENOMEM;
+ }
+
+ conf->pattern_duration = 0;
+ conf->pattern = strdup(result->name);
+ if (!conf->pattern) {
+ _E("Failed to copy pattern data(%s).", result->name);
+ goto error_out;
+ }
+
+ value = result->value;
+ len = strlen(value);
+
+ if (len == 0) {
+ if (insert_raw_data_format(&conf->data, NULL) < 0)
+ goto error_out;
+ SYS_G_LIST_APPEND(vib_conf_list, conf);
+ return 0;
+ }
+
+ /* Load Standard Pattern Name */
+ /* value: 1,A_W or A,A_W */
+ if ((check = strchr(value, ','))) {
+ *check = '\0';
+ if (strncmp(value, "A", 1) == 0)
+ conf->unlimit = 1;
+ value = check + 1;
+ conf->standard = strdup(value);
+ if (!conf->standard) {
+ _E("Failed to copy standard name.");
+ goto error_out;
+ }
+ SYS_G_LIST_APPEND(vib_conf_list, conf);
+ return 0;
+ }
+
+ /* value : A100D or 100D0W or 250D250W250D750W */
+ /* Load Vibration Pattern Data */
+ check = strchr(value, 'A');
+ if (check) {
+ *check = '\0';
+ conf->unlimit = 1;
+ if (!value)
+ len = len - 1;
+ else
+ len = len - strlen(value) - 1;
+ value = check + 1;
+ }
+ duration = insert_raw_data_format(&conf->data, value);
+ if (duration < 0) {
+ conf->pattern_duration = 0;
+ goto error_out;
+ } else
+ conf->pattern_duration = duration;
+ SYS_G_LIST_APPEND(vib_conf_list, conf);
+
+ return 0;
+
+error_out:
+ if (conf) {
+ if (conf->pattern)
+ free(conf->pattern);
+ if (conf->standard)
+ free(conf->standard);
+ }
+ return -ENOMEM;
+}
+
+static void load_standard_vibration_patterns(void)
+{
+ DIR *dir;
+ struct dirent *dent;
+ int ret;
+
+ dir = opendir(STANDARD_FILE_PATH);
+ if (!dir) {
+ _E("Failed to load '%s' Use default value.", STANDARD_FILE_PATH);
+ return;
+ }
+ while ((dent = readdir(dir))) {
+ if (dent->d_type == DT_DIR)
+ continue;
+ ret = load_standard_format(dent->d_name);
+ if (ret < 0)
+ _E("Failed to parse %s: %d", dent->d_name, ret);
+ }
+ closedir(dir);
+ _D("Success to load '%s'", STANDARD_FILE_PATH);
+}
+
+void pattern_config_parse(void)
+{
+ int ret;
+
+ ret = config_parse(VIBRATION_CONF_PATH, vibration_load_config, NULL);
+ if (ret < 0)
+ _E("Failed to load '%s'. Use default value: %d", VIBRATION_CONF_PATH, ret);
+
+ load_standard_vibration_patterns();
+}
+
+static int haptic_module_load(void)
+{
+ int r;
+
+ pattern_config_parse();
+
+ r = hal_device_haptic_get_backend();
+ if (r < 0) {
+ _E("Failed to load device. ret=%d", r);
+ return r;
+ }
+
+ /* solution bug
+ * we do not use internal vibration except power off.
+ * if the last handle is closed during the playing of vibration,
+ * solution makes unlimited vibration.
+ * so we need at least one handle. */
+ r = hal_device_haptic_open_device(&g_handle);
+ if (r < 0) {
+ _E("Failed to open device. ret=%d", r);
+ return r;
+ }
+
+ return 0;
+}
+
+/*
+static int convert_magnitude_by_conf(int level)
+{
+ int i, step;
+
+ if (level < LOW_FEEDBACK_LEVEL)
+ level = LOW_FEEDBACK_LEVEL;
+ else if (level > HIGH_FEEDBACK_LEVEL)
+ level = HIGH_FEEDBACK_LEVEL;
+
+ step = 100 / (haptic_conf.level-1);
+ for (i = 0; i < haptic_conf.level; ++i) {
+ if (level <= i*step) {
+ _D("Level changed. %d -> %d", level, haptic_conf.level_arr[i]);
+ return haptic_conf.level_arr[i];
+ }
+ }
+
+ _D("Play default level.");
+ return DEFAULT_FEEDBACK_LEVEL * HAPTIC_FEEDBACK_STEP;
+}
+*/
+GVariant *hdbus_get_count(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ int ret, val;
+
+ ret = hal_device_haptic_get_device_count(&val);
+ if (ret >= 0)
+ ret = val;
+
+ return g_variant_new("(i)", ret);
+}
+
+void haptic_name_owner_changed(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GList *n;
+ struct haptic_info *info = user_data;
+ int handle;
+
+ _I("%s (sender=%s)", __func__, name);
+
+ if (!info)
+ return;
+
+ for (n = info->handle_list; n; n = n->next) {
+ handle = (int)(long)n->data;
+ hal_device_haptic_stop_device(handle);
+ hal_device_haptic_close_device(handle);
+ }
+
+ remove_haptic_info(info);
+}
+
+static struct haptic_info *add_haptic_info(const char *sender)
+{
+ struct haptic_info *info;
+
+ assert(sender);
+
+ info = calloc(1, sizeof(struct haptic_info));
+ if (!info)
+ return NULL;
+
+ info->sender = strdup(sender);
+ if (!info->sender) {
+ free(info);
+ return NULL;
+ }
+
+ SYS_G_LIST_APPEND(haptic_handle_list, info);
+
+ info->id_watch = dbus_handle_watch_name(sender, NULL, haptic_name_owner_changed, info, NULL);
+
+ return info;
+}
+
+static int remove_haptic_info(struct haptic_info *info)
+{
+ assert(info);
+
+ dbus_handle_unwatch_name(info->id_watch);
+
+ SYS_G_LIST_REMOVE(haptic_handle_list, info);
+ SYS_G_LIST_FREE_LIST(info->handle_list);
+ if (info->sender) {
+ free(info->sender);
+ }
+ free(info);
+
+ return 0;
+}
+
+static struct haptic_info *get_matched_haptic_info(const char *sender)
+{
+ GList *n;
+ struct haptic_info *info;
+ int len;
+
+ assert(sender);
+
+ len = strlen(sender) + 1;
+ SYS_G_LIST_FOREACH(haptic_handle_list, n, info) {
+ if (!strncmp(info->sender, sender, len))
+ return info;
+ }
+
+ return NULL;
+}
+
+GVariant *hdbus_open_device(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ int index, handle, ret;
+ struct haptic_info *info;
+
+ /* Load haptic module before booting done */
+ if (hal_device_haptic_check_backend() < 0) {
+ ret = hal_device_haptic_get_backend();
+ if (ret < 0)
+ goto exit;
+ }
+
+ g_variant_get(param, "(i)", &index);
+
+ ret = hal_device_haptic_open_device(&handle);
+ if (ret < 0)
+ goto exit;
+
+ if (!sender) {
+ ret = -EPERM;
+ hal_device_haptic_close_device(handle);
+ goto exit;
+ }
+
+ info = get_matched_haptic_info(sender);
+ if (!info) {
+ info = add_haptic_info(sender);
+ if (!info) {
+ _E("Failed to create haptic information.");
+ ret = -EPERM;
+ hal_device_haptic_close_device(handle);
+ goto exit;
+ }
+ }
+
+ SYS_G_LIST_APPEND(info->handle_list, (gpointer)(long)handle);
+
+ ret = handle;
+
+exit:
+ return g_variant_new("(i)", ret);
+}
+
+int clear_current_data(void)
+{
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+
+ if (duration_timer) {
+ _I("Remove duration_timer.");
+ g_source_remove(duration_timer);
+ duration_timer = 0;
+ }
+
+ return 0;
+}
+
+GVariant *hdbus_close_device(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ unsigned int handle;
+ int ret;
+ struct haptic_info *info;
+ int cnt;
+
+ g_variant_get(param, "(u)", &handle);
+
+ if (!sender) {
+ _E("Failed to get sender from dbus message.");
+ ret = -EPERM;
+ goto exit;
+ }
+
+ ret = hal_device_haptic_close_device(handle);
+ if (ret < 0)
+ goto exit;
+
+ if (cur_h_data.handle == handle) {
+ /* Remove duration_timer for vibrate_effect */
+ clear_current_data();
+ }
+
+ info = get_matched_haptic_info(sender);
+ if (!info) {
+ _E("Failed to find the matched haptic info.");
+ goto exit;
+ }
+
+ SYS_G_LIST_REMOVE(info->handle_list, (gpointer)(long)handle);
+ cnt = SYS_G_LIST_LENGTH(info->handle_list);
+ if (cnt == 0)
+ remove_haptic_info(info);
+
+exit:
+ return g_variant_new("(i)", ret);
+}
+
+static gboolean _cb(void *data)
+{
+ if (duration_timer) {
+ g_source_remove(duration_timer);
+ duration_timer = 0;
+ }
+
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+
+ return G_SOURCE_REMOVE;
+}
+
+static void vibrate_monotone_idler_cb(void *data)
+{
+ struct vibrate_monotone_info *vibrate_info;
+ int ret;
+
+ if (!data)
+ return;
+
+ vibrate_info = (struct vibrate_monotone_info *)data;
+
+ if (vibrate_info->priority < cur_h_data.priority) {
+ _I("Handle(%d) skip low priority. pre=%d now=%d", vibrate_info->handle, cur_h_data.priority, vibrate_info->priority);
+ free(vibrate_info);
+ return;
+ }
+
+ if (duration_timer) {
+ g_source_remove(duration_timer);
+ duration_timer = 0;
+ }
+
+ cur_h_data.vibration_data = NULL;
+ cur_h_data.handle = vibrate_info->handle;
+ cur_h_data.level = vibrate_info->level;
+ cur_h_data.priority = vibrate_info->priority;
+ cur_h_data.stop = false;
+ cur_h_data.unlimit = false;
+
+ ret = device_power_request_lock(POWER_LOCK_CPU, vibrate_info->duration);
+ if (ret != DEVICE_ERROR_NONE)
+ _E("Failed to request power lock.");
+
+ _D("Handle(%d) play=%dms, level=%d, intensity=%d, frequency=0)",
+ cur_h_data.handle, vibrate_info->duration, cur_h_data.level,
+ vibrate_info->intensity);
+
+ duration_timer = g_timeout_add(vibrate_info->duration, _cb, NULL);
+ hal_device_haptic_vibrate(cur_h_data.handle, vibrate_info->duration, 0, 0, cur_h_data.level, vibrate_info->intensity, cur_h_data.priority);
+
+ free(vibrate_info);
+}
+
+GVariant *hdbus_vibrate_monotone(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ struct vibrate_monotone_info *vibrate_info;
+ unsigned int handle;
+ int duration, level, intensity, priority, ret = 0;
+
+ if ((ret = hal_device_haptic_check_backend()) < 0)
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ g_variant_get(param, "(uiii)", &handle, &duration, &intensity, &priority);
+ _D("param (uiii): handle=%u, duration=%d, intensity=%d, priority=%d", handle, duration, intensity, priority);
+
+ if (intensity < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (priority < PRIORITY_MIN)
+ priority = PRIORITY_MIN;
+ else if (priority > PRIORITY_TOP)
+ priority = PRIORITY_TOP;
+
+ if (duration <= 0) {
+ _E("Skip vibrate handle(%d) requested less than 0.", handle);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &level) < 0) {
+ _E("Failed to get '"VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT"' value.");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ vibrate_info = calloc(1, sizeof(struct vibrate_monotone_info));
+ if (!vibrate_info) {
+ _E("Failed to allocate memory for vibrate_info.");
+ ret = -errno;
+ goto exit;
+ }
+
+ vibrate_info->handle = handle;
+ vibrate_info->duration = duration;
+ vibrate_info->level = (level/2) + 1;
+ vibrate_info->intensity = intensity * 100; // 1~100 (API spec)
+ vibrate_info->priority = priority;
+
+ ret = add_idle_request(vibrate_monotone_idler_cb, (void *)vibrate_info);
+exit:
+ return g_variant_new("(i)", ret);
+}
+
+static gboolean haptic_duration_play(void *data)
+{
+ GList *head, *n, *next;
+ struct duration_data *node;
+ int ret = 0;
+
+ if (duration_timer) {
+ g_source_remove(duration_timer);
+ duration_timer = 0;
+ }
+
+ if (!data) {
+ if (cur_h_data.unlimit) /* In case of unlimit pattern, do not stop */
+ head = cur_h_data.vibration_data;
+ else {
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+ goto out;
+ }
+ } else
+ head = (GList *)data;
+
+ if (cur_h_data.stop) {
+ _I("Stop currunt vibration.");
+ cur_h_data.stop = false;
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+ goto out;
+ }
+
+ SYS_G_LIST_FOREACH_SAFE(head, n, next, node) {
+ _I("Handle(%d) play=%dms and Wait=%dms %s type. (level=%d, intensity=%d, frequency=%d)",
+ cur_h_data.handle, node->duration, node->wait,
+ cur_h_data.unlimit ? "Unlimit" : "Once", cur_h_data.level, node->intensity, node->frequency);
+ if ((node->duration + node->wait) <= 0) {
+ if (!cur_h_data.unlimit) {
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+ break;
+ } else {
+ next = cur_h_data.vibration_data;
+ continue;
+ }
+ }
+
+ duration_timer = g_timeout_add((node->duration + node->wait), haptic_duration_play, (void *)next);
+
+ ret = hal_device_haptic_vibrate(cur_h_data.handle, node->duration, node->frequency, node->overdrive, cur_h_data.level, node->intensity, cur_h_data.priority);
+
+ break;
+ }
+ if (ret != 0) {
+ _D("Auto stop vibration.");
+ cur_h_data.stop = true;
+ }
+out:
+ return G_SOURCE_REMOVE;
+}
+
+static void vibrate_pattern_idler_cb(void *data)
+{
+ struct vibrate_pattern_info *vibrate_info;
+ GList *elem;
+ struct vibration_config *conf;
+ char pattern[PATH_MAX];
+ int ret;
+ int unlimit = 0;
+
+ if (!data)
+ return;
+
+ vibrate_info = (struct vibrate_pattern_info *)data;
+
+ if (!(vibrate_info->pattern)) {
+ free(vibrate_info);
+ return;
+ }
+
+ /* Same or higher priority pattern should be played */
+ if (vibrate_info->priority < cur_h_data.priority) {
+ _I("Handle(%d) skip low priority. pre=%d now=%d", vibrate_info->handle, cur_h_data.priority, vibrate_info->priority);
+ goto out;
+ }
+
+ snprintf(pattern, sizeof(pattern), "%s", vibrate_info->pattern);
+ SYS_G_LIST_FOREACH(vib_conf_list, elem, conf) {
+ if (!conf->pattern)
+ continue;
+ if (strcmp(conf->pattern, pattern))
+ continue;
+ if (conf->standard) {
+ unlimit = conf->unlimit;
+ snprintf(pattern, sizeof(pattern), "%s", conf->standard);
+ continue;
+ }
+
+ if (unlimit)
+ cur_h_data.unlimit = unlimit;
+ else
+ cur_h_data.unlimit = conf->unlimit;
+ cur_h_data.vibration_data = conf->data;
+ cur_h_data.handle = vibrate_info->handle;
+ cur_h_data.level = vibrate_info->level;
+ cur_h_data.priority = vibrate_info->priority;
+ cur_h_data.stop = false;
+ _I("Handle(%d) play=%s pri=%d %s", cur_h_data.handle, conf->pattern, cur_h_data.priority,
+ cur_h_data.unlimit ? "Unlimit" : "Once");
+
+ if (conf->pattern_duration <= 0)
+ break;
+
+ if (!cur_h_data.unlimit && conf->pattern_duration > 0) {
+ ret = device_power_request_lock(POWER_LOCK_CPU, (int)conf->pattern_duration);
+ if (ret != DEVICE_ERROR_NONE)
+ _E("Failed to request power lock.");
+ }
+ haptic_duration_play((void *)cur_h_data.vibration_data);
+ goto out;
+ }
+ _E("Handle(%d) %s is not supported.", vibrate_info->handle, pattern);
+
+out:
+ free(vibrate_info->pattern);
+ free(vibrate_info);
+}
+
+GVariant *hdbus_vibrate_pattern(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ struct vibrate_pattern_info *vibrate_info;
+ unsigned int handle;
+ char *pattern = NULL;
+ int level, priority, ret = 0;
+
+ if ((ret = hal_device_haptic_check_backend()) < 0)
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ g_variant_get(param, "(usii)", &handle, &pattern, &level, &priority);
+
+ if (level < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (priority < PRIORITY_MIN)
+ priority = PRIORITY_MIN;
+ else if (priority > PRIORITY_TOP)
+ priority = PRIORITY_TOP;
+
+ vibrate_info = calloc(1, sizeof(struct vibrate_pattern_info));
+ if (!vibrate_info) {
+ _E("Failed to allocate memory for vibrate_info.");
+ ret = -errno;
+ goto exit;
+ }
+ vibrate_info->handle = handle;
+ vibrate_info->pattern = pattern;
+ pattern = NULL;
+ if (!vibrate_info->pattern) {
+ _E("Failed to allocate memory for pattern.");
+ ret = -errno;
+ free(vibrate_info);
+ goto exit;
+ }
+ vibrate_info->level = level;
+ vibrate_info->priority = priority;
+
+ ret = add_idle_request(vibrate_pattern_idler_cb, (void *)vibrate_info);
+
+exit:
+ g_free(pattern);
+ return g_variant_new("(i)", ret);
+}
+
+GVariant *hdbus_stop_device(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ unsigned int handle;
+ int ret = 0;
+
+ if ((ret = hal_device_haptic_check_backend()) < 0)
+ goto exit;
+
+ if (haptic_disabled) {
+ _I("Haptic disabled.");
+ goto exit;
+ }
+
+ g_variant_get(param, "(u)", &handle);
+
+ if (cur_h_data.handle != handle) {
+ _D("Not the request from current vibration handle(%d). Skip.", handle);
+ goto exit;
+ }
+
+ ret = hal_device_haptic_stop_device(handle);
+ _I("Stop the device(handle=%u) :%d", handle, ret);
+
+ /* Remove duration_timer for vibrate_effect */
+ clear_current_data();
+
+exit:
+ return g_variant_new("(i)", ret);
+}
+
+GVariant *hdbus_show_handle_list(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ GList *n;
+ GList *elem;
+ struct haptic_info *info;
+
+ _D("Sender Handle");
+ SYS_G_LIST_FOREACH(haptic_handle_list, n, info) {
+ for (elem = info->handle_list; elem; elem = elem->next)
+ _D("%s %d", info->sender, (int)(long)elem->data);
+ }
+
+ return g_variant_new_tuple(NULL, 0);
+}
+
+int pattern_is_supported(const char *pattern)
+{
+ GList *elem;
+ struct vibration_config *conf;
+ int ret;
+
+ if (!pattern)
+ return -EINVAL;
+
+ ret = 0;
+ SYS_G_LIST_FOREACH(vib_conf_list, elem, conf) {
+ if (!conf->pattern)
+ continue;
+ if (!strcmp(conf->pattern, pattern)) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+GVariant *hdbus_pattern_is_supported(GDBusConnection *conn,
+ const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+
+{
+ char *data = NULL;
+ int ret = 0;
+
+ if ((ret = hal_device_haptic_check_backend()) < 0)
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ g_variant_get(param, "(s)", &data);
+
+ ret = pattern_is_supported(data);
+
+ _I("%s is supported: %d", data, ret);
+
+exit:
+ g_free(data);
+ return g_variant_new("(i)", ret);
+}
+
+static void haptic_poweroff_cb(GDBusConnection *conn,
+ const gchar *sender,
+ const gchar *path,
+ const gchar *iface,
+ const gchar *name,
+ GVariant *param,
+ gpointer data)
+{
+ int type = POWER_OFF_NONE;
+ int ret, level;
+ struct timespec time = {0,};
+
+ if (!g_variant_get_safe(param, "(i)", &type)) {
+ _E("Failed to get params from gvariant. expected:%s, type:%s", "(i)", g_variant_get_type_string(param));
+ return;
+ }
+
+ if (type != POWER_OFF_DIRECT && type != POWER_OFF_RESTART)
+ return;
+
+ _D("Poweroff: %d", type);
+
+ if (hal_device_haptic_check_backend() < 0) {
+ if (haptic_module_load() < 0)
+ return ;
+ }
+
+ if (!g_handle) {
+ if (hal_device_haptic_open_device(&g_handle) < 0)
+ return ;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &level) < 0) {
+ _E("Failed to get '"VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT"' vconf value.");
+ return;
+ }
+ level = (level/2) + 1;
+
+ /* power off vibration */
+ _I("Handle=%d dur=%dms pri=%d level=%d intensity=%d frequency=0",
+ g_handle, POWER_OFF_VIB_DURATION, PRIORITY_HIGH, level,
+ POWER_VIB_FEEDBACK * 100);
+ ret = hal_device_haptic_vibrate(g_handle, POWER_OFF_VIB_DURATION, 0, 0,
+ level, POWER_VIB_FEEDBACK * 100, PRIORITY_HIGH);
+ if (ret < 0) {
+ _E("Failed to vibrate_monotone: %d", ret);
+ return;
+ }
+
+ /* sleep for vibration */
+ time.tv_nsec = POWER_OFF_VIB_DURATION * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+ return;
+}
+
+static void sound_capturing_cb(keynode_t *key, void *data)
+{
+ int status;
+
+ status = vconf_keynode_get_int(key);
+
+ /* if sound capture is in use, this value is 1(true). */
+ if (status == VCONFKEY_RECORDER_STATE_RECORDING)
+ haptic_stop();
+ else
+ haptic_start();
+}
+
+static int parse_section(struct parse_result *result, void *user_data, int index)
+{
+ struct haptic_config *conf = (struct haptic_config *)user_data;
+
+ if (!result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ if (MATCH(result->name, "sound_capture")) {
+ conf->sound_capture = atoi(result->value);
+ } else if (MATCH(result->name, "level")) {
+ conf->level = atoi(result->value);
+ if (conf->level < 0 || conf->level >= INT_MAX - 1) {
+ _E("You must set level with positive number in integer range.");
+ return -EINVAL;
+ }
+ conf->level_arr = calloc(sizeof(int), conf->level);
+ if (!conf->level_arr) {
+ _E("Failed to allocate memory for level.");
+ return -errno;
+ }
+ } else if (MATCH(result->name, "value")) {
+ if (index < 0)
+ return -EINVAL;
+ conf->level_arr[index] = atoi(result->value);
+ }
+
+ return 0;
+}
+
+static int haptic_load_config(struct parse_result *result, void *user_data)
+{
+ struct haptic_config *conf = (struct haptic_config *)user_data;
+ char name[NAME_MAX];
+ int ret;
+ static int index;
+
+ if (!result)
+ return 0;
+
+ if (!result->section || !result->name || !result->value)
+ return 0;
+
+ // Parsing 'Haptic' section
+ if (MATCH(result->section, "Haptic")) {
+ ret = parse_section(result, user_data, -1);
+ if (ret < 0) {
+ _E("Failed to parse 'Haptic' section: %d", ret);
+ return ret;
+ }
+ goto out;
+ }
+
+ // Parsing 'level' section
+ for (index = 0; index < conf->level; ++index) {
+ snprintf(name, sizeof(name), "level%d", index);
+ if (MATCH(result->section, name)) {
+ ret = parse_section(result, user_data, index);
+ if (ret < 0) {
+ _E("Failed to parse 'level' section: %d", ret);
+ return ret;
+ }
+ goto out;
+ }
+ }
+
+out:
+ return 0;
+}
+
+static const dbus_method_s hdbus_methods[] = {
+ { "GetCount", NULL, "i", hdbus_get_count }, // device_haptic_get_count
+ { "OpenDevice", "i", "i", hdbus_open_device }, // device_haptic_open, feedback_initialize
+ { "CloseDevice", "u", "i", hdbus_close_device }, // device_haptic_close, feedback_deinitialize
+ { "StopDevice", "u", "i", hdbus_stop_device }, // device_haptic_stop, feedback_stop
+ { "VibrateMonotone", "uiii", "i", hdbus_vibrate_monotone }, // device_haptic_vibrate
+ { "VibratePattern", "usii", "i", hdbus_vibrate_pattern }, // feedback_play*
+ { "ShowHandleList", NULL, NULL, hdbus_show_handle_list },
+ { "IsSupported", "s", "i", hdbus_pattern_is_supported }, // feedback_is_supported_pattern
+ /* Add methods here */
+};
+
+static const dbus_interface_u dbus_interface = {
+ .name = VIBRATOR_INTERFACE_HAPTIC,
+ .methods = hdbus_methods,
+ .nr_methods = ARRAY_SIZE(hdbus_methods),
+};
+
+int haptic_probe(void)
+{
+ /**
+ * load haptic module.
+ * if there is no haptic module,
+ * feedbackd does not activate a haptic interface.
+ */
+ return haptic_module_load();
+}
+
+static guint id_sig_pwr_off_state;
+
+void haptic_init(void)
+{
+ int r;
+
+ /* get haptic data from configuration file */
+ r = config_parse(HAPTIC_CONF_PATH, haptic_load_config, &haptic_conf);
+ if (r < 0) {
+ _E("Failed to load configuration file(%s): %d", HAPTIC_CONF_PATH, r);
+ safe_free(haptic_conf.level_arr);
+ }
+
+ /* init dbus interface */
+ r = dbus_handle_register_dbus_object(NULL, VIBRATOR_PATH_HAPTIC, &dbus_interface);
+ if (r < 0)
+ _E("Failed to init hdbus interface and method: %d", r);
+
+ id_sig_pwr_off_state = subscribe_dbus_signal(NULL,
+ DEVICED_PATH_POWEROFF,
+ DEVICED_INTERFACE_POWEROFF,
+ SIGNAL_POWEROFF_STATE,
+ haptic_poweroff_cb,
+ NULL,
+ NULL);
+ if (id_sig_pwr_off_state <= 0) {
+ _E("Failed to register signal handler: %d", r);
+ return;
+ }
+
+ dbus_handle_emit_dbus_signal(NULL,
+ VIBRATOR_PATH_HAPTIC,
+ VIBRATOR_INTERFACE_HAPTIC,
+ SIGNAL_VIBRATOR_INITIATED,
+ NULL);
+
+ /* add watch for sound capturing value */
+ if (haptic_conf.sound_capture) {
+ r = vconf_notify_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb, NULL);
+ if (r != 0)
+ _W("Add watch for VCONFKEY_RECORDER_STATE failed.");
+ }
+
+ /* Initialize vibration_handle (Use vibration now) */
+ cur_h_data.handle = INVALID_HANDLE;
+ cur_h_data.priority = PRIORITY_MIN;
+}
+
+void haptic_exit(void)
+{
+ int r;
+
+ /* remove watch */
+ if (haptic_conf.sound_capture) {
+ r = vconf_ignore_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb);
+ if (r != 0)
+ _W("Remove watch for VCONFKEY_RECORDER_STATE failed.");
+ }
+
+ /* unregister notifier for below each event */
+ unsubscribe_dbus_signal(NULL, id_sig_pwr_off_state);
+
+ /* release haptic data memory */
+ safe_free(haptic_conf.level_arr);
+
+ /* haptic exit for feedbackd */
+ hal_device_haptic_close_device(g_handle);
+ hal_device_haptic_put_backend();
+}
+
+static int haptic_start(void)
+{
+ _I("Start");
+ haptic_disabled = false;
+ return 0;
+}
+
+static int haptic_stop(void)
+{
+ _I("Stop");
+ haptic_disabled = true;
+ return 0;
+}
--- /dev/null
+/*
+ * feedbackd
+ *
+ * Copyright (c) 2012 - 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.
+ */
+
+
+#ifndef __FEEDBACKD_HAPTIC_H__
+#define __FEEDBACKD_HAPTIC_H__
+
+#include <stdbool.h>
+#include <glib.h>
+#include <device/power.h>
+#include "shared/common.h"
+
+enum priority_level {
+ PRIORITY_MIN = 0,
+ PRIORITY_MIDDLE,
+ PRIORITY_HIGH,
+ PRIORITY_TOP,
+};
+
+struct haptic_data {
+ GList *vibration_data;
+ unsigned int handle;
+ int level;
+ int priority;
+ bool stop;
+ int unlimit;
+};
+
+#define INVALID_HANDLE 0
+
+int haptic_probe(void);
+void haptic_init(void);
+void haptic_exit(void);
+
+#endif /* __FEEDBACKD_HAPTIC_H__ */
#include "shared/log.h"
#include "shared/common.h"
-#include "driver/haptic.h"
+#include "haptic.h"
#define VIBRATION_FEATURE "http://tizen.org/feature/feedback.vibration"
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2012 - 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 <stdio.h>
-#include <errno.h>
-#include <libsyscommon/list.h>
-
-#include "shared/common.h"
-#include "shared/log.h"
-#include "haptic-dev.h"
-
-static GList *handle_list;
-static int unique_number = 0;
-
-/* START: Haptic Module APIs */
-static int get_device_count(int *count)
-{
- if (count)
- *count = 1;
-
- return 0;
-}
-
-static int open_device(int device_index, int *device_handle)
-{
- GList *elem;
- int handle;
- bool found = false;
-
- if (unique_number == INT_MAX)
- unique_number = 0;
-
- while (found != true) {
- ++unique_number;
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)unique_number);
- if (!elem)
- found = true;
- }
- handle = unique_number;
- SYS_G_LIST_APPEND(handle_list, (gpointer)(long)handle);
-
- if (device_handle)
- *device_handle = handle;
-
- return 0;
-}
-
-static int close_device(int device_handle)
-{
- SYS_G_LIST_REMOVE(handle_list, (gpointer)(long)device_handle);
-
- return 0;
-}
-
-static int vibrate_monotone(int device_handle, int duration, int frequency, int overdrive, int level, int intensity, int priority)
-{
- GList *elem;
-
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)device_handle);
- if (!elem)
- return -EINVAL;
-
- return 0;
-}
-
-static int stop_device(int device_handle)
-{
- GList *elem;
-
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)device_handle);
- if (!elem)
- return -EINVAL;
-
- return 0;
-}
-/* END: Haptic Module APIs */
-
-static const struct haptic_plugin_ops default_plugin = {
- .get_device_count = get_device_count,
- .open_device = open_device,
- .close_device = close_device,
- .vibrate_monotone = vibrate_monotone,
- .stop_device = stop_device,
-};
-
-static bool is_valid(void)
-{
- if (is_emulator()) {
- _I("Support emulator haptic device.");
- return true;
- }
-
- _E("Do not support emulator haptic device.");
- return false;
-}
-
-static const struct haptic_plugin_ops *load(void)
-{
- return &default_plugin;
-}
-
-static const struct haptic_ops emul_ops = {
- .is_valid = is_valid,
- .load = load,
-};
-
-EXPORT_GET_VAR_HAPTIC_OPS(&emul_ops)
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2012 - 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 <stdio.h>
-#include <stdbool.h>
-#include <dlfcn.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "shared/log.h"
-#include "haptic.h"
-
-#define HAPTIC_MODULE_PATH "/usr/lib/libhaptic-module.so"
-
-/* Haptic Plugin Interface */
-static void *dlopen_handle;
-static const struct haptic_plugin_ops *plugin_intf;
-
-static bool is_valid(void)
-{
- struct stat buf;
- int ret;
- const struct haptic_plugin_ops *(*get_haptic_plugin_interface) () = NULL;
-
- ret = stat(HAPTIC_MODULE_PATH, &buf);
- if (ret < 0) {
- _E("Failed to stat file(%s): %d", HAPTIC_MODULE_PATH, errno);
- goto error;
- }
-
- dlopen_handle = dlopen(HAPTIC_MODULE_PATH, RTLD_NOW);
- if (!dlopen_handle) {
- _E("Failed to dlopen.");
- goto error;
- }
-
- get_haptic_plugin_interface = dlsym(dlopen_handle, "get_haptic_plugin_interface");
- if (!get_haptic_plugin_interface) {
- _E("Failed to dlsym.");
- goto error;
- }
-
- plugin_intf = get_haptic_plugin_interface();
- if (!plugin_intf) {
- _E("Failed to get_haptic_plugin_interface().");
- goto error;
- }
-
- _I("Support external haptic device.");
- return true;
-
-error:
- if (dlopen_handle) {
- dlclose(dlopen_handle);
- dlopen_handle = NULL;
- }
-
- _I("Do not support external haptic device.");
- return false;
-}
-
-static const struct haptic_plugin_ops *load(void)
-{
- return plugin_intf;
-}
-
-static void release(void)
-{
- if (dlopen_handle) {
- dlclose(dlopen_handle);
- dlopen_handle = NULL;
- }
-
- plugin_intf = NULL;
-}
-
-static const struct haptic_ops ext_ops = {
- .type = HAPTIC_EXTERNAL,
- .is_valid = is_valid,
- .load = load,
- .release = release,
-};
-
-HAPTIC_OPS_REGISTER(&ext_ops)
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2016 - 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 <stdlib.h>
-#include <glib.h>
-#include <libsyscommon/list.h>
-
-#include "shared/common.h"
-#include "shared/log.h"
-#include "haptic-interface.h"
-#include "peripheral_io.h"
-
-#define GPIO_I2C_BUS_INDEX 1
-#define MAX_HAPIC 1
-#define DRV2605L_DEFAULT_ADDR 0x5A
-
-#define START_CMD_CODE 1
-#define STOP_CMD_CODE 0
-
-#define DRV2605L_REGISTER_STATUS 0x00
-#define DRV2605L_REGISTER_MODE 0x01
-#define DRV2605L_REGISTER_RTPINPUT 0x02
-#define DRV2605L_REGISTER_LIBRARY 0x03
-#define DRV2605L_REGISTER_WAVESEQ1 0x04
-#define DRV2605L_REGISTER_WAVESEQ2 0x05
-#define DRV2605L_REGISTER_WAVESEQ3 0x06
-#define DRV2605L_REGISTER_WAVESEQ4 0x07
-#define DRV2605L_REGISTER_WAVESEQ5 0x08
-#define DRV2605L_REGISTER_WAVESEQ6 0x09
-#define DRV2605L_REGISTER_WAVESEQ7 0x0A
-#define DRV2605L_REGISTER_WAVESEQ8 0x0B
-#define DRV2605L_REGISTER_GO 0x0C
-
-/**
- * Mode register
- */
-#define MODE_INTERNAL_TRIGGER 0
-#define MODE_EXTERNAL_TRIGGER_EDGE 1
-#define MODE_EXTERNAL_TRIGGER_LEVEL 2
-#define MODE_PWM_INPUT_ANALOG_INPUT 3
-#define MODE_AUDIO_TO_VIBE 4
-#define MODE_REALTIME_PLAYBACK 5
-#define MODE_DIAGNOSTICS 6
-#define MODE_AUTO_CALIBRATION 7
-/**
- * Library register
- */
-#define EMPTY_LIBRARY 0
-#define TS2200_LIBRARY_A 1
-#define TS2200_LIBRARY_B 2
-#define TS2200_LIBRARY_C 3
-#define TS2200_LIBRARY_D 4
-#define TS2200_LIBRARY_E 5
-#define LRA_LIBRARY_E 6
-#define TS2200_LIBRARY_F 7
-
-#define MAX_LEVEL 2
-#define MAX_INTENSITY 10000
-
-static peripheral_i2c_h device_handle = NULL;
-
-static GList *handle_list;
-static int unique_number;
-
-static bool state = false;
-//static bool is_playing = false;
-static guint stop_timer = 0;
-
-static int gpio_haptic_stop_device(int handle);
-
-static bool find_from_list(int handle)
-{
- GList *elem;
-
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)handle);
- if (elem)
- return true;
-
- return false;
-}
-
-/* START: Haptic Module APIs */
-static gboolean gpio_haptic_timer_cb(void *data)
-{
- int handle = (int)(long)data;
- bool found;
-
- _I("Stop vibration by timer.");
-
- found = find_from_list(handle);
- if (!found)
- return G_SOURCE_REMOVE;
-
- if (device_handle == NULL) {
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- return -EIO;
- }
- }
-
- /* stop playing */
- peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
-
- stop_timer = 0;
- return G_SOURCE_REMOVE;
-}
-
-static int gpio_haptic_get_device_count(int *count)
-{
- _I("HAL: The max number of DRV2605L is %d.", (int)MAX_HAPIC);
- if (count)
- *count = MAX_HAPIC;
-
- return 0;
-}
-
-/**
- * Only one handle
- * return device_handle
- */
-static int gpio_haptic_open_device(int device_index, int *handle)
-{
- int n;
- bool found = false;
- GList *elem;
-
- if (!handle)
- return -EINVAL;
-
- /* if it is the first element */
- n = SYS_G_LIST_LENGTH(handle_list);
- if (n == 0) {
- _I("Peripheral Device Open.");
- if (device_handle == NULL) {
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- return -EIO;
- }
- }
- }
-
- if (unique_number == INT_MAX)
- unique_number = 0;
-
- while (found != true) {
- ++unique_number;
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)unique_number);
- if (!elem)
- found = true;
- }
-
- /* add info to local list */
- SYS_G_LIST_APPEND(handle_list, (gpointer)(long)unique_number);
-
- *handle = unique_number;
- return 0;
-}
-
-static int gpio_haptic_close_device(int handle)
-{
- int r, n;
- bool found;
-
- found = find_from_list(handle);
- if (!found)
- return -EINVAL;
-
- if (device_handle == NULL) {
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- return -EIO;
- }
- }
-
- /* stop vibration */
- r = gpio_haptic_stop_device(handle);
- if (r < 0)
- _I("Already stopped or failed to stop effect: %d", r);
-
- _D("Handle(%d) is closed and timer deleted.", handle);
- SYS_G_LIST_REMOVE(handle_list, (gpointer)(long)handle);
-
- /* if it is the last element */
- n = SYS_G_LIST_LENGTH(handle_list);
- if (n == 0) {
- _I("Peripheral Device Close.");
- if (device_handle != NULL) {
- if (peripheral_i2c_close(device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to close peripheral I2C.");
- return -EIO;
- }
- device_handle = NULL;
- }
- }
- return 0;
-}
-
-static int gpio_haptic_vibrate_monotone(int handle, int duration, int frequency, int overdrive, int level, int intensity, int priority)
-{
- bool found;
- int feedback;
- int max_level;
-
- if (level <= 0)
- return -EINVAL;
-
- found = find_from_list(handle);
- if (!found)
- return -EINVAL;
-
- if (device_handle == NULL) {
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- return -EIO;
- }
- }
-
- /* Zero(0) is the infinitely vibration value */
- if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
- duration = 0;
-
- if (stop_timer)
- gpio_haptic_stop_device(handle);
-
- max_level = (level <= MAX_LEVEL)? MAX_LEVEL: level;
- if (intensity)
- feedback = ((level/max_level) * intensity) / 100;
- else
- feedback = ((level/max_level) * MAX_INTENSITY) / 100;
-
- /* play vibration */
- peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_LIBRARY, TS2200_LIBRARY_A);
- /* continuously vibrate*/
- peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_REALTIME_PLAYBACK);
- peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_RTPINPUT, (uint8_t)feedback);
-
- /* register timer */
- if (duration) {
- //stop_timer = ecore_timer_add(duration/1000.f, gpio_haptic_timer_cb, (void *)(long)handle);
- stop_timer = g_timeout_add(duration, gpio_haptic_timer_cb, (void *)(long)handle);
- if (!stop_timer)
- _E("Failed to add timer callback.");
- }
- _D("Device handle(%d) %dms", handle, duration);
-
- return 0;
-}
-
-static int gpio_haptic_stop_device(int handle)
-{
- bool found;
-
- found = find_from_list(handle);
- if (!found)
- return -EINVAL;
-
- if (device_handle == NULL) {
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- return -EIO;
- }
- }
-
- /* stop playing */
- peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
-
- if (stop_timer) {
- //ecore_timer_del(stop_timer);
- g_source_remove(stop_timer);
- stop_timer = 0;
- }
-
- return 0;
-}
-/* END: Haptic Module APIs */
-
-static const struct haptic_plugin_ops default_plugin = {
- .get_device_count = gpio_haptic_get_device_count,
- .open_device = gpio_haptic_open_device,
- .close_device = gpio_haptic_close_device,
- .vibrate_monotone = gpio_haptic_vibrate_monotone,
- .stop_device = gpio_haptic_stop_device,
-};
-
-static bool is_valid(void)
-{
- uint8_t result;
- peripheral_i2c_h handle;
-
- if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to open I2C.");
- state = false;
- return false;
- }
- if (peripheral_i2c_read_register_byte(handle, DRV2605L_REGISTER_STATUS, &result) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to read peripheral I2C.");
- if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE)
- _E("Failed to close peripheral I2C.");
- state = false;
- return false;
- }
- if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE) {
- _E("Failed to close peripheral I2C.");
- state = false;
- return false;
- }
-
- state = true;
- _I("Support gpio haptic device.");
- return true;
-}
-
-static const struct haptic_plugin_ops *load(void)
-{
- _I("Gpio haptic device module loaded.");
- return &default_plugin;
-}
-
-static const struct haptic_ops gpio_haptic_ops = {
- .is_valid = is_valid,
- .load = load,
-};
-
-EXPORT_GET_VAR_HAPTIC_OPS(&gpio_haptic_ops)
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2020 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
- *
- * Unlessnn 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 <stdio.h>
-#include <stdbool.h>
-#include <dlfcn.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "shared/log.h"
-#include "haptic.h"
-#include "haptic-dev.h"
-
-#ifndef LIBPATH
-#error LIBPATH is not defined.
-#endif
-#define HAPTIC_MODULE_PATH LIBPATH"/feedbackd/haptic.so"
-
-#define CHECK_NO_DEVICE(dev) \
- do { \
- if (!dev) \
- return -ENODEV; \
- }while(0) \
-
-/* Haptic Plugin Interface */
-static void *haptic_handle;
-static const struct haptic_plugin_ops *plugin_ops;
-static const struct haptic_ops *haptic_ops;
-static const struct haptic_ops* (*fp_get_var_haptic_ops)(void);
-
-int haptic_load_device(void)
-{
- struct stat buf;
- int ret;
-
- ret = stat(HAPTIC_MODULE_PATH, &buf);
- if (ret < 0) {
- _E("Failed to stat file(%s): %d", HAPTIC_MODULE_PATH, errno);
- goto error;
- }
-
- haptic_handle = dlopen(HAPTIC_MODULE_PATH, RTLD_NOW);
- if (!haptic_handle) {
- _E("Failed to open file(%s): %s.", HAPTIC_MODULE_PATH, dlerror());
- goto error;
- }
-
- fp_get_var_haptic_ops = dlsym(haptic_handle, "get_var_haptic_ops");
- if (!fp_get_var_haptic_ops) {
- _E("Failed to get \'get_var_haptic_ops\' function.");
- goto error;
- }
-
- haptic_ops = fp_get_var_haptic_ops();
- if (!haptic_ops) {
- _E("Failed to call get_var_haptic_ops");
- goto error;
- }
-
- if (haptic_ops->is_valid && haptic_ops->is_valid()) {
- if (haptic_ops->load)
- plugin_ops = haptic_ops->load();
- }
-
- if (!plugin_ops) {
- _E("Failed to load haptic device.");
- goto error;
- }
-
- return 0;
-
-error:
- if (haptic_handle) {
- dlclose(haptic_handle);
- haptic_handle = NULL;
- haptic_ops = NULL;
- }
-
- return -ENODEV;
-}
-
-void haptic_release_device()
-{
- if (haptic_ops) {
- if (haptic_ops->is_valid && haptic_ops->is_valid()) {
- if (haptic_ops->release)
- haptic_ops->release();
- }
- }
-
- if (haptic_handle)
- dlclose(haptic_handle);
-
- haptic_handle = NULL;
- haptic_ops = NULL;
- plugin_ops = NULL;
-}
-
-int haptic_open_device(int *dev_handle)
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- if (!dev_handle)
- return -EINVAL;
-
- return plugin_ops->open_device(HAPTIC_MODULE_DEVICE_ALL, dev_handle);
-}
-
-int haptic_close_device(int dev_handle)
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- return plugin_ops->close_device(dev_handle);
-}
-
-int haptic_check_device()
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- return 0;
-}
-
-int haptic_vibrate_device(int device_handle, int duration, int frequency,
- int overdrive, int level, int intensity, int priority)
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- return plugin_ops->vibrate_monotone(device_handle, duration, frequency, overdrive,
- level, intensity, priority);
-
-}
-
-int haptic_get_count_device(int *count)
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- if (!count)
- return -EINVAL;
-
- return plugin_ops->get_device_count(count);
-}
-
-int haptic_stop_device(int handle)
-{
- CHECK_NO_DEVICE(plugin_ops);
-
- return plugin_ops->stop_device(handle);
-}
-
+++ /dev/null
-/*
- * feedbackd
- *
-i * Copyright (c) 2012 - 2020 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 __FEEDBACKD_HAPTIC_DEV_H__
-#define __FEEDBACKD_HAPTIC_DEV_H__
-
-#include <stdbool.h>
-#include "haptic-interface.h"
-
-int haptic_load_device(void);
-void haptic_release_device();
-int haptic_open_device(int *dev_handle);
-int haptic_check_device();
-int haptic_close_device(int dev_handle);
-
-int haptic_vibrate_device(int device_handle, int duration, int frequency, int overdrive, int level, int intensity, int priority);
-
-int haptic_get_count_device(int *count);
-int haptic_stop_device(int handle);
-
-#endif /* __FEEDBACKD_HAPTIC_DEV_H__ */
+++ /dev/null
-/*
- * deviced
- *
- * Copyright (c) 2012 - 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.
- */
-
-
-#ifndef __FEEDBACKD_HAPTIC_INTERFACE_H__
-#define __FEEDBACKD_HAPTIC_INTERFACE_H__
-
-#include <stdio.h>
-
-enum haptic_type {
- HAPTIC_STANDARD,
- HAPTIC_EXTERNAL,
-};
-
-/**
- * @brief Enumerations of device id for the Haptic Module API.
- * @details We support two motors now.
- */
-typedef enum {
- HAPTIC_MODULE_DEVICE_0 = 0x0, /**< 1st motor */
- HAPTIC_MODULE_DEVICE_1 = 0x1, /**< 2nd motor */
- HAPTIC_MODULE_DEVICE_ALL = 0x4, /**< both of them */
-} haptic_module_device;
-
-/**
- * @brief Enumerations of unlimited duration for the Haptic Module API.
- */
-typedef enum {
- HAPTIC_MODULE_DURATION_UNLIMITED = 0x7FFFFFFF,
-} haptic_module_duration;
-
-struct haptic_ops {
- enum haptic_type type;
- bool (*is_valid)(void);
- const struct haptic_plugin_ops *(*load)(void);
- void (*release)(void);
-};
-
-struct haptic_plugin_ops {
- int (*get_device_count) (int*);
- int (*open_device) (int, int*);
- int (*close_device) (int);
- int (*vibrate_monotone) (int, int, int, int, int, int, int);
- int (*stop_device) (int);
-};
-
-#define EXPORT_GET_VAR_HAPTIC_OPS(ops) \
-const struct haptic_ops __attribute__((visibility("default")))* get_var_haptic_ops(void) \
-{ \
- return ops; \
-} \
-
-const struct haptic_ops *get_var_haptic_ops();
-#endif /* __FEEDBACKD_HAPTIC_INTERFACE_H__ */
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2012 - 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 <stdio.h>
-#include <stdbool.h>
-#include <dlfcn.h>
-#include <assert.h>
-#include <vconf.h>
-#include <time.h>
-#include <string.h>
-#include <libsyscommon/dbus-system.h>
-#include <libsyscommon/list.h>
-#include <libsyscommon/ini-parser.h>
-
-#include "shared/log.h"
-#include "shared/common.h"
-#include "shared/device-idler.h"
-#include "haptic.h"
-#include "haptic-dev.h"
-
-#define FEEDBACK_BASE_PATH "/usr/share/feedback/"
-#define STANDARD_FILE_PATH FEEDBACK_BASE_PATH"vibration/"
-#define VIBRATION_CONF_PATH FEEDBACK_BASE_PATH"vibration.conf"
-
-#define HAPTIC_CONF_PATH "/etc/feedbackd/haptic.conf"
-#define SIGNAL_POWEROFF_STATE "ChangeState"
-#define SIGNAL_VIBRATOR_INITIATED "InitiateVibrator"
-
-/* hardkey vibration variable */
-#define HARDKEY_VIB_ITERATION 1
-#define HARDKEY_VIB_FEEDBACK 3
-#define HARDKEY_VIB_DURATION 30
-#define HAPTIC_FEEDBACK_STEP 20
-#define DEFAULT_FEEDBACK_LEVEL 3
-#define HIGH_FEEDBACK_LEVEL 100
-#define LOW_FEEDBACK_LEVEL 0
-
-/* power on, power off vibration variable */
-#define POWER_ON_VIB_DURATION 300
-#define POWER_OFF_VIB_DURATION 300
-#define POWER_VIB_FEEDBACK 100
-
-#define MAX_EFFECT_BUFFER (64*1024)
-
-#ifndef VCONFKEY_RECORDER_STATE
-#define VCONFKEY_RECORDER_STATE "memory/recorder/state"
-#define VCONFKEY_RECORDER_STATE_RECORDING 2
-#endif
-
-#define RETRY_CNT 3
-
-#define INTENSITY_BASE_RATE (10000)
-#define VALUE_MAX_LEN 10
-#define VIB_LOCK_TIMEOUT_MAX (300000) /* 5minutes */
-
-/*
- 1,A_W or A,A_W or 250D250W250D750W
-
- 85,10000,
- 90,0,
- 105,10000,
- 0,end
-*/
-struct vibration_config {
- char *pattern; /* pattern name */
- char *standard; /* assigned standard pattern name */
- GList *data; /* duration_data list */
- unsigned int pattern_duration;
- int unlimit;
-};
-
-struct duration_data {
- int duration;
- int intensity;
- int frequency;
- int overdrive;
- int wait;
-};
-
-enum poweroff_type {
- POWER_OFF_NONE = 0,
- POWER_OFF_POPUP,
- POWER_OFF_DIRECT,
- POWER_OFF_RESTART,
-};
-
-struct haptic_info {
- char *sender;
- GList *handle_list;
- guint id_watch;
-};
-
-struct vibrate_pattern_info {
- unsigned int handle;
- char *pattern;
- int level;
- int priority;
-};
-
-struct vibrate_monotone_info {
- unsigned int handle;
- int duration;
- int level;
- int intensity;
- int priority;
-};
-
-/* for playing */
-static int g_handle;
-
-/* pattern configuration list */
-static GList *vib_conf_list;
-
-static guint duration_timer;
-
-/* haptic operation variable */
-static GList *haptic_handle_list;
-
-static bool haptic_disabled;
-
-struct haptic_config {
- int level;
- int *level_arr;
- int sound_capture;
-};
-
-static struct haptic_config haptic_conf;
-
-static int haptic_start(void);
-static int haptic_stop(void);
-static int remove_haptic_info(struct haptic_info *info);
-
-struct haptic_data cur_h_data;
-
-static int insert_conf_data(GList **conf_data, struct duration_data *update)
-{
- struct duration_data *data;
-
- data = (struct duration_data *)calloc(1, sizeof(struct duration_data));
- if (!data) {
- _E("Not enough memory.");
- return -ENOMEM;
- }
- memcpy(data, update, sizeof(struct duration_data));
- /* insert vibration pattern data */
- // to debug :
- // _D("%dD%dI%dF%dO%dW", data->duration, data->intensity, data->frequency, data->overdrive, data->wait);
- SYS_G_LIST_APPEND(*conf_data, data);
- return 0;
-}
-
-static void get_pattern_property(char **iter, char property, int *value)
-{
- char *check;
- unsigned long int val;
-
- check = strchr(*iter, property);
- if (!check)
- return;
-
- *check = '\0';
- val = strtoul(*iter, NULL, 10);
- if (errno == EINVAL || errno == ERANGE) {
- val = 0;
- _E("Failed to get value of %s: %d", *iter, errno);
- }
- if (val > VIB_LOCK_TIMEOUT_MAX)
- val = VIB_LOCK_TIMEOUT_MAX;
-
- *value = (int)val;
-
- *iter = check + 1;
-}
-
-/* [A]xxxDxxxIxxxFxxxOxxxW format */
-static int insert_raw_data_format(GList **conf_data, char *value)
-{
- struct duration_data update = {0, };
- char *iter;
- char *end;
- int pattern_duration = 0;
-
- if (!value)
- return insert_conf_data(conf_data, &update);
- if (!conf_data) {
- _E("Invalid parameter: Configuration list is null");
- return -EINVAL;
- }
-
- iter = value;
- end = iter + strlen(iter);
- while (iter < end) {
- memset(&update, 0, sizeof(struct duration_data));
-
- get_pattern_property(&iter, 'D', &update.duration);
- get_pattern_property(&iter, 'I', &update.intensity);
- if (update.intensity > INTENSITY_BASE_RATE)
- update.intensity = INTENSITY_BASE_RATE;
- get_pattern_property(&iter, 'F', &update.frequency);
- get_pattern_property(&iter, 'W', &update.wait);
-
- if (update.duration == 0 && update.wait == 0) {
- _D("Pattern duration is zero.");
- break;
- }
-
- pattern_duration += (update.duration + update.wait);
- if (pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
- _D("Max pattern duration.");
- pattern_duration = VIB_LOCK_TIMEOUT_MAX;
- }
-
- if (insert_conf_data(conf_data, &update) < 0)
- return -EINVAL;
- }
-
- return pattern_duration;
-}
-
-static int get_config_data(int count, bool *packed, char *val, unsigned int *pattern_duration, struct duration_data *update)
-{
- static int duration = 0;
- static int intensity = 0;
- int value;
- int ret;
-
- if (count > 4 || count <= 0) {
- _E("Invalid parameter: count is invalid");
- return -EINVAL;
- }
-
- if (!packed || !val || !pattern_duration || !update) {
- _E("Invalid parameter: %p %p %p %p", packed, val, pattern_duration, update);
- return -EINVAL;
- }
-
- get_pattern_property(&val, 'C', &value);
-
- ret = count;
- switch (count) {
- case 1: /* D */
- duration = value;
- *pattern_duration += duration;
- if (*pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
- _D("Max pattern duration.");
- *pattern_duration = VIB_LOCK_TIMEOUT_MAX;
- }
- break;
- case 2: /* I or W */
- if (value > INTENSITY_BASE_RATE)
- value = INTENSITY_BASE_RATE;
- intensity = value;
- if (*packed == false) {
- update->duration = duration;
- update->intensity = intensity;
- break;
- }
- /* if intensity is 0, duration use for wait(off) time */
- if (intensity == 0)
- update->wait = duration;
- else
- update->wait = 0;
- *packed = false;
- duration = 0;
- intensity = 0;
- ret = -1;
- break;
- case 3: /* F */
- if (intensity != 0)
- update->frequency = value;
- break;
- case 4: /* O */
- if (intensity != 0) {
- update->overdrive = value;
- *packed = true;
- }
- ret = 0;
- break;
- default:
- break;
- }
- return ret;
-}
-
-/*
- duration, intensity, frequency, overdrive
- waiting duration, intensity=0, frequency, overdrive
- 85,10000,
- 90,0,
- 105,10000,
- 0,end
-*/
-static int load_standard_format(const char *pattern)
-{
- struct duration_data update = {0, };
- bool packed = false;
- struct vibration_config *conf;
- int ret = 0, count = 0, end = 2;
- int index = 0;
- int fd;
- char path[PATH_MAX], elem, val[VALUE_MAX_LEN] = {0, };
-
- snprintf(path, sizeof(path), STANDARD_FILE_PATH"%s", pattern);
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return -ENOENT;
-
- conf = (struct vibration_config *)calloc(1, sizeof(struct vibration_config));
- if (!conf) {
- _E("Failed to alloc.");
- ret = -errno;
- goto error_out;
- }
-
- conf->pattern = strdup(pattern);
- if (!conf->pattern) {
- _E("Failed to copy pattern data(%s).", pattern);
- ret = -errno;
- goto error_out;
- }
-
- /* make feedback pattern(xDxIxFxOxW) format from d,i,f,o, */
- while (read(fd, &elem, 1) != 0) {
- if (end == 0) {
- if (insert_conf_data(&conf->data, &update) < 0)
- goto error_out;
- break;
- }
- if (elem == 'e' || elem == 'n' || elem == 'd') {
- end--;
- continue;
- }
- if (elem == '\n') {
- count = 0;
- continue;
- }
- if (elem == ',') {
- count++;
- val[index] = 'C';
- index = 0;
-
- ret = get_config_data(count, &packed, val, &(conf->pattern_duration), &update);
- if (ret < 0) {
- if (ret == -EINVAL)
- break;
- if (insert_conf_data(&conf->data, &update) < 0)
- goto error_out;
- memset(&update, 0, sizeof(struct duration_data));
- } else
- count = ret;
- } else {
- if (index < (VALUE_MAX_LEN - 2)) /* Temporal limit */
- val[index++] = elem;
- else
- _E("Pattern(%s) is out of bound: %s", pattern, val);
- }
- }
- close(fd);
- SYS_G_LIST_APPEND(vib_conf_list, conf);
- return ret;
-
-error_out:
- if (fd >= 0)
- close(fd);
- if (conf) {
- if (conf->pattern)
- free(conf->pattern);
- free(conf);
- }
- return -ENOENT;
-}
-
-static int vibration_load_config(struct parse_result *result, void *user_data)
-{
- struct vibration_config *conf;
- char *value;
- char *check;
- int len;
- int duration;
-
- if (!result)
- return 0;
-
- if (!MATCH(result->section, "Vibration"))
- return 0;
-
-
- if (!result->name || !result->value)
- return 0;
-
- conf = (struct vibration_config *)calloc(1, sizeof(struct vibration_config));
- if (!conf) {
- _E("Failed to alloc.");
- return -ENOMEM;
- }
-
- conf->pattern_duration = 0;
- conf->pattern = strdup(result->name);
- if (!conf->pattern) {
- _E("Failed to copy pattern data(%s).", result->name);
- goto error_out;
- }
-
- value = result->value;
- len = strlen(value);
-
- if (len == 0) {
- if (insert_raw_data_format(&conf->data, NULL) < 0)
- goto error_out;
- SYS_G_LIST_APPEND(vib_conf_list, conf);
- return 0;
- }
-
- /* Load Standard Pattern Name */
- /* value: 1,A_W or A,A_W */
- if ((check = strchr(value, ','))) {
- *check = '\0';
- if (strncmp(value, "A", 1) == 0)
- conf->unlimit = 1;
- value = check + 1;
- conf->standard = strdup(value);
- if (!conf->standard) {
- _E("Failed to copy standard name.");
- goto error_out;
- }
- SYS_G_LIST_APPEND(vib_conf_list, conf);
- return 0;
- }
-
- /* value : A100D or 100D0W or 250D250W250D750W */
- /* Load Vibration Pattern Data */
- check = strchr(value, 'A');
- if (check) {
- *check = '\0';
- conf->unlimit = 1;
- if (!value)
- len = len - 1;
- else
- len = len - strlen(value) - 1;
- value = check + 1;
- }
- duration = insert_raw_data_format(&conf->data, value);
- if (duration < 0) {
- conf->pattern_duration = 0;
- goto error_out;
- } else
- conf->pattern_duration = duration;
- SYS_G_LIST_APPEND(vib_conf_list, conf);
-
- return 0;
-
-error_out:
- if (conf) {
- if (conf->pattern)
- free(conf->pattern);
- if (conf->standard)
- free(conf->standard);
- }
- return -ENOMEM;
-}
-
-static void load_standard_vibration_patterns(void)
-{
- DIR *dir;
- struct dirent *dent;
- int ret;
-
- dir = opendir(STANDARD_FILE_PATH);
- if (!dir) {
- _E("Failed to load '%s' Use default value.", STANDARD_FILE_PATH);
- return;
- }
- while ((dent = readdir(dir))) {
- if (dent->d_type == DT_DIR)
- continue;
- ret = load_standard_format(dent->d_name);
- if (ret < 0)
- _E("Failed to parse %s: %d", dent->d_name, ret);
- }
- closedir(dir);
- _D("Success to load '%s'", STANDARD_FILE_PATH);
-}
-
-void pattern_config_parse(void)
-{
- int ret;
-
- ret = config_parse(VIBRATION_CONF_PATH, vibration_load_config, NULL);
- if (ret < 0)
- _E("Failed to load '%s'. Use default value: %d", VIBRATION_CONF_PATH, ret);
-
- load_standard_vibration_patterns();
-}
-
-static int haptic_module_load(void)
-{
- int r;
-
- pattern_config_parse();
-
- r = haptic_load_device();
- if (r < 0) {
- _E("Failed to load device. ret=%d", r);
- return r;
- }
-
- /* solution bug
- * we do not use internal vibration except power off.
- * if the last handle is closed during the playing of vibration,
- * solution makes unlimited vibration.
- * so we need at least one handle. */
- r = haptic_open_device(&g_handle);
- if (r < 0) {
- _E("Failed to open device. ret=%d", r);
- return r;
- }
-
- return 0;
-}
-
-/*
-static int convert_magnitude_by_conf(int level)
-{
- int i, step;
-
- if (level < LOW_FEEDBACK_LEVEL)
- level = LOW_FEEDBACK_LEVEL;
- else if (level > HIGH_FEEDBACK_LEVEL)
- level = HIGH_FEEDBACK_LEVEL;
-
- step = 100 / (haptic_conf.level-1);
- for (i = 0; i < haptic_conf.level; ++i) {
- if (level <= i*step) {
- _D("Level changed. %d -> %d", level, haptic_conf.level_arr[i]);
- return haptic_conf.level_arr[i];
- }
- }
-
- _D("Play default level.");
- return DEFAULT_FEEDBACK_LEVEL * HAPTIC_FEEDBACK_STEP;
-}
-*/
-GVariant *hdbus_get_count(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- int ret, val;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- ret = haptic_get_count_device(&val);
- if (ret >= 0)
- ret = val;
-
-exit:
- return g_variant_new("(i)", ret);
-}
-
-void haptic_name_owner_changed(GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
-{
- GList *n;
- struct haptic_info *info = user_data;
- int handle;
-
- _I("%s (sender=%s)", __func__, name);
-
- if (!info)
- return;
-
- for (n = info->handle_list; n; n = n->next) {
- handle = (int)(long)n->data;
- haptic_stop_device(handle);
- haptic_close_device(handle);
- }
-
- remove_haptic_info(info);
-}
-
-static struct haptic_info *add_haptic_info(const char *sender)
-{
- struct haptic_info *info;
-
- assert(sender);
-
- info = calloc(1, sizeof(struct haptic_info));
- if (!info)
- return NULL;
-
- info->sender = strdup(sender);
- if (!info->sender) {
- free(info);
- return NULL;
- }
-
- SYS_G_LIST_APPEND(haptic_handle_list, info);
-
- info->id_watch = dbus_handle_watch_name(sender, NULL, haptic_name_owner_changed, info, NULL);
-
- return info;
-}
-
-static int remove_haptic_info(struct haptic_info *info)
-{
- assert(info);
-
- dbus_handle_unwatch_name(info->id_watch);
-
- SYS_G_LIST_REMOVE(haptic_handle_list, info);
- SYS_G_LIST_FREE_LIST(info->handle_list);
- if (info->sender) {
- free(info->sender);
- }
- free(info);
-
- return 0;
-}
-
-static struct haptic_info *get_matched_haptic_info(const char *sender)
-{
- GList *n;
- struct haptic_info *info;
- int len;
-
- assert(sender);
-
- len = strlen(sender) + 1;
- SYS_G_LIST_FOREACH(haptic_handle_list, n, info) {
- if (!strncmp(info->sender, sender, len))
- return info;
- }
-
- return NULL;
-}
-
-GVariant *hdbus_open_device(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- int index, handle, ret;
- struct haptic_info *info;
-
- /* Load haptic module before booting done */
- if (haptic_check_device() < 0) {
- ret = haptic_module_load();
- if (ret < 0)
- goto exit;
- }
-
- g_variant_get(param, "(i)", &index);
-
- ret = haptic_open_device(&handle);
- if (ret < 0)
- goto exit;
-
- if (!sender) {
- ret = -EPERM;
- haptic_close_device(handle);
- goto exit;
- }
-
- info = get_matched_haptic_info(sender);
- if (!info) {
- info = add_haptic_info(sender);
- if (!info) {
- _E("Failed to create haptic information.");
- ret = -EPERM;
- haptic_close_device(handle);
- goto exit;
- }
- }
-
- SYS_G_LIST_APPEND(info->handle_list, (gpointer)(long)handle);
-
- ret = handle;
-
-exit:
- return g_variant_new("(i)", ret);
-}
-
-int clear_current_data(void)
-{
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
-
- if (duration_timer) {
- _I("Remove duration_timer.");
- g_source_remove(duration_timer);
- duration_timer = 0;
- }
-
- return 0;
-}
-
-GVariant *hdbus_close_device(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- unsigned int handle;
- int ret;
- struct haptic_info *info;
- int cnt;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- g_variant_get(param, "(u)", &handle);
-
- if (!sender) {
- _E("Failed to get sender from dbus message.");
- ret = -EPERM;
- goto exit;
- }
-
- ret = haptic_close_device(handle);
- if (ret < 0)
- goto exit;
-
- if (cur_h_data.handle == handle) {
- /* Remove duration_timer for vibrate_effect */
- clear_current_data();
- }
-
- info = get_matched_haptic_info(sender);
- if (!info) {
- _E("Failed to find the matched haptic info.");
- goto exit;
- }
-
- SYS_G_LIST_REMOVE(info->handle_list, (gpointer)(long)handle);
- cnt = SYS_G_LIST_LENGTH(info->handle_list);
- if (cnt == 0)
- remove_haptic_info(info);
-
-exit:
- return g_variant_new("(i)", ret);
-}
-
-static gboolean _cb(void *data)
-{
- if (duration_timer) {
- g_source_remove(duration_timer);
- duration_timer = 0;
- }
-
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
-
- return G_SOURCE_REMOVE;
-}
-
-static void vibrate_monotone_idler_cb(void *data)
-{
- struct vibrate_monotone_info *vibrate_info;
- int ret;
-
- if (!data)
- return;
-
- vibrate_info = (struct vibrate_monotone_info *)data;
-
- if (vibrate_info->priority < cur_h_data.priority) {
- _I("Handle(%d) skip low priority. pre=%d now=%d", vibrate_info->handle, cur_h_data.priority, vibrate_info->priority);
- free(vibrate_info);
- return;
- }
-
- if (duration_timer) {
- g_source_remove(duration_timer);
- duration_timer = 0;
- }
-
- cur_h_data.vibration_data = NULL;
- cur_h_data.handle = vibrate_info->handle;
- cur_h_data.level = vibrate_info->level;
- cur_h_data.priority = vibrate_info->priority;
- cur_h_data.stop = false;
- cur_h_data.unlimit = false;
-
- ret = device_power_request_lock(POWER_LOCK_CPU, vibrate_info->duration);
- if (ret != DEVICE_ERROR_NONE)
- _E("Failed to request power lock.");
-
- _D("Handle(%d) play=%dms, level=%d, intensity=%d, frequency=0)",
- cur_h_data.handle, vibrate_info->duration, cur_h_data.level,
- vibrate_info->intensity);
-
- duration_timer = g_timeout_add(vibrate_info->duration, _cb, NULL);
- haptic_vibrate_device(cur_h_data.handle, vibrate_info->duration, 0, 0, cur_h_data.level, vibrate_info->intensity, cur_h_data.priority);
-
- free(vibrate_info);
-}
-
-GVariant *hdbus_vibrate_monotone(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- struct vibrate_monotone_info *vibrate_info;
- unsigned int handle;
- int duration, level, intensity, priority, ret = 0;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- if (haptic_disabled)
- goto exit;
-
- g_variant_get(param, "(uiii)", &handle, &duration, &intensity, &priority);
- _D("param (uiii): handle=%u, duration=%d, intensity=%d, priority=%d", handle, duration, intensity, priority);
-
- if (intensity < 0) {
- ret = -EINVAL;
- goto exit;
- }
-
- if (priority < PRIORITY_MIN)
- priority = PRIORITY_MIN;
- else if (priority > PRIORITY_TOP)
- priority = PRIORITY_TOP;
-
- if (duration <= 0) {
- _E("Skip vibrate handle(%d) requested less than 0.", handle);
- ret = -EINVAL;
- goto exit;
- }
-
- if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &level) < 0) {
- _E("Failed to get '"VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT"' value.");
- ret = -EINVAL;
- goto exit;
- }
-
- vibrate_info = calloc(1, sizeof(struct vibrate_monotone_info));
- if (!vibrate_info) {
- _E("Failed to allocate memory for vibrate_info.");
- ret = -errno;
- goto exit;
- }
-
- vibrate_info->handle = handle;
- vibrate_info->duration = duration;
- vibrate_info->level = (level/2) + 1;
- vibrate_info->intensity = intensity * 100; // 1~100 (API spec)
- vibrate_info->priority = priority;
-
- ret = add_idle_request(vibrate_monotone_idler_cb, (void *)vibrate_info);
-exit:
- return g_variant_new("(i)", ret);
-}
-
-static gboolean haptic_duration_play(void *data)
-{
- GList *head, *n, *next;
- struct duration_data *node;
- int ret = 0;
-
- if (duration_timer) {
- g_source_remove(duration_timer);
- duration_timer = 0;
- }
-
- if (!data) {
- if (cur_h_data.unlimit) /* In case of unlimit pattern, do not stop */
- head = cur_h_data.vibration_data;
- else {
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
- goto out;
- }
- } else
- head = (GList *)data;
-
- if (cur_h_data.stop) {
- _I("Stop currunt vibration.");
- cur_h_data.stop = false;
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
- goto out;
- }
-
- SYS_G_LIST_FOREACH_SAFE(head, n, next, node) {
- _I("Handle(%d) play=%dms and Wait=%dms %s type. (level=%d, intensity=%d, frequency=%d)",
- cur_h_data.handle, node->duration, node->wait,
- cur_h_data.unlimit ? "Unlimit" : "Once", cur_h_data.level, node->intensity, node->frequency);
- if ((node->duration + node->wait) <= 0) {
- if (!cur_h_data.unlimit) {
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
- break;
- } else {
- next = cur_h_data.vibration_data;
- continue;
- }
- }
-
- duration_timer = g_timeout_add((node->duration + node->wait), haptic_duration_play, (void *)next);
-
- ret = haptic_vibrate_device(cur_h_data.handle, node->duration, node->frequency, node->overdrive, cur_h_data.level, node->intensity, cur_h_data.priority);
-
- break;
- }
- if (ret != 0) {
- _D("Auto stop vibration.");
- cur_h_data.stop = true;
- }
-out:
- return G_SOURCE_REMOVE;
-}
-
-static void vibrate_pattern_idler_cb(void *data)
-{
- struct vibrate_pattern_info *vibrate_info;
- GList *elem;
- struct vibration_config *conf;
- char pattern[PATH_MAX];
- int ret;
- int unlimit = 0;
-
- if (!data)
- return;
-
- vibrate_info = (struct vibrate_pattern_info *)data;
-
- if (!(vibrate_info->pattern)) {
- free(vibrate_info);
- return;
- }
-
- /* Same or higher priority pattern should be played */
- if (vibrate_info->priority < cur_h_data.priority) {
- _I("Handle(%d) skip low priority. pre=%d now=%d", vibrate_info->handle, cur_h_data.priority, vibrate_info->priority);
- goto out;
- }
-
- snprintf(pattern, sizeof(pattern), "%s", vibrate_info->pattern);
- SYS_G_LIST_FOREACH(vib_conf_list, elem, conf) {
- if (!conf->pattern)
- continue;
- if (strcmp(conf->pattern, pattern))
- continue;
- if (conf->standard) {
- unlimit = conf->unlimit;
- snprintf(pattern, sizeof(pattern), "%s", conf->standard);
- continue;
- }
-
- if (unlimit)
- cur_h_data.unlimit = unlimit;
- else
- cur_h_data.unlimit = conf->unlimit;
- cur_h_data.vibration_data = conf->data;
- cur_h_data.handle = vibrate_info->handle;
- cur_h_data.level = vibrate_info->level;
- cur_h_data.priority = vibrate_info->priority;
- cur_h_data.stop = false;
- _I("Handle(%d) play=%s pri=%d %s", cur_h_data.handle, conf->pattern, cur_h_data.priority,
- cur_h_data.unlimit ? "Unlimit" : "Once");
-
- if (conf->pattern_duration <= 0)
- break;
-
- if (!cur_h_data.unlimit && conf->pattern_duration > 0) {
- ret = device_power_request_lock(POWER_LOCK_CPU, (int)conf->pattern_duration);
- if (ret != DEVICE_ERROR_NONE)
- _E("Failed to request power lock.");
- }
- haptic_duration_play((void *)cur_h_data.vibration_data);
- goto out;
- }
- _E("Handle(%d) %s is not supported.", vibrate_info->handle, pattern);
-
-out:
- free(vibrate_info->pattern);
- free(vibrate_info);
-}
-
-GVariant *hdbus_vibrate_pattern(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- struct vibrate_pattern_info *vibrate_info;
- unsigned int handle;
- char *pattern = NULL;
- int level, priority, ret = 0;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- if (haptic_disabled)
- goto exit;
-
- g_variant_get(param, "(usii)", &handle, &pattern, &level, &priority);
-
- if (level < 0) {
- ret = -EINVAL;
- goto exit;
- }
-
- if (priority < PRIORITY_MIN)
- priority = PRIORITY_MIN;
- else if (priority > PRIORITY_TOP)
- priority = PRIORITY_TOP;
-
- vibrate_info = calloc(1, sizeof(struct vibrate_pattern_info));
- if (!vibrate_info) {
- _E("Failed to allocate memory for vibrate_info.");
- ret = -errno;
- goto exit;
- }
- vibrate_info->handle = handle;
- vibrate_info->pattern = pattern;
- pattern = NULL;
- if (!vibrate_info->pattern) {
- _E("Failed to allocate memory for pattern.");
- ret = -errno;
- free(vibrate_info);
- goto exit;
- }
- vibrate_info->level = level;
- vibrate_info->priority = priority;
-
- ret = add_idle_request(vibrate_pattern_idler_cb, (void *)vibrate_info);
-
-exit:
- g_free(pattern);
- return g_variant_new("(i)", ret);
-}
-
-GVariant *hdbus_stop_device(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- unsigned int handle;
- int ret = 0;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- if (haptic_disabled) {
- _I("Haptic disabled.");
- goto exit;
- }
-
- g_variant_get(param, "(u)", &handle);
-
- if (cur_h_data.handle != handle) {
- _D("Not the request from current vibration handle(%d). Skip.", handle);
- goto exit;
- }
-
- ret = haptic_stop_device(handle);
- _I("Stop the device(handle=%u) :%d", handle, ret);
-
- /* Remove duration_timer for vibrate_effect */
- clear_current_data();
-
-exit:
- return g_variant_new("(i)", ret);
-}
-
-GVariant *hdbus_show_handle_list(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-{
- GList *n;
- GList *elem;
- struct haptic_info *info;
-
- _D("Sender Handle");
- SYS_G_LIST_FOREACH(haptic_handle_list, n, info) {
- for (elem = info->handle_list; elem; elem = elem->next)
- _D("%s %d", info->sender, (int)(long)elem->data);
- }
-
- return g_variant_new_tuple(NULL, 0);
-}
-
-int pattern_is_supported(const char *pattern)
-{
- GList *elem;
- struct vibration_config *conf;
- int ret;
-
- if (!pattern)
- return -EINVAL;
-
- ret = 0;
- SYS_G_LIST_FOREACH(vib_conf_list, elem, conf) {
- if (!conf->pattern)
- continue;
- if (!strcmp(conf->pattern, pattern)) {
- ret = true;
- break;
- }
- }
-
- return ret;
-}
-
-GVariant *hdbus_pattern_is_supported(GDBusConnection *conn,
- const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
- GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
-
-{
- char *data = NULL;
- int ret = 0;
-
- if ((ret = haptic_check_device()) < 0)
- goto exit;
-
- if (haptic_disabled)
- goto exit;
-
- g_variant_get(param, "(s)", &data);
-
- ret = pattern_is_supported(data);
-
- _I("%s is supported: %d", data, ret);
-
-exit:
- g_free(data);
- return g_variant_new("(i)", ret);
-}
-
-static void haptic_poweroff_cb(GDBusConnection *conn,
- const gchar *sender,
- const gchar *path,
- const gchar *iface,
- const gchar *name,
- GVariant *param,
- gpointer data)
-{
- int type = POWER_OFF_NONE;
- int ret, level;
- struct timespec time = {0,};
-
- if (!g_variant_get_safe(param, "(i)", &type)) {
- _E("Failed to get params from gvariant. expected:%s, type:%s", "(i)", g_variant_get_type_string(param));
- return;
- }
-
- if (type != POWER_OFF_DIRECT && type != POWER_OFF_RESTART)
- return;
-
- _D("Poweroff: %d", type);
-
- if (haptic_check_device() < 0) {
- if (haptic_module_load() < 0)
- return ;
- }
-
- if (!g_handle) {
- if (haptic_open_device(&g_handle) < 0)
- return ;
- }
-
- if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &level) < 0) {
- _E("Failed to get '"VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT"' vconf value.");
- return;
- }
- level = (level/2) + 1;
-
- /* power off vibration */
- _I("Handle=%d dur=%dms pri=%d level=%d intensity=%d frequency=0",
- g_handle, POWER_OFF_VIB_DURATION, PRIORITY_HIGH, level,
- POWER_VIB_FEEDBACK * 100);
- ret = haptic_vibrate_device(g_handle, POWER_OFF_VIB_DURATION, 0, 0,
- level, POWER_VIB_FEEDBACK * 100, PRIORITY_HIGH);
- if (ret < 0) {
- _E("Failed to vibrate_monotone: %d", ret);
- return;
- }
-
- /* sleep for vibration */
- time.tv_nsec = POWER_OFF_VIB_DURATION * NANO_SECOND_MULTIPLIER;
- nanosleep(&time, NULL);
- return;
-}
-
-static void sound_capturing_cb(keynode_t *key, void *data)
-{
- int status;
-
- status = vconf_keynode_get_int(key);
-
- /* if sound capture is in use, this value is 1(true). */
- if (status == VCONFKEY_RECORDER_STATE_RECORDING)
- haptic_stop();
- else
- haptic_start();
-}
-
-static int parse_section(struct parse_result *result, void *user_data, int index)
-{
- struct haptic_config *conf = (struct haptic_config *)user_data;
-
- if (!result)
- return 0;
-
- if (!result->section || !result->name || !result->value)
- return 0;
-
- if (MATCH(result->name, "sound_capture")) {
- conf->sound_capture = atoi(result->value);
- } else if (MATCH(result->name, "level")) {
- conf->level = atoi(result->value);
- if (conf->level < 0 || conf->level >= INT_MAX - 1) {
- _E("You must set level with positive number in integer range.");
- return -EINVAL;
- }
- conf->level_arr = calloc(sizeof(int), conf->level);
- if (!conf->level_arr) {
- _E("Failed to allocate memory for level.");
- return -errno;
- }
- } else if (MATCH(result->name, "value")) {
- if (index < 0)
- return -EINVAL;
- conf->level_arr[index] = atoi(result->value);
- }
-
- return 0;
-}
-
-static int haptic_load_config(struct parse_result *result, void *user_data)
-{
- struct haptic_config *conf = (struct haptic_config *)user_data;
- char name[NAME_MAX];
- int ret;
- static int index;
-
- if (!result)
- return 0;
-
- if (!result->section || !result->name || !result->value)
- return 0;
-
- // Parsing 'Haptic' section
- if (MATCH(result->section, "Haptic")) {
- ret = parse_section(result, user_data, -1);
- if (ret < 0) {
- _E("Failed to parse 'Haptic' section: %d", ret);
- return ret;
- }
- goto out;
- }
-
- // Parsing 'level' section
- for (index = 0; index < conf->level; ++index) {
- snprintf(name, sizeof(name), "level%d", index);
- if (MATCH(result->section, name)) {
- ret = parse_section(result, user_data, index);
- if (ret < 0) {
- _E("Failed to parse 'level' section: %d", ret);
- return ret;
- }
- goto out;
- }
- }
-
-out:
- return 0;
-}
-
-static const dbus_method_s hdbus_methods[] = {
- { "GetCount", NULL, "i", hdbus_get_count }, // device_haptic_get_count
- { "OpenDevice", "i", "i", hdbus_open_device }, // device_haptic_open, feedback_initialize
- { "CloseDevice", "u", "i", hdbus_close_device }, // device_haptic_close, feedback_deinitialize
- { "StopDevice", "u", "i", hdbus_stop_device }, // device_haptic_stop, feedback_stop
- { "VibrateMonotone", "uiii", "i", hdbus_vibrate_monotone }, // device_haptic_vibrate
- { "VibratePattern", "usii", "i", hdbus_vibrate_pattern }, // feedback_play*
- { "ShowHandleList", NULL, NULL, hdbus_show_handle_list },
- { "IsSupported", "s", "i", hdbus_pattern_is_supported }, // feedback_is_supported_pattern
- /* Add methods here */
-};
-
-static const dbus_interface_u dbus_interface = {
- .name = VIBRATOR_INTERFACE_HAPTIC,
- .methods = hdbus_methods,
- .nr_methods = ARRAY_SIZE(hdbus_methods),
-};
-
-int haptic_probe(void)
-{
- /**
- * load haptic module.
- * if there is no haptic module,
- * feedbackd does not activate a haptic interface.
- */
- return haptic_module_load();
-}
-
-static guint id_sig_pwr_off_state;
-
-void haptic_init(void)
-{
- int r;
-
- /* get haptic data from configuration file */
- r = config_parse(HAPTIC_CONF_PATH, haptic_load_config, &haptic_conf);
- if (r < 0) {
- _E("Failed to load configuration file(%s): %d", HAPTIC_CONF_PATH, r);
- safe_free(haptic_conf.level_arr);
- }
-
- /* init dbus interface */
- r = dbus_handle_register_dbus_object(NULL, VIBRATOR_PATH_HAPTIC, &dbus_interface);
- if (r < 0)
- _E("Failed to init hdbus interface and method: %d", r);
-
- id_sig_pwr_off_state = subscribe_dbus_signal(NULL,
- DEVICED_PATH_POWEROFF,
- DEVICED_INTERFACE_POWEROFF,
- SIGNAL_POWEROFF_STATE,
- haptic_poweroff_cb,
- NULL,
- NULL);
- if (id_sig_pwr_off_state <= 0) {
- _E("Failed to register signal handler: %d", r);
- return;
- }
-
- dbus_handle_emit_dbus_signal(NULL,
- VIBRATOR_PATH_HAPTIC,
- VIBRATOR_INTERFACE_HAPTIC,
- SIGNAL_VIBRATOR_INITIATED,
- NULL);
-
- /* add watch for sound capturing value */
- if (haptic_conf.sound_capture) {
- r = vconf_notify_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb, NULL);
- if (r != 0)
- _W("Add watch for VCONFKEY_RECORDER_STATE failed.");
- }
-
- /* Initialize vibration_handle (Use vibration now) */
- cur_h_data.handle = INVALID_HANDLE;
- cur_h_data.priority = PRIORITY_MIN;
-}
-
-void haptic_exit(void)
-{
- int r;
-
- /* remove watch */
- if (haptic_conf.sound_capture) {
- r = vconf_ignore_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb);
- if (r != 0)
- _W("Remove watch for VCONFKEY_RECORDER_STATE failed.");
- }
-
- /* unregister notifier for below each event */
- unsubscribe_dbus_signal(NULL, id_sig_pwr_off_state);
-
- /* release haptic data memory */
- safe_free(haptic_conf.level_arr);
-
- if (haptic_check_device() < 0)
- return;
-
- /* haptic exit for feedbackd */
- haptic_close_device(g_handle);
- haptic_release_device();
-}
-
-static int haptic_start(void)
-{
- _I("Start");
- haptic_disabled = false;
- return 0;
-}
-
-static int haptic_stop(void)
-{
- _I("Stop");
- haptic_disabled = true;
- return 0;
-}
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2012 - 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.
- */
-
-
-#ifndef __FEEDBACKD_HAPTIC_H__
-#define __FEEDBACKD_HAPTIC_H__
-
-#include <stdbool.h>
-#include <glib.h>
-#include <device/power.h>
-#include "shared/common.h"
-
-enum priority_level {
- PRIORITY_MIN = 0,
- PRIORITY_MIDDLE,
- PRIORITY_HIGH,
- PRIORITY_TOP,
-};
-
-struct haptic_data {
- GList *vibration_data;
- unsigned int handle;
- int level;
- int priority;
- bool stop;
- int unlimit;
-};
-
-#define INVALID_HANDLE 0
-
-int haptic_probe(void);
-void haptic_init(void);
-void haptic_exit(void);
-
-#endif /* __FEEDBACKD_HAPTIC_H__ */
+++ /dev/null
-/*
- * feedbackd
- *
- * Copyright (c) 2012 - 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 <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <linux/input.h>
-#include <libsyscommon/list.h>
-
-#include "shared/common.h"
-#include "shared/log.h"
-#include "haptic-interface.h"
-
-#define MAX_MAGNITUDE 0xFFFF
-#define PERIODIC_MAX_MAGNITUDE 0x7FFF /* 0.5 * MAX_MAGNITUDE */
-#define RUMBLE_MAX_MAGNITUDE 0xFFFF
-
-#define DEV_INPUT "/dev/input"
-#define EVENT "event"
-
-#define MAX_DATA 16
-#define FF_INFO_MAGIC 0xDEADFEED
-
-#define SET_OVERDRIVE_BIT(x,value) (x |= ((value > 0)? 1: 0)<<14)
-#define SET_LEVEL_BIT(x,value) (x |= (value<<13))
-
-struct ff_info_header {
- unsigned int magic;
- int iteration;
- int ff_info_data_count;
-};
-
-struct ff_info_data {
- int type;/* play, stop etc */
- int magnitude; /* strength */
- int length; /* in ms for stop, play*/
-};
-
-struct ff_info_buffer {
- struct ff_info_header header;
- struct ff_info_data data[MAX_DATA];
-};
-
-struct ff_info {
- int handle;
- guint timer;
- struct ff_effect effect;
- struct ff_info_buffer *ffinfobuffer;
- int currentindex;
-};
-
-static int ff_fd;
-static GList *ff_list;
-static GList *handle_list;
-static char ff_path[PATH_MAX];
-static int unique_number;
-static int current_effect_id = -1;
-
-static int stop_device(int device_handle);
-
-struct ff_info *read_from_list(int handle)
-{
- struct ff_info *temp;
- GList *elem;
-
- SYS_G_LIST_FOREACH(ff_list, elem, temp) {
- if (temp->handle == handle)
- return temp;
- }
- return NULL;
-}
-
-static bool check_valid_handle(struct ff_info *info)
-{
- struct ff_info *temp;
- GList *elem;
-
- SYS_G_LIST_FOREACH(ff_list, elem, temp) {
- if (temp == info)
- break;
- }
-
- if (!temp)
- return false;
- return true;
-}
-
-static bool check_fd(int *fd)
-{
- int ffd;
-
- if (*fd > 0)
- return true;
-
- ffd = open(ff_path, O_RDWR);
- if (ffd < 0)
- return false;
-
- *fd = ffd;
- return true;
-}
-
-static int ff_stop(int fd, struct ff_effect *effect);
-static gboolean timer_cb(void *data)
-{
- struct ff_info *info = (struct ff_info *)data;
-
- if (!info) {
- _E("Failed to check info.");
- return G_SOURCE_REMOVE;
- }
-
- if (!check_valid_handle(info)) {
- _E("Failed to check valied info.");
- return G_SOURCE_REMOVE;
- }
-
- _I("Stop vibration by timer. id(%d)", info->effect.id);
-
- /* stop previous vibration */
- ff_stop(ff_fd, &info->effect);
-
- /* reset timer */
- info->timer = 0;
-
- return G_SOURCE_REMOVE;
-}
-
-static int ff_find_device(void)
-{
- DIR *dir;
- struct dirent *dent;
- char ev_path[PATH_MAX];
- unsigned long features[1+FF_MAX/sizeof(unsigned long)];
- int fd, ret;
-
- dir = opendir(DEV_INPUT);
- if (!dir)
- return -errno;
-
- while (1) {
- dent = readdir(dir);
- if (dent == NULL)
- break;
-
- if (dent->d_type == DT_DIR ||
- !strstr(dent->d_name, "event"))
- continue;
-
- snprintf(ev_path, sizeof(ev_path), "%s/%s", DEV_INPUT, dent->d_name);
-
- fd = open(ev_path, O_RDWR);
- if (fd < 0) {
- _E("Failed to open '%s'.: %d", ev_path, errno);
- continue;
- }
-
- /* get force feedback device */
- memset(features, 0, sizeof(features));
- ret = ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features);
- if (ret == -1) {
- close(fd);
- continue;
- }
-
- if (test_bit(FF_CONSTANT, features))
- _D("'%s' type: constant", ev_path);
- if (test_bit(FF_PERIODIC, features))
- _D("'%s' type: periodic", ev_path);
- if (test_bit(FF_SPRING, features))
- _D("'%s' type: spring", ev_path);
- if (test_bit(FF_FRICTION, features))
- _D("'%s' type: friction", ev_path);
- if (test_bit(FF_RUMBLE, features))
- _D("'%s' type: rumble", ev_path);
-
- if (test_bit(FF_RUMBLE, features)) {
- memcpy(ff_path, ev_path, strlen(ev_path)+1);
- close(fd);
- closedir(dir);
- return 0;
- }
-
- close(fd);
- }
-
- closedir(dir);
- return -1;
-}
-
-static int ff_init_effect(struct ff_effect *effect)
-{
- if (!effect)
- return -EINVAL;
-
- effect->type = FF_RUMBLE;
- effect->replay.length = 0;
- effect->replay.delay = 0;
- effect->id = -1;
- effect->u.rumble.strong_magnitude = 0;
- effect->u.rumble.weak_magnitude = 0;
-
- return 0;
-}
-
-static int ff_set_effect(struct ff_effect *effect, int duration, int level, int intensity, int frequency, int overdrive)
-{
- if (!effect) {
- _E("There is no valid effect.");
- return -EINVAL;
- }
-
- /*
- __u16 strong_magnitude; // strong_magnitude[15:15] = 0 (Reserved)
- // strong_magnitude[14:14] = Overdrive : 0 (Off) or 1 (On)
- // strong_magnitude[13:0] = Intensity Value : 0 (Stop) or 1 ~ 10000 (Intensity)
- __u16 weak_magnitude; // weak_magnitude[15:13] = Intensity Level : 1 ~ 5
- // weak_magnitude[12:0] = Frequency : 0 ~ 8191 (0 ~ 819.1 Hz)
- */
-
- effect->u.rumble.strong_magnitude = intensity;
- SET_OVERDRIVE_BIT(effect->u.rumble.strong_magnitude, overdrive);
-
- effect->u.rumble.weak_magnitude = frequency;
- SET_LEVEL_BIT(effect->u.rumble.weak_magnitude, level);
-
- /* set member variables in effect struct */
- effect->replay.length = duration; /* length millisecond */
-
- //_D("rumble data: strong_magnitude = 0x%x, weak_magnitude = 0x%x", effect->u.rumble.strong_magnitude, effect->u.rumble.weak_magnitude);
- return 0;
-}
-
-static int ff_play(int fd, struct ff_effect *effect)
-{
- struct input_event play;
- int ret;
-
- if (fd < 0 || !effect) {
- _E("Fd(%d) or effect(%s) is invalid", fd, effect ? "not null" : "null");
- return -EINVAL;
- }
-
- /* upload an effect */
- if (current_effect_id == -1) {
- if (ioctl(fd, EVIOCSFF, effect) == -1) {
- _E("Failed to ioctl");
- return -errno;
- }
- current_effect_id = effect->id;
- } else
- effect->id = current_effect_id;
-
- /* play vibration*/
- play.type = EV_FF;
- play.code = effect->id;
- play.value = 1; /* 1 : PLAY, 0 : STOP */
-
- ret = write(fd, (const void *)&play, sizeof(play));
- if (ret == -1) {
- _E("Failed to write");
- return -errno;
- }
-
- return 0;
-}
-
-static int ff_stop(int fd, struct ff_effect *effect)
-{
- struct input_event stop;
- int ret;
-
- if (fd < 0 || !effect)
- return -EINVAL;
-
- if (effect->id == -1) {
- if (current_effect_id == -1)
- return 0;
- effect->id = current_effect_id;
- }
-
- /* Stop vibration */
- stop.type = EV_FF;
- stop.code = effect->id;
- stop.value = 0; /* 1 : PLAY, 0 : STOP */
- ret = write(fd, (const void *)&stop, sizeof(stop));
- if (ret == -1)
- return -errno;
-
- /* removing an effect from the device */
- if (ioctl(fd, EVIOCRMFF, effect->id) == -1)
- return -errno;
-
- /* reset effect id */
- effect->id = -1;
- current_effect_id = -1;
-
- return 0;
-}
-
-/* START: Haptic Module APIs */
-static int get_device_count(int *count)
-{
- /* suppose there is just one haptic device */
- if (count)
- *count = 1;
-
- return 0;
-}
-
-static int open_device(int device_index, int *device_handle)
-{
- struct ff_info *info;
- int n;
- bool found = false;
- GList *elem;
-
- if (!device_handle)
- return -EINVAL;
-
- /* if it is the first element */
- n = SYS_G_LIST_LENGTH(ff_list);
- if (n == 0 && !ff_fd) {
- _I("First element: open ff driver");
- /* open ff driver */
- ff_fd = open(ff_path, O_RDWR);
- if (ff_fd < 0) {
- _E("Failed to open %s : %d", ff_path, errno);
- return -errno;
- }
- }
-
- /* allocate memory */
- info = calloc(sizeof(struct ff_info), 1);
- if (!info) {
- _E("Failed to allocate memory : %d", errno);
- return -errno;
- }
-
- /* initialize ff_effect structure */
- ff_init_effect(&info->effect);
-
- if (unique_number == INT_MAX)
- unique_number = 0;
-
- while (found != true) {
- ++unique_number;
- elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)unique_number);
- if (!elem)
- found = true;
- }
-
- info->handle = unique_number;
-
- /* add info to local list */
- SYS_G_LIST_APPEND(ff_list, info);
- SYS_G_LIST_APPEND(handle_list, (gpointer)(long)info->handle);
-
- *device_handle = info->handle;
- return 0;
-}
-
-static int close_device(int device_handle)
-{
- struct ff_info *info;
- int n;
-
- info = read_from_list(device_handle);
- if (!info) {
- _E("Handle %d failed to check info", device_handle);
- return -ENOENT; /* 2 */
- }
-
- if (!check_valid_handle(info)) {
- _E("Handle %d failed to check valid handle", device_handle);
- return -EINVAL; /* 22 */
- }
-
- if (!check_fd(&ff_fd)) {
- _E("Handle %d failed to check fd", device_handle);
- return -ENODEV; /* 19 */
- }
-
- /* stop vibration */
- stop_device(device_handle);
-
- SYS_G_LIST_REMOVE(handle_list, (gpointer)(long)info->handle);
-
- safe_free(info->ffinfobuffer);
- /* remove info from local list */
- SYS_G_LIST_REMOVE(ff_list, info);
- safe_free(info);
-
- /* if it is the last element */
- n = SYS_G_LIST_LENGTH(ff_list);
- if (n == 0 && ff_fd) {
- _I("Last element: close ff driver");
- /* close ff driver */
- close(ff_fd);
- ff_fd = 0;
- }
-
- return 0;
-}
-
-static int vibrate_monotone(int device_handle, int duration, int frequency, int overdrive, int level, int intensity, int priority)
-{
- struct ff_info *info;
- int ret;
-
- info = read_from_list(device_handle);
- if (!info) {
- _E("Handle %d failed to check list.", device_handle);
- return -EINVAL;
- }
-
- if (!check_valid_handle(info)) {
- _E("Handle %d failed to check handle.", device_handle);
- return -EINVAL;
- }
-
- if (!check_fd(&ff_fd))
- return -ENODEV;
-
- if (duration <= 0) {
- _I("Handle %d skip requests with duration 0.", device_handle);
- return 0;
- }
-
- /* Zero(0) is the infinitely vibration value */
- if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
- duration = 0;
-
- /* unregister existing timer */
- if (info->timer) {
- ff_stop(ff_fd, &info->effect);
- g_source_remove(info->timer);
- info->timer = 0;
- }
-
- /* set effect as per arguments */
- ff_init_effect(&info->effect);
- ret = ff_set_effect(&info->effect, duration, level, intensity, frequency, overdrive);
- if (ret < 0) {
- _E("Handle %d fail to set effect(duration:%d, level:%d, intensity:%d, frequency:%d, overdrive:%d) : %d",
- device_handle, duration, level, intensity, frequency, overdrive, ret);
- return ret;
- }
-
- /* play effect as per arguments */
- ret = ff_play(ff_fd, &info->effect);
- if (ret < 0) {
- _E("Handle %d fail to play haptic effect(fd:%d id:%d) : %d",
- device_handle, ff_fd, info->effect.id, ret);
- return ret;
- }
-
- _I("Play vibration. Handle %d effect id : %d %dms", device_handle, info->effect.id, duration);
-
- /* register timer */
- if (duration) {
- info->timer = g_timeout_add(duration, timer_cb, info);
- if (!info->timer)
- _E("Handle %d failed to add timer callback", device_handle);
- }
-
- return 0;
-}
-
-static int stop_device(int device_handle)
-{
- struct ff_info *info;
- int r;
-
- info = read_from_list(device_handle);
- if (!info) {
- _E("Handle %d fail to check info", device_handle);
- return -ENOENT; /* 2 */
- }
-
- if (!check_fd(&ff_fd)) {
- _E("Handle %d fail to check fd", device_handle);
- return -ENODEV; /* 19 */
- }
-
- /* stop effect */
- r = ff_stop(ff_fd, &info->effect);
- if (r < 0)
- _E("failed to stop effect(id:%d) : %d", info->effect.id, r);
- else
- _I("Stop vibration by request. id(%d)", info->effect.id);
-
- /* unregister existing timer */
- if (r >= 0 && info->timer) {
- g_source_remove(info->timer);
- info->timer = 0;
- }
-
- return 0;
-}
-/* END: Haptic Module APIs */
-
-static const struct haptic_plugin_ops default_plugin = {
- .get_device_count = get_device_count,
- .open_device = open_device,
- .close_device = close_device,
- .vibrate_monotone = vibrate_monotone,
- .stop_device = stop_device,
-};
-
-static bool is_valid(void)
-{
- int ret;
-
- ret = ff_find_device();
- if (ret < 0) {
- _E("Do not support standard haptic device");
- return false;
- }
-
- _I("Support standard haptic device");
- return true;
-}
-
-static const struct haptic_plugin_ops *load(void)
-{
- return &default_plugin;
-}
-
-static const struct haptic_ops std_ops = {
- .type = HAPTIC_STANDARD,
- .is_valid = is_valid,
- .load = load,
-};
-
-EXPORT_GET_VAR_HAPTIC_OPS(&std_ops)