--- /dev/null
+Thanks to the follow people for contributing to deviced by reporting
+bugs, providing fixes, providing information, providing resources or
+porting to new systems:
+
+The names are sorted alphabetically by last name.
+Names taken from sources and from version control system.
+
+ChanWoo Choi <cw00.choi@samsung.com>
+Byung-Soo Kim <bs1770.kim@samsung.com>
+Taeyoung Kim <ty317.kim@samsung.com>
+Gi-Yeol Ok <giyeol.ok@samsung.com>
+Kyungmin Park <kyungmin.park@samsung.com>
+SeungHun Pi <sh.pi@samsung.com>
+Juho Son <juho80.son@samsung.com>
+Jiyoung Yun <jy910.yun@samsung.com>
--- /dev/null
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
--- /dev/null
+DBus Error note
+
+Functions Defines Values
+======================================================================
+dbus_bus_get EPERM 1
+dbus_message_get_args ENOMSG 42
+dbus_connection_send_with_reply_and_block ECOMM 70
+dbus_connection_send ECOMM 70
+dbus_message_new_method_call EBADMSG 74
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <stdarg.h>
+#include "core/log.h"
+#include "core/common.h"
+#include "apps.h"
+#include "core/edbus-handler.h"
+
+#define POPUP_METHOD "PopupLaunch"
+
+static const struct app_dbus_match {
+ const char *type;
+ const char *bus;
+ const char *path;
+ const char *iface;
+ const char *method;
+} app_match[] = {
+ { APP_DEFAULT , POPUP_BUS_NAME, POPUP_PATH_SYSTEM , POPUP_INTERFACE_SYSTEM , POPUP_METHOD },
+ { APP_POWERKEY, POPUP_BUS_NAME, POPUP_PATH_POWERKEY, POPUP_INTERFACE_POWERKEY, POPUP_METHOD },
+};
+
+int launch_system_app(char *type, int num, ...)
+{
+ char *app_type;
+ va_list args;
+ int i, match, ret;
+
+ if (type)
+ app_type = type;
+ else
+ app_type = APP_DEFAULT;
+
+ match = -1;
+ for (i = 0 ; i < ARRAY_SIZE(app_match) ; i++) {
+ if (strncmp(app_type, app_match[i].type, strlen(app_type)))
+ continue;
+ match = i;
+ break;
+ }
+ if (match < 0) {
+ _E("Failed to find app matched (%s)", app_type);
+ return -EINVAL;
+ }
+
+ va_start(args, num);
+
+ ret = dbus_method_sync_pairs(app_match[match].bus,
+ app_match[match].path,
+ app_match[match].iface,
+ app_match[match].method,
+ num, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+int launch_message_post(char *type)
+{
+ char *param[1];
+
+ if (!type)
+ return -EINVAL;
+
+ param[0] = type;
+
+ return dbus_method_sync(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ "MessagePostOn",
+ "s", param);
+}
+
+int add_notification(char *type)
+{
+ if (!type)
+ return -EINVAL;
+
+ return dbus_method_sync(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ type, NULL, NULL);
+}
+
+int remove_notification(char *type, int id)
+{
+ char *param[1];
+ char id_str[16];
+
+ if (!type || id < 0)
+ return -EINVAL;
+
+ snprintf(id_str, sizeof(id_str), "%d", id);
+ param[0] = id_str;
+
+ return dbus_method_sync(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ type, "i", param);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 __APPS_H__
+#define __APPS_H__
+
+
+#include "core/edbus-handler.h"
+#include "core/common.h"
+
+#define APP_POWERKEY "powerkey"
+#define APP_DEFAULT "system"
+#define APP_KEY_TYPE "_SYSPOPUP_CONTENT_"
+
+int launch_system_app(char *type, int num, ...);
+int launch_message_post(char *type);
+int add_notification(char *type);
+int remove_notification(char *type, int id);
+
+#endif /* __APPS_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <Ecore.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vconf.h>
+#include <device-node.h>
+
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/log.h"
+#include "core/edbus-handler.h"
+#include "display/setting.h"
+#include "power-supply.h"
+
+#define CHARGING_STATE(x) ((x) & CHRGR_FLAG)
+#define FULL_CAPACITY (100)
+#define BATTERY_FULL_THRESHOLD (98)
+#define MAX_COUNT_UNCHARGING (10)
+#define MAX_COUNT_CHARGING (10)
+#define PRINT_ALL_BATT_NODE(x) /*print_all_batt_node(x)*/
+#define POLLING_TIME (30) /* seconds */
+
+#define SIGNAL_TIMETOFULL "TimeToFull"
+#define SIGNAL_TIMETOEMPTY "TimeToEmpty"
+
+enum state_b {
+ B_UNCHARGING = 0,
+ B_CHARGING = 1,
+ B_END = 2
+};
+
+struct Batt_node {
+ time_t clock;
+ int capacity;
+ struct Batt_node *preview;
+ struct Batt_node *next;
+};
+
+enum state_a {
+ A_TIMETOEMPTY = 0,
+ A_TIMETOFULL = 1,
+ A_END = 2
+};
+
+static Ecore_Timer *timeout_id;
+
+static struct Batt_node *batt_head[B_END];
+static struct Batt_node *batt_tail[B_END];
+static int MAX_VALUE_COUNT[B_END] = {MAX_COUNT_UNCHARGING, MAX_COUNT_CHARGING};
+static double avg_factor[B_END] = {-1.0, -1.0};
+static int old_capacity;
+static int charging_state;
+extern int system_wakeup_flag;
+static int time_to_full = -1;
+static int time_to_empty = -1;
+
+static int add_batt_node(enum state_b b_index, time_t clock, int capacity)
+{
+ struct Batt_node *node = NULL;
+
+ PRINT_ALL_BATT_NODE(b_index);
+
+ if (b_index < 0 || b_index >= B_END)
+ return -1;
+
+ node = (struct Batt_node *) malloc(sizeof(struct Batt_node));
+ if (node == NULL) {
+ _E("Not enough memory, add battery node fail!");
+ return -1;
+ }
+
+ node->clock = clock;
+ node->capacity = capacity;
+
+ if (batt_head[b_index] == NULL && batt_tail[b_index] == NULL) {
+ batt_head[b_index] = batt_tail[b_index] = node;
+ node->preview = NULL;
+ node->next = NULL;
+ } else {
+ node->next = batt_head[b_index];
+ node->preview = NULL;
+ batt_head[b_index]->preview = node;
+ batt_head[b_index] = node;
+ }
+ PRINT_ALL_BATT_NODE(b_index);
+ return 0;
+}
+
+static int reap_batt_node(enum state_b b_index, int max_count)
+{
+ struct Batt_node *node = NULL;
+ struct Batt_node *tmp = NULL;
+ int cnt = 0;
+
+ PRINT_ALL_BATT_NODE(b_index);
+
+ if (b_index < 0 || b_index >= B_END)
+ return -1;
+
+ if (max_count <= 0)
+ return -1;
+
+ node = batt_head[b_index];
+
+ while (node != NULL) {
+ if (cnt >= max_count) break;
+ cnt++;
+ node = node->next;
+ }
+
+ if (node != NULL && node != batt_tail[b_index]) {
+ batt_tail[b_index] = node;
+ node = node->next;
+ batt_tail[b_index]->next = NULL;
+ while (node != NULL) {
+ tmp = node;
+ node = node->next;
+ free(tmp);
+ }
+ }
+ PRINT_ALL_BATT_NODE(b_index);
+ return 0;
+}
+
+static int del_all_batt_node(enum state_b b_index)
+{
+ struct Batt_node *node = NULL;
+
+ PRINT_ALL_BATT_NODE(b_index);
+
+ if (b_index < 0 || b_index >= B_END)
+ return -1;
+ if (batt_head[b_index] == NULL)
+ return 0;
+
+ while (batt_head[b_index] != NULL) {
+ node = batt_head[b_index];
+ batt_head[b_index] = batt_head[b_index]->next;
+ free(node);
+ }
+ batt_tail[b_index] = NULL;
+ PRINT_ALL_BATT_NODE(b_index);
+ return 0;
+}
+
+static float update_factor(enum state_b b_index)
+{
+ struct Batt_node *node = NULL;
+ double factor = 0.0;
+ double total_factor = 0.0;
+ int cnt = 0;
+ double timediff = 0.0;
+ double capadiff = 0.0;
+
+ if (b_index < 0 || b_index >= B_END)
+ return 0;
+
+ if (batt_head[b_index] == NULL || batt_head[b_index]->next == NULL)
+ return avg_factor[b_index];
+
+ node = batt_head[b_index];
+ while (1) {
+ timediff = difftime(node->clock, node->next->clock);
+ capadiff = node->capacity - node->next->capacity;
+ if (capadiff < 0)
+ capadiff *= (-1);
+ if (capadiff != 0)
+ factor = timediff / capadiff;
+ total_factor += factor;
+
+ node = node->next;
+ cnt++;
+
+ /*_I("[%d] timediff(%lf) / capadiff(%lf) = factor(%lf)",
+ cnt, timediff, capadiff, factor);*/
+ factor = 0.0;
+
+ if (node == NULL || node->next == NULL)
+ break;
+ if (cnt >= MAX_VALUE_COUNT[b_index]) {
+ reap_batt_node(b_index, MAX_VALUE_COUNT[b_index]);
+ break;
+ }
+ }
+ total_factor /= (float)cnt;
+
+ return total_factor;
+}
+
+static void broadcast_battery_time(char *signal, int time)
+{
+ char *param[1];
+ char buf[10];
+
+ if (!signal)
+ return;
+
+ snprintf(buf, 10, "%d", time);
+ param[0] = buf;
+
+ broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
+ signal, "i", param);
+}
+
+static void update_time(enum state_a a_index, int seconds)
+{
+ if (a_index < 0 || a_index >= A_END)
+ return;
+
+ if (seconds <= 0)
+ return;
+
+ switch (a_index) {
+ case A_TIMETOFULL:
+ broadcast_battery_time(SIGNAL_TIMETOFULL, seconds);
+ time_to_full = seconds;
+ break;
+ case A_TIMETOEMPTY:
+ broadcast_battery_time(SIGNAL_TIMETOEMPTY, seconds);
+ time_to_empty = seconds;
+ break;
+ default:
+ break;
+ }
+}
+
+static int battinfo_calculation(void)
+{
+ time_t clock;
+ int capacity = 0;
+ int estimated_time = 0;
+ int tmp = 0;
+
+ capacity = battery.capacity;
+
+ if (capacity <= 0)
+ return -1;
+ if (capacity == old_capacity)
+ return 0;
+
+ old_capacity = capacity;
+
+ if (get_charging_status(&tmp) == 0)
+ charging_state = (tmp > 0 ? EINA_TRUE : EINA_FALSE);
+
+ clock = time(NULL);
+ if (charging_state == EINA_TRUE) {
+ del_all_batt_node(B_UNCHARGING);
+ if ((capacity * 100 / FULL_CAPACITY)
+ >= BATTERY_FULL_THRESHOLD) {
+ if (battery.charge_full == CHARGING_FULL) {
+ del_all_batt_node(B_CHARGING);
+ _I("battery fully charged!");
+ update_time(A_TIMETOFULL, 0);
+ return 0;
+ }
+ }
+ if (batt_head[B_CHARGING] == NULL) {
+ add_batt_node(B_CHARGING, clock, capacity);
+ } else {
+ add_batt_node(B_CHARGING, clock, capacity);
+ avg_factor[B_CHARGING] = update_factor(B_CHARGING);
+ }
+ estimated_time = (float)(FULL_CAPACITY - capacity) *
+ avg_factor[B_CHARGING];
+ update_time(A_TIMETOFULL, estimated_time);
+ } else {
+ del_all_batt_node(B_CHARGING);
+ if (system_wakeup_flag == true) {
+ del_all_batt_node(B_UNCHARGING);
+ system_wakeup_flag = false;
+ }
+ if (batt_head[B_UNCHARGING] == NULL) {
+ add_batt_node(B_UNCHARGING, clock, capacity);
+ } else {
+ add_batt_node(B_UNCHARGING, clock, capacity);
+ avg_factor[B_UNCHARGING] = update_factor(B_UNCHARGING);
+ }
+ estimated_time = (float)capacity * avg_factor[B_UNCHARGING];
+ update_time(A_TIMETOEMPTY, estimated_time);
+ }
+ return 0;
+}
+
+static Eina_Bool battinfo_cb(void *data)
+{
+ battinfo_calculation();
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int start_battinfo_gathering(int timeout)
+{
+ _I("Start battery gathering!");
+
+ if (timeout <= 0) {
+ _E("invalid timeout value [%d]!", timeout);
+ return -1;
+ }
+
+ old_capacity = 0;
+ battinfo_calculation();
+
+ if (timeout > 0) {
+ /* Using g_timer for gathering battery info */
+ timeout_id = ecore_timer_add(timeout,
+ (Ecore_Task_Cb)battinfo_cb, NULL);
+ }
+
+ return 0;
+}
+
+static void end_battinfo_gathering(void)
+{
+ _I("End battery gathering!");
+
+ if (timeout_id) {
+ ecore_timer_del(timeout_id);
+ timeout_id = NULL;
+ }
+
+ del_all_batt_node(B_UNCHARGING);
+ del_all_batt_node(B_CHARGING);
+}
+
+static DBusMessage *dbus_get_timetofull(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int val;
+
+ val = time_to_full;
+
+ _D("get time %d", val);
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &val);
+ return reply;
+}
+
+static DBusMessage *dbus_get_timetoempty(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int val;
+
+ val = time_to_empty;
+
+ _D("get time %d", val);
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &val);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { SIGNAL_TIMETOFULL, NULL, "i", dbus_get_timetofull },
+ { SIGNAL_TIMETOEMPTY, NULL, "i", dbus_get_timetoempty },
+ /* Add methods here */
+};
+
+static void battery_init(void *data)
+{
+ int ret;
+
+ /* init dbus interface */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+
+ start_battinfo_gathering(POLLING_TIME);
+}
+
+static void battery_exit(void *data)
+{
+ end_battinfo_gathering();
+}
+
+static const struct device_ops battery_time_device_ops = {
+ .name = "battery-time",
+ .init = battery_init,
+ .exit = battery_exit,
+};
+
+DEVICE_OPS_REGISTER(&battery_time_device_ops)
--- /dev/null
+[LOWBAT]
+#low battery level
+Normal=100
+Warning=15
+Critical=5
+PowerOff=1
+RealOff=0
+WarningMethod=warning
+CriticalMethod=critical
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __BATTERY_H__
+#define __BATTERY_H__
+
+#define BATTERY_LEVEL_CHECK_FULL 95
+#define BATTERY_LEVEL_CHECK_HIGH 15
+#define BATTERY_LEVEL_CHECK_LOW 5
+#define BATTERY_LEVEL_CHECK_CRITICAL 1
+
+#define LOWBAT_OPT_WARNING 1
+#define LOWBAT_OPT_POWEROFF 2
+#define LOWBAT_OPT_CHARGEERR 3
+#define LOWBAT_OPT_CHECK 4
+
+#define METHOD_NAME_MAX 32
+struct battery_config_info {
+ int normal;
+ int warning;
+ int critical;
+ int poweroff;
+ int realoff;
+};
+
+int battery_charge_err_low_act(void *data);
+int battery_charge_err_high_act(void *data);
+#endif /* __BATTERY_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/config-parser.h"
+#include "battery.h"
+#include "config.h"
+
+#define BAT_CONF_FILE "/etc/deviced/battery.conf"
+
+static int load_config(struct parse_result *result, void *user_data)
+{
+ struct battery_config_info *info = user_data;
+ char *name;
+ char *value;
+
+ _D("%s,%s,%s", result->section, result->name, result->value);
+
+ if (!info)
+ return -EINVAL;
+
+ if (!MATCH(result->section, "LOWBAT"))
+ return -EINVAL;
+
+ name = result->name;
+ value = result->value;
+ if (MATCH(name, "Normal"))
+ info->normal = atoi(value);
+ else if (MATCH(name, "Warning"))
+ info->warning = atoi(value);
+ else if (MATCH(name, "Critical"))
+ info->critical = atoi(value);
+ else if (MATCH(name, "PowerOff"))
+ info->poweroff = atoi(value);
+ else if (MATCH(name, "RealOff"))
+ info->realoff = atoi(value);
+
+ return 0;
+}
+
+void battery_config_load(struct battery_config_info *info)
+{
+ int ret;
+
+ ret = config_parse(BAT_CONF_FILE, load_config, info);
+ if (ret < 0)
+ _E("Failed to load %s, %d Use default value!", BAT_CONF_FILE, ret);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 __BATTERY_CONFIG_H__
+#define __BATTERY_CONFIG_H__
+
+#define BATTERY_FULL 100
+#define BATTERY_NORMAL BATTERY_FULL
+#define BATTERY_WARNING 15
+#define BATTERY_CRITICAL 5
+#define BATTERY_POWEROFF 1
+#define BATTERY_REALOFF 0
+
+void battery_config_load(struct battery_config_info *info);
+#endif /* __BATTERY_CONFIG_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdbool.h>
+#include <assert.h>
+#include <limits.h>
+#include <vconf.h>
+#include <fcntl.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "battery.h"
+#include "config.h"
+#include "core/log.h"
+#include "core/launch.h"
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "core/common.h"
+#include "core/list.h"
+#include "core/udev.h"
+#include "device-node.h"
+#include "display/setting.h"
+#include "display/poll.h"
+#include "core/edbus-handler.h"
+#include "power/power-handler.h"
+#include "apps/apps.h"
+#include "power-supply.h"
+
+#define CHARGE_POWERSAVE_FREQ_ACT "charge_powersave_freq_act"
+#define CHARGE_RELEASE_FREQ_ACT "charge_release_freq_act"
+
+#define POWER_OFF_CHECK_TIMER (30)
+
+#define BATTERY_CHARGING 65535
+#define BATTERY_UNKNOWN -1
+
+#define WARNING_LOW_BAT_ACT "warning_low_bat_act"
+#define CRITICAL_LOW_BAT_ACT "critical_low_bat_act"
+#define POWER_OFF_BAT_ACT "power_off_bat_act"
+#define CHARGE_BAT_ACT "charge_bat_act"
+#define CHARGE_CHECK_ACT "charge_check_act"
+#define CHARGE_ERROR_ACT "charge_error_act"
+#define CHARGE_ERROR_LOW_ACT "charge_error_low_act"
+#define CHARGE_ERROR_HIGH_ACT "charge_error_high_act"
+#define CHARGE_ERROR_OVP_ACT "charge_error_ovp_act"
+#define WAITING_INTERVAL 10
+
+#define LOWBAT_CPU_CTRL_ID "id6"
+#define LOWBAT_CPU_FREQ_RATE (0.7)
+
+#define POWER_OFF_UNLOCK 0
+#define POWER_OFF_LOCK 1
+
+struct lowbat_process_entry {
+ int old;
+ int now;
+ int (*func) (void *data);
+};
+
+static int cur_bat_state = BATTERY_UNKNOWN;
+static int cur_bat_capacity = -1;
+
+static struct battery_config_info battery_info = {
+ .normal = BATTERY_NORMAL,
+ .warning = BATTERY_WARNING,
+ .critical = BATTERY_CRITICAL,
+ .poweroff = BATTERY_POWEROFF,
+ .realoff = BATTERY_REALOFF,
+};
+
+static dd_list *lpe;
+static int scenario_count;
+static int power_off_lock = POWER_OFF_UNLOCK;
+static Ecore_Timer *power_off_timer;
+
+static int lowbat_popup(char *option);
+
+static int lowbat_initialized(void *data)
+{
+ static int status;
+
+ if (!data)
+ return status;
+
+ status = *(int *)data;
+ return status;
+}
+
+static int lowbat_scenario(int old, int now, void *data)
+{
+ dd_list *n;
+ struct lowbat_process_entry *scenario;
+ int found = 0;
+
+ if (old == now && battery.charge_now)
+ return found;
+ DD_LIST_FOREACH(lpe, n, scenario) {
+ if (old != scenario->old || now != scenario->now)
+ continue;
+ if (!scenario->func)
+ continue;
+ scenario->func(data);
+ found = 1;
+ break;
+ }
+ return found;
+}
+
+static int lowbat_add_scenario(int old, int now, int (*func)(void *data))
+{
+ struct lowbat_process_entry *scenario;
+
+ _I("%d %d, %x", old, now, func);
+
+ if (!func) {
+ _E("invalid func address!");
+ return -EINVAL;
+ }
+
+ scenario = malloc(sizeof(struct lowbat_process_entry));
+ if (!scenario) {
+ _E("Fail to malloc for notifier!");
+ return -ENOMEM;
+ }
+
+ scenario->old = old;
+ scenario->now = now;
+ scenario->func = func;
+
+ DD_LIST_APPEND(lpe, scenario);
+ scenario_count++;
+ return 0;
+}
+
+static void print_lowbat_state(unsigned int bat_percent)
+{
+#if 0
+ int i;
+ for (i = 0; i < BAT_MON_SAMPLES; i++)
+ _D("\t%d", recent_bat_percent[i]);
+#endif
+}
+
+static int power_execute(void *data)
+{
+ static const struct device_ops *ops;
+
+ FIND_DEVICE_INT(ops, POWER_OPS_NAME);
+
+ return ops->execute(data);
+}
+
+static int booting_done(void *data)
+{
+ static int done;
+ static int popup;
+
+ if (data == NULL) {
+ if (!done)
+ popup = 1;
+ goto out;
+ }
+ done = *(int *)data;
+ if (!done)
+ goto out;
+ _I("booting done");
+ if (popup) {
+ popup = 0;
+ lowbat_popup(NULL);
+ }
+out:
+ return done;
+}
+
+static void power_off_pm_lock(void)
+{
+ if (power_off_lock == POWER_OFF_UNLOCK) {
+ pm_lock_internal(INTERNAL_LOCK_LOWBAT, LCD_OFF, STAY_CUR_STATE, 0);
+ power_off_lock = POWER_OFF_LOCK;
+ }
+}
+
+static void power_off_pm_unlock(void)
+{
+ if (power_off_lock == POWER_OFF_LOCK) {
+ pm_unlock_internal(INTERNAL_LOCK_LOWBAT, LCD_OFF, PM_SLEEP_MARGIN);
+ power_off_lock = POWER_OFF_UNLOCK;
+ }
+}
+
+static Eina_Bool power_off_cb(void *data)
+{
+ power_off_pm_unlock();
+ power_execute(POWER_POWEROFF);
+ return EINA_FALSE;
+}
+
+void power_off_timer_start(void)
+{
+ if (power_off_timer)
+ return;
+ _I("power off after %d", POWER_OFF_CHECK_TIMER);
+ power_off_pm_lock();
+ power_off_timer = ecore_timer_add(POWER_OFF_CHECK_TIMER,
+ power_off_cb, NULL);
+ if (power_off_timer == NULL)
+ _E("fail to add battery init timer during booting");
+}
+
+void power_off_timer_stop(void)
+{
+ if (!power_off_timer)
+ return;
+ _I("cancel power off");
+ power_off_pm_unlock();
+ ecore_timer_del(power_off_timer);
+ power_off_timer = NULL;
+}
+
+static int lowbat_popup(char *option)
+{
+ static int launched_poweroff;
+ static int lowbat_popup_option;
+ int ret;
+ int r_disturb, s_disturb, r_block, s_block;
+ static char *value;
+
+ if (!option) {
+ if (!value)
+ return -1;
+ else
+ goto direct_launch;
+ }
+
+ if (strcmp(option, POWER_OFF_BAT_ACT))
+ launched_poweroff = 0;
+
+ if (!strcmp(option, CRITICAL_LOW_BAT_ACT)) {
+ value = "lowbattery_critical";
+ lowbat_popup_option = LOWBAT_OPT_CHECK;
+ } else if (!strcmp(option, WARNING_LOW_BAT_ACT)) {
+ value = "lowbattery_warning";
+ lowbat_popup_option = LOWBAT_OPT_WARNING;
+ } else if (!strcmp(option, POWER_OFF_BAT_ACT)) {
+ value = "poweroff";
+ lowbat_popup_option = LOWBAT_OPT_POWEROFF;
+ } else if (!strcmp(option, CHARGE_ERROR_ACT)) {
+ value = "chargeerr";
+ lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
+ } else if (!strcmp(option, CHARGE_ERROR_LOW_ACT)) {
+ value = "chargeerrlow";
+ lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
+ } else if (!strcmp(option, CHARGE_ERROR_HIGH_ACT)) {
+ value = "chargeerrhigh";
+ lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
+ } else if (!strcmp(option, CHARGE_ERROR_OVP_ACT)) {
+ value = "chargeerrovp";
+ lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
+ } else if (!strcmp(option, CHARGE_CHECK_ACT)) {
+ launched_poweroff = 0;
+ return 0;
+ } else
+ return -1;
+
+direct_launch:
+ _D("%s", value);
+ if (booting_done(NULL)) {
+
+ if (launched_poweroff == 1) {
+ _I("will be foreced power off");
+ power_execute(POWER_POWEROFF);
+ return 0;
+ }
+
+ if (lowbat_popup_option == LOWBAT_OPT_POWEROFF)
+ launched_poweroff = 1;
+
+ ret = launch_system_app(APP_DEFAULT,
+ 2, APP_KEY_TYPE, "remove_battery_popups");
+ if (ret < 0)
+ _E("Failed to close all of battery popups");
+
+ r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
+ r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
+ if ((r_disturb != 0 && r_block != 0) ||
+ (s_disturb == 0 && s_block == 0) ||
+ lowbat_popup_option == LOWBAT_OPT_CHARGEERR)
+ pm_change_internal(getpid(), LCD_NORMAL);
+ else
+ _I("block LCD");
+
+ return launch_system_app(APP_DEFAULT,
+ 2, APP_KEY_TYPE, value);
+ } else {
+ _D("boot-animation running yet");
+ }
+
+ return 0;
+}
+
+static int battery_check_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CHARGE_CHECK_ACT);
+ return 0;
+}
+
+static int battery_warning_low_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(WARNING_LOW_BAT_ACT);
+ return 0;
+}
+
+static int battery_critical_low_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CRITICAL_LOW_BAT_ACT);
+ return 0;
+}
+
+int battery_power_off_act(void *data)
+{
+ lowbat_popup(CRITICAL_LOW_BAT_ACT);
+ power_off_timer_start();
+ return 0;
+}
+
+int battery_charge_err_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CHARGE_ERROR_ACT);
+ return 0;
+}
+
+int battery_charge_err_low_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CHARGE_ERROR_LOW_ACT);
+ return 0;
+}
+
+int battery_charge_err_high_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CHARGE_ERROR_HIGH_ACT);
+ return 0;
+}
+
+int battery_charge_err_ovp_act(void *data)
+{
+ power_off_timer_stop();
+ lowbat_popup(CHARGE_ERROR_OVP_ACT);
+ return 0;
+}
+
+static void lowbat_scenario_init(void)
+{
+ lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
+ lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
+ lowbat_add_scenario(battery_info.warning, battery_info.warning, battery_warning_low_act);
+ lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.warning, battery_info.realoff, battery_power_off_act);
+ lowbat_add_scenario(battery_info.critical, battery_info.critical, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.critical, battery_info.realoff, battery_power_off_act);
+ lowbat_add_scenario(battery_info.poweroff, battery_info.poweroff, battery_critical_low_act);
+ lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.normal, battery_check_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.warning, battery_check_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.critical, battery_check_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.poweroff, battery_check_act);
+ lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
+}
+
+static void battery_level_send_system_event(int bat_percent)
+{
+ bundle *b;
+ const char *str;
+ static const char *prev;
+
+ if (bat_percent > BATTERY_LEVEL_CHECK_FULL)
+ str = EVT_VAL_BATTERY_LEVEL_FULL;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH)
+ str = EVT_VAL_BATTERY_LEVEL_HIGH;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_LOW)
+ str = EVT_VAL_BATTERY_LEVEL_LOW;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL)
+ str = EVT_VAL_BATTERY_LEVEL_CRITICAL;
+ else
+ str = EVT_VAL_BATTERY_LEVEL_EMPTY;
+
+ if (prev == str)
+ return;
+
+ prev = str;
+
+ _D("system_event(%s)", str);
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_BATTERY_LEVEL_STATUS, str);
+ eventsystem_send_system_event(SYS_EVENT_BATTERY_LEVEL_STATUS, b);
+ bundle_free(b);
+}
+
+static void change_lowbat_level(int bat_percent)
+{
+ int prev, now;
+
+ if (cur_bat_capacity == bat_percent)
+ return;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev) < 0) {
+ _E("vconf_get_int() failed");
+ return;
+ }
+
+ if (bat_percent > BATTERY_LEVEL_CHECK_FULL)
+ now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH)
+ now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_LOW)
+ now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
+ else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL)
+ now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
+ else
+ now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
+
+ if (prev != now)
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
+}
+
+static int lowbat_process(int bat_percent, void *ad)
+{
+ static int online;
+ int new_bat_capacity;
+ int new_bat_state;
+ int vconf_state = -1;
+ int ret = 0;
+ int status = -1;
+ bool low_bat = false;
+ int result = 0;
+ int lock = -1;
+
+ new_bat_capacity = bat_percent;
+ if (new_bat_capacity < 0)
+ return -EINVAL;
+ change_lowbat_level(new_bat_capacity);
+ battery_level_send_system_event(new_bat_capacity);
+
+ if (new_bat_capacity != cur_bat_capacity) {
+ _D("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
+ if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
+ cur_bat_capacity = new_bat_capacity;
+ power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, new_bat_capacity);
+ }
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state) < 0) {
+ _E("vconf_get_int() failed");
+ result = -EIO;
+ goto exit;
+ }
+
+ if (new_bat_capacity <= battery_info.realoff) {
+ if (battery.charge_now) {
+ new_bat_state = battery_info.poweroff;
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
+ status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
+ } else {
+ new_bat_state = battery_info.realoff;
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
+ status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
+ }
+ } else if (new_bat_capacity <= battery_info.poweroff) {
+ new_bat_state = battery_info.poweroff;
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
+ status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
+ } else if (new_bat_capacity <= battery_info.critical) {
+ new_bat_state = battery_info.critical;
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
+ status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
+ } else if (new_bat_capacity <= battery_info.warning) {
+ new_bat_state = battery_info.warning;
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
+ status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
+ } else {
+ new_bat_state = battery_info.normal;
+ if (new_bat_capacity == BATTERY_FULL) {
+ if (battery.charge_full) {
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
+ status = VCONFKEY_SYSMAN_BAT_FULL;
+ } else {
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
+ status = VCONFKEY_SYSMAN_BAT_NORMAL;
+ }
+ } else {
+ if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
+ status = VCONFKEY_SYSMAN_BAT_NORMAL;
+ }
+ }
+
+ if (status != -1) {
+ lock = pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
+ ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, status);
+ power_supply_broadcast(CHARGE_LEVEL_SIGNAL, status);
+ if (update_pm_setting)
+ update_pm_setting(SETTING_LOW_BATT, status);
+ }
+
+ if (ret < 0) {
+ result = -EIO;
+ goto exit;
+ }
+
+ if (new_bat_capacity <= battery_info.warning)
+ low_bat = true;
+
+ device_notify(DEVICE_NOTIFIER_LOWBAT, (void *)low_bat);
+
+ if (battery.online == POWER_SUPPLY_TYPE_UNKNOWN)
+ goto exit;
+ if (cur_bat_state == new_bat_state &&
+ online == battery.online)
+ goto exit;
+ online = battery.online;
+ if (cur_bat_state == BATTERY_UNKNOWN)
+ cur_bat_state = battery_info.normal;
+ result = lowbat_scenario(cur_bat_state, new_bat_state, NULL);
+ if (result)
+ _I("cur %d, new %d(capacity %d)",
+ cur_bat_state, new_bat_state, bat_percent);
+ cur_bat_state = new_bat_state;
+exit:
+ if (lock == 0)
+ pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
+
+ return result;
+}
+
+static int check_lowbat_percent(int *pct)
+{
+ int bat_percent;
+
+ bat_percent = battery.capacity;
+ if (bat_percent < 0) {
+ _E("[BATMON] Cannot read battery gage. stop read fuel gage");
+ return -ENODEV;
+ }
+ if (bat_percent > 100)
+ bat_percent = 100;
+ change_lowbat_level(bat_percent);
+ battery_level_send_system_event(bat_percent);
+ *pct = bat_percent;
+ return 0;
+}
+
+static void lowbat_monitor(void *data)
+{
+ int bat_percent, r;
+
+ r = lowbat_initialized(NULL);
+ if (!r)
+ return;
+
+ if (data == NULL) {
+ r = check_lowbat_percent(&bat_percent);
+ if (r < 0)
+ return;
+ } else
+ bat_percent = *(int *)data;
+ print_lowbat_state(bat_percent);
+ lowbat_process(bat_percent, NULL);
+}
+
+static int lowbat_monitor_init(void *data)
+{
+ int status = 1;
+
+ lowbat_initialized(&status);
+
+ /* it's called just this once. */
+ unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
+
+ /* load battery configuration file */
+ battery_config_load(&battery_info);
+ _I("battery conf %d %d %d %d %d", battery_info.normal, battery_info.warning,
+ battery_info.critical, battery_info.poweroff, battery_info.realoff);
+
+ lowbat_scenario_init();
+ check_lowbat_percent(&battery.capacity);
+ lowbat_process(battery.capacity, NULL);
+ return 0;
+}
+
+static void lowbat_init(void *data)
+{
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
+}
+
+static void lowbat_exit(void *data)
+{
+ int status = 0;
+
+ lowbat_initialized(&status);
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+}
+
+static int lowbat_execute(void *data)
+{
+ lowbat_monitor(data);
+ return 0;
+}
+
+static const struct device_ops lowbat_device_ops = {
+ .name = "lowbat",
+ .init = lowbat_init,
+ .execute = lowbat_execute,
+ .exit = lowbat_exit,
+};
+
+DEVICE_OPS_REGISTER(&lowbat_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <vconf.h>
+#include <Ecore.h>
+#include <device-node.h>
+#include <bundle.h>
+#include <eventsystem.h>
+#include <hw/battery.h>
+
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "core/udev.h"
+#include "core/log.h"
+#include "core/config-parser.h"
+#include "display/poll.h"
+#include "display/setting.h"
+#include "apps/apps.h"
+#include "power-supply.h"
+#include "battery.h"
+
+#define BATTERY_NAME "battery"
+#define CHARGEFULL_NAME "Full"
+#define CHARGENOW_NAME "Charging"
+#define DISCHARGE_NAME "Discharging"
+#define NOTCHARGE_NAME "Not charging"
+#define OVERHEAT_NAME "Overheat"
+#define TEMPCOLD_NAME "Cold"
+#define OVERVOLT_NAME "Over voltage"
+
+#define BUFF_MAX 255
+
+#define SIGNAL_CHARGEERR_RESPONSE "ChargeErrResponse"
+#define SIGNAL_TEMP_GOOD "TempGood"
+
+#define ABNORMAL_CHECK_TIMER_INTERVAL 60
+
+#define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
+#define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
+#define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
+
+#define RETRY_MAX 5
+#define BATTERY_CHECK_TIMER_INTERVAL (0.5)
+
+enum power_supply_init_type {
+ POWER_SUPPLY_NOT_READY = 0,
+ POWER_SUPPLY_INITIALIZED = 1,
+};
+
+static void uevent_power_handler(struct udev_device *dev);
+static const struct uevent_handler uh = {
+ .subsystem = POWER_SUBSYSTEM,
+ .uevent_func = uevent_power_handler,
+};
+
+struct battery_status battery;
+static int noti_id;
+static Ecore_Timer *power_timer;
+static Ecore_Timer *abnormal_timer;
+
+static int booting_done(void *data);
+
+static struct battery_device *battery_dev;
+
+static void lowbat_execute(void *data)
+{
+ static const struct device_ops *lowbat_ops;
+
+ FIND_DEVICE_VOID(lowbat_ops, "lowbat");
+ device_execute(lowbat_ops, data);
+}
+
+static void pm_check_and_change(int bInserted)
+{
+ static int old = -1;
+
+ if (old == bInserted)
+ return;
+ old = bInserted;
+ pm_change_internal(getpid(), LCD_NORMAL);
+}
+
+static int changed_battery_cf(enum present_type status)
+{
+ char *value;
+
+ if (status == PRESENT_ABNORMAL)
+ value = "battdisconnect";
+ else
+ value = "remove_battery_popups";
+
+ return launch_system_app(APP_DEFAULT,
+ 2, APP_KEY_TYPE, value);
+}
+
+static void abnormal_popup_timer_init(void)
+{
+ if (abnormal_timer == NULL)
+ return;
+ ecore_timer_del(abnormal_timer);
+ abnormal_timer = NULL;
+ _I("delete health timer");
+}
+
+static void health_status_broadcast(void)
+{
+ broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
+ SIGNAL_TEMP_GOOD, NULL, NULL);
+}
+
+
+static void health_timer_reset(void)
+{
+ abnormal_timer = NULL;
+}
+
+static Eina_Bool health_timer_cb(void *data)
+{
+ health_timer_reset();
+
+ if (battery.health == HEALTH_GOOD)
+ return EINA_FALSE;
+
+ _I("popup - Battery health status is not good");
+ device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
+ pm_change_internal(getpid(), LCD_NORMAL);
+ pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
+ if (battery.temp == TEMP_LOW)
+ battery_charge_err_low_act(NULL);
+ else if (battery.temp == TEMP_HIGH)
+ battery_charge_err_high_act(NULL);
+ return EINA_FALSE;
+}
+
+static void abnormal_popup_edbus_signal_handler(void *data, DBusMessage *msg)
+{
+ if (battery.health == HEALTH_GOOD)
+ return;
+ _I("restart health timer");
+ abnormal_timer = ecore_timer_add(ABNORMAL_CHECK_TIMER_INTERVAL,
+ health_timer_cb, NULL);
+ if (abnormal_timer == NULL)
+ _E("Fail to add abnormal check timer");
+}
+
+static void full_noti_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+ DBusError r_err;
+ int ret, id;
+
+ if (!msg)
+ return;
+
+ dbus_error_init(&r_err);
+ ret = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &id, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message [%s:%s]", r_err.name, r_err.message);
+ dbus_error_free(&r_err);
+ return;
+ }
+
+ noti_id = id;
+ _D("Inserted battery full noti : %d", noti_id);
+}
+
+static int check_power_supply_noti(void)
+{
+#ifdef MICRO_DD
+ int r_disturb, s_disturb, r_block, s_block;
+ r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
+ r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
+ if ((r_disturb != 0 && r_block != 0) ||
+ (s_disturb == 0 && s_block == 0)) {
+ return 1;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+static int send_full_noti(enum charge_full_type state)
+{
+ int ret = 0;
+ int noti;
+ int retry;
+ char str_id[32];
+ char *arr[1];
+
+ noti = check_power_supply_noti();
+
+ if (!noti)
+ return noti;
+
+ switch (state) {
+ case CHARGING_FULL:
+ for (retry = RETRY_MAX; retry > 0; retry--) {
+ ret = dbus_method_async_with_reply(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ METHOD_FULL_NOTI_ON,
+ NULL, NULL, full_noti_cb, -1, NULL);
+ if (ret == 0) {
+ _D("Created battery full noti");
+ return ret;
+ }
+ }
+ _E("Failed to call dbus method (err: %d)", ret);
+ break;
+ case CHARGING_NOT_FULL:
+ if (noti_id <= 0)
+ return -EPERM;
+ snprintf(str_id, sizeof(str_id), "%d", noti_id);
+ arr[0] = str_id;
+ for (retry = RETRY_MAX; retry > 0; retry--) {
+ ret = dbus_method_async(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ METHOD_FULL_NOTI_OFF,
+ "i", arr);
+ if (ret == 0) {
+ _D("Deleted battery full noti");
+ noti_id = 0;
+ return ret;
+ }
+ }
+ _E("Failed to call dbus method (err: %d)", ret);
+ break;
+ }
+ return ret;
+}
+
+static int send_charge_noti(void)
+{
+ int ret = 0;
+ int retry;
+
+ for (retry = RETRY_MAX; retry > 0; retry--) {
+ ret = dbus_method_async(POPUP_BUS_NAME,
+ POPUP_PATH_NOTI,
+ POPUP_INTERFACE_NOTI,
+ METHOD_CHARGE_NOTI_ON,
+ NULL, NULL);
+ if (ret == 0) {
+ _D("Created battery charge noti");
+ return ret;
+ }
+ }
+ _E("Failed to call dbus method (err: %d)", ret);
+ return ret;
+}
+
+static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
+{
+ static int charger = CHARGER_DISCHARGING;
+ static int full = CHARGING_NOT_FULL;
+ int ret;
+
+ if (type == DEVICE_NOTI_BATT_CHARGE) {
+ if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
+ send_charge_noti();
+ charger = CHARGER_CHARGING;
+ } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING) {
+ charger = CHARGER_DISCHARGING;
+ }
+ } else if (type == DEVICE_NOTI_BATT_FULL) {
+ if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
+ ret = send_full_noti(CHARGING_FULL);
+ if (ret == 0)
+ full = CHARGING_FULL;
+ } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
+ ret = send_full_noti(CHARGING_NOT_FULL);
+ if (ret == 0)
+ full = CHARGING_NOT_FULL;
+ }
+ }
+}
+
+void power_supply_broadcast(char *sig, int status)
+{
+ static int old;
+ static char sig_old[32];
+ char *arr[1];
+ char str_status[32];
+
+ if (strcmp(sig_old, sig) == 0 && old == status)
+ return;
+
+ _D("%s %d", sig, status);
+
+ old = status;
+ snprintf(sig_old, sizeof(sig_old), "%s", sig);
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+
+ broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
+ sig, "i", arr);
+}
+
+static void noti_batt_full(void)
+{
+ static int bat_full_noti;
+ int noti;
+
+ if (!battery.charge_full && bat_full_noti == 1) {
+ power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
+ bat_full_noti = 0;
+ /* off the full charge state */
+ device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)false);
+ }
+ if (battery.charge_full && bat_full_noti == 0) {
+ power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
+ bat_full_noti = 1;
+ /* turn on LCD, if battery is full charged */
+ noti = check_power_supply_noti();
+ if (noti)
+ pm_change_internal(INTERNAL_LOCK_BATTERY_FULL,
+ LCD_NORMAL);
+ else
+ _I("block LCD");
+ /* on the full charge state */
+ device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)true);
+ }
+}
+
+static void check_power_supply(int state)
+{
+ pm_check_and_change(state);
+ if (update_pm_setting)
+ update_pm_setting(SETTING_CHARGING, state);
+}
+
+static void charger_state_send_system_event(int state)
+{
+ bundle *b;
+ const char *str;
+
+ switch (state) {
+ case CHARGE_STATUS_CHARGING:
+ str = EVT_VAL_BATTERY_CHARGER_CHARGING;
+ break;
+ case CHARGE_STATUS_FULL:
+ case CHARGE_STATUS_DISCHARGING:
+ str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
+ break;
+ case CHARGE_STATUS_CONNECTED:
+ str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
+ break;
+ case CHARGE_STATUS_DISCONNECTED:
+ str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
+ break;
+ default:
+ _E("invalid parameter(%d)", state);
+ return;
+ }
+
+ _D("system_event(%s)", str);
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_BATTERY_CHARGER_STATUS, str);
+ eventsystem_send_system_event(SYS_EVENT_BATTERY_CHARGER_STATUS, b);
+ bundle_free(b);
+}
+
+static void update_present(enum battery_noti_status status)
+{
+ static int old = DEVICE_NOTI_OFF;
+ enum present_type present;
+
+ if (old == status)
+ return;
+ _I("charge %d present %d", battery.charge_now, battery.present);
+ old = status;
+ pm_change_internal(getpid(), LCD_NORMAL);
+ if (status == DEVICE_NOTI_ON) {
+ present = PRESENT_ABNORMAL;
+ device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)PRESENT_ABNORMAL);
+ pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
+ } else {
+ present = PRESENT_NORMAL;
+ device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)PRESENT_NORMAL);
+ pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
+ }
+ changed_battery_cf(present);
+}
+
+static void update_health(enum battery_noti_status status)
+{
+ static int old = DEVICE_NOTI_OFF;
+
+ if (old == status)
+ return;
+ _I("charge %d health %d", battery.charge_now, battery.health);
+ old = status;
+
+ pm_change_internal(getpid(), LCD_NORMAL);
+ if (status == DEVICE_NOTI_ON) {
+ _I("popup - Battery health status is not good");
+ device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
+ pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
+ if (battery.temp == TEMP_LOW)
+ battery_charge_err_low_act(NULL);
+ else if (battery.temp == TEMP_HIGH)
+ battery_charge_err_high_act(NULL);
+ } else {
+ device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_GOOD);
+ pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
+ health_status_broadcast();
+ abnormal_popup_timer_init();
+ }
+}
+
+static void update_ovp(enum battery_noti_status status)
+{
+ static int old = DEVICE_NOTI_OFF;
+
+ if (old == status)
+ return;
+ _I("charge %d ovp %d", battery.charge_now, battery.ovp);
+ old = status;
+ pm_change_internal(getpid(), LCD_NORMAL);
+ if (status == DEVICE_NOTI_ON)
+ device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_ABNORMAL);
+ else
+ device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_NORMAL);
+}
+
+static void check_battery_status(void)
+{
+ static int old = DEVICE_CHANGE_NORMAL;
+ int status;
+
+ if (battery.charge_now == CHARGER_ABNORMAL &&
+ (battery.health == HEALTH_BAD || battery.present == PRESENT_ABNORMAL))
+ status = DEVICE_CHANGE_ABNORMAL;
+ else if (battery.ovp == OVP_ABNORMAL)
+ status = DEVICE_CHANGE_ABNORMAL;
+ else
+ status = DEVICE_CHANGE_NORMAL;
+ if (old == status)
+ return;
+ old = status;
+
+ if (battery.charge_now == CHARGER_ABNORMAL) {
+ if (battery.health == HEALTH_BAD) {
+ update_health(DEVICE_NOTI_ON);
+ return;
+ } else if (battery.present == PRESENT_ABNORMAL) {
+ update_present(DEVICE_NOTI_ON);
+ return;
+ }
+ }
+ if (battery.ovp == OVP_ABNORMAL) {
+ update_ovp(DEVICE_NOTI_ON);
+ return;
+ }
+
+ if (battery.charge_now != CHARGER_ABNORMAL &&
+ status == DEVICE_CHANGE_NORMAL) {
+ update_health(DEVICE_NOTI_OFF);
+ update_ovp(DEVICE_NOTI_OFF);
+ update_present(DEVICE_NOTI_OFF);
+ }
+}
+
+static void check_online(void)
+{
+ static int old_online;
+ static int old_charge_status;
+ int charge_status;
+
+ if (battery.charge_status == CHARGE_STATUS_FULL)
+ charge_status = CHARGE_STATUS_DISCHARGING;
+ else
+ charge_status = battery.charge_status;
+
+ if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
+ old_online == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
+ old_online = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
+ vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
+ power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
+ check_power_supply(old_online);
+ charger_state_send_system_event(CHARGE_STATUS_CONNECTED);
+ if (charge_status != old_charge_status)
+ charger_state_send_system_event(charge_status);
+
+ } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
+ old_online == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
+ old_online = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
+ vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
+ power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
+ check_power_supply(old_online);
+ if (charge_status != old_charge_status)
+ charger_state_send_system_event(charge_status);
+ charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED);
+
+ } else {
+ if (charge_status != old_charge_status)
+ charger_state_send_system_event(charge_status);
+ }
+
+ old_charge_status = charge_status;
+}
+
+static void check_charge_status(const char *env_value)
+{
+ if (env_value == NULL)
+ return;
+
+ _D("Charge Status(%s)", env_value);
+
+ if (strncmp(env_value, CHARGEFULL_NAME,
+ sizeof(CHARGEFULL_NAME)) == 0)
+ battery.charge_status = CHARGE_STATUS_FULL;
+ else if (strncmp(env_value, CHARGENOW_NAME,
+ sizeof(CHARGENOW_NAME)) == 0)
+ battery.charge_status = CHARGE_STATUS_CHARGING;
+ else if (strncmp(env_value, DISCHARGE_NAME,
+ sizeof(DISCHARGE_NAME)) == 0)
+ battery.charge_status = CHARGE_STATUS_DISCHARGING;
+ else if (strncmp(env_value, NOTCHARGE_NAME,
+ sizeof(NOTCHARGE_NAME)) == 0)
+ battery.charge_status = CHARGE_STATUS_NOT_CHARGING;
+ else
+ battery.charge_status = CHARGE_STATUS_UNKNOWN;
+
+ if (battery.charge_status == CHARGE_STATUS_FULL) {
+ battery.charge_full = CHARGING_FULL;
+ battery.charge_now = CHARGER_DISCHARGING;
+ } else if (battery.charge_status == CHARGE_STATUS_CHARGING) {
+ battery.charge_full = CHARGING_NOT_FULL;
+ battery.charge_now = CHARGER_CHARGING;
+ } else if (battery.charge_status == CHARGE_STATUS_DISCHARGING) {
+ battery.charge_full = CHARGING_NOT_FULL;
+ battery.charge_now = CHARGER_DISCHARGING;
+ } else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING) {
+ battery.charge_full = CHARGING_NOT_FULL;
+ battery.charge_now = CHARGER_ABNORMAL;
+ } else {
+ battery.charge_full = CHARGING_NOT_FULL;
+ battery.charge_now = CHARGER_DISCHARGING;
+ }
+}
+
+static void check_health_status(const char *env_value)
+{
+ if (env_value == NULL) {
+ battery.health = HEALTH_GOOD;
+ battery.temp = TEMP_LOW;
+ battery.ovp = OVP_NORMAL;
+ return;
+ }
+ if (strncmp(env_value, OVERHEAT_NAME,
+ sizeof(OVERHEAT_NAME)) == 0) {
+ battery.health = HEALTH_BAD;
+ battery.temp = TEMP_HIGH;
+ battery.ovp = OVP_NORMAL;
+ } else if (strncmp(env_value, TEMPCOLD_NAME,
+ sizeof(TEMPCOLD_NAME)) == 0) {
+ battery.health = HEALTH_BAD;
+ battery.temp = TEMP_LOW;
+ battery.ovp = OVP_NORMAL;
+ } else if (strncmp(env_value, OVERVOLT_NAME,
+ sizeof(OVERVOLT_NAME)) == 0) {
+ battery.health = HEALTH_GOOD;
+ battery.temp = TEMP_LOW;
+ battery.ovp = OVP_ABNORMAL;
+ } else {
+ battery.health = HEALTH_GOOD;
+ battery.temp = TEMP_LOW;
+ battery.ovp = OVP_NORMAL;
+ }
+}
+
+static void check_online_status(const char *env_value)
+{
+ if (env_value == NULL)
+ return;
+ battery.online = atoi(env_value);
+}
+
+static void check_present_status(const char *env_value)
+{
+ if (env_value == NULL) {
+ battery.present = PRESENT_NORMAL;
+ return;
+ }
+ battery.present = atoi(env_value);
+}
+
+static void check_capacity_status(const char *env_value)
+{
+ if (env_value == NULL)
+ return;
+ battery.capacity = atoi(env_value);
+}
+
+static void process_power_supply(void *data)
+{
+ static struct battery_status old;
+
+ if (old.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
+ power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
+ }
+
+ lowbat_execute(data);
+ check_online();
+ if (old.charge_full != battery.charge_full)
+ noti_batt_full();
+
+ old.capacity = battery.capacity;
+ old.online = battery.online;
+ old.charge_status = battery.charge_status;
+ old.charge_now = battery.charge_now;
+ old.charge_full = battery.charge_full;
+
+ check_battery_status();
+ device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
+ device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
+}
+
+static void uevent_power_handler(struct udev_device *dev)
+{
+ struct udev_list_entry *list_entry;
+ const char *env_name;
+ const char *env_value;
+ bool matched = false;
+ int ret;
+
+ udev_list_entry_foreach(list_entry,
+ udev_device_get_properties_list_entry(dev)) {
+ env_name = udev_list_entry_get_name(list_entry);
+ if (!env_name)
+ continue;
+
+ if (!strncmp(env_name, CHARGE_NAME, sizeof(CHARGE_NAME))) {
+ env_value = udev_list_entry_get_value(list_entry);
+ if (!env_value)
+ continue;
+ if (!strncmp(env_value, BATTERY_NAME,
+ sizeof(BATTERY_NAME))) {
+ matched = true;
+ break;
+ }
+ }
+ }
+
+ if (!matched)
+ return;
+
+ env_value = udev_device_get_property_value(dev, CHARGE_STATUS);
+ check_charge_status(env_value);
+ env_value = udev_device_get_property_value(dev, CHARGE_ONLINE);
+ check_online_status(env_value);
+ env_value = udev_device_get_property_value(dev, CHARGE_HEALTH);
+ check_health_status(env_value);
+ env_value = udev_device_get_property_value(dev, CHARGE_PRESENT);
+ check_present_status(env_value);
+ env_value = udev_device_get_property_value(dev, CAPACITY);
+ check_capacity_status(env_value);
+
+ ret = booting_done(NULL);
+ if (ret) {
+ if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
+ else
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
+ }
+
+ process_power_supply(&battery.capacity);
+}
+
+static void battery_state(struct battery_info *info)
+{
+ if (!info)
+ return;
+
+ _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%s) Pres(%d) OVP(%s) Curr(%d,%d)",
+ info->status,
+ battery.charge_now == CHARGER_CHARGING ? "Charging"
+ : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
+ info->power_source,
+ info->online,
+ info->capacity,
+ info->health,
+ battery.temp == TEMP_LOW ? "Low" : "High",
+ info->present,
+ battery.ovp == OVP_NORMAL ? "X" : "O",
+ info->current_now,
+ info->current_average);
+}
+
+static void battery_changed(struct battery_info *info, void *data)
+{
+ int ret;
+
+ if (!info)
+ return;
+
+ if (info->status) {
+ snprintf(battery.status_s, sizeof(battery.status_s),
+ "%s", info->status);
+ check_charge_status(info->status);
+ } else
+ battery.status_s[0] = '\0';
+
+ if (info->health) {
+ snprintf(battery.health_s, sizeof(battery.health_s),
+ "%s", info->health);
+ check_health_status(info->health);
+ } else
+ battery.health_s[0] = '\0';
+
+ if (info->power_source)
+ snprintf(battery.power_source_s, sizeof(battery.power_source_s),
+ "%s", info->power_source);
+ else
+ battery.power_source_s[0] = '\0';
+
+ battery.online = info->online;
+ battery.present = info->present;
+ battery.capacity = info->capacity;
+ battery.current_now = info->current_now;
+ battery.current_average = info->current_average;
+
+ battery_state(info);
+
+ ret = booting_done(NULL);
+ if (ret) {
+ if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
+ else
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
+ }
+
+ process_power_supply(&battery.capacity);
+
+}
+
+static int lowbat_read(int *val)
+{
+ int r;
+
+ if (!val)
+ return -EINVAL;
+
+ r = sys_get_int("/sys/class/power_supply/battery/capacity", val);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void battery_get_capacity(struct battery_info *info, void *data)
+{
+ int *capa = data;
+
+ if (info && info->capacity >= 0)
+ *capa = info->capacity;
+}
+
+static void power_supply_status_init(void)
+{
+ static int charge_now = -1;
+ static int charge_full = -1;
+ static int capacity = -1;
+ int pct;
+ int r;
+
+ if (battery_dev && battery_dev->get_current_state) {
+ pct = -1;
+ r = battery_dev->get_current_state(battery_get_capacity, &pct);
+ if (r < 0 || pct < 0) {
+ _E("Failed to get battery capacity (capa:%d, ret:%d)", pct, r);
+ return;
+ }
+ } else {
+ r = lowbat_read(&pct);
+ if (r < 0) {
+ _E("fail to read capacity data : %d", r);
+ return;
+ }
+ }
+
+ battery.capacity = pct;
+ battery.health = HEALTH_GOOD;
+ battery.ovp = OVP_NORMAL;
+ battery.present = PRESENT_NORMAL;
+ battery.temp = TEMP_LOW;
+
+ if (charge_now == battery.charge_now &&
+ charge_full == battery.charge_full &&
+ capacity == battery.capacity)
+ return;
+
+ _I("charging %d full %d capacity %d", battery.charge_now, battery.charge_full, battery.capacity);
+
+ if (charge_now != battery.charge_now) {
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
+ power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
+ }
+ if (capacity != battery.capacity) {
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
+ power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity);
+ }
+
+ charge_now = battery.charge_now;
+ charge_full = battery.charge_full;
+ capacity = battery.capacity;
+}
+
+static Eina_Bool power_supply_update(void *data)
+{
+ power_supply_status_init();
+ return EINA_TRUE;
+}
+
+static void power_supply_timer_start(void)
+{
+ _D("battery init timer during booting");
+ power_timer = ecore_timer_add(BATTERY_CHECK_TIMER_INTERVAL,
+ power_supply_update, NULL);
+ if (power_timer == NULL)
+ _E("fail to add battery init timer during booting");
+}
+
+static void power_supply_timer_stop(void)
+{
+ _D("battery init timer during booting");
+ if (!power_timer)
+ return;
+ ecore_timer_del(power_timer);
+ power_timer = NULL;
+}
+
+static DBusMessage *dbus_get_charger_status(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &ret) < 0) {
+ _E("vconf_get_int() failed");
+ ret = -EIO;
+ }
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_get_charge_now(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = battery.charge_now;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_get_charge_level(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &ret) < 0) {
+ _E("vconf_get_int() failed");
+ ret = -EIO;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_get_percent(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = battery.capacity;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_get_percent_raw(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = -ENOTSUP;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_is_full(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = battery.charge_full;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_get_health(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = battery.health;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *dbus_power_supply_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret = 0;
+ int argc;
+ char *type_str;
+ char *argv[5];
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv[0],
+ DBUS_TYPE_STRING, &argv[1],
+ DBUS_TYPE_STRING, &argv[2],
+ DBUS_TYPE_STRING, &argv[3],
+ DBUS_TYPE_STRING, &argv[4], DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+ check_capacity_status(argv[0]);
+ check_charge_status(argv[1]);
+ check_health_status(argv[2]);
+ check_online_status(argv[3]);
+ check_present_status(argv[4]);
+ _I("%d %d %d %d %d %d %d %d",
+ battery.capacity,
+ battery.charge_full,
+ battery.charge_now,
+ battery.health,
+ battery.online,
+ battery.ovp,
+ battery.present,
+ battery.temp);
+
+ if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
+ else
+ power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
+
+ process_power_supply(&battery.capacity);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static void battery_get_info(struct battery_info *info, void *data)
+{
+ struct battery_info *bat = data;
+
+ if (!info || !bat)
+ return;
+
+ bat->status = strdup(info->status);
+ bat->health = strdup(info->health);
+ bat->power_source = strdup(info->power_source);
+ bat->online = info->online;
+ bat->present = info->present;
+ bat->capacity = info->capacity;
+ bat->current_now = info->current_now;
+ bat->current_average = info->current_average;
+}
+
+static DBusMessage *dbus_get_battery_info(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret, val;
+ const char *str;
+ struct battery_info info = { 0, };
+
+ if (battery_dev && battery_dev->get_current_state) {
+ ret = battery_dev->get_current_state(battery_get_info, &info);
+ if (ret < 0)
+ _E("Failed to get battery info (%d)", ret);
+
+ battery_changed(&info, NULL);
+ free(info.status);
+ free(info.health);
+ free(info.power_source);
+ } else {
+ if (battery.charge_status == CHARGE_STATUS_FULL)
+ str = CHARGEFULL_NAME;
+ else if (battery.charge_status == CHARGE_STATUS_CHARGING)
+ str = CHARGENOW_NAME;
+ else if (battery.charge_status == CHARGE_STATUS_DISCHARGING)
+ str = DISCHARGE_NAME;
+ else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING)
+ str = NOTCHARGE_NAME;
+ else
+ str = "Unknown";
+ snprintf(battery.status_s, sizeof(battery.status_s), "%s", str);
+
+ if (battery.health == HEALTH_GOOD) {
+ if (battery.temp == TEMP_LOW && battery.ovp == OVP_ABNORMAL)
+ str = OVERVOLT_NAME;
+ else
+ str = "Good";
+ } else { /* HEALTH_BAD */
+ if (battery.temp == TEMP_HIGH)
+ str = OVERHEAT_NAME;
+ else /* TEMP_LOW */
+ str = TEMPCOLD_NAME;
+ }
+ snprintf(battery.health_s, sizeof(battery.health_s), "%s", str);
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
+ val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
+ str = POWER_SOURCE_USB;
+ else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
+ val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
+ str = POWER_SOURCE_AC;
+ else
+ str = POWER_SOURCE_NONE;
+ snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
+
+ battery.current_now = -1; /* Not supported */
+ battery.current_average = -1; /* Not supported */
+ ret = 0;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ str = battery.status_s;
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &str);
+ str = battery.health_s;
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &str);
+ str = battery.power_source_s;
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &str);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(battery.online));
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(battery.present));
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(battery.capacity));
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(battery.current_now));
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(battery.current_average));
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
+ { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
+ { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
+ { CHARGE_CAPACITY_SIGNAL, NULL, "i", dbus_get_percent },
+ { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
+ { CHARGE_FULL_SIGNAL, NULL, "i", dbus_is_full },
+ { CHARGE_HEALTH_SIGNAL, NULL, "i", dbus_get_health },
+ { POWER_SUBSYSTEM, "sisssss", "i", dbus_power_supply_handler },
+ { "GetBatteryInfo", NULL, "isssiiiii", dbus_get_battery_info },
+};
+
+static int booting_done(void *data)
+{
+ static int done;
+
+ if (data == NULL)
+ return done;
+ done = *(int *)data;
+ if (done == 0)
+ return done;
+
+ _I("booting done");
+
+ power_supply_timer_stop();
+
+ /* for simple noti change cb */
+ power_supply_status_init();
+ process_power_supply(NULL);
+
+ return done;
+}
+
+static int display_changed(void *data)
+{
+ if (battery.charge_now != CHARGER_ABNORMAL)
+ return 0;
+ if (battery.health != HEALTH_BAD && battery.present != PRESENT_ABNORMAL)
+ return 0;
+ pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
+ return 0;
+}
+
+static int load_uevent(struct parse_result *result, void *user_data)
+{
+ struct battery_status *info = user_data;
+
+ if (!info)
+ return -EINVAL;
+
+ if (MATCH(result->name, CHARGE_STATUS)) {
+ if (strstr(result->value, "Charging")) {
+ info->charge_now = CHARGER_CHARGING;
+ info->charge_full = CHARGING_NOT_FULL;
+ } else if (strstr(result->value, "Discharging")) {
+ info->charge_now = CHARGER_DISCHARGING;
+ info->charge_full = CHARGING_NOT_FULL;
+ } else if (strstr(result->value, "Full")) {
+ info->charge_now = CHARGER_DISCHARGING;
+ info->charge_full = CHARGING_FULL;
+ } else if (strstr(result->value, "Not charging")) {
+ info->charge_now = CHARGER_ABNORMAL;
+ info->charge_full = CHARGING_NOT_FULL;
+ }
+ snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
+ } else if (MATCH(result->name, CAPACITY))
+ info->capacity = atoi(result->value);
+ else if (MATCH(result->name, CHARGE_HEALTH))
+ snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
+ return 0;
+}
+
+static int power_supply_probe(void *data)
+{
+ struct hw_info *info;
+ int ret;
+
+ if (battery_dev)
+ return 0;
+
+ ret = hw_get_info(BATTERY_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+
+ if (ret < 0) { /* There is no HAL for battery */
+ if (access(POWER_PATH, R_OK) == 0)
+ return 0; /* Just power_supply uevent is used */
+ goto out;
+ }
+
+ if (!info->open) {
+ _E("Failed to open battery device; open(NULL)");
+ return -ENODEV;
+ }
+
+ ret = info->open(info, NULL, (struct hw_common**)&battery_dev);
+ if (ret < 0) {
+ _E("Failed to get battery device structure (%d)", ret);
+ return ret;
+ }
+
+ if (!battery_dev || !battery_dev->get_current_state) {
+ _E("get_current_state() is not supported by the Battery HAL");
+ return -ENODEV;
+ }
+
+ _I("battery device structure load success");
+ return 0;
+
+out:
+ /**
+ * Set battery vconf as -ENOTSUP
+ * These vconf key used by runtime-info and capi-system-device.
+ */
+ vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
+ vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
+ _I("There is no battery device(%d)", ret);
+ return -ENODEV;
+}
+
+static void power_supply_init(void *data)
+{
+ int ret;
+
+ if (battery_dev) {
+ if (battery_dev->register_changed_event)
+ battery_dev->register_changed_event(battery_changed, NULL);
+
+ if (battery_dev->get_current_state)
+ battery_dev->get_current_state(battery_changed, NULL);
+ } else {
+ ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
+ if (ret < 0)
+ _E("Failed to load %s, %d Use default value!",
+ POWER_SUPPLY_UEVENT, ret);
+
+ /* register power subsystem */
+ register_kernel_uevent_control(&uh);
+ }
+
+ /* process check battery timer until booting done */
+ power_supply_timer_start();
+
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ register_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+
+ ret = register_edbus_interface_and_method(DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+
+ ret = register_edbus_signal_handler(DEVICED_PATH_SYSNOTI,
+ DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE,
+ abnormal_popup_edbus_signal_handler);
+ if (ret < 0)
+ _E("fail to init edbus signal(%d)", ret);
+}
+
+static void power_supply_exit(void *data)
+{
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ unregister_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+
+ /* unregister power subsystem */
+ unregister_kernel_uevent_control(&uh);
+}
+
+static const struct device_ops power_supply_ops = {
+ .name = "power_supply",
+ .probe = power_supply_probe,
+ .init = power_supply_init,
+ .exit = power_supply_exit,
+};
+
+DEVICE_OPS_REGISTER(&power_supply_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __POWER_SUPPLY_H__
+#define __POWER_SUPPLY_H__
+
+enum device_change_type {
+ DEVICE_CHANGE_ABNORMAL = 0,
+ DEVICE_CHANGE_NORMAL = 1,
+};
+
+enum charge_status_type {
+ CHARGE_STATUS_UNKNOWN,
+ CHARGE_STATUS_DISCONNECTED,
+ CHARGE_STATUS_CONNECTED,
+ CHARGE_STATUS_CHARGING,
+ CHARGE_STATUS_DISCHARGING,
+ CHARGE_STATUS_NOT_CHARGING,
+ CHARGE_STATUS_FULL,
+};
+enum charge_full_type {
+ CHARGING_NOT_FULL = 0,
+ CHARGING_FULL = 1,
+};
+enum charge_now_type {
+ CHARGER_ABNORMAL = -1,
+ CHARGER_DISCHARGING = 0,
+ CHARGER_CHARGING = 1,
+};
+enum health_type {
+ HEALTH_BAD = 0,
+ HEALTH_GOOD = 1,
+};
+
+enum temp_type {
+ TEMP_LOW = 0,
+ TEMP_HIGH = 1,
+};
+
+enum present_type {
+ PRESENT_ABNORMAL = 0,
+ PRESENT_NORMAL = 1,
+};
+
+enum ovp_type {
+ OVP_NORMAL = 0,
+ OVP_ABNORMAL = 1,
+};
+
+enum battery_noti_type {
+ DEVICE_NOTI_BATT_CHARGE = 0,
+ DEVICE_NOTI_BATT_LOW,
+ DEVICE_NOTI_BATT_FULL,
+ DEVICE_NOTI_MAX,
+};
+
+enum battery_noti_status {
+ DEVICE_NOTI_OFF = 0,
+ DEVICE_NOTI_ON = 1,
+};
+
+struct battery_status {
+ int capacity;
+ int charge_status;
+ int charge_full;
+ int charge_now;
+ int health;
+ int present;
+ int online;
+ int temp;
+ int ovp;
+ int current_now;
+ int current_average;
+ char status_s[32];
+ char health_s[32];
+ char power_source_s[32];
+};
+
+extern struct battery_status battery;
+
+void power_supply_broadcast(char *sig, int status);
+
+#define CHARGER_STATUS_SIGNAL "ChargerStatus"
+#define CHARGE_NOW_SIGNAL "ChargeNow"
+#define CHARGE_LEVEL_SIGNAL "BatteryStatusLow"
+#define CHARGE_CAPACITY_SIGNAL "GetPercent"
+#define CHARGE_CAPACITY_LAW_SIGNAL "GetPercentRaw"
+#define CHARGE_HEALTH_SIGNAL "GetHealth"
+#define CHARGE_FULL_SIGNAL "IsFull"
+
+#endif /* __POWER_SUPPLY_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+#include <fnmatch.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/statfs.h>
+#include <stdbool.h>
+#include <pthread.h>
+#include <time.h>
+#include <assert.h>
+#include <vconf.h>
+#include <ctype.h>
+#include <tzplatform_config.h>
+#include <app2ext_interface.h>
+#include <libmount.h>
+#include <system_info.h>
+
+#include "core/log.h"
+#include "core/config-parser.h"
+#include "core/device-idler.h"
+#include "core/device-notifier.h"
+#include "core/devices.h"
+#include "core/udev.h"
+#include "core/edbus-handler.h"
+#include "core/list.h"
+#include "block.h"
+
+/**
+ * TODO Assume root device is always mmcblk0*.
+ */
+#define MMC_PATH "*/mmcblk[0-9]*"
+#define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
+#define MMC_LINK_PATH "*/sdcard/*"
+#define SCSI_PATH "*/sd[a-z]*"
+#define SCSI_PARTITION_PATH "sd[a-z][0-9]"
+#define SCSI_PARTITION_LENGTH 9
+#define EMUL_PATH "*/vd[a-z]*"
+#define EMUL_PARTITION_PATH "vd[a-z][0-9]"
+
+#define FILESYSTEM "filesystem"
+
+#define DEV_PREFIX "/dev/"
+#define ROOT_DIR "/"
+
+#define UNMOUNT_RETRY 5
+#define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
+
+#define BLOCK_DEVICE_ADDED "DeviceAdded"
+#define BLOCK_DEVICE_REMOVED "DeviceRemoved"
+#define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
+#define BLOCK_DEVICE_CHANGED "DeviceChanged"
+#define BLOCK_DEVICE_CHANGED_2 "DeviceChanged2"
+
+#define BLOCK_TYPE_MMC "mmc"
+#define BLOCK_TYPE_SCSI "scsi"
+#define BLOCK_TYPE_ALL "all"
+
+#define BLOCK_MMC_NODE_PREFIX "SDCard"
+#define BLOCK_SCSI_NODE_PREFIX "USBDrive"
+
+#define BLOCK_CONF_FILE "/etc/deviced/block.conf"
+#define MODEL_NAME "http://tizen.org/system/model_name"
+#define MODEL_EMULATOR "Emulator"
+
+/* Minimum value of block id */
+#define BLOCK_ID_MIN 10
+/* For 2.4 Backward Compatibility */
+#define EXT_PRIMARY_SD_FIXID 1
+
+/* Maximum number of thread */
+#define THREAD_MAX 5
+
+enum block_dev_operation {
+ BLOCK_DEV_MOUNT,
+ BLOCK_DEV_UNMOUNT,
+ BLOCK_DEV_FORMAT,
+ BLOCK_DEV_INSERT,
+ BLOCK_DEV_REMOVE,
+};
+
+struct operation_queue {
+ enum block_dev_operation op;
+ DBusMessage *msg;
+ void *data;
+ bool done;
+};
+
+struct block_device {
+ struct block_data *data;
+ dd_list *op_queue;
+ int thread_id; /* Current thread ID */
+ bool removed; /* True when device is physically removed but operation is not precessed yet */
+};
+
+struct format_data {
+ struct block_device *bdev;
+ char *fs_type;
+ enum unmount_operation option;
+};
+
+struct pipe_data {
+ enum block_dev_operation op;
+ struct block_device *bdev;
+ int result;
+};
+
+static struct block_conf {
+ bool multimount;
+} block_conf[BLOCK_MMC_DEV + 1];
+
+static struct manage_thread {
+ dd_list *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
+ dd_list *block_dev_list; /* Use thread mutex */
+ pthread_t th;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int num_dev; /* Number of devices which thread holds. Only main thread access */
+ int op_len; /* Number of operation of thread. Use thread mutex */
+ int thread_id; /* Never changed */
+ bool start_th;
+} th_manager[THREAD_MAX];
+
+static dd_list *fs_head;
+static dd_list *block_ops_list;
+static bool smack;
+static int pfds[2];
+static Ecore_Fd_Handler *phandler;
+static bool block_control = false;
+static bool block_boot = false;
+
+static bool emulator = false;
+
+/* Assume there is only one physical internal storage */
+static int dev_internal = -1;
+static char dev_emul = '\0';
+static char dev_internal_scsi = '\0';
+
+static int add_operation(struct block_device *bdev,
+ enum block_dev_operation operation,
+ DBusMessage *msg, void *data);
+static void remove_operation(struct block_device *bdev);
+static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
+static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op);
+
+static void uevent_block_handler(struct udev_device *dev);
+static struct uevent_handler uh = {
+ .subsystem = BLOCK_SUBSYSTEM,
+ .uevent_func = uevent_block_handler,
+};
+
+static void __CONSTRUCTOR__ smack_check(void)
+{
+ FILE *fp;
+ char buf[128];
+
+ fp = fopen("/proc/filesystems", "r");
+ if (!fp)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (strstr(buf, "smackfs")) {
+ smack = true;
+ break;
+ }
+ }
+
+ fclose(fp);
+}
+
+void add_fs(const struct block_fs_ops *fs)
+{
+ DD_LIST_APPEND(fs_head, (void *)fs);
+}
+
+void remove_fs(const struct block_fs_ops *fs)
+{
+ DD_LIST_REMOVE(fs_head, (void *)fs);
+}
+
+const struct block_fs_ops *find_fs(enum block_fs_type type)
+{
+ struct block_fs_ops *fs;
+ dd_list *elem;
+
+ DD_LIST_FOREACH(fs_head, elem, fs) {
+ if (fs->type == type)
+ return fs;
+ }
+ return NULL;
+}
+
+void add_block_dev(const struct block_dev_ops *ops)
+{
+ DD_LIST_APPEND(block_ops_list, (void *)ops);
+}
+
+void remove_block_dev(const struct block_dev_ops *ops)
+{
+ DD_LIST_REMOVE(block_ops_list, (void *)ops);
+}
+
+static void broadcast_block_info(enum block_dev_operation op,
+ struct block_data *data, int result)
+{
+ struct block_dev_ops *ops;
+ dd_list *elem;
+
+ DD_LIST_FOREACH(block_ops_list, elem, ops) {
+ if (ops->block_type != data->block_type)
+ continue;
+ if (op == BLOCK_DEV_MOUNT)
+ ops->mounted(data, result);
+ else if (op == BLOCK_DEV_UNMOUNT)
+ ops->unmounted(data, result);
+ else if (op == BLOCK_DEV_FORMAT)
+ ops->formatted(data, result);
+ else if (op == BLOCK_DEV_INSERT)
+ ops->inserted(data);
+ else if (op == BLOCK_DEV_REMOVE)
+ ops->removed(data);
+ }
+}
+
+// Called by MainThread - Insert
+static int block_get_new_id(void)
+{
+ static int id = BLOCK_ID_MIN;
+ struct block_device *bdev;
+ dd_list *elem;
+ bool found;
+ int i, j;
+
+ for (i = 0 ; i < INT_MAX ; i++) {
+ found = false;
+ for (j = 0; j < THREAD_MAX; j++) {
+ pthread_mutex_lock(&(th_manager[j].mutex));
+ DD_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
+ if (bdev->data->id == id) {
+ found = true;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&(th_manager[j].mutex));
+ if (found)
+ break;
+ }
+
+ if (!found)
+ return id++;
+
+ if (++id == INT_MAX)
+ id = BLOCK_ID_MIN;
+ }
+
+ return -ENOENT;
+}
+
+static void signal_device_blocked(struct block_device *bdev)
+{
+ struct block_data *data;
+ char *arr[13];
+ char str_block_type[32];
+ char str_readonly[32];
+ char str_state[32];
+ char str_primary[32];
+ char str_flags[32];
+ char str_id[32];
+ char *str_null = "";
+ int flags;
+
+ if (!bdev || !bdev->data)
+ return;
+
+ data = bdev->data;
+ flags = 0;
+
+ /* Broadcast outside with BlockManager iface */
+ snprintf(str_block_type, sizeof(str_block_type),
+ "%d", data->block_type);
+ arr[0] = str_block_type;
+ arr[1] = (data->devnode ? data->devnode : str_null);
+ arr[2] = (data->syspath ? data->syspath : str_null);
+ arr[3] = (data->fs_usage ? data->fs_usage : str_null);
+ arr[4] = (data->fs_type ? data->fs_type : str_null);
+ arr[5] = (data->fs_version ? data->fs_version : str_null);
+ arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
+ snprintf(str_readonly, sizeof(str_readonly),
+ "%d", data->readonly);
+ arr[7] = str_readonly;
+ arr[8] = (data->mount_point ? data->mount_point : str_null);
+ snprintf(str_state, sizeof(str_state),
+ "%d", data->state);
+ arr[9] = str_state;
+ snprintf(str_primary, sizeof(str_primary),
+ "%d", data->primary);
+ arr[10] = str_primary;
+ snprintf(str_flags, sizeof(str_flags), "%d", flags);
+ arr[11] = str_flags;
+ snprintf(str_id, sizeof(str_id), "%d", data->id);
+ arr[12] = str_id;
+
+
+ broadcast_block_edbus_signal(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ BLOCK_DEVICE_BLOCKED,
+ "issssssisibii", arr);
+}
+
+static void signal_device_changed(struct block_device *bdev,
+ enum block_dev_operation op)
+{
+ struct block_data *data;
+ char *arr[13];
+ char str_block_type[32];
+ char str_readonly[32];
+ char str_state[32];
+ char str_primary[32];
+ char str_flags[32];
+ char str_id[32];
+ char *str_null = "";
+ int flags;
+
+ if (!bdev || !bdev->data)
+ return;
+
+ data = bdev->data;
+
+ switch (op) {
+ case BLOCK_DEV_MOUNT:
+ BLOCK_GET_MOUNT_FLAGS(data, flags);
+ break;
+ case BLOCK_DEV_UNMOUNT:
+ BLOCK_GET_UNMOUNT_FLAGS(data, flags);
+ break;
+ case BLOCK_DEV_FORMAT:
+ BLOCK_GET_FORMAT_FLAGS(data, flags);
+ break;
+ default:
+ flags = 0;
+ break;
+ }
+
+ /* Broadcast outside with BlockManager iface */
+ snprintf(str_block_type, sizeof(str_block_type),
+ "%d", data->block_type);
+ arr[0] = str_block_type;
+ arr[1] = (data->devnode ? data->devnode : str_null);
+ arr[2] = (data->syspath ? data->syspath : str_null);
+ arr[3] = (data->fs_usage ? data->fs_usage : str_null);
+ arr[4] = (data->fs_type ? data->fs_type : str_null);
+ arr[5] = (data->fs_version ? data->fs_version : str_null);
+ arr[6] = (data->fs_uuid_enc ? data->fs_uuid_enc : str_null);
+ snprintf(str_readonly, sizeof(str_readonly),
+ "%d", data->readonly);
+ arr[7] = str_readonly;
+ arr[8] = (data->mount_point ? data->mount_point : str_null);
+ snprintf(str_state, sizeof(str_state),
+ "%d", data->state);
+ arr[9] = str_state;
+ snprintf(str_primary, sizeof(str_primary),
+ "%d", data->primary);
+ arr[10] = str_primary;
+ snprintf(str_flags, sizeof(str_flags), "%d", flags);
+ arr[11] = str_flags;
+ snprintf(str_id, sizeof(str_id), "%d", data->id);
+ arr[12] = str_id;
+
+ if (op == BLOCK_DEV_INSERT)
+ broadcast_block_edbus_signal(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ BLOCK_DEVICE_ADDED,
+ "issssssisibii", arr);
+ else if (op == BLOCK_DEV_REMOVE)
+ broadcast_block_edbus_signal(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ BLOCK_DEVICE_REMOVED,
+ "issssssisibii", arr);
+ else {
+ broadcast_block_edbus_signal(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ BLOCK_DEVICE_CHANGED,
+ "issssssisibii", arr);
+ broadcast_block_edbus_signal(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ BLOCK_DEVICE_CHANGED_2,
+ "issssssisibi", arr);
+ }
+}
+
+static int get_mmc_mount_node(char *devnode, char *node, size_t len)
+{
+ char *name = devnode;
+ int dev = -1, part = -1;
+ char emul[32] = { 0, };
+ int i;
+
+ if (!name)
+ return -EINVAL;
+
+ /* Check Target */
+ sscanf(name, "mmcblk%dp%d", &dev, &part);
+ if (dev >= 0) {
+ if (part < 0)
+ snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
+ else
+ snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
+ return 0;
+ }
+
+ /* Check Emulator */
+ sscanf(name, "vd%s", emul);
+ if (emul[0] == '\0')
+ return -EINVAL;
+ for (i = 0 ; i < strlen(emul) ; i++)
+ emul[i] = toupper(emul[i]);
+ snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
+ return 0;
+}
+
+static int get_scsi_mount_node(char *devnode, char *node, size_t len)
+{
+ char dev[64], *name;
+ int i;
+
+ if (!devnode)
+ return -EINVAL;
+
+ snprintf(dev, sizeof(dev), "%s", devnode);
+
+ if (!strstr(dev, "sd"))
+ return -EINVAL;
+
+ name = dev;
+ name += strlen("sd");
+
+ for (i = 0 ; i < strlen(name) ; i++)
+ name[i] = toupper(name[i]);
+ snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
+
+ return 0;
+}
+
+static char *generate_mount_path(struct block_data *data)
+{
+ const char *str;
+ char *name, node[64];
+ int ret;
+
+ if (!data || !data->devnode)
+ return NULL;
+
+ name = strrchr(data->devnode, '/');
+ if (!name)
+ goto out;
+ name++;
+
+ switch (data->block_type) {
+ case BLOCK_MMC_DEV:
+ ret = get_mmc_mount_node(name, node, sizeof(node));
+ break;
+ case BLOCK_SCSI_DEV:
+ ret = get_scsi_mount_node(name, node, sizeof(node));
+ break;
+ default:
+ _E("Invalid block type (%d)", data->block_type);
+ return NULL;
+ }
+ if (ret < 0)
+ goto out;
+
+ str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
+ if (!str)
+ return NULL;
+ return strdup(str);
+
+out:
+ _E("Invalid devnode (%s)", data->devnode ? data->devnode : "NULL");
+ return NULL;
+}
+
+static bool check_primary_partition(const char *devnode)
+{
+ char str[PATH_MAX];
+ char str2[PATH_MAX];
+ int len;
+ int i;
+
+ /* if no partition */
+ if (!fnmatch(MMC_LINK_PATH, devnode, 0) ||
+ !fnmatch(MMC_PATH, devnode, 0) ||
+ !fnmatch(SCSI_PATH, devnode, 0))
+ return true;
+
+ snprintf(str, sizeof(str), "%s", devnode);
+
+ len = strlen(str);
+ str[len - 1] = '\0';
+
+ for (i = 1; i < 9; ++i) {
+ snprintf(str2, sizeof(str2), "%s%d", str, i);
+ if (access(str2, R_OK) == 0)
+ break;
+ }
+
+ if (!strncmp(devnode, str2, strlen(str2) + 1))
+ return true;
+
+ return false;
+}
+
+/* Whole data in struct block_data should be freed. */
+static struct block_data *make_block_data(const char *devnode,
+ const char *syspath,
+ const char *fs_usage,
+ const char *fs_type,
+ const char *fs_version,
+ const char *fs_uuid_enc,
+ const char *readonly)
+{
+ struct block_data *data;
+
+ /* devnode is unique value so it should exist. */
+ if (!devnode)
+ return NULL;
+
+ data = calloc(1, sizeof(struct block_data));
+ if (!data)
+ return NULL;
+
+ data->devnode = strdup(devnode);
+ if (syspath)
+ data->syspath = strdup(syspath);
+ if (fs_usage)
+ data->fs_usage = strdup(fs_usage);
+ if (fs_type)
+ data->fs_type = strdup(fs_type);
+ if (fs_version)
+ data->fs_version = strdup(fs_version);
+ if (fs_uuid_enc)
+ data->fs_uuid_enc = strdup(fs_uuid_enc);
+ if (readonly)
+ data->readonly = atoi(readonly);
+ data->primary = check_primary_partition(devnode);
+
+ /* TODO should we know block dev type? */
+ if (!fnmatch(MMC_LINK_PATH, devnode, 0))
+ data->block_type = BLOCK_MMC_DEV;
+ else if (!fnmatch(MMC_PATH, devnode, 0))
+ data->block_type = BLOCK_MMC_DEV;
+ else if (!fnmatch(SCSI_PATH, devnode, 0))
+ data->block_type = BLOCK_SCSI_DEV;
+ else
+ data->block_type = -1;
+
+ data->mount_point = generate_mount_path(data);
+ BLOCK_FLAG_CLEAR_ALL(data);
+
+ /* for 2.4 backward compatibility */
+ if (data->primary == true && data->block_type == BLOCK_MMC_DEV)
+ data->id = EXT_PRIMARY_SD_FIXID;
+ else
+ data->id = block_get_new_id();
+
+ return data;
+}
+
+static void free_block_data(struct block_data *data)
+{
+ if (!data)
+ return;
+ free(data->devnode);
+ free(data->syspath);
+ free(data->fs_usage);
+ free(data->fs_type);
+ free(data->fs_version);
+ free(data->fs_uuid_enc);
+ free(data->mount_point);
+ free(data);
+}
+
+static int update_block_data(struct block_data *data,
+ const char *fs_usage,
+ const char *fs_type,
+ const char *fs_version,
+ const char *fs_uuid_enc,
+ const char *readonly)
+{
+ if (!data)
+ return -EINVAL;
+
+ free(data->fs_usage);
+ data->fs_usage = NULL;
+ if (fs_usage)
+ data->fs_usage = strdup(fs_usage);
+
+ free(data->fs_type);
+ data->fs_type = NULL;
+ if (fs_type)
+ data->fs_type = strdup(fs_type);
+
+ free(data->fs_version);
+ data->fs_version = NULL;
+ if (fs_version)
+ data->fs_version = strdup(fs_version);
+
+ free(data->fs_uuid_enc);
+ data->fs_uuid_enc = NULL;
+ if (fs_uuid_enc)
+ data->fs_uuid_enc = strdup(fs_uuid_enc);
+
+ /* generate_mount_path function should be invoked
+ * after fs_uuid_enc is updated */
+ free(data->mount_point);
+ data->mount_point = generate_mount_path(data);
+
+ data->readonly = false;
+ if (readonly)
+ data->readonly = atoi(readonly);
+
+ BLOCK_FLAG_MOUNT_CLEAR(data);
+
+ return 0;
+}
+
+static struct block_device *make_block_device(struct block_data *data)
+{
+ struct block_device *bdev;
+
+ if (!data)
+ return NULL;
+
+ bdev = calloc(1, sizeof(struct block_device));
+ if (!bdev)
+ return NULL;
+
+ bdev->data = data;
+ bdev->thread_id = -1;
+ bdev->removed = false;
+
+ return bdev;
+}
+
+// Called by MainThread - Remove DevNode
+static void free_block_device(struct block_device *bdev)
+{
+ dd_list *l, *next;
+ struct operation_queue *op;
+ int thread_id;
+
+ if (!bdev)
+ return;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return;
+
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+
+ th_manager[thread_id].num_dev--;
+ DD_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
+ free_block_data(bdev->data);
+
+ DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
+ if (!op->done)
+ th_manager[thread_id].op_len--;
+ DD_LIST_REMOVE(bdev->op_queue, op);
+ free(op);
+ }
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+
+ free(bdev);
+}
+
+// Called By MainThread - Remove Device
+static struct block_device *find_block_device(const char *devnode)
+{
+ struct block_device *bdev;
+ dd_list *elem;
+ int len;
+ int i;
+
+ len = strlen(devnode) + 1;
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ if (bdev->data &&
+ !strncmp(bdev->data->devnode, devnode, len)) {
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ return bdev;
+ }
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ }
+
+ return NULL;
+}
+
+// Called By MainThread - Mount,Unmount,Format,GetInfo
+static struct block_device *find_block_device_by_id(int id)
+{
+ struct block_device *bdev;
+ dd_list *elem;
+ int i;
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ if (!bdev->data)
+ continue;
+ if (bdev->data->id == id) {
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ return bdev;
+ }
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ }
+
+ return NULL;
+}
+
+static char *get_operation_char(enum block_dev_operation op,
+ char *name, unsigned int len)
+{
+ char *str = "unknown";
+
+ if (!name)
+ return NULL;
+
+ switch (op) {
+ case BLOCK_DEV_MOUNT:
+ str = "MOUNT";
+ break;
+ case BLOCK_DEV_UNMOUNT:
+ str = "UNMOUNT";
+ break;
+ case BLOCK_DEV_FORMAT:
+ str = "FORMAT";
+ break;
+ case BLOCK_DEV_INSERT:
+ str = "INSERT";
+ break;
+ case BLOCK_DEV_REMOVE:
+ str = "REMOVE";
+ break;
+ default:
+ _E("invalid operation (%d)", op);
+ break;
+ }
+
+ snprintf(name, len, "%s", str);
+ return name;
+}
+
+static int pipe_trigger(enum block_dev_operation op,
+ struct block_device *bdev, int result)
+{
+ struct pipe_data pdata = { op, bdev, result };
+ int n;
+ char name[16];
+
+ _D("op : %s, bdev : %p, result : %d",
+ get_operation_char(pdata.op, name, sizeof(name)),
+ pdata.bdev, pdata.result);
+
+ n = write(pfds[1], &pdata, sizeof(struct pipe_data));
+
+ return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
+}
+
+static Eina_Bool pipe_cb(void *data, Ecore_Fd_Handler *fdh)
+{
+ struct pipe_data pdata = {0,};
+ int fd;
+ int n;
+ int thread_id;
+ char name[16];
+
+ if (ecore_main_fd_handler_active_get(fdh, ECORE_FD_ERROR)) {
+ _E("an error has occured. Ignore it.");
+ goto out;
+ }
+
+ fd = ecore_main_fd_handler_fd_get(fdh);
+ if (fd <= 0) {
+ _E("fail to get fd");
+ goto out;
+ }
+
+ n = read(fd, &pdata, sizeof(pdata));
+ if (n != sizeof(pdata) || !pdata.bdev) {
+ _E("fail to read struct pipe data");
+ goto out;
+ }
+
+ _D("op : %s, bdev : %p, result : %d",
+ get_operation_char(pdata.op, name, sizeof(name)),
+ pdata.bdev, pdata.result);
+
+ /* Broadcast to mmc and usb storage module */
+ broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
+
+ /* Broadcast outside with Block iface */
+ signal_device_changed(pdata.bdev, pdata.op);
+
+ if (pdata.op == BLOCK_DEV_REMOVE) {
+ thread_id = pdata.bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return ECORE_CALLBACK_RENEW;
+ free_block_device(pdata.bdev);
+ }
+
+out:
+ return ECORE_CALLBACK_RENEW;
+
+}
+
+static int pipe_init(void)
+{
+ int ret;
+
+ ret = pipe2(pfds, O_CLOEXEC);
+ if (ret == -1)
+ return -errno;
+
+ phandler = ecore_main_fd_handler_add(pfds[0],
+ ECORE_FD_READ | ECORE_FD_ERROR,
+ pipe_cb, NULL, NULL, NULL);
+ if (!phandler)
+ return -EPERM;
+
+ return 0;
+}
+
+static void pipe_exit(void)
+{
+ if (phandler) {
+ ecore_main_fd_handler_del(phandler);
+ phandler = NULL;
+ }
+
+ if (pfds[0])
+ close(pfds[0]);
+ if (pfds[1])
+ close(pfds[1]);
+}
+
+static int mmc_check_and_unmount(const char *path)
+{
+ int ret = 0;
+ int retry = 0;
+
+ if (!path)
+ return 0;
+
+ while (mount_check(path)) {
+ ret = umount(path);
+ if (ret < 0) {
+ retry++;
+ if (retry > UNMOUNT_RETRY)
+ return -errno;
+ }
+ }
+ return ret;
+}
+
+static bool check_rw_mount(const char *szPath)
+{
+ struct statvfs mount_stat;
+
+ if (!statvfs(szPath, &mount_stat)) {
+ if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
+ return false;
+ }
+ return true;
+}
+
+static int retrieve_udev_device(struct block_data *data)
+{
+ struct udev *udev;
+ struct udev_device *dev;
+ int r;
+
+ if (!data)
+ return -EINVAL;
+
+ udev = udev_new();
+ if (!udev) {
+ _E("fail to create udev library context");
+ return -EPERM;
+ }
+
+ dev = udev_device_new_from_syspath(udev, data->syspath);
+ if (!dev) {
+ _E("fail to create new udev device");
+ udev_unref(udev);
+ return -EPERM;
+ }
+
+ r = update_block_data(data,
+ udev_device_get_property_value(dev, "ID_FS_USAGE"),
+ udev_device_get_property_value(dev, "ID_FS_TYPE"),
+ udev_device_get_property_value(dev, "ID_FS_VERSION"),
+ udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
+ udev_device_get_sysattr_value(dev, "ro"));
+ if (r < 0)
+ _E("fail to update block data for %s", data->devnode);
+
+ udev_device_unref(dev);
+ udev_unref(udev);
+ return r;
+}
+
+static int block_mount(struct block_data *data)
+{
+ struct block_fs_ops *fs;
+ dd_list *elem;
+ int r;
+ int len;
+
+ if (!data || !data->devnode || !data->mount_point)
+ return -EINVAL;
+
+ /* check existing mounted */
+ if (mount_check(data->mount_point))
+ return -EEXIST;
+
+ /* create mount point */
+ if (access(data->mount_point, R_OK) != 0) {
+ if (mkdir(data->mount_point, 0755) < 0)
+ return -errno;
+ }
+
+ /* check matched file system */
+ if (!data->fs_usage ||
+ strncmp(data->fs_usage, FILESYSTEM,
+ sizeof(FILESYSTEM)) != 0) {
+ r = -ENODEV;
+ goto out;
+ }
+
+ if (!data->fs_type) {
+ _E("There is no file system");
+ BLOCK_FLAG_SET(data, FS_EMPTY);
+ r = -ENODATA;
+ goto out;
+ }
+
+ fs = NULL;
+ len = strlen(data->fs_type) + 1;
+ DD_LIST_FOREACH(fs_head, elem, fs) {
+ if (!strncmp(fs->name, data->fs_type, len))
+ break;
+ }
+
+ if (!fs) {
+ _E("Not supported file system (%s)", data->fs_type);
+ BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
+ r = -ENOTSUP;
+ goto out;
+ }
+
+ r = fs->mount(smack, data->devnode, data->mount_point);
+
+ if (r == -EIO)
+ BLOCK_FLAG_SET(data, FS_BROKEN);
+
+ if (r < 0)
+ goto out;
+
+ r = check_rw_mount(data->mount_point);
+ if (!r)
+ return -EROFS;
+
+ return 0;
+
+out:
+ rmdir(data->mount_point);
+ return r;
+}
+
+static int mount_start(struct block_device *bdev)
+{
+ struct block_data *data;
+ int r;
+
+ assert(bdev);
+ assert(bdev->data);
+
+ data = bdev->data;
+ _I("Mount Start : (%s -> %s)",
+ data->devnode, data->mount_point);
+
+ /* mount operation */
+ r = block_mount(data);
+ if (r != -EROFS && r < 0) {
+ _E("fail to mount %s device : %d", data->devnode, r);
+ goto out;
+ }
+
+ if (r == -EROFS) {
+ data->readonly = true;
+ BLOCK_FLAG_SET(data, MOUNT_READONLY);
+ }
+
+ data->state = BLOCK_MOUNT;
+
+out:
+ _I("%s result : %s, %d", __func__, data->devnode, r);
+
+ if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
+ _E("fail to trigger pipe");
+
+ return r;
+}
+
+static int change_mount_point(struct block_device *bdev,
+ const char *mount_point)
+{
+ struct block_data *data;
+
+ if (!bdev)
+ return -EINVAL;
+
+ data = bdev->data;
+ free(data->mount_point);
+
+ /* If the mount path already exists, the path cannot be used */
+ if (mount_point &&
+ access(mount_point, F_OK) != 0)
+ data->mount_point = strdup(mount_point);
+ else
+ data->mount_point = generate_mount_path(data);
+
+ return 0;
+}
+
+static int mount_block_device(struct block_device *bdev)
+{
+ struct block_data *data;
+ int r;
+
+ if (!bdev || !bdev->data)
+ return -EINVAL;
+
+ data = bdev->data;
+ if (data->state == BLOCK_MOUNT) {
+ _I("%s is already mounted", data->devnode);
+ return 0;
+ }
+
+ if (!block_conf[data->block_type].multimount &&
+ !data->primary) {
+ _I("Not support multi mount by config info");
+ return 0;
+ }
+
+ r = mount_start(bdev);
+ if (r < 0) {
+ _E("Failed to mount (%d)", data->devnode);
+ return r;
+ }
+
+ return 0;
+}
+
+static int block_unmount(struct block_device *bdev,
+ enum unmount_operation option)
+{
+ struct block_data *data;
+ int r, retry = 0;
+ struct timespec time = {0,};
+
+ if (!bdev || !bdev->data || !bdev->data->mount_point)
+ return -EINVAL;
+
+ data = bdev->data;
+
+ signal_device_blocked(bdev);
+
+ /* Need to disble app2ext whenever unmounting mmc */
+ if (data->block_type == BLOCK_MMC_DEV && data->primary)
+ if (app2ext_disable_all_external_pkgs() < 0)
+ _E("app2ext_disable_all_external_pkgs() failed");
+
+ /* it must called before unmounting mmc */
+ r = mmc_check_and_unmount(data->mount_point);
+ if (!r)
+ goto out;
+ if (option == UNMOUNT_NORMAL) {
+ _I("Failed to unmount with normal option : %d", r);
+ return r;
+ }
+
+ _I("Execute force unmount!");
+ /* Force Unmount Scenario */
+ while (1) {
+ switch (retry++) {
+ case 0:
+ /* At first, notify to other app
+ * who already access sdcard */
+ _I("Notify to other app who already access sdcard");
+
+ /* Mobile specific:
+ * should unmount the below vconf key. */
+ if (data->block_type == BLOCK_MMC_DEV && data->primary)
+ vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
+ VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
+ break;
+ case 1:
+ /* Second, kill app with SIGTERM */
+ _I("Kill app with SIGTERM");
+ terminate_process(data->mount_point, false);
+ break;
+ case 2:
+ /* Last time, kill app with SIGKILL */
+ _I("Kill app with SIGKILL");
+ terminate_process(data->mount_point, true);
+ break;
+ default:
+ if (umount2(data->mount_point, MNT_DETACH) != 0) {
+ _I("Failed to unmount with lazy option : %d",
+ errno);
+ return -errno;
+ }
+ goto out;
+ }
+
+ /* it takes some seconds til other app completely clean up */
+ time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+
+ /* Need to disble app2ext whenever unmounting mmc */
+ if (data->block_type == BLOCK_MMC_DEV && data->primary)
+ if (app2ext_disable_all_external_pkgs() < 0)
+ _E("app2ext_disable_all_external_pkgs() failed");
+
+ r = mmc_check_and_unmount(data->mount_point);
+ if (!r) {
+ _E("Failed to unmount (%d)", data->mount_point);
+ break;
+ }
+ }
+
+out:
+ data->state = BLOCK_UNMOUNT;
+
+ if (rmdir(data->mount_point) < 0)
+ _E("fail to remove %s directory", data->mount_point);
+
+ return r;
+}
+
+static int unmount_block_device(struct block_device *bdev,
+ enum unmount_operation option)
+{
+ struct block_data *data;
+ int r;
+
+ if (!bdev || !bdev->data)
+ return -EINVAL;
+
+ data = bdev->data;
+ if (data->state == BLOCK_UNMOUNT) {
+ _I("%s is already unmounted", data->devnode);
+ r = mmc_check_and_unmount(data->mount_point);
+ if (r < 0)
+ _E("The path was existed, but could not delete it(%s)",
+ data->mount_point);
+ return 0;
+ }
+
+ _I("Unmount Start : (%s -> %s)",
+ data->devnode, data->mount_point);
+
+ r = block_unmount(bdev, option);
+ if (r < 0) {
+ _E("fail to unmount %s device : %d", data->devnode, r);
+ goto out;
+ }
+
+ BLOCK_FLAG_MOUNT_CLEAR(data);
+
+out:
+ _I("%s result : %s, %d", __func__, data->devnode, r);
+
+ if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
+ _E("fail to trigger pipe");
+
+ return r;
+}
+
+static int block_format(struct block_data *data,
+ const char *fs_type)
+{
+ const struct block_fs_ops *fs;
+ dd_list *elem;
+ int len;
+ int r;
+
+ if (!data || !data->devnode || !data->mount_point)
+ return -EINVAL;
+
+ if (!fs_type)
+ fs_type = data->fs_type;
+
+ fs = NULL;
+ len = strlen(fs_type);
+ DD_LIST_FOREACH(fs_head, elem, fs) {
+ if (!strncmp(fs->name, fs_type, len))
+ break;
+ }
+
+ if (!fs) {
+ BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
+ _E("not supported file system(%s)", fs_type);
+ return -ENOTSUP;
+ }
+
+ _I("format path : %s", data->devnode);
+ fs->check(data->devnode);
+ r = fs->format(data->devnode);
+ if (r < 0) {
+ _E("fail to format block data for %s", data->devnode);
+ goto out;
+ }
+
+ /* need to update the partition data.
+ * It can be changed in doing format. */
+ retrieve_udev_device(data);
+
+out:
+ return r;
+}
+
+static int format_block_device(struct block_device *bdev,
+ const char *fs_type,
+ enum unmount_operation option)
+{
+ struct block_data *data;
+ int r;
+
+ assert(bdev);
+ assert(bdev->data);
+
+ data = bdev->data;
+
+ _I("Format Start : (%s -> %s)",
+ data->devnode, data->mount_point);
+
+ if (data->state == BLOCK_MOUNT) {
+ r = block_unmount(bdev, option);
+ if (r < 0) {
+ _E("fail to unmount %s device : %d", data->devnode, r);
+ goto out;
+ }
+ }
+
+ r = block_format(data, fs_type);
+ if (r < 0)
+ _E("fail to format %s device : %d", data->devnode, r);
+
+out:
+ _I("%s result : %s, %d", __func__, data->devnode, r);
+
+ r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
+ if (r < 0)
+ _E("fail to trigger pipe");
+
+ return r;
+}
+
+static struct format_data *get_format_data(
+ const char *fs_type, enum unmount_operation option)
+{
+ struct format_data *fdata;
+
+ fdata = (struct format_data *)malloc(sizeof(struct format_data));
+ if (!fdata) {
+ _E("fail to allocate format data");
+ return NULL;
+ }
+
+ if (fs_type)
+ fdata->fs_type = strdup(fs_type);
+ else
+ fdata->fs_type = NULL;
+ fdata->option = option;
+
+ return fdata;
+}
+
+static void release_format_data(struct format_data *data)
+{
+ if (data) {
+ free(data->fs_type);
+ free(data);
+ }
+}
+
+// Called by BlockThread - Real Mount Op
+static int block_mount_device(struct block_device *bdev, void *data)
+{
+ dd_list *l;
+ int ret;
+ int thread_id;
+
+ if (!bdev)
+ return -EINVAL;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return -EINVAL;
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+ l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+ if (!l) {
+ _E("(%d) does not exist in the device list", bdev->data->devnode);
+ return -ENOENT;
+ }
+
+ /* mount automatically */
+ ret = mount_block_device(bdev);
+ if (ret < 0)
+ _E("fail to mount block device for %s", bdev->data->devnode);
+
+ return ret;
+}
+
+// Called by BlockThread - Real Format Op
+static int block_format_device(struct block_device *bdev, void *data)
+{
+ dd_list *l;
+ int ret;
+ int thread_id;
+ struct format_data *fdata = (struct format_data *)data;
+
+ if (!bdev || !fdata) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return -EINVAL;
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+ l = DD_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+ if (!l) {
+ _E("(%d) does not exist in the device list", bdev->data->devnode);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = format_block_device(bdev, fdata->fs_type, fdata->option);
+ if (ret < 0)
+ _E("fail to mount block device for %s", bdev->data->devnode);
+
+out:
+ release_format_data(fdata);
+
+ return ret;
+}
+
+// Called by BlockThread - Real Unmount Op
+static int block_unmount_device(struct block_device *bdev, void *data)
+{
+ int ret;
+ long option = (long)data;
+
+ if (!bdev)
+ return -EINVAL;
+
+ ret = unmount_block_device(bdev, option);
+ if (ret < 0) {
+ _E("Failed to unmount block device (%s)", bdev->data->devnode);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Called by BlockThread - Remove Operation
+ Direct Call at BlockThread
+ Previously this function was called by MainThread. However, it will increase complexity.
+ Need thread lock before to call remove_operation
+*/
+static void remove_operation(struct block_device *bdev)
+{
+ struct operation_queue *op;
+ dd_list *l, *next;
+ char name[16];
+ int thread_id;
+
+ assert(bdev);
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return;
+
+ DD_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
+ if (op->done) {
+ _D("Remove operation (%s, %s)",
+ get_operation_char(op->op, name, sizeof(name)),
+ bdev->data->devnode);
+
+ DD_LIST_REMOVE(bdev->op_queue, op);
+ free(op);
+ }
+ }
+}
+
+static void block_send_dbus_reply(DBusMessage *msg, int result)
+{
+ DBusMessage *rep;
+ int ret;
+ DBusConnection *conn = NULL;
+
+ if (!msg)
+ return;
+
+ conn = get_block_dbus_connection();
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return;
+ }
+
+ rep = make_reply_message(msg, result);
+ ret = dbus_connection_send(conn, rep, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(rep);
+
+ if (ret == TRUE)
+ _I("Success to send reply");
+ else
+ _E("Failed to send reply");
+}
+
+// Called by BlockThread
+static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
+{
+ struct operation_queue *temp;
+ dd_list *l;
+ int thread_id;
+
+ if (!bdev)
+ return;
+
+ if (!queue)
+ return;
+
+ if (!op)
+ return;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return;
+
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+
+ DD_LIST_FOREACH(*queue, l, temp) {
+ if (temp->op == BLOCK_DEV_REMOVE) {
+ *op = temp;
+ break;
+ }
+ temp->done = true;
+ th_manager[thread_id].op_len--;
+ block_send_dbus_reply((*op)->msg, 0);
+ }
+
+ remove_operation(bdev);
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+}
+
+// Called by BlockThread
+static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op)
+{
+ struct operation_queue *temp;
+ dd_list *l;
+ int thread_id;
+ bool unmounted = false;
+
+ if (!bdev)
+ return false;
+
+ if (!queue)
+ return false;
+
+ if (!op)
+ return false;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return false;
+
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+ DD_LIST_FOREACH(*queue, l, temp) {
+ if (temp->op == BLOCK_DEV_UNMOUNT) {
+ unmounted = true;
+ _D("Operation queue has unmount operation");
+ break;
+ }
+ }
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+
+ if (!unmounted)
+ return unmounted;
+
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+
+ DD_LIST_FOREACH(*queue, l, temp) {
+ if (temp->op == BLOCK_DEV_UNMOUNT) {
+ *op = temp;
+ break;
+ }
+ temp->done = true;
+ th_manager[thread_id].op_len--;
+ block_send_dbus_reply((*op)->msg, 0);
+ }
+
+ remove_operation(bdev);
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+
+ return unmounted;
+}
+
+// Called by BlockThread
+static void trigger_operation(struct block_device *bdev, dd_list *queue, struct operation_queue *op)
+{
+ int ret = 0;
+ int thread_id;
+ char devnode[PATH_MAX];
+ char name[16];
+ enum block_dev_operation operation;
+ bool unmounted = false;
+
+ assert(bdev);
+
+ if (!queue)
+ return;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX)
+ return;
+
+ snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
+
+ do {
+ if (!op)
+ return;
+ if (op->done)
+ return;
+
+ operation = op->op;
+
+ _D("Thread id %d Trigger operation (%s, %s)", thread_id,
+ get_operation_char(operation, name, sizeof(name)), devnode);
+
+ unmounted = false;
+ if (operation == BLOCK_DEV_INSERT && bdev->removed) {
+ check_removed(bdev, &queue, &op);
+ operation = op->op;
+ _D("Trigger operation again (%s, %s)",
+ get_operation_char(operation, name, sizeof(name)), devnode);
+ }
+ if (operation == BLOCK_DEV_MOUNT) {
+ unmounted = check_unmount(bdev, &queue, &op);
+ if (unmounted) {
+ operation = op->op;
+ _D("Trigger operation again (%s, %s)",
+ get_operation_char(operation, name, sizeof(name)), devnode);
+ }
+ }
+
+ switch (operation) {
+ case BLOCK_DEV_INSERT:
+ break;
+ case BLOCK_DEV_MOUNT:
+ ret = block_mount_device(bdev, op->data);
+ _D("Mount (%s) result:(%d)", devnode, ret);
+ break;
+ case BLOCK_DEV_FORMAT:
+ ret = block_format_device(bdev, op->data);
+ _D("Format (%s) result:(%d)", devnode, ret);
+ break;
+ case BLOCK_DEV_UNMOUNT:
+ ret = block_unmount_device(bdev, op->data);
+ _D("Unmount (%s) result:(%d)", devnode, ret);
+ break;
+ case BLOCK_DEV_REMOVE:
+ /* Do nothing */
+ break;
+ default:
+ _E("Operation type is invalid (%d)", op->op);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* LOCK
+ * during checking the queue length */
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+
+ op->done = true;
+ th_manager[thread_id].op_len--;
+
+ block_send_dbus_reply(op->msg, ret);
+
+ queue = bdev->op_queue;
+ queue = DD_LIST_NEXT(queue);
+ op = DD_LIST_NTH(queue, 0);
+ remove_operation(bdev);
+
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+ /* UNLOCK */
+
+
+ if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE) {
+ if (pipe_trigger(operation, bdev, 0) < 0)
+ _E("fail to trigger pipe");
+ }
+
+ } while(true);
+
+}
+
+// Called by BlockThread
+static void *block_th_start(void *arg)
+{
+ struct block_device *temp;
+ struct manage_thread *th = (struct manage_thread *)arg;
+ struct operation_queue *op = NULL;
+ dd_list *elem;
+ dd_list *queue = NULL;
+ int thread_id;
+
+ assert(th);
+
+ thread_id = th->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX) {
+ _E("Thread Number: %d", th->thread_id);
+ return NULL;
+ }
+
+ do {
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+ if (th_manager[thread_id].op_len == 0) {
+ _D("Operation queue of thread is empty");
+ pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
+ _D("Wake up %d", thread_id);
+ }
+
+ DD_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
+ queue = temp->op_queue;
+ do {
+ op = DD_LIST_NTH(queue, 0);
+ if (!op) {
+ _D("Operation queue for device %s is Empty", temp->data->devnode);
+ break;
+ }
+ if (op->done) {
+ queue = DD_LIST_NEXT(queue);
+ continue;
+ }
+ break;
+ } while(true);
+ if (op)
+ break;
+ }
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+
+ if (op && !op->done)
+ trigger_operation(temp, queue, op);
+
+ } while (true);
+}
+
+// This function will be refactored later
+// Especially, we don't need to keep th_node_list.
+static int find_thread(char *devnode)
+{
+ dd_list *elem;
+ char str[PATH_MAX];
+ char *th_node;
+ char *temp;
+ char dev_scsi;
+ int i, len, min, min_num;
+ int dev_mmc = -1, part = -1, num;
+
+ len = 0;
+ if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
+ sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
+ num = dev_mmc;
+ while (num > 0) {
+ num = num / 10;
+ len++;
+ }
+ len = len + 12;
+ snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
+ th_node = strdup(str);
+ } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
+ sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
+ snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
+ th_node = strdup(str);
+ } else
+ th_node = devnode;
+
+ len = strlen(str) + 1;
+ min_num = 1000;
+ min = -1;
+ for (i = 0; i < THREAD_MAX; i++){
+ DD_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
+ if (!temp)
+ continue;
+ if (!strncmp(temp, th_node, len))
+ return i;
+ }
+ if (th_manager[i].num_dev < min_num) {
+ min_num = th_manager[i].num_dev;
+ min = i;
+ }
+ }
+
+ if (min >= 0 && min < THREAD_MAX) {
+ DD_LIST_APPEND(th_manager[min].th_node_list, th_node);
+ return min;
+ }
+
+ _E("Finding thread is failed");
+ DD_LIST_APPEND(th_manager[0].th_node_list, th_node);
+ return 0;
+}
+
+/* Only Main thread is permmited */
+// Called by MainThread
+static int add_operation(struct block_device *bdev,
+ enum block_dev_operation operation,
+ DBusMessage *msg, void *data)
+{
+ struct operation_queue *op;
+ int ret;
+ int thread_id;
+ bool start_th;
+ char name[16];
+
+ if (!bdev)
+ return -EINVAL;
+
+ _D("Add operation (%s, %s)",
+ get_operation_char(operation, name, sizeof(name)),
+ bdev->data->devnode);
+
+ op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
+ if (!op) {
+ _E("malloc failed");
+ return -ENOMEM;
+ }
+
+ op->op = operation;
+ op->data = data;
+ op->done = false;
+
+ if (msg)
+ msg = dbus_message_ref(msg);
+ op->msg = msg;
+
+ thread_id = bdev->thread_id;
+ if (thread_id < 0 || thread_id >= THREAD_MAX) {
+ _E("Fail to find thread to add");
+ return -EPERM;
+ }
+
+ /* LOCK
+ * during adding queue and checking the queue length */
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+
+ start_th = th_manager[thread_id].start_th;
+ DD_LIST_APPEND(bdev->op_queue, op);
+ th_manager[thread_id].op_len++;
+
+ if (th_manager[thread_id].op_len == 1 && !start_th)
+ pthread_cond_signal(&(th_manager[thread_id].cond));
+
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+ /* UNLOCK */
+
+ if (start_th) {
+ _D("Start New thread for block device");
+ th_manager[thread_id].start_th = false;
+ ret = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
+ if (ret != 0) {
+ _E("fail to create thread for %s", bdev->data->devnode);
+ return -EPERM;
+ }
+
+ pthread_detach(th_manager[thread_id].th);
+ }
+
+ return 0;
+}
+
+static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
+{
+ DIR *dp;
+ struct dirent entry;
+ struct dirent *dir;
+ const char *syspath;
+ bool ret = false;
+
+ syspath = udev_device_get_syspath(dev);
+ if (!syspath)
+ goto out;
+
+ dp = opendir(syspath);
+ if (!dp) {
+ _E("fail to open %s", syspath);
+ goto out;
+ }
+
+ /* TODO compare devname and d_name */
+ while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
+ if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
+ !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
+ ret = true;
+ break;
+ }
+ }
+
+ closedir(dp);
+
+out:
+ return ret;
+}
+
+static bool check_partition(struct udev_device *dev)
+{
+ const char *devtype;
+ const char *part_table_type;
+ const char *fs_usage;
+ bool ret = false;
+
+ /* only consider disk type, never partitions */
+ devtype = udev_device_get_devtype(dev);
+ if (!devtype)
+ goto out;
+
+ if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
+ sizeof(BLOCK_DEVTYPE_DISK)) != 0)
+ goto out;
+
+ part_table_type = udev_device_get_property_value(dev,
+ "ID_PART_TABLE_TYPE");
+ if (part_table_type) {
+ fs_usage = udev_device_get_property_value(dev,
+ "ID_FS_USAGE");
+ if (fs_usage &&
+ strncmp(fs_usage, FILESYSTEM, sizeof(FILESYSTEM)) == 0) {
+ if (!disk_is_partitioned_by_kernel(dev))
+ goto out;
+ }
+ ret = true;
+ goto out;
+ }
+
+ if (disk_is_partitioned_by_kernel(dev)) {
+ ret = true;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+// Called by MainThread
+static int add_block_device(struct udev_device *dev, const char *devnode)
+{
+ struct block_data *data;
+ struct block_device *bdev;
+ bool partition;
+ int ret;
+ int thread_id;
+
+ partition = check_partition(dev);
+ if (partition) {
+ /* if there is a partition, skip this request */
+ _I("%s device has partitions, skip this time", devnode);
+ return 0;
+ }
+
+ data = make_block_data(devnode,
+ udev_device_get_syspath(dev),
+ udev_device_get_property_value(dev, "ID_FS_USAGE"),
+ udev_device_get_property_value(dev, "ID_FS_TYPE"),
+ udev_device_get_property_value(dev, "ID_FS_VERSION"),
+ udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
+ udev_device_get_sysattr_value(dev, "ro"));
+ if (!data) {
+ _E("fail to make block data for %s", devnode);
+ return -EPERM;
+ }
+
+ bdev = make_block_device(data);
+ if (!bdev) {
+ _E("fail to make block device for %s", devnode);
+ free_block_data(data);
+ return -EPERM;
+ }
+
+ thread_id = find_thread(bdev->data->devnode);
+ if (thread_id < 0 || thread_id >= THREAD_MAX) {
+ _E("Fail to find thread to add");
+ return -EPERM;
+ }
+ bdev->thread_id = thread_id;
+
+ pthread_mutex_lock(&(th_manager[thread_id].mutex));
+ th_manager[thread_id].num_dev++;
+ DD_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
+ pthread_mutex_unlock(&(th_manager[thread_id].mutex));
+
+ ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
+ if (ret < 0) {
+ _E("Failed to add operation (mount %s)", devnode);
+ return ret;
+ }
+
+ ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
+ if (ret < 0) {
+ _E("Failed to add operation (mount %s)", devnode);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int remove_block_device(struct udev_device *dev, const char *devnode)
+{
+ struct block_device *bdev;
+ int ret;
+
+ bdev = find_block_device(devnode);
+ if (!bdev) {
+ _E("fail to find block data for %s", devnode);
+ return -ENODEV;
+ }
+
+ BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
+
+ bdev->removed = true;
+ ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
+ if (ret < 0) {
+ _E("Failed to add operation (unmount %s)", devnode);
+ return ret;
+ }
+
+ ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
+ if (ret < 0) {
+ _E("Failed to add operation (remove %s)", devnode);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_internal_storage_number(void)
+{
+ struct libmnt_table *t = NULL;
+ struct libmnt_fs *fs;
+ const char *temp;
+ char *name;
+ int r = 0;
+
+ if (dev_internal >= 0 || dev_internal_scsi != '\0' || dev_emul != '\0')
+ return 0;
+
+ t = mnt_new_table();
+ if (!t)
+ return -EPERM;
+
+ r = mnt_table_parse_mtab(t, NULL);
+ if (r < 0) {
+ mnt_free_table(t);
+ return -EPERM;
+ }
+
+ fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
+
+ if (!fs) {
+ mnt_free_table(t);
+ return -EPERM;
+ }
+ temp = mnt_fs_get_srcpath(fs);
+ name = strrchr(temp, '/');
+ if (!name)
+ return -EPERM;
+ name++;
+ /* Boot from USB is not handled */
+ if (!emulator) {
+ if (!fnmatch(MMC_PATH, temp, 0))
+ sscanf(name, "mmcblk%d", &dev_internal);
+ else if (!fnmatch(SCSI_PATH, temp, 0))
+ sscanf(name, "sd%c", &dev_internal_scsi);
+ } else {
+ if (!fnmatch(EMUL_PATH, temp, 0))
+ sscanf(name, "vd%c", &dev_emul);
+ }
+
+ mnt_free_table(t);
+
+ return 0;
+}
+
+static int check_external_storage(const char* devnode)
+{
+ char emul = '\0';
+ char dev_scsi = '\0';
+ char *name;
+ int dev_num = -1;
+
+ if (!devnode)
+ return -EPERM;
+
+ name = strrchr(devnode, '/');
+ if (!name)
+ return -EPERM;
+ name++;
+ if (!emulator) {
+ if (!fnmatch(MMC_PATH, devnode, 0)) {
+ sscanf(name, "mmcblk%d", &dev_num);
+ if (dev_internal == dev_num) {
+ _D("%s is internal storage", devnode);
+ return 0;
+ }
+ } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
+ sscanf(name, "sd%c", &dev_scsi);
+ if (dev_internal_scsi == dev_scsi) {
+ _D("%s is internal storage", devnode);
+ return 0;
+ }
+ }
+ } else {
+ if (!fnmatch(EMUL_PATH, devnode, 0)) {
+ sscanf(name, "vd%c", &emul);
+ if (emul == '\0')
+ return -EPERM;
+ if (dev_emul == emul) {
+ _D("%s is internal storage", devnode);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int block_init_from_udev_enumerate(void)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *list_entry, *list_sub_entry;
+ struct udev_device *dev;
+ const char *syspath;
+ const char *devnode;
+ int r = 0;
+
+ udev = udev_new();
+ if (!udev) {
+ _E("fail to create udev library context");
+ return -EPERM;
+ }
+
+ /* create a list of the devices in the 'usb' subsystem */
+ enumerate = udev_enumerate_new(udev);
+ if (!enumerate) {
+ _E("fail to create an enumeration context");
+ return -EPERM;
+ }
+
+ if (dev_internal < 0 && dev_emul == '\0' && dev_internal_scsi == '\0') {
+ r = get_internal_storage_number();
+ if (r < 0)
+ return -EPERM;
+ }
+
+ udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
+ udev_enumerate_add_match_property(enumerate,
+ UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
+ udev_enumerate_add_match_property(enumerate,
+ UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
+ udev_enumerate_scan_devices(enumerate);
+
+ udev_list_entry_foreach(list_entry,
+ udev_enumerate_get_list_entry(enumerate)) {
+ syspath = udev_list_entry_get_name(list_entry);
+ if (!syspath)
+ continue;
+
+ dev = udev_device_new_from_syspath(
+ udev_enumerate_get_udev(enumerate),
+ syspath);
+ if (!dev)
+ continue;
+
+ devnode = NULL;
+ udev_list_entry_foreach(list_sub_entry,
+ udev_device_get_devlinks_list_entry(dev)) {
+ const char *devlink = udev_list_entry_get_name(list_sub_entry);
+ if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
+ devnode = devlink;
+ break;
+ }
+ }
+
+ if (!devnode) {
+ devnode = udev_device_get_devnode(dev);
+ if (!devnode)
+ continue;
+
+ if (fnmatch(MMC_PATH, devnode, 0) &&
+ fnmatch(SCSI_PATH, devnode, 0))
+ continue;
+ }
+
+ r = check_external_storage(devnode);
+ if (r <= 0)
+ continue;
+
+ _D("%s device add", devnode);
+ add_block_device(dev, devnode);
+
+ udev_device_unref(dev);
+ }
+
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+ return 0;
+}
+
+// Called by MainThread
+static void show_block_device_list(void)
+{
+ struct block_device *bdev;
+ struct block_data *data;
+ dd_list *elem;
+ int i;
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ data = bdev->data;
+ if (!data)
+ continue;
+ if (bdev->removed)
+ continue;
+ _D("%s:", data->devnode);
+ _D("\tSyspath: %s", data->syspath);
+ _D("\tBlock type: %s",
+ (data->block_type == BLOCK_MMC_DEV ?
+ BLOCK_TYPE_MMC : BLOCK_TYPE_SCSI));
+ _D("\tFs type: %s", data->fs_type);
+ _D("\tFs usage: %s", data->fs_usage);
+ _D("\tFs version: %s", data->fs_version);
+ _D("\tFs uuid enc: %s", data->fs_uuid_enc);
+ _D("\tReadonly: %s",
+ (data->readonly ? "true" : "false"));
+ _D("\tMount point: %s", data->mount_point);
+ _D("\tMount state: %s",
+ (data->state == BLOCK_MOUNT ?
+ "mount" : "unmount"));
+ _D("\tPrimary: %s",
+ (data->primary ? "true" : "false"));
+ _D("\tID: %d", data->id);
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ }
+}
+
+// Called by MainThread
+static void remove_whole_block_device(void)
+{
+ struct block_device *bdev;
+ dd_list *elem;
+ dd_list *next;
+ int r;
+ int i;
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ do {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
+ if (bdev->removed == false) {
+ break;
+ }
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+
+ if (bdev && bdev->removed == false) {
+ bdev->removed = true;
+ r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_NORMAL);
+ if (r < 0)
+ _E("Failed to add operation (unmount %s)", bdev->data->devnode);
+
+ r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
+ if (r < 0)
+ _E("Failed to add operation (remove %s)", bdev->data->devnode);
+ } else
+ break;
+ } while(true);
+ }
+}
+
+static int booting_done(void *data)
+{
+ /* if there is the attached device, try to mount */
+ block_init_from_udev_enumerate();
+ block_control = true;
+ block_boot = true;
+ return 0;
+}
+
+static int block_poweroff(void *data)
+{
+ /* unregister mmc uevent control routine */
+ unregister_udev_uevent_control(&uh);
+ remove_whole_block_device();
+ return 0;
+}
+
+static void uevent_block_handler(struct udev_device *dev)
+{
+ const char *devnode = NULL;
+ const char *action;
+ struct udev_list_entry *list_entry;
+ int r;
+
+ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
+ const char *devlink = udev_list_entry_get_name(list_entry);
+ if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
+ devnode = devlink;
+ break;
+ }
+ }
+
+ if (!devnode) {
+ devnode = udev_device_get_devnode(dev);
+ if (!devnode)
+ return;
+
+ if (fnmatch(MMC_PATH, devnode, 0) &&
+ fnmatch(SCSI_PATH, devnode, 0))
+ return;
+ }
+
+ r = check_external_storage(devnode);
+ if (r <= 0)
+ return;
+
+ action = udev_device_get_action(dev);
+ if (!action)
+ return;
+
+ _D("%s device %s", devnode, action);
+ if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)))
+ add_block_device(dev, devnode);
+ else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)))
+ remove_block_device(dev, devnode);
+}
+
+static DBusMessage *request_mount_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ struct block_device *bdev;
+ char *mount_point;
+ int id;
+ int ret = -EBADMSG;
+
+ if (!obj || !msg)
+ goto out;
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &id,
+ DBUS_TYPE_STRING, &mount_point,
+ DBUS_TYPE_INVALID);
+ if (!ret)
+ goto out;
+ bdev = find_block_device_by_id(id);
+ if (!bdev) {
+ _E("Failed to find (%d) in the device list", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* if requester want to use a specific mount point */
+ if (mount_point && strncmp(mount_point, "", 1) != 0) {
+ ret = change_mount_point(bdev, mount_point);
+ if (ret < 0) {
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
+ ret = add_operation(bdev, BLOCK_DEV_MOUNT, msg, NULL);
+ if (ret < 0) {
+ _E("Failed to add operation (mount %s)", bdev->data->devnode);
+ goto out;
+ }
+
+ return NULL;
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static DBusMessage *request_unmount_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ struct block_device *bdev;
+ long option;
+ int id;
+ int ret = -EBADMSG;
+
+ if (!obj || !msg)
+ goto out;
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &id,
+ DBUS_TYPE_INT32, &option,
+ DBUS_TYPE_INVALID);
+ if (!ret)
+ goto out;
+ bdev = find_block_device_by_id(id);
+ if (!bdev) {
+ _E("Failed to find (%d) in the device list", id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, msg, (void *)option);
+ if (ret < 0) {
+ _E("Failed to add operation (unmount %s)", bdev->data->devnode);
+ goto out;
+ }
+
+ return NULL;
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static DBusMessage *request_format_block(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ struct block_device *bdev;
+ struct format_data *fdata;
+ int id;
+ int option;
+ int ret = -EBADMSG;
+ int prev_state;
+
+ if (!obj || !msg)
+ goto out;
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &id,
+ DBUS_TYPE_INT32, &option,
+ DBUS_TYPE_INVALID);
+ if (!ret)
+ goto out;
+ bdev = find_block_device_by_id(id);
+ if (!bdev) {
+ _E("Failed to find (%d) in the device list", id);
+ goto out;
+ }
+
+ fdata = get_format_data(NULL, option);
+ if (!fdata) {
+ _E("Failed to get format data");
+ goto out;
+ }
+
+ prev_state = bdev->data->state;
+ if (prev_state == BLOCK_MOUNT) {
+ ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
+ if (ret < 0) {
+ _E("Failed to add operation (unmount %s)", bdev->data->devnode);
+ release_format_data(fdata);
+ goto out;
+ }
+ }
+
+ ret = add_operation(bdev, BLOCK_DEV_FORMAT, msg, (void *)fdata);
+ if (ret < 0) {
+ _E("Failed to add operation (format %s)", bdev->data->devnode);
+ release_format_data(fdata);
+ }
+
+ /* Maintain previous state of mount/unmount */
+ if (prev_state == BLOCK_MOUNT) {
+ if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
+ _E("Failed to add operation (mount %s)", bdev->data->devnode);
+ goto out;
+ }
+ }
+
+ return NULL;
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static int add_device_to_iter(struct block_data *data, DBusMessageIter *piter)
+{
+ char *str_null = "";
+
+ if (!data || !piter)
+ return -EINVAL;
+
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
+ &(data->block_type));
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->devnode ? &(data->devnode) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->syspath ? &(data->syspath) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->fs_usage ? &(data->fs_usage) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->fs_type ? &(data->fs_type) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->fs_version ? &(data->fs_version) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
+ &(data->readonly));
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_STRING,
+ data->mount_point ? &(data->mount_point) : &str_null);
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
+ &(data->state));
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_BOOLEAN,
+ &(data->primary));
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
+ &(data->flags));
+ dbus_message_iter_append_basic(piter, DBUS_TYPE_INT32,
+ &(data->id));
+
+ return 0;
+}
+
+
+static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
+{
+ DBusMessageIter piter;
+
+ if (!data || !iter)
+ return -EINVAL;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
+ add_device_to_iter(data, &piter);
+ dbus_message_iter_close_container(iter, &piter);
+
+ return 0;
+}
+
+static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
+{
+ DBusMessageIter piter;
+ char *str_null = "";
+
+ if (!data || !iter)
+ return -EINVAL;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
+ &(data->block_type));
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->devnode ? &(data->devnode) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->syspath ? &(data->syspath) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->fs_usage ? &(data->fs_usage) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->fs_type ? &(data->fs_type) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->fs_version ? &(data->fs_version) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
+ &(data->readonly));
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
+ data->mount_point ? &(data->mount_point) : &str_null);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
+ &(data->state));
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
+ &(data->primary));
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
+ &(data->flags));
+ dbus_message_iter_close_container(iter, &piter);
+
+ return 0;
+}
+
+static DBusMessage *request_get_device_info(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ struct block_device *bdev;
+ struct block_data *data;
+ int ret, id;
+
+ if (!obj || !msg)
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ goto out;
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &id,
+ DBUS_TYPE_INVALID);
+ if (!ret)
+ goto out;
+
+ bdev = find_block_device_by_id(id);
+ if (!bdev)
+ goto out;
+ data = bdev->data;
+ if (!data)
+ goto out;
+
+ dbus_message_iter_init_append(reply, &iter);
+ add_device_to_iter(data, &iter);
+
+out:
+ return reply;
+}
+
+static DBusMessage *request_show_device_list(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ show_block_device_list();
+ return dbus_message_new_method_return(msg);
+}
+
+// Called by MainThread
+static DBusMessage *request_get_device_list(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessageIter aiter;
+ DBusMessage *reply;
+ struct block_device *bdev;
+ struct block_data *data;
+ dd_list *elem;
+ char *type = NULL;
+ int ret = -EBADMSG;
+ int block_type;
+ int i;
+
+ reply = dbus_message_new_method_return(msg);
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("Failed to get args");
+ goto out;
+ }
+
+ if (!type) {
+ _E("Delivered type is NULL");
+ goto out;
+ }
+
+ _D("Block (%s) device list is requested", type);
+
+ if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
+ block_type = BLOCK_SCSI_DEV;
+ else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
+ block_type = BLOCK_MMC_DEV;
+ else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
+ block_type = -1;
+ else {
+ _E("Invalid type (%s) is requested", type);
+ goto out;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibii)", &aiter);
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ data = bdev->data;
+ if (!data)
+ continue;
+ if (bdev->removed)
+ continue;
+
+ switch (block_type) {
+ case BLOCK_SCSI_DEV:
+ case BLOCK_MMC_DEV:
+ if (data->block_type != block_type)
+ continue;
+ break;
+ default:
+ break;
+ }
+ add_device_to_struct_iter(data, &aiter);
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ }
+ dbus_message_iter_close_container(&iter, &aiter);
+
+out:
+ return reply;
+}
+
+// Called by MainThread
+static DBusMessage *request_get_device_list_2(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessageIter aiter;
+ DBusMessage *reply;
+ struct block_device *bdev;
+ struct block_data *data;
+ dd_list *elem;
+ char *type = NULL;
+ int ret = -EBADMSG;
+ int block_type;
+ int i;
+
+ reply = dbus_message_new_method_return(msg);
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("Failed to get args");
+ goto out;
+ }
+
+ if (!type) {
+ _E("Delivered type is NULL");
+ goto out;
+ }
+
+ _D("Block (%s) device list is requested", type);
+
+ if (!strncmp(type, BLOCK_TYPE_SCSI, sizeof(BLOCK_TYPE_SCSI)))
+ block_type = BLOCK_SCSI_DEV;
+ else if (!strncmp(type, BLOCK_TYPE_MMC, sizeof(BLOCK_TYPE_MMC)))
+ block_type = BLOCK_MMC_DEV;
+ else if (!strncmp(type, BLOCK_TYPE_ALL, sizeof(BLOCK_TYPE_ALL)))
+ block_type = -1;
+ else {
+ _E("Invalid type (%s) is requested", type);
+ goto out;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(issssssisibi)", &aiter);
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ data = bdev->data;
+ if (!data)
+ continue;
+ if (bdev->removed)
+ continue;
+
+ switch (block_type) {
+ case BLOCK_SCSI_DEV:
+ case BLOCK_MMC_DEV:
+ if (data->block_type != block_type)
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ add_device_to_iter_2(data, &aiter);
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ }
+ dbus_message_iter_close_container(&iter, &aiter);
+
+out:
+ return reply;
+}
+
+static DBusMessage *request_get_mmc_primary(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ struct block_device *bdev;
+ struct block_data *data, nodata = {0,};
+ dd_list *elem;
+ bool found;
+ int i;
+
+ if (!obj || !msg)
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ goto out;
+
+ found = false;
+ for (i = 0; i < THREAD_MAX; i++) {
+ pthread_mutex_lock(&(th_manager[i].mutex));
+ DD_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
+ data = bdev->data;
+ if (!data)
+ continue;
+ if (bdev->removed)
+ continue;
+ if (data->block_type != BLOCK_MMC_DEV)
+ continue;
+ if (!data->primary)
+ continue;
+ found = true;
+ break;
+ }
+ pthread_mutex_unlock(&(th_manager[i].mutex));
+ if (found)
+ break;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ if (found)
+ add_device_to_iter(data, &iter);
+ else {
+ nodata.id = -ENODEV;
+ add_device_to_iter(&nodata, &iter);
+ }
+
+out:
+ return reply;
+}
+
+static const struct edbus_method manager_methods[] = {
+ { "ShowDeviceList", NULL, NULL, request_show_device_list },
+ { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
+ { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
+ { "Mount", "is", "i", request_mount_block },
+ { "Unmount", "ii", "i", request_unmount_block },
+ { "Format", "ii", "i", request_format_block },
+ { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
+ { "GetMmcPrimary" , NULL, "(issssssisibii)" , request_get_mmc_primary },
+};
+
+static int load_config(struct parse_result *result, void *user_data)
+{
+ int index;
+
+ if (MATCH(result->section, "Block"))
+ return 0;
+
+ if (MATCH(result->section, "SCSI"))
+ index = BLOCK_SCSI_DEV;
+ else if (MATCH(result->section, "MMC"))
+ index = BLOCK_MMC_DEV;
+ else
+ return -EINVAL;
+
+ if (MATCH(result->name, "Multimount"))
+ block_conf[index].multimount =
+ (MATCH(result->value, "yes") ? true : false);
+
+ return 0;
+}
+
+#ifdef BLOCK_TMPFS
+static int mount_root_path_tmpfs(void)
+{
+ int ret;
+ char *root;
+
+ root = tzplatform_getenv(TZ_SYS_MEDIA);
+ if (!root)
+ return -ENOTSUP;
+
+ if (access(root, F_OK) != 0)
+ return -ENODEV;
+
+ if (mount_check(root))
+ return 0;
+
+ ret = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
+ if (ret < 0) {
+ ret = -errno;
+ _E("tmpfs mount failed (%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#else
+#define mount_root_path_tmpfs() 0
+#endif
+
+static void block_init(void *data)
+{
+ char *model_name;
+ int ret;
+ int i;
+
+ /* load config */
+ ret = config_parse(BLOCK_CONF_FILE, load_config, NULL);
+ if (ret < 0)
+ _E("fail to load %s, Use default value", BLOCK_CONF_FILE);
+
+ ret = mount_root_path_tmpfs();
+ if (ret < 0)
+ _E("Failed to mount tmpfs to root mount path (%d)", ret);
+
+ /* register block manager object and interface */
+ ret = register_block_edbus_interface_and_method(DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ manager_methods, ARRAY_SIZE(manager_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+
+ /* init pipe */
+ ret = pipe_init();
+ if (ret < 0)
+ _E("fail to init pipe");
+
+ /* register mmc uevent control routine */
+ ret = register_udev_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to register block uevent : %d", ret);
+
+ /* register notifier */
+ register_notifier(DEVICE_NOTIFIER_POWEROFF, block_poweroff);
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+
+ ret = system_info_get_platform_string(MODEL_NAME, &model_name);
+ if (!strncmp(MODEL_EMULATOR, model_name, strlen(model_name)))
+ emulator = true;
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ th_manager[i].num_dev = 0;
+ th_manager[i].op_len = 0;
+ th_manager[i].start_th = true;
+ th_manager[i].thread_id = i;
+ pthread_mutex_init(&(th_manager[i].mutex), NULL);
+ pthread_cond_init(&(th_manager[i].cond), NULL);
+ }
+}
+
+static void block_exit(void *data)
+{
+ int ret, i;
+
+ /* unregister notifier */
+ unregister_notifier(DEVICE_NOTIFIER_POWEROFF, block_poweroff);
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+
+ /* exit pipe */
+ pipe_exit();
+
+ /* unregister mmc uevent control routine */
+ ret = unregister_udev_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to unregister block uevent : %d", ret);
+
+ /* remove remaining blocks */
+ remove_whole_block_device();
+
+ for (i = 0; i < THREAD_MAX; i++) {
+ if (!th_manager[i].start_th)
+ pthread_cancel(th_manager[i].th);
+ }
+
+ block_control = false;
+}
+
+static int block_start(enum device_flags flags)
+{
+ int ret;
+
+ if (!block_boot) {
+ _E("Cannot be started. Booting is not ready");
+ return -ENODEV;
+ }
+
+ if (block_control) {
+ _I("Already started");
+ return 0;
+ }
+
+ /* register mmc uevent control routine */
+ ret = register_udev_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to register block uevent : %d", ret);
+
+ block_init_from_udev_enumerate();
+
+ block_control = true;
+
+ _I("start");
+ return 0;
+}
+
+static int block_stop(enum device_flags flags)
+{
+ if (!block_boot) {
+ _E("Cannot be stopped. Booting is not ready");
+ return -ENODEV;
+ }
+
+ if (!block_control) {
+ _I("Already stopped");
+ return 0;
+ }
+
+ /* unregister mmc uevent control routine */
+ unregister_udev_uevent_control(&uh);
+
+ /* remove the existing blocks */
+ remove_whole_block_device();
+
+ block_control = false;
+
+ _I("stop");
+ return 0;
+}
+
+const struct device_ops block_device_ops = {
+ .name = "block",
+ .init = block_init,
+ .exit = block_exit,
+ .start = block_start,
+ .stop = block_stop,
+};
+
+DEVICE_OPS_REGISTER(&block_device_ops)
--- /dev/null
+[Block]
+
+[MMC]
+Multimount=no # yes or no
+
+[SCSI]
+Multimount=yes # yes or no
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __BLOCK_H__
+#define __BLOCK_H__
+
+#include <stdbool.h>
+#include "core/common.h"
+
+#define SMACKFS_MOUNT_OPT "smackfsroot=*,smackfsdef=*"
+
+#define RETRY_COUNT 10
+
+enum block_fs_type {
+ FS_TYPE_VFAT = 0,
+ FS_TYPE_EXT4,
+};
+
+struct block_fs_ops {
+ enum block_fs_type type;
+ const char *name;
+ bool (*match) (const char *);
+ int (*check) (const char *);
+ int (*mount) (bool, const char *, const char *);
+ int (*format) (const char *);
+};
+
+struct fs_check {
+ int type;
+ char *name;
+ unsigned int offset;
+ unsigned int magic_sz;
+ char magic[4];
+};
+
+void add_fs(const struct block_fs_ops *fs);
+void remove_fs(const struct block_fs_ops *fs);
+
+enum block_device_type {
+ BLOCK_SCSI_DEV,
+ BLOCK_MMC_DEV,
+};
+
+enum mount_state {
+ BLOCK_UNMOUNT,
+ BLOCK_MOUNT,
+};
+
+enum unmount_operation {
+ UNMOUNT_NORMAL,
+ UNMOUNT_FORCE,
+};
+
+struct block_data {
+ enum block_device_type block_type;
+ char *devnode;
+ char *syspath;
+ char *fs_usage;
+ char *fs_type;
+ char *fs_version;
+ char *fs_uuid_enc;
+ bool readonly;
+ char *mount_point;
+ enum mount_state state;
+ bool primary; /* the first partition */
+ int flags;
+ int id; /* libstorage uses the id as the storage_id */
+};
+
+struct block_dev_ops {
+ const char *name;
+ enum block_device_type block_type;
+ void (*mounted) (struct block_data *data, int result);
+ void (*unmounted) (struct block_data *data, int result);
+ void (*formatted) (struct block_data *data, int result);
+ void (*inserted) (struct block_data *data);
+ void (*removed) (struct block_data *data);
+};
+
+void add_block_dev(const struct block_dev_ops *ops);
+void remove_block_dev(const struct block_dev_ops *ops);
+
+#define BLOCK_DEVICE_OPS_REGISTER(dev) \
+static void __CONSTRUCTOR__ block_dev_init(void) \
+{ \
+ add_block_dev(dev); \
+} \
+static void __DESTRUCTOR__ block_dev_exit(void) \
+{ \
+ remove_block_dev(dev); \
+}
+
+enum block_flags {
+ FLAG_NONE = 0,
+ UNMOUNT_UNSAFE = 1 << 0,
+ FS_BROKEN = 1 << 1,
+ FS_EMPTY = 1 << 2,
+ FS_NOT_SUPPORTED = 1 << 3,
+ MOUNT_READONLY = 1 << 4,
+};
+
+/* a: struct block_data
+ * b: enum block_flags */
+#define BLOCK_FLAG_SET(a, b) \
+ do { \
+ if (a) { \
+ (((a)->flags) |= (b)); \
+ } \
+ } while (0)
+
+#define BLOCK_FLAG_UNSET(a, b) \
+ do { \
+ if (a) { \
+ (((a)->flags) &= ~(b)); \
+ } \
+ } while (0)
+
+#define BLOCK_IS_FLAG_SET(a, b) \
+ ((a) ? ((((a)->flags) & (b)) ? true : false) : false)
+
+#define BLOCK_FLAG_CLEAR_ALL(a) \
+ do { \
+ if (a) { \
+ ((a)->flags) = FLAG_NONE; \
+ } \
+ } while (0)
+
+#define BLOCK_FLAG_MOUNT_CLEAR(a) \
+ do { \
+ BLOCK_FLAG_UNSET((a), FS_BROKEN); \
+ BLOCK_FLAG_UNSET((a), FS_EMPTY); \
+ BLOCK_FLAG_UNSET((a), FS_NOT_SUPPORTED); \
+ BLOCK_FLAG_UNSET((a), MOUNT_READONLY); \
+ } while (0)
+
+#define BLOCK_FLAG_UNMOUNT_CLEAR(a) \
+ do { \
+ BLOCK_FLAG_UNSET((a), UNMOUNT_UNSAFE); \
+ } while (0)
+
+#define BLOCK_GET_MOUNT_FLAGS(a, c) \
+ do { \
+ (c) = (a)->flags; \
+ (c) &= ~UNMOUNT_UNSAFE; \
+ } while (0)
+
+#define BLOCK_GET_UNMOUNT_FLAGS(a, c) \
+ do { \
+ (c) = 0; \
+ if (BLOCK_IS_FLAG_SET((a), UNMOUNT_UNSAFE)) \
+ (c) |= UNMOUNT_UNSAFE; \
+ } while (0)
+
+#define BLOCK_GET_FORMAT_FLAGS(a, c) \
+ do { \
+ (c) = 0; \
+ if (BLOCK_IS_FLAG_SET((a), FS_NOT_SUPPORTED)) \
+ (c) |= FS_NOT_SUPPORTED; \
+ } while (0)
+
+#endif /* __BLOCK_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <stdlib.h>
+#include <sys/mount.h>
+#include <limits.h>
+#include <vconf.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/launch.h"
+#include "core/log.h"
+#include "block.h"
+
+#define FS_EXT4_NAME "ext4"
+
+#define FS_EXT4_SMACK_LABEL "/usr/bin/mmc-smack-label"
+
+static const char *ext4_arg[] = {
+ "/sbin/mkfs.ext4",
+ NULL, NULL,
+};
+
+static const char *ext4_check_arg[] = {
+ "/sbin/fsck.ext4",
+ "-f", "-y", NULL, NULL,
+};
+
+static struct fs_check ext4_info = {
+ FS_TYPE_EXT4,
+ "ext4",
+ 0x438,
+ 2,
+ {0x53, 0xef},
+};
+
+static int mmc_popup_pid;
+
+static bool ext4_match(const char *devpath)
+{
+ char buf[4];
+ int fd, r;
+
+ fd = open(devpath, O_RDONLY);
+ if (fd < 0) {
+ _E("failed to open fd(%s) : %d", devpath, errno);
+ return false;
+ }
+
+ /* check fs type with magic code */
+ r = lseek(fd, ext4_info.offset, SEEK_SET);
+ if (r < 0)
+ goto error;
+
+ r = read(fd, buf, 2);
+ if (r < 0)
+ goto error;
+
+ _I("mmc search magic : 0x%2x, 0x%2x", buf[0], buf[1]);
+ if (memcmp(buf, ext4_info.magic, ext4_info.magic_sz))
+ goto error;
+
+ close(fd);
+ _I("MMC type : %s", ext4_info.name);
+ return true;
+
+error:
+ close(fd);
+ _E("failed to match with ext4(%s)", devpath);
+ return false;
+}
+
+static int ext4_check(const char *devpath)
+{
+ int argc;
+ argc = ARRAY_SIZE(ext4_check_arg);
+ ext4_check_arg[argc - 2] = devpath;
+ return run_child(argc, ext4_check_arg);
+}
+
+static int mmc_check_smack(const char *mount_point)
+{
+ char buf[NAME_MAX] = {0,};
+
+ snprintf(buf, sizeof(buf), "%s", mount_point);
+
+#ifdef TIZEN_FEATURE_BLOCK_SET_PERMISSION
+ launch_evenif_exist(FS_EXT4_SMACK_LABEL, buf);
+#endif
+
+ if (mmc_popup_pid > 0) {
+ _E("will be killed mmc-popup(%d)", mmc_popup_pid);
+ kill(mmc_popup_pid, SIGTERM);
+ }
+ return 0;
+}
+
+static int check_smack_popup(void)
+{
+ /* TODO: show smack popup */
+ return 0;
+}
+
+static int ext4_mount(bool smack, const char *devpath, const char *mount_point)
+{
+ int r, retry = RETRY_COUNT;
+ struct timespec time = {0,};
+ unsigned long mountflags = MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_DIRSYNC;
+
+ do {
+ r = mount(devpath, mount_point, "ext4", mountflags, NULL);
+ if (!r) {
+ _I("Mounted mmc card [ext4]");
+ if (smack) {
+ check_smack_popup();
+ mmc_check_smack(mount_point);
+ }
+ return 0;
+ }
+ _I("mount fail : r = %d, err = %d", r, errno);
+ time.tv_nsec = 100 * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+ if (r < 0 && errno == EROFS)
+ mountflags |= MS_RDONLY;
+ } while (r < 0 && (errno == ENOENT || errno == EROFS) && retry-- > 0);
+
+ return -errno;
+}
+
+static int ext4_format(const char *devpath)
+{
+ int argc;
+ argc = ARRAY_SIZE(ext4_arg);
+ ext4_arg[argc - 2] = devpath;
+ return run_child(argc, ext4_arg);
+}
+
+static const struct block_fs_ops ext4_ops = {
+ .type = FS_TYPE_EXT4,
+ .name = "ext4",
+ .match = ext4_match,
+ .check = ext4_check,
+ .mount = ext4_mount,
+ .format = ext4_format,
+};
+
+static void __CONSTRUCTOR__ module_init(void)
+{
+ add_fs(&ext4_ops);
+}
+/*
+static void __DESTRUCTOR__ module_exit(void)
+{
+ remove_fs(&ext4_ops);
+}
+*/
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <vconf.h>
+#include <sys/types.h>
+#include <attr/xattr.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "block/block.h"
+
+static void mmc_update_state(int state)
+{
+ static int old = -1;
+
+ if (old == state)
+ return;
+
+ if (vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, state) == 0)
+ old = state;
+}
+
+static void mmc_update_mount_state(int state)
+{
+ static int old = -1;
+
+ if (old == state)
+ return;
+
+ if (vconf_set_int(VCONFKEY_SYSMAN_MMC_MOUNT, state) == 0)
+ old = state;
+}
+
+static void mmc_mount(struct block_data *data, int result)
+{
+ int r;
+
+ /* Only the primary partition is valid. */
+ if (!data || !data->primary)
+ return;
+
+ if (result < 0) {
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
+ mmc_update_mount_state(VCONFKEY_SYSMAN_MMC_MOUNT_FAILED);
+ return;
+ }
+
+ /* Give a transmutable attribute to mount_point */
+ r = setxattr(data->mount_point, "security.SMACK64TRANSMUTE",
+ "TRUE", strlen("TRUE"), 0);
+ if (r < 0)
+ _E("setxattr error : %d", errno);
+
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_MOUNTED);
+ mmc_update_mount_state(VCONFKEY_SYSMAN_MMC_MOUNT_COMPLETED);
+}
+
+static void mmc_unmount(struct block_data *data, int result)
+{
+ /* Only the primary partition is valid. */
+ if (!data || !data->primary)
+ return;
+
+ if (result == 0)
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
+ else
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_MOUNTED);
+}
+
+static void mmc_format(struct block_data *data, int result)
+{
+ /* Only the primary partition is valid. */
+ if (!data || !data->primary)
+ return;
+
+ if (data->state == BLOCK_MOUNT) {
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_MOUNTED);
+ mmc_update_mount_state(VCONFKEY_SYSMAN_MMC_MOUNT_COMPLETED);
+ }
+}
+
+static void mmc_insert(struct block_data *data)
+{
+ /* Do nothing */
+}
+
+static void mmc_remove(struct block_data *data)
+{
+ /* Only the primary partition is valid. */
+ if (!data || !data->primary)
+ return;
+
+ mmc_update_state(VCONFKEY_SYSMAN_MMC_REMOVED);
+}
+
+const struct block_dev_ops mmc_block_ops = {
+ .name = "mmc",
+ .block_type = BLOCK_MMC_DEV,
+ .mounted = mmc_mount,
+ .unmounted = mmc_unmount,
+ .formatted = mmc_format,
+ .inserted = mmc_insert,
+ .removed = mmc_remove,
+};
+
+BLOCK_DEVICE_OPS_REGISTER(&mmc_block_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <fcntl.h>
+#include <assert.h>
+#include <limits.h>
+#include <vconf.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/shm.h>
+#include <time.h>
+#include <storage.h>
+#include <tzplatform_config.h>
+
+#include "device-node.h"
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/common.h"
+#include "core/edbus-handler.h"
+#include "core/device-notifier.h"
+#include "core/config-parser.h"
+#include "apps/apps.h"
+
+#define MEMORY_STATUS_TMP_PATH "/tmp"
+#define MEMNOTI_TMP_CRITICAL_VALUE (20)
+
+#define MEMORY_MEGABYTE_VALUE 1048576
+
+#define MEMNOTI_WARNING_VALUE (5) /* 5% under */
+#define MEMNOTI_CRITICAL_VALUE (0.1) /* 0.1% under */
+#define MEMNOTI_FULL_VALUE (0.0) /* 0.0% under */
+
+#define SIGNAL_LOWMEM_STATE "ChangeState"
+#define SIGNAL_LOWMEM_FULL "Full"
+#define MEMNOTI_TIMER_INTERVAL 5
+
+#define STORAGE_CONF_FILE "/etc/deviced/storage.conf"
+
+enum memnoti_level {
+ MEMNOTI_LEVEL_CRITICAL = 0,
+ MEMNOTI_LEVEL_WARNING,
+ MEMNOTI_LEVEL_NORMAL,
+ MEMNOTI_LEVEL_FULL,
+};
+
+enum memnoti_status {
+ MEMNOTI_DISABLE,
+ MEMNOTI_ENABLE,
+};
+
+struct storage_config_info {
+ enum memnoti_level current_noti_level;
+ double warning_level;
+ double critical_level;
+ double full_level;
+};
+
+static Ecore_Timer *memnoti_timer;
+
+static struct storage_config_info storage_internal_info = {
+ .current_noti_level = MEMNOTI_LEVEL_NORMAL,
+ .warning_level = MEMNOTI_WARNING_VALUE,
+ .critical_level = MEMNOTI_CRITICAL_VALUE,
+ .full_level = MEMNOTI_FULL_VALUE,
+};
+
+static struct storage_config_info storage_tmp_info = {
+ .current_noti_level = MEMNOTI_LEVEL_NORMAL,
+ .warning_level = MEMNOTI_TMP_CRITICAL_VALUE,
+ .critical_level = MEMNOTI_TMP_CRITICAL_VALUE,
+ .full_level = MEMNOTI_FULL_VALUE,
+};
+
+static void memnoti_send_broadcast(char *signal, int status)
+{
+ char *arr[1];
+ char str_status[32];
+
+ _I("signal %s status %d", signal, status);
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+ broadcast_edbus_signal(DEVICED_PATH_LOWMEM, DEVICED_INTERFACE_LOWMEM,
+ signal, "i", arr);
+}
+
+static int memnoti_popup(enum memnoti_level level)
+{
+ int ret = -1;
+ int val = -1;
+ char *value = NULL;
+
+ if (level != MEMNOTI_LEVEL_WARNING && level != MEMNOTI_LEVEL_CRITICAL) {
+ _E("level check error : %d", level);
+ return 0;
+ }
+
+ if (level == MEMNOTI_LEVEL_WARNING)
+ value = "lowstorage_warning";
+ else if (level == MEMNOTI_LEVEL_CRITICAL)
+ value = "lowstorage_critical";
+
+ ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &val);
+ if (val == 0 || ret != 0)
+ goto out;
+
+ if (value) {
+ ret = launch_system_app(APP_DEFAULT,
+ 2, APP_KEY_TYPE, value);
+ if (ret < 0)
+ _E("Failed to launch (%s) popup", value);
+ }
+
+ return 0;
+out:
+ return -1;
+}
+
+static void storage_status_broadcast(struct storage_config_info *info, double total, double avail)
+{
+ double level = (avail/total)*100;
+ int status = MEMNOTI_DISABLE;
+
+ if (level <= info->full_level) {
+ if (info->current_noti_level == MEMNOTI_LEVEL_FULL)
+ return;
+ info->current_noti_level = MEMNOTI_LEVEL_FULL;
+ status = MEMNOTI_ENABLE;
+ memnoti_send_broadcast(SIGNAL_LOWMEM_FULL, status);
+ return;
+ }
+
+ if (level <= info->critical_level) {
+ if (info->current_noti_level == MEMNOTI_LEVEL_CRITICAL)
+ return;
+ if (info->current_noti_level == MEMNOTI_LEVEL_FULL)
+ memnoti_send_broadcast(SIGNAL_LOWMEM_FULL, status);
+ info->current_noti_level = MEMNOTI_LEVEL_CRITICAL;
+ status = MEMNOTI_ENABLE;
+ memnoti_send_broadcast(SIGNAL_LOWMEM_STATE, status);
+ return;
+ }
+
+ if (info->current_noti_level == MEMNOTI_LEVEL_FULL)
+ memnoti_send_broadcast(SIGNAL_LOWMEM_FULL, status);
+ if (info->current_noti_level == MEMNOTI_LEVEL_CRITICAL)
+ memnoti_send_broadcast(SIGNAL_LOWMEM_STATE, status);
+ if (level <= info->warning_level)
+ info->current_noti_level = MEMNOTI_LEVEL_WARNING;
+ else
+ info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
+}
+
+static int storage_get_memory_size(const char *path, struct statvfs *s)
+{
+ int ret;
+
+ if (!path) {
+ _E("input param error");
+ return -EINVAL;
+ }
+
+ ret = statvfs(path, s);
+ if (ret) {
+ _E("fail to get storage size");
+ return -errno;
+ }
+
+ return 0;
+}
+
+static void get_storage_status(const char *path, struct statvfs *s)
+{
+ if (strcmp(path, tzplatform_getenv(TZ_SYS_HOME)) == 0)
+ storage_get_internal_memory_size(s);
+ else
+ storage_get_memory_size(path, s);
+}
+
+static void init_storage_config_info(const char *path, struct storage_config_info *info)
+{
+ struct statvfs s;
+ double dAvail = 0.0;
+ double dTotal = 0.0;
+
+ get_storage_status(path, &s);
+
+ dTotal = (double)(s.f_frsize * s.f_blocks);
+ dAvail = (double)(s.f_bsize * s.f_bavail);
+
+ info->full_level += (MEMORY_MEGABYTE_VALUE/dTotal)*100;
+
+ _I("%s t: %4.0lf a: %4.0lf(%4.2lf) c:%4.4lf f:%4.4lf",
+ path, dTotal, dAvail, (dAvail*100/dTotal), info->critical_level, info->full_level);
+}
+
+static void check_internal_storage_popup(struct storage_config_info *info)
+{
+ static enum memnoti_level old = MEMNOTI_LEVEL_NORMAL;
+ int ret;
+
+ if (info->current_noti_level < MEMNOTI_LEVEL_NORMAL && info->current_noti_level < old) {
+ ret = memnoti_popup(info->current_noti_level);
+ if (ret != 0)
+ info->current_noti_level = MEMNOTI_LEVEL_NORMAL;
+ }
+ old = info->current_noti_level;
+}
+
+static Eina_Bool check_storage_status(void *data)
+{
+ struct statvfs s;
+ double dAvail = 0.0;
+ double dTotal = 0.0;
+
+ /* check internal */
+ storage_get_internal_memory_size(&s);
+ dTotal = (double)s.f_frsize * s.f_blocks;
+ dAvail = (double)s.f_bsize * s.f_bavail;
+ storage_status_broadcast(&storage_internal_info, dTotal, dAvail);
+ check_internal_storage_popup(&storage_internal_info);
+ /* check tmp */
+ storage_get_memory_size(MEMORY_STATUS_TMP_PATH, &s);
+ dTotal = (double)s.f_frsize * s.f_blocks;
+ dAvail = (double)s.f_bsize * s.f_bavail;
+ storage_status_broadcast(&storage_tmp_info, dTotal, dAvail);
+
+ if (memnoti_timer)
+ ecore_timer_interval_set(memnoti_timer, MEMNOTI_TIMER_INTERVAL);
+
+ return EINA_TRUE;
+}
+
+static int init_storage_config_info_all(void)
+{
+ init_storage_config_info(tzplatform_getenv(TZ_SYS_HOME), &storage_internal_info);
+ init_storage_config_info(MEMORY_STATUS_TMP_PATH, &storage_tmp_info);
+ memnoti_timer = ecore_timer_add(MEMNOTI_TIMER_INTERVAL,
+ check_storage_status, NULL);
+ if (memnoti_timer == NULL)
+ _E("fail mem available noti timer add");
+ return 0;
+}
+
+static DBusMessage *edbus_getstatus(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ struct statvfs s;
+ unsigned long long dAvail = 0.0;
+ unsigned long long dTotal = 0.0;
+
+ storage_get_internal_memory_size(&s);
+ dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
+ dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &dTotal);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &dAvail);
+ return reply;
+}
+
+static DBusMessage *edbus_get_storage_status(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ char *path;
+ struct statvfs s;
+ pid_t pid;
+ unsigned long long dAvail = 0.0;
+ unsigned long long dTotal = 0.0;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) {
+ _E("Bad message: [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ goto out;
+ }
+
+ if (!strcmp(path, tzplatform_getenv(TZ_SYS_HOME)))
+ storage_get_internal_memory_size(&s);
+ else
+ storage_get_memory_size(path, &s);
+
+ dTotal = (unsigned long long)s.f_frsize * s.f_blocks;
+ dAvail = (unsigned long long)s.f_bsize * s.f_bavail;
+
+ pid = get_edbus_sender_pid(msg);
+
+ _D("[request %d] path %s total %4.0lf avail %4.0lf", pid, path, dTotal, dAvail);
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &dTotal);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &dAvail);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "getstorage", NULL, "tt", edbus_getstatus },
+ { "GetStatus", "s", "tt", edbus_get_storage_status},
+ /* Add methods here */
+};
+
+static int booting_done(void *data)
+{
+ static int done;
+
+ if (data == NULL)
+ return done;
+ done = *(int *)data;
+ if (done == 0)
+ return done;
+
+ _I("booting done");
+
+ if (init_storage_config_info_all() == -1)
+ _E("fail remain mem noti control fd init");
+ return done;
+}
+
+static int storage_poweroff(void *data)
+{
+ if (memnoti_timer) {
+ ecore_timer_del(memnoti_timer);
+ memnoti_timer = NULL;
+ }
+ return 0;
+}
+
+static int load_config(struct parse_result *result, void *user_data)
+{
+ struct storage_config_info *info = (struct storage_config_info *)user_data;
+ char *name;
+ char *value;
+
+ if (!info)
+ return -EINVAL;
+
+ if (!MATCH(result->section, "LOWSTORAGE"))
+ return -EINVAL;
+
+ _D("%s,%s,%s", result->section, result->name, result->value);
+
+ name = result->name;
+ value = result->value;
+
+ if (MATCH(name, "WARNING_LEVEL"))
+ info->warning_level = (double)atof(value);
+ else if (MATCH(name, "CRITICAL_LEVEL"))
+ info->critical_level = (double)atof(value);
+ else if (MATCH(name, "FULL_LEVEL"))
+ info->full_level = (double)atof(value);
+
+ return 0;
+}
+
+static void storage_config_load(struct storage_config_info *info)
+{
+ int ret;
+
+ ret = config_parse(STORAGE_CONF_FILE, load_config, info);
+ if (ret < 0)
+ _E("Failed to load %s, %d Use default value!", STORAGE_CONF_FILE, ret);
+}
+
+static void storage_init(void *data)
+{
+ int ret;
+
+ storage_config_load(&storage_internal_info);
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ register_notifier(DEVICE_NOTIFIER_POWEROFF, storage_poweroff);
+ ret = register_edbus_method(DEVICED_PATH_STORAGE, edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static void storage_exit(void *data)
+{
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ unregister_notifier(DEVICE_NOTIFIER_POWEROFF, storage_poweroff);
+}
+
+static const struct device_ops storage_device_ops = {
+ .name = "storage",
+ .init = storage_init,
+ .exit = storage_exit,
+};
+
+DEVICE_OPS_REGISTER(&storage_device_ops)
--- /dev/null
+[LOWSTORAGE]
+#5%
+WARNING_LEVEL=5
+#0.1%
+CRITICAL_LEVEL=0.1
+#0.0%
+FULL_LEVEL=0
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <sys/mount.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "core/common.h"
+#include "core/log.h"
+#include "block.h"
+
+#define FS_VFAT_NAME "mkdosfs"
+
+#ifdef TIZEN_FEATURE_BLOCK_SET_PERMISSION
+/* guid 10001 - group priv_externalstorage */
+#define FS_VFAT_MOUNT_OPT "uid=0,gid=10001,dmask=0007,fmask=0117,iocharset=iso8859-1,utf8,shortname=mixed"
+#else
+#define FS_VFAT_MOUNT_OPT "iocharset=iso8859-1,utf8,shortname=mixed"
+#endif
+
+static const char *vfat_arg[] = {
+ "/usr/bin/newfs_msdos",
+ "-F", "32", "-O", "tizen", "-c", "8", NULL, NULL,
+};
+
+static const char *vfat_check_arg[] = {
+ "/usr/bin/fsck_msdosfs",
+ "-pf", NULL, NULL,
+};
+
+static struct fs_check vfat_info = {
+ FS_TYPE_VFAT,
+ "vfat",
+ 0x1fe,
+ 2,
+ {0x55, 0xAA},
+};
+
+static int vfat_check(const char *devpath)
+{
+ int argc, r, pass = 0;
+
+ argc = ARRAY_SIZE(vfat_check_arg);
+ vfat_check_arg[argc - 2] = devpath;
+
+ do {
+ r = run_child(argc, vfat_check_arg);
+
+ switch (r) {
+ case 0:
+ _I("filesystem check completed OK");
+ return 0;
+ case 2:
+ _I("file system check failed (not a FAT filesystem)");
+ errno = ENODATA;
+ return -1;
+ case 4:
+ if (pass++ <= 2) {
+ _I("filesystem modified - rechecking (pass : %d)", pass);
+ continue;
+ }
+ _I("failing check after rechecks, but file system modified");
+ errno = EIO;
+ return -1;
+ default:
+ _I("filesystem check failed (unknown exit code %d)", r);
+ errno = EIO;
+ return -1;
+ }
+ } while (1);
+}
+
+static bool vfat_match(const char *devpath)
+{
+ int r;
+
+ r = vfat_check(devpath);
+ if (r < 0) {
+ _E("failed to match with vfat(%s)", devpath);
+ return false;
+ }
+
+ _I("MMC type : %s", vfat_info.name);
+ return true;
+}
+
+static int vfat_mount(bool smack, const char *devpath, const char *mount_point)
+{
+ char options[NAME_MAX];
+ int r, retry = RETRY_COUNT;
+ struct timespec time = {0,};
+ unsigned long mountflags = MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_DIRSYNC;
+
+ if (smack)
+ snprintf(options, sizeof(options), "%s,%s", FS_VFAT_MOUNT_OPT, SMACKFS_MOUNT_OPT);
+ else
+ snprintf(options, sizeof(options), "%s", FS_VFAT_MOUNT_OPT);
+
+ do {
+ r = mount(devpath, mount_point, "vfat", mountflags, options);
+ if (!r) {
+ _I("Mounted mmc card [vfat]");
+ return 0;
+ }
+ _I("mount fail : r = %d, err = %d", r, errno);
+ time.tv_nsec = 100 * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+ if (r < 0 && errno == EROFS)
+ mountflags |= MS_RDONLY;
+ } while (r < 0 && (errno == ENOENT || errno == EROFS) && retry-- > 0);
+
+ return -errno;
+}
+
+static int vfat_format(const char *devpath)
+{
+ int argc;
+ argc = ARRAY_SIZE(vfat_arg);
+ vfat_arg[argc - 2] = devpath;
+ return run_child(argc, vfat_arg);
+}
+
+static const struct block_fs_ops vfat_ops = {
+ .type = FS_TYPE_VFAT,
+ .name = "vfat",
+ .match = vfat_match,
+ .check = vfat_check,
+ .mount = vfat_mount,
+ .format = vfat_format,
+};
+
+static void __CONSTRUCTOR__ module_init(void)
+{
+ add_fs(&vfat_ops);
+}
+/*
+static void __DESTRUCTOR__ module_exit(void)
+{
+ _I("module exit");
+ remove_fs(&vfat_ops);
+}
+*/
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <assert.h>
+#include <sys/types.h>
+#include <dd-control.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+
+#define CONTROL_HANDLER_NAME "control"
+#define CONTROL_GETTER_NAME "getcontrol"
+
+static const struct control_device {
+ const int id;
+ const char *name;
+} devices[] = {
+ /* Add id & ops to provide start/stop control */
+ { DEVICE_CONTROL_MMC, "mmc" },
+ { DEVICE_CONTROL_USBCLIENT, "usbclient" },
+ { DEVICE_CONTROL_BLOCK, "block" },
+};
+
+static int control_handler(int argc, char **argv)
+{
+ int i;
+ int pid;
+ int device;
+ bool enable;
+ int ret;
+ const struct device_ops *dev_ops = NULL;
+
+ _I("argc : %d", argc);
+ for (i = 0; i < argc; ++i)
+ _I("[%2d] %s", i, argv[i]);
+
+ if (argc > 5) {
+ _E("Invalid argument");
+ errno = EINVAL;
+ return -1;
+ }
+
+ pid = atoi(argv[0]);
+ device = atoi(argv[1]);
+ enable = atoi(argv[2]);
+ _I("pid : %d, device : %d, enable :%d", pid, device, enable);
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++)
+ if (devices[i].id == device)
+ break;
+
+ if (i >= ARRAY_SIZE(devices))
+ return -EINVAL;
+ FIND_DEVICE_INT(dev_ops, devices[i].name);
+ if (enable)
+ ret = device_start(dev_ops);
+ else
+ ret = device_stop(dev_ops);
+
+ return ret;
+}
+
+static int get_control_handler(int argc, char **argv)
+{
+ int i;
+ int pid;
+ int device;
+ const struct device_ops *dev_ops = NULL;
+
+ _I("argc : %d", argc);
+ for (i = 0; i < argc; ++i)
+ _I("[%2d] %s", i, argv[i]);
+
+ if (argc > 4) {
+ _E("Invalid argument");
+ errno = EINVAL;
+ return -1;
+ }
+
+ pid = atoi(argv[0]);
+ device = atoi(argv[1]);
+ _I("pid : %d, device : %d", pid, device);
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++)
+ if (devices[i].id == device)
+ break;
+
+ if (i >= ARRAY_SIZE(devices))
+ return -EINVAL;
+
+ FIND_DEVICE_INT(dev_ops, devices[i].name);
+
+ return device_get_status(dev_ops);
+}
+
+
+static DBusMessage *dbus_control_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret;
+ int argc;
+ char *type_str;
+ char *argv[3];
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv[0],
+ DBUS_TYPE_STRING, &argv[1],
+ DBUS_TYPE_STRING, &argv[2], DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ ret = control_handler(argc, (char **)&argv);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *dbus_get_control_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret;
+ int argc;
+ char *type_str;
+ char *argv[2];
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv[0],
+ DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ ret = get_control_handler(argc, (char **)&argv);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { CONTROL_HANDLER_NAME, "sisss", "i", dbus_control_handler },
+ { CONTROL_GETTER_NAME , "siss", "i", dbus_get_control_handler },
+};
+
+static void control_init(void *data)
+{
+ int ret;
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI, edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static const struct device_ops control_device_ops = {
+ .name = "control",
+ .init = control_init,
+};
+
+DEVICE_OPS_REGISTER(&control_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <poll.h>
+#include <mntent.h>
+
+#include "log.h"
+#include "common.h"
+
+#define PERMANENT_DIR "/tmp/permanent"
+#define VIP_DIR "/tmp/vip"
+#define BUFF_MAX 255
+
+#define APP_ATTR_PATH "/proc/%d/attr/current"
+
+/**
+ * Opens "/proc/$pid/oom_score_adj" file for w/r;
+ * Return: FILE pointer or NULL
+ */
+FILE *open_proc_oom_score_adj_file(int pid, const char *mode)
+{
+ char buf[32];
+ FILE *fp;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/oom_score_adj", pid);
+ fp = fopen(buf, mode);
+ return fp;
+}
+
+int get_exec_pid(const char *execpath)
+{
+ DIR *dp;
+ struct dirent entry;
+ struct dirent *dentry;
+ int pid = -1, fd;
+ int ret;
+ int len;
+ char buf[PATH_MAX];
+ char buf2[PATH_MAX];
+
+ dp = opendir("/proc");
+ if (!dp) {
+ _E("FAIL: open /proc");
+ return -1;
+ }
+
+ len = strlen(execpath) + 1;
+ while (1) {
+ ret = readdir_r(dp, &entry, &dentry);
+ if (ret != 0 || dentry == NULL)
+ break;
+
+ if (!isdigit(dentry->d_name[0]))
+ continue;
+
+ pid = atoi(dentry->d_name);
+
+ snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ continue;
+ ret = read(fd, buf2, PATH_MAX);
+ close(fd);
+
+ if (ret < 0 || ret >= PATH_MAX)
+ continue;
+
+ buf2[ret] = '\0';
+
+ if (!strncmp(buf2, execpath, len)) {
+ closedir(dp);
+ return pid;
+ }
+ }
+
+ errno = ESRCH;
+ closedir(dp);
+ return -1;
+}
+
+int get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
+{
+ int fd, ret;
+ char buf[PATH_MAX + 1];
+ char *filename;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ errno = ESRCH;
+ return -1;
+ }
+
+ ret = read(fd, buf, PATH_MAX);
+ close(fd);
+ if (ret < 0)
+ return -1;
+
+ buf[PATH_MAX] = '\0';
+
+ filename = strrchr(buf, '/');
+ if (filename == NULL)
+ filename = buf;
+ else
+ filename = filename + 1;
+
+ if (cmdline_size < strlen(filename) + 1) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ strncpy(cmdline, filename, cmdline_size - 1);
+ cmdline[cmdline_size - 1] = '\0';
+ return 0;
+}
+
+int is_vip(int pid)
+{
+ if (pid < 1)
+ return -1;
+
+ char buf[PATH_MAX];
+
+ snprintf(buf, PATH_MAX, "%s/%d", VIP_DIR, pid);
+
+ if (access(buf, R_OK) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static int remove_dir_internal(int fd)
+{
+ DIR *dir;
+ struct dirent entry;
+ struct dirent *de;
+ int subfd, ret = 0;
+
+ dir = fdopendir(fd);
+ if (!dir)
+ return -1;
+ while (1) {
+ ret = readdir_r(dir, &entry, &de);
+ if (ret != 0 || de == NULL)
+ break;
+ if (de->d_type == DT_DIR) {
+ if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
+ continue;
+ subfd = openat(fd, de->d_name, O_RDONLY | O_DIRECTORY);
+ if (subfd < 0) {
+ _SE("Couldn't openat %s: %d\n", de->d_name, errno);
+ ret = -1;
+ continue;
+ }
+ if (remove_dir_internal(subfd))
+ ret = -1;
+
+ close(subfd);
+ if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+ ret = -1;
+ }
+ } else {
+ if (unlinkat(fd, de->d_name, 0) < 0) {
+ _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+ ret = -1;
+ }
+ }
+ }
+ closedir(dir);
+ return ret;
+}
+
+int remove_dir(const char *path, int del_dir)
+{
+ int fd, ret = 0;
+
+ if (!path)
+ return -1;
+ fd = open(path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
+ if (fd < 0) {
+ _SE("Couldn't opendir %s: %d\n", path, errno);
+ return -errno;
+ }
+ ret = remove_dir_internal(fd);
+ close(fd);
+
+ if (del_dir) {
+ if (rmdir(path)) {
+ _SE("Couldn't rmdir %s: %d\n", path, errno);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Helper function
+ * - Read from sysfs entry
+ * - Write to sysfs entry
+ */
+int sys_check_node(char *path)
+{
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ close(fd);
+ return 0;
+}
+
+static int sys_read_buf(char *file, char *buf)
+{
+ int fd;
+ int r;
+ int ret = 0;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -ENOENT;
+
+ r = read(fd, buf, BUFF_MAX);
+ if ((r >= 0) && (r < BUFF_MAX))
+ buf[r] = '\0';
+ else
+ ret = -EIO;
+
+ close(fd);
+
+ return ret;
+}
+
+static int sys_write_buf(char *file, char *buf)
+{
+ int fd;
+ int r;
+ int ret = 0;
+
+ fd = open(file, O_WRONLY);
+ if (fd == -1)
+ return -ENOENT;
+
+ r = write(fd, buf, strlen(buf));
+ if (r < 0)
+ ret = -EIO;
+
+ close(fd);
+
+ return ret;
+}
+
+int sys_get_int(char *fname, int *val)
+{
+ char buf[BUFF_MAX];
+ int ret = 0;
+
+ if (sys_read_buf(fname, buf) == 0) {
+ *val = atoi(buf);
+ } else {
+ *val = -1;
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+int sys_set_int(char *fname, int val)
+{
+ char buf[BUFF_MAX];
+ int ret = 0;
+
+ snprintf(buf, sizeof(buf), "%d", val);
+
+ if (sys_write_buf(fname, buf) != 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+int sys_get_str(char *fname, char *str)
+{
+ char buf[BUFF_MAX] = {0};
+
+ if (sys_read_buf(fname, buf) == 0) {
+ strncpy(str, buf, strlen(buf));
+ return 0;
+ }
+
+ return -1;
+}
+
+int sys_set_str(char *fname, char *val)
+{
+ int r = -1;
+
+ if (val != NULL) {
+ if (sys_write_buf(fname, val) == 0)
+ r = 0;
+ }
+
+ return r;
+}
+
+int terminate_process(const char *partition, bool force)
+{
+ const char *argv[7] = {"/usr/bin/fuser", "-m", "-k", "-s", NULL, NULL, NULL};
+ int argc;
+
+ if (force)
+ argv[4] = "-SIGKILL";
+ else
+ argv[4] = "-SIGTERM";
+ argv[5] = partition;
+ argc = sizeof(argv) / sizeof(argv[0]);
+ return run_child(argc, argv);
+}
+
+int mount_check(const char *path)
+{
+ int ret = false;
+ struct mntent *mnt;
+ const char *table = "/etc/mtab";
+ FILE *fp;
+ int len;
+
+ fp = setmntent(table, "r");
+ if (!fp)
+ return ret;
+
+ len = strlen(path) + 1;
+ while (1) {
+ mnt = getmntent(fp);
+ if (mnt == NULL)
+ break;
+ if (!strncmp(mnt->mnt_dir, path, len)) {
+ ret = true;
+ break;
+ }
+ }
+ endmntent(fp);
+ return ret;
+}
+
+void print_time(const char *prefix)
+{
+ struct timeval tv;
+ struct tm tm;
+ struct tm *ret;
+ gettimeofday(&tv, NULL);
+ ret = localtime_r(&(tv.tv_sec), &tm);
+ if (ret)
+ _D("%s --> %d:%02d:%02d %d",
+ prefix, tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec);
+}
+
+int get_privilege(pid_t pid, char *name, size_t len)
+{
+ char path[PATH_MAX];
+ char attr[BUFF_MAX];
+ size_t attr_len;
+ FILE *fp;
+
+ snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
+
+ fp = fopen(path, "r");
+ if (!fp)
+ return -errno;
+
+ attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
+ fclose(fp);
+ if (attr_len == 0)
+ return -ENOENT;
+
+ attr[attr_len] = '\0';
+
+ snprintf(name, len, "%s", attr);
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __CORE_COMMON_H__
+#define __CORE_COMMON_H__
+
+#include <Ecore.h>
+#include <stdio.h>
+#include <error.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
+
+/*
+ * One byte digit has 3 position in decimal representation
+ * 2 - 5
+ * 4 - 10
+ * 8 - 20
+ * >8 - compile time error
+ * plus 1 null termination byte
+ * plus 1 for negative prefix
+ */
+#define MAX_DEC_SIZE(type) \
+ (2 + (sizeof(type) <= 1 ? 3 : \
+ sizeof(type) <= 2 ? 5 : \
+ sizeof(type) <= 4 ? 10 : \
+ sizeof(type) <= 8 ? 20 : \
+ sizeof(int[-2*(sizeof(type) > 8)])))
+
+#ifndef __CONSTRUCTOR__
+#define __CONSTRUCTOR__ __attribute__ ((constructor))
+#endif
+
+#ifndef __DESTRUCTOR__
+#define __DESTRUCTOR__ __attribute__ ((destructor))
+#endif
+
+#ifndef __WEAK__
+#define __WEAK__ __attribute__ ((weak))
+#endif
+
+#ifndef max
+#define max(a, b) \
+ __extension__ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a > _b ? _a : _b; \
+ })
+#endif
+
+#ifndef min
+#define min(a, b) \
+ __extension__ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+#endif
+
+#ifndef clamp
+#define clamp(x, low, high) \
+ __extension__ ({ \
+ typeof(x) _x = (x); \
+ typeof(low) _low = (low); \
+ typeof(high) _high = (high); \
+ ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
+ })
+#endif
+
+#ifndef SEC_TO_MSEC
+#define SEC_TO_MSEC(x) ((x)*1000)
+#endif
+#ifndef MSEC_TO_USEC
+#define MSEC_TO_USEC(x) ((unsigned int)(x)*1000)
+#endif
+#ifndef NSEC_TO_MSEC
+#define NSEC_TO_MSEC(x) ((double)x/1000000)
+#endif
+#ifndef USEC_TO_MSEC
+#define USEC_TO_MSEC(x) ((double)x/1000)
+#endif
+
+#define NANO_SECOND_MULTIPLIER 1000000 /* 1ms = 1,000,000 nsec */
+
+#ifndef safe_free
+#define safe_free(x) safe_free_memory((void**)&(x))
+#endif
+
+static inline void safe_free_memory(void** mem)
+{
+ if (mem && *mem) {
+ free(*mem);
+ *mem = NULL;
+ }
+}
+
+#define ret_value_if(expr, val) do { \
+ if (expr) { \
+ _E("(%s)", #expr); \
+ return (val); \
+ } \
+} while (0)
+
+#define ret_value_msg_if(expr, val, fmt, arg...) do { \
+ if (expr) { \
+ _E(fmt, ##arg); \
+ return val; \
+ } \
+} while (0)
+
+#define ret_msg_if(expr, fmt, arg...) do { \
+ if (expr) { \
+ _E(fmt, ##arg); \
+ return; \
+ } \
+} while (0)
+
+FILE * open_proc_oom_score_adj_file(int pid, const char *mode);
+int get_exec_pid(const char *execpath);
+int get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size);
+int is_vip(int pid);
+int run_child(int argc, const char *argv[]);
+int remove_dir(const char *path, int del_dir);
+int sys_check_node(char *path);
+int sys_get_int(char *fname, int *val);
+int sys_set_int(char *fname, int val);
+int sys_get_str(char *fname, char *str);
+int sys_set_str(char *fname, char *val);
+int terminate_process(const char *partition, bool force);
+int mount_check(const char* path);
+void print_time(const char *prefix);
+int get_privilege(pid_t pid, char *name, size_t len);
+
+#endif /* __CORE_COMMON_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2013 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 <string.h>
+#include <errno.h>
+#include "log.h"
+#include "config-parser.h"
+
+#define MAX_LINE 128
+#define MAX_SECTION 64
+#define WHITESPACE " \t"
+#define NEWLINE "\n\r"
+#define COMMENT '#'
+
+static inline char *trim_str(char *s)
+{
+ char *t;
+ /* left trim */
+ s += strspn(s, WHITESPACE);
+
+ /* right trim */
+ for (t = strchr(s, 0); t > s; t--)
+ if (!strchr(WHITESPACE, t[-1]))
+ break;
+ *t = 0;
+ return s;
+}
+
+int config_parse(const char *file_name, int cb(struct parse_result *result,
+ void *user_data), void *user_data)
+{
+ FILE *f = NULL;
+ struct parse_result result;
+ /* use stack for parsing */
+ char line[MAX_LINE];
+ char section[MAX_SECTION];
+ char *start, *end, *name, *value;
+ int lineno = 0, ret = 0;
+
+ if (!file_name || !cb) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* open conf file */
+ f = fopen(file_name, "r");
+ if (!f) {
+ _E("Failed to open file %s", file_name);
+ ret = -EIO;
+ goto error;
+ }
+
+ /* parsing line by line */
+ while (fgets(line, MAX_LINE, f) != NULL) {
+ lineno++;
+
+ start = line;
+ start[strcspn(start, NEWLINE)] = '\0';
+ start = trim_str(start);
+
+ if (*start == COMMENT) {
+ continue;
+ } else if (*start == '[') {
+ /* parse section */
+ end = strchr(start, ']');
+ if (!end || *end != ']') {
+ ret = -EBADMSG;
+ goto error;
+ }
+
+ *end = '\0';
+ strncpy(section, start + 1, sizeof(section));
+ section[MAX_SECTION-1] = '\0';
+ } else if (*start) {
+ /* parse name & value */
+ end = strchr(start, '=');
+ if (!end || *end != '=') {
+ ret = -EBADMSG;
+ goto error;
+ }
+ *end = '\0';
+ name = trim_str(start);
+ value = trim_str(end + 1);
+ end = strchr(value, COMMENT);
+ if (end && *end == COMMENT) {
+ *end = '\0';
+ value = trim_str(value);
+ }
+
+ result.section = section;
+ result.name = name;
+ result.value = value;
+ /* callback with parse result */
+ ret = cb(&result, user_data);
+ if (ret < 0) {
+ ret = -EBADMSG;
+ goto error;
+ }
+ }
+ }
+ _D("Success to load %s", file_name);
+ fclose(f);
+ return 0;
+
+error:
+ if (f)
+ fclose(f);
+ _E("Failed to read %s:%d!", file_name, lineno);
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2013 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 __CONFIG_PARSER_H__
+#define __CONFIG_PARSER_H__
+
+#define MATCH(a, b) (!strncmp(a, b, strlen(a)))
+#define SET_CONF(a, b) (a = (b > 0.0 ? b : a))
+
+struct parse_result {
+ char *section;
+ char *name;
+ char *value;
+};
+
+/**
+ * @brief Parse config file and call callback\n
+ * @param[in] file_name conf file.
+ * @param[in] cb cb is called when conf file is parsed line by line.
+ * @param[in] user_data user data is passed to cb.
+ * @return 0 on success, negative if failed
+ */
+int config_parse(const char *file_name, int cb(struct parse_result *result,
+ void *user_data), void *user_data);
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <Ecore.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "log.h"
+
+struct device_request {
+ void (*func)(void *data);
+ void *data;
+};
+
+static GQueue req_queue = G_QUEUE_INIT;
+static Ecore_Idler *idler;
+
+static int free_request(struct device_request *req)
+{
+ if (!req)
+ return -EINVAL;
+
+ free(req);
+ return 0;
+}
+
+static Eina_Bool idler_cb(void *data)
+{
+ struct device_request *req;
+
+ req = g_queue_pop_head(&req_queue);
+ if (req) {
+ if (req->func)
+ req->func(req->data);
+ free_request(req);
+ }
+
+ if (g_queue_is_empty(&req_queue)) {
+ idler = NULL;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void process_next_request_in_idle(void)
+{
+ if (g_queue_is_empty(&req_queue))
+ return;
+
+ if (idler)
+ return;
+
+ idler = ecore_idler_add(idler_cb, NULL);
+ /**
+ * if idler is null,
+ * it means whole system might be an abnormal state.
+ * so it just prints out error log.
+ */
+ if (!idler)
+ _E("fail to add request to idler");
+}
+
+int add_idle_request(void (*func)(void *data), void *data)
+{
+ struct device_request *req;
+
+ if (!func) {
+ _E("invalid argumet : func(NULL)");
+ return -EINVAL;
+ }
+
+ req = calloc(1, sizeof(struct device_request));
+ if (!req) {
+ _E("fail to allocate request : %d", errno);
+ return -errno;
+ }
+
+ req->func = func;
+ req->data = data;
+
+ g_queue_push_tail(&req_queue, req);
+ process_next_request_in_idle();
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __DEVICE_IDLER_H__
+#define __DEVICE_IDLER_H__
+
+/*
+ * To allow for callbacks to be called when the daemon is idle state.
+ */
+
+int add_idle_request(void (*func)(void *data), void *data);
+
+#endif /* __DEVICE_IDLER_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 "log.h"
+#include "device-notifier.h"
+#include "list.h"
+#include "common.h"
+
+struct device_notifier {
+ bool deleted;
+ enum device_notifier_type status;
+ int (*func)(void *data);
+};
+
+static dd_list *device_notifier_list;
+static Ecore_Idler *idl;
+
+#define FIND_NOTIFIER(a, b, d, e, f) \
+ DD_LIST_FOREACH(a, b, d) \
+ if (e == d->e && f == (d->f))
+
+int register_notifier(enum device_notifier_type status, int (*func)(void *data))
+{
+ dd_list *n;
+ struct device_notifier *notifier;
+
+ _I("%d, %x", status, func);
+
+ if (!func) {
+ _E("invalid func address!");
+ return -EINVAL;
+ }
+
+ FIND_NOTIFIER(device_notifier_list, n, notifier, status, func) {
+ _E("function is already registered! [%d, %x]",
+ status, func);
+ return -EINVAL;
+ }
+
+ notifier = calloc(1, sizeof(struct device_notifier));
+ if (!notifier) {
+ _E("Fail to malloc for notifier!");
+ return -ENOMEM;
+ }
+
+ notifier->status = status;
+ notifier->func = func;
+
+ DD_LIST_APPEND(device_notifier_list, notifier);
+
+ return 0;
+}
+
+int unregister_notifier(enum device_notifier_type status, int (*func)(void *data))
+{
+ dd_list *n;
+ struct device_notifier *notifier;
+
+ if (!func) {
+ _E("invalid func address!");
+ return -EINVAL;
+ }
+
+ FIND_NOTIFIER(device_notifier_list, n, notifier, status, func) {
+ _I("[%d, %x]", status, func);
+ notifier->deleted = true;
+ }
+
+ return 0;
+}
+
+static Eina_Bool delete_unused_notifier_cb(void *data)
+{
+ dd_list *n;
+ dd_list *next;
+ struct device_notifier *notifier;
+
+ DD_LIST_FOREACH_SAFE(device_notifier_list, n, next, notifier) {
+ if (notifier->deleted) {
+ DD_LIST_REMOVE_LIST(device_notifier_list, n);
+ free(notifier);
+ }
+ }
+
+ idl = NULL;
+ return ECORE_CALLBACK_CANCEL;
+}
+
+void device_notify(enum device_notifier_type status, void *data)
+{
+ dd_list *n;
+ struct device_notifier *notifier;
+
+ DD_LIST_FOREACH(device_notifier_list, n, notifier) {
+ if (!notifier->deleted && status == notifier->status) {
+ if (notifier->func)
+ notifier->func(data);
+ }
+ }
+
+ if (!idl)
+ idl = ecore_idler_add(delete_unused_notifier_cb, NULL);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __DEVICE_NOTIFIER_H__
+#define __DEVICE_NOTIFIER_H__
+
+enum device_notifier_type {
+ DEVICE_NOTIFIER_BOOTING_DONE,
+ DEVICE_NOTIFIER_LCD,
+ DEVICE_NOTIFIER_TA,
+ DEVICE_NOTIFIER_LOWBAT,
+ DEVICE_NOTIFIER_FULLBAT,
+ DEVICE_NOTIFIER_TOUCH_HARDKEY,
+ DEVICE_NOTIFIER_PROCESS_TERMINATED,
+ DEVICE_NOTIFIER_POWER_SUPPLY,
+ DEVICE_NOTIFIER_BATTERY_HEALTH,
+ DEVICE_NOTIFIER_BATTERY_PRESENT,
+ DEVICE_NOTIFIER_BATTERY_OVP,
+ DEVICE_NOTIFIER_BATTERY_CHARGING,
+ DEVICE_NOTIFIER_DISPLAY_LOCK,
+ DEVICE_NOTIFIER_POWER_RESUME,
+ DEVICE_NOTIFIER_POWEROFF,
+ DEVICE_NOTIFIER_POWEROFF_HAPTIC,
+ DEVICE_NOTIFIER_PMQOS_OOM,
+ DEVICE_NOTIFIER_PROCESS_BACKGROUND,
+ DEVICE_NOTIFIER_PROCESS_FOREGROUND,
+ DEVICE_NOTIFIER_USB_TETHERING_MODE,
+ DEVICE_NOTIFIER_MAX,
+};
+
+/*
+ * This is for internal callback method.
+ */
+int register_notifier(enum device_notifier_type status, int (*func)(void *data));
+int unregister_notifier(enum device_notifier_type status, int (*func)(void *data));
+void device_notify(enum device_notifier_type status, void *value);
+
+#endif /* __DEVICE_NOTIFIER_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 "log.h"
+#include "list.h"
+#include "common.h"
+#include "devices.h"
+#include "edbus-handler.h"
+
+static const struct device_ops default_ops = {
+ .name = "default-ops",
+};
+
+static dd_list *dev_head;
+
+void add_device(const struct device_ops *dev)
+{
+ if (dev->priority == DEVICE_PRIORITY_HIGH)
+ DD_LIST_PREPEND(dev_head, dev);
+ else
+ DD_LIST_APPEND(dev_head, dev);
+}
+
+void remove_device(const struct device_ops *dev)
+{
+ DD_LIST_REMOVE(dev_head, dev);
+}
+
+const struct device_ops *find_device(const char *name)
+{
+ dd_list *elem;
+ const struct device_ops *dev;
+
+ DD_LIST_FOREACH(dev_head, elem, dev) {
+ if (!strcmp(dev->name, name))
+ return dev;
+ }
+
+ dev = &default_ops;
+ return dev;
+}
+
+int check_default(const struct device_ops *dev)
+{
+ return (dev == &default_ops);
+}
+
+static DBusMessage *edbus_device_list(E_DBus_Object *obj, DBusMessage *msg)
+{
+ dd_list *elem;
+ const struct device_ops *dev;
+
+ _I("device list!");
+ DD_LIST_FOREACH(dev_head, elem, dev)
+ _I("%s", dev->name);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "DeviceList", NULL, NULL, edbus_device_list },
+};
+
+void devices_init(void *data)
+{
+ dd_list *elem, *elem_n;
+ const struct device_ops *dev;
+ int ret;
+
+ DD_LIST_FOREACH_SAFE(dev_head, elem, elem_n, dev) {
+ if (dev->probe && dev->probe(data) != 0) {
+ _E("[%s] probe fail", dev->name);
+ DD_LIST_REMOVE(dev_head, dev);
+ continue;
+ }
+
+ _D("[%s] initialize", dev->name);
+ if (dev->init)
+ dev->init(data);
+ }
+
+ ret = register_edbus_method(DEVICED_PATH_CORE,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("Failed to register edbus method! %d", ret);
+}
+
+void devices_exit(void *data)
+{
+ dd_list *elem;
+ const struct device_ops *dev;
+
+ DD_LIST_FOREACH(dev_head, elem, dev) {
+ _D("[%s] deinitialize", dev->name);
+ if (dev->exit)
+ dev->exit(data);
+ }
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DEVICES_H__
+#define __DEVICES_H__
+
+#include <errno.h>
+#include "common.h"
+
+enum device_priority {
+ DEVICE_PRIORITY_NORMAL = 0,
+ DEVICE_PRIORITY_HIGH,
+};
+
+enum device_flags {
+ NORMAL_MODE = 0x00000001,
+ CORE_LOGIC_MODE = 0x00010000,
+ TOUCH_SCREEN_OFF_MODE = 0x00020000,
+ LCD_PANEL_OFF_MODE = 0x00040000,
+ LCD_PHASED_TRANSIT_MODE = 0x00080000,
+ LCD_ON_BY_GESTURE = 0x00100000,
+ LCD_ON_BY_POWER_KEY = 0x00200000,
+ LCD_ON_BY_EVENT = 0x00400000,
+ LCD_ON_BY_TOUCH = 0x00800000,
+ LCD_OFF_BY_POWER_KEY = 0x01000000,
+ LCD_OFF_BY_TIMEOUT = 0x02000000,
+ LCD_OFF_BY_EVENT = 0x04000000,
+ LCD_OFF_LATE_MODE = 0x08000000,
+};
+
+struct device_ops {
+ enum device_priority priority;
+ char *name;
+ int (*probe) (void *data);
+ void (*init) (void *data);
+ void (*exit) (void *data);
+ int (*start) (enum device_flags flags);
+ int (*stop) (enum device_flags flags);
+ int (*status) (void);
+ int (*execute) (void *data);
+};
+
+enum device_ops_status {
+ DEVICE_OPS_STATUS_UNINIT,
+ DEVICE_OPS_STATUS_START,
+ DEVICE_OPS_STATUS_STOP,
+ DEVICE_OPS_STATUS_MAX,
+};
+
+void devices_init(void *data);
+void devices_exit(void *data);
+
+static inline int device_start(const struct device_ops *dev)
+{
+ if (dev && dev->start)
+ return dev->start(NORMAL_MODE);
+
+ return -EINVAL;
+}
+
+static inline int device_stop(const struct device_ops *dev)
+{
+ if (dev && dev->stop)
+ return dev->stop(NORMAL_MODE);
+
+ return -EINVAL;
+}
+
+static inline int device_exit(const struct device_ops *dev, void *data)
+{
+ if (dev && dev->exit) {
+ dev->exit(data);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static inline int device_execute(const struct device_ops *dev, void *data)
+{
+ if (dev && dev->execute)
+ return dev->execute(data);
+
+ return -EINVAL;
+}
+
+static inline int device_get_status(const struct device_ops *dev)
+{
+ if (dev && dev->status)
+ return dev->status();
+
+ return -EINVAL;
+}
+
+#define DEVICE_OPS_REGISTER(dev) \
+static void __CONSTRUCTOR__ module_init(void) \
+{ \
+ add_device(dev); \
+} \
+static void __DESTRUCTOR__ module_exit(void) \
+{ \
+ remove_device(dev); \
+}
+
+void add_device(const struct device_ops *dev);
+void remove_device(const struct device_ops *dev);
+
+const struct device_ops *find_device(const char *name);
+int check_default(const struct device_ops *dev);
+
+#define NOT_SUPPORT_OPS(dev) \
+ ((check_default(dev))? 1 : 0)
+
+#define FIND_DEVICE_INT(dev, name) do { \
+ if (!dev) dev = find_device(name); if(check_default(dev)) return -ENODEV; \
+} while(0)
+
+#define FIND_DEVICE_VOID(dev, name) do { \
+ if (!dev) dev = find_device(name); if(check_default(dev)) return; \
+} while(0)
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <assert.h>
+
+#include "core/log.h"
+#include "core/edbus-handler.h"
+#include "core/common.h"
+#include "core/device-idler.h"
+#include "core/device-notifier.h"
+#include "core/list.h"
+
+#define EDBUS_INIT_RETRY_COUNT 5
+#define NAME_OWNER_CHANGED "NameOwnerChanged"
+#define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus'," \
+ "path='/org/freedesktop/DBus',interface='org.freedesktop.DBus'," \
+ "member='NameOwnerChanged',arg0='%s'"
+
+/* -1 is a default timeout value, it's converted to 25*1000 internally. */
+#define DBUS_REPLY_TIMEOUT (-1)
+#define RETRY_MAX 5
+
+struct edbus_list {
+ char *signal_name;
+ E_DBus_Signal_Handler *handler;
+};
+
+static struct edbus_object {
+ char *path;
+ char *interface;
+ E_DBus_Object *obj;
+ E_DBus_Interface *iface;
+} edbus_objects[] = {
+ { DEVICED_PATH_CORE , DEVICED_INTERFACE_CORE , NULL, NULL },
+ { DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY, NULL, NULL },
+ { DEVICED_PATH_POWER , DEVICED_INTERFACE_POWER , NULL, NULL },
+ { DEVICED_PATH_STORAGE, DEVICED_INTERFACE_STORAGE, NULL, NULL },
+ { DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS, NULL, NULL },
+ { DEVICED_PATH_KEY , DEVICED_INTERFACE_KEY , NULL, NULL },
+ { DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI, NULL, NULL },
+ { DEVICED_PATH_USB , DEVICED_INTERFACE_USB , NULL, NULL },
+ /* Add new object & interface here*/
+};
+
+struct watch_func_info {
+ bool deleted;
+ void (*func)(const char *sender, void *data);
+ void *data;
+};
+
+struct watch_info {
+ bool deleted;
+ char *sender;
+ dd_list *func_list;
+};
+
+static dd_list *edbus_object_list;
+static dd_list *edbus_owner_list;
+static dd_list *edbus_handler_list;
+static dd_list *edbus_watch_list;
+static int edbus_init_val;
+static DBusConnection *conn;
+static DBusConnection *conn_block;
+static E_DBus_Connection *edbus_conn;
+static E_DBus_Connection *edbus_conn_block;
+static DBusPendingCall *edbus_request_name;
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+ DBusMessage *message, void *data);
+
+DBusConnection *get_block_dbus_connection(void)
+{
+ return conn_block;
+}
+
+E_DBus_Object *register_edbus_object(const char *object_path, void *data)
+{
+ E_DBus_Object *object;
+
+ if (!object_path) {
+ _E("invalid parameter");
+ return NULL;
+ }
+
+ object = e_dbus_object_add(edbus_conn, object_path, data);
+ if (!object) {
+ _E("fail to add object for %s", object_path);
+ return NULL;
+ }
+
+ return object;
+}
+
+E_DBus_Object *register_block_edbus_object(const char *object_path, void *data)
+{
+ E_DBus_Object *object;
+
+ if (!object_path) {
+ _E("invalid parameter");
+ return NULL;
+ }
+
+ object = e_dbus_object_add(edbus_conn_block, object_path, data);
+ if (!object) {
+ _E("fail to add object for %s", object_path);
+ return NULL;
+ }
+
+ return object;
+}
+
+void unregister_edbus_object(E_DBus_Object *object)
+{
+ if (!object)
+ return;
+
+ e_dbus_object_free(object);
+}
+
+static int register_edbus_interface(struct edbus_object *object)
+{
+ if (!object) {
+ _E("object is invalid value!");
+ return -1;
+ }
+
+ object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
+ if (!object->obj) {
+ _E("fail to add edbus obj");
+ return -1;
+ }
+
+ object->iface = e_dbus_interface_new(object->interface);
+ if (!object->iface) {
+ _E("fail to add edbus interface");
+ return -1;
+ }
+
+ e_dbus_object_interface_attach(object->obj, object->iface);
+
+ return 0;
+}
+
+static int register_block_edbus_interface(struct edbus_object *object)
+{
+ if (!object) {
+ _E("object is invalid value!");
+ return -1;
+ }
+
+ object->obj = e_dbus_object_add(edbus_conn_block, object->path, NULL);
+ if (!object->obj) {
+ _E("fail to add edbus obj");
+ return -1;
+ }
+
+ object->iface = e_dbus_interface_new(object->interface);
+ if (!object->iface) {
+ _E("fail to add edbus interface");
+ return -1;
+ }
+
+ e_dbus_object_interface_attach(object->obj, object->iface);
+
+ return 0;
+}
+
+E_DBus_Interface *get_edbus_interface(const char *path)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
+ if (!strcmp(path, edbus_objects[i].path))
+ return edbus_objects[i].iface;
+
+ return NULL;
+}
+
+pid_t get_edbus_sender_pid(DBusMessage *msg)
+{
+ const char *sender;
+ DBusMessage *send_msg;
+ DBusPendingCall *pending;
+ DBusMessageIter iter;
+ int ret;
+ pid_t pid;
+
+ if (!msg) {
+ _E("invalid argument!");
+ return -1;
+ }
+
+ sender = dbus_message_get_sender(msg);
+ if (!sender) {
+ _E("invalid sender!");
+ return -1;
+ }
+
+ send_msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "GetConnectionUnixProcessID");
+ if (!send_msg) {
+ _E("invalid send msg!");
+ return -1;
+ }
+
+ ret = dbus_message_append_args(send_msg, DBUS_TYPE_STRING,
+ &sender, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("fail to append args!");
+ dbus_message_unref(send_msg);
+ return -1;
+ }
+
+ pending = e_dbus_message_send(edbus_conn, send_msg, NULL, -1, NULL);
+ if (!pending) {
+ _E("pending is null!");
+ dbus_message_unref(send_msg);
+ return -1;
+ }
+
+ dbus_message_unref(send_msg);
+
+ /* block until reply is received */
+ dbus_pending_call_block(pending);
+
+ msg = dbus_pending_call_steal_reply(pending);
+ dbus_pending_call_unref(pending);
+ if (!msg) {
+ _E("reply msg is null!");
+ return -1;
+ }
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_get_basic(&iter, &pid);
+ dbus_message_unref(msg);
+
+ return pid;
+}
+
+static void unregister_edbus_signal_handle(void)
+{
+ dd_list *tmp, *next;
+ struct edbus_list *entry;
+
+ DD_LIST_FOREACH_SAFE(edbus_handler_list, tmp, next, entry) {
+ if (!entry->handler)
+ continue;
+ e_dbus_signal_handler_del(edbus_conn, entry->handler);
+ DD_LIST_REMOVE(edbus_handler_list, entry);
+ free(entry->signal_name);
+ free(entry);
+ }
+}
+
+int register_edbus_signal_handler(const char *path, const char *interface,
+ const char *name, E_DBus_Signal_Cb cb)
+{
+ dd_list *tmp;
+ struct edbus_list *entry;
+ E_DBus_Signal_Handler *handler;
+
+ DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
+ if (strncmp(entry->signal_name, name, strlen(name)) == 0)
+ return -EEXIST;
+ }
+
+ handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
+ interface, name, cb, NULL);
+
+ if (!handler) {
+ _E("fail to add edbus handler");
+ return -ENOMEM;
+ }
+
+ entry = malloc(sizeof(struct edbus_list));
+
+ if (!entry) {
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ entry->signal_name = strndup(name, strlen(name));
+
+ if (!entry->signal_name) {
+ _E("Malloc failed");
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ free(entry);
+ return -ENOMEM;
+ }
+
+ entry->handler = handler;
+ DD_LIST_PREPEND(edbus_handler_list, entry);
+ if (!edbus_handler_list) {
+ _E("dd_list_prepend failed");
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ free(entry->signal_name);
+ free(entry);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int unregister_edbus_signal_handler(const char *path, const char *interface,
+ const char *name)
+{
+ dd_list *tmp, *next;
+ struct edbus_list *entry;
+
+ DD_LIST_FOREACH_SAFE(edbus_handler_list, tmp, next, entry) {
+ if (strncmp(entry->signal_name, name, strlen(name) + 1) == 0) {
+ e_dbus_signal_handler_del(edbus_conn, entry->handler);
+ DD_LIST_REMOVE(edbus_handler_list, entry);
+ free(entry->signal_name);
+ free(entry);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int broadcast_edbus_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[])
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ int r;
+
+ msg = dbus_message_new_signal(path, interface, name);
+ if (!msg) {
+ _E("fail to allocate new %s.%s signal", interface, name);
+ return -EPERM;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ r = append_variant(&iter, sig, param);
+ if (r < 0) {
+ _E("append_variant error(%d)", r);
+ return -EPERM;
+ }
+
+ r = dbus_connection_send(conn, msg, NULL);
+ dbus_message_unref(msg);
+
+ if (r != TRUE) {
+ _E("dbus_connection_send error(%s:%s-%s)",
+ path, interface, name);
+ return -ECOMM;
+ }
+
+ return 0;
+}
+
+int broadcast_block_edbus_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[])
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ int r;
+
+ msg = dbus_message_new_signal(path, interface, name);
+ if (!msg) {
+ _E("fail to allocate new %s.%s signal", interface, name);
+ return -EPERM;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ r = append_variant(&iter, sig, param);
+ if (r < 0) {
+ _E("append_variant error(%d)", r);
+ return -EPERM;
+ }
+
+ r = dbus_connection_send(conn_block, msg, NULL);
+ dbus_message_unref(msg);
+
+ if (r != TRUE) {
+ _E("dbus_connection_send error(%s:%s-%s)",
+ path, interface, name);
+ return -ECOMM;
+ }
+
+ return 0;
+}
+
+static void print_watch_item(void)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ dd_list *e;
+
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ _D("watch sender : %s, deleted : %d",
+ watch->sender, watch->deleted);
+ DD_LIST_FOREACH(watch->func_list, e, finfo)
+ _D("\tfunc : %p, deleted : %d",
+ finfo->func, finfo->deleted);
+ }
+}
+
+static bool get_valid_watch_item(void)
+{
+ struct watch_info *watch;
+ dd_list *elem;
+
+ DD_LIST_FOREACH(edbus_watch_list, elem, watch) {
+ if (!watch->deleted)
+ return true;
+ }
+
+ return false;
+}
+
+static void watch_idler_cb(void *data)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ dd_list *next;
+ dd_list *elem;
+ dd_list *enext;
+ char match[256];
+
+ DD_LIST_FOREACH_SAFE(edbus_watch_list, n, next, watch) {
+ if (!watch->deleted)
+ continue;
+
+ /* remove dbus match */
+ snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->sender);
+ dbus_bus_remove_match(conn, match, NULL);
+
+ _I("%s is not watched by dbus!", watch->sender);
+
+ /* remove watch func list */
+ DD_LIST_FOREACH_SAFE(watch->func_list, elem, enext, finfo)
+ free(finfo);
+
+ /* remove watch item */
+ DD_LIST_FREE_LIST(watch->func_list);
+ DD_LIST_REMOVE_LIST(edbus_watch_list, n);
+ free(watch->sender);
+ free(watch);
+ }
+
+ /* if the last request, remove message filter */
+ if (!get_valid_watch_item())
+ dbus_connection_remove_filter(conn, message_filter, NULL);
+}
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+ DBusMessage *message, void *data)
+{
+ int ret;
+ const char *iface, *member;
+ const char *sender;
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ int len;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ iface = dbus_message_get_interface(message);
+ member = dbus_message_get_member(message);
+
+ if (strncmp(iface, DBUS_INTERFACE_DBUS,
+ sizeof(DBUS_INTERFACE_DBUS)))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (strncmp(member, NAME_OWNER_CHANGED,
+ sizeof(NAME_OWNER_CHANGED)))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ ret = dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &sender,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ len = strlen(sender) + 1;
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ if (!watch->deleted &&
+ !strncmp(watch->sender, sender, len))
+ break;
+ }
+
+ if (!watch)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ DD_LIST_FOREACH(watch->func_list, n, finfo) {
+ if (!finfo->deleted &&
+ finfo->func)
+ finfo->func(watch->sender, finfo->data);
+ }
+
+ /* no interest in this item anymore */
+ watch->deleted = true;
+
+ print_watch_item();
+ add_idle_request(watch_idler_cb, NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static struct watch_info *get_matched_watch_item(const char *sender)
+{
+ int len;
+ dd_list *n;
+ struct watch_info *watch;
+
+ if (!sender)
+ return NULL;
+
+ len = strlen(sender) + 1;
+ /* check the sender&type is already registered */
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ if (!watch->deleted &&
+ !strncmp(watch->sender, sender, len))
+ return watch;
+ }
+
+ return NULL;
+}
+
+static struct watch_info *add_watch_item(const char *sender)
+{
+ DBusError err;
+ struct watch_info *watch;
+ char match[256];
+ int ret;
+
+ if (!sender)
+ return NULL;
+
+ watch = calloc(1, sizeof(struct watch_info));
+ if (!watch)
+ return NULL;
+
+ watch->sender = strdup(sender);
+ if (!watch->sender)
+ goto out;
+
+ dbus_error_init(&err);
+ /* add name owner changed match string */
+ snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->sender);
+ dbus_bus_add_match(conn, match, &err);
+
+ if (dbus_error_is_set(&err)) {
+ _E("fail to add match for %s [%s:%s]",
+ sender, err.name, err.message);
+ dbus_error_free(&err);
+ goto out;
+ }
+
+ /* if the first request, add message filter */
+ if (!get_valid_watch_item()) {
+ ret = dbus_connection_add_filter(conn,
+ message_filter, NULL, NULL);
+ if (!ret) {
+ _E("fail to add message filter!");
+ dbus_bus_remove_match(conn, match, NULL);
+ goto out;
+ }
+ _I("success to add message filter!");
+ }
+
+ /* Add watch to watch list */
+ DD_LIST_APPEND(edbus_watch_list, watch);
+ _I("%s is watched by dbus!", sender);
+ return watch;
+
+out:
+ if (watch) {
+ free(watch->sender);
+ free(watch);
+ }
+
+ return NULL;
+}
+
+int register_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data), void *data)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *elem;
+ bool isnew = false;
+
+ if (!sender || !func) {
+ _E("invalid argument : sender(NULL) || func(NULL)");
+ return -EINVAL;
+ }
+
+ watch = get_matched_watch_item(sender);
+ if (!watch) {
+ /* create new watch item */
+ watch = add_watch_item(sender);
+ if (!watch) {
+ _E("fail to add watch item");
+ return -EPERM;
+ }
+ isnew = true;
+ }
+
+ /* find the same callback */
+ DD_LIST_FOREACH(watch->func_list, elem, finfo) {
+ if (finfo->func == func) {
+ _E("there is already the same callback");
+ goto out;
+ }
+ }
+
+ finfo = calloc(1, sizeof(struct watch_func_info));
+ if (!finfo) {
+ _E("fail to allocate watch func info");
+ goto out;
+ }
+
+ finfo->func = func;
+ finfo->data = data;
+
+ /* add callback function to the watch list */
+ DD_LIST_APPEND(watch->func_list, finfo);
+
+ _I("register watch func(%p) of %s", func, sender);
+ return 0;
+out:
+ if (isnew)
+ watch->deleted = true;
+
+ return -EPERM;
+}
+
+int unregister_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data))
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *elem;
+ bool matched = false;
+
+ if (!sender || !func) {
+ _E("invalid argument : sender(NULL) || func(NULL)");
+ return -EINVAL;
+ }
+
+ watch = get_matched_watch_item(sender);
+ if (!watch) {
+ _E("fail to get matched watch item");
+ return -ENODEV;
+ }
+
+ /* check the no interest function */
+ DD_LIST_FOREACH(watch->func_list, elem, finfo) {
+ if (finfo->func == func)
+ finfo->deleted = true;
+ if (!finfo->deleted)
+ matched = true;
+ }
+
+ /* if it is the last item */
+ if (!matched)
+ watch->deleted = true;
+
+ _I("unregister watch func(%p) of %s", func, sender);
+ return 0;
+}
+
+static void unregister_edbus_watch_all(void)
+{
+ dd_list *n, *next;
+ struct watch_info *watch;
+
+ DD_LIST_FOREACH_SAFE(edbus_watch_list, n, next, watch)
+ watch->deleted = true;
+
+ add_idle_request(watch_idler_cb, NULL);
+}
+
+static int register_method(E_DBus_Interface *iface,
+ const struct edbus_method *edbus_methods, int size)
+{
+ int ret;
+ int i;
+
+ assert(iface);
+ assert(edbus_methods);
+
+ for (i = 0; i < size; i++) {
+ ret = e_dbus_interface_method_add(iface,
+ edbus_methods[i].member,
+ edbus_methods[i].signature,
+ edbus_methods[i].reply_signature,
+ edbus_methods[i].func);
+ if (!ret) {
+ _E("fail to add method %s!", edbus_methods[i].member);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int register_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size)
+{
+ struct edbus_object *obj;
+ dd_list *elem;
+ int ret;
+
+ if (!path || !interface || !edbus_methods || size < 1) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ /* find matched obj */
+ DD_LIST_FOREACH(edbus_object_list, elem, obj) {
+ if (strncmp(obj->path, path, strlen(obj->path)) == 0 &&
+ strncmp(obj->interface, interface, strlen(obj->interface)) == 0) {
+ _I("found matched item : obj(%p)", obj);
+ break;
+ }
+ }
+
+ /* if there is no matched obj */
+ if (!obj) {
+ obj = malloc(sizeof(struct edbus_object));
+ if (!obj) {
+ _E("fail to allocate %s interface", path);
+ return -ENOMEM;
+ }
+
+ obj->path = strdup(path);
+ obj->interface = strdup(interface);
+
+ ret = register_edbus_interface(obj);
+ if (ret < 0) {
+ _E("fail to register %s interface(%d)", obj->path, ret);
+ free(obj->path);
+ free(obj->interface);
+ free(obj);
+ return ret;
+ }
+
+ DD_LIST_APPEND(edbus_object_list, obj);
+ }
+
+ ret = register_method(obj->iface, edbus_methods, size);
+ if (ret < 0) {
+ _E("fail to register %s method(%d)", obj->path, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int register_block_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size)
+{
+ struct edbus_object *obj;
+ dd_list *elem;
+ int ret;
+
+ if (!path || !interface || !edbus_methods || size < 1) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ /* find matched obj */
+ DD_LIST_FOREACH(edbus_object_list, elem, obj) {
+ if (strncmp(obj->path, path, strlen(obj->path)) == 0 &&
+ strncmp(obj->interface, interface, strlen(obj->interface)) == 0) {
+ _I("found matched item : obj(%p)", obj);
+ break;
+ }
+ }
+
+ /* if there is no matched obj */
+ if (!obj) {
+ obj = malloc(sizeof(struct edbus_object));
+ if (!obj) {
+ _E("fail to allocate %s interface", path);
+ return -ENOMEM;
+ }
+
+ obj->path = strdup(path);
+ obj->interface = strdup(interface);
+
+ ret = register_block_edbus_interface(obj);
+ if (ret < 0) {
+ _E("fail to register %s interface(%d)", obj->path, ret);
+ free(obj->path);
+ free(obj->interface);
+ free(obj);
+ return ret;
+ }
+
+ DD_LIST_APPEND(edbus_object_list, obj);
+ }
+
+ ret = register_method(obj->iface, edbus_methods, size);
+ if (ret < 0) {
+ _E("fail to register %s method(%d)", obj->path, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int unregister_edbus_interface_all(void)
+{
+ struct edbus_object *obj;
+ dd_list *elem, *n;
+
+ DD_LIST_FOREACH_SAFE(edbus_object_list, elem, n, obj) {
+ DD_LIST_REMOVE(edbus_object_list, obj);
+ free(obj->path);
+ free(obj->interface);
+ free(obj);
+ }
+
+ return 0;
+}
+
+int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size)
+{
+ E_DBus_Interface *iface;
+ int ret;
+
+ if (!path || !edbus_methods || size < 1) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ iface = get_edbus_interface(path);
+ if (!iface) {
+ _E("fail to get edbus interface!");
+ return -ENODEV;
+ }
+
+ ret = register_method(iface, edbus_methods, size);
+ if (ret < 0) {
+ _E("fail to register %s method(%d)", path, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
+{
+ DBusError err;
+ unsigned int val;
+ int r;
+
+ if (!msg) {
+ _D("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
+ if (!r) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ _I("Request Name reply : %d", val);
+}
+
+static void check_owner_name(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char *pa[1];
+ char exe_name[PATH_MAX];
+ char *entry;
+ dd_list *n;
+ int pid;
+
+ DD_LIST_FOREACH(edbus_owner_list, n, entry) {
+ pa[0] = entry;
+ msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
+ E_DBUS_FDO_PATH,
+ E_DBUS_FDO_INTERFACE,
+ "GetConnectionUnixProcessID", "s", pa);
+
+ if (!msg) {
+ _E("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &pid);
+ if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0)
+ goto out;
+ _I("%s(%d)", exe_name, pid);
+
+out:
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+ }
+}
+
+static void check_owner_list(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter array, item;
+ char *pa[1];
+ char *name;
+ char *entry;
+
+ pa[0] = DEVICED_BUS_NAME;
+ msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
+ E_DBUS_FDO_PATH,
+ E_DBUS_FDO_INTERFACE,
+ "ListQueuedOwners", "s", pa);
+
+ if (!msg) {
+ _E("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ dbus_message_iter_init(msg, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ goto out;
+ dbus_message_iter_recurse(&array, &item);
+ while (dbus_message_iter_get_arg_type(&item) == DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(&item, &name);
+ entry = strndup(name, strlen(name));
+ DD_LIST_APPEND(edbus_owner_list, entry);
+ if (!edbus_owner_list) {
+ _E("append failed");
+ free(entry);
+ goto out;
+ }
+ dbus_message_iter_next(&item);
+ }
+
+out:
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+}
+
+void edbus_init(void *data)
+{
+ DBusError error;
+ int retry = 0;
+ int i, ret;
+
+ dbus_threads_init_default();
+ dbus_error_init(&error);
+
+ do {
+ edbus_init_val = e_dbus_init();
+ if (edbus_init_val)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to init edbus");
+ return;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (conn)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get dbus");
+ goto out1;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ conn_block = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+ if (conn_block)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get dbus");
+ goto out1;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_conn = e_dbus_connection_setup(conn);
+ if (edbus_conn)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get edbus");
+ goto out2;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_conn_block = e_dbus_connection_setup(conn_block);
+ if (edbus_conn)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get edbus");
+ goto out2;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_request_name = e_dbus_request_name(edbus_conn, DEVICED_BUS_NAME,
+ DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
+ if (edbus_request_name)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to request edbus name");
+ goto out3;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_request_name = e_dbus_request_name(edbus_conn_block, STORAGE_BUS_NAME,
+ DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
+ if (edbus_request_name)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to request edbus name");
+ goto out3;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
+ ret = register_edbus_interface(&edbus_objects[i]);
+ if (ret < 0) {
+ _E("fail to add obj & interface for %s",
+ edbus_objects[i].interface);
+ return;
+ }
+ _D("add new obj for %s", edbus_objects[i].interface);
+ }
+ check_owner_list();
+ check_owner_name();
+ return;
+
+out3:
+ e_dbus_connection_close(edbus_conn);
+ e_dbus_connection_close(edbus_conn_block);
+out2:
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+ dbus_connection_set_exit_on_disconnect(conn_block, FALSE);
+out1:
+ e_dbus_shutdown();
+}
+
+void edbus_exit(void *data)
+{
+ unregister_edbus_signal_handle();
+ unregister_edbus_watch_all();
+ unregister_edbus_interface_all();
+ e_dbus_connection_close(edbus_conn);
+ e_dbus_connection_close(edbus_conn_block);
+ e_dbus_shutdown();
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __EDBUS_HANDLE_H__
+#define __EDBUS_HANDLE_H__
+
+#include <stdbool.h>
+#include <E_DBus.h>
+#include "shared/dbus.h"
+
+struct edbus_method {
+ const char *member;
+ const char *signature;
+ const char *reply_signature;
+ E_DBus_Method_Cb func;
+};
+
+static inline DBusMessage *make_reply_message(DBusMessage *msg, int ret)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+DBusConnection *get_block_dbus_connection(void);
+E_DBus_Object *register_edbus_object(const char *object_path, void *data);
+E_DBus_Object *register_block_edbus_object(const char *object_path, void *data);
+void unregister_edbus_object(E_DBus_Object *object);
+int register_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size);
+int register_block_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size);
+int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size);
+int register_edbus_signal_handler(const char *path, const char *interface,
+ const char *name, E_DBus_Signal_Cb cb);
+int unregister_edbus_signal_handler(const char *path, const char *interface,
+ const char *name);
+E_DBus_Interface *get_edbus_interface(const char *path);
+pid_t get_edbus_sender_pid(DBusMessage *msg);
+int broadcast_edbus_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[]);
+int broadcast_block_edbus_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[]);
+int register_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data), void *data);
+int unregister_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data));
+
+void edbus_init(void *data);
+void edbus_exit(void *data);
+
+#endif /* __EDBUS_HANDLE_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "log.h"
+
+static int parent(pid_t pid)
+{
+ int status;
+
+ /* wait for child */
+ if (waitpid(pid, &status, 0) != -1) {
+ /* terminated normally */
+ if (WIFEXITED(status)) {
+ _I("%d terminated by exit(%d)", pid, WEXITSTATUS(status));
+ return WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status))
+ _I("%d terminated by signal %d", pid, WTERMSIG(status));
+ else if (WIFSTOPPED(status))
+ _I("%d stopped by signal %d", pid, WSTOPSIG(status));
+ } else
+ _I("%d waitpid() failed : %d", pid, errno);
+
+ return -EAGAIN;
+}
+
+static void child(int argc, const char *argv[])
+{
+ int i, r;
+
+ for (i = 0; i < _NSIG; ++i)
+ signal(i, SIG_DFL);
+
+ r = execv(argv[0], (char **)argv);
+ if (r < 0)
+ exit(EXIT_FAILURE);
+}
+
+int run_child(int argc, const char *argv[])
+{
+ pid_t pid;
+ struct sigaction act, oldact;
+ int r = 0;
+ FILE *fp;
+
+ if (!argv)
+ return -EINVAL;
+
+ fp = fopen(argv[0], "r");
+ if (fp == NULL) {
+ _E("fail %s (%d)", argv[0], errno);
+ return -errno;
+ }
+ fclose(fp);
+
+ /* Use default signal handler */
+ act.sa_handler = SIG_DFL;
+ act.sa_sigaction = NULL;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+
+ if (sigaction(SIGCHLD, &act, &oldact) < 0)
+ return -errno;
+
+ pid = fork();
+ if (pid < 0) {
+ _E("failed to fork");
+ r = -errno;
+ } else if (pid == 0) {
+ child(argc, argv);
+ } else
+ r = parent(pid);
+
+ if (sigaction(SIGCHLD, &oldact, NULL) < 0)
+ _E("failed to restore sigaction");
+
+ return r;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <vconf.h>
+
+#include "log.h"
+#include "launch.h"
+#include "common.h"
+
+#define MAX_ARGS 255
+
+#define _S(str) ((str == NULL) ? "" : str)
+
+static int set_current_lang(void)
+{
+ char *lang;
+ int ret;
+
+ lang = vconf_get_str(VCONFKEY_LANGSET);
+ if (lang == NULL)
+ return -1;
+ ret = setenv("LANG", lang, 1);
+ if (ret < 0)
+ return -1;
+ free(lang);
+ return 0;
+}
+
+
+static void prepare_exec(void)
+{
+ int i;
+ int maxfd;
+
+ maxfd = getdtablesize();
+ for (i = 3; i < maxfd; i++)
+ close(i);
+
+ for (i = 0; i < _NSIG; i++)
+ signal(i, SIG_DFL);
+}
+
+static int parse_cmd(const char *cmdline, char **argv, int max_args)
+{
+ const char *p;
+ char *buf, *bufp;
+ int nargs = 0;
+ int escape = 0, squote = 0, dquote = 0;
+ int bufsize;
+
+ if (cmdline == NULL || cmdline[0] == '\0')
+ return -1;
+ bufsize = strlen(cmdline)+1;
+ bufp = buf = malloc(bufsize);
+ if (bufp == NULL || buf == NULL)
+ return -1;
+ memset(buf, 0, bufsize);
+ p = cmdline;
+
+ while (*p) {
+ if (escape) {
+ *bufp++ = *p;
+ escape = 0;
+ } else {
+ switch (*p) {
+ case '\\':
+ escape = 1;
+ break;
+ case '"':
+ if (squote)
+ *bufp++ = *p;
+ else
+ dquote = !dquote;
+ break;
+ case '\'':
+ if (dquote)
+ *bufp++ = *p;
+ else
+ squote = !squote;
+ break;
+ case ' ':
+ if (!squote && !dquote) {
+ *bufp = '\0';
+ if (nargs < max_args)
+ argv[nargs++] = strdup(buf);
+ bufp = buf;
+ break;
+ }
+ default:
+ *bufp++ = *p;
+ break;
+ }
+ }
+ p++;
+ }
+
+ if (bufp != buf) {
+ *bufp = '\0';
+ if (nargs < max_args)
+ argv[nargs++] = strdup(buf);
+ }
+
+ argv[nargs++] = NULL;
+
+ free(buf);
+ return nargs;
+}
+
+int launch_app_with_nice(const char *file, char *const argv[], pid_t *pid, int _nice)
+{
+ int ret;
+ int _pid;
+
+ if (file == NULL || access(file, X_OK) != 0) {
+ _E("launch app error: Invalid input");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (pid && (*pid > 0 && kill(*pid, 0) != -1))
+ return *pid;
+
+ _pid = fork();
+
+ if (_pid == -1) {
+ _E("fork error: %d", errno);
+ /* keep errno */
+ return -1;
+ }
+
+ if (_pid > 0) { /* parent */
+ if (pid)
+ *pid = _pid;
+ return _pid;
+ }
+
+ /* child */
+ prepare_exec();
+
+ ret = nice(_nice);
+
+ if (ret == -1 && errno != 0)
+ _E("nice error: %d", errno);
+
+ ret = execvp(file, argv);
+
+ /* If failed... */
+ _E("exec. error: %s", errno);
+ return -2;
+}
+
+int launch_app_cmd_with_nice(const char *cmdline, int _nice)
+{
+ int i;
+ int nargs;
+ int ret;
+ char *argv[MAX_ARGS + 1];
+
+ nargs = parse_cmd(cmdline, argv, MAX_ARGS + 1);
+ if (nargs == -1) {
+ _E("launch app error: Invalid input");
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = launch_app_with_nice(argv[0], argv, NULL, _nice);
+
+ for (i = 0; i < nargs; i++)
+ free(argv[i]);
+
+ return ret;
+}
+
+int launch_app_cmd(const char *cmdline)
+{
+ return launch_app_cmd_with_nice(cmdline, 0);
+}
+
+int launch_if_noexist(const char *execpath, const char *arg, ...)
+{
+ char *buf;
+ int pid;
+ int nice_value = 0;
+ int flag = 0;
+ int buf_size = -1;
+ va_list argptr;
+
+ if (execpath == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ pid = get_exec_pid(execpath);
+ if (pid > 0)
+ return pid;
+
+ va_start(argptr, arg);
+ flag = va_arg(argptr, int);
+
+ if (flag & LAUNCH_NICE)
+ nice_value = va_arg(argptr, int);
+
+ va_end(argptr);
+
+ set_current_lang();
+ arg = _S(arg);
+
+ buf_size = strlen(execpath) + strlen(arg) + 10;
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ /* Do something for not enought memory error */
+ _E("Malloc failed");
+ return -1;
+ }
+
+ snprintf(buf, buf_size, "%s %s", execpath, arg);
+ pid = launch_app_cmd_with_nice(buf, nice_value);
+ if (pid == -2)
+ exit(EXIT_FAILURE);
+ free(buf);
+
+ return pid;
+}
+
+int launch_evenif_exist(const char *execpath, const char *arg, ...)
+{
+ char *buf;
+ int pid;
+ int nice_value = 0;
+ int flag = 0;
+ int buf_size = -1;
+
+ va_list argptr;
+
+ if (execpath == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ va_start(argptr, arg);
+ flag = va_arg(argptr, int);
+
+ if (flag & LAUNCH_NICE)
+ nice_value = va_arg(argptr, int);
+
+ va_end(argptr);
+
+ set_current_lang();
+
+ arg = _S(arg);
+
+ buf_size = strlen(execpath) + strlen(arg) + 10;
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ _E("Malloc failed");
+ return -1;
+ }
+
+ snprintf(buf, buf_size, "%s %s", execpath, arg);
+ pid = launch_app_cmd_with_nice(buf, nice_value);
+ if (pid == -2)
+ exit(EXIT_FAILURE);
+ free(buf);
+
+ return pid;
+}
+
+int launch_after_kill_if_exist(const char *execpath, const char *arg, ...)
+{
+ char *buf;
+ int pid;
+ int flag;
+ int buf_size;
+ int exist_pid;
+ va_list argptr;
+ int nice_value = 0;
+
+ if (execpath == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ exist_pid = get_exec_pid(execpath);
+ if (exist_pid > 0)
+ kill(exist_pid, SIGTERM);
+
+ va_start(argptr, arg);
+ flag = va_arg(argptr, int);
+
+ if (flag & LAUNCH_NICE)
+ nice_value = va_arg(argptr, int);
+
+ va_end(argptr);
+
+ set_current_lang();
+
+ arg = _S(arg);
+
+ buf_size = strlen(execpath) + strlen(arg) + 10;
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ /* Do something for not enought memory error */
+ _E("Malloc Failed");
+ return -1;
+ }
+
+ snprintf(buf, buf_size, "%s %s", execpath, arg);
+ pid = launch_app_cmd_with_nice(buf, nice_value);
+ if (pid == -2) /* It means that the 'execvp' return -1 */
+ exit(EXIT_FAILURE);
+ free(buf);
+
+ return pid;
+
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __LAUNCH_H__
+#define __LAUNCH_H__
+
+#define LAUNCH_NICE 0x0002
+
+int launch_if_noexist(const char *execpath, const char *arg, ...);
+int launch_evenif_exist(const char *execpath, const char *arg, ...);
+int launch_after_kill_if_exist(const char *execpath, const char *arg, ...);
+
+int launch_app_cmd(const char *cmdline);
+int launch_app_cmd_with_nice(const char *cmdline, int _nice);
+
+#endif /* __LAUNCH_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __LIST_H__
+#define __LIST_H__
+
+#include <glib.h>
+typedef GList dd_list;
+
+#define DD_LIST_PREPEND(a, b) \
+ a = g_list_prepend(a, (gpointer)b)
+#define DD_LIST_APPEND(a, b) \
+ a = g_list_append(a, (gpointer)b)
+#define DD_LIST_REMOVE(a, b) \
+ a = g_list_remove(a, (gpointer)b)
+#define DD_LIST_REMOVE_LIST(a, b) \
+ a = g_list_delete_link(a, b)
+#define DD_LIST_LENGTH(a) \
+ g_list_length(a)
+#define DD_LIST_NTH(a, b) \
+ g_list_nth_data(a, b)
+#define DD_LIST_FIND(a, b) \
+ g_list_find(a, (gpointer)b)
+#define DD_LIST_FREE_LIST(a) \
+ g_list_free(a)
+#define DD_LIST_FOREACH(head, elem, node) \
+ for (elem = head, node = NULL; \
+ elem && ((node = elem->data) != NULL); \
+ elem = elem->next, node = NULL)
+#define DD_LIST_FOREACH_SAFE(head, elem, elem_next, node) \
+ for (elem = head, elem_next = g_list_next(elem), node = NULL; \
+ elem && ((node = elem->data) != NULL); \
+ elem = elem_next, elem_next = g_list_next(elem), node = NULL)
+#define DD_LIST_REVERSE_FOREACH(head, elem, node) \
+ for (elem = g_list_last(head), node = NULL; \
+ elem && ((node = elem->data) != NULL); \
+ elem = g_list_previous(elem), node = NULL)
+#define DD_LIST_REVERSE_FOREACH_SAFE(head, elem, elem_next, node) \
+ for (elem = g_list_last(head), elem_next = g_list_previous(elem), node = NULL; \
+ elem && ((node = elem->data) != NULL); \
+ elem = elem_next, elem_next = g_list_previous(elem), node = NULL)
+#define DD_LIST_NEXT(a) \
+ g_list_next(a)
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 "log.h"
+
+#ifdef DEBUG
+void __cyg_profile_func_enter(void *, void *)
+ __attribute__ ((no_instrument_function));
+void __cyg_profile_func_exit(void *, void *)
+ __attribute__ ((no_instrument_function));
+
+int g_trace_depth = -2;
+
+void __cyg_profile_func_enter(void *func, void *caller)
+{
+ g_trace_depth++;
+}
+
+void __cyg_profile_func_exit(void *func, void *caller)
+{
+ g_trace_depth--;
+}
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __LOG_H__
+#define __LOG_H__
+
+#ifdef ENABLE_DEVICED_DLOG
+#define ENABLE_DLOG
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "DEVICED"
+#include "shared/log-macro.h"
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <fcntl.h>
+#include <sys/reboot.h>
+
+#include "display/core.h"
+#include "log.h"
+#include "common.h"
+#include "edbus-handler.h"
+#include "devices.h"
+#include "shared/dbus.h"
+#include "power/boot.h"
+#include "device-notifier.h"
+
+#define PIDFILE_PATH "/var/run/.deviced.pid"
+
+static void writepid(char *pidpath)
+{
+ FILE *fp;
+
+ fp = fopen(pidpath, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d", getpid());
+ fclose(fp);
+ }
+}
+
+static void sig_quit(int signo)
+{
+ _D("received SIGTERM signal %d", signo);
+}
+
+static void sig_usr1(int signo)
+{
+ _D("received SIGUSR1 signal %d, deviced'll be finished!", signo);
+
+ ecore_main_loop_quit();
+}
+
+static int deviced_main(int argc, char **argv)
+{
+ int ret;
+
+ edbus_init(NULL);
+ devices_init(NULL);
+ ret = booting_finished();
+ if (ret == 1) {
+ _I("notify relaunch");
+ device_notify(DEVICE_NOTIFIER_BOOTING_DONE, &ret);
+ }
+ signal(SIGTERM, sig_quit);
+ signal(SIGUSR1, sig_usr1);
+
+ ecore_main_loop_begin();
+
+ devices_exit(NULL);
+ edbus_exit(NULL);
+ ecore_shutdown();
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ writepid(PIDFILE_PATH);
+ ecore_init();
+ return deviced_main(argc, argv);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <sys/types.h>
+#include <sys/wait.h>
+
+#include "log.h"
+#include "devices.h"
+#include "common.h"
+
+static struct sigaction sig_child_old_act;
+static struct sigaction sig_pipe_old_act;
+
+static void sig_child_handler(int signo, siginfo_t *info, void *data)
+{
+ pid_t pid;
+ int status;
+
+ if (!info || signo != SIGCHLD)
+ return;
+
+ pid = waitpid(info->si_pid, &status, 0);
+ if (pid == -1) {
+ _E("SIGCHLD received\n");
+ return;
+ }
+
+ _D("sig child actend call - %d\n", info->si_pid);
+}
+
+static void sig_pipe_handler(int signo, siginfo_t *info, void *data)
+{
+
+}
+
+static void signal_init(void *data)
+{
+ struct sigaction sig_act;
+
+ sig_act.sa_handler = NULL;
+ sig_act.sa_sigaction = sig_child_handler;
+ sig_act.sa_flags = SA_SIGINFO;
+ sigemptyset(&sig_act.sa_mask);
+ sigaction(SIGCHLD, &sig_act, &sig_child_old_act);
+
+ sig_act.sa_handler = NULL;
+ sig_act.sa_sigaction = sig_pipe_handler;
+ sig_act.sa_flags = SA_SIGINFO;
+ sigemptyset(&sig_act.sa_mask);
+ sigaction(SIGPIPE, &sig_act, &sig_pipe_old_act);
+}
+
+static const struct device_ops signal_device_ops = {
+ .name = "signal",
+ .init = signal_init,
+};
+
+DEVICE_OPS_REGISTER(&signal_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <assert.h>
+
+#include "log.h"
+#include "device-notifier.h"
+#include "devices.h"
+#include "udev.h"
+#include "list.h"
+#include "edbus-handler.h"
+
+#define KERNEL "kernel"
+#define UDEV "udev"
+
+#define UDEV_MONITOR_SIZE (10*1024)
+
+struct uevent_info {
+ struct udev_monitor *mon;
+ Ecore_Fd_Handler *fdh;
+ dd_list *event_list;
+};
+
+/* Uevent */
+static struct udev *udev;
+
+static struct uevent_info kevent; /* kernel */
+static struct uevent_info uevent; /* udev */
+
+static Eina_Bool uevent_control_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ struct uevent_info *info = data;
+ struct udev_device *dev;
+ struct uevent_handler *l;
+ dd_list *elem;
+ const char *subsystem;
+ int len;
+
+ assert(info);
+
+ dev = udev_monitor_receive_device(info->mon);
+ if (!dev)
+ return ECORE_CALLBACK_RENEW;
+
+ subsystem = udev_device_get_subsystem(dev);
+ if (!subsystem)
+ goto out;
+
+ len = strlen(subsystem);
+ DD_LIST_FOREACH(info->event_list, elem, l) {
+ if (!strncmp(l->subsystem, subsystem, len) &&
+ l->uevent_func)
+ l->uevent_func(dev);
+ }
+
+out:
+ udev_device_unref(dev);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int uevent_control_stop(struct uevent_info *info)
+{
+ struct udev_device *dev;
+
+ if (!info)
+ return -EINVAL;
+
+ if (info->fdh) {
+ ecore_main_fd_handler_del(info->fdh);
+ info->fdh = NULL;
+ }
+ if (info->mon) {
+ dev = udev_monitor_receive_device(info->mon);
+ if (dev)
+ udev_device_unref(dev);
+ udev_monitor_unref(info->mon);
+ info->mon = NULL;
+ }
+ if (udev)
+ udev = udev_unref(udev);
+ return 0;
+}
+
+static int uevent_control_start(const char *type,
+ struct uevent_info *info)
+{
+ struct uevent_handler *l;
+ dd_list *elem;
+ int fd;
+ int ret;
+
+ if (!info)
+ return -EINVAL;
+
+ if (info->mon) {
+ _E("%s uevent control routine is alreay started", type);
+ return -EINVAL;
+ }
+
+ if (!udev) {
+ udev = udev_new();
+ if (!udev) {
+ _E("error create udev");
+ return -EINVAL;
+ }
+ } else
+ udev = udev_ref(udev);
+
+ info->mon = udev_monitor_new_from_netlink(udev, type);
+ if (info->mon == NULL) {
+ _E("error udev_monitor create");
+ goto stop;
+ }
+
+ ret = udev_monitor_set_receive_buffer_size(info->mon,
+ UDEV_MONITOR_SIZE);
+ if (ret != 0) {
+ _E("fail to set receive buffer size");
+ goto stop;
+ }
+
+ DD_LIST_FOREACH(info->event_list, elem, l) {
+ ret = udev_monitor_filter_add_match_subsystem_devtype(
+ info->mon,
+ l->subsystem, NULL);
+ if (ret < 0) {
+ _E("error apply subsystem filter");
+ goto stop;
+ }
+ }
+
+ ret = udev_monitor_filter_update(info->mon);
+ if (ret < 0)
+ _E("error udev_monitor_filter_update");
+
+ fd = udev_monitor_get_fd(info->mon);
+ if (fd == -1) {
+ _E("error udev_monitor_get_fd");
+ goto stop;
+ }
+
+ info->fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ uevent_control_cb, info, NULL, NULL);
+ if (!info->fdh) {
+ _E("error ecore_main_fd_handler_add");
+ goto stop;
+ }
+
+ if (udev_monitor_enable_receiving(info->mon) < 0) {
+ _E("error unable to subscribe to udev events");
+ goto stop;
+ }
+
+ return 0;
+stop:
+ uevent_control_stop(info);
+ return -EINVAL;
+}
+
+static int register_uevent_control(struct uevent_info *info,
+ const struct uevent_handler *uh)
+{
+ struct uevent_handler *l;
+ dd_list *elem;
+ int r;
+ bool matched = false;
+ int len;
+
+ if (!info || !uh || !uh->subsystem)
+ return -EINVAL;
+
+ /* if udev is not initialized, it just will be added list */
+ if (!udev || !info->mon)
+ goto add_list;
+
+ len = strlen(uh->subsystem);
+ /* check if the same subsystem is already added */
+ DD_LIST_FOREACH(info->event_list, elem, l) {
+ if (!strncmp(l->subsystem, uh->subsystem, len)) {
+ matched = true;
+ break;
+ }
+ }
+
+ /* the first request to add subsystem */
+ if (!matched) {
+ r = udev_monitor_filter_add_match_subsystem_devtype(info->mon,
+ uh->subsystem, NULL);
+ if (r < 0) {
+ _E("fail to add %s subsystem : %d", uh->subsystem, r);
+ return -EPERM;
+ }
+ }
+
+ r = udev_monitor_filter_update(info->mon);
+ if (r < 0)
+ _E("fail to update udev monitor filter : %d", r);
+
+add_list:
+ DD_LIST_APPEND(info->event_list, uh);
+ return 0;
+}
+
+static int unregister_uevent_control(struct uevent_info *info,
+ const struct uevent_handler *uh)
+{
+ struct uevent_handler *l;
+ dd_list *n, *next;
+ int len;
+
+ if (!info || !uh || !uh->subsystem)
+ return -EINVAL;
+
+ len = strlen(uh->subsystem);
+ DD_LIST_FOREACH_SAFE(info->event_list, n, next, l) {
+ if (!strncmp(l->subsystem, uh->subsystem, len) &&
+ l->uevent_func == uh->uevent_func) {
+ DD_LIST_REMOVE(info->event_list, l);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int register_kernel_uevent_control(const struct uevent_handler *uh)
+{
+ return register_uevent_control(&kevent, uh);
+}
+
+int unregister_kernel_uevent_control(const struct uevent_handler *uh)
+{
+ return unregister_uevent_control(&kevent, uh);
+}
+
+int register_udev_uevent_control(const struct uevent_handler *uh)
+{
+ return register_uevent_control(&uevent, uh);
+}
+
+int unregister_udev_uevent_control(const struct uevent_handler *uh)
+{
+ return unregister_uevent_control(&uevent, uh);
+}
+
+static DBusMessage *dbus_udev_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret = 0;
+ int argc;
+ char *type_str;
+ char *argv;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (strncmp(argv, "start", strlen("start")) == 0) {
+ uevent_control_start(KERNEL, &kevent);
+ uevent_control_start(UDEV, &uevent);
+ } else if (strncmp(argv, "stop", strlen("stop")) == 0) {
+ uevent_control_stop(&kevent);
+ uevent_control_stop(&uevent);
+ }
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { UDEV, "sis", "i", dbus_udev_handler },
+};
+
+static int device_change_poweroff(void *data)
+{
+ uevent_control_stop(&kevent);
+ uevent_control_stop(&uevent);
+ return 0;
+}
+
+static void udev_init(void *data)
+{
+ int ret;
+
+ register_notifier(DEVICE_NOTIFIER_POWEROFF, device_change_poweroff);
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+
+ if (uevent_control_start(KERNEL, &kevent) != 0)
+ _E("fail uevent kernel control init");
+
+ if (uevent_control_start(UDEV, &uevent) != 0)
+ _E("fail uevent udev control init");
+}
+
+static void udev_exit(void *data)
+{
+ unregister_notifier(DEVICE_NOTIFIER_POWEROFF, device_change_poweroff);
+}
+
+static const struct device_ops udev_device_ops = {
+ .priority = DEVICE_PRIORITY_NORMAL,
+ .name = "udev",
+ .init = udev_init,
+ .exit = udev_exit,
+};
+
+DEVICE_OPS_REGISTER(&udev_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 __UDEV_H__
+#define __UDEV_H__
+
+#include <libudev.h>
+
+#define UDEV_CHANGE "change"
+#define UDEV_ADD "add"
+#define UDEV_REMOVE "remove"
+
+#define UDEV_DEVPATH "DEVPATH"
+#define UDEV_DEVTYPE "DEVTYPE"
+
+/* battery device */
+#define POWER_SUBSYSTEM "power_supply"
+#define POWER_PATH "/sys/class/power_supply/battery"
+#define POWER_SUPPLY_UEVENT POWER_PATH"/uevent"
+#define CAPACITY "POWER_SUPPLY_CAPACITY"
+#define CHARGE_HEALTH "POWER_SUPPLY_HEALTH"
+#define CHARGE_PRESENT "POWER_SUPPLY_PRESENT"
+#define CHARGE_NAME "POWER_SUPPLY_NAME"
+#define CHARGE_STATUS "POWER_SUPPLY_STATUS"
+#define CHARGE_ONLINE "POWER_SUPPLY_ONLINE"
+
+/* extcon */
+#define EXTCON_SUBSYSTEM "extcon"
+
+/* usb */
+#define USB_SUBSYSTEM "usb"
+#define USB_INTERFACE_DEVTYPE "usb_interface"
+#define USB_DEVICE_DEVTYPE "usb_device"
+
+/* block */
+#define BLOCK_SUBSYSTEM "block"
+#define BLOCK_DEVTYPE_DISK "disk"
+#define BLOCK_DEVTYPE_PARTITION "partition"
+
+/* power supply status */
+enum {
+ POWER_SUPPLY_STATUS_UNKNOWN = 0,
+ POWER_SUPPLY_STATUS_CHARGING,
+ POWER_SUPPLY_STATUS_DISCHARGING,
+ POWER_SUPPLY_STATUS_NOT_CHARGING,
+ POWER_SUPPLY_STATUS_FULL,
+};
+
+enum {
+ POWER_SUPPLY_TYPE_UNKNOWN = 0,
+ POWER_SUPPLY_TYPE_BATTERY,
+ POWER_SUPPLY_TYPE_UPS,
+ POWER_SUPPLY_TYPE_MAINS,
+ POWER_SUPPLY_TYPE_USB,
+};
+
+enum dock_type {
+ DOCK_NONE = 0,
+ DOCK_SOUND = 7,
+};
+
+struct uevent_handler {
+ char *subsystem;
+ void (*uevent_func)(struct udev_device *dev);
+ void *data;
+};
+
+int register_kernel_uevent_control(const struct uevent_handler *uh);
+int unregister_kernel_uevent_control(const struct uevent_handler *uh);
+
+int register_udev_uevent_control(const struct uevent_handler *uh);
+int unregister_udev_uevent_control(const struct uevent_handler *uh);
+
+#endif /* __UDEV_H__ */
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(devicectl C)
+
+IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_ENGINEER_MODE")
+ OPTION(USE_ENGINEER_MODE "Use Engineer mode" ON)
+ENDIF()
+
+SET(SRCS
+ devicectl.c
+ usb.c
+)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED dbus-1)
+
+FOREACH(flag ${pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+IF( $ENV{ARCH} MATCHES "arm" )
+ ADD_DEFINITIONS("-DTARGET")
+ENDIF()
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} shared)
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
--- /dev/null
+/*
+ * devicectl
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dbus/dbus.h>
+#include <shared/dbus.h>
+#include <core/common.h>
+#include "usb.h"
+
+/*
+ * devicectl [device] [action]
+ * ex> devicectl display stop
+ * devicectl pass start
+ */
+
+enum device_type {
+ DEVICE_CORE,
+ DEVICE_DISPLAY,
+ DEVICE_LED,
+ DEVICE_PASS,
+ DEVICE_USB,
+ DEVICE_EXTCON,
+ DEVICE_POWER,
+ DEVICE_USB_HOST_TEST,
+ DEVICE_MAX,
+ DEVICE_ALL,
+};
+static enum device_type arg_id;
+
+static const struct device {
+ const enum device_type id;
+ const char *name;
+ const char *path;
+ const char *iface;
+} devices[] = {
+ { DEVICE_CORE, "core", DEVICED_PATH_CORE, DEVICED_INTERFACE_CORE },
+ { DEVICE_DISPLAY, "display", DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY },
+ { DEVICE_LED, "led", DEVICED_PATH_LED, DEVICED_INTERFACE_LED },
+ { DEVICE_PASS, "pass", DEVICED_PATH_PASS, DEVICED_INTERFACE_PASS },
+ { DEVICE_USB, "usb", DEVICED_PATH_USB, DEVICED_INTERFACE_USB },
+ { DEVICE_EXTCON, "extcon", DEVICED_PATH_EXTCON, DEVICED_INTERFACE_EXTCON },
+ { DEVICE_POWER, "power", DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER },
+ { DEVICE_USB_HOST_TEST, "usb-host-test", DEVICED_PATH_USB_HOST_TEST, DEVICED_INTERFACE_USB_HOST_TEST},
+};
+
+static int start_device(char **args)
+{
+ DBusMessage *msg;
+
+ if (!args[1])
+ return -EINVAL;
+
+ printf("start %s device!\n", args[1]);
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "start", NULL, NULL);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int stop_device(char **args)
+{
+ DBusMessage *msg;
+
+ if (!args[1])
+ return -EINVAL;
+
+ printf("stop %s device!\n", args[1]);
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "stop", NULL, NULL);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int dump_mode(char **args)
+{
+ int ret;
+ char *arr[1];
+
+ if (!args[1] || !args[2] || !args[3])
+ return -EINVAL;
+
+ printf("%s (%s %s)!\n", args[1], args[2], args[3]);
+
+ arr[0] = args[3];
+ ret = dbus_method_async(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "Dumpmode", "s", arr);
+ if (ret < 0)
+ printf("failed to set dump mode (%d)", ret);
+
+ return ret;
+}
+
+static int save_log(char **args)
+{
+ int ret;
+
+ if (!args[1])
+ return -EINVAL;
+
+ printf("save log %s device!\n", args[1]);
+
+ ret = dbus_method_async(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "SaveLog", NULL, NULL);
+ if (ret < 0)
+ printf("failed to save log (%d)", ret);
+
+ return ret;
+}
+
+static void get_pname(pid_t pid, char *pname)
+{
+ char buf[PATH_MAX];
+ int cmdline, r;
+
+ snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
+ cmdline = open(buf, O_RDONLY);
+ if (cmdline < 0) {
+ pname[0] = '\0';
+ return;
+ }
+
+ r = read(cmdline, pname, PATH_MAX);
+ if ((r >= 0) && (r < PATH_MAX))
+ pname[r] = '\0';
+ else
+ pname[0] = '\0';
+
+ close(cmdline);
+}
+
+static int save_dbus_name(char **args)
+{
+ DBusMessage *msg;
+ char **list;
+ int ret, size, i;
+ pid_t pid;
+ char *arr[1];
+ char pname[PATH_MAX];
+
+ if (!args[1])
+ return -EINVAL;
+
+ printf("save dbus name!\n");
+
+ msg = dbus_method_sync_with_reply(DBUS_BUS_NAME,
+ DBUS_OBJECT_PATH, DBUS_INTERFACE_NAME,
+ "ListNames", NULL, NULL);
+ if (!msg) {
+ printf("failed to get list names");
+ return -EBADMSG;
+ }
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING, &list, &size, DBUS_TYPE_INVALID);
+ dbus_message_unref(msg);
+ if (!ret) {
+ printf("invalid list name arguments!");
+ return -EINVAL;
+ }
+
+ printf("%d connections\n", size);
+
+ for (i = 0; i < size; i++) {
+ arr[0] = list[i];
+ msg = dbus_method_sync_with_reply(DBUS_BUS_NAME,
+ DBUS_OBJECT_PATH, DBUS_INTERFACE_NAME,
+ "GetConnectionUnixProcessID", "s", arr);
+ if (!msg)
+ continue;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32,
+ &pid, DBUS_TYPE_INVALID);
+ dbus_message_unref(msg);
+ if (!ret)
+ continue;
+
+ get_pname(pid, pname);
+ printf("%6d %6s %s\n", pid, list[i], pname);
+
+ }
+
+ return 0;
+}
+
+static int device_list(char **args)
+{
+ DBusMessage *msg;
+
+ if (!args[1])
+ return -EINVAL;
+
+ printf("print %s to dlog!\n", args[1]);
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "DeviceList", NULL, NULL);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int set_usb_mode(char **args)
+{
+ return load_usb_mode(args[3]);
+}
+
+static int unset_usb_mode(char **args)
+{
+ return unload_usb_mode(args[3]);
+}
+
+static int enable_device(char **args)
+{
+ DBusMessage *msg;
+ char *arr[1];
+
+ if (!args[3])
+ return -EINVAL;
+
+ printf("enable %s device!\n", args[3]);
+
+ arr[0] = args[3];
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "enable", "s", arr);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int disable_device(char **args)
+{
+ DBusMessage *msg;
+ char *arr[1];
+
+ if (!args[3])
+ return -EINVAL;
+
+ printf("disable %s device!\n", args[3]);
+
+ arr[0] = args[3];
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "disable", "s", arr);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+
+static int power_operation(char **args, char *type)
+{
+ DBusMessage *msg;
+ char *arr[2];
+
+ if (!args[1] || !type)
+ return -EINVAL;
+
+ printf("Power %s device!\n", args[2]);
+
+ arr[0] = type;
+ arr[1] = "0";
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ devices[arg_id].path, devices[arg_id].iface,
+ "reboot", "si", arr);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_message_unref(msg);
+
+ return 0;
+}
+static int power_off(char **args)
+{
+ return power_operation(args, "poweroff");
+}
+
+static int power_reboot(char **args)
+{
+ return power_operation(args, "reboot");
+}
+
+static const struct action {
+ const enum device_type id;
+ const char *action;
+ const int argc;
+ int (* const func)(char **args);
+ const char *option;
+} actions[] = {
+ { DEVICE_ALL, "start", 3, start_device, "" },
+ { DEVICE_ALL, "stop", 3, stop_device, "" },
+ { DEVICE_DISPLAY, "dumpmode", 4, dump_mode, "[on|off]" },
+ { DEVICE_LED, "dumpmode", 4, dump_mode, "[on|off]" },
+ { DEVICE_DISPLAY, "savelog", 3, save_log, "" },
+ { DEVICE_USB, "set", 4, set_usb_mode, "[sdb|ssh]" },
+ { DEVICE_USB, "unset", 4, unset_usb_mode, "[sdb|ssh]" },
+ { DEVICE_CORE, "dbusname", 3, save_dbus_name, "" },
+ { DEVICE_CORE, "devicelist", 3, device_list, "" },
+ { DEVICE_EXTCON, "enable", 4, enable_device, "[USB|HEADPHONE|HDMI|DOCK]" },
+ { DEVICE_EXTCON, "disable", 4, disable_device, "[USB|HEADPHONE|HDMI|DOCK]" },
+ { DEVICE_POWER, "off", 3, power_off, "" },
+ { DEVICE_POWER, "reboot", 3, power_reboot, "" },
+};
+
+static inline void usage()
+{
+ printf("[usage] devicectl <device_name> <action>\n");
+ printf("Please use option --help to check options\n");
+}
+
+static void help()
+{
+ int i;
+
+ printf("[usage] devicectl <device_name> <action> <option>\n");
+ printf("device name & action & option\n");
+ for (i = 0; i < ARRAY_SIZE(actions); i++) {
+ if (actions[i].id == DEVICE_ALL) {
+ printf(" [all-device] %s %s\n", actions[i].action,
+ actions[i].option);
+ } else {
+ printf(" %s %s %s\n", devices[actions[i].id].name,
+ actions[i].action, actions[i].option);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ if (argc == 2 && !strcmp(argv[1], "--help")) {
+ help();
+ return 0;
+ }
+
+ if (argc < 3) {
+ usage();
+ return -EINVAL;
+ }
+
+ for (i = 0; i < argc; i++)
+ if (argv[i] == NULL) {
+ usage();
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++)
+ if (!strcmp(argv[1], devices[i].name))
+ break;
+
+ if (i >= ARRAY_SIZE(devices)) {
+ printf("invalid device name! %s\n", argv[1]);
+ usage();
+ return -EINVAL;
+ }
+
+ arg_id = devices[i].id;
+
+ for (i = 0; i < ARRAY_SIZE(actions); i++)
+ if (actions[i].id == arg_id || actions[i].id == DEVICE_ALL)
+ if (!strcmp(argv[2], actions[i].action))
+ break;
+
+ if (i >= ARRAY_SIZE(actions)) {
+ printf("invalid action name! %s\n", argv[2]);
+ usage();
+ return -EINVAL;
+ }
+
+ if (actions[i].argc != argc) {
+ printf("invalid arg count!\n");
+ usage();
+ return -EINVAL;
+ }
+
+ return actions[i].func(argv);
+}
--- /dev/null
+/*
+ * devicectl
+ *
+ * Copyright (c) 2012 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <core/common.h>
+#include <core/launch.h>
+#include "usb.h"
+
+#define USB_SDB "sdb"
+#define USB_SSH "ssh"
+
+#define ARG_MAX 10
+#define CMD_MAX 128
+
+static struct usb_sysfs {
+ char *path;
+ char *value;
+} usb_confs[] = {
+ { "/sys/class/usb_mode/usb0/enable", "0" },
+ { "/sys/class/usb_mode/usb0/idVendor", "04e8" },
+ { "/sys/class/usb_mode/usb0/idProduct", NULL },
+ { "/sys/class/usb_mode/usb0/funcs_fconf", NULL },
+ { "/sys/class/usb_mode/usb0/funcs_sconf", NULL },
+ { "/sys/class/usb_mode/usb0/bDeviceClass", "239" },
+ { "/sys/class/usb_mode/usb0/bDeviceSubClass", "2" },
+ { "/sys/class/usb_mode/usb0/bDeviceProtocol", "1" },
+ { "/sys/class/usb_mode/usb0/enable", "1" },
+};
+
+static int launch_app(char **argv)
+{
+ pid_t pid;
+
+ if (!argv || !argv[0])
+ return -EINVAL;
+
+ pid = fork();
+
+ if (pid < 0) {
+ printf("fork() failed\n");
+ return -ENOMEM;
+ }
+
+ if (pid > 0) { /*parent*/
+ return pid;
+ }
+
+ /*child*/
+
+ if (execvp(argv[0], argv) < 0)
+ printf("execvp failed (%d)\n", errno);
+
+ return 0;
+}
+
+static int write_sysfs(char *path, char *value)
+{
+ FILE *fp;
+ int ret;
+
+ if (!path || !value)
+ return -ENOMEM;
+
+ fp = fopen(path, "w");
+ if (!fp) {
+ printf("FAIL: fopen(%s)\n", path);
+ return -ENOMEM;
+ }
+
+ ret = fwrite(value, sizeof(char), strlen(value), fp);
+ fclose(fp);
+ if (ret < strlen(value)) {
+ printf("FAIL: fwrite(%s)\n", value);
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static int set_usb_configuration(char *idproduct, char *fconf, char *sconf)
+{
+ int i, ret;
+
+ usb_confs[2].value = idproduct;
+ usb_confs[3].value = fconf;
+ usb_confs[4].value = sconf;
+
+ for (i = 0; i < ARRAY_SIZE(usb_confs); i++) {
+ ret = write_sysfs(usb_confs[i].path, usb_confs[i].value);
+ if (ret < 0) {
+ printf("usb setting fails (%s), (%s)\n", usb_confs[i].path, usb_confs[i].value);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int divide_cmd(char **command, int len, char *cmd)
+{
+ char *param, *next, *term;
+ int cnt = 0;
+
+ if (!cmd)
+ return -EINVAL;
+
+ term = strchr(cmd, '\0');
+ if (!term)
+ return -EINVAL;
+
+ memset(command, 0, len);
+
+ param = cmd;
+ while (1) {
+ if (*param == '\0')
+ break;
+ if (*param == ' ') {
+ param++;
+ continue;
+ }
+
+ next = strchr(param, ' ');
+ if (!next) {
+ command[cnt++] = param;
+ break;
+ }
+
+ if (next == param) {
+ param++;
+ continue;
+ }
+
+ *next = '\0';
+ command[cnt++] = param;
+ param = next + 1;
+ }
+
+ return 0;
+}
+
+static int run_cmd(char *cmd)
+{
+ int ret;
+ char *command[ARG_MAX];
+ char in_cmd[CMD_MAX];
+
+ if (!cmd)
+ return -EINVAL;
+
+ snprintf(in_cmd, sizeof(in_cmd), "%s", cmd);
+
+ ret = divide_cmd(command, sizeof(command), in_cmd);
+ if (ret < 0)
+ return ret;
+
+ ret = launch_app(command);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+
+}
+
+static int load_sdb(void)
+{
+ int ret;
+
+ ret = set_usb_configuration("6860", "mtp", "mtp,acm,sdb");
+ if (ret < 0)
+ return ret;
+
+ return run_cmd("/usr/bin/systemctl start sdbd.service");
+}
+
+static int load_ssh(void)
+{
+ int ret;
+
+ ret = set_usb_configuration("6863", "rndis", " ");
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/sbin/ifconfig usb0 192.168.129.3 up");
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/sbin/route add -net 192.168.129.0 netmask 255.255.255.0 dev usb0");
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/usr/bin/systemctl start sshd.service");
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int unload_sdb(void)
+{
+ int ret;
+
+ ret = write_sysfs(usb_confs[0].path, usb_confs[0].value);
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/usr/bin/systemctl stop sdbd.service");
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int unload_ssh(void)
+{
+ int ret;
+
+ ret = write_sysfs(usb_confs[0].path, usb_confs[0].value);
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/sbin/ifconfig usb0 down");
+ if (ret < 0)
+ return ret;
+
+ ret = run_cmd("/usr/bin/systemctl stop sshd.service");
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int load_usb_mode(char *opt)
+{
+ if (!opt) {
+ printf("Failed: Forth parameter is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!strncmp(opt, USB_SDB, strlen(opt)))
+ return load_sdb();
+
+ if (!strncmp(opt, USB_SSH, strlen(opt)))
+ return load_ssh();
+
+ printf("Failed: Forth parameter is invalid (%s)\n", opt);
+ return -EINVAL;
+}
+
+int unload_usb_mode(char *opt)
+{
+ if (!opt) {
+ printf("Failed: Forth parameter is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!strncmp(opt, USB_SDB, strlen(opt)))
+ return unload_sdb();
+
+ if (!strncmp(opt, USB_SSH, strlen(opt)))
+ return unload_ssh();
+
+ printf("Failed: Forth parameter is invalid (%s)\n", opt);
+ return -EINVAL;
+}
--- /dev/null
+/*
+ * devicectl
+ *
+ * Copyright (c) 2012 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __DEVICECTL_USBCLIENT_H__
+#define __DEVICECTL_USBCLIENT_H__
+
+int load_usb_mode(char *opt);
+int unload_usb_mode(char *opt);
+
+#endif /* __DEVICECTL_USBCLIENT_H__*/
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_COMMON_H__
+#define __DD_COMMON_H__
+
+/**
+ * @file dd-common.h
+ * @ingroup CAPI_SYSTEM_DEVICED
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DEPRECATED
+#define DEPRECATED __attribute__((deprecated))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DD_COMMON_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_CONTROL_H__
+#define __DD_CONTROL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+/**
+ * @file dd-control.h
+ * @defgroup CAPI_SYSTEM_DEVICED_CONTROL_MODULE Control
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API to enable/disable devices
+ * @section CAPI_SYSTEM_DEVICED_CONTROL_MODULE_HEADER Required Header
+ * \#include <dd-control.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_CONTROL_MODULE
+ * @{
+ */
+
+/**
+ * @par Description
+ * Control Device type
+ */
+enum control_device_type {
+/* Add device define here */
+ DEVICE_CONTROL_MMC,
+ DEVICE_CONTROL_USBCLIENT,
+ DEVICE_CONTROL_BLOCK,
+ DEVICE_CONTROL_MAX,
+};
+
+/**
+ * @par Description:
+ * This API is used to enable/disable mmc device.\n
+ * @param[in] enable enable/disable mmc device
+ * @return 0 on success, -1 if failed
+ * @par Example
+ * @code
+ * ...
+ * if( deviced_mmc_control(1) < 0 )
+ * printf("Enable mmc device failed\n");
+ * ...
+ * @endcode
+ */
+int deviced_mmc_control(bool enable);
+
+/**
+ * @par Description:
+ * This API is used to enable/disable usb device.\n
+ * @param[in] enable enable/disable usb device
+ * @return 0 on success, -1 if failed
+ * @par Example
+ * @code
+ * ...
+ * if( deviced_usb_control(1) < 0 )
+ * printf("Enable usb device failed\n");
+ * ...
+ * @endcode
+ */
+int deviced_usb_control(bool enable);
+
+/* Only USB-manager will use the api */
+/**
+ * @par Description:
+ * @return
+ * @par Example
+ * @code
+ * @endcode
+ * @todo describe function
+ */
+int deviced_get_usb_control(void);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_CONTROL_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_DEVICED_MANAGED_H__
+#define __DD_DEVICED_MANAGED_H__
+
+#include <sys/time.h>
+#include "dd-mmc.h"
+
+/**
+ * @file dd-deviced-managed.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED
+ * @{
+ */
+
+/**
+ * @fn int deviced_get_pid(const char *execpath)
+ * @brief This API is used to get the pid of the process which has the specified execpath.\n
+ * Internally, this API searches /proc/{pid}/cmdline and compares the parameter execpath with 1st argument of cmdline. \n
+ * If there is no process that has same execpath in /proc/{pid}/cmdline, it will return -1.
+ * @param[in] execpath program path which you want to know whether it is run or not
+ * @return pid when the program is running, -1 if it is not.
+ */
+int deviced_get_pid(const char *execpath);
+
+/**
+ * @fn int deviced_set_datetime(time_t timet)
+ * @brief This API is used to set date time.\n
+ * Internally, this API call predefined action API. That is send a notify message. \n
+ * @param[in] timet type of time which you want to set.
+ * @return pid when the program is running, -1 if param is less than 0 or when failed set datetime.
+ */
+int deviced_set_datetime(time_t timet);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DD_DEVICED_MANAGED_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_DEVICED__
+#define __DD_DEVICED__
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "dd-deviced-managed.h"
+
+/**
+ * @file dd-deviced.h
+ * @defgroup CAPI_SYSTEM_DEVICED_UTIL_MODULE Util
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @section CAPI_SYSTEM_DEVICED_UTIL_MODULE_HEADER Required Header
+ * \#include <dd-deviced.h>
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_UTIL_MODULE
+ * @{
+ */
+
+/**
+ * @brief Policy for low memory
+ */
+enum mem_policy {
+ OOM_LIKELY, /**< For miscellaneous applications */
+ OOM_IGNORE /**< For daemons */
+};
+
+/* deviced_util */
+
+/**
+ * @fn int deviced_get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
+ * @brief This API is used to get the file name of command line of the process from the proc fs.
+ * Caller process MUST allocate enough memory for the cmdline parameter. \n
+ * Its size should be assigned to cmdline_size. \n
+ * Internally it reads the 1st argument of /proc/{pid}/cmdline and copies it to cmdline.
+ * @param[in] pid pid of the process that you want to get the file name of command line
+ * @param[out] cmdline command line of the process that you want to get the file name <br>
+ * Callers should allocate memory to this parameter before calling this function.
+ * The allocated memory size must be large enough to store the file name.
+ * The result will include the terminating null byte('\0') at the end of the string.
+ * @param[in] cmdline_size
+ * @return 0 on success, negative value if failed.\n
+ * If the size of cmdline is smaller than the result, it will return -75 and \n
+ * errno will be set as EOVERFLOW. \n
+ * If the function cannot open /proc/%d/cmdline file then it will return -3 and \n
+ * errno will be set as ESRCH.
+ */
+int deviced_get_cmdline_name(pid_t pid, char *cmdline,
+ size_t cmdline_size);
+
+/**
+ * @fn int deviced_get_apppath(pid_t pid, char *app_path, size_t app_path_size)
+ * @brief This API is used to get the execution path of the process specified by the pid parameter.\n
+ * Caller process MUST allocate enough memory for the app_path parameter. \n
+ * Its size should be assigned to app_path_size. \n
+ * Internally it reads a link of /proc/{pid}/exe and copies the path to app_path.
+ * @param[in] pid pid of the process that you want to get the executed path
+ * @param[out] app_path the executed file path of the process <br>
+ * Callers should allocate memory to this parameter before calling this function.
+ * The allocated memory size must be large enough to store the executed file path.
+ * The result will include the terminating null byte('\0') at the end of the string.
+ * @param[in] app_path_size allocated memory size of char *app_path
+ * @return 0 on success, -1 if failed. \n
+ * If the size of app_path is smaller than the result, it will return -1 and \n
+ * errno will be set as EOVERFLOW.
+ */
+int deviced_get_apppath(pid_t pid, char *app_path, size_t app_path_size);
+
+/* sysconf */
+
+/**
+ * @fn int deviced_conf_set_mempolicy(enum mem_policy mempol)
+ * @brief This API is used to set the policy of the current process when the phone has low available memory.
+ * @param[in] mempol oom adjust value which you want to set
+ * @return 0 on success, -1 if failed.
+ * @see deviced_conf_set_mempolicy_bypid()
+ * @retval -1 operation error
+ * @retval -EBADMSG - dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_conf_set_mempolicy(enum mem_policy mempol);
+
+/**
+ * @fn int deviced_conf_set_mempolicy_bypid(pid_t pid, enum mem_policy mempol)
+ * @brief This API is used to set the policy of the given process when the phone has low available memory.
+ * @param[in] pid process id which you want to set
+ * @param[in] mempol oom adjust value which you want to set
+ * @return 0 on success, -1 if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG - dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_conf_set_mempolicy_bypid(pid_t pid, enum mem_policy mempol);
+
+/**
+ * @fn int deviced_conf_set_permanent(void)
+ * @brief This API is used to set itself as a permanent process.\n
+ * If the permanent process is dead, system server will relaunch the process automatically.
+ * @return 0 on success, -1 if failed.
+ * @see deviced_conf_set_permanent_bypid()
+ * @par Example
+ * @code
+ * ...
+ * ret = deviced_conf_set_permanent();
+ * if( ret < 0 )
+ * printf("Fail to set a process as permanent\n");
+ * ...
+ * @endcode
+ */
+int deviced_conf_set_permanent(void);
+
+/**
+ * @fn int deviced_conf_set_permanent_bypid(pid_t pid)
+ * @brief This API is used to set a given process as permanent.\n
+ * If the permanent process is dead, system server will relaunch the process automatically.
+ * @param[in] pid proces id
+ * @return 0 on success, -1 if failed.
+ * @see deviced_set_permanent()
+ * @par Example
+ * @code
+ * ...
+ * ret = deviced_conf_set_permanent_bypid(pid);
+ * if( ret < 0 )
+ * printf("Fail to set a process(%d) as permanent\n",pid);
+ * ...
+ * @endcode
+ */
+int deviced_conf_set_permanent_bypid(pid_t pid);
+
+/**
+ * @fn int deviced_conf_set_vip(pid_t pid)
+ * @brief This API is used to set a process which has pid as Very Important Process(VIP) .\n
+ * If the VIP process is dead, restarter program will be run. \n
+ * Restarter program may kill almost processes and run rc.local scripts again.
+ * @param[in] pid process id to be vip
+ * @return 0 on success, -1 if failed.
+ * @see sysconf_is_vip
+ * @par Example
+ * @code
+ * ...
+ * ret = deviced_conf_set_vip(pid);
+ * if( ret < 0 )
+ * printf("Fail to set a process(%d) as VIP\n",pid);
+ * ...
+ * @endcode
+ */
+int deviced_conf_set_vip(pid_t pid);
+
+/**
+ * @fn int deviced_conf_is_vip(pid_t pid)
+ * @brief This API is used to verify that process which has pid is Very Important Process(VIP) or not.
+ * @param[in] pid process id to be vip
+ * @return 1 if given process if vip process, otherwise 0 is returned.
+ * @see deviced_conf_set_vip
+ * @par Example
+ * @code
+ * ...
+ * ret = deviced_conf_is_vip(pid);
+ * if(ret)
+ * printf("process(%d) is Very Important Process\n",pid);
+ * ...
+ * @endcode
+ */
+int deviced_conf_is_vip(pid_t pid);
+
+/**
+ * @fn int deviced_set_timezone(char *tzpath_str)
+ * @brief This API sets system timezone.
+ * @param[in] tzpath_str path to timezone definition file
+ * @return 0 on success, negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_set_timezone(char *tzpath_str);
+
+/**
+ * @fn int deviced_call_predef_action(const char *type, int num, ...)
+ * @brief This API calls predefined systemd action.
+ * Internally it send message through SYSTEM_NOTI_SOCKET_PATH (/tmp/sn) UNIX socket to systemd.
+ * @param[in] type systemd action type name
+ * @param[in] num input parameters count. num cannot exceed SYSTEM_NOTI_MAXARG (16).
+ * @param[in] ... action input parameters. List of the parameters depends on action type.
+ * @return 0 on success, -1 if failed.
+ * If the action type is not set (is blank) or num > SYSTEM_NOTI_MAXARG it will return -1
+ * and errno will be set as EINVAL.
+ */
+int deviced_call_predef_action(const char *type, int num, ...);
+
+/**
+ * @fn int deviced_change_flightmode(int mode)
+ * @brief This API call notifies about flight mode.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_change_flightmode(int mode);
+
+/**
+ * @fn int deviced_inform_foregrd(void)
+ * @brief This API call notifies that current process is running in foreground.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_inform_foregrd(void);
+
+/**
+ * @fn int deviced_inform_backgrd(void)
+ * @brief This API call notifies that current process is running in background.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_inform_backgrd(void);
+
+/**
+ * @fn int deviced_inform_active(pid_t pid)
+ * @brief This API call notifies deviced daemon that given process (pid) is active.
+ * @param[in] pid process pid
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_inform_active(pid_t pid);
+
+/**
+ * @fn int deviced_inform_active(pid_t pid)
+ * @brief This API call notifies deviced daemon that given process (pid) is inactive.
+ * @param[in] pid process pid
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_inform_inactive(pid_t pid);
+
+/**
+ * @fn int deviced_request_poweroff(void)
+ * @brief This API call requests deviced daemon to launch "system poweroff popup".
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_request_poweroff(void);
+
+/**
+ * @fn deviced_request_entersleep(void)
+ * @brief This API call requests deviced daemon to enter system into sleep mode.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_request_entersleep(void);
+
+/**
+ * @fn int deviced_request_leavesleep(void)
+ * @brief This API calls requests deviced daemon to leave by system "sleep" mode and enter into "normal" mode.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_request_leavesleep(void);
+
+/**
+ * @fn int deviced_request_reboot(void)
+ * @brief This API call requests deviced daemon to initiate system reboot.
+ * @return 0 on success and negative value if failed.
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ * @retval -EINVAL no mandatory parameters
+ * @retval -ESRCH incorrect sender process id
+ */
+int deviced_request_reboot(void);
+
+/**
+ * @fn int deviced_request_set_cpu_max_frequency(int val)
+ * @brief This API call requests deviced daemon to set maximum CPU frequency.
+ * @param[in] val maximum CPU frequency to be set.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG - dbus error (in case of any error on the bus)
+ */
+int deviced_request_set_cpu_max_frequency(int val);
+
+/**
+ * @fn int deviced_request_set_cpu_min_frequency(int val)
+ * @brief This API call requests deviced daemon to set minimum CPU frequency.
+ * @param[in] val minimum CPU frequency to be set
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ */
+int deviced_request_set_cpu_min_frequency(int val);
+
+/**
+ * @fn int deviced_release_cpu_max_frequency(void)
+ * @brief This API call releases limit of maximum CPU frequency set by deviced_request_set_cpu_max_frequency() API.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ */
+int deviced_release_cpu_max_frequency(void);
+
+/**
+ * @fn int deviced_release_cpu_min_frequency(void)
+ * @brief This API calls releases limit of minimum CPU frequency set by deviced_request_set_cpu_min_frequency() API.
+ * @return 0 or positive value on success and negative value if failed.
+ * @retval -1 operation error
+ * @retval -EBADMSG dbus error (in case of any error on the bus)
+ */
+int deviced_release_cpu_min_frequency(void);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DD_DEVICED__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_DISPLAY_H__
+#define __DD_DISPLAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file dd-display.h
+ * @defgroup CAPI_SYSTEM_DEVICED_DISPLAY_MODULE Display
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API for control of display
+ * @section CAPI_SYSTEM_DEVICED_DISPLAY_MODULE_HEADER Required Header
+ * \#include <dd-display.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_DISPLAY_MODULE
+ * @{
+ */
+
+#include "dd-common.h"
+
+/**
+ * LCD state
+ */
+#define LCD_NORMAL 0x01 /**< NORMAL state */
+#define LCD_DIM 0x02 /**< LCD dimming state */
+#define LCD_OFF 0x04 /**< LCD off state */
+#define SUSPEND 0x08 /**< Sleep state */
+#define POWER_OFF 0x10 /**< Sleep state */
+#define STANDBY 0x20 /**< Standby state */
+#define SETALL (LCD_DIM | LCD_OFF | LCD_NORMAL) /*< select all state - not supported yet */
+
+/**
+ * Parameters for display_lock_state()
+ */
+#define STAY_CUR_STATE 0x1
+#define GOTO_STATE_NOW 0x2
+#define HOLD_KEY_BLOCK 0x4
+#define STANDBY_MODE 0x8
+
+/**
+ * Parameters for display_unlock_state()
+ */
+#define PM_SLEEP_MARGIN 0x0 /**< keep guard time for unlock */
+#define PM_RESET_TIMER 0x1 /**< reset timer for unlock */
+#define PM_KEEP_TIMER 0x2 /**< keep timer for unlock */
+
+/**
+ * @brief This API is used to get the max brightness of the display.\n
+ * @details It gets the current brightness of the display
+ * by calling device_get_property() function.\n
+ * It returns integer value which is the max brightness on success.\n
+ * Or a negative value(-1) is returned on failure
+ * @return max brightness value on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * int max_brt;
+ * max_brt = display_get_max_brightness();
+ * if( max_brt < 0 )
+ * printf("Fail to get the max brightness of the display.\n");
+ * else
+ * printf("Max brightness of the display is %d\n", max_brt);
+ * ...
+ * @endcode
+ */
+int display_get_max_brightness(void);
+
+/**
+ * @brief This API is used to set the current brightness of the display
+ * and system brightness value in settings.\n
+ * @details It sets the current brightness of the display
+ * by calling device_set_property() function.\n
+ * MUST use this API very carefully. \n
+ * This api is different from display_set_brightness api.\n
+ * display_set_brightness api will change only device brightness value.\n
+ * but this api will change device brightness
+ * as well as system brightness value.\n
+ * @param[in] val brightness value that you want to set
+ * @return 0 on success, negative if failed
+ * @see display_set_brightness()
+ * @par Example
+ * @code
+ * ...
+ * if( display_set_brightness_with_setting(6) < 0 )
+ * printf("Fail to set the current brightness of the display\n");
+ * else
+ * printf("The current brightness of the display is set 6\n");
+ * ...
+ * @endcode
+ */
+int display_set_brightness_with_setting(int val);
+
+enum refresh_app {
+ REFRESH_SETTING,
+ REFRESH_VIDEO,
+ REFRESH_CAMERA,
+ REFRESH_WEB,
+};
+
+/**
+ * @brief This API is used to lock a particular display state
+ * as the current display-state.\n
+ * @details The parameter state specifies the display state which
+ * you want to lock LCD_NORMAL, LCD_DIM, LCD_OFF. \n
+ * The second parameter Flag is set if you want to go
+ * the requested lock state directly.\n
+ * The third parameter timeout specifies lock-timeout in milliseconds.
+ * If the value 0 is selected, the display state remains locked
+ * until display_unlock_state is called.
+ * @param[in] state target power state which you want to lock
+ * - LCD_NORMAL, LCD_DIM, LCD_OFF
+ * @param[in] flag set if you want to go the lock state directly \n
+ * GOTO_STATE_NOW - State is changed directly you want to lock.\n
+ * STAY_CUR_STATE - State is not changed directly and
+ * phone stay current state until timeout expired.\n
+ * HOLD_KEY_BLOCK - Hold key is blocked during locking
+ * LCD_NORMAL or LCD_DIM. \n
+ * Then LCD state transition to LCD_OFF is blocked. \n
+ * If this flag is not set, phone state is lcd off
+ * after pressing hold key. \n
+ * GOTO_STATE_NOW and STAY_CUR_STATE can't be applied at the same time.
+ * @param[in] timeout lock-timeout in miliseconds. \n
+ * 0 is always lock until calling display_unlock_state
+ * @return 0 on success, negative if failed
+ * @see display_unlock_state(), display_change_state()
+ * @par Example
+ * @code
+ * ...
+ * result = pm_lock_state(LCD_NORMAL, GOTO_STATE_NOW, SET_TIMEOUT);
+ * if( result < 0 )
+ * printf("[ERROR] return value result =%d, \n",result);
+ * else
+ * printf("[SUCCESS]return value result =%d \n",result);
+ * ...
+ * @endcode
+ */
+int display_lock_state(unsigned int state, unsigned int flag, unsigned int timeout);
+
+/**
+ * @brief This API is used to unlock the display state. \n
+ * @details The parameter state specifies the display
+ * state which you want to unlock. \n
+ * Some examples are LCD_NORMAL, LCD_DIM, LCD_OFF.
+ * @param[in] state target display state which you want to unlock
+ * @param[in] flag set timer which is going to the next state after unlocking\n
+ * PM_SLEEP_MARGIN - If the current status is lcd off,
+ * deviced reset timer to 1 second.
+ * If the current status is not lcd off, deviced uses the existing timer.\n
+ * PM_RESET_TIMER - deviced resets timer.
+ * (lcd normal : reset timer to predfined value
+ * which is set in setting module,
+ * lcd dim : reset timer to 5 seconds, lcd off : reset timer to 1 seconds)\n
+ * PM_KEEP_TIMER - deviced uses the existing timer
+ * (if timer is already expired, deviced changes the status) \n
+ * @return 0 on success, negative if failed
+ * @see display_lock_state(), display_change_state()
+ * @par Example
+ * @code
+ * ...
+ * result = display_unlock_state(LCD_NORMAL,PM_RESET_TIMER);
+ * if( result < 0 )
+ * printf("[ERROR] return value result =%d, \n",result);
+ * else
+ * printf("[SUCCESS]return value result =%d \n",result);
+ * ...
+ * @endcode
+ */
+int display_unlock_state(unsigned int state, unsigned int flag);
+
+/**
+ * @brief This API is used to change display state by force.
+ * @param[in] state display state - LCD_NORMAL, LCD_DIM, LCD_OFF
+ * @return 0 on success, negative if failed.
+ * @see display_lock_state(), display_unlock_state()
+ * @par Example
+ * @code
+ * ...
+ * result = display_change_state(LCD_OFF);
+ * if( result < 0 )
+ * printf("[ERROR] return value result =%d, \n",result);
+ * else
+ * printf("[SUCCESS]return value result =%d \n",result);
+ * ...
+ * @endcode
+ */
+int display_change_state(unsigned int state);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_DISPLAY_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_HAPTIC_H__
+#define __DD_HAPTIC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file dd-haptic.h
+ * @defgroup CAPI_SYSTEM_DEVICED_HAPTIC_MODULE Haptic
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API for control of haptic
+ * @section CAPI_SYSTEM_DEVICED_HAPTI_MODULE_HEADER Required Header
+ * \#include <dd-haptic.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_HAPTIC_MODULE
+ * @{
+ */
+
+/**
+ * @brief The handle of haptic device
+ */
+typedef int haptic_device_h;
+
+/**
+ * @brief The handle of haptic effect
+ */
+typedef int haptic_effect_h;
+
+/**
+ * @brief Enumerations of device id for the Haptic API.
+ * @details We support two motors now.
+ */
+typedef enum {
+ HAPTIC_DEVICE_0 = 0x0, /**< 1st motor */
+ HAPTIC_DEVICE_1 = 0x1, /**< 2nd motor */
+ HAPTIC_DEVICE_ALL = 0x4, /**< both of them */
+} haptic_device_e;
+
+/**
+ * @brief Enumerations of priority level for the Haptic API.
+ */
+typedef enum
+{
+ HAPTIC_PRIORITY_MIN = 0, /**< Minimum effect priority for developers (default) */
+ HAPTIC_PRIORITY_MIDDLE, /**< Maximum effect priority for developers */
+ HAPTIC_PRIORITY_HIGH, /**< Maximum effect priority for OEMs */
+} haptic_priority_e;
+
+/**
+ * @brief Enumerations of feedback level for the Haptic API.
+ * @details Haptic level means vibration power (intensity).
+ */
+typedef enum
+{
+ HAPTIC_FEEDBACK_0 = 0, /**< feedback level 0 */
+ HAPTIC_FEEDBACK_1 = 20, /**< feedback level 1 */
+ HAPTIC_FEEDBACK_2 = 40, /**< feedback level 2 */
+ HAPTIC_FEEDBACK_3 = 60, /**< feedback level 3 */
+ HAPTIC_FEEDBACK_4 = 80, /**< feedback level 4 */
+ HAPTIC_FEEDBACK_5 = 100, /**< feedback level 5 */
+ HAPTIC_FEEDBACK_AUTO, /**< feedback level auto */
+} haptic_feedback_e;
+
+/**
+ * @brief Enumerations of unlimited duration for the Haptic API.
+ */
+typedef enum {
+ HAPTIC_DURATION_UNLIMITED = 0x7FFFFFFF,
+} haptic_duration_e;
+
+/**
+ * @brief Enumerations of iteration count for the Haptic API.
+ */
+typedef enum
+{
+ HAPTIC_ITERATION_ONCE = 1,
+ HAPTIC_ITERATION_INFINITE = 256,
+} haptic_iteration_e;
+
+/**
+ * @brief Enumerations of effect or device state for the Haptic API.
+ */
+typedef enum
+{
+ HAPTIC_STATE_STOP = 0,
+ HAPTIC_STATE_PLAYING,
+} haptic_state_e;
+
+/**
+ * @brief Enumerations of error codes for the Haptic API.
+ */
+typedef enum
+{
+ HAPTIC_ERROR_NONE = 0, //TIZEN_ERROR_NONE, /**< Successful */
+ HAPTIC_ERROR_INVALID_PARAMETER = -1, //TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ HAPTIC_ERROR_FILE_EXISTS = -2, //TIZEN_ERROR_FILE_EXISTS, /**< File exists */
+ HAPTIC_ERROR_NOT_INITIALIZED = -3, //TIZEN_ERROR_SYSTEM_CLASS | 0x26, /**< Not initialized */
+ HAPTIC_ERROR_OPERATION_FAILED = -4, //TIZEN_ERROR_SYSTEM_CLASS | 0x28, /**< Operation failed */
+ HAPTIC_ERROR_NOT_SUPPORTED_DEVICE = -5, //TIZEN_ERROR_SYSTEM_CLASS | 0x30, /**< Not supported device */
+} haptic_error_e;
+
+/**
+ * @brief Gets the number of the vibrators.
+ *
+ * @remarks The index HAPTIC_DEVICE_ALL is reserved meaning for all vibrators at a time.
+ *
+ * @param[in] device_number A number of vibrators
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ */
+int haptic_get_count(int *device_number);
+
+/**
+ * @brief Opens a haptic-vibration device.
+ *
+ * @details Internally, it makes a connection to the vibrator.
+ *
+ * @remarks If this function is not called in advance, other functions will return #HAPTIC_ERROR_NOT_INITIALIZED.
+ * @remarks Haptic API must be closed by haptic_close().
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_close()
+ */
+int haptic_open(haptic_device_e device, haptic_device_h *device_handle);
+
+/**
+ * @brief Closes a haptic-vibration device.
+ *
+ * @details Internally, it disconnects the connection to vibrator.
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_open()
+ */
+int haptic_close(haptic_device_h device_handle);
+
+/**
+ * @brief Vibrates during the specified time with a constant intensity.
+ * @details
+ * This function can be used to start monotonous vibration for specified time.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.\n
+ * And default value of feedback and priority is used.\n
+ * feedback level is reserved for auto chaning to save variable in the settings.\n
+ * priority level uses HAPTIC_PRIORITY_MIN.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] duration The play duration in milliseconds
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_monotone_with_detail()
+ * @see haptic_vibrate_file()
+ * @see haptic_vibrate_buffer()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_monotone(haptic_device_h device_handle, int duration, haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates during the specified time with a constant intensity.
+ * @details
+ * This function can be used to start monotonous vibration for specified time.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] duration The play duration in milliseconds
+ * @param[in] feedback The amount of the intensity variation
+ * @param[in] priority The priority from HAPTIC_PRIORITY_MIN to HAPTIC_PRIORITY_HIGH
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file_with_detail()
+ * @see haptic_vibrate_buffer_with_detail()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_monotone_with_detail(haptic_device_h device_handle,
+ int duration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern file.
+ * @details
+ * This function can be used to play a haptic-vibration pattern file.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.\n
+ * And default value of feedback and priority is used.\n
+ * feedback level is reserved for auto chaning to save variable in the settings.\n
+ * priority level uses HAPTIC_PRIORITY_MIN.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] file_path Vibration pattern file with path
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_file_with_detail()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_buffer()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_file(haptic_device_h device_handle, const char *file_path, haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern file.
+ * @details
+ * This function can be used to play a haptic-vibration pattern file.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] file_path Vibration pattern file with path
+ * @param[in] iteration The number of times to repeat the effect
+ * @param[in] feedback The amount of the intensity variation
+ * @param[in] priority The priority from HAPTIC_PRIORITY_MIN to HAPTIC_PRIORITY_HIGH
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_file()
+ * @see haptic_vibrate_monotone_with_detail()
+ * @see haptic_vibrate_buffer_with_detail()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_file_with_detail(haptic_device_h device_handle,
+ const char *file_path,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern buffer.
+ * @details
+ * This function can be used to play a haptic-vibration pattern buffer.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.\n
+ * And default value of feedback and priority is used.\n
+ * feedback level is reserved for auto chaning to save variable in the settings.\n
+ * priority level uses HAPTIC_PRIORITY_MIN.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer_with_detail()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_buffer(haptic_device_h device_handle, const unsigned char *vibe_buffer, haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern buffer.
+ * @details
+ * This function can be used to play a haptic-vibration pattern buffer.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[in] iteration The number of times to repeat the effect
+ * @param[in] feedback The amount of the intensity variation
+ * @param[in] priority The priority from HAPTIC_PRIORITY_MIN to HAPTIC_PRIORITY_HIGH
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer()
+ * @see haptic_vibrate_monotone_with_detail()
+ * @see haptic_vibrate_file_with_detail()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_buffer_with_detail(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern buffer.
+ * @details
+ * This function can be used to play a haptic-vibration pattern buffer.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.\n
+ * And default value of feedback and priority is used.\n
+ * feedback level is reserved for auto chaning to save variable in the settings.\n
+ * priority level uses HAPTIC_PRIORITY_MIN.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[in] size Size to the vibration pattern
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer_with_detail()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_buffers(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ int size,
+ haptic_effect_h *effect_handle);
+
+/**
+ * @brief Vibrates a predefined rhythmic haptic-vibration pattern buffer.
+ * @details
+ * This function can be used to play a haptic-vibration pattern buffer.
+ *
+ * @remark
+ * If you don't use th api regarding effect_handle, you can pass in a NULL value to last parameter.
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[in] size Size to the vibration pattern
+ * @param[in] iteration The number of times to repeat the effect
+ * @param[in] feedback The amount of the intensity variation
+ * @param[in] priority The priority from HAPTIC_PRIORITY_MIN to HAPTIC_PRIORITY_HIGH
+ * @param[out] effect_handle Pointer to the variable that will receive a handle to the playing effect
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer()
+ * @see haptic_vibrate_monotone_with_detail()
+ * @see haptic_vibrate_file_with_detail()
+ * @see haptic_get_count()
+ */
+int haptic_vibrate_buffers_with_detail(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ int size,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle);
+
+/**
+ * @brief Stops the current vibration effect which is being played.
+ * @details This function can be used to stop each effect started by haptic_vibrate_xxx().
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] effect_handle The effect handle from haptic_vibrate_xxx()
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file()
+ * @see haptic_get_count()
+ * @see haptic_stop_all_effects()
+ */
+int haptic_stop_effect(haptic_device_h device_handle, haptic_effect_h effect_handle);
+
+/**
+ * @brief Stops all vibration effects which are being played.
+ * @details This function can be used to stop all effects started by haptic_vibrate_xxx().
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file()
+ * @see haptic_get_count()
+ * @see haptic_stop_effect()
+ */
+int haptic_stop_all_effects(haptic_device_h device_handle);
+
+/**
+ * @brief Gets the status of the effect.
+ * @details This function can be used to get the status of the effect wheter the effect are playing or not.
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] effect_handle The effect handle from haptic_vibrate_xxx()
+ * @param[out] state The pointer to variable that will receive the status of the effect.
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_vibrate_buffer()
+ * @see haptic_vibrate_monotone()
+ * @see haptic_vibrate_file()
+ * @see haptic_get_count()
+ * @see haptic_stop_effect()
+ * @see haptic_stop_all_effects()
+ */
+int haptic_get_effect_state(haptic_device_h device_handle, haptic_effect_h effect_handle, haptic_state_e *state);
+
+/**
+ * @par Description:
+ * effect element for haptic.
+ */
+typedef struct {
+ int haptic_duration; /**< Start time of the effect element in millisecond */
+ int haptic_level; /**< Duration of the effect element in millisecond */
+} haptic_effect_element_s;
+
+/**
+ * @brief Creates an effect buffer.
+ * @details This function can be used to create an effect buffer using effeclt_element variable.
+ *
+ * @remark
+ *
+ * @param[out] vibe_buffer Pointer to the vibration pattern
+ * @param[in] max_bufsize The size of the buffer pointed to by vibe_buffer
+ * @param[in] elem_arr Pointer to an haptic_effect_element_s structure
+ * @param[in] max_elemcnt The size fo the buffer pointed to by elem_arr
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_save_effect()
+ */
+int haptic_create_effect(unsigned char *vibe_buffer,
+ int max_bufsize,
+ haptic_effect_element_s *elem_arr,
+ int max_elemcnt);
+
+/**
+ * @brief Save an effect buffer to the file.
+ * @details This function can be used to save an effect buffer to the file using third parameter.
+ *
+ * @remark
+ *
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[in] max_bufsize The size of the buffer pointed to by vibe_buffer
+ * @param[in] file_path The pointer to the character buffer containing the path to save
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_FILE_EXISTS File exists
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_create_effect()
+ */
+int haptic_save_effect(const unsigned char *vibe_buffer,
+ int max_bufsize,
+ const char *file_path);
+
+/**
+ * @brief Gets a duration time value from file.
+ * @details This function can be used to get a duration time value from the file using second parameter.
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] file_path The pointer to the character buffer containing the path to save
+ * @param[out] duration The pointer to the duration time value
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_get_buffer_duration()
+ */
+int haptic_get_file_duration(haptic_device_h device_handle, const char *file_path, int *duration);
+
+/**
+ * @brief Gets a duration time value from buffer.
+ * @details This function can be used to get a duration time value from the buffer using second parameter.
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern buffer
+ * @param[out] duration The pointer to the duration time value
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_get_file_duration()
+ */
+int haptic_get_buffer_duration(haptic_device_h device_handle, const unsigned char *vibe_buffer, int *duration);
+
+/**
+ * @brief Gets a duration time value from buffer.
+ * @details This function can be used to get a duration time value from the buffer using second parameter.
+ *
+ * @remark
+ *
+ * @param[in] device_handle The device handle from haptic_open()
+ * @param[in] vibe_buffer Pointer to the vibration pattern buffer
+ * @param[in] size Size to the vibration pattern buffer
+ * @param[out] buffer_duration The pointer to the duration time value
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_get_file_duration()
+ */
+int haptic_get_buffers_duration(haptic_device_h device_handle, const unsigned char *vibe_buffer, int size, int *buffer_duration);
+
+/**
+ * @brief Save an effect buffer to the led file.
+ * @details This function can be used to save an effect buffer to the led file which name is third parameter.
+ *
+ * @remark
+ * Third parameter should be compatible with ledplayer file.
+ *
+ * @param[in] vibe_buffer Pointer to the vibration pattern
+ * @param[in] max_bufsize The size of the buffer pointed to by vibe_buffer
+ * @param[in] file_path The pointer to the character buffer containing the path to save
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #HAPTIC_ERROR_NONE Successful
+ * @retval #HAPTIC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #HAPTIC_ERROR_NOT_INITIALIZED Not initialized
+ * @retval #HAPTIC_ERROR_FILE_EXISTS File exists
+ * @retval #HAPTIC_ERROR_OPERATION_FAILED Operation failed
+ * @retval #HAPTIC_ERROR_NOT_SUPPORTED_DEVICE Not supported device
+ *
+ * @see haptic_save_effect()
+ */
+int haptic_save_led(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path);
+
+/**
+ * @} end of CAPI_SYSTEM_DEVICED_HAPTIC_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_LED_H__
+#define __DD_LED_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+/**
+ * @file dd-led.h
+ * @defgroup CAPI_SYSTEM_DEVICED_LED_MODULE Led
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API for control of led
+ * @section CAPI_SYSTEM_DEVICED_LED_MODULE_HEADER Required Header
+ * \#include <dd-led.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_LED_MODULE
+ * @{
+ */
+
+#define led_set_brightness(val) \
+ led_set_brightness_with_noti(val, false)
+
+/**
+ * @par Description:
+ * This API is used to get the current brightness of the led.\n
+ * It gets the current brightness of the led by calling device_get_property() function.\n
+ * It returns integer value which is the current brightness on success.\n
+ * Or a negative value(-1) is returned on failure.
+ * @return current brightness value on success, -1 if failed
+ * @see led_set_brightness_with_noti()
+ * @par Example
+ * @code
+ * ...
+ * int cur_brt;
+ * cur_brt = led_get_brightness();
+ * if( cur_brt < 0 )
+ * printf("Fail to get the current brightness of the led.\n");
+ * else
+ * printf("Current brightness of the led is %d\n", cur_brt);
+ * ...
+ * @endcode
+ */
+int led_get_brightness(void);
+
+/**
+ * @par Description:
+ * This API is used to get the max brightness of the led.\n
+ * It gets the max brightness of the led by calling device_get_property() function.\n
+ * It returns integer value which is the max brightness on success.\n
+ * Or a negative value(-1) is returned on failure
+ * @return max brightness value on success, -1 if failed
+ * @par Example
+ * @code
+ * ...
+ * int max_brt;
+ * max_brt = led_get_max_brightness();
+ * if( max_brt < 0 )
+ * printf("Fail to get the max brightness of the led.\n");
+ * ...
+ * @endcode
+ */
+int led_get_max_brightness(void);
+
+/**
+ * @par Description:
+ * This API is used to set the current brightness of the led.\n
+ * It sets the current brightness of the led by calling device_set_property() function.\n
+ * @param[in] val brightness value that you want to set
+ * @param[in] enable noti
+ * @return 0 on success, -1 if failed
+ * @see led_get_brightness()
+ * @par Example
+ * @code
+ * ...
+ * if( led_set_brightness_with_noti(1, 1) < 0 )
+ * printf("Fail to set the brightness of the led\n");
+ * ...
+ * @endcode
+ */
+int led_set_brightness_with_noti(int val, bool enable);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_LED_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_MMC_H__
+#define __DD_MMC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file dd-mmc.h
+ * @defgroup CAPI_SYSTEM_DEVICED_MMC_MODULE MMC
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API for control of mmc(sd-card)
+ * @section CAPI_SYSTEM_DEVICED_MMC_MODULE_HEADER Required Header
+ * \#include <dd-mmc.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_MMC_MODULE
+ * @{
+ */
+
+/**
+ * @brief This structure defines the data for receive result of mmc operations(mount/unmount/format)
+ */
+struct mmc_contents {
+ void (*mmc_cb) (int result, void* data);/**< user callback function for receive result of mmc operations */
+ void* user_data;/**< input data for callback function's second-param(data) */
+};
+
+/**
+ * @fn int deviced_request_mount_mmc(struct mmc_contents *mmc_data)
+ * @brief This API is used to mount mmc.\n
+ * Internally, this API call predefined action API. That is send a notify message. \n
+ * and when mount operation is finished, cb of deviced_mmc_content struct is called with cb's param1(result). \n
+ * means of param1 - 0(mount success) and negative value if failed \n
+ * [mount fail value] \n
+ * -1 : operation not permmitted \n
+ * -2 : no such file or directory \n
+ * -6 : no such device or address \n
+ * -12 : out of memory \n
+ * -13 : A component of a path was not searchable \n
+ * -14 : bad address \n
+ * -15 : block device is requested \n
+ * -16 : device or resource busy \n
+ * -19 : filesystemtype not configured in the kernel \n
+ * -20 : target, or a prefix of source, is not a directory \n
+ * -22 : point does not exist \n
+ * -24 : table of dummy devices is full \n
+ * -36 : requested name is too long \n
+ * -40 : Too many links encountered during pathname resolution. \n
+ * Or, a move was attempted, while target is a descendant of source \n
+ * @param[in] mmc_data for receive result of mount operation
+ * @return non-zero on success message sending, -1 if message sending is failed.
+ */
+int deviced_request_mount_mmc(struct mmc_contents *mmc_data);
+
+/**
+ * @fn int deviced_request_unmount_mmc(struct mmc_contents *mmc_data,int option)
+ * @brief This API is used to unmount mmc.\n
+ * Internally, this API call predefined action API. That is send a notify message. \n
+ * and when unmount opeation is finished, cb of deviced_mmc_content struct is called with cb's param1(result). \n
+ * means of param1 - 0(unmount success) and negative value if failed \n
+ * [unmount fail value] \n
+ * -1 : operation not permmitted \n
+ * -2 : no such file or directory \n
+ * -11 : try again \n
+ * -12 : out of memory \n
+ * -14 : bad address \n
+ * -16 : device or resource busy \n
+ * -22 : point does not exist \n
+ * -36 : requested name is too long \n
+ * @param[in] mmc_data for receive result of unmount operation
+ * @param[in] option type of unmount option \n
+ * 0 : Normal unmount \n
+ * (if other process still access a sdcard, \n
+ * unmount will be failed.) \n
+ * 1 : Force unmount \n
+ * (if other process still access a sdcard, \n
+ * this process will be received SIGTERM or SIGKILL.)
+ * @return non-zero on success message sending, -1 if message sending is failed.
+ */
+int deviced_request_unmount_mmc(struct mmc_contents *mmc_data, int option);
+
+/**
+ * @fn int deviced_request_format_mmc(struct mmc_contents *mmc_data)
+ * @brief This API is used to format mmc.\n
+ * Internally, this API call predefined action API. That is send a notify message. \n
+ * and when format opeation is finished, cb of deviced_mmc_content struct is called with cb's param1(result). \n
+ * means of param1 - 0(format success) , -1(format fail)
+ * @param[in] mmc_data for receive result of format operation
+ * @return non-zero on success message sending, -1 if message sending is failed.
+ */
+int deviced_request_format_mmc(struct mmc_contents *mmc_data);
+
+/**
+ * @fn int deviced_format_mmc(struct mmc_contents *mmc_data, int option)
+ * @brief This API is used to format mmc.\n
+ * Internally, this API call predefined action API. That is send a notify message. \n
+ * and when format opeation is finished, cb of deviced_mmc_content struct is called with cb's param1(result). \n
+ * means of param1 - 0(format success) and negative value if failed \n
+ * [format fail value] \n
+ * -22 : Invalid argument(EINVAL) \n
+ * @param[in] mmc_data for receive result of format operation
+ * @param[in] option FMT_NORMAL is 0, FMT_FORCE is 1
+ * @return non-zero on success message sending, -1 if message sending is failed.
+ */
+int deviced_format_mmc(struct mmc_contents *mmc_data, int option);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_MMC_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_STORAGE_H__
+#define __DD_STORAGE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file dd-storage.h
+ * @defgroup CAPI_SYSTEM_DEVICED_STORAGE_MODULE Storage
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @brief This file provides the API for control of storage
+ * @section CAPI_SYSTEM_DEVICED_STORAGE_MODULE_HEADER Required Header
+ * \#include <dd-storage.h>
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_STORAGE_MODULE
+ * @{
+ */
+
+/**
+ * @par Description
+ * Storage path type
+ */
+enum storage_path_type {
+ STORAGE_DEFAULT = 0,
+ STORAGE_INTERNAL,
+ STORAGE_EXTERNAL,
+ STORAGE_MAX,
+};
+
+/**
+ * @par Description:
+ * This API is used go get storage path.\n
+ * @param[in] type storage path type
+ * @param[in] path pointer to a buffer where the path is stored
+ * @param[in] size size of buffer
+ * @return 0 on success, -1 if failed
+ * @see storage_path_type
+ * @par Example
+ * @code
+ * ...
+ * if ( storage_get_path(STORAGE_INTERNAL, path, 50) < 0 )
+ * printf("Get storage path failed\n");
+ * ...
+ * @endcode
+ */
+int storage_get_path(int type, char *path, int size);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_STORAGE_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DD_USBHOST_H__
+#define __DD_USBHOST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file dd-usbhost.h
+ * @ingroup CAPI_SYSTEM_DEVICED
+ * @defgroup CAPI_SYSTEM_DEVICED_USBHOST_MODULE usbhost
+ * @brief This file provides the API for usb host operations
+ */
+
+/**
+ * @addtogroup CAPI_SYSTEM_DEVICED_USBHOST_MODULE
+ * @{
+ */
+
+#include <limits.h>
+struct usbhost_device {
+ char devpath[PATH_MAX]; /* unique info. */
+ int baseclass;
+ int subclass;
+ int protocol;
+ int vendorid;
+ int productid;
+ char *manufacturer;
+ char *product;
+ char *serial;
+};
+
+enum usbhost_state {
+ USB_HOST_REMOVED,
+ USB_HOST_ADDED,
+};
+
+/**
+ * @par Description:
+ * This API is used to initialize usbhost signal \n
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ * ...
+ * @endcode
+ */
+int init_usbhost_signal(void);
+
+/**
+ * @par Description:
+ * This API is used to deinitialize usbhost signal \n
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * // Do something
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+void deinit_usbhost_signal(void);
+
+/**
+ * @par Description:
+ * This API is used to register usbhost signal \n
+ * @param[in] storage_changed callback function which is called when the usbhost signal is delivered
+ * @param[in] data parameter of storage_changed callback function
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * // Do something
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int register_usb_storage_change_handler(
+ void (*storage_changed)(char *type, char *path, int mount, void *),
+ void *data);
+
+/**
+ * @par Description:
+ * This API is used to register usbhost signal \n
+ * @param[in] device_changed callback function which is called when the device is connected/disconnected
+ * @param[in] data parameter of the callback function
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_device_change_handler(device_cb, data) < 0) {
+ * printf("Failed to register device handler\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * // Do something
+ *
+ * if (unregister_usb_device_changed_handler() < 0)
+ * printf("Failed to unregister device changed signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int register_usb_device_change_handler(
+ void (*device_changed)(struct usbhost_device *device, int state, void *data),
+ void *data);
+
+/**
+ * @par Description:
+ * This API is used to unregister usbhost signal \n
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * // Do something
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int unregister_usb_storage_change_handler(void);
+
+/**
+ * @par Description:
+ * This API is used to unregister usb connect/disconnect signal handler\n
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_device_change_handler(device_cb, data) < 0) {
+ * printf("Failed to register device signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * // Do something
+ *
+ * if (unregister_usb_device_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int unregister_usb_device_change_handler(
+ void (*device_changed)(struct usbhost_device *device, int state, void *data));
+
+/**
+ * @par Description:
+ * This API is used to request usb storage information \n
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * if (request_usb_storage_info() < 0)
+ * printf("Failed to request all of storage information");
+ *
+ * // Do someting
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int request_usb_storage_info(void);
+
+/**
+ * @par Description:
+ * This API is used to mount usb storage \n
+ * @param[in] path path to unmount
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * if (mount_usb_storage("/opt/storage/usb/UsbDriveA1") < 0)
+ * printf("Failed to mount usb storage");
+ *
+ * // Do something.. Mounting takes some time
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int mount_usb_storage(char *path);
+
+/**
+ * @par Description:
+ * This API is used to unmount usb storage \n
+ * @param[in] path path to mount
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * if (ummount_usb_storage("/opt/storage/usb/UsbDriveA1") < 0)
+ * printf("Failed to unmount usb storage");
+ *
+ * // Do something.. Unmounting takes some time
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int unmount_usb_storage(char *path);
+
+/**
+ * @par Description:
+ * This API is used to format usb storage \n
+ * @param[in] path path to format
+ * @return 0 on success, negative if failed
+ * @par Example
+ * @code
+ * ...
+ * if (init_usbhost_signal() < 0)
+ * printf("Failed to initialize usbhost signal\n");
+ *
+ * if (register_usb_storage_change_handler(storage_cb, data) < 0) {
+ * printf("Failed to register storage signal\n");
+ * deinit_usbhost_signal();
+ * return;
+ * }
+ *
+ * if (format_usb_storage("/opt/storage/usb/UsbDriveA1") < 0)
+ * printf("Failed to unmount usb storage");
+ *
+ * // Do something.. Formatting takes some time
+ *
+ * if (unregister_usb_storage_change_handler() < 0)
+ * printf("Failed to unregister storage signal\n");
+ *
+ * deinit_usbhost_signal();
+ * ...
+ * @endcode
+ */
+int format_usb_storage(char *path);
+
+/**
+ * @par Description:
+ * This API is used to open usb device \n
+ * @param[in] path path to device
+ * @return 0 on success, negative error code if failed
+ * @par Example
+ * @code
+ * ...
+ *
+ * r = open_usb_device(path, &fd);
+ * if (r < 0)
+ * printf("failed to open device");
+ *
+ * ...
+ * @endcode
+ */
+int open_usb_device(char *path, int *fd);
+
+/**
+ * @} // end of CAPI_SYSTEM_DEVICED_USBHOST_MODULE
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __TIZEN_SYSTEM_DEVICED_DOC_H__
+#define __TIZEN_SYSTEM_DEVICED_DOC_H__
+
+/**
+ * @defgroup CAPI_SYSTEM_DEVICED deviced
+ * @brief The deviced APIs provide functions to control devices.
+ * @ingroup CAPI_SYSTEM_FRAMEWORK
+ * @section CAPI_SYSTEM_DEVICED_HEADER Required Header
+ * \#include <dd-deviced-managed.h>
+ *
+ * @section CAPI_SYSTEM_SYSTEM_DEVICED_OVERVIEW Overview
+ * Provides access to a set of device like battery, display, haptic, LED, etc.
+ * The state of the device is changed or obtained by using APIs provided.
+ *
+ * - battery percentage, full charging state, etc.
+ * - brightness control, enhance mode setting, display lock/unlock, etc.
+ * - haptic play
+ * - service led control
+ * - other devices
+ *
+ */
+
+#endif /* __TIZEN_SYSTEM_DEVICED_DOC_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __HAPTIC_MODULE_H__
+#define __HAPTIC_MODULE_H__
+
+/**
+ * @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 priority level for the Haptic Module API.
+ */
+typedef enum
+{
+ HAPTIC_MODULE_PRIORITY_MIN = 0, /**< Minimum effect priority for developers (default) */
+ HAPTIC_MODULE_PRIORITY_MIDDLE, /**< Maximum effect priority for developers */
+ HAPTIC_MODULE_PRIORITY_HIGH, /**< Maximum effect priority for OEMs */
+} haptic_module_priority;
+
+/**
+ * @brief Enumerations of feedback level for the Haptic Module API.
+ * @details Haptic level means vibration power (intensity).
+ */
+typedef enum
+{
+ HAPTIC_MODULE_FEEDBACK_MIN = 0,
+ HAPTIC_MODULE_FEEDBACK_MAX = 100,
+} haptic_module_feedback;
+
+/**
+ * @brief Enumerations of unlimited duration for the Haptic Module API.
+ */
+typedef enum {
+ HAPTIC_MODULE_DURATION_UNLIMITED = 0x7FFFFFFF,
+} haptic_module_duration;
+
+/**
+ * @brief Enumerations of iteration count for the Haptic Module API.
+ */
+typedef enum
+{
+ HAPTIC_MODULE_ITERATION_ONCE = 1,
+ HAPTIC_MODULE_ITERATION_INFINITE = 256,
+} haptic_module_iteration;
+
+/**
+ * @brief Enumerations of effect or device state for the Haptic Module API.
+ */
+typedef enum
+{
+ HAPTIC_MODULE_STATE_STOP = 0,
+ HAPTIC_MODULE_STATE_PLAYING,
+} haptic_module_state;
+
+/* Error and Return value codes */
+#define HAPTIC_MODULE_ERROR_NONE 0
+#define HAPTIC_MODULE_NOT_INITIALIZED -1
+#define HAPTIC_MODULE_ALREADY_INITIALIZED -2
+#define HAPTIC_MODULE_INVALID_ARGUMENT -3
+#define HAPTIC_MODULE_OPERATION_FAILED -4
+#define HAPTIC_MODULE_NOT_SUPPORTED -5
+
+/**
+ * @par Description:
+ * effect element for haptic module.
+ */
+typedef struct {
+ int haptic_duration; /**< Start time of the effect element in millisecond */
+ int haptic_level; /**< Duration of the effect element in millisecond */
+} haptic_module_effect_element;
+
+#endif /* __HAPTIC_MODULE_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __HAPTIC_PLUGIN_INTF_H__
+#define __HAPTIC_PLUGIN_INTF_H__
+
+#include "haptic-module.h"
+
+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 (*vibrate_buffer) (int, const unsigned char*, int, int, int, int*);
+ int (*vibrate_effect) (int, const char*, int, int);
+ int (*is_supported) (const char*);
+ int (*stop_device) (int);
+ int (*get_device_state) (int, int*);
+ int (*create_effect) (unsigned char*, int, haptic_module_effect_element*, int);
+ int (*get_buffer_duration) (int, const unsigned char*, int*);
+ int (*convert_binary) (const unsigned char*, int, const char*);
+};
+
+const struct haptic_plugin_ops *get_haptic_plugin_interface();
+
+#endif /* __HAPTIC_PLUGIN_INTF_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdbool.h>
+#include <stdio.h>
+#include <math.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <vconf.h>
+#include <sensor.h>
+#include <Ecore.h>
+
+#include "util.h"
+#include "core.h"
+#include "display-ops.h"
+#include "device-node.h"
+#include "setting.h"
+#include "core/device-notifier.h"
+#include "core/config-parser.h"
+
+#define METHOD_CHECK_SUPPORTED "CheckSupported"
+
+#define DISP_FORCE_SHIFT 12
+#define DISP_FORCE_CMD(prop, force) (((force) << DISP_FORCE_SHIFT) | prop)
+
+#define SAMPLING_INTERVAL 1 /* 1 sec */
+#define MAX_SAMPLING_COUNT 3
+#define MAX_FAULT 5
+#define DEFAULT_AUTOMATIC_BRT 5
+#define AUTOMATIC_DEVIDE_VAL 10
+#define AUTOMATIC_DELAY_TIME 0.5 /* 0.5 sec */
+
+#define RADIAN_VALUE (57.2957)
+#define ROTATION_90 90
+#define WORKING_ANGLE_MIN 0
+#define WORKING_ANGLE_MAX 20
+
+#define BOARD_CONF_FILE "/etc/deviced/display.conf"
+
+#define ON_LUX -1
+#define OFF_LUX -1
+#define ON_COUNT 1
+#define OFF_COUNT 1
+
+static int (*_default_action) (int);
+static Ecore_Timer *alc_timeout_id = 0;
+static Ecore_Timer *update_timeout;
+static sensor_listener_h light_listener;
+static sensor_listener_h accel_listener;
+static int fault_count;
+static int automatic_brt = DEFAULT_AUTOMATIC_BRT;
+static int min_brightness = PM_MIN_BRIGHTNESS;
+static char *min_brightness_name = 0;
+
+/* light sensor */
+static float lmax, lmin;
+
+static bool update_working_position(void)
+{
+ sensor_event_s data;
+ int ret;
+ float x, y, z, pitch, realg;
+
+ if (!display_conf.accel_sensor_on)
+ return false;
+
+ ret = sensor_listener_read_data(accel_listener, &data);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Fail to get accelerometer data! %d", ret);
+ return true;
+ }
+
+ x = data.values[0];
+ y = data.values[1];
+ z = data.values[2];
+
+ realg = (float)sqrt((x * x) + (y * y) + (z * z));
+ pitch = ROTATION_90 - abs((int) (asin(z / realg) * RADIAN_VALUE));
+
+ _D("accel data [%f, %f, %f] - %f", x, y, z, pitch);
+
+ if (pitch >= WORKING_ANGLE_MIN && pitch <= WORKING_ANGLE_MAX)
+ return true;
+ return false;
+}
+
+static void alc_set_brightness(int setting, int value, float light)
+{
+ static float old;
+ int position, tmp_value = 0, ret;
+
+ ret = backlight_ops.get_brightness(&tmp_value);
+ if (ret < 0) {
+ _E("Fail to get display brightness!");
+ return;
+ }
+
+ if (value < min_brightness)
+ value = min_brightness;
+
+ if (tmp_value != value) {
+ if (!setting && min_brightness == PM_MIN_BRIGHTNESS &&
+ display_conf.accel_sensor_on == true) {
+ position = update_working_position();
+ if (!position && (old > light)) {
+ _D("It's not working position, "
+ "LCD isn't getting dark!");
+ return;
+ }
+ }
+ int diff, step;
+
+ diff = value - tmp_value;
+ if (abs(diff) < display_conf.brightness_change_step)
+ step = (diff > 0 ? 1 : -1);
+ else
+ step = (int)ceil(diff /
+ (float)display_conf.brightness_change_step);
+
+ _D("%d", step);
+ while (tmp_value != value) {
+ if (step == 0) break;
+
+ tmp_value += step;
+ if ((step > 0 && tmp_value > value) ||
+ (step < 0 && tmp_value < value))
+ tmp_value = value;
+
+ backlight_ops.set_default_brt(tmp_value);
+ backlight_ops.update();
+ }
+ _I("load light data:%f ,auto brt %d,min brightness %d,"
+ "brightness %d", light, automatic_brt, min_brightness, value);
+ old = light;
+ }
+}
+
+static bool check_brightness_changed(int value)
+{
+ int i;
+ static int values[MAX_SAMPLING_COUNT], count = 0;
+
+ if (count >= MAX_SAMPLING_COUNT || count < 0)
+ count = 0;
+
+ values[count++] = value;
+
+ for (i = 0; i < MAX_SAMPLING_COUNT - 1; i++)
+ if (values[i] != values[i+1])
+ return false;
+ return true;
+}
+
+static bool alc_update_brt(bool setting)
+{
+ int value = 0;
+ int ret = -1;
+ sensor_event_s light_data;
+ int index;
+ float light;
+
+ ret = sensor_listener_read_data(light_listener, &light_data);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to read light sensor data(%d)",ret);
+ goto out;
+ }
+
+ index = light_data.value_count - 1;
+ if (index < 0 || light_data.values[index] < 0) {
+ _E("Invalid light sensor data");
+ goto out;
+ }
+
+ light = light_data.values[index];
+ ret = backlight_ops.get_brightness_by_light_sensor(
+ lmax, lmin, light, &value);
+ if (ret == -ENOTSUP) {
+ _E("Not supported to handle the light data");
+ goto out;
+ }
+
+ if (ret < 0 || value < PM_MIN_BRIGHTNESS || value > PM_MAX_BRIGHTNESS) {
+ _E("fail to load light data : light(%f), value(%d), ret(%d)", light, value, ret);
+ goto out;
+ }
+
+ fault_count = 0;
+
+ if (display_conf.continuous_sampling &&
+ !check_brightness_changed(value) &&
+ !setting)
+ return true;
+
+ alc_set_brightness(setting, value, light);
+
+ return true;
+
+out:
+ fault_count++;
+
+ if ((fault_count > MAX_FAULT) && !(pm_status_flag & PWROFF_FLAG)) {
+ if (alc_timeout_id) {
+ ecore_timer_del(alc_timeout_id);
+ alc_timeout_id = NULL;
+ }
+ vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
+ SETTING_BRIGHTNESS_AUTOMATIC_OFF);
+ _E("Fault counts is over %d, disable automatic brightness", MAX_FAULT);
+ return false;
+ }
+ return true;
+}
+
+static bool alc_handler(void *data)
+{
+ if (pm_cur_state != S_NORMAL) {
+ if (alc_timeout_id > 0)
+ ecore_timer_del(alc_timeout_id);
+ alc_timeout_id = NULL;
+ return EINA_FALSE;
+ }
+
+ if (!alc_update_brt(false))
+ return EINA_FALSE;
+
+ if (alc_timeout_id != 0)
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
+static int alc_action(int timeout)
+{
+ /* sampling timer add */
+ if (alc_timeout_id == 0 && !(pm_status_flag & PWRSV_FLAG)) {
+ display_info.update_auto_brightness(true);
+
+ alc_timeout_id =
+ ecore_timer_add(display_conf.lightsensor_interval,
+ (Ecore_Task_Cb)alc_handler, NULL);
+ }
+
+ if (_default_action != NULL)
+ return _default_action(timeout);
+
+ /* unreachable code */
+ return -1;
+}
+
+static int connect_sensor(void)
+{
+ int ret;
+ sensor_h sensor;
+ sensor_h *list;
+ int cnt;
+
+ _I("connect with sensor fw");
+ /* light sensor */
+ ret = sensor_get_sensor_list(SENSOR_LIGHT, &list, &cnt);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to get light sensor list(%d)", ret);
+ goto error;
+ }
+
+ /* TODO
+ * Sensor apis will be fixed
+ * to provide which sensor is effective among sensors */
+ if (cnt == 3) /* three light sensors exist */
+ sensor = list[2];
+ else
+ sensor = list[0];
+
+ free(list);
+
+ ret = sensor_get_min_range(sensor, &lmin);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to get light sensor min range (%d)", ret);
+ goto error;
+ }
+ ret = sensor_get_max_range(sensor, &lmax);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to get light sensor max range (%d)", ret);
+ goto error;
+ }
+ _I("Light sensor min(%f), max(%f)", lmin, lmax);
+
+ ret = sensor_create_listener(sensor, &light_listener);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to create listener(light)!");
+ goto error;
+ }
+ sensor_listener_set_option(light_listener, SENSOR_OPTION_ALWAYS_ON);
+ ret = sensor_listener_start(light_listener);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to start light sensor!");
+ sensor_destroy_listener(light_listener);
+ light_listener = 0;
+ goto error;
+ }
+
+ if (!display_conf.accel_sensor_on)
+ goto success;
+
+ /* accelerometer sensor */
+ ret = sensor_get_default_sensor(SENSOR_ACCELEROMETER, &sensor);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to get default accel sensor!");
+ goto error;
+ }
+ ret = sensor_create_listener(&sensor, &accel_listener);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to create listener(accel)!");
+ goto error;
+ }
+ sensor_listener_set_option(accel_listener, SENSOR_OPTION_ALWAYS_ON);
+ ret = sensor_listener_start(accel_listener);
+ if (ret != SENSOR_ERROR_NONE) {
+ _E("Failed to start accel sensor!");
+ sensor_destroy_listener(accel_listener);
+ accel_listener = 0;
+ goto error;
+ }
+
+success:
+ fault_count = 0;
+ return 0;
+
+error:
+ if (light_listener > 0) {
+ sensor_listener_stop(light_listener);
+ sensor_destroy_listener(light_listener);
+ light_listener = 0;
+ }
+ if (display_conf.accel_sensor_on && accel_listener > 0) {
+ sensor_listener_stop(accel_listener);
+ sensor_destroy_listener(accel_listener);
+ accel_listener = 0;
+ }
+ return -EIO;
+}
+
+static int disconnect_sensor(void)
+{
+ _I("disconnect with sensor fw");
+ /* light sensor*/
+ if (light_listener > 0) {
+ sensor_listener_stop(light_listener);
+ sensor_destroy_listener(light_listener);
+ light_listener = 0;
+ }
+
+ /* accelerometer sensor*/
+ if (display_conf.accel_sensor_on && accel_listener > 0) {
+ sensor_listener_stop(accel_listener);
+ sensor_destroy_listener(accel_listener);
+ accel_listener = 0;
+ }
+
+ if (_default_action != NULL) {
+ states[S_NORMAL].action = _default_action;
+ _default_action = NULL;
+ }
+ if (alc_timeout_id > 0) {
+ ecore_timer_del(alc_timeout_id);
+ alc_timeout_id = NULL;
+ }
+
+ return 0;
+}
+
+void set_brightness_changed_state(void)
+{
+ if (pm_status_flag & PWRSV_FLAG) {
+ pm_status_flag |= BRTCH_FLAG;
+ _D("brightness changed in low battery,"
+ "escape dim state (light)");
+ }
+}
+
+static int set_autobrightness_state(int status)
+{
+ int ret = -1;
+ int brt = -1;
+ int default_brt = -1;
+
+ if (status == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
+ if (connect_sensor() < 0)
+ return -1;
+
+ /* escape dim state if it's in low battery.*/
+ set_brightness_changed_state();
+
+ /* change alc action func */
+ if (_default_action == NULL)
+ _default_action = states[S_NORMAL].action;
+ states[S_NORMAL].action = alc_action;
+
+ display_info.update_auto_brightness(true);
+
+ alc_timeout_id =
+ ecore_timer_add(display_conf.lightsensor_interval,
+ (Ecore_Task_Cb)alc_handler, NULL);
+ } else if (status == SETTING_BRIGHTNESS_AUTOMATIC_PAUSE) {
+ _I("auto brightness paused!");
+ disconnect_sensor();
+ } else {
+ disconnect_sensor();
+ /* escape dim state if it's in low battery.*/
+ set_brightness_changed_state();
+
+ ret = get_setting_brightness(&default_brt);
+ if (ret != 0 || (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)) {
+ _I("fail to read vconf value for brightness");
+ brt = PM_DEFAULT_BRIGHTNESS;
+ if (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)
+ vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
+ default_brt = brt;
+ }
+
+ backlight_ops.set_default_brt(default_brt);
+ backlight_ops.update();
+ }
+
+ return 0;
+}
+
+static void set_alc_function(keynode_t *key_nodes, void *data)
+{
+ int status, ret;
+
+ if (key_nodes == NULL) {
+ _E("wrong parameter, key_nodes is null");
+ return;
+ }
+
+ status = vconf_keynode_get_int(key_nodes);
+
+ switch (status) {
+ case SETTING_BRIGHTNESS_AUTOMATIC_OFF:
+ case SETTING_BRIGHTNESS_AUTOMATIC_ON:
+ case SETTING_BRIGHTNESS_AUTOMATIC_PAUSE:
+ ret = set_autobrightness_state(status);
+ _D("set auto brightness : %d", ret);
+ break;
+ default:
+ _E("invalid value! %d", status);
+ }
+}
+
+static void set_alc_automatic_brt(keynode_t *key_nodes, void *data)
+{
+ if (key_nodes == NULL) {
+ _E("wrong parameter, key_nodes is null");
+ return;
+ }
+ automatic_brt = vconf_keynode_get_int(key_nodes) / AUTOMATIC_DEVIDE_VAL;
+ _D("automatic brt : %d", automatic_brt);
+
+ alc_update_brt(true);
+}
+
+static Eina_Bool update_handler(void *data)
+{
+ int ret, on;
+
+ update_timeout = NULL;
+
+ if (pm_cur_state != S_NORMAL)
+ return EINA_FALSE;
+
+ ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &on);
+ if (ret < 0 || on != SETTING_BRIGHTNESS_AUTOMATIC_ON)
+ return EINA_FALSE;
+
+ _D("auto brightness is working!");
+ alc_update_brt(true);
+
+ return EINA_FALSE;
+}
+
+static void update_auto_brightness(bool update)
+{
+ if (update_timeout) {
+ ecore_timer_del(update_timeout);
+ update_timeout = NULL;
+ }
+
+ if (update) {
+ update_timeout = ecore_timer_add(AUTOMATIC_DELAY_TIME,
+ update_handler, NULL);
+ }
+}
+
+static int prepare_lsensor(void *data)
+{
+ int status, ret;
+ int brt = -1;
+
+ ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
+
+ if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
+ set_autobrightness_state(status);
+
+ /* add auto_brt_setting change handler */
+ vconf_notify_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
+ set_alc_function, NULL);
+
+ vconf_get_int(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS, &brt);
+ if (brt < PM_MIN_BRIGHTNESS || brt > PM_MAX_BRIGHTNESS) {
+ _E("Failed to get automatic brightness!");
+ } else {
+ automatic_brt = brt / AUTOMATIC_DEVIDE_VAL;
+ _I("automatic brt init success %d", automatic_brt);
+ }
+
+ vconf_notify_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
+ set_alc_automatic_brt, NULL);
+
+ return 0;
+}
+
+static void update_brightness_direct(void)
+{
+ int ret, status;
+
+ ret = vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &status);
+ if (ret == 0 && status == SETTING_BRIGHTNESS_AUTOMATIC_ON)
+ alc_update_brt(true);
+}
+
+static int set_autobrightness_min(int val, char *name)
+{
+ if (!name)
+ return -EINVAL;
+
+ if (val < PM_MIN_BRIGHTNESS || val > PM_MAX_BRIGHTNESS)
+ return -EINVAL;
+
+ min_brightness = val;
+
+ if (min_brightness_name) {
+ free(min_brightness_name);
+ min_brightness_name = 0;
+ }
+ min_brightness_name = strndup(name, strlen(name));
+
+ update_brightness_direct();
+
+ _I("auto brightness min value changed! (%d, %s)",
+ min_brightness, min_brightness_name);
+
+ return 0;
+}
+
+static void reset_autobrightness_min(const char *sender, void *data)
+{
+ if (!sender)
+ return;
+
+ if (!min_brightness_name)
+ return;
+
+ if (strcmp(sender, min_brightness_name))
+ return;
+
+ _I("change to default %d -> %d, %s", min_brightness,
+ PM_MIN_BRIGHTNESS, min_brightness_name);
+ min_brightness = PM_MIN_BRIGHTNESS;
+ if (min_brightness_name) {
+ free(min_brightness_name);
+ min_brightness_name = 0;
+ }
+
+ update_brightness_direct();
+}
+
+static int lcd_changed_cb(void *data)
+{
+ int lcd_state;
+
+ if (!data)
+ return 0;
+ lcd_state = *(int *)data;
+ if (lcd_state == S_LCDOFF && alc_timeout_id > 0) {
+ ecore_timer_del(alc_timeout_id);
+ alc_timeout_id = NULL;
+ }
+
+ return 0;
+}
+
+static int booting_done_cb(void *data)
+{
+ int state;
+
+ if (!data)
+ return 0;
+
+ state = *(int *)data;
+ if (state != true)
+ return 0;
+
+ /* get light data from sensor fw */
+ prepare_lsensor(NULL);
+
+ return 0;
+}
+
+static void exit_lsensor(void)
+{
+ vconf_ignore_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT,
+ set_alc_function);
+
+ vconf_ignore_key_changed(VCONFKEY_SETAPPL_LCD_AUTOMATIC_BRIGHTNESS,
+ set_alc_automatic_brt);
+
+ set_autobrightness_state(SETTING_BRIGHTNESS_AUTOMATIC_OFF);
+}
+
+static void auto_brightness_init(void *data)
+{
+ display_info.update_auto_brightness = update_auto_brightness;
+ display_info.set_autobrightness_min = set_autobrightness_min;
+ display_info.reset_autobrightness_min = reset_autobrightness_min;
+
+ register_notifier(DEVICE_NOTIFIER_LCD, lcd_changed_cb);
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done_cb);
+}
+
+static void auto_brightness_exit(void *data)
+{
+ exit_lsensor();
+
+ unregister_notifier(DEVICE_NOTIFIER_LCD, lcd_changed_cb);
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done_cb);
+}
+
+static const struct display_ops display_autobrightness_ops = {
+ .name = "auto-brightness",
+ .init = auto_brightness_init,
+ .exit = auto_brightness_exit,
+};
+
+DISPLAY_OPS_REGISTER(&display_autobrightness_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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.
+ */
+
+
+/**
+ * @file core.c
+ * @brief Power manager main loop.
+ *
+ * This file includes Main loop, the FSM, signal processing.
+ */
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <vconf-keys.h>
+#include <Ecore.h>
+
+#include "util.h"
+#include "core.h"
+#include "device-node.h"
+#include "lock-detector.h"
+#include "display-ops.h"
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "core/udev.h"
+#include "core/list.h"
+#include "core/common.h"
+#include "core/edbus-handler.h"
+#include "core/config-parser.h"
+#include "core/launch.h"
+#include "extcon/extcon.h"
+#include "power/power-handler.h"
+#include "dd-display.h"
+
+#define PM_STATE_LOG_FILE "/var/log/pm_state.log"
+#define DISPLAY_CONF_FILE "/etc/deviced/display.conf"
+
+/**
+ * @addtogroup POWER_MANAGER
+ * @{
+ */
+
+#define SET_BRIGHTNESS_IN_BOOTLOADER "/usr/bin/save_blenv SLP_LCD_BRIGHT"
+#define LOCK_SCREEN_INPUT_TIMEOUT 10000
+#define LOCK_SCREEN_CONTROL_TIMEOUT 5000
+#define DD_LCDOFF_INPUT_TIMEOUT 3000
+#define ALWAYS_ON_TIMEOUT 3600000
+
+#define GESTURE_STR "gesture"
+#define POWER_KEY_STR "powerkey"
+#define TOUCH_STR "touch"
+#define EVENT_STR "event"
+#define TIMEOUT_STR "timeout"
+#define UNKNOWN_STR "unknown"
+
+unsigned int pm_status_flag;
+static int trans_condition;
+
+static void (*power_saving_func) (int onoff);
+static enum device_ops_status status = DEVICE_OPS_STATUS_UNINIT;
+
+int pm_cur_state;
+int pm_old_state;
+Ecore_Timer *timeout_src_id;
+int system_wakeup_flag = false;
+static unsigned int custom_normal_timeout = 0;
+static unsigned int custom_dim_timeout = 0;
+static int custom_holdkey_block = false;
+static int custom_change_pid = -1;
+static char *custom_change_name;
+static bool hallic_open = true;
+static Ecore_Timer *lock_timeout_id;
+static int lock_screen_timeout = LOCK_SCREEN_INPUT_TIMEOUT;
+static struct timeval lcdon_tv;
+static int lcd_paneloff_mode = false;
+static int stay_touchscreen_off = false;
+static dd_list *lcdon_ops;
+static bool lcdon_broadcast = false;
+
+static bool touch_blocked = false;
+
+/* default transition, action fuctions */
+static int default_trans(int evt);
+static int default_action(int timeout);
+static int default_check(int curr, int next);
+
+static Eina_Bool del_normal_cond(void *data);
+static Eina_Bool del_dim_cond(void *data);
+static Eina_Bool del_off_cond(void *data);
+
+static int default_proc_change_state(unsigned int cond, pid_t pid);
+static int (*proc_change_state)(unsigned int cond, pid_t pid) = default_proc_change_state;
+
+struct state states[S_END] = {
+ { S_START, "S_START", NULL, NULL, NULL, NULL },
+ { S_NORMAL, "S_NORMAL", default_trans, default_action, default_check, del_normal_cond },
+ { S_LCDDIM, "S_LCDDIM", default_trans, default_action, default_check, del_dim_cond },
+ { S_LCDOFF, "S_LCDOFF", default_trans, default_action, default_check, del_off_cond },
+ { S_STANDBY, "S_STANDBY", NULL, NULL, NULL, NULL },
+ { S_SLEEP, "S_SLEEP", default_trans, default_action, default_check, NULL },
+ { S_POWEROFF, "S_POWEROFF", NULL, NULL, NULL, NULL },
+};
+
+static int trans_table[S_END][EVENT_END] = {
+ /* Timeout, Input */
+ { S_START, S_START }, /* S_START */
+ { S_LCDDIM, S_NORMAL }, /* S_NORMAL */
+ { S_LCDOFF, S_NORMAL }, /* S_LCDDIM */
+ { S_SLEEP, S_NORMAL }, /* S_LCDOFF */
+ { S_SLEEP, S_STANDBY }, /* S_STANDBY */
+ { S_LCDOFF, S_NORMAL }, /* S_SLEEP */
+ { S_POWEROFF, S_POWEROFF }, /* S_POWEROFF */
+};
+
+enum signal_type {
+ SIGNAL_INVALID = 0,
+ SIGNAL_PRE,
+ SIGNAL_POST,
+ SIGNAL_MAX,
+};
+
+static const char *lcdon_sig_lookup[SIGNAL_MAX] = {
+ [SIGNAL_PRE] = "LCDOn",
+ [SIGNAL_POST] = "LCDOnCompleted",
+};
+static const char *lcdoff_sig_lookup[SIGNAL_MAX] = {
+ [SIGNAL_PRE] = "LCDOff",
+ [SIGNAL_POST] = "LCDOffCompleted",
+};
+
+#define SHIFT_UNLOCK 4
+#define SHIFT_CHANGE_STATE 7
+#define CHANGE_STATE_BIT 0xF00 /* 1111 0000 0000 */
+#define SHIFT_LOCK_FLAG 16
+#define SHIFT_CHANGE_TIMEOUT 20
+#define CUSTOM_TIMEOUT_BIT 0x1
+#define CUSTOM_HOLDKEY_BIT 0x2
+#define HOLD_KEY_BLOCK_BIT 0x1
+#define TIMEOUT_NONE (-1)
+
+#define S_COVER_TIMEOUT 8000
+#define GET_HOLDKEY_BLOCK_STATE(x) ((x >> SHIFT_LOCK_FLAG) & HOLD_KEY_BLOCK_BIT)
+#define BOOTING_DONE_WATING_TIME 60000 /* 1 minute */
+#define LOCK_TIME_WARNING 60 /* 60 seconds */
+
+#define ACTIVE_ACT "active"
+#define INACTIVE_ACT "inactive"
+
+#define LOCK_SCREEN_WATING_TIME 0.3 /* 0.3 second */
+#define LONG_PRESS_INTERVAL 2 /* 2 seconds */
+#define SAMPLING_INTERVAL 1 /* 1 sec */
+#define BRIGHTNESS_CHANGE_STEP 10
+#define LCD_ALWAYS_ON 0
+#define ACCEL_SENSOR_ON 1
+#define CONTINUOUS_SAMPLING 1
+#define LCDOFF_TIMEOUT 500 /* milli second */
+
+#define DIFF_TIMEVAL_MS(a, b) \
+ (((a.tv_sec * 1000000 + a.tv_usec) - \
+ (b.tv_sec * 1000000 + b.tv_usec)) \
+ / 1000)
+
+struct display_config display_conf = {
+ .lock_wait_time = LOCK_SCREEN_WATING_TIME,
+ .longpress_interval = LONG_PRESS_INTERVAL,
+ .lightsensor_interval = SAMPLING_INTERVAL,
+ .lcdoff_timeout = LCDOFF_TIMEOUT,
+ .brightness_change_step = BRIGHTNESS_CHANGE_STEP,
+ .lcd_always_on = LCD_ALWAYS_ON,
+ .framerate_app = {0, 0, 0, 0},
+ .control_display = 0,
+ .powerkey_doublepress = 0,
+ .accel_sensor_on = ACCEL_SENSOR_ON,
+ .continuous_sampling = CONTINUOUS_SAMPLING,
+ .timeout_enable = true,
+ .input_support = true,
+};
+
+struct display_function_info display_info = {
+ .update_auto_brightness = NULL,
+ .set_autobrightness_min = NULL,
+ .reset_autobrightness_min = NULL,
+ .face_detection = NULL,
+};
+
+typedef struct _pm_lock_node {
+ pid_t pid;
+ Ecore_Timer *timeout_id;
+ time_t time;
+ bool holdkey_block;
+ struct _pm_lock_node *next;
+ bool background;
+} PmLockNode;
+
+static PmLockNode *cond_head[S_END];
+
+static void set_process_active(bool flag, pid_t pid)
+{
+ char str[6];
+ char *arr[2];
+ int ret;
+
+ if (pid >= INTERNAL_LOCK_BASE)
+ return;
+
+ snprintf(str, sizeof(str), "%d", (int)pid);
+
+ arr[0] = (flag ? ACTIVE_ACT : INACTIVE_ACT);
+ arr[1] = str;
+
+ /* Send dbug to resourced */
+ ret = broadcast_edbus_signal(RESOURCED_PATH_PROCESS,
+ RESOURCED_INTERFACE_PROCESS, RESOURCED_METHOD_ACTIVE, "si", arr);
+ if (ret < 0)
+ _E("Fail to send dbus signal to resourced!!");
+}
+
+bool check_lock_state(int state)
+{
+ PmLockNode *t = cond_head[state];
+
+ while (t) {
+ if (t->background == false)
+ return true;
+ t = t->next;
+ }
+
+ return false;
+}
+
+void change_state_action(enum state_t state, int (*func)(int timeout))
+{
+ _I("[%s] action is changed", states[state].name);
+ states[state].action = func;
+}
+
+void change_state_trans(enum state_t state, int (*func)(int evt))
+{
+ _I("[%s] trans is changed", states[state].name);
+ states[state].trans = func;
+}
+
+void change_state_check(enum state_t state, int (*func)(int curr, int next))
+{
+ _I("[%s] check is changed", states[state].name);
+ states[state].check = func;
+}
+
+void change_state_name(enum state_t state, char *name)
+{
+ _I("[%s] name is changed", states[state].name);
+ states[state].name = name;
+}
+
+void change_trans_table(enum state_t state, enum state_t next)
+{
+ _I("[%s] timeout trans table is changed", states[state].name);
+ trans_table[state][EVENT_TIMEOUT] = next;
+}
+
+void change_proc_change_state(int (*func)(unsigned int cond, pid_t pid))
+{
+ _I("proc change state is changed");
+ proc_change_state = func;
+}
+
+static void broadcast_lcd_on(enum signal_type type, enum device_flags flags)
+{
+ char *arr[1];
+ const char *signal;
+
+ if (type <= SIGNAL_INVALID || type >= SIGNAL_MAX) {
+ _E("invalid signal type %d", type);
+ return;
+ }
+
+ if (flags & LCD_ON_BY_GESTURE)
+ arr[0] = GESTURE_STR;
+ else if (flags & LCD_ON_BY_POWER_KEY)
+ arr[0] = POWER_KEY_STR;
+ else if (flags & LCD_ON_BY_EVENT)
+ arr[0] = EVENT_STR;
+ else if (flags & LCD_ON_BY_TOUCH)
+ arr[0] = TOUCH_STR;
+ else
+ arr[0] = UNKNOWN_STR;
+
+ signal = lcdon_sig_lookup[type];
+ _I("lcdstep : broadcast %s %s", signal, arr[0]);
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ signal, "s", arr);
+}
+
+static void broadcast_lcd_off(enum signal_type type, enum device_flags flags)
+{
+ char *arr[1];
+ const char *signal;
+
+ if (type <= SIGNAL_INVALID || type >= SIGNAL_MAX) {
+ _E("invalid signal type %d", type);
+ return;
+ }
+
+ signal = lcdoff_sig_lookup[type];
+
+ if (flags & LCD_OFF_BY_POWER_KEY)
+ arr[0] = POWER_KEY_STR;
+ else if (flags & LCD_OFF_BY_TIMEOUT)
+ arr[0] = TIMEOUT_STR;
+ else if (flags & LCD_OFF_BY_EVENT)
+ arr[0] = EVENT_STR;
+ else
+ arr[0] = UNKNOWN_STR;
+
+ _I("lcdstep : broadcast %s", signal);
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ signal, "s", arr);
+}
+
+static unsigned long get_lcd_on_flags(void)
+{
+ unsigned long flags = NORMAL_MODE;
+
+ if (lcd_paneloff_mode)
+ flags |= LCD_PANEL_OFF_MODE;
+
+ if (stay_touchscreen_off)
+ flags |= TOUCH_SCREEN_OFF_MODE;
+
+ return flags;
+}
+
+bool touch_event_blocked(void)
+{
+ return touch_blocked;
+}
+
+void lcd_on_procedure(int state, enum device_flags flag)
+{
+ dd_list *l = NULL;
+ const struct device_ops *ops = NULL;
+ unsigned long flags = get_lcd_on_flags();
+ flags |= flag;
+
+ /* send LCDOn dbus signal */
+ if (!lcdon_broadcast) {
+ broadcast_lcd_on(SIGNAL_PRE, flags);
+ lcdon_broadcast = true;
+ }
+
+ if (!(flags & LCD_PHASED_TRANSIT_MODE)) {
+ /* Update brightness level */
+ if (state == LCD_DIM)
+ backlight_ops.dim();
+ else if (state == LCD_NORMAL)
+ backlight_ops.update();
+ }
+
+ DD_LIST_FOREACH(lcdon_ops, l, ops)
+ ops->start(flags);
+
+ broadcast_lcd_on(SIGNAL_POST, flags);
+
+ if (CHECK_OPS(keyfilter_ops, backlight_enable))
+ keyfilter_ops->backlight_enable(true);
+
+ touch_blocked = false;
+}
+
+inline void lcd_off_procedure(enum device_flags flag)
+{
+ dd_list *l = NULL;
+ const struct device_ops *ops = NULL;
+ unsigned long flags = NORMAL_MODE;
+ flags |= flag;
+
+ touch_blocked = true;
+
+ if (lcdon_broadcast) {
+ broadcast_lcd_off(SIGNAL_PRE, flags);
+ lcdon_broadcast = false;
+ }
+ if (CHECK_OPS(keyfilter_ops, backlight_enable))
+ keyfilter_ops->backlight_enable(false);
+
+ DD_LIST_REVERSE_FOREACH(lcdon_ops, l, ops)
+ ops->stop(flags);
+
+ broadcast_lcd_off(SIGNAL_POST, flags);
+}
+
+void set_stay_touchscreen_off(int val)
+{
+ _D("stay touch screen off : %d", val);
+ stay_touchscreen_off = val;
+
+ lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
+ set_setting_pmstate(LCD_NORMAL);
+}
+
+void set_lcd_paneloff_mode(int val)
+{
+ _D("lcd paneloff mode : %d", val);
+ lcd_paneloff_mode = val;
+
+ lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
+ set_setting_pmstate(LCD_NORMAL);
+}
+
+int low_battery_state(int val)
+{
+ switch (val) {
+ case VCONFKEY_SYSMAN_BAT_POWER_OFF:
+ case VCONFKEY_SYSMAN_BAT_CRITICAL_LOW:
+ case VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF:
+ return true;
+ }
+ return false;
+}
+
+int get_hallic_open(void)
+{
+ return hallic_open;
+}
+
+static int refresh_app_cond()
+{
+ trans_condition = 0;
+
+ if (check_lock_state(S_NORMAL))
+ trans_condition = trans_condition | MASK_NORMAL;
+ if (check_lock_state(S_LCDDIM))
+ trans_condition = trans_condition | MASK_DIM;
+ if (check_lock_state(S_LCDOFF))
+ trans_condition = trans_condition | MASK_OFF;
+
+ return 0;
+}
+
+static void makeup_trans_condition(void)
+{
+ check_processes(S_NORMAL);
+ check_processes(S_LCDDIM);
+ check_processes(S_LCDOFF);
+ refresh_app_cond();
+}
+
+static PmLockNode *find_node(enum state_t s_index, pid_t pid)
+{
+ PmLockNode *t = cond_head[s_index];
+
+ while (t != NULL) {
+ if (t->pid == pid)
+ break;
+ t = t->next;
+ }
+ return t;
+}
+
+static PmLockNode *add_node(enum state_t s_index, pid_t pid, Ecore_Timer *timeout_id,
+ bool holdkey_block)
+{
+ PmLockNode *n;
+ time_t now;
+
+ n = (PmLockNode *) malloc(sizeof(PmLockNode));
+ if (n == NULL) {
+ _E("Not enough memory, add cond. fail");
+ return NULL;
+ }
+
+ time(&now);
+ n->pid = pid;
+ n->timeout_id = timeout_id;
+ n->time = now;
+ n->holdkey_block = holdkey_block;
+ n->next = cond_head[s_index];
+ n->background = false;
+ cond_head[s_index] = n;
+
+ refresh_app_cond();
+ return n;
+}
+
+static int del_node(enum state_t s_index, PmLockNode *n)
+{
+ PmLockNode *t;
+ PmLockNode *prev;
+
+ if (n == NULL)
+ return 0;
+
+ t = cond_head[s_index];
+ prev = NULL;
+ while (t != NULL) {
+ if (t == n) {
+ if (prev != NULL)
+ prev->next = t->next;
+ else
+ cond_head[s_index] = cond_head[s_index]->next;
+ /* delete timer */
+ if (t->timeout_id)
+ ecore_timer_del(t->timeout_id);
+ free(t);
+ break;
+ }
+ prev = t;
+ t = t->next;
+ }
+ refresh_app_cond();
+ return 0;
+}
+
+static void print_node(int next)
+{
+ PmLockNode *n;
+ char buf[30];
+ time_t now;
+ double diff;
+
+ if (next <= S_START || next >= S_END)
+ return;
+
+ time(&now);
+ n = cond_head[next];
+ while (n != NULL) {
+ diff = difftime(now, n->time);
+ ctime_r(&n->time, buf);
+
+ if (diff > LOCK_TIME_WARNING)
+ _W("over %.0f s, pid: %5d, lock time: %s", diff, n->pid, buf);
+ else
+ _I("pid: %5d, lock time: %s", n->pid, buf);
+
+ n = n->next;
+ }
+}
+
+void get_pname(pid_t pid, char *pname)
+{
+ char buf[PATH_MAX];
+ int cmdline, r;
+
+ if (pid >= INTERNAL_LOCK_BASE)
+ snprintf(buf, PATH_MAX, "/proc/%d/cmdline", getpid());
+ else
+ snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
+
+ cmdline = open(buf, O_RDONLY);
+ if (cmdline < 0) {
+ pname[0] = '\0';
+ _E("%d does not exist now(may be dead without unlock)", pid);
+ return;
+ }
+
+ r = read(cmdline, pname, PATH_MAX);
+ if ((r >= 0) && (r < PATH_MAX))
+ pname[r] = '\0';
+ else
+ pname[0] = '\0';
+
+ close(cmdline);
+}
+
+static void del_state_cond(void *data, enum state_t state)
+{
+ PmLockNode *tmp = NULL;
+ char pname[PATH_MAX];
+ pid_t pid;
+
+ if (!data)
+ return;
+
+ /* A passed data is a pid_t type data, not a 64bit data. */
+ pid = (pid_t)((intptr_t)data);
+ _I("delete prohibit dim condition by timeout (%d)", pid);
+
+ tmp = find_node(state, pid);
+ del_node(state, tmp);
+ get_pname(pid, pname);
+ set_unlock_time(pname, state);
+
+ if (!timeout_src_id)
+ states[pm_cur_state].trans(EVENT_TIMEOUT);
+
+ if (state == S_LCDOFF)
+ set_process_active(EINA_FALSE, pid);
+}
+
+static Eina_Bool del_normal_cond(void *data)
+{
+ del_state_cond(data, S_NORMAL);
+ return EINA_FALSE;
+}
+
+static Eina_Bool del_dim_cond(void *data)
+{
+ del_state_cond(data, S_LCDDIM);
+ return EINA_FALSE;
+}
+
+static Eina_Bool del_off_cond(void *data)
+{
+ del_state_cond(data, S_LCDOFF);
+ return EINA_FALSE;
+}
+
+/* timeout handler */
+Eina_Bool timeout_handler(void *data)
+{
+ _I("Time out state %s\n", states[pm_cur_state].name);
+
+ if (timeout_src_id) {
+ ecore_timer_del(timeout_src_id);
+ timeout_src_id = NULL;
+ }
+
+ states[pm_cur_state].trans(EVENT_TIMEOUT);
+ return EINA_FALSE;
+}
+
+void reset_timeout(int timeout)
+{
+ if (!display_conf.timeout_enable)
+ return;
+
+ _I("Reset Timeout (%d)ms", timeout);
+ if (timeout_src_id != 0) {
+ ecore_timer_del(timeout_src_id);
+ timeout_src_id = NULL;
+ }
+
+ if (trans_table[pm_cur_state][EVENT_TIMEOUT] == pm_cur_state)
+ return;
+
+ if (timeout > 0)
+ timeout_src_id = ecore_timer_add(MSEC_TO_SEC((double)timeout),
+ (Ecore_Task_Cb)timeout_handler, NULL);
+ else if (timeout == 0)
+ states[pm_cur_state].trans(EVENT_TIMEOUT);
+}
+
+/* get configurations from setting */
+static int get_lcd_timeout_from_settings(void)
+{
+ int i;
+ int val = 0;
+
+ for (i = 0; i < S_END; i++) {
+ switch (states[i].state) {
+ case S_NORMAL:
+ get_run_timeout(&val);
+ break;
+ case S_LCDDIM:
+ get_dim_timeout(&val);
+ break;
+ case S_LCDOFF:
+ val = display_conf.lcdoff_timeout;
+ break;
+ default:
+ /* This state doesn't need to set time out. */
+ val = 0;
+ break;
+ }
+ if (val > 0)
+ states[i].timeout = val;
+
+ _I("%s state : %d ms timeout", states[i].name,
+ states[i].timeout);
+ }
+
+ return 0;
+}
+
+static void update_display_time(void)
+{
+ int run_timeout, val;
+
+ /* first priority : s cover */
+ if (!hallic_open) {
+ states[S_NORMAL].timeout = S_COVER_TIMEOUT;
+ _I("S cover closed : timeout is set by normal(%d ms)",
+ S_COVER_TIMEOUT);
+ return;
+ }
+
+ /* second priority : custom timeout */
+ if (custom_normal_timeout > 0) {
+ states[S_NORMAL].timeout = custom_normal_timeout;
+ states[S_LCDDIM].timeout = custom_dim_timeout;
+ _I("CUSTOM : timeout is set by normal(%d ms), dim(%d ms)",
+ custom_normal_timeout, custom_dim_timeout);
+ return;
+ }
+
+ /* third priority : lock state */
+ if ((get_lock_screen_state() == VCONFKEY_IDLE_LOCK) &&
+ !get_lock_screen_bg_state()) {
+ /* timeout is different according to key or event. */
+ states[S_NORMAL].timeout = lock_screen_timeout;
+ _I("LOCK : timeout is set by normal(%d ms)",
+ lock_screen_timeout);
+ return;
+ }
+
+ /* default setting */
+ get_run_timeout(&run_timeout);
+
+ /* for sdk
+ * if the run_timeout is zero, it regards AlwaysOn state
+ */
+ if (run_timeout == 0 || display_conf.lcd_always_on) {
+ run_timeout = ALWAYS_ON_TIMEOUT;
+ _I("LCD Always On");
+ }
+
+ states[S_NORMAL].timeout = run_timeout;
+
+ get_dim_timeout(&val);
+ states[S_LCDDIM].timeout = val;
+
+ _I("Normal: NORMAL timeout is set by %d ms", states[S_NORMAL].timeout);
+ _I("Normal: DIM timeout is set by %d ms", states[S_LCDDIM].timeout);
+}
+
+static void update_display_locktime(int time)
+{
+ lock_screen_timeout = time;
+ update_display_time();
+}
+
+
+void set_dim_state(bool on)
+{
+ _I("dim state is %d", on);
+ update_display_time();
+ states[pm_cur_state].trans(EVENT_INPUT);
+}
+
+
+void lcd_on_direct(enum device_flags flags)
+{
+ int ret, call_state;
+
+ if (power_ops.get_power_lock_support()
+ && pm_cur_state == S_SLEEP)
+ power_ops.power_lock();
+
+#ifdef MICRO_DD
+ _D("lcd is on directly");
+ gettimeofday(&lcdon_tv, NULL);
+ lcd_on_procedure(LCD_NORMAL, flags);
+ reset_timeout(DD_LCDOFF_INPUT_TIMEOUT);
+#else
+ ret = vconf_get_int(VCONFKEY_CALL_STATE, &call_state);
+ if ((ret >= 0 && call_state != VCONFKEY_CALL_OFF) ||
+ (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)) {
+ _D("LOCK state, lcd is on directly");
+ lcd_on_procedure(LCD_NORMAL, flags);
+ }
+ reset_timeout(display_conf.lcdoff_timeout);
+#endif
+ update_display_locktime(LOCK_SCREEN_INPUT_TIMEOUT);
+}
+
+static inline bool check_lcd_on(void)
+{
+ if (backlight_ops.get_lcd_power() != DPMS_ON)
+ return true;
+
+ return false;
+}
+
+int custom_lcdon(int timeout)
+{
+ struct state *st;
+
+ if (timeout <= 0)
+ return -EINVAL;
+
+ if (check_lcd_on() == true)
+ lcd_on_direct(LCD_ON_BY_GESTURE);
+
+ _I("custom lcd on %d ms", timeout);
+ if (set_custom_lcdon_timeout(timeout) == true)
+ update_display_time();
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_NORMAL;
+ st = &states[pm_cur_state];
+
+ /* enter action */
+ if (st->action) {
+ st->action(st->timeout);
+ }
+
+ return 0;
+}
+
+static void default_proc_change_state_action(enum state_t next, int timeout)
+{
+ struct state *st;
+
+ pm_old_state = pm_cur_state;
+ pm_cur_state = next;
+
+ st = &states[pm_cur_state];
+
+ if (st && st->action) {
+ if (timeout < 0)
+ st->action(st->timeout);
+ else
+ st->action(timeout);
+ }
+}
+
+static int default_proc_change_state(unsigned int cond, pid_t pid)
+{
+ enum state_t next;
+
+ next = GET_COND_STATE(cond);
+ if (pm_cur_state == next) {
+ _I("current state (%d) == next state (%d)", pm_cur_state, next);
+ return 0;
+ }
+
+ _I("Change State to %s (%d)", states[next].name, pid);
+
+ switch (next) {
+ case S_NORMAL:
+ if (check_lcd_on())
+ lcd_on_direct(LCD_ON_BY_EVENT);
+ update_display_locktime(LOCK_SCREEN_CONTROL_TIMEOUT);
+ default_proc_change_state_action(next, -1);
+ break;
+ case S_LCDDIM:
+ default_proc_change_state_action(next, -1);
+ break;
+ case S_LCDOFF:
+ if (backlight_ops.get_lcd_power() != DPMS_OFF)
+ lcd_off_procedure(LCD_OFF_BY_EVENT);
+ if (set_custom_lcdon_timeout(0))
+ update_display_time();
+ default_proc_change_state_action(next, -1);
+ break;
+ case S_SLEEP:
+ _I("Dangerous requests.");
+ /* at first LCD_OFF and then goto sleep */
+ /* state transition */
+ default_proc_change_state_action(S_LCDOFF, TIMEOUT_NONE);
+ delete_condition(S_LCDOFF);
+ default_proc_change_state_action(S_SLEEP, TIMEOUT_NONE);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* update transition condition for application requrements */
+static void update_lock_timer(PMMsg *data,
+ PmLockNode *node, Ecore_Timer *timeout_id)
+{
+ time_t now;
+
+ if (data->timeout > 0) {
+ time(&now);
+ node->time = now;
+ }
+
+ if (node->timeout_id) {
+ ecore_timer_del(node->timeout_id);
+ node->timeout_id = timeout_id;
+ }
+}
+
+static void proc_condition_lock(PMMsg *data)
+{
+ PmLockNode *tmp;
+ Ecore_Timer *cond_timeout_id = NULL;
+ char pname[PATH_MAX];
+ pid_t pid = data->pid;
+ enum state_t state;
+ int holdkey_block;
+
+ state = GET_COND_STATE(data->cond);
+ if (!state)
+ return;
+
+ get_pname(pid, pname);
+
+ if (state == S_LCDOFF &&
+ pm_cur_state == S_SLEEP)
+ proc_change_state(data->cond, getpid());
+
+ if (data->timeout > 0) {
+ /* To pass a pid_t data through the timer infrastructure
+ * without memory allocation, a pid_t data becomes typecast
+ * to intptr_t and void *(64bit) type. */
+ cond_timeout_id = ecore_timer_add(
+ MSEC_TO_SEC((double)data->timeout),
+ states[state].timeout_cb,
+ (void*)((intptr_t)pid));
+ if (!cond_timeout_id)
+ _E("Failed to register display timer");
+ }
+
+ holdkey_block = GET_COND_FLAG(data->cond) & PM_FLAG_BLOCK_HOLDKEY;
+
+ tmp = find_node(state, pid);
+ if (!tmp)
+ add_node(state, pid, cond_timeout_id, holdkey_block);
+ else {
+ update_lock_timer(data, tmp, cond_timeout_id);
+ tmp->holdkey_block = holdkey_block;
+ }
+
+ if (state == S_LCDOFF)
+ set_process_active(EINA_TRUE, pid);
+
+ /* for debug */
+ _SD("[%s] locked by pid %d - process %s holdkeyblock %d\n",
+ states[state].name, pid, pname, holdkey_block);
+ set_lock_time(pname, state);
+
+ device_notify(DEVICE_NOTIFIER_DISPLAY_LOCK, (void *)true);
+}
+
+static void proc_condition_unlock(PMMsg *data)
+{
+ pid_t pid = data->pid;
+ enum state_t state;
+ PmLockNode *tmp;
+ char pname[PATH_MAX];
+
+ state = GET_COND_STATE(data->cond);
+ if (!state)
+ return;
+
+ get_pname(pid, pname);
+
+ tmp = find_node(state, pid);
+ del_node(state, tmp);
+
+ if (state == S_LCDOFF)
+ set_process_active(EINA_FALSE, pid);
+
+ _SD("[%s] unlocked by pid %d - process %s\n",
+ states[state].name, pid, pname);
+ set_unlock_time(pname, state);
+
+ device_notify(DEVICE_NOTIFIER_DISPLAY_LOCK, (void *)false);
+}
+
+static int proc_condition(PMMsg *data)
+{
+ unsigned int flags;
+
+ if (IS_COND_REQUEST_LOCK(data->cond))
+ proc_condition_lock(data);
+
+ if (IS_COND_REQUEST_UNLOCK(data->cond))
+ proc_condition_unlock(data);
+
+ if (!display_conf.timeout_enable)
+ return 0;
+
+ flags = GET_COND_FLAG(data->cond);
+ if (flags == 0) {
+ /* guard time for suspend */
+ if (pm_cur_state == S_LCDOFF) {
+ reset_timeout(states[S_LCDOFF].timeout);
+ _I("Margin timeout (%d ms)", states[S_LCDOFF].timeout);
+ }
+ } else {
+ if (flags & PM_FLAG_RESET_TIMER) {
+ reset_timeout(states[pm_cur_state].timeout);
+ _I("Reset timeout (%d ms)", states[pm_cur_state].timeout);
+ }
+ }
+
+ if (!timeout_src_id)
+ states[pm_cur_state].trans(EVENT_TIMEOUT);
+
+ return 0;
+}
+
+/* If some changed, return 1 */
+int check_processes(enum state_t prohibit_state)
+{
+ PmLockNode *t = cond_head[prohibit_state];
+ PmLockNode *tmp = NULL;
+ int ret = 0;
+
+ while (t != NULL) {
+ if (t->pid < INTERNAL_LOCK_BASE && kill(t->pid, 0) == -1) {
+ _E("%d process does not exist, delete the REQ"
+ " - prohibit state %d ",
+ t->pid, prohibit_state);
+ if (t->pid == custom_change_pid) {
+ get_lcd_timeout_from_settings();
+ custom_normal_timeout = custom_dim_timeout = 0;
+ custom_change_pid = -1;
+ }
+ tmp = t;
+ ret = 1;
+ }
+ t = t->next;
+
+ if (tmp != NULL) {
+ del_node(prohibit_state, tmp);
+ tmp = NULL;
+ }
+ }
+
+ return ret;
+}
+
+int check_holdkey_block(enum state_t state)
+{
+ PmLockNode *t = cond_head[state];
+ int ret = 0;
+
+ _I("check holdkey block : state of %s", states[state].name);
+
+ if (custom_holdkey_block == true) {
+ _I("custom hold key blocked by pid(%d)",
+ custom_change_pid);
+ return 1;
+ }
+
+ while (t != NULL) {
+ if (t->holdkey_block == true) {
+ ret = 1;
+ _I("Hold key blocked by pid(%d)!", t->pid);
+ break;
+ }
+ t = t->next;
+ }
+
+ return ret;
+}
+
+int delete_condition(enum state_t state)
+{
+ PmLockNode *t = cond_head[state];
+ PmLockNode *tmp = NULL;
+ pid_t pid;
+ char pname[PATH_MAX];
+
+ _I("delete condition : state of %s", states[state].name);
+
+ while (t != NULL) {
+ if (t->timeout_id > 0) {
+ ecore_timer_del(t->timeout_id);
+ t->timeout_id = NULL;
+ }
+ tmp = t;
+ t = t->next;
+ pid = tmp->pid;
+ if (state == S_LCDOFF)
+ set_process_active(EINA_FALSE, pid);
+ _I("delete node of pid(%d)", pid);
+ del_node(state, tmp);
+ get_pname(pid, pname);
+ set_unlock_time(pname, state-1);
+ }
+
+ return 0;
+}
+
+void update_lcdoff_source(int source)
+{
+ switch (source) {
+ case VCONFKEY_PM_LCDOFF_BY_TIMEOUT:
+ _I("LCD OFF by timeout");
+ break;
+ case VCONFKEY_PM_LCDOFF_BY_POWERKEY:
+ _I("LCD OFF by powerkey");
+ break;
+ default:
+ _E("Invalid value(%d)", source);
+ return;
+ }
+ vconf_set_int(VCONFKEY_PM_LCDOFF_SOURCE, source);
+}
+
+#ifdef ENABLE_PM_LOG
+
+typedef struct _pm_history {
+ time_t time;
+ enum pm_log_type log_type;
+ int keycode;
+} pm_history;
+
+static int max_history_count = MAX_LOG_COUNT;
+static pm_history pm_history_log[MAX_LOG_COUNT] = {{0, }, };
+static int history_count = 0;
+
+static const char history_string[PM_LOG_MAX][15] = {
+ "PRESS", "LONG PRESS", "RELEASE", "LCD ON", "LCD ON FAIL",
+ "LCD DIM", "LCD DIM FAIL", "LCD OFF", "LCD OFF FAIL", "SLEEP"};
+
+void pm_history_init()
+{
+ memset(pm_history_log, 0x0, sizeof(pm_history_log));
+ history_count = 0;
+ max_history_count = MAX_LOG_COUNT;
+}
+
+void pm_history_save(enum pm_log_type log_type, int code)
+{
+ time_t now;
+
+ time(&now);
+ pm_history_log[history_count].time = now;
+ pm_history_log[history_count].log_type = log_type;
+ pm_history_log[history_count].keycode = code;
+ history_count++;
+
+ if (history_count >= max_history_count)
+ history_count = 0;
+}
+
+void pm_history_print(int fd, int count)
+{
+ int start_index, index, i;
+ int ret;
+ char buf[255];
+ char time_buf[30];
+
+ if (count <= 0 || count > max_history_count)
+ return;
+
+ start_index = (history_count - count + max_history_count)
+ % max_history_count;
+
+ for (i = 0; i < count; i++) {
+ index = (start_index + i) % max_history_count;
+
+ if (pm_history_log[index].time == 0)
+ continue;
+
+ if (pm_history_log[index].log_type < PM_LOG_MIN ||
+ pm_history_log[index].log_type >= PM_LOG_MAX)
+ continue;
+ ctime_r(&pm_history_log[index].time, time_buf);
+ snprintf(buf, sizeof(buf), "[%3d] %15s %3d %s",
+ index,
+ history_string[pm_history_log[index].log_type],
+ pm_history_log[index].keycode,
+ time_buf);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+ }
+}
+#endif
+
+void print_info(int fd)
+{
+ int s_index = 0;
+ char buf[255];
+ int i = 1;
+ int ret;
+ char pname[PATH_MAX];
+
+ if (fd < 0)
+ return;
+
+ snprintf(buf, sizeof(buf),
+ "\n==========================================="
+ "===========================\n");
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+ snprintf(buf, sizeof(buf), "Timeout Info: Run[%dms] Dim[%dms] Off[%dms]\n",
+ states[S_NORMAL].timeout,
+ states[S_LCDDIM].timeout, states[S_LCDOFF].timeout);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf), "Tran. Locked : %s %s %s\n",
+ (trans_condition & MASK_NORMAL) ? states[S_NORMAL].name : "-",
+ (trans_condition & MASK_DIM) ? states[S_LCDDIM].name : "-",
+ (trans_condition & MASK_OFF) ? states[S_LCDOFF].name : "-");
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf), "Current State: %s\n",
+ states[pm_cur_state].name);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf), "Current Lock Conditions: \n");
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ for (s_index = S_NORMAL; s_index < S_END; s_index++) {
+ PmLockNode *t;
+ char time_buf[30];
+ t = cond_head[s_index];
+
+ while (t != NULL) {
+ get_pname((pid_t)t->pid, pname);
+ ctime_r(&t->time, time_buf);
+ snprintf(buf, sizeof(buf),
+ " %d: [%s] locked by pid %d %s %s",
+ i++, states[s_index].name, t->pid, pname, time_buf);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+ t = t->next;
+ }
+ }
+
+ print_lock_info_list(fd);
+
+#ifdef ENABLE_PM_LOG
+ pm_history_print(fd, 250);
+#endif
+}
+
+void save_display_log(void)
+{
+ int fd, ret;
+ char buf[255];
+ time_t now_time;
+ char time_buf[30];
+
+ _D("internal state is saved!");
+
+ time(&now_time);
+ ctime_r(&now_time, time_buf);
+
+ fd = open(PM_STATE_LOG_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (fd != -1) {
+ snprintf(buf, sizeof(buf),
+ "\npm_state_log now-time : %d(s) %s\n\n",
+ (int)now_time, time_buf);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf), "pm_status_flag: %x\n", pm_status_flag);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf), "screen lock status : %d\n",
+ get_lock_screen_state());
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+ print_info(fd);
+ close(fd);
+ }
+
+ fd = open("/dev/console", O_WRONLY);
+ if (fd != -1) {
+ print_info(fd);
+ close(fd);
+ }
+}
+
+/* SIGHUP signal handler
+ * For debug... print info to syslog
+ */
+static void sig_hup(int signo)
+{
+ save_display_log();
+}
+
+int check_lcdoff_direct(void)
+{
+ int ret, lock, cradle;
+ int hdmi_state;
+
+ if (pm_old_state != S_NORMAL)
+ return false;
+
+ if (pm_cur_state != S_LCDDIM)
+ return false;
+
+ lock = get_lock_screen_state();
+ if (lock != VCONFKEY_IDLE_LOCK && hallic_open)
+ return false;
+
+ hdmi_state = extcon_get_status(EXTCON_CABLE_HDMI);
+ if (hdmi_state)
+ return false;
+
+ ret = vconf_get_int(VCONFKEY_SYSMAN_CRADLE_STATUS, &cradle);
+ if (ret >= 0 && cradle == DOCK_SOUND)
+ return false;
+
+ _D("Goto LCDOFF direct(%d,%d,%d)", lock, hdmi_state, cradle);
+
+ return true;
+}
+
+int check_lcdoff_lock_state(void)
+{
+ if (cond_head[S_LCDOFF] != NULL)
+ return true;
+
+ return false;
+}
+
+/*
+ * default transition function
+ * 1. call check
+ * 2. transition
+ * 3. call enter action function
+ */
+static int default_trans(int evt)
+{
+ struct state *st = &states[pm_cur_state];
+ int next_state;
+
+ next_state = (enum state_t)trans_table[pm_cur_state][evt];
+
+ /* check conditions */
+ while (st->check && !st->check(pm_cur_state, next_state)) {
+ /* There is a condition. */
+ _I("(%s) locked. Trans to (%s) failed", states[pm_cur_state].name,
+ states[next_state].name);
+ if (!check_processes(pm_cur_state)) {
+ /* This is valid condition
+ * The application that sent the condition is running now. */
+ return -1;
+ }
+ }
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = next_state;
+ st = &states[pm_cur_state];
+
+ /* enter action */
+ if (st->action) {
+ if (pm_cur_state == S_LCDOFF)
+ update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_TIMEOUT);
+
+ if (pm_cur_state == S_NORMAL || pm_cur_state == S_LCDOFF)
+ if (set_custom_lcdon_timeout(0) == true)
+ update_display_time();
+
+ if (check_lcdoff_direct() == true) {
+ /* enter next state directly */
+ states[pm_cur_state].trans(EVENT_TIMEOUT);
+ } else {
+ st->action(st->timeout);
+ }
+ }
+
+ return 0;
+}
+
+static Eina_Bool lcd_on_expired(void *data)
+{
+ int lock_state, ret;
+
+ if (lock_timeout_id)
+ lock_timeout_id = NULL;
+
+ /* check state of lock */
+ ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
+
+ if (ret > 0 && lock_state == VCONFKEY_IDLE_LOCK)
+ return EINA_FALSE;
+
+ /* lock screen is not launched yet, but lcd is on */
+ if (check_lcd_on() == true)
+ lcd_on_procedure(LCD_NORMAL, NORMAL_MODE);
+
+ return EINA_FALSE;
+}
+
+static inline void stop_lock_timer(void)
+{
+ if (lock_timeout_id) {
+ ecore_timer_del(lock_timeout_id);
+ lock_timeout_id = NULL;
+ }
+}
+
+static void check_lock_screen(void)
+{
+ int lock_setting, lock_state, app_state, ret;
+
+ stop_lock_timer();
+
+ ret = vconf_get_int(VCONFKEY_CALL_STATE, &app_state);
+ if (ret >= 0 && app_state != VCONFKEY_CALL_OFF)
+ goto lcd_on;
+
+ /* check setting of lock screen is enabled. */
+ ret = vconf_get_int(VCONFKEY_SETAPPL_SCREEN_LOCK_TYPE_INT,
+ &lock_setting);
+
+ /* check state of lock */
+ ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
+
+ if (ret < 0 || lock_state == VCONFKEY_IDLE_LOCK)
+ goto lcd_on;
+
+ /* Use time to check lock is done. */
+ lock_timeout_id = ecore_timer_add(display_conf.lock_wait_time,
+ (Ecore_Task_Cb)lcd_on_expired, (void*)NULL);
+
+ return;
+
+lcd_on:
+ if (check_lcd_on() == true)
+ lcd_on_procedure(LCD_NORMAL, NORMAL_MODE);
+}
+
+/* default enter action function */
+static int default_action(int timeout)
+{
+ int wakeup_count = -1;
+ time_t now;
+ double diff;
+ static time_t last_update_time = 0;
+ static int last_timeout = 0;
+ struct timeval now_tv;
+
+ if (status != DEVICE_OPS_STATUS_START) {
+ _E("display is not started!");
+ return -EINVAL;
+ }
+
+ if (pm_cur_state != S_SLEEP) {
+ if (pm_cur_state == S_NORMAL &&
+ lcdon_tv.tv_sec != 0) {
+ gettimeofday(&now_tv, NULL);
+ timeout -= DIFF_TIMEVAL_MS(now_tv, lcdon_tv);
+ lcdon_tv.tv_sec = 0;
+ }
+ /* set timer with current state timeout */
+ reset_timeout(timeout);
+
+ if (pm_cur_state == S_NORMAL) {
+ time(&last_update_time);
+ last_timeout = timeout;
+ } else {
+ _I("timout set: %s state %d ms",
+ states[pm_cur_state].name, timeout);
+ }
+ }
+
+ if (pm_cur_state != pm_old_state && pm_cur_state != S_SLEEP) {
+ if (power_ops.get_power_lock_support())
+ power_ops.power_lock();
+ set_setting_pmstate(pm_cur_state);
+ device_notify(DEVICE_NOTIFIER_LCD, &pm_cur_state);
+ }
+
+ if (pm_old_state == S_NORMAL && pm_cur_state != S_NORMAL) {
+ time(&now);
+ diff = difftime(now, last_update_time);
+ _I("S_NORMAL is changed to %s [%d ms, %.0f s]",
+ states[pm_cur_state].name, last_timeout, diff);
+ }
+
+ switch (pm_cur_state) {
+ case S_NORMAL:
+ /*
+ * normal state : backlight on and restore
+ * the previous brightness
+ */
+ if (pm_old_state == S_LCDOFF || pm_old_state == S_SLEEP)
+ check_lock_screen();
+ else if (pm_old_state == S_LCDDIM)
+ backlight_ops.update();
+
+ if (check_lcd_on() == true)
+ lcd_on_procedure(LCD_NORMAL, NORMAL_MODE);
+ break;
+
+ case S_LCDDIM:
+ if (pm_old_state == S_NORMAL &&
+ backlight_ops.get_custom_status())
+ backlight_ops.save_custom_brightness();
+ /* lcd dim state : dim the brightness */
+ backlight_ops.dim();
+
+ if (pm_old_state == S_LCDOFF || pm_old_state == S_SLEEP)
+ lcd_on_procedure(LCD_DIM, NORMAL_MODE);
+ break;
+
+ case S_LCDOFF:
+ if (pm_old_state != S_SLEEP && pm_old_state != S_LCDOFF) {
+ stop_lock_timer();
+ /* lcd off state : turn off the backlight */
+ if (backlight_ops.get_lcd_power() != DPMS_OFF)
+ lcd_off_procedure(LCD_OFF_BY_TIMEOUT);
+ }
+
+ if (backlight_ops.get_lcd_power() != DPMS_OFF
+ || lcd_paneloff_mode)
+ lcd_off_procedure(LCD_OFF_BY_TIMEOUT);
+ break;
+
+ case S_SLEEP:
+ if (pm_old_state != S_SLEEP && pm_old_state != S_LCDOFF)
+ stop_lock_timer();
+
+ if (backlight_ops.get_lcd_power() != DPMS_OFF)
+ lcd_off_procedure(LCD_OFF_BY_TIMEOUT);
+
+ if (!power_ops.get_power_lock_support()) {
+ /* sleep state : set system mode to SUSPEND */
+ if (power_ops.get_wakeup_count(&wakeup_count) < 0)
+ _E("wakeup count read error");
+
+ if (wakeup_count < 0) {
+ _I("Wakup Event! Can not enter suspend mode.");
+ goto go_lcd_off;
+ }
+
+ if (power_ops.set_wakeup_count(wakeup_count) < 0) {
+ _E("wakeup count write error");
+ goto go_lcd_off;
+ }
+ }
+ goto go_suspend;
+ }
+
+ return 0;
+
+go_suspend:
+#ifdef ENABLE_PM_LOG
+ pm_history_save(PM_LOG_SLEEP, pm_cur_state);
+#endif
+ if (power_ops.get_power_lock_support()) {
+ if (power_ops.enable_autosleep)
+ power_ops.enable_autosleep();
+
+ if (power_ops.power_unlock() < 0)
+ _E("power unlock state error!");
+ } else {
+ power_ops.suspend();
+ _I("system wakeup!!");
+ system_wakeup_flag = true;
+ /* Resume !! */
+ if (power_ops.check_wakeup_src() == EVENT_DEVICE)
+ /* system waked up by devices */
+ states[pm_cur_state].trans(EVENT_DEVICE);
+ else
+ /* system waked up by user input */
+ states[pm_cur_state].trans(EVENT_INPUT);
+ }
+ return 0;
+
+go_lcd_off:
+ if (!power_ops.get_power_lock_support()) {
+ /* Resume !! */
+ states[pm_cur_state].trans(EVENT_DEVICE);
+ }
+ return 0;
+}
+
+/*
+ * default check function
+ * return
+ * 0 : can't transit, others : transitable
+ */
+static int default_check(int curr, int next)
+{
+ int trans_cond;
+ int lock_state = -1;
+ int app_state = -1;
+
+ makeup_trans_condition();
+
+ trans_cond = trans_condition & MASK_BIT;
+
+ vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
+ if (lock_state == VCONFKEY_IDLE_LOCK && curr != S_LCDOFF) {
+ vconf_get_int(VCONFKEY_CALL_STATE, &app_state);
+ if (app_state == VCONFKEY_CALL_OFF) {
+ _I("default_check:LOCK STATE, it's transitable");
+ return 1;
+ }
+ }
+
+ if (next == S_NORMAL) /* S_NORMAL is exceptional */
+ return 1;
+
+ switch (curr) {
+ case S_NORMAL:
+ trans_cond = trans_cond & MASK_NORMAL;
+ break;
+ case S_LCDDIM:
+ trans_cond = trans_cond & MASK_DIM;
+ break;
+ case S_LCDOFF:
+ trans_cond = trans_cond & MASK_OFF;
+ break;
+ default:
+ trans_cond = 0;
+ break;
+ }
+
+ if (trans_cond != 0) {
+ print_node(curr);
+ return 0;
+ }
+
+ return 1; /* transitable */
+}
+
+static void default_saving_mode(int onoff)
+{
+ if (onoff) {
+ pm_status_flag |= PWRSV_FLAG;
+ } else {
+ pm_status_flag &= ~PWRSV_FLAG;
+ }
+ if (pm_cur_state == S_NORMAL)
+ backlight_ops.update();
+}
+
+static int poll_callback(int condition, PMMsg *data)
+{
+ static time_t last_t;
+ time_t now;
+
+ if (status != DEVICE_OPS_STATUS_START) {
+ _E("display logic is not started!");
+ return -ECANCELED;
+ }
+
+ if (condition == INPUT_POLL_EVENT) {
+ if (pm_cur_state == S_LCDOFF || pm_cur_state == S_SLEEP)
+ _I("Power key input");
+ time(&now);
+ if (last_t != now ||
+ pm_cur_state == S_LCDOFF ||
+ pm_cur_state == S_SLEEP) {
+ states[pm_cur_state].trans(EVENT_INPUT);
+ last_t = now;
+ }
+ }
+
+ if (condition == PM_CONTROL_EVENT) {
+ proc_condition(data);
+
+ if (IS_COND_REQUEST_CHANGE(data->cond))
+ proc_change_state(data->cond, data->pid);
+ }
+
+ return 0;
+}
+
+static int update_setting(int key_idx, int val)
+{
+ char buf[PATH_MAX];
+
+ switch (key_idx) {
+ case SETTING_TO_NORMAL:
+ update_display_time();
+ states[pm_cur_state].trans(EVENT_INPUT);
+ break;
+ case SETTING_HALLIC_OPEN:
+ hallic_open = val;
+ update_display_time();
+ if (pm_cur_state == S_NORMAL || pm_cur_state == S_LCDDIM)
+ states[pm_cur_state].trans(EVENT_INPUT);
+ else if (pm_cur_state == S_SLEEP && hallic_open)
+ proc_change_state(S_LCDOFF, getpid());
+ break;
+ case SETTING_LOW_BATT:
+ if (low_battery_state(val)) {
+ if (!(pm_status_flag & CHRGR_FLAG))
+ power_saving_func(true);
+ pm_status_flag |= LOWBT_FLAG;
+ } else {
+ if (pm_status_flag & PWRSV_FLAG)
+ power_saving_func(false);
+ pm_status_flag &= ~LOWBT_FLAG;
+ pm_status_flag &= ~BRTCH_FLAG;
+ vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
+ false);
+ }
+ break;
+ case SETTING_CHARGING:
+ if (val) {
+ if (pm_status_flag & LOWBT_FLAG) {
+ power_saving_func(false);
+ pm_status_flag &= ~LOWBT_FLAG;
+ }
+ pm_status_flag |= CHRGR_FLAG;
+ } else {
+ int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
+ vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
+ &bat_state);
+ if (low_battery_state(bat_state)) {
+ power_saving_func(true);
+ pm_status_flag |= LOWBT_FLAG;
+ }
+ pm_status_flag &= ~CHRGR_FLAG;
+ }
+ break;
+ case SETTING_BRT_LEVEL:
+ if (pm_status_flag & PWRSV_FLAG) {
+ pm_status_flag |= BRTCH_FLAG;
+ vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
+ true);
+ _I("brightness changed in low battery,"
+ "escape dim state");
+ }
+ backlight_ops.set_default_brt(val);
+ snprintf(buf, sizeof(buf), "%d", val);
+ _D("Brightness set in bl : %d", val);
+ launch_evenif_exist(SET_BRIGHTNESS_IN_BOOTLOADER, buf);
+ break;
+ case SETTING_LOCK_SCREEN:
+ set_lock_screen_state(val);
+ if (val == VCONFKEY_IDLE_UNLOCK) {
+ if (CHECK_OPS(keyfilter_ops, backlight_enable))
+ keyfilter_ops->backlight_enable(false);
+ }
+
+ /* LCD on if lock screen show before waiting time */
+ if (pm_cur_state == S_NORMAL &&
+ val == VCONFKEY_IDLE_LOCK &&
+ backlight_ops.get_lcd_power() != DPMS_ON)
+ lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
+ stop_lock_timer();
+ update_display_time();
+ if (pm_cur_state == S_NORMAL) {
+ states[pm_cur_state].trans(EVENT_INPUT);
+ }
+ break;
+ case SETTING_LOCK_SCREEN_BG:
+ set_lock_screen_bg_state(val);
+ update_display_time();
+ if (pm_cur_state == S_NORMAL) {
+ states[pm_cur_state].trans(EVENT_INPUT);
+ }
+ break;
+ case SETTING_POWEROFF:
+ switch (val) {
+ case POWER_OFF_NONE:
+ case POWER_OFF_POPUP:
+ pm_status_flag &= ~PWROFF_FLAG;
+ break;
+ case POWER_OFF_DIRECT:
+ case POWER_OFF_RESTART:
+ pm_status_flag |= PWROFF_FLAG;
+ break;
+ }
+ break;
+ case SETTING_POWER_CUSTOM_BRIGHTNESS:
+ if (val == VCONFKEY_PM_CUSTOM_BRIGHTNESS_ON)
+ backlight_ops.set_custom_status(true);
+ else
+ backlight_ops.set_custom_status(false);
+ break;
+
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static void check_seed_status(void)
+{
+ int ret = -1;
+ int tmp = 0;
+ int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
+ int brt = 0;
+ int lock_state = -1;
+
+ /* Charging check */
+ if ((get_charging_status(&tmp) == 0) && (tmp > 0)) {
+ pm_status_flag |= CHRGR_FLAG;
+ }
+
+ ret = get_setting_brightness(&tmp);
+ if (ret != 0 || (tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)) {
+ _I("fail to read vconf value for brightness");
+ brt = PM_DEFAULT_BRIGHTNESS;
+ if (tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)
+ vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
+ tmp = brt;
+ }
+ _I("Set brightness from Setting App. %d", tmp);
+ backlight_ops.set_default_brt(tmp);
+
+ vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
+ if (low_battery_state(bat_state)) {
+ if (!(pm_status_flag & CHRGR_FLAG)) {
+ power_saving_func(true);
+ pm_status_flag |= LOWBT_FLAG;
+ }
+ }
+
+ /* lock screen check */
+ ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
+ set_lock_screen_state(lock_state);
+ if (lock_state == VCONFKEY_IDLE_LOCK) {
+ states[S_NORMAL].timeout = lock_screen_timeout;
+ _I("LCD NORMAL timeout is set by %d ms"
+ " for lock screen", lock_screen_timeout);
+ }
+
+ return;
+}
+
+static void init_lcd_operation(void)
+{
+ const struct device_ops *ops = NULL;
+
+ ops = find_device("touchscreen");
+ if (!check_default(ops))
+ DD_LIST_APPEND(lcdon_ops, ops);
+
+ ops = find_device("touchkey");
+ if (!check_default(ops))
+ DD_LIST_APPEND(lcdon_ops, ops);
+
+ ops = find_device("display");
+ if (!check_default(ops))
+ DD_LIST_APPEND(lcdon_ops, ops);
+}
+
+static void exit_lcd_operation(void)
+{
+ dd_list *l = NULL;
+ dd_list *l_next = NULL;
+ const struct device_ops *ops = NULL;
+
+ DD_LIST_FOREACH_SAFE(lcdon_ops, l, l_next, ops)
+ DD_LIST_REMOVE_LIST(lcdon_ops, l);
+}
+
+enum {
+ INIT_SETTING = 0,
+ INIT_INTERFACE,
+ INIT_POLL,
+ INIT_FIFO,
+ INIT_DBUS,
+ INIT_END
+};
+
+static const char *errMSG[INIT_END] = {
+ [INIT_SETTING] = "setting init error",
+ [INIT_INTERFACE] = "lowlevel interface(sysfs or others) init error",
+ [INIT_POLL] = "input devices poll init error",
+ [INIT_FIFO] = "FIFO poll init error",
+ [INIT_DBUS] = "d-bus init error",
+};
+
+int set_lcd_timeout(int on, int dim, int holdkey_block, const char *name)
+{
+ if (on == 0 && dim == 0) {
+ _I("LCD timeout changed : default setting");
+ custom_normal_timeout = custom_dim_timeout = 0;
+ } else if (on < 0 || dim < 0) {
+ _E("fail to set value (%d,%d)", on, dim);
+ return -EINVAL;
+ } else {
+ _I("LCD timeout changed : on(%ds), dim(%ds)", on, dim);
+ custom_normal_timeout = SEC_TO_MSEC(on);
+ custom_dim_timeout = SEC_TO_MSEC(dim);
+ }
+ /* Apply new backlight time */
+ update_display_time();
+ if (pm_cur_state == S_NORMAL)
+ states[pm_cur_state].trans(EVENT_INPUT);
+
+ if (holdkey_block) {
+ custom_holdkey_block = true;
+ _I("hold key disabled !");
+ } else {
+ custom_holdkey_block = false;
+ _I("hold key enabled !");
+ }
+
+ if (custom_change_name) {
+ free(custom_change_name);
+ custom_change_name = 0;
+ }
+
+ if (custom_normal_timeout == 0 &&
+ custom_dim_timeout == 0 &&
+ !holdkey_block)
+ return 0;
+
+ custom_change_name = strndup(name, strlen(name));
+ if (!custom_change_name) {
+ _E("Malloc falied!");
+ custom_normal_timeout = custom_dim_timeout = 0;
+ custom_holdkey_block = false;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void reset_lcd_timeout(const char *sender, void *data)
+{
+ if (!sender)
+ return;
+
+ if (!custom_change_name)
+ return;
+
+ if (strcmp(sender, custom_change_name))
+ return;
+
+ _I("reset lcd timeout %s: set default timeout", sender);
+
+ free(custom_change_name);
+ custom_change_name = 0;
+ custom_normal_timeout = custom_dim_timeout = 0;
+ custom_holdkey_block = false;
+
+ update_display_time();
+ if (pm_cur_state == S_NORMAL) {
+ states[pm_cur_state].trans(EVENT_INPUT);
+ }
+}
+
+static int booting_done(void *data)
+{
+ static bool done = false;
+
+ if (data != NULL) {
+ done = *(int*)data;
+ if (done)
+ return 0;
+ _I("booting done, unlock LCD_OFF");
+ pm_unlock_internal(INTERNAL_LOCK_BOOTING, LCD_OFF, PM_SLEEP_MARGIN);
+ }
+
+ return 0;
+}
+
+static int process_background(void *data)
+{
+ pid_t pid;
+ PmLockNode *node;
+
+ pid = *(pid_t *)data;
+
+ node = find_node(S_NORMAL, pid);
+ if (node) {
+ node->background = true;
+ _I("%d pid is background, then PM will be unlocked LCD_NORMAL", pid);
+ }
+
+ return 0;
+}
+
+static int process_foreground(void *data)
+{
+ pid_t pid;
+ PmLockNode *node;
+
+ pid = *(pid_t *)data;
+
+ node = find_node(S_NORMAL, pid);
+ if (node) {
+ node->background = false;
+ _I("%d pid is foreground, then PM will be maintained locked LCD_NORMAL", pid);
+ }
+
+ return 0;
+}
+
+static int display_load_config(struct parse_result *result, void *user_data)
+{
+ struct display_config *c = user_data;
+
+ _D("%s,%s,%s", result->section, result->name, result->value);
+
+ if (!c)
+ return -EINVAL;
+
+ if (!MATCH(result->section, "Display"))
+ return 0;
+
+ if (MATCH(result->name, "LockScreenWaitingTime")) {
+ SET_CONF(c->lock_wait_time, atof(result->value));
+ _D("lock wait time is %.3f", c->lock_wait_time);
+ } else if (MATCH(result->name, "LongPressInterval")) {
+ SET_CONF(c->longpress_interval, atof(result->value));
+ _D("long press interval is %.3f", c->longpress_interval);
+ } else if (MATCH(result->name, "LightSensorSamplingInterval")) {
+ SET_CONF(c->lightsensor_interval, atof(result->value));
+ _D("lightsensor interval is %.3f", c->lightsensor_interval);
+ } else if (MATCH(result->name, "LCDOffTimeout")) {
+ SET_CONF(c->lcdoff_timeout, atoi(result->value));
+ _D("lcdoff timeout is %d ms", c->lcdoff_timeout);
+ } else if (MATCH(result->name, "BrightnessChangeStep")) {
+ SET_CONF(c->brightness_change_step, atoi(result->value));
+ _D("brightness change step is %d", c->brightness_change_step);
+ } else if (MATCH(result->name, "LCDAlwaysOn")) {
+ c->lcd_always_on = (MATCH(result->value, "yes") ? 1 : 0);
+ _D("LCD always on is %d", c->lcd_always_on);
+ } else if (MATCH(result->name, "ChangedFrameRateAllowed")) {
+ if (strstr(result->value, "setting")) {
+ c->framerate_app[REFRESH_SETTING] = 1;
+ _D("framerate app is Setting");
+ }
+ if (strstr(result->value, "all")) {
+ memset(c->framerate_app, 1, sizeof(c->framerate_app));
+ _D("framerate app is All");
+ }
+ } else if (MATCH(result->name, "ControlDisplay")) {
+ c->control_display = (MATCH(result->value, "yes") ? 1 : 0);
+ _D("ControlDisplay is %d", c->control_display);
+ } else if (MATCH(result->name, "PowerKeyDoublePressSupport")) {
+ c->powerkey_doublepress = (MATCH(result->value, "yes") ? 1 : 0);
+ _D("PowerKeyDoublePressSupport is %d", c->powerkey_doublepress);
+ } else if (MATCH(result->name, "AccelSensorOn")) {
+ c->accel_sensor_on = (MATCH(result->value, "yes") ? 1 : 0);
+ _D("AccelSensorOn is %d", c->accel_sensor_on);
+ } else if (MATCH(result->name, "ContinuousSampling")) {
+ c->continuous_sampling = (MATCH(result->value, "yes") ? 1 : 0);
+ _D("ContinuousSampling is %d", c->continuous_sampling);
+ } else if (MATCH(result->name, "TimeoutEnable")) {
+ c->timeout_enable = (MATCH(result->value, "yes") ? true : false);
+ _D("Timeout is %s", c->timeout_enable ? "enalbed" : "disabled");
+ } else if (MATCH(result->name, "InputSupport")) {
+ c->input_support = (MATCH(result->value, "yes") ? true : false);
+ _D("Input is %s", c->input_support ? "supported" : "NOT supported");
+ }
+
+ return 0;
+}
+
+static bool check_wm_ready(void)
+{
+ if (access("/run/.wm_ready", F_OK) == 0) {
+ _I("Window manager is ready");
+ return true;
+ }
+
+ _I("Window manager is not ready");
+ return false;
+}
+
+static gboolean lcd_on_wm_ready(gpointer data)
+{
+ int timeout;
+
+ if (!check_wm_ready())
+ return G_SOURCE_CONTINUE;
+
+ switch (pm_cur_state) {
+ case S_NORMAL:
+ case S_LCDDIM:
+ lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
+ if (display_conf.timeout_enable) {
+ timeout = states[S_NORMAL].timeout;
+ /* check minimun lcd on time */
+ if (timeout < SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT))
+ timeout = SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT);
+ reset_timeout(timeout);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void add_timer_for_wm_ready(void)
+{
+ guint id = g_timeout_add(500/* milliseconds */, lcd_on_wm_ready, NULL);
+ if (id == 0)
+ _E("Failed to add wm_ready timeout");
+}
+
+/**
+ * Power manager Main
+ *
+ */
+static int display_probe(void *data)
+{
+ /**
+ * load display service
+ * if there is no display shared library,
+ * deviced does not provide any method and function of display.
+ */
+ return display_service_load();
+}
+
+static void display_init(void *data)
+{
+ int ret, i;
+ unsigned int flags = (WITHOUT_STARTNOTI | FLAG_X_DPMS);
+ int timeout = 0;
+ bool wm_ready;
+
+ _I("Start power manager");
+
+ signal(SIGHUP, sig_hup);
+
+ power_saving_func = default_saving_mode;
+
+ /* load configutation */
+ ret = config_parse(DISPLAY_CONF_FILE, display_load_config, &display_conf);
+ if (ret < 0)
+ _W("Failed to load %s, %d Use default value!",
+ DISPLAY_CONF_FILE, ret);
+
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ register_notifier(DEVICE_NOTIFIER_PROCESS_BACKGROUND, process_background);
+ register_notifier(DEVICE_NOTIFIER_PROCESS_FOREGROUND, process_foreground);
+
+ for (i = INIT_SETTING; i < INIT_END; i++) {
+ switch (i) {
+ case INIT_SETTING:
+ ret = init_setting(update_setting);
+ break;
+ case INIT_INTERFACE:
+ if (display_conf.timeout_enable)
+ get_lcd_timeout_from_settings();
+ ret = init_sysfs(flags);
+ break;
+ case INIT_POLL:
+ _I("input init");
+ pm_callback = poll_callback;
+ if (display_conf.input_support)
+ ret = init_input();
+ else
+ ret = 0;
+ break;
+ case INIT_DBUS:
+ _I("dbus init");
+ ret = init_pm_dbus();
+ break;
+ }
+ if (ret != 0) {
+ _E("%s", errMSG[i]);
+ break;
+ }
+ }
+
+ if (i == INIT_END) {
+ display_ops_init(NULL);
+#ifdef ENABLE_PM_LOG
+ pm_history_init();
+#endif
+ init_lcd_operation();
+ check_seed_status();
+
+ /* wm_ready needs to be checked
+ * since display manager can be launched later than deviced.
+ * In the case, display cannot be turned on at the first booting */
+ wm_ready = check_wm_ready();
+ if (wm_ready)
+ lcd_on_procedure(LCD_NORMAL, LCD_ON_BY_EVENT);
+ else
+ add_timer_for_wm_ready();
+
+ if (display_conf.lcd_always_on) {
+ _I("LCD always on!");
+ trans_table[S_NORMAL][EVENT_TIMEOUT] = S_NORMAL;
+ }
+
+ if (flags & WITHOUT_STARTNOTI) { /* start without noti */
+ _I("Start Power managing without noti");
+ pm_cur_state = S_NORMAL;
+ set_setting_pmstate(pm_cur_state);
+
+ if (display_conf.timeout_enable) {
+ timeout = states[S_NORMAL].timeout;
+ /* check minimun lcd on time */
+ if (timeout < SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT))
+ timeout = SEC_TO_MSEC(DEFAULT_NORMAL_TIMEOUT);
+
+ reset_timeout(timeout);
+ }
+
+ status = DEVICE_OPS_STATUS_START;
+ /*
+ * Lock lcd off until booting is done.
+ * deviced guarantees all booting script is executing.
+ * Last script of booting unlocks this suspend blocking state.
+ */
+ pm_lock_internal(INTERNAL_LOCK_BOOTING, LCD_OFF,
+ STAY_CUR_STATE, BOOTING_DONE_WATING_TIME);
+ }
+
+ if (display_conf.input_support)
+ if (CHECK_OPS(keyfilter_ops, init))
+ keyfilter_ops->init();
+ }
+}
+
+static void display_exit(void *data)
+{
+ int i = INIT_END;
+
+ status = DEVICE_OPS_STATUS_STOP;
+
+ /* Set current state to S_NORMAL */
+ pm_cur_state = S_NORMAL;
+ set_setting_pmstate(pm_cur_state);
+ /* timeout is not needed */
+ reset_timeout(TIMEOUT_NONE);
+
+ if (CHECK_OPS(keyfilter_ops, exit))
+ keyfilter_ops->exit();
+
+ display_ops_exit(NULL);
+
+ for (i = i - 1; i >= INIT_SETTING; i--) {
+ switch (i) {
+ case INIT_SETTING:
+ exit_setting();
+ break;
+ case INIT_INTERFACE:
+ exit_sysfs();
+ break;
+ case INIT_POLL:
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ unregister_notifier(DEVICE_NOTIFIER_PROCESS_BACKGROUND, process_background);
+ unregister_notifier(DEVICE_NOTIFIER_PROCESS_FOREGROUND, process_foreground);
+
+ exit_input();
+ break;
+ }
+ }
+
+ exit_lcd_operation();
+ free_lock_info_list();
+
+ /* free display service */
+ display_service_free();
+
+ _I("Stop power manager");
+}
+
+static int display_start(enum device_flags flags)
+{
+ /* NORMAL MODE */
+ if (flags & NORMAL_MODE) {
+ if (flags & LCD_PANEL_OFF_MODE)
+ /* standby on */
+ backlight_ops.standby(true);
+ else
+ /* normal lcd on */
+ backlight_ops.on(flags);
+ return 0;
+ }
+
+ /* CORE LOGIC MODE */
+ if (!(flags & CORE_LOGIC_MODE))
+ return 0;
+
+ if (status == DEVICE_OPS_STATUS_START)
+ return -EALREADY;
+
+ if (display_probe(NULL) < 0)
+ return -EPERM;
+
+ display_init(NULL);
+
+ return 0;
+}
+
+static int display_stop(enum device_flags flags)
+{
+ /* NORMAL MODE */
+ if (flags & NORMAL_MODE) {
+ backlight_ops.off(flags);
+ return 0;
+ }
+
+ /* CORE LOGIC MODE */
+ if (!(flags & CORE_LOGIC_MODE))
+ return 0;
+
+ if (status == DEVICE_OPS_STATUS_STOP)
+ return -EALREADY;
+
+ display_exit(NULL);
+
+ return 0;
+}
+
+static int display_status(void)
+{
+ return status;
+}
+
+static const struct device_ops display_device_ops = {
+ .priority = DEVICE_PRIORITY_HIGH,
+ .name = "display",
+ .probe = display_probe,
+ .init = display_init,
+ .exit = display_exit,
+ .start = display_start,
+ .stop = display_stop,
+ .status = display_status,
+};
+
+DEVICE_OPS_REGISTER(&display_device_ops)
+
+/**
+ * @}
+ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/**
+ * @file core.h
+ * @brief Power manager main loop header file
+ */
+#ifndef __POWER_MANAGER_H__
+#define __POWER_MANAGER_H__
+
+#include "poll.h"
+#include "device-interface.h"
+#include "setting.h"
+
+#define WITHOUT_STARTNOTI 0x1
+#define MASK_BIT 0x7 /* 111 */
+#define MASK_NORMAL 0x1 /* 001 */
+#define MASK_DIM 0x2 /* 010 */
+#define MASK_OFF 0x4 /* 100 */
+
+#define VCALL_FLAG 0x00000001
+#define LOWBT_FLAG 0x00000100
+#define CHRGR_FLAG 0x00000200
+#define PWRSV_FLAG 0x00000400
+#define BRTCH_FLAG 0x00002000
+#define PWROFF_FLAG 0x00004000
+#define DIMSTAY_FLAG 0x00008000
+
+#define DEFAULT_NORMAL_TIMEOUT 30
+
+#define MASK32 0xffffffff
+
+#define CHECK_OPS(d, op) (d != NULL && d->op != NULL)
+
+#ifdef ENABLE_PM_LOG
+#define MAX_LOG_COUNT 250
+
+enum pm_log_type {
+ PM_LOG_MIN = 0,
+ PM_LOG_KEY_PRESS = PM_LOG_MIN, /* key log */
+ PM_LOG_KEY_LONG_PRESS,
+ PM_LOG_KEY_RELEASE,
+ PM_LOG_LCD_ON, /* lcd log */
+ PM_LOG_LCD_ON_FAIL,
+ PM_LOG_LCD_DIM,
+ PM_LOG_LCD_DIM_FAIL,
+ PM_LOG_LCD_OFF,
+ PM_LOG_LCD_OFF_FAIL,
+ PM_LOG_SLEEP,
+ PM_LOG_MAX
+};
+
+void pm_history_save(enum pm_log_type, int);
+#endif
+
+extern unsigned int pm_status_flag;
+
+/*
+ * State enumeration
+ */
+enum state_t {
+ S_START,
+ S_NORMAL, /*< normal state */
+ S_LCDON = S_NORMAL, /*< LCD on == normal state*/
+ S_LCDDIM, /*< LCD dimming */
+ S_LCDOFF, /*< LCD off */
+ S_STANDBY, /*< Standby */
+ S_SLEEP, /*< system suspend */
+ S_SUSPEND = S_SLEEP, /*< Suspend == Sleep state */
+ S_POWEROFF, /*< Power off */
+ S_END
+};
+
+/*
+ * Global variables
+ * pm_cur_state : current state
+ * states : state definitions
+ * trans_table : state transition table
+ */
+extern int pm_cur_state;
+extern int pm_old_state;
+
+/*
+ * @brief State structure
+ */
+struct state {
+ enum state_t state; /**< state number */
+ char *name; /**< state name (string) */
+ int (*trans) (int evt); /**< transition function pointer */
+ int (*action) (int timeout); /**< enter action */
+ int (*check) (int curr, int next); /**< transition check function */
+ Ecore_Task_Cb timeout_cb;
+ int timeout;
+};
+extern struct state states[S_END];
+
+/*
+ * @brief Configuration structure
+ */
+struct display_config {
+ double lock_wait_time;
+ double longpress_interval;
+ double lightsensor_interval;
+ int lcdoff_timeout;
+ int brightness_change_step;
+ int lcd_always_on;
+ int framerate_app[4];
+ int control_display;
+ int powerkey_doublepress;
+ int alpm_on;
+ int accel_sensor_on;
+ int continuous_sampling;
+ bool timeout_enable;
+ bool input_support;
+};
+
+/*
+ * Global variables
+ * display_conf : configuration of display
+ */
+extern struct display_config display_conf;
+
+/*
+ * @brief Display Extension features
+ */
+struct display_function_info {
+ void (*update_auto_brightness)(bool);
+ int (*set_autobrightness_min)(int, char *);
+ void (*reset_autobrightness_min)(const char *, void *data);
+ int (*face_detection)(int, int, int);
+};
+
+extern struct display_function_info display_info;
+
+struct display_keyfilter_ops {
+ void (*init)(void);
+ void (*exit)(void);
+ int (*check)(void *, int);
+ void (*set_powerkey_ignore)(int);
+ int (*powerkey_lcdoff)(void);
+ void (*backlight_enable)(bool);
+};
+
+extern const struct display_keyfilter_ops *keyfilter_ops;
+
+/* If the bit in a condition variable is set,
+ * we cannot transit the state until clear this bit. */
+int check_processes(enum state_t prohibit_state);
+extern struct state state[S_END];
+void reset_lcd_timeout(const char *sender, void *data);
+int check_lcdoff_lock_state(void);
+
+/* setting.c */
+int get_lock_screen_bg_state(void);
+int set_custom_lcdon_timeout(int timeout);
+void set_lock_screen_state(int state);
+void set_lock_screen_bg_state(bool state);
+
+/* core.c */
+void change_state_action(enum state_t state, int (*func)(int timeout));
+void change_state_trans(enum state_t state, int (*func)(int evt));
+void change_state_check(enum state_t state, int (*func)(int curr, int next));
+void change_state_name(enum state_t state, char *name);
+void change_trans_table(enum state_t state, enum state_t next);
+void change_proc_change_state(int (*func)(unsigned int cond, pid_t pid));
+
+bool check_lock_state(int state);
+
+int delete_condition(enum state_t state);
+void update_lcdoff_source(int source);
+int low_battery_state(int val);
+int set_lcd_timeout(int on, int dim, int holdkey_block, const char *name);
+void save_display_log(void);
+int custom_lcdon(int timeout);
+void set_stay_touchscreen_off(int val);
+void set_lcd_paneloff_mode(int val);
+void lcd_on_direct(enum device_flags flags);
+void lcd_off_procedure(enum device_flags flag);
+int check_holdkey_block(enum state_t state);
+bool touch_event_blocked(void);
+
+/* poll.c */
+int check_dimstay(int next_state, int flag);
+
+/* display-dbus.c */
+int init_pm_dbus(void);
+
+/**
+ * @}
+ */
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2015 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 <stdlib.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <math.h>
+#include <assert.h>
+#include <errno.h>
+#include <hw/display.h>
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/common.h"
+#include "util.h"
+#include "device-interface.h"
+#include "vconf.h"
+#include "core.h"
+#include "device-node.h"
+
+#define TOUCH_ON 1
+#define TOUCH_OFF 0
+
+#define LCD_PHASED_MIN_BRIGHTNESS 1
+#define LCD_PHASED_MAX_BRIGHTNESS 100
+#define LCD_PHASED_CHANGE_STEP 5
+#define LCD_PHASED_DELAY 35000 /* microsecond */
+
+#define POWER_AUTOSLEEP_PATH "/sys/power/autosleep"
+#define POWER_LOCK_PATH "/sys/power/wake_lock"
+#define POWER_UNLOCK_PATH "/sys/power/wake_unlock"
+#define POWER_WAKEUP_PATH "/sys/power/wakeup_count"
+#define POWER_STATE_PATH "/sys/power/state"
+
+enum {
+ POWER_UNLOCK = 0,
+ POWER_LOCK,
+};
+
+struct _backlight_ops backlight_ops;
+struct _power_ops power_ops;
+
+static bool custom_status;
+static int custom_brightness;
+static int force_brightness;
+static int default_brightness;
+
+static struct display_device *display_dev;
+
+#ifdef PROFILE_TV
+#include <sys/ioctl.h>
+#define PANEL_PATH "/dev/tztv_frc"
+#define FRC_IOCTL_CTRL_PVCC _IOWR('f', 0xAD, int)
+static int bl_onoff(int on)
+{
+ int fd, ret;
+ int value;
+
+ switch (on) {
+ case DPMS_ON:
+ value = 1;
+ break;
+ case DPMS_OFF:
+ case DPMS_STANDBY:
+ value = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fd = open(PANEL_PATH, O_RDWR);
+ if (fd == -1) {
+ ret = -errno;
+ _E("Failed to open panel path (%s, ret:%d)", PANEL_PATH, ret);
+ return ret;
+ }
+
+ ret = ioctl(fd, FRC_IOCTL_CTRL_PVCC, &value);
+ close(fd);
+
+ if (ret < 0) {
+ ret = -errno;
+ _E("ioctl() failed (%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static int bl_onoff(int on)
+{
+ return dpms_set_power(on);
+}
+#endif
+
+static int bl_brt(int brightness, int delay)
+{
+ int ret = -1;
+ int prev;
+
+ if (!display_dev ||
+ !display_dev->get_brightness ||
+ !display_dev->set_brightness) {
+ _E("there is no display device");
+ return -ENOENT;
+ }
+
+ if (delay > 0)
+ usleep(delay);
+
+ if (force_brightness > 0 && brightness != PM_DIM_BRIGHTNESS) {
+ _I("brightness(%d), force brightness(%d)",
+ brightness, force_brightness);
+ brightness = force_brightness;
+ }
+
+ ret = display_dev->get_brightness(&prev);
+
+ /* Update new brightness to vconf */
+ if (!ret && (brightness != prev)) {
+ vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, brightness);
+ }
+
+ /* Update device brightness */
+ ret = display_dev->set_brightness(brightness);
+
+ _I("set brightness %d, %d", brightness, ret);
+
+ return ret;
+}
+
+static int system_suspend(void)
+{
+ int ret;
+
+ _I("system suspend");
+ ret = sys_set_str(POWER_STATE_PATH, "mem");
+ _I("system resume (result : %d)", ret);
+ return 0;
+}
+
+static int system_enable_autosleep(void)
+{
+ _I("system autosleep enabled");
+ return sys_set_str(POWER_AUTOSLEEP_PATH, "mem");
+}
+
+static int system_power_lock(void)
+{
+ _I("system power lock");
+ return sys_set_str(POWER_LOCK_PATH, "mainlock");
+}
+
+static int system_power_unlock(void)
+{
+ _I("system power unlock");
+ return sys_set_str(POWER_UNLOCK_PATH, "mainlock");
+}
+
+static int system_get_power_lock_support(void)
+{
+ static int power_lock_support = -1;
+ int ret;
+
+ if (power_lock_support >= 0)
+ goto out;
+
+ ret = sys_check_node(POWER_LOCK_PATH);
+ if (ret < 0)
+ power_lock_support = false;
+ else
+ power_lock_support = true;
+
+ _I("system power lock : %s",
+ (power_lock_support ? "support" : "not support"));
+
+out:
+ return power_lock_support;
+}
+
+static int get_lcd_power(void)
+{
+ enum dpms_state state;
+ int ret;
+
+ ret = dpms_get_power(&state);
+ if (ret < 0)
+ return ret;
+
+ return state;
+}
+
+void change_brightness(int start, int end, int step)
+{
+ int diff, val;
+ int ret = -1;
+ int prev;
+
+ if (!display_dev ||
+ !display_dev->get_brightness) {
+ _E("there is no display device");
+ return;
+ }
+
+ if ((pm_status_flag & PWRSV_FLAG) &&
+ !(pm_status_flag & BRTCH_FLAG))
+ return;
+
+ ret = display_dev->get_brightness(&prev);
+ if (ret < 0) {
+ _E("fail to get brightness : %d", ret);
+ return;
+ }
+
+ if (prev == end)
+ return;
+
+ _D("start %d end %d step %d", start, end, step);
+
+ diff = end - start;
+
+ if (abs(diff) < step)
+ val = (diff > 0 ? 1 : -1);
+ else
+ val = (int)ceil((double)diff / step);
+
+ while (start != end) {
+ if (val == 0) break;
+
+ start += val;
+ if ((val > 0 && start > end) ||
+ (val < 0 && start < end))
+ start = end;
+
+ bl_brt(start, LCD_PHASED_DELAY);
+ }
+}
+
+#ifdef PROFILE_TV
+static int backlight_on(enum device_flags flags)
+{
+ int ret;
+
+ _I("LCD on %x", flags);
+
+ ret = bl_onoff(DPMS_ON);
+ if (ret < 0)
+ _E("Failed to turn on backlight (%d)", ret);
+
+ return ret;
+}
+
+static int backlight_off(enum device_flags flags)
+{
+ int ret;
+
+ _I("LCD off %x", flags);
+
+ ret = bl_onoff(DPMS_OFF);
+ if (ret < 0)
+ _E("Failed to turn off backlight (%d)", ret);
+
+ return ret;
+}
+#else
+static int backlight_on(enum device_flags flags)
+{
+ int ret = -1;
+ int i;
+
+ _D("LCD on %x", flags);
+
+ for (i = 0; i < PM_LCD_RETRY_CNT; i++) {
+ ret = bl_onoff(DPMS_ON);
+ if (get_lcd_power() == DPMS_ON) {
+#ifdef ENABLE_PM_LOG
+ pm_history_save(PM_LOG_LCD_ON, pm_cur_state);
+#endif
+ break;
+ } else {
+#ifdef ENABLE_PM_LOG
+ pm_history_save(PM_LOG_LCD_ON_FAIL, pm_cur_state);
+#endif
+ _E("Failed to LCD on, through OAL");
+ ret = -1;
+ }
+ }
+
+ if (flags & LCD_PHASED_TRANSIT_MODE)
+ change_brightness(LCD_PHASED_MIN_BRIGHTNESS,
+ default_brightness, LCD_PHASED_CHANGE_STEP);
+
+ return ret;
+}
+
+static int backlight_off(enum device_flags flags)
+{
+ int ret = -1;
+ int i;
+
+ _D("LCD off %x", flags);
+
+ if (flags & LCD_PHASED_TRANSIT_MODE)
+ change_brightness(default_brightness,
+ LCD_PHASED_MIN_BRIGHTNESS, LCD_PHASED_CHANGE_STEP);
+
+ for (i = 0; i < PM_LCD_RETRY_CNT; i++) {
+ usleep(30000);
+ ret = bl_onoff(DPMS_OFF);
+ if (get_lcd_power() == DPMS_OFF) {
+#ifdef ENABLE_PM_LOG
+ pm_history_save(PM_LOG_LCD_OFF, pm_cur_state);
+#endif
+ break;
+ } else {
+#ifdef ENABLE_PM_LOG
+ pm_history_save(PM_LOG_LCD_OFF_FAIL, pm_cur_state);
+#endif
+ _E("Failed to LCD off, through OAL");
+ ret = -1;
+ }
+ }
+ return ret;
+}
+#endif
+
+static int backlight_dim(void)
+{
+ int ret;
+
+ ret = bl_brt(PM_DIM_BRIGHTNESS, 0);
+#ifdef ENABLE_PM_LOG
+ if (!ret)
+ pm_history_save(PM_LOG_LCD_DIM, pm_cur_state);
+ else
+ pm_history_save(PM_LOG_LCD_DIM_FAIL, pm_cur_state);
+#endif
+ return ret;
+}
+
+static int set_custom_status(bool on)
+{
+ custom_status = on;
+ return 0;
+}
+
+static bool get_custom_status(void)
+{
+ return custom_status;
+}
+
+static int save_custom_brightness(void)
+{
+ int ret, brightness;
+
+ if (!display_dev ||
+ !display_dev->get_brightness) {
+ _E("there is no display device");
+ return -ENOENT;
+ }
+
+ ret = display_dev->get_brightness(&brightness);
+
+ custom_brightness = brightness;
+
+ return ret;
+}
+
+static int custom_backlight_update(void)
+{
+ int ret = 0;
+
+ if (custom_brightness < PM_MIN_BRIGHTNESS ||
+ custom_brightness > PM_MAX_BRIGHTNESS)
+ return -EINVAL;
+
+ if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG)) {
+ ret = backlight_dim();
+ } else {
+ _I("custom brightness restored! %d", custom_brightness);
+ ret = bl_brt(custom_brightness, 0);
+ }
+
+ return ret;
+}
+
+static int set_force_brightness(int level)
+{
+ if (level < 0 || level > PM_MAX_BRIGHTNESS)
+ return -EINVAL;
+
+ force_brightness = level;
+
+ return 0;
+}
+
+static int backlight_update(void)
+{
+ int ret = 0;
+
+ if (get_custom_status()) {
+ _I("custom brightness mode! brt no updated");
+ return 0;
+ }
+ if ((pm_status_flag & PWRSV_FLAG) && !(pm_status_flag & BRTCH_FLAG)) {
+ ret = backlight_dim();
+ } else {
+ ret = bl_brt(default_brightness, 0);
+ }
+ return ret;
+}
+
+static int backlight_standby(int force)
+{
+ int ret = -1;
+
+ if ((get_lcd_power() == DPMS_ON) || force) {
+ _I("LCD standby");
+ ret = bl_onoff(DPMS_STANDBY);
+ }
+
+ return ret;
+}
+
+static int set_default_brt(int level)
+{
+ if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS)
+ level = PM_DEFAULT_BRIGHTNESS;
+
+ default_brightness = level;
+
+ return 0;
+}
+
+static int check_wakeup_src(void)
+{
+ /* TODO if nedded.
+ * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
+ */
+ return EVENT_DEVICE;
+}
+
+static int get_wakeup_count(int *cnt)
+{
+ int ret;
+ int wakeup_count;
+
+ if (!cnt)
+ return -EINVAL;
+
+ ret = sys_get_int(POWER_WAKEUP_PATH, &wakeup_count);
+ if (ret < 0)
+ return ret;
+
+ *cnt = wakeup_count;
+ return 0;
+}
+
+static int set_wakeup_count(int cnt)
+{
+ int ret;
+
+ ret = sys_set_int(POWER_WAKEUP_PATH, cnt);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int get_max_brightness(void)
+{
+ static int max = -1;
+ int ret;
+
+ if (max > 0)
+ return max;
+
+ if (!display_dev) {
+ _E("there is no display device");
+ return -ENOENT;
+ }
+
+ if (!display_dev->get_max_brightness) {
+ max = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
+ return max;
+ }
+
+ ret = display_dev->get_max_brightness(&max);
+ if (ret < 0) {
+ _E("Failed to get max brightness (%d)", ret);
+ return ret;
+ }
+
+ return max;
+}
+
+static int set_brightness(int val)
+{
+ int max;
+
+ if (!display_dev || !display_dev->set_brightness) {
+ _E("there is no display device");
+ return -ENOENT;
+ }
+
+ max = get_max_brightness();
+ if (max < 0) {
+ _E("Failed to get max brightness");
+ return max;
+ }
+
+ /* Maximum Brightness to users is 100.
+ * Thus real brightness need to be calculated */
+ val = val * max / 100;
+
+ return display_dev->set_brightness(val);
+}
+
+static int get_brt_normalized(int brt_raw)
+{
+ int quotient, remainder;
+ int max;
+
+ max = get_max_brightness();
+ if (max < 0) {
+ _E("Failed to get max brightness");
+ return max;
+ }
+
+ /* Maximum Brightness to users is 100.
+ * Thus the brightness value need to be calculated using real brightness.
+ * ex) Let's suppose that the maximum brightness of driver is 255.
+ * case 1) When the user sets the brightness to 41,
+ * real brightness is
+ * 41 * 255 / 100 = 104.55 = 104 (rounded off)
+ * case 2) When the user gets the brightness,
+ * the driver returns the brightness 104.
+ * Thus the brightness to users is
+ * 104 * 100 / 255 = 40.7843.... = 41 (rounded up)
+ */
+ quotient = brt_raw * 100 / max;
+ remainder = brt_raw * 100 % max;
+ if (remainder > 0)
+ quotient++;
+
+ return quotient;
+}
+
+static int get_brightness(int *val)
+{
+ int brt, ret;
+
+ if (!display_dev || !display_dev->get_brightness) {
+ _E("there is no display device");
+ return -ENOENT;
+ }
+
+ ret = display_dev->get_brightness(&brt);
+ if (ret < 0) {
+ _E("failed to get brightness (%d)", ret);
+ return ret;
+ }
+
+ *val = get_brt_normalized(brt);
+ return 0;
+}
+
+static int get_brightness_by_light_sensor(float lmax, float lmin, float light, int *brt)
+{
+ int brt_raw;
+ int ret;
+
+ if (!display_dev || !display_dev->get_auto_brightness)
+ return -ENOTSUP;
+
+ ret = display_dev->get_auto_brightness(lmax, lmin, light, &brt_raw);
+ if (ret < 0) {
+ _E("failed to get brightness by light sensor(%d)", ret);
+ return ret;
+ }
+
+ *brt = get_brt_normalized(brt_raw);
+ return 0;
+}
+
+static int get_frame_rate(int *rate)
+{
+ if (!rate)
+ return -EINVAL;
+
+ if (!display_dev || !display_dev->get_frame_rate)
+ return -ENOTSUP;
+
+ return display_dev->get_frame_rate(rate);
+}
+
+static int set_frame_rate(int rate)
+{
+ int ret;
+ static int fmin = -1, fmax = -1;
+
+ if (!display_dev ||
+ !display_dev->set_frame_rate)
+ return -ENOTSUP;
+
+ if (display_dev->get_min_frame_rate) {
+ if (fmin < 0) {
+ ret = display_dev->get_min_frame_rate(&fmin);
+ if (ret < 0) {
+ _E("Failed to get min frate rate (%d)", ret);
+ return ret;
+ }
+ }
+ if (rate < fmin) {
+ _E("Invalid rate(%d)! (Valid rate: %d <= rate)", rate, fmin);
+ return -EINVAL;
+ }
+ }
+
+ if (display_dev->get_max_frame_rate) {
+ if (fmax < 0) {
+ ret = display_dev->get_max_frame_rate(&fmax);
+ if (ret < 0) {
+ _E("Failed to get max frate rate (%d)", ret);
+ return ret;
+ }
+ }
+ if (rate > fmax) {
+ _E("Invalid rate(%d)! (Valid rate: rate <= %d)", rate, fmax);
+ return -EINVAL;
+ }
+ }
+
+ return display_dev->set_frame_rate(rate);
+}
+
+static void _init_ops(void)
+{
+ backlight_ops.off = backlight_off;
+ backlight_ops.dim = backlight_dim;
+ backlight_ops.on = backlight_on;
+ backlight_ops.update = backlight_update;
+ backlight_ops.standby = backlight_standby;
+ backlight_ops.set_default_brt = set_default_brt;
+ backlight_ops.get_lcd_power = get_lcd_power;
+ backlight_ops.set_custom_status = set_custom_status;
+ backlight_ops.get_custom_status = get_custom_status;
+ backlight_ops.save_custom_brightness = save_custom_brightness;
+ backlight_ops.custom_update = custom_backlight_update;
+ backlight_ops.set_force_brightness = set_force_brightness;
+ backlight_ops.set_brightness = set_brightness;
+ backlight_ops.get_brightness = get_brightness;
+ backlight_ops.get_brightness_by_light_sensor = get_brightness_by_light_sensor;
+ backlight_ops.get_frame_rate = get_frame_rate;
+ backlight_ops.set_frame_rate = set_frame_rate;
+
+ power_ops.suspend = system_suspend;
+ power_ops.enable_autosleep = system_enable_autosleep;
+ power_ops.power_lock = system_power_lock;
+ power_ops.power_unlock = system_power_unlock;
+ power_ops.get_power_lock_support = system_get_power_lock_support;
+ power_ops.check_wakeup_src = check_wakeup_src;
+ power_ops.get_wakeup_count = get_wakeup_count;
+ power_ops.set_wakeup_count = set_wakeup_count;
+}
+
+int display_service_load(void)
+{
+ struct hw_info *info;
+ int r;
+
+ if (display_dev)
+ return 0;
+
+ r = hw_get_info(DISPLAY_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (r < 0) {
+ _I("display shared library is not supported: %d", r);
+ return 0;
+ }
+
+ if (!info->open) {
+ _E("fail to open display device : open(NULL)");
+ return -EPERM;
+ }
+
+ r = info->open(info, NULL, (struct hw_common **)&display_dev);
+ if (r < 0) {
+ _E("fail to get display device structure : %d", r);
+ return -EPERM;
+ }
+
+ _D("display device structure load success");
+ return 0;
+}
+
+int display_service_free(void)
+{
+ struct hw_info *info;
+
+ if (!display_dev)
+ return -ENOENT;
+
+ info = display_dev->common.info;
+
+ assert(info);
+
+ info->close((struct hw_common *)display_dev);
+ display_dev = NULL;
+
+ return 0;
+}
+
+int init_sysfs(unsigned int flags)
+{
+ _init_ops();
+ return 0;
+}
+
+int exit_sysfs(void)
+{
+ int fd;
+ const struct device_ops *ops = NULL;
+
+ fd = open("/tmp/sem.pixmap_1", O_RDONLY);
+ if (fd == -1) {
+ _E("X server disable");
+ backlight_on(NORMAL_MODE);
+ }
+
+ backlight_update();
+
+ ops = find_device("touchscreen");
+ if (!check_default(ops))
+ ops->start(NORMAL_MODE);
+
+ ops = find_device("touchkey");
+ if (!check_default(ops))
+ ops->start(NORMAL_MODE);
+
+ if (fd != -1)
+ close(fd);
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/**
+ * @file device-interface.h
+ * @brief backlight, touch, power devices interface module header
+ */
+#ifndef __DEVICE_INTERFACE_H__
+#define __DEVICE_INTERFACE_H__
+
+#include <stdbool.h>
+#include "core/devices.h"
+
+#define FLAG_X_DPMS 0x2
+
+#define DEFAULT_DISPLAY 0
+
+#define PM_MAX_BRIGHTNESS 100
+#define PM_MIN_BRIGHTNESS 1
+#define PM_DEFAULT_BRIGHTNESS 60
+#define PM_DIM_BRIGHTNESS 0
+
+#define PM_LCD_RETRY_CNT 3
+
+#define DISP_INDEX_SHIFT 16
+#define DISP_CMD(prop, index) ((index << DISP_INDEX_SHIFT) | prop)
+
+#define DEFAULT_DISPLAY_COUNT 1
+#define DEFAULT_DISPLAY_MAX_BRIGHTNESS 100
+
+/*
+ * Event type enumeration
+ */
+enum {
+ EVENT_TIMEOUT = 0, /*< time out event from timer */
+ EVENT_DEVICE = EVENT_TIMEOUT, /*< wake up by devices except input devices */
+ EVENT_INPUT, /*< input event from noti service */
+ EVENT_END,
+};
+
+int init_sysfs(unsigned int);
+int exit_sysfs(void);
+int display_service_load(void);
+int display_service_free(void);
+
+struct _backlight_ops {
+ int (*off)(enum device_flags);
+ int (*dim)(void);
+ int (*on)(enum device_flags);
+ int (*update)(void);
+ int (*standby)(int);
+ int (*set_default_brt)(int level);
+ int (*get_lcd_power)(void);
+ int (*set_custom_status)(bool on);
+ bool (*get_custom_status)(void);
+ int (*save_custom_brightness)(void);
+ int (*custom_update)(void);
+ int (*set_force_brightness)(int level);
+ int (*set_brightness)(int val);
+ int (*get_brightness)(int *val);
+ int (*get_brightness_by_light_sensor)(float lmax, float lmin, float light, int *brt);
+ int (*get_frame_rate)(int *rate);
+ int (*set_frame_rate)(int rate);
+};
+
+struct _power_ops {
+ int (*suspend)(void);
+ int (*enable_autosleep)(void);
+ int (*power_lock)(void);
+ int (*power_unlock)(void);
+ int (*get_power_lock_support)(void);
+ int (*check_wakeup_src)(void);
+ int (*get_wakeup_count)(int *cnt);
+ int (*set_wakeup_count)(int cnt);
+};
+
+extern struct _backlight_ops backlight_ops;
+extern struct _power_ops power_ops;
+
+enum dpms_state {
+ DPMS_ON, /* In use */
+ DPMS_STANDBY, /* Blanked, low power */
+ DPMS_SUSPEND, /* Blanked, lower power */
+ DPMS_OFF, /* Shut off, awaiting activity */
+};
+
+int dpms_set_power(enum dpms_state state);
+int dpms_get_power(enum dpms_state *state);
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 "util.h"
+#include "display-actor.h"
+#include "core/list.h"
+#include "core/common.h"
+
+static dd_list *actor_head;
+
+void display_add_actor(struct display_actor_ops *actor)
+{
+ DD_LIST_APPEND(actor_head, actor);
+}
+
+static struct display_actor_ops *display_find_actor(enum display_actor_id id)
+{
+ dd_list *elem;
+ struct display_actor_ops *actor;
+
+ DD_LIST_FOREACH(actor_head, elem, actor) {
+ if (actor->id == id)
+ return actor;
+ }
+ return NULL;
+}
+
+int display_set_caps(enum display_actor_id id, unsigned int caps)
+{
+ struct display_actor_ops *actor;
+
+ if (id <= 0 || !caps)
+ return -EINVAL;
+
+ actor = display_find_actor(id);
+ if (!actor)
+ return -EINVAL;
+
+ actor->caps |= caps;
+
+ return 0;
+}
+
+int display_reset_caps(enum display_actor_id id, unsigned int caps)
+{
+ struct display_actor_ops *actor;
+
+ if (id <= 0 || !caps)
+ return -EINVAL;
+
+ actor = display_find_actor(id);
+ if (!actor)
+ return -EINVAL;
+
+ actor->caps &= ~caps;
+
+ return 0;
+}
+
+unsigned int display_get_caps(enum display_actor_id id)
+{
+ struct display_actor_ops *actor;
+
+ if (id <= 0)
+ return 0;
+
+ actor = display_find_actor(id);
+ if (!actor)
+ return 0;
+
+ return actor->caps;
+}
+
+int display_has_caps(unsigned int total_caps, unsigned int caps)
+{
+ if (!total_caps || !caps)
+ return false;
+
+ if ((total_caps & caps) == caps)
+ return true;
+
+ return false;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 __DISPLAY_ACTOR_H__
+#define __DISPLAY_ACTOR_H__
+
+#include <errno.h>
+#include "core/common.h"
+
+enum display_actor_id {
+ DISPLAY_ACTOR_POWER_KEY = 1,
+ DISPLAY_ACTOR_MENU_KEY,
+ DISPLAY_ACTOR_API,
+ DISPLAY_ACTOR_GESTURE,
+};
+
+struct display_actor_ops {
+ enum display_actor_id id;
+ unsigned int caps;
+};
+
+enum display_capability {
+ DISPLAY_CAPA_BRIGHTNESS = 1 << 0,
+ DISPLAY_CAPA_LCDON = 1 << 1,
+ DISPLAY_CAPA_LCDOFF = 1 << 2,
+ DISPLAY_CAPA_POWEROFF = 1 << 3,
+};
+
+void display_add_actor(struct display_actor_ops *actor);
+int display_set_caps(enum display_actor_id id, unsigned int caps);
+int display_reset_caps(enum display_actor_id id, unsigned int caps);
+unsigned int display_get_caps(enum display_actor_id id);
+int display_has_caps(unsigned int total_caps, unsigned int caps);
+
+#endif
--- /dev/null
+[Display]
+# If this value is yes, LCD is turned off by lcd timeout.
+# If this value is no, LCD is turned off just by external requests.
+# Default value is yes.
+TimeoutEnable=no # yes or no
+
+# If this value is yes, input events such as screen touchs
+# and/or HW key inputs are supported.
+# Default value is yes.
+InputSupport=no # yes or no
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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.
+ */
+
+
+/**
+ * @file display-dbus.c
+ * @brief dbus interface
+ *
+ */
+
+#include <error.h>
+#include <stdbool.h>
+#include <Ecore.h>
+#include <device-node.h>
+
+#include "core/log.h"
+#include "util.h"
+#include "core.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "dd-display.h"
+#include "display-actor.h"
+#include "display-ops.h"
+
+#define TELEPHONY_PATH "/org/tizen/telephony/SAMSUNG_QMI"
+#define TELEPHONY_INTERFACE_SIM "org.tizen.telephony.Sim"
+#define SIGNAL_SIM_STATUS "Status"
+#define SIM_CARD_NOT_PRESENT (0x01)
+
+#define DISPLAY_DIM_BRIGHTNESS 0
+#define DUMP_MODE_WATING_TIME 600000
+
+static DBusMessage *edbus_start(E_DBus_Object *obj, DBusMessage *msg)
+{
+ static const struct device_ops *display_device_ops = NULL;
+
+ if (!display_device_ops)
+ display_device_ops = find_device("display");
+ if (NOT_SUPPORT_OPS(display_device_ops))
+ return dbus_message_new_method_return(msg);
+
+ display_device_ops->start(CORE_LOGIC_MODE);
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *edbus_stop(E_DBus_Object *obj, DBusMessage *msg)
+{
+ static const struct device_ops *display_device_ops = NULL;
+
+ if (!display_device_ops)
+ display_device_ops = find_device("display");
+ if (NOT_SUPPORT_OPS(display_device_ops))
+ return dbus_message_new_method_return(msg);
+
+ display_device_ops->stop(CORE_LOGIC_MODE);
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *edbus_lockstate(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *state_str;
+ char *option1_str;
+ char *option2_str;
+ int timeout;
+ pid_t pid;
+ int state;
+ int flag;
+ int ret;
+ unsigned int caps;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &state_str,
+ DBUS_TYPE_STRING, &option1_str,
+ DBUS_TYPE_STRING, &option2_str,
+ DBUS_TYPE_INT32, &timeout, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!state_str || timeout < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (!strcmp(state_str, PM_LCDON_STR))
+ state = LCD_NORMAL;
+ else if (!strcmp(state_str, PM_LCDDIM_STR))
+ state = LCD_DIM;
+ else if (!strcmp(state_str, PM_LCDOFF_STR))
+ state = LCD_OFF;
+ else {
+ _E("%s state is invalid, dbus ignored!", state_str);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!strcmp(option1_str, STAYCURSTATE_STR))
+ flag = STAY_CUR_STATE;
+ else if (!strcmp(option1_str, GOTOSTATENOW_STR))
+ flag = GOTO_STATE_NOW;
+ else {
+ _E("%s option is invalid. set default option!", option1_str);
+ flag = STAY_CUR_STATE;
+ }
+
+ if (!strcmp(option2_str, HOLDKEYBLOCK_STR))
+ flag |= HOLD_KEY_BLOCK;
+
+ if (flag & GOTO_STATE_NOW) {
+ caps = display_get_caps(DISPLAY_ACTOR_API);
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDON) &&
+ state == LCD_NORMAL) {
+ _D("No lcdon capability!");
+ ret = -EPERM;
+ goto out;
+ }
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDOFF) &&
+ state == LCD_OFF) {
+ _D("No lcdoff capability!");
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
+ if (check_dimstay(state, flag) == true) {
+ _E("LCD state can not be changed to OFF state now!");
+ flag &= ~GOTO_STATE_NOW;
+ flag |= STAY_CUR_STATE;
+ }
+
+ ret = pm_lock_internal(pid, state, flag, timeout);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_unlockstate(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *state_str;
+ char *option_str;
+ pid_t pid;
+ int state;
+ int flag;
+ int ret;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &state_str,
+ DBUS_TYPE_STRING, &option_str, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!state_str) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (!strcmp(state_str, PM_LCDON_STR))
+ state = LCD_NORMAL;
+ else if (!strcmp(state_str, PM_LCDDIM_STR))
+ state = LCD_DIM;
+ else if (!strcmp(state_str, PM_LCDOFF_STR))
+ state = LCD_OFF;
+ else {
+ _E("%s state is invalid, dbus ignored!", state_str);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!strcmp(option_str, SLEEP_MARGIN_STR))
+ flag = PM_SLEEP_MARGIN;
+ else if (!strcmp(option_str, RESET_TIMER_STR))
+ flag = PM_RESET_TIMER;
+ else if (!strcmp(option_str, KEEP_TIMER_STR))
+ flag = PM_KEEP_TIMER;
+ else {
+ _E("%s option is invalid. set default option!", option_str);
+ flag = PM_RESET_TIMER;
+ }
+
+ ret = pm_unlock_internal(pid, state, flag);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_changestate(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *state_str;
+ pid_t pid;
+ int state;
+ int ret;
+ unsigned int caps;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &state_str, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!state_str) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (!strcmp(state_str, PM_LCDON_STR))
+ state = LCD_NORMAL;
+ else if (!strcmp(state_str, PM_LCDDIM_STR))
+ state = LCD_DIM;
+ else if (!strcmp(state_str, PM_LCDOFF_STR))
+ state = LCD_OFF;
+ else if (!strcmp(state_str, PM_STANDBY_STR))
+ state = STANDBY;
+ else if (!strcmp(state_str, PM_SUSPEND_STR))
+ state = SUSPEND;
+ else {
+ _E("%s state is invalid, dbus ignored!", state_str);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ caps = display_get_caps(DISPLAY_ACTOR_API);
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDON) &&
+ state == LCD_NORMAL) {
+ _D("No lcdon capability!");
+ ret = -EPERM;
+ goto out;
+ }
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDOFF) &&
+ state == LCD_OFF) {
+ _D("No lcdoff capability!");
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (check_dimstay(state, GOTO_STATE_NOW) == true) {
+ _E("LCD state can not be changed to OFF state!");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = pm_change_internal(pid, state);
+
+ if (!ret && state == LCD_OFF)
+ update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_TIMEOUT);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_getdisplaycount(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = DEFAULT_DISPLAY_COUNT;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_getmaxbrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = DEFAULT_DISPLAY_MAX_BRIGHTNESS;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_setmaxbrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = -ENOTSUP;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_getbrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int brt, ret;
+
+ ret = backlight_ops.get_brightness(&brt);
+ if (ret >= 0)
+ ret = brt;
+
+ _I("get brightness %d, %d", brt, ret);
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_setbrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int brt, autobrt, ret, caps;
+
+ caps = display_get_caps(DISPLAY_ACTOR_API);
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_BRIGHTNESS)) {
+ _D("No brightness changing capability!");
+ ret = -EPERM;
+ goto error;
+ }
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_get_basic(&iter, &brt);
+
+ if (brt == DISPLAY_DIM_BRIGHTNESS) {
+ _E("application can not set this value(DIM VALUE:%d)", brt);
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &autobrt) != 0) {
+ _E("Failed to get VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT value");
+ autobrt = SETTING_BRIGHTNESS_AUTOMATIC_OFF;
+ }
+
+ if (autobrt == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
+ _E("auto_brightness state is ON, can not change the brightness value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ ret = backlight_ops.set_brightness(brt);
+ if (ret < 0)
+ goto error;
+ if (vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt) != 0)
+ _E("Failed to set VCONFKEY_SETAPPL_LCD_BRIGHTNESS value");
+
+ if (vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, brt) != 0)
+ _E("Failed to set VCONFKEY_PM_CURRENT_BRIGHTNESS value");
+
+ _I("set brightness %d, %d", brt, ret);
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_holdbrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int brt, autobrt, ret, caps;
+
+ caps = display_get_caps(DISPLAY_ACTOR_API);
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_BRIGHTNESS)) {
+ _D("No brightness changing capability!");
+ ret = -EPERM;
+ goto error;
+ }
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_get_basic(&iter, &brt);
+
+ if (brt == DISPLAY_DIM_BRIGHTNESS) {
+ _E("application can not set this value(DIM VALUE:%d)", brt);
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &autobrt) != 0) {
+ _E("Failed to get VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT value");
+ autobrt = SETTING_BRIGHTNESS_AUTOMATIC_OFF;
+ }
+
+ vconf_set_int(VCONFKEY_PM_CUSTOM_BRIGHTNESS_STATUS, VCONFKEY_PM_CUSTOM_BRIGHTNESS_ON);
+
+ ret = backlight_ops.set_brightness(brt);
+ if (ret < 0)
+ goto error;
+
+ if (autobrt == SETTING_BRIGHTNESS_AUTOMATIC_ON) {
+ _D("Auto brightness will be paused");
+ vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, SETTING_BRIGHTNESS_AUTOMATIC_PAUSE);
+ }
+
+ if (vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, brt) != 0)
+ _E("Failed to set VCONFKEY_PM_CURRENT_BRIGHTNESS value");
+
+ _I("hold brightness %d, %d", brt, ret);
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+
+}
+
+static DBusMessage *edbus_releasebrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int bat, charger, changed, setting, brt, autobrt, ret = 0;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat) != 0) {
+ _E("Failed to get VCONFKEY_SYSMAN_BATTERY_STATUS_LOW value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &charger) != 0) {
+ _E("Failed to get VCONFKEY_SYSMAN_CHARGER_STATUS value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM, &changed) != 0) {
+ _E("Failed to get VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, &setting) != 0) {
+ _E("Failed to get VCONFKEY_SETAPPL_LCD_BRIGHTNESS value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &autobrt) != 0) {
+ _E("Failed to get VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT value");
+ ret = -EPERM;
+ goto error;
+ }
+
+ vconf_set_int(VCONFKEY_PM_CUSTOM_BRIGHTNESS_STATUS, VCONFKEY_PM_CUSTOM_BRIGHTNESS_OFF);
+
+ ret = backlight_ops.get_brightness(&brt);
+ if (ret < 0)
+ brt = ret;
+
+ // check dim state
+ if (low_battery_state(bat) &&
+ charger == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED && !changed) {
+ _D("batt warning low : brightness is not changed!");
+ if (brt != 0) {
+ backlight_ops.set_brightness(0);
+ }
+ goto error;
+ }
+
+ if (autobrt == SETTING_BRIGHTNESS_AUTOMATIC_OFF) {
+ if (brt != setting) {
+ backlight_ops.set_brightness(setting);
+ if (vconf_set_int(VCONFKEY_PM_CURRENT_BRIGHTNESS, setting) != 0) {
+ _E("Failed to set VCONFKEY_PM_CURRENT_BRIGHTNESS value");
+ }
+ }
+ } else if (autobrt == SETTING_BRIGHTNESS_AUTOMATIC_PAUSE) {
+ _D("Auto brightness will be enable");
+ vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, SETTING_BRIGHTNESS_AUTOMATIC_ON);
+ }
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_setrefreshrate(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int app, val, ret, control;
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &app,
+ DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _I("there is no message");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (app < 0 || app >= ARRAY_SIZE(display_conf.framerate_app) || val < 0) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!display_conf.framerate_app[app]) {
+ _I("This case(%d) is not support in this target", app);
+ ret = -EPERM;
+ goto error;
+ }
+
+ control = display_conf.control_display;
+
+ if (control)
+ backlight_ops.off(NORMAL_MODE);
+
+ _D("app : %d, value : %d", app, val);
+ ret = backlight_ops.set_frame_rate(val);
+ if (ret < 0)
+ _E("Failed to set frame rate (%d)", ret);
+
+ if (control)
+ backlight_ops.on(NORMAL_MODE);
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_setautobrightnessmin(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int val, ret;
+ pid_t pid;
+ const char *sender;
+
+ sender = dbus_message_get_sender(msg);
+ if (!sender) {
+ _E("invalid sender name!");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (!display_info.set_autobrightness_min) {
+ ret = -EIO;
+ goto error;
+ }
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_get_basic(&iter, &val);
+
+ pid = get_edbus_sender_pid(msg);
+ ret = display_info.set_autobrightness_min(val, (char *)sender);
+ if (ret) {
+ _W("fail to set autobrightness min %d, %d by %d", val, ret, pid);
+ goto error;
+ }
+ if (display_info.reset_autobrightness_min) {
+ register_edbus_watch(sender,
+ display_info.reset_autobrightness_min, NULL);
+ _I("set autobrightness min %d by %d", val, pid);
+ }
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_setlcdtimeout(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int on, dim, holdkey_block, ret;
+ pid_t pid;
+ const char *sender;
+
+ sender = dbus_message_get_sender(msg);
+ if (!sender) {
+ _E("invalid sender name!");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &on,
+ DBUS_TYPE_INT32, &dim, DBUS_TYPE_INT32, &holdkey_block,
+ DBUS_TYPE_INVALID);
+
+ pid = get_edbus_sender_pid(msg);
+ ret = set_lcd_timeout(on, dim, holdkey_block, sender);
+ if (ret) {
+ _W("fail to set lcd timeout %d by %d", ret, pid);
+ } else {
+ register_edbus_watch(sender,
+ reset_lcd_timeout, NULL);
+ _I("set lcd timeout on %d, dim %d, holdblock %d by %d",
+ on, dim, holdkey_block, pid);
+ }
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_lockscreenbgon(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ char *on;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &on,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to update lcdscreen bg on state %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(on, "true"))
+ update_pm_setting(SETTING_LOCK_SCREEN_BG, true);
+ else if (!strcmp(on, "false"))
+ update_pm_setting(SETTING_LOCK_SCREEN_BG, false);
+ else
+ ret = -EINVAL;
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_dumpmode(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ char *on;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &on,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to get dumpmode state %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(on, "on"))
+ pm_lock_internal(INTERNAL_LOCK_DUMPMODE, LCD_OFF,
+ STAY_CUR_STATE, DUMP_MODE_WATING_TIME);
+ else if (!strcmp(on, "off"))
+ pm_unlock_internal(INTERNAL_LOCK_DUMPMODE, LCD_OFF,
+ PM_SLEEP_MARGIN);
+ else
+ ret = -EINVAL;
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_savelog(E_DBus_Object *obj, DBusMessage *msg)
+{
+ save_display_log();
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *edbus_powerkeyignore(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ int on;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &on,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to get powerkey ignore %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (CHECK_OPS(keyfilter_ops, set_powerkey_ignore))
+ keyfilter_ops->set_powerkey_ignore(on == 1 ? true : false);
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_powerkeylcdoff(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ if (CHECK_OPS(keyfilter_ops, powerkey_lcdoff))
+ ret = keyfilter_ops->powerkey_lcdoff();
+ else
+ ret = -ENOSYS;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_customlcdon(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ int timeout;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &timeout,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to get custom lcd timeout %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = custom_lcdon(timeout);
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_staytouchscreenoff(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ int val;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &val,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to get stay touchscreen off state %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ set_stay_touchscreen_off(val);
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_lcdpaneloffmode(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ int val;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &val,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to get lcd panel off mode %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ set_lcd_paneloff_mode(val);
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_actorcontrol(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0, val, actor;
+ char *op;
+
+ ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &op,
+ DBUS_TYPE_INT32, &actor, DBUS_TYPE_INT32, &val,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("fail to update actor control %d", ret);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!strcmp(op, "set"))
+ ret = display_set_caps(actor, val);
+ else if (!strcmp(op, "reset"))
+ ret = display_reset_caps(actor, val);
+ else
+ ret = -EINVAL;
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *edbus_getcustombrightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int status = 0;
+
+ status = backlight_ops.get_custom_status();
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &status);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "start", NULL, NULL, edbus_start },
+ { "stop", NULL, NULL, edbus_stop },
+ { "lockstate", "sssi", "i", edbus_lockstate },
+ { "unlockstate", "ss", "i", edbus_unlockstate },
+ { "changestate", "s", "i", edbus_changestate },
+ { "ChangeState", "s", "i", edbus_changestate },
+ { "getbrightness", NULL, "i", edbus_getbrightness }, /* deprecated */
+ { "setbrightness", "i", "i", edbus_setbrightness }, /* deprecated */
+ { "setframerate", "ii", "i", edbus_setrefreshrate }, /* deprecated */
+ { "setautobrightnessmin", "i", "i", edbus_setautobrightnessmin },
+ { "setlcdtimeout", "iii", "i", edbus_setlcdtimeout },
+ { "LockScreenBgOn", "s", "i", edbus_lockscreenbgon },
+ { "GetDisplayCount", NULL, "i", edbus_getdisplaycount },
+ { "GetMaxBrightness", NULL, "i", edbus_getmaxbrightness },
+ { "SetMaxBrightness", "i", "i", edbus_setmaxbrightness },
+ { "GetBrightness", NULL, "i", edbus_getbrightness },
+ { "SetBrightness", "i", "i", edbus_setbrightness },
+ { "HoldBrightness", "i", "i", edbus_holdbrightness },
+ { "ReleaseBrightness", NULL, "i", edbus_releasebrightness },
+ { "SetRefreshRate", "ii", "i", edbus_setrefreshrate },
+ { "Dumpmode", "s", "i", edbus_dumpmode },
+ { "SaveLog", NULL, NULL, edbus_savelog },
+ { "PowerKeyIgnore", "i", NULL, edbus_powerkeyignore },
+ { "PowerKeyLCDOff", NULL, "i", edbus_powerkeylcdoff },
+ { "CustomLCDOn", "i", "i", edbus_customlcdon },
+ { "StayTouchScreenOff", "i", "i", edbus_staytouchscreenoff },
+ { "LCDPanelOffMode", "i", "i", edbus_lcdpaneloffmode },
+ { "ActorControl", "sii", "i", edbus_actorcontrol },
+ { "CustomBrightness", NULL, "i", edbus_getcustombrightness },
+ { "CurrentBrightness", NULL, "i", edbus_getbrightness }, /* deprecated. It is remained for tizen 2.4 */
+ /* Add methods here */
+};
+
+static void sim_signal_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ int ret, val;
+ static int state = false;
+
+ if (!find_display_feature("auto-brightness")) {
+ _D("auto brightness is not supported!");
+ return;
+ }
+
+ if (state)
+ return;
+
+ ret = dbus_message_is_signal(msg, TELEPHONY_INTERFACE_SIM,
+ SIGNAL_SIM_STATUS);
+ if (!ret) {
+ _E("there is no power off popup signal");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ }
+
+ if (val != SIM_CARD_NOT_PRESENT) {
+ state = true;
+ vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS,
+ PM_DEFAULT_BRIGHTNESS);
+ _I("SIM card is inserted at first!");
+ }
+}
+
+/*
+ * Default capability
+ * api := LCDON | LCDOFF | BRIGHTNESS
+ * gesture := LCDON
+ */
+static struct display_actor_ops display_api_actor = {
+ .id = DISPLAY_ACTOR_API,
+ .caps = DISPLAY_CAPA_LCDON |
+ DISPLAY_CAPA_LCDOFF |
+ DISPLAY_CAPA_BRIGHTNESS,
+};
+
+static struct display_actor_ops display_gesture_actor = {
+ .id = DISPLAY_ACTOR_GESTURE,
+ .caps = DISPLAY_CAPA_LCDON,
+};
+
+int init_pm_dbus(void)
+{
+ int ret;
+
+ display_add_actor(&display_api_actor);
+ display_add_actor(&display_gesture_actor);
+
+ ret = register_edbus_method(DEVICED_PATH_DISPLAY,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0) {
+ _E("Failed to register edbus method! %d", ret);
+ return ret;
+ }
+/*
+ * Auto-brightness feature has been implemented in wearable-device.
+ * But UX is not determined yet. Thus this logic can be modified
+ * when UX concept related to sim is changed
+ */
+ ret = register_edbus_signal_handler(TELEPHONY_PATH,
+ TELEPHONY_INTERFACE_SIM, SIGNAL_SIM_STATUS,
+ sim_signal_handler);
+ if (ret < 0 && ret != -EEXIST) {
+ _E("Failed to register signal handler! %d", ret);
+ return ret;
+ }
+ return 0;
+}
--- /dev/null
+[Display]
+# If this value is yes, LCD is always on except pressing power key.
+# Default value is no, LCD is turned off by lcd timeout.
+LCDAlwaysOn=yes # yes or no
+
+# If this value is yes, LCD is turned off by lcd timeout.
+# If this value is no, LCD is turned off just by external requests.
+# Default value is yes.
+TimeoutEnable=no # yes or no
+
+# If this value is yes, input events such as screen touchs
+# and/or HW key inputs are supported.
+# Default value is yes.
+InputSupport=no # yes or no
+
+# Use Accelator sensor when autobrightness is on.
+AccelSensorOn=no # yes or no
--- /dev/null
+[Display]
+# deviced is pending lcd on until lock screen shows.
+# This is the maximum pending time.
+LockScreenWaitingTime=0.3 #second
+
+# Power-off popup is launched when power key is long pressed.
+# This is duration of pressing power key.
+LongPressInterval=0.4 #second
+
+# This is polling time of auto brightness.
+LightSensorSamplingInterval=1 #second
+
+# display state is changed to SLEEP state after this time.
+# If this value is large, it causes power consumption problem.
+LCDOffTimeout=500 # milli second
+
+# This is n step of auto brightness.
+# If brightness is change from a to b, brightness's changed n times from a to b.
+BrightnessChangeStep=10
+
+# If this value is yes, LCD is always on except pressing power key.
+# Default value is no, LCD is turned off by lcd timeout.
+LCDAlwaysOn=no # yes or no
+
+# Just below application only allow to change display frame rate.
+# refer to enum refresh_app
+ChangedFrameRateAllowed=setting # setting
+ControlDisplay=yes # yes or no
+
+# LCD is not turned off when this value is yes and key double pressed
+PowerKeyDoublePressSupport=no # yes or no
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 "util.h"
+#include "display-ops.h"
+#include "core/list.h"
+#include "core/common.h"
+
+static dd_list *disp_head;
+
+void add_display(const struct display_ops *disp)
+{
+ DD_LIST_APPEND(disp_head, disp);
+}
+
+void remove_display(const struct display_ops *disp)
+{
+ DD_LIST_REMOVE(disp_head, disp);
+}
+
+const struct display_ops *find_display_feature(const char *name)
+{
+ dd_list *elem;
+ const struct display_ops *disp;
+
+ DD_LIST_FOREACH(disp_head, elem, disp) {
+ if (!strcmp(disp->name, name))
+ return disp;
+ }
+ return NULL;
+}
+
+void display_ops_init(void *data)
+{
+ dd_list *elem;
+ const struct display_ops *disp;
+
+ DD_LIST_FOREACH(disp_head, elem, disp) {
+ _D("[%s] initialize", disp->name);
+ if (disp->init)
+ disp->init(data);
+ }
+}
+
+void display_ops_exit(void *data)
+{
+ dd_list *elem;
+ const struct display_ops *disp;
+
+ DD_LIST_FOREACH(disp_head, elem, disp) {
+ _D("[%s] deinitialize", disp->name);
+ if (disp->exit)
+ disp->exit(data);
+ }
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DISPLAY_OPS_H__
+#define __DISPLAY_OPS_H__
+
+#include <errno.h>
+#include "core/common.h"
+
+struct display_ops {
+ char *name;
+ void (*init) (void *data);
+ void (*exit) (void *data);
+};
+
+void display_ops_init(void *data);
+void display_ops_exit(void *data);
+
+#define DISPLAY_OPS_REGISTER(disp) \
+static void __CONSTRUCTOR__ module_init(void) \
+{ \
+ add_display(disp); \
+} \
+static void __DESTRUCTOR__ module_exit(void) \
+{ \
+ remove_display(disp); \
+}
+
+void add_display(const struct display_ops *disp);
+void remove_display(const struct display_ops *disp);
+const struct display_ops *find_display_feature(const char *name);
+
+#endif
--- /dev/null
+[Display]
+# If this value is yes, LCD is always on except pressing power key.
+# Default value is no, LCD is turned off by lcd timeout.
+LCDAlwaysOn=yes # yes or no
+
+# If this value is yes, LCD is turned off by lcd timeout.
+# If this value is no, LCD is turned off just by external requests.
+# Default value is yes.
+TimeoutEnable=no # yes or no
+
+# If this value is yes, input events such as screen touchs
+# and/or HW key inputs are supported.
+# Default value is yes.
+InputSupport=no # yes or no
--- /dev/null
+[Display]
+# deviced is pending lcd on until lock screen shows.
+# This is the maximum pending time.
+LockScreenWaitingTime=0.3 #second
+
+# Power-off popup is launched when power key is long pressed.
+# This is duration of pressing power key.
+LongPressInterval=0.4 #second
+
+# This is polling time of auto brightness.
+LightSensorSamplingInterval=1 #second
+
+# display state is changed to SLEEP state after this time.
+# If this value is large, it causes power consumption problem.
+LCDOffTimeout=500 # milli second
+
+# This is n step of auto brightness.
+# If brightness is change from a to b, brightness's changed n times from a to b.
+BrightnessChangeStep=10
+
+# If this value is yes, LCD is always on except pressing power key.
+# Default value is no, LCD is turned off by lcd timeout.
+LCDAlwaysOn=no # yes or no
+
+# Just below application only allow to change display frame rate.
+# refer to enum refresh_app
+ChangedFrameRateAllowed=all # all
+ControlDisplay=no # yes or no
+
+# LCD is not turned off when this value is yes and key double pressed
+PowerKeyDoublePressSupport=yes # yes or no
+
+# Use Accelator sensor when autobrightness is on.
+AccelSensorOn=no # yes or no
+
+# Use Continuous Sampling when autobrightness is on.
+ContinuousSampling=no # yes or no
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 "core/edbus-handler.h"
+#include "device-interface.h"
+
+#define ENLIGHTENMENT_BUS_NAME "org.enlightenment.wm"
+#define ENLIGHTENMENT_OBJECT_PATH "/org/enlightenment/wm"
+#define ENLIGHTENMENT_INTERFACE_NAME ENLIGHTENMENT_BUS_NAME".dpms"
+
+int dpms_set_power(enum dpms_state state)
+{
+ char *arr[1];
+ char str[32];
+ int ret;
+
+ snprintf(str, sizeof(str), "%d", state);
+ arr[0] = str;
+ ret = dbus_method_sync(ENLIGHTENMENT_BUS_NAME,
+ ENLIGHTENMENT_OBJECT_PATH,
+ ENLIGHTENMENT_INTERFACE_NAME,
+ "set", "u", arr);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int dpms_get_power(enum dpms_state *state)
+{
+ int ret;
+
+ if (!state)
+ return -EINVAL;
+
+ ret = dbus_method_sync(ENLIGHTENMENT_BUS_NAME,
+ ENLIGHTENMENT_OBJECT_PATH,
+ ENLIGHTENMENT_INTERFACE_NAME,
+ "get", NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ *state = ret;
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <errno.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/dpms.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "device-interface.h"
+
+static CARD16 modes[] = {
+ [DPMS_ON] = DPMSModeOn,
+ [DPMS_STANDBY] = DPMSModeStandby,
+ [DPMS_SUSPEND] = DPMSModeSuspend,
+ [DPMS_OFF] = DPMSModeOff,
+};
+
+static CARD16 dpms_state_to_DPMSMode(enum dpms_state state)
+{
+ if (state < 0 || state > DPMS_OFF)
+ state = DPMS_OFF;
+
+ return modes[state];
+}
+
+static enum dpms_state DPMSMode_to_dpms_state(CARD16 state)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(modes); ++i) {
+ if (modes[i] == state)
+ return i;
+ }
+
+ return DPMS_OFF;
+}
+
+int dpms_set_power(enum dpms_state state)
+{
+ Display *dpy;
+
+ if (state < DPMS_ON || state > DPMS_OFF)
+ return -EINVAL;
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy) {
+ _E("fail to open display");
+ return -EPERM;
+ }
+
+ DPMSEnable(dpy);
+ DPMSForceLevel(dpy, dpms_state_to_DPMSMode(state));
+
+ XCloseDisplay(dpy);
+ return 0;
+}
+
+int dpms_get_power(enum dpms_state *state)
+{
+ Display *dpy;
+ int dummy;
+ CARD16 dpms_state = DPMSModeOff;
+ BOOL onoff;
+
+ if (!state)
+ return -EINVAL;
+
+ dpy = XOpenDisplay(NULL);
+ if (dpy == NULL) {
+ _E("fail to open display");
+ return -EPERM;
+ }
+
+ if (DPMSQueryExtension(dpy, &dummy, &dummy)) {
+ if (DPMSCapable(dpy))
+ DPMSInfo(dpy, &dpms_state, &onoff);
+ }
+
+ XCloseDisplay(dpy);
+
+ *state = DPMSMode_to_dpms_state(dpms_state);
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <fcntl.h>
+#include <sys/stat.h>
+#include <linux/input.h>
+#include <libinput.h>
+#include <Ecore.h>
+#include "util.h"
+#include "core.h"
+#include "poll.h"
+
+#define SEAT_NAME "seat0"
+
+static struct udev *udev;
+static struct libinput *li;
+static Ecore_Fd_Handler *efd;
+
+int (*pm_callback) (int, PMMsg *);
+
+static inline void process_event(struct libinput_event *ev)
+{
+ static const struct device_ops *display_device_ops;
+ struct input_event input;
+ struct libinput *li;
+ struct libinput_event_keyboard *k;
+ unsigned int time;
+ int fd;
+
+ if (!pm_callback)
+ return;
+
+ if (!display_device_ops) {
+ display_device_ops = find_device("display");
+ if (!display_device_ops)
+ return;
+ }
+
+ /* do not operate when display stops */
+ if (device_get_status(display_device_ops)
+ != DEVICE_OPS_STATUS_START) {
+ _E("display status is stop");
+ return;
+ }
+
+ switch (libinput_event_get_type(ev)) {
+ case LIBINPUT_EVENT_DEVICE_ADDED:
+ return;
+ case LIBINPUT_EVENT_KEYBOARD_KEY:
+ k = libinput_event_get_keyboard_event(ev);
+ time = libinput_event_keyboard_get_time(k);
+ li = libinput_event_get_context(ev);
+
+ input.time.tv_sec = MSEC_TO_SEC(time);
+ input.time.tv_usec = MSEC_TO_USEC(time % 1000);
+ input.type = EV_KEY;
+ input.code = libinput_event_keyboard_get_key(k);
+ input.value = libinput_event_keyboard_get_key_state(k);
+
+ fd = libinput_get_fd(li);
+ _D("time %d.%d type %d code %d value %d fd %d",
+ input.time.tv_sec, input.time.tv_usec, input.type,
+ input.code, input.value, fd);
+
+ if (CHECK_OPS(keyfilter_ops, check) &&
+ keyfilter_ops->check(&input, fd) != 0)
+ return;
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION:
+ case LIBINPUT_EVENT_POINTER_BUTTON:
+ case LIBINPUT_EVENT_POINTER_AXIS:
+ li = libinput_event_get_context(ev);
+ input.type = EV_REL;
+
+ fd = libinput_get_fd(li);
+ _D("time %d.%d type %d code %d value %d fd %d",
+ input.time.tv_sec, input.time.tv_usec, input.type,
+ input.code, input.value, fd);
+
+ if (CHECK_OPS(keyfilter_ops, check) &&
+ keyfilter_ops->check(&input, fd) != 0)
+ return;
+ break;
+ case LIBINPUT_EVENT_TOUCH_DOWN:
+ case LIBINPUT_EVENT_TOUCH_UP:
+ case LIBINPUT_EVENT_TOUCH_MOTION:
+ case LIBINPUT_EVENT_TOUCH_FRAME:
+ if (touch_event_blocked())
+ return ;
+ break;
+ default:
+ break;
+ }
+
+ /* lcd on or update lcd timeout */
+ (*pm_callback) (INPUT_POLL_EVENT, NULL);
+}
+
+static Eina_Bool input_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ struct libinput_event *ev;
+ struct libinput *input = (struct libinput *)data;
+
+ if (!input)
+ return ECORE_CALLBACK_RENEW;
+
+ libinput_dispatch(input);
+
+ while ((ev = libinput_get_event(input))) {
+ process_event(ev);
+
+ libinput_event_destroy(ev);
+ libinput_dispatch(input);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int open_restricted(const char *path, int flags, void *user_data)
+{
+ int fd;
+ unsigned int clockid = CLOCK_MONOTONIC;
+
+ if (!path)
+ return -EINVAL;
+
+ fd = open(path, flags);
+ if (fd >= 0) {
+ /* TODO Why does fd change the clock? */
+ if (ioctl(fd, EVIOCSCLOCKID, &clockid) < 0)
+ _E("fail to change clock %s", path);
+ }
+
+ return fd < 0 ? -errno : fd;
+}
+
+static void close_restricted(int fd, void *user_data)
+{
+ close(fd);
+}
+
+static const struct libinput_interface interface = {
+ .open_restricted = open_restricted,
+ .close_restricted = close_restricted,
+};
+
+int init_input(void)
+{
+ int ret;
+ int fd;
+
+ udev = udev_new();
+ if (!udev) {
+ _E("fail to create udev library context");
+ return -EPERM;
+ }
+
+ li = libinput_udev_create_context(&interface, NULL, udev);
+ if (!li) {
+ _E("fail to create a new libinput context from udev");
+ return -EPERM;
+ }
+
+ ret = libinput_udev_assign_seat(li, SEAT_NAME);
+ if (ret < 0) {
+ _E("fail to assign a seat");
+ return -EPERM;
+ }
+
+ fd = libinput_get_fd(li);
+ if (fd < 0) {
+ _E("fail to get file descriptor from libinput context");
+ return -EPERM;
+ }
+
+ /* add to poll handler */
+ efd = ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ input_handler,
+ (void *)((intptr_t)li), NULL, NULL);
+ if (!efd) {
+ _E("fail to add fd handler");
+ /* TODO Does it really need close()? */
+ close(fd);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+int exit_input(void)
+{
+ if (efd)
+ ecore_main_fd_handler_del(efd);
+
+ if (li)
+ libinput_unref(li);
+
+ if (udev)
+ udev_unref(udev);
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <vconf.h>
+#include <Ecore.h>
+#include "util.h"
+#include "core.h"
+#include "poll.h"
+#include "device-node.h"
+#include "display-actor.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "core/edbus-handler.h"
+#include "power/power-handler.h"
+#include "led/touch-key.h"
+
+#include <linux/input.h>
+#ifndef KEY_SCREENLOCK
+#define KEY_SCREENLOCK 0x98
+#endif
+#ifndef SW_GLOVE
+#define SW_GLOVE 0x16
+#endif
+
+#define PREDEF_LEAVESLEEP "leavesleep"
+#define POWEROFF_ACT "poweroff"
+#define PWROFF_POPUP_ACT "pwroff-popup"
+#define USEC_PER_SEC 1000000
+#define COMBINATION_INTERVAL 0.5 /* 0.5 second */
+
+#define KEY_MAX_DELAY_TIME 700 /* ms */
+
+#define KEY_RELEASED 0
+#define KEY_PRESSED 1
+#define KEY_BEING_PRESSED 2
+
+#define KEY_COMBINATION_STOP 0
+#define KEY_COMBINATION_START 1
+#define KEY_COMBINATION_SCREENCAPTURE 2
+
+#define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
+#define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
+#define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
+
+#define TOUCH_RELEASE (-1)
+
+#define GLOVE_MODE 1
+
+int __WEAK__ get_glove_state(void);
+void __WEAK__ switch_glove_key(int val);
+
+static struct timeval pressed_time;
+static Ecore_Timer *longkey_timeout_id = NULL;
+static Ecore_Timer *combination_timeout_id = NULL;
+static int cancel_lcdoff;
+static int key_combination = KEY_COMBINATION_STOP;
+static int menu_pressed = false;
+static bool touch_pressed = false;
+static int skip_lcd_off = false;
+static bool powerkey_pressed = false;
+static const struct device_ops *touchled;
+
+static inline int current_state_in_on(void)
+{
+ return (pm_cur_state == S_LCDDIM || pm_cur_state == S_NORMAL);
+}
+
+static inline void restore_custom_brightness(void)
+{
+ if (pm_cur_state == S_LCDDIM &&
+ backlight_ops.get_custom_status())
+ backlight_ops.custom_update();
+}
+
+static int power_execute(void *data)
+{
+ static const struct device_ops *ops = NULL;
+
+ FIND_DEVICE_INT(ops, POWER_OPS_NAME);
+
+ return ops->execute(data);
+}
+
+static void longkey_pressed()
+{
+ char *opt;
+ unsigned int caps;
+
+ _I("Power key long pressed!");
+ cancel_lcdoff = 1;
+
+ caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
+
+ if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
+ /* change state - LCD on */
+ pm_change_internal(getpid(), LCD_NORMAL);
+ (*pm_callback)(INPUT_POLL_EVENT, NULL);
+ }
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDOFF)) {
+ _D("No poweroff capability!");
+ return;
+ }
+
+ opt = PWROFF_POPUP_ACT;
+ power_execute(opt);
+}
+
+static Eina_Bool longkey_pressed_cb(void *data)
+{
+ longkey_pressed();
+ longkey_timeout_id = NULL;
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool combination_failed_cb(void *data)
+{
+ key_combination = KEY_COMBINATION_STOP;
+ combination_timeout_id = NULL;
+
+ return EINA_FALSE;
+}
+
+static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
+{
+ unsigned long udiff;
+
+ udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
+ udiff += (t2.tv_usec - t1.tv_usec);
+
+ return udiff;
+}
+
+static void stop_key_combination(void)
+{
+ key_combination = KEY_COMBINATION_STOP;
+ if (combination_timeout_id > 0) {
+ ecore_timer_del(combination_timeout_id);
+ combination_timeout_id = NULL;
+ }
+}
+
+static inline void check_key_pair(int code, int new, int *old)
+{
+ if (new == *old)
+ _E("key pair is not matched! (%d, %d)", code, new);
+ else
+ *old = new;
+}
+
+static inline void broadcast_lcdon_by_powerkey(void)
+{
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_LCDON_BY_POWERKEY, NULL, NULL);
+}
+
+static inline void broadcast_lcdoff_by_powerkey(void)
+{
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_LCDOFF_BY_POWERKEY, NULL, NULL);
+}
+
+static inline bool switch_on_lcd(void)
+{
+ if (current_state_in_on())
+ return false;
+
+ if (backlight_ops.get_lcd_power() == DPMS_ON)
+ return false;
+
+ broadcast_lcdon_by_powerkey();
+
+ lcd_on_direct(LCD_ON_BY_POWER_KEY);
+
+ return true;
+}
+
+static inline void switch_off_lcd(void)
+{
+ if (!current_state_in_on())
+ return;
+
+ if (backlight_ops.get_lcd_power() == DPMS_OFF)
+ return;
+
+ broadcast_lcdoff_by_powerkey();
+
+ lcd_off_procedure(LCD_OFF_BY_POWER_KEY);
+}
+
+static void process_combination_key(struct input_event *pinput)
+{
+ if (pinput->value == KEY_PRESSED) {
+ if (key_combination == KEY_COMBINATION_STOP) {
+ key_combination = KEY_COMBINATION_START;
+ combination_timeout_id = ecore_timer_add(
+ COMBINATION_INTERVAL,
+ (Ecore_Task_Cb)combination_failed_cb, NULL);
+ } else if (key_combination == KEY_COMBINATION_START) {
+ if (combination_timeout_id > 0) {
+ ecore_timer_del(combination_timeout_id);
+ combination_timeout_id = NULL;
+ }
+ if (longkey_timeout_id > 0) {
+ ecore_timer_del(longkey_timeout_id);
+ longkey_timeout_id = NULL;
+ }
+ _I("capture mode");
+ key_combination = KEY_COMBINATION_SCREENCAPTURE;
+ skip_lcd_off = true;
+ }
+ menu_pressed = true;
+ } else if (pinput->value == KEY_RELEASED) {
+ if (key_combination != KEY_COMBINATION_SCREENCAPTURE)
+ stop_key_combination();
+ menu_pressed = false;
+ }
+}
+
+
+static int process_menu_key(struct input_event *pinput)
+{
+ int caps;
+
+ caps = display_get_caps(DISPLAY_ACTOR_MENU_KEY);
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
+ if (current_state_in_on()) {
+ process_combination_key(pinput);
+ return false;
+ }
+ _D("No lcd-on capability!");
+ return true;
+ } else if (pinput->value == KEY_PRESSED) {
+ switch_on_lcd();
+ }
+
+ process_combination_key(pinput);
+
+ return false;
+}
+
+static int decide_lcdoff(void)
+{
+ /* It's not needed if it's already LCD off state */
+ if (!current_state_in_on() &&
+ backlight_ops.get_lcd_power() != DPMS_ON)
+ return false;
+
+ /*
+ * This flag is set at the moment
+ * that LCD is turned on by power key
+ * LCD has not to turned off in the situation.
+ */
+ if (skip_lcd_off)
+ return false;
+
+ /* LCD is not turned off when powerkey is pressed,not released */
+ if (powerkey_pressed)
+ return false;
+
+ /* LCD-off is blocked at the moment poweroff popup shows */
+ if (cancel_lcdoff)
+ return false;
+
+ /* LCD-off is blocked at the moment volumedown key is pressed */
+ if (menu_pressed)
+ return false;
+
+ /* LCD-off is blocked when powerkey and volmedown key are pressed */
+ if (key_combination == KEY_COMBINATION_SCREENCAPTURE)
+ return false;
+
+ return true;
+}
+
+static int lcdoff_powerkey(void)
+{
+ int ignore = true;
+
+ if (decide_lcdoff() == true) {
+ check_processes(S_NORMAL);
+ check_processes(S_LCDDIM);
+
+ if (!check_holdkey_block(S_NORMAL) &&
+ !check_holdkey_block(S_LCDDIM)) {
+ if (display_info.update_auto_brightness)
+ display_info.update_auto_brightness(false);
+ switch_off_lcd();
+ delete_condition(S_NORMAL);
+ delete_condition(S_LCDDIM);
+ update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
+ pm_change_internal(getpid(), LCD_OFF);
+ }
+ } else {
+ ignore = false;
+ }
+ cancel_lcdoff = 0;
+
+ return ignore;
+}
+
+static int process_power_key(struct input_event *pinput)
+{
+ int ignore = true;
+ static int value = KEY_RELEASED;
+ unsigned int caps;
+
+ caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
+
+ switch (pinput->value) {
+ case KEY_RELEASED:
+ powerkey_pressed = false;
+ check_key_pair(pinput->code, pinput->value, &value);
+
+ if (!display_conf.powerkey_doublepress) {
+ if (display_has_caps(caps, DISPLAY_CAPA_LCDOFF))
+ ignore = lcdoff_powerkey();
+ else
+ _D("No lcdoff capability!");
+ } else if (skip_lcd_off) {
+ ignore = false;
+ }
+
+ if (!display_has_caps(caps, DISPLAY_CAPA_LCDON))
+ ignore = true;
+
+ stop_key_combination();
+ if (longkey_timeout_id > 0) {
+ ecore_timer_del(longkey_timeout_id);
+ longkey_timeout_id = NULL;
+ }
+
+ break;
+ case KEY_PRESSED:
+ powerkey_pressed = true;
+ if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
+ skip_lcd_off = switch_on_lcd();
+ } else {
+ _D("No lcdon capability!");
+ skip_lcd_off = false;
+ }
+ check_key_pair(pinput->code, pinput->value, &value);
+ _I("power key pressed");
+ pressed_time.tv_sec = (pinput->time).tv_sec;
+ pressed_time.tv_usec = (pinput->time).tv_usec;
+ if (key_combination == KEY_COMBINATION_STOP) {
+ /* add long key timer */
+ longkey_timeout_id = ecore_timer_add(
+ display_conf.longpress_interval,
+ (Ecore_Task_Cb)longkey_pressed_cb, NULL);
+ key_combination = KEY_COMBINATION_START;
+ combination_timeout_id = ecore_timer_add(
+ COMBINATION_INTERVAL,
+ (Ecore_Task_Cb)combination_failed_cb, NULL);
+ } else if (key_combination == KEY_COMBINATION_START) {
+ if (combination_timeout_id > 0) {
+ ecore_timer_del(combination_timeout_id);
+ combination_timeout_id = NULL;
+ }
+ _I("capture mode");
+ key_combination = KEY_COMBINATION_SCREENCAPTURE;
+ skip_lcd_off = true;
+ ignore = false;
+ }
+ if (skip_lcd_off)
+ ignore = false;
+ cancel_lcdoff = 0;
+
+ break;
+ case KEY_BEING_PRESSED:
+ if (timediff_usec(pressed_time, pinput->time) >
+ (display_conf.longpress_interval * USEC_PER_SEC))
+ longkey_pressed();
+ break;
+ }
+ return ignore;
+}
+
+static int process_screenlock_key(struct input_event *pinput)
+{
+ if (pinput->value != KEY_RELEASED) {
+ stop_key_combination();
+ return true;
+ }
+
+ if (!current_state_in_on())
+ return false;
+
+ check_processes(S_NORMAL);
+ check_processes(S_LCDDIM);
+
+ if (!check_holdkey_block(S_NORMAL) && !check_holdkey_block(S_LCDDIM)) {
+ delete_condition(S_NORMAL);
+ delete_condition(S_LCDDIM);
+ update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
+
+ /* LCD off forcly */
+ pm_change_internal(-1, LCD_OFF);
+ }
+
+ return true;
+}
+
+static void sound_vibrate_hardkey(void)
+{
+ /* device notify(vibrator) */
+ /* sound(dbus) */
+ /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangedHardKey signal */
+ broadcast_edbus_signal(DEVICED_PATH_KEY, DEVICED_INTERFACE_KEY,
+ SIGNAL_CHANGE_HARDKEY, NULL, NULL);
+}
+
+static void process_hardkey_backlight(struct input_event *pinput)
+{
+ int opt;
+
+ _E("pinput->value : %d", pinput->value);
+ if (pinput->value == KEY_PRESSED) {
+ if (touch_pressed) {
+ _I("Touch is pressed, then hard key is not working!");
+ return;
+ }
+ /* Sound & Vibrate only in unlock state */
+ if (get_lock_screen_state() == VCONFKEY_IDLE_UNLOCK
+ || get_lock_screen_bg_state())
+ sound_vibrate_hardkey();
+
+ if (touchled && touchled->execute) {
+ opt = TOUCHLED_PRESS;
+ touchled->execute(&opt);
+ }
+ } else if (pinput->value == KEY_RELEASED) {
+ /* if lockscreen is idle lock */
+ if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK) {
+ _D("Lock state, key backlight is off when phone is unlocked!");
+ return;
+ }
+
+ if (touchled && touchled->execute) {
+ opt = TOUCHLED_RELEASE;
+ touchled->execute(&opt);
+ }
+ }
+}
+
+static int check_key(struct input_event *pinput, int fd)
+{
+ int ignore = true;
+
+ switch (pinput->code) {
+ case KEY_MENU:
+ ignore = process_menu_key(pinput);
+ break;
+ case KEY_POWER:
+ ignore = process_power_key(pinput);
+ break;
+ case KEY_SCREENLOCK:
+ ignore = process_screenlock_key(pinput);
+ break;
+ case KEY_BACK:
+ case KEY_PHONE:
+ stop_key_combination();
+ if (current_state_in_on()) {
+ process_hardkey_backlight(pinput);
+ ignore = false;
+ }
+ break;
+ case KEY_VOLUMEUP:
+ case KEY_VOLUMEDOWN:
+ case KEY_CAMERA:
+ case KEY_EXIT:
+ case KEY_CONFIG:
+ case KEY_MEDIA:
+ case KEY_MUTE:
+ case KEY_PLAYPAUSE:
+ case KEY_PLAYCD:
+ case KEY_PAUSECD:
+ case KEY_STOPCD:
+ case KEY_NEXTSONG:
+ case KEY_PREVIOUSSONG:
+ case KEY_REWIND:
+ case KEY_FASTFORWARD:
+ stop_key_combination();
+ if (current_state_in_on())
+ ignore = false;
+ break;
+ case 0x1DB:
+ case 0x1DC:
+ case 0x1DD:
+ case 0x1DE:
+ stop_key_combination();
+ break;
+ default:
+ stop_key_combination();
+ ignore = false;
+ }
+#ifdef ENABLE_PM_LOG
+ if (pinput->value == KEY_PRESSED)
+ pm_history_save(PM_LOG_KEY_PRESS, pinput->code);
+ else if (pinput->value == KEY_RELEASED)
+ pm_history_save(PM_LOG_KEY_RELEASE, pinput->code);
+#endif
+ return ignore;
+}
+
+static int check_key_filter(void *data, int fd)
+{
+ struct input_event *pinput = data;
+ int ignore = true;
+ static int old_fd, code, value;
+
+ assert(pinput);
+
+ switch (pinput->type) {
+ case EV_KEY:
+ if (pinput->code == BTN_TOUCH &&
+ pinput->value == KEY_RELEASED)
+ touch_pressed = false;
+ /*
+ * Normally, touch press/release events don't occur
+ * in lcd off state. But touch release events can occur
+ * in the state abnormally. Then touch events are ignored
+ * when lcd is off state.
+ */
+ if (pinput->code == BTN_TOUCH && !current_state_in_on())
+ break;
+ if (pinput->code == code && pinput->value == value) {
+ _E("Same key(%d, %d) is polled [%d,%d]",
+ code, value, old_fd, fd);
+ }
+ old_fd = fd;
+ code = pinput->code;
+ value = pinput->value;
+
+ ignore = check_key(pinput, fd);
+ restore_custom_brightness();
+
+ break;
+ case EV_REL:
+ ignore = false;
+ break;
+ case EV_ABS:
+ if (current_state_in_on())
+ ignore = false;
+ restore_custom_brightness();
+
+ touch_pressed =
+ (pinput->value == TOUCH_RELEASE ? false : true);
+ break;
+ case EV_SW:
+ if (!get_glove_state || !switch_glove_key)
+ break;
+ if (pinput->code == SW_GLOVE &&
+ get_glove_state() == GLOVE_MODE) {
+ switch_glove_key(pinput->value);
+ }
+ break;
+ }
+
+ if (ignore)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Default capability
+ * powerkey := LCDON | LCDOFF | POWEROFF
+ * homekey := LCDON
+ */
+static struct display_actor_ops display_powerkey_actor = {
+ .id = DISPLAY_ACTOR_POWER_KEY,
+ .caps = DISPLAY_CAPA_LCDON |
+ DISPLAY_CAPA_LCDOFF |
+ DISPLAY_CAPA_POWEROFF,
+};
+
+static struct display_actor_ops display_menukey_actor = {
+ .id = DISPLAY_ACTOR_MENU_KEY,
+ .caps = DISPLAY_CAPA_LCDON,
+};
+
+static void keyfilter_init(void)
+{
+ display_add_actor(&display_powerkey_actor);
+ display_add_actor(&display_menukey_actor);
+
+ touchled = find_device(TOUCHLED_NAME);
+}
+
+static void key_backlight_enable(bool enable)
+{
+ int opt;
+
+ if (!touchled || !touchled->execute)
+ return;
+
+ if (enable)
+ opt = TOUCHLED_DIRECT_ON;
+ else
+ opt = TOUCHLED_DIRECT_OFF;
+
+ touchled->execute(&opt);
+}
+
+static const struct display_keyfilter_ops normal_keyfilter_ops = {
+ .init = keyfilter_init,
+ .check = check_key_filter,
+ .set_powerkey_ignore = NULL,
+ .powerkey_lcdoff = NULL,
+ .backlight_enable = key_backlight_enable,
+};
+const struct display_keyfilter_ops *keyfilter_ops = &normal_keyfilter_ops;
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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.
+ */
+
+
+/**
+ * @file lock-detector.c
+ * @brief
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "util.h"
+#include "core.h"
+#include "core/list.h"
+
+struct lock_info {
+ unsigned long hash;
+ char *name;
+ int state;
+ int count;
+ long locktime;
+ long unlocktime;
+ long time;
+};
+
+#define LIMIT_COUNT 128
+
+static dd_list *lock_info_list;
+
+static long get_time(void)
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return (long)(now.tv_sec * 1000 + now.tv_usec / 1000);
+}
+
+static void shrink_lock_info_list(void)
+{
+ dd_list *l, *l_prev;
+ struct lock_info *info;
+ unsigned int count;
+
+ count = DD_LIST_LENGTH(lock_info_list);
+ if (count <= LIMIT_COUNT)
+ return;
+ _D("list is shrink : count %d", count);
+
+ DD_LIST_REVERSE_FOREACH_SAFE(lock_info_list, l, l_prev, info) {
+ if (info->locktime == 0) {
+ DD_LIST_REMOVE_LIST(lock_info_list, l);
+ if (info->name)
+ free(info->name);
+ free(info);
+ count--;
+ }
+ if (count <= (LIMIT_COUNT / 2))
+ break;
+ }
+}
+
+int set_lock_time(const char *pname, int state)
+{
+ struct lock_info *info;
+ dd_list *l;
+ unsigned long val;
+
+ if (!pname)
+ return -EINVAL;
+
+ if (state < S_NORMAL || state > S_SLEEP)
+ return -EINVAL;
+
+ val = g_str_hash(pname);
+
+ DD_LIST_FOREACH(lock_info_list, l, info)
+ if (info->hash == val &&
+ !strncmp(info->name, pname, strlen(pname)+1) &&
+ info->state == state) {
+ info->count += 1;
+ if (info->locktime == 0)
+ info->locktime = get_time();
+ info->unlocktime = 0;
+ DD_LIST_REMOVE(lock_info_list, info);
+ DD_LIST_PREPEND(lock_info_list, info);
+ return 0;
+ }
+
+ info = malloc(sizeof(struct lock_info));
+ if (!info) {
+ _E("Malloc is failed for lock_info!");
+ return -ENOMEM;
+ }
+
+ info->hash = val;
+ info->name = strndup(pname, strlen(pname));
+ info->state = state;
+ info->count = 1;
+ info->locktime = get_time();
+ info->unlocktime = 0;
+ info->time = 0;
+
+ DD_LIST_APPEND(lock_info_list, info);
+
+ return 0;
+}
+
+int set_unlock_time(const char *pname, int state)
+{
+ bool find = false;
+ long diff;
+ struct lock_info *info;
+ dd_list *l;
+ unsigned long val;
+
+ if (!pname)
+ return -EINVAL;
+
+ if (state < S_NORMAL || state > S_SLEEP)
+ return -EINVAL;
+
+ val = g_str_hash(pname);
+
+ DD_LIST_FOREACH(lock_info_list, l, info)
+ if (info->hash == val &&
+ !strncmp(info->name, pname, strlen(pname)+1) &&
+ info->state == state) {
+ DD_LIST_REMOVE(lock_info_list, info);
+ DD_LIST_PREPEND(lock_info_list, info);
+ find = true;
+ break;
+ }
+
+ if (!find)
+ return -EINVAL;
+
+ if (info->locktime == 0)
+ return -EINVAL;
+
+ /* update time */
+ info->unlocktime = get_time();
+ diff = info->unlocktime - info->locktime;
+ if (diff > 0)
+ info->time += diff;
+ info->locktime = 0;
+
+ if (DD_LIST_LENGTH(lock_info_list) > LIMIT_COUNT)
+ shrink_lock_info_list();
+
+ return 0;
+}
+
+void free_lock_info_list(void)
+{
+ dd_list *l, *l_next;
+ struct lock_info *info;
+
+ if (!lock_info_list)
+ return;
+
+ DD_LIST_FOREACH_SAFE(lock_info_list, l, l_next, info) {
+ DD_LIST_REMOVE(lock_info_list, info);
+ if (info->name)
+ free(info->name);
+ free(info);
+ }
+ lock_info_list = NULL;
+}
+
+void print_lock_info_list(int fd)
+{
+ struct lock_info *info;
+ dd_list *l;
+ char buf[255];
+ int ret;
+
+ if (!lock_info_list)
+ return;
+
+ snprintf(buf, sizeof(buf),
+ "current time : %ld ms\n", get_time());
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ snprintf(buf, sizeof(buf),
+ "[%10s %6s] %6s %10s %10s %10s %s\n", "hash", "state",
+ "count", "locktime", "unlocktime", "time", "process name");
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+
+ DD_LIST_FOREACH(lock_info_list, l, info) {
+ long time = 0;
+ if (info->locktime != 0 && info->unlocktime == 0)
+ time = get_time() - info->locktime;
+ snprintf(buf, sizeof(buf),
+ "[%10lu %6d] %6d %10ld %10ld %10ld %s\n",
+ info->hash,
+ info->state,
+ info->count,
+ info->locktime,
+ info->unlocktime,
+ info->time + time,
+ info->name);
+ ret = write(fd, buf, strlen(buf));
+ if (ret < 0)
+ _E("write() failed (%d)", errno);
+ }
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/**
+ * @file lock-detector.h
+ * @brief
+ *
+ */
+
+#ifndef _LOCK_DETECTOR_H_
+#define _LOCK_DETECTOR_H_
+
+int set_lock_time(const char *pname, int state);
+int set_unlock_time(const char *pname, int state);
+void free_lock_info_list(void);
+void print_lock_info_list(int fd);
+
+#endif //_LOCK_DETECTOR_H_
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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.
+ */
+
+
+/**
+ * @file poll.c
+ * @brief Power Manager poll implementation
+ *
+ */
+
+#include <stdio.h>
+#include "util.h"
+#include "core.h"
+#include "poll.h"
+
+#define SHIFT_UNLOCK 4
+#define SHIFT_UNLOCK_PARAMETER 12
+#define SHIFT_CHANGE_STATE 8
+#define SHIFT_CHANGE_TIMEOUT 20
+#define LOCK_FLAG_SHIFT 16
+#define __HOLDKEY_BLOCK_BIT 0x1
+#define HOLDKEY_BLOCK_BIT (__HOLDKEY_BLOCK_BIT << LOCK_FLAG_SHIFT)
+
+static PMMsg recv_data;
+
+int check_dimstay(int next_state, int flag)
+{
+ if (next_state != LCD_OFF)
+ return false;
+
+ if (!(flag & GOTO_STATE_NOW))
+ return false;
+
+ if (!(pm_status_flag & DIMSTAY_FLAG))
+ return false;
+
+ return true;
+}
+
+static enum state_t get_state(int s_bits)
+{
+ switch (s_bits) {
+ case LCD_NORMAL:
+ return S_NORMAL;
+ case LCD_DIM:
+ return S_LCDDIM;
+ case LCD_OFF:
+ return S_LCDOFF;
+ case STANDBY:
+ return S_STANDBY;
+ case SUSPEND:
+ return S_SLEEP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static bool state_supported(enum state_t st)
+{
+ if (states[st].trans)
+ return true;
+ return false;
+}
+
+int pm_lock_internal(pid_t pid, int s_bits, int flag, int timeout)
+{
+ int cond;
+
+ if (!pm_callback)
+ return -1;
+
+ cond = get_state(s_bits);
+ if (cond < 0)
+ return cond;
+
+ if (!state_supported(cond))
+ return -ENOTSUP;
+
+ cond = SET_COND_REQUEST(cond, PM_REQUEST_LOCK);
+
+ if (flag & GOTO_STATE_NOW)
+ /* if the flag is true, go to the locking state directly */
+ cond = SET_COND_FLAG(cond, PM_REQUEST_CHANGE);
+
+ if (flag & HOLD_KEY_BLOCK)
+ cond = SET_COND_FLAG(cond, PM_FLAG_BLOCK_HOLDKEY);
+
+ recv_data.pid = pid;
+ recv_data.cond = cond;
+ recv_data.timeout = timeout;
+
+ (*pm_callback)(PM_CONTROL_EVENT, &recv_data);
+
+ return 0;
+}
+
+int pm_unlock_internal(pid_t pid, int s_bits, int flag)
+{
+ int cond;
+
+ if (!pm_callback)
+ return -1;
+
+ cond = get_state(s_bits);
+ if (cond < 0)
+ return cond;
+
+ if (!state_supported(cond))
+ return -ENOTSUP;
+
+ cond = SET_COND_REQUEST(cond, PM_REQUEST_UNLOCK);
+
+ if (flag & PM_KEEP_TIMER)
+ cond = SET_COND_FLAG(cond, PM_FLAG_KEEP_TIMER);
+
+ if (flag & PM_RESET_TIMER)
+ cond = SET_COND_FLAG(cond, PM_FLAG_RESET_TIMER);
+
+ recv_data.pid = pid;
+ recv_data.cond = cond;
+ recv_data.timeout = 0;
+
+ (*pm_callback)(PM_CONTROL_EVENT, &recv_data);
+
+ return 0;
+}
+
+int pm_change_internal(pid_t pid, int s_bits)
+{
+ int cond;
+
+ if (!pm_callback)
+ return -1;
+
+ cond = get_state(s_bits);
+ if (cond < 0)
+ return cond;
+
+ if (!state_supported(cond))
+ return -ENOTSUP;
+
+ cond = SET_COND_REQUEST(cond, PM_REQUEST_CHANGE);
+
+ recv_data.pid = pid;
+ recv_data.cond = cond;
+ recv_data.timeout = 0;
+
+ (*pm_callback)(PM_CONTROL_EVENT, &recv_data);
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/**
+ * @file poll.h
+ * @brief Power Manager input device poll implementation
+ *
+ */
+
+#ifndef __PM_POLL_H__
+#define __PM_POLL_H__
+
+#include <Ecore.h>
+#include "core/edbus-handler.h"
+/**
+ * @addtogroup POWER_MANAGER
+ * @{
+ */
+
+enum {
+ INPUT_POLL_EVENT = -9,
+ SIDEKEY_POLL_EVENT,
+ PWRKEY_POLL_EVENT,
+ PM_CONTROL_EVENT,
+};
+
+enum {
+ INTERNAL_LOCK_BASE = 100000,
+ INTERNAL_LOCK_BATTERY,
+ INTERNAL_LOCK_BATTERY_FULL,
+ INTERNAL_LOCK_BOOTING,
+ INTERNAL_LOCK_DUMPMODE,
+ INTERNAL_LOCK_HDMI,
+ INTERNAL_LOCK_ODE,
+ INTERNAL_LOCK_POPUP,
+ INTERNAL_LOCK_SOUNDDOCK,
+ INTERNAL_LOCK_TIME,
+ INTERNAL_LOCK_USB,
+ INTERNAL_LOCK_POWEROFF,
+ INTERNAL_LOCK_SUSPEND,
+ INTERNAL_LOCK_COOL_DOWN,
+ INTERNAL_LOCK_LOWBAT,
+};
+
+#define SIGNAL_NAME_LCD_CONTROL "lcdcontol"
+
+#define LCD_NORMAL 0x01 /**< NORMAL state */
+#define LCD_DIM 0x02 /**< LCD dimming state */
+#define LCD_OFF 0x04 /**< LCD off state */
+#define SUSPEND 0x08 /**< Suspend state */
+#define POWER_OFF 0x10 /**< Sleep state */
+#define STANDBY 0x20 /**< Standby state */
+
+
+#define STAY_CUR_STATE 0x1
+#define GOTO_STATE_NOW 0x2
+#define HOLD_KEY_BLOCK 0x4
+
+#define PM_SLEEP_MARGIN 0x0 /**< keep guard time for unlock */
+#define PM_RESET_TIMER 0x1 /**< reset timer for unlock */
+#define PM_KEEP_TIMER 0x2 /**< keep timer for unlock */
+
+/**
+ * display lock condition (unsigned integer)
+ *
+ * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+ * reserved flags request state
+ *
+ */
+
+enum cond_request_e {
+ PM_REQUEST_LOCK = 1 << 0,
+ PM_REQUEST_UNLOCK = 1 << 1,
+ PM_REQUEST_CHANGE = 1 << 2,
+};
+
+enum cond_flags_e {
+ PM_FLAG_BLOCK_HOLDKEY = 1 << 0,
+ PM_FLAG_RESET_TIMER = 1 << 1,
+ PM_FLAG_KEEP_TIMER = 1 << 2,
+};
+
+#define SHIFT_STATE 0
+#define SHIFT_REQUEST 8
+#define SHIFT_FLAGS 16
+#define COND_MASK 0xff /* 11111111 */
+#define SET_COND_REQUEST(cond, req) ((cond) | ((req) << SHIFT_REQUEST))
+#define SET_COND_FLAG(cond, flags) ((cond) | ((flags) << SHIFT_FLAGS))
+#define IS_COND_REQUEST_LOCK(cond) (((cond) >> SHIFT_REQUEST) & COND_MASK & PM_REQUEST_LOCK)
+#define IS_COND_REQUEST_UNLOCK(cond) (((cond) >> SHIFT_REQUEST) & COND_MASK & PM_REQUEST_UNLOCK)
+#define IS_COND_REQUEST_CHANGE(cond) (((cond) >> SHIFT_REQUEST) & COND_MASK & PM_REQUEST_CHANGE)
+#define GET_COND_STATE(cond) ((cond) & COND_MASK)
+#define GET_COND_FLAG(cond) (((cond) >> SHIFT_FLAGS) & COND_MASK)
+
+
+#define PM_LOCK_STR "lock"
+#define PM_UNLOCK_STR "unlock"
+#define PM_CHANGE_STR "change"
+
+#define PM_LCDOFF_STR "lcdoff"
+#define PM_LCDDIM_STR "lcddim"
+#define PM_LCDON_STR "lcdon"
+#define PM_STANDBY_STR "standby"
+#define PM_SUSPEND_STR "suspend"
+
+#define STAYCURSTATE_STR "staycurstate"
+#define GOTOSTATENOW_STR "gotostatenow"
+
+#define HOLDKEYBLOCK_STR "holdkeyblock"
+#define STANDBYMODE_STR "standbymode"
+
+#define SLEEP_MARGIN_STR "sleepmargin"
+#define RESET_TIMER_STR "resettimer"
+#define KEEP_TIMER_STR "keeptimer"
+
+typedef struct {
+ pid_t pid;
+ unsigned int cond;
+ unsigned int timeout;
+ unsigned int timeout2;
+} PMMsg;
+
+extern int (*pm_callback) (int, PMMsg *);
+
+int init_input(void);
+int exit_input(void);
+
+extern int pm_lock_internal(pid_t pid, int s_bits, int flag, int timeout);
+extern int pm_unlock_internal(pid_t pid, int s_bits, int flag);
+extern int pm_change_internal(pid_t pid, int s_bits);
+
+/**
+ * @}
+ */
+
+#endif /*__PM_POLL_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "core.h"
+#include "util.h"
+#include "setting.h"
+
+#define LCD_DIM_RATIO 0.3
+#define LCD_MAX_DIM_TIMEOUT 7000
+#define LCD_MIN_DIM_TIMEOUT 500
+
+static const char *setting_keys[SETTING_GET_END] = {
+ [SETTING_TO_NORMAL] = VCONFKEY_SETAPPL_LCD_TIMEOUT_NORMAL,
+ [SETTING_BRT_LEVEL] = VCONFKEY_SETAPPL_LCD_BRIGHTNESS,
+ [SETTING_LOCK_SCREEN] = VCONFKEY_IDLE_LOCK_STATE,
+ [SETTING_POWER_CUSTOM_BRIGHTNESS] = VCONFKEY_PM_CUSTOM_BRIGHTNESS_STATUS,
+};
+
+static int lock_screen_state = VCONFKEY_IDLE_UNLOCK;
+static bool lock_screen_bg_state = false;
+static int force_lcdtimeout = 0;
+static int custom_on_timeout = 0;
+static int custom_normal_timeout = 0;
+static int custom_dim_timeout = 0;
+
+int (*update_pm_setting) (int key_idx, int val);
+
+static void display_state_send_system_event(int state)
+{
+ bundle *b;
+ const char *str;
+
+ if (state == S_NORMAL)
+ str = EVT_VAL_DISPLAY_NORMAL;
+ else if (state == S_LCDDIM)
+ str = EVT_VAL_DISPLAY_DIM;
+ else if (state == S_LCDOFF)
+ str = EVT_VAL_DISPLAY_OFF;
+ else
+ return;
+
+ _I("eventsystem (%s)", str);
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_DISPLAY_STATE, str);
+ eventsystem_send_system_event(SYS_EVENT_DISPLAY_STATE, b);
+ bundle_free(b);
+}
+
+int set_force_lcdtimeout(int timeout)
+{
+ if (timeout < 0)
+ return -EINVAL;
+
+ force_lcdtimeout = timeout;
+
+ return 0;
+}
+
+int get_lock_screen_state(void)
+{
+ return lock_screen_state;
+}
+
+void set_lock_screen_state(int state)
+{
+ switch (state) {
+ case VCONFKEY_IDLE_LOCK:
+ case VCONFKEY_IDLE_UNLOCK:
+ lock_screen_state = state;
+ break;
+ default:
+ lock_screen_state = VCONFKEY_IDLE_UNLOCK;
+ }
+}
+
+int get_lock_screen_bg_state(void)
+{
+ return lock_screen_bg_state;
+}
+
+void set_lock_screen_bg_state(bool state)
+{
+ _I("state is %d", state);
+ lock_screen_bg_state = state;
+}
+
+int get_charging_status(int *val)
+{
+ return vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, val);
+}
+
+int get_lowbatt_status(int *val)
+{
+ return vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, val);
+}
+
+int get_usb_status(int *val)
+{
+ return vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, val);
+}
+
+int set_setting_pmstate(int val)
+{
+ display_state_send_system_event(val);
+ return vconf_set_int(VCONFKEY_PM_STATE, val);
+}
+
+int get_setting_brightness(int *level)
+{
+ return vconf_get_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, level);
+}
+
+void get_dim_timeout(int *dim_timeout)
+{
+ int vconf_timeout, on_timeout, val, ret;
+
+ if (custom_dim_timeout > 0) {
+ *dim_timeout = custom_dim_timeout;
+ return;
+ }
+
+ ret = vconf_get_int(setting_keys[SETTING_TO_NORMAL], &vconf_timeout);
+ if (ret != 0) {
+ _E("Failed ro get setting timeout!");
+ vconf_timeout = DEFAULT_NORMAL_TIMEOUT;
+ }
+
+ if (force_lcdtimeout > 0)
+ on_timeout = SEC_TO_MSEC(force_lcdtimeout);
+ else
+ on_timeout = SEC_TO_MSEC(vconf_timeout);
+
+ val = (double)on_timeout * LCD_DIM_RATIO;
+ if (val > LCD_MAX_DIM_TIMEOUT)
+ val = LCD_MAX_DIM_TIMEOUT;
+
+ *dim_timeout = val;
+}
+
+void get_run_timeout(int *timeout)
+{
+ int dim_timeout = -1;
+ int vconf_timeout = -1;
+ int on_timeout;
+ int ret;
+
+ if (custom_normal_timeout > 0) {
+ *timeout = custom_normal_timeout;
+ return;
+ }
+
+ ret = vconf_get_int(setting_keys[SETTING_TO_NORMAL], &vconf_timeout);
+ if (ret != 0) {
+ _E("Failed ro get setting timeout!");
+ vconf_timeout = DEFAULT_NORMAL_TIMEOUT;
+ }
+
+ if (force_lcdtimeout > 0)
+ on_timeout = SEC_TO_MSEC(force_lcdtimeout);
+ else
+ on_timeout = SEC_TO_MSEC(vconf_timeout);
+
+ if (on_timeout == 0) {
+ *timeout = on_timeout;
+ return;
+ }
+
+ get_dim_timeout(&dim_timeout);
+ *timeout = on_timeout - dim_timeout;
+}
+
+int set_custom_lcdon_timeout(int timeout)
+{
+ int changed = (custom_on_timeout == timeout ? false : true);
+
+ custom_on_timeout = timeout;
+
+ if (timeout <= 0) {
+ custom_normal_timeout = 0;
+ custom_dim_timeout = 0;
+ return changed;
+ }
+
+ custom_dim_timeout = (double)timeout * LCD_DIM_RATIO;
+ custom_normal_timeout = timeout - custom_dim_timeout;
+
+ _I("custom normal(%d), dim(%d)", custom_normal_timeout,
+ custom_dim_timeout);
+
+ return changed;
+}
+
+static int setting_cb(keynode_t *key_nodes, void *data)
+{
+ keynode_t *tmp = key_nodes;
+ int index;
+
+ index = (int)((intptr_t)data);
+ if (index > SETTING_END) {
+ _E("Unknown setting key: %s, idx=%d",
+ vconf_keynode_get_name(tmp), index);
+ return -1;
+ }
+ if (update_pm_setting != NULL) {
+ update_pm_setting(index, vconf_keynode_get_int(tmp));
+ }
+
+ return 0;
+}
+
+int init_setting(int (*func) (int key_idx, int val))
+{
+ int i;
+
+ if (func != NULL)
+ update_pm_setting = func;
+
+ for (i = SETTING_BEGIN; i < SETTING_GET_END; i++) {
+ /*
+ * To pass an index data through the vconf infratstructure
+ * without memory allocation, an index data becomes typecast
+ * to proper pointer size on each architecture.
+ */
+ vconf_notify_key_changed(setting_keys[i], (void *)setting_cb,
+ (void *)((intptr_t)i));
+ }
+
+ return 0;
+}
+
+int exit_setting(void)
+{
+ int i;
+ for (i = SETTING_BEGIN; i < SETTING_GET_END; i++) {
+ vconf_ignore_key_changed(setting_keys[i], (void *)setting_cb);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/*
+ * @file setting.h
+ * @brief Power manager setting module header
+ */
+#ifndef __PM_SETTING_H__
+#define __PM_SETTING_H__
+
+#include <vconf.h>
+
+/*
+ * @addtogroup POWER_MANAGER
+ * @{
+ */
+
+enum {
+ SETTING_BEGIN = 0,
+ SETTING_TO_NORMAL = SETTING_BEGIN,
+ SETTING_BRT_LEVEL,
+ SETTING_LOCK_SCREEN,
+ SETTING_POWER_CUSTOM_BRIGHTNESS,
+ SETTING_GET_END,
+ SETTING_PM_STATE = SETTING_GET_END,
+ SETTING_LOW_BATT,
+ SETTING_CHARGING,
+ SETTING_POWEROFF,
+ SETTING_HALLIC_OPEN,
+ SETTING_LOCK_SCREEN_BG,
+ SETTING_END
+};
+
+extern int (*update_pm_setting) (int key_idx, int val);
+
+int get_setting_brightness(int *level);
+
+/*
+ * @brief setting initialization function
+ *
+ * get the variables if it exists. otherwise, set the default.
+ * and register some callback functions.
+ *
+ * @internal
+ * @param[in] func configuration change callback function
+ * @return 0 : success, -1 : error
+ */
+extern int init_setting(int (*func) (int key_idx, int val));
+
+extern int exit_setting();
+
+/*
+ * get normal state timeout from SLP-setting SLP_SETTING_LCD_TIMEOUT_NORMAL
+ *
+ * @internal
+ * @param[out] timeout timeout variable pointer
+ */
+void get_run_timeout(int *timeout);
+
+/*
+ * get LCD dim state timeout from environment variable.
+ *
+ * @internal
+ * @param[out] dim_timeout timeout variable pointer
+ */
+void get_dim_timeout(int *dim_timeout);
+/*
+ * get USB connection status from SLP-setting SLP_SETTING_USB_STATUS
+ *
+ * @internal
+ * @param[out] val usb connection status variable pointer, 0 is disconnected, others is connected.
+ * @return 0 : success, -1 : error
+ */
+extern int get_usb_status(int *val);
+
+/*
+ * set Current power manager state at SLP-setting "memory/pwrmgr/state"
+ *
+ * @internal
+ * @param[in] val current power manager state.
+ * @return 0 : success, -1 : error
+ */
+extern int set_setting_pmstate(int val);
+
+/*
+ * get charging status at SLP-setting "memory/Battery/Charger"
+ *
+ * @internal
+ * @param[in] val charging or not (1 or 0 respectively).
+ * @return 0 : success, -1 : error
+ */
+extern int get_charging_status(int *val);
+
+/*
+ * get current battery low status at SLP-setting "memory/Battery/Status/Low"
+ *
+ * @internal
+ * @param[in] val current low battery status
+ * @return 0 : success, -1 : error
+ */
+extern int get_lowbatt_status(int *val);
+
+int get_lock_screen_state(void);
+
+/*
+ * @}
+ */
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <time.h>
+#include <Ecore.h>
+#include "core/common.h"
+#include "core/log.h"
+#include "core/device-notifier.h"
+#include "core/devices.h"
+#include "power/power-handler.h"
+#include "core.h"
+#include "poll.h"
+#include "device-interface.h"
+#include "util.h"
+
+#define PRE_STATE_CHANGE_TIMEOUT 500*1000 /* 500ms */
+#define SIGNAL_CHANGE_STATE "ChangeState"
+#define SIGNAL_PRE_CHANGE_STATE "PreChangeState"
+#define SIGNAL_WAKEUP "WakeUp"
+#define SIGNAL_PRE_WAKEUP "PreWakeUp"
+#define SIGNAL_POST_WAKEUP "PostWakeUp"
+#define SIGNAL_EARLY_WAKEUP "EarlyWakeUp"
+
+static Ecore_Timer *standby_timer;
+
+static int change_state(pid_t pid, int type, enum state_t st)
+{
+ int ret;
+
+ if (type == PM_CONTROL_EVENT && states[st].check) {
+ ret = states[pm_cur_state].check(pm_cur_state, st);
+ if (ret != 0) {
+ _E("(%s) State Locked. Cannot be changed to (%s)",
+ states[pm_cur_state].name, states[st].name);
+ return ret;
+ }
+ }
+
+ if (states[st].trans) {
+ ret = states[st].trans(type);
+ if (ret < 0) {
+ _E("Failed to trans state (%s, ret:%d)", states[st].name, ret);
+ return ret;
+ }
+ }
+
+ _I("Success to change state (%s) requested by pid(%d)", states[st].name, pid);
+
+ return 0;
+}
+
+static int tv_proc_change_state(unsigned int cond, pid_t pid)
+{
+ enum state_t next;
+ int ret;
+
+ next = GET_COND_STATE(cond);
+ if (pm_cur_state == next) {
+ _I("current state (%d) == next state (%d)", pm_cur_state, next);
+ return 0;
+ }
+
+ if (pid < INTERNAL_LOCK_BASE) { /* Request from other process*/
+ if (next == S_SUSPEND || next == S_POWEROFF) {
+ _E("Do not change to suspend or power off directly");
+ return -EPERM;
+ }
+ }
+
+ _I("Change State to %s (%d)", states[next].name, pid);
+
+ ret = change_state(pid, PM_CONTROL_EVENT, next);
+ if (ret != 0) {
+ _E("Failed to change state (%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+unsigned long long get_uptime(void)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_sec;
+}
+
+static int lcdon_check(int curr, int next)
+{
+ /* do not changed to next state if who lock the normal mode */
+ check_processes(pm_cur_state);
+ if (check_lock_state(pm_cur_state)) {
+ _I("S_LCDON Lock state");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int lcdon_pre(void *data)
+{
+ char *arr[1];
+
+ /* TODO: cancel suspend */
+
+ /* That will unlock callback registration in case of getting back to normal
+ * from partial poweroff. If someone start poweroff with standby lock and then
+ * unlock, change state to lcdon, registration of poweroff callback would be blocked
+ * as unblocking is done when resuming from suspend.
+ */
+ device_notify(DEVICE_NOTIFIER_POWER_RESUME, NULL);
+
+ if (pm_cur_state == S_STANDBY) {
+ arr[0] = states[S_LCDON].name;
+ _I("send pre state change NORMAL");
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_PRE_CHANGE_STATE, "s", arr);
+ /*Give time to process callback */
+ usleep(PRE_STATE_CHANGE_TIMEOUT);
+ }
+
+ return 0;
+}
+
+static int lcdon_post(void *data)
+{
+ char *arr[1];
+
+ arr[0] = states[S_LCDON].name;
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_CHANGE_STATE, "s", arr);
+
+ /* TODO: set_power */
+
+ return 0;
+}
+
+static int lcdon_action(int timeout)
+{
+ if (pm_cur_state != pm_old_state &&
+ pm_cur_state != S_SLEEP)
+ set_setting_pmstate(pm_cur_state);
+
+ if (pm_old_state != S_LCDOFF ||
+ pm_old_state != S_SLEEP) {
+ _I("pm_old_state (%s). Skip lcd on", states[pm_old_state].name);
+ return 0;
+ }
+
+ /* TODO: post resume */
+
+ backlight_ops.on(0);
+
+ return 0;
+}
+
+static int lcdon_trans(int evt)
+{
+ int ret;
+ struct state *st;
+
+ ret = lcdon_pre(NULL);
+ if (ret < 0) {
+ _E("S_LCDON pre-operation failed(%d)", ret);
+ return ret;
+ }
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_LCDON;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ ret = lcdon_post(NULL);
+ if (ret < 0)
+ _E("S_LCDON post-operation failed(%d)", ret);
+
+ return 0;
+}
+
+static int lcdoff_check(int curr, int next)
+{
+ /* LCD OFF can change to LCD ON and STANDBY state */
+ return 0;
+}
+
+static int lcdoff_pre(void *data)
+{
+ return 0;
+}
+
+static int lcdoff_post(void *data)
+{
+ char *arr[1];
+
+ /* broadcast to other application */
+ arr[0] = states[S_LCDOFF].name;
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_CHANGE_STATE, "s", arr);
+
+ return 0;
+}
+
+static int lcdoff_action(int timeout)
+{
+ if (pm_cur_state != pm_old_state &&
+ pm_cur_state != S_SLEEP)
+ set_setting_pmstate(pm_cur_state);
+
+ if (pm_old_state == S_SUSPEND ||
+ pm_old_state == S_LCDOFF)
+ return 0;
+
+ backlight_ops.off(0);
+
+ return 0;
+}
+
+static int lcdoff_trans(int evt)
+{
+ int ret;
+ struct state *st;
+
+ ret = lcdoff_pre(NULL);
+ if (ret < 0) {
+ _E("S_LCDOFF pre-operation failed (%d)", ret);
+ return ret;
+ }
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_LCDOFF;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ ret = lcdoff_post(NULL);
+ if (ret < 0)
+ _E("S_LCDOFF post-operation failed (%d)", ret);
+
+ return 0;
+}
+
+static int standby_check(int curr, int next)
+{
+ /* STANDBY can change to LCD ON or POWER OFF state */
+ if (next == S_LCDOFF)
+ return -EPERM;
+
+ /* do not change to next state if who lock the standby mode */
+ check_processes(S_LCDOFF);
+ if (check_lock_state(S_LCDOFF)) {
+ _I("S_LCDOFF Lock state");
+ return 1;
+ }
+
+ /* TODO: Instant on timer */
+
+ return 0;
+}
+
+static int standby_pre(void *data)
+{
+ return 0;
+}
+
+static int standby_post(void *data)
+{
+ char *arr[1];
+
+ /* broadcast to other application */
+ arr[0] = states[S_STANDBY].name;
+ broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_CHANGE_STATE, "s", arr);
+
+ backlight_ops.off(0);
+
+ /* Set power */
+
+ return 0;
+}
+
+static int poweroff_trans(int evt);
+
+static Eina_Bool standby_go_next_state(void *data)
+{
+ int ret;
+
+ if (standby_timer) {
+ ecore_timer_del(standby_timer);
+ standby_timer = NULL;
+ }
+
+ ret = pm_change_internal(INTERNAL_LOCK_SUSPEND, SUSPEND);
+ if (ret < 0) {
+ _E("Failed to change state to S_SUSPEND. Now Power off !!");
+ poweroff_trans(0);
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int standby_action(int timeout)
+{
+ if (pm_cur_state != pm_old_state &&
+ pm_cur_state != S_SLEEP)
+ set_setting_pmstate(pm_cur_state);
+
+ backlight_ops.off(0);
+
+ standby_timer = ecore_timer_add(0,
+ standby_go_next_state, NULL);
+ if (!standby_timer)
+ _E("Failed to add timer to go to next state of S_STANDBY");
+
+ return 0;
+}
+
+static int standby_trans(int evt)
+{
+ int ret;
+ struct state *st;
+
+ ret = standby_pre(NULL);
+ if (ret < 0) {
+ _E("S_STANDBY pre-operation failed(%d)", ret);
+ return ret;
+ }
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_STANDBY;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ ret = standby_post(NULL);
+ if (ret < 0)
+ _E("S_STANDBY post-operation failed(%d)", ret);
+
+ return 0;
+}
+
+static int suspend_check(int curr, int next)
+{
+ /* DO NOT USE THIS FUNCTION */
+ return 0;
+}
+
+static int suspend_pre(void *data)
+{
+ return 0;
+}
+
+static int suspend_post(void *data)
+{
+ char *arr[1];
+ int ret;
+ unsigned int cond = 0;
+
+ /* TODO: count InstandOn */
+
+ cond = S_LCDON;
+ ret = tv_proc_change_state(cond, INTERNAL_LOCK_SUSPEND);
+ if (ret < 0)
+ _E("Fail to change state to next_state(%s)", states[cond].name);
+
+ /* Broadcast pre-wakeup signal */
+ arr[0] = "0";
+ broadcast_edbus_signal(DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER,
+ SIGNAL_PRE_WAKEUP, "i", arr);
+
+ /* Notify resume state */
+ device_notify(DEVICE_NOTIFIER_POWER_RESUME, NULL);
+
+ return 0;
+}
+
+static int suspend_action(int timeout)
+{
+ struct state *st;
+
+ if (pm_cur_state != pm_old_state &&
+ pm_cur_state != S_SLEEP)
+ set_setting_pmstate(pm_cur_state);
+
+ /* TODO: set wakeup count */
+
+ /* sleep state : set system mode to SUSPEND */
+ power_ops.suspend();
+
+ _I("system wakeup!!");
+
+ /* Resume !! */
+ /* system waked up by devices */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_LCDOFF;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ return 0;
+}
+
+static int suspend_trans(int evt)
+{
+ int ret;
+ struct state *st;
+
+ ret = suspend_pre(NULL);
+ if (ret < 0) {
+ _E("S_SUSPEND pre-operation failed(%d)", ret);
+ return ret;
+ }
+
+ /* state transition */
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_LCDOFF;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ pm_old_state = pm_cur_state;
+ pm_cur_state = S_SUSPEND;
+ st = &states[pm_cur_state];
+
+ if (st->action)
+ st->action(0);
+
+ ret = suspend_post(NULL);
+ if (ret < 0)
+ _E("S_SUSPEND post-operation failed(%d)", ret);
+
+ return 0;
+}
+
+static int poweroff_check(int curr, int next)
+{
+ /* DO NOT USE THIS FUNCTION */
+ return 0;
+}
+
+static int poweroff_action(int timeout)
+{
+ static const struct device_ops *ops;
+
+ FIND_DEVICE_INT(ops, POWER_OPS_NAME);
+
+ return ops->execute(POWER_POWEROFF);
+}
+
+static int poweroff_trans(int evt)
+{
+ struct state *st;
+ st = &states[S_POWEROFF];
+ if (st->action)
+ st->action(0);
+ return 0;
+}
+
+static int display_lock_changed(void *data)
+{
+ bool state = (bool)data;
+
+ if (pm_cur_state != S_STANDBY)
+ return 0;
+
+ if (!state)
+ standby_go_next_state(NULL);
+
+ return 0;
+}
+
+static void set_tv_operations(enum state_t st,
+ char *name,
+ int (*check) (int curr, int next),
+ int (*trans) (int evt),
+ int (*action) (int timeout))
+{
+ change_state_name(st, name);
+ change_state_check(st, check);
+ change_state_trans(st, trans);
+ change_state_action(st, action);
+}
+
+struct _tv_states {
+ enum state_t state;
+ char *name;
+ int (*check)(int curr, int next);
+ int (*trans)(int evt);
+ int (*action)(int timeout);
+} tv_states[] = {
+ { S_LCDON, "S_LCDON", lcdon_check, lcdon_trans, lcdon_action },
+ { S_LCDDIM, "S_LCDDIM", NULL, NULL, NULL },
+ { S_LCDOFF, "S_LCDOFF", lcdoff_check, lcdoff_trans, lcdoff_action },
+ { S_STANDBY, "S_STANDBY", standby_check, standby_trans, standby_action },
+ { S_SUSPEND, "S_SUSPEND", suspend_check, suspend_trans, suspend_action },
+ { S_POWEROFF, "S_POWEROFF", poweroff_check, poweroff_trans, poweroff_action },
+};
+
+static void __CONSTRUCTOR__ state_tv_init(void)
+{
+ int i;
+
+ _I("TV Profile !!");
+
+ for (i = 0 ; i < ARRAY_SIZE(tv_states) ; i++)
+ set_tv_operations(tv_states[i].state,
+ tv_states[i].name,
+ tv_states[i].check,
+ tv_states[i].trans,
+ tv_states[i].action);
+
+ change_proc_change_state(tv_proc_change_state);
+
+ register_notifier(DEVICE_NOTIFIER_DISPLAY_LOCK, display_lock_changed);
+}
+
+static void __DESTRUCTOR__ state_tv_deinit(void)
+{
+ unregister_notifier(DEVICE_NOTIFIER_DISPLAY_LOCK, display_lock_changed);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+
+/**
+ * @file util.h
+ * @brief Utilities header for Power manager
+ */
+#ifndef __DEF_UTIL_H__
+#define __DEF_UTIL_H__
+
+/**
+ * @addtogroup POWER_MANAGER
+ * @{
+ */
+#ifdef ENABLE_DEVICED_DLOG
+#define ENABLE_DLOG
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "POWER_MANAGER"
+#include "shared/log-macro.h"
+
+#define SEC_TO_MSEC(x) ((x)*1000)
+#define MSEC_TO_SEC(x) ((x)/1000)
+
+/**
+ * @}
+ */
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <vconf.h>
+
+#include "core/log.h"
+#include "core/device-notifier.h"
+#include "core/edbus-handler.h"
+#include "core/udev.h"
+#include "display/core.h"
+#include "extcon/extcon.h"
+
+#define METHOD_GET_CRADLE "GetCradle"
+#define SIGNAL_CRADLE_STATE "ChangedCradle"
+
+static struct extcon_ops cradle_extcon_ops;
+
+static void cradle_send_broadcast(int status)
+{
+ static int old;
+ char *arr[1];
+ char str_status[32];
+
+ if (old == status)
+ return;
+
+ _I("broadcast cradle status %d", status);
+ old = status;
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+
+ broadcast_edbus_signal(DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
+ SIGNAL_CRADLE_STATE, "i", arr);
+}
+
+static int cradle_update(int status)
+{
+ _I("jack - cradle changed %d", status);
+ pm_change_internal(getpid(), LCD_NORMAL);
+ cradle_send_broadcast(status);
+ if (vconf_set_int(VCONFKEY_SYSMAN_CRADLE_STATUS, status) != 0) {
+ _E("failed to set vconf status");
+ return -EIO;
+ }
+
+ if (status == DOCK_SOUND)
+ pm_lock_internal(getpid(), LCD_DIM, STAY_CUR_STATE, 0);
+ else if (status == DOCK_NONE)
+ pm_unlock_internal(getpid(), LCD_DIM, PM_SLEEP_MARGIN);
+
+ return 0;
+}
+
+static int display_changed(void *data)
+{
+ enum state_t state;
+ int cradle;
+
+ if (!data)
+ return 0;
+
+ state = *(int *)data;
+ if (state != S_NORMAL)
+ return 0;
+
+ cradle = cradle_extcon_ops.status;
+ if (cradle == DOCK_SOUND) {
+ pm_lock_internal(getpid(), LCD_DIM, STAY_CUR_STATE, 0);
+ _I("sound dock is connected! dim lock is on.");
+ }
+
+ return 0;
+}
+
+static DBusMessage *dbus_cradle_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ return make_reply_message(msg, cradle_extcon_ops.status);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { METHOD_GET_CRADLE, NULL, "i", dbus_cradle_handler },
+};
+
+static void cradle_init(void *data)
+{
+ int ret;
+
+ register_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static void cradle_exit(void *data)
+{
+ unregister_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+}
+
+static struct extcon_ops cradle_extcon_ops = {
+ .name = EXTCON_CABLE_DOCK,
+ .init = cradle_init,
+ .exit = cradle_exit,
+ .update = cradle_update,
+};
+
+EXTCON_OPS_REGISTER(cradle_extcon_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 <vconf.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "core/log.h"
+#include "display/poll.h"
+#include "extcon/extcon.h"
+
+#define SIGNAL_EARJACK_STATE "ChangedEarjack"
+#define GET_EARJACK_STATE "Earjack"
+
+static void earjack_send_broadcast(int status)
+{
+ static int old = 0;
+ char *arr[1];
+ char str_status[32];
+
+ if (old == status)
+ return;
+
+ _I("broadcast earjack status %d", status);
+ old = status;
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+
+ broadcast_edbus_signal(DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
+ SIGNAL_EARJACK_STATE, "i", arr);
+}
+
+static void earjack_send_system_event(int status)
+{
+ bundle *b;
+ const char *str;
+
+ if (status)
+ str = EVT_VAL_EARJACK_CONNECTED;
+ else
+ str = EVT_VAL_EARJACK_DISCONNECTED;
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_EARJACK_STATUS, str);
+ eventsystem_send_system_event(SYS_EVENT_EARJACK_STATUS, b);
+ bundle_free(b);
+}
+
+static int earjack_update(int status)
+{
+ _I("jack - earjack changed %d", status);
+ vconf_set_int(VCONFKEY_SYSMAN_EARJACK, status);
+ earjack_send_broadcast(status);
+ earjack_send_system_event(status);
+ if (status != 0)
+ pm_change_internal(getpid(), LCD_NORMAL);
+
+ return 0;
+}
+
+static struct extcon_ops earjack_extcon_ops = {
+ .name = EXTCON_CABLE_HEADPHONE_OUT,
+ .update = earjack_update,
+};
+
+EXTCON_OPS_REGISTER(earjack_extcon_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <hw/external_connection.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/config-parser.h"
+#include "core/device-notifier.h"
+#include "core/edbus-handler.h"
+#include "core/udev.h"
+#include "extcon.h"
+
+#define EXTCON_PATH "/sys/class/extcon"
+#define STATE_NAME "STATE"
+
+#define BUF_MAX 256
+
+static dd_list *extcon_list;
+
+static struct external_connection_device *extcon_dev;
+
+void add_extcon(struct extcon_ops *dev)
+{
+ DD_LIST_APPEND(extcon_list, dev);
+}
+
+void remove_extcon(struct extcon_ops *dev)
+{
+ DD_LIST_REMOVE(extcon_list, dev);
+}
+
+static struct extcon_ops *find_extcon(const char *name)
+{
+ dd_list *l;
+ struct extcon_ops *dev;
+
+ if (!name)
+ return NULL;
+
+ DD_LIST_FOREACH(extcon_list, l, dev) {
+ if (!strcmp(dev->name, name))
+ return dev;
+ }
+
+ return NULL;
+}
+
+int extcon_get_status(const char *name)
+{
+ struct extcon_ops *dev;
+
+ if (!name)
+ return -EINVAL;
+
+ dev = find_extcon(name);
+ if (!dev)
+ return -ENOENT;
+
+ return dev->status;
+}
+
+static int extcon_update(const char *name, const char *value)
+{
+ struct extcon_ops *dev;
+ int status;
+
+ if (!name || !value)
+ return -EINVAL;
+
+ dev = find_extcon(name);
+ if (!dev)
+ return -EINVAL;
+
+ status = atoi(value);
+
+ /* Do not invoke update func. if it's the same value */
+ if (dev->status == status)
+ return 0;
+
+ _I("Changed %s device : %d -> %d", name, dev->status, status);
+
+ dev->status = status;
+ if (dev->update)
+ dev->update(status);
+
+ return 0;
+}
+
+static int extcon_parsing_value(const char *value)
+{
+ char *s, *p;
+ char name[NAME_MAX];
+
+ if (!value)
+ return -EINVAL;
+
+ s = (char*)value;
+ while (s && *s != '\0') {
+ p = strchr(s, '=');
+ if (!p)
+ break;
+ memset(name, 0, sizeof(name));
+ memcpy(name, s, p-s);
+ /* name is env_name and p+1 is env_value */
+ extcon_update(name, p+1);
+ s = strchr(p, '\n');
+ if (!s)
+ break;
+ s += 1;
+ }
+
+ return 0;
+}
+
+static void uevent_extcon_handler(struct udev_device *dev)
+{
+ const char *env_value;
+ int ret;
+
+ env_value = udev_device_get_property_value(dev, STATE_NAME);
+ if (!env_value)
+ return;
+
+ ret = extcon_parsing_value(env_value);
+ if (ret < 0)
+ _E("fail to parse extcon value : %d", ret);
+}
+
+static int extcon_load_uevent(struct parse_result *result, void *user_data)
+{
+ if (!result)
+ return 0;
+
+ if (!result->name || !result->value)
+ return 0;
+
+ extcon_update(result->name, result->value);
+
+ return 0;
+}
+
+static int get_extcon_init_state(void)
+{
+ DIR *dir;
+ struct dirent entry;
+ struct dirent *result;
+ char node[BUF_MAX];
+ int ret;
+
+ dir = opendir(EXTCON_PATH);
+ if (!dir) {
+ ret = -errno;
+ _E("Cannot open dir (%s, errno:%d)", EXTCON_PATH, ret);
+ return ret;
+ }
+
+ ret = -ENOENT;
+ while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+ if (result->d_name[0] == '.')
+ continue;
+ snprintf(node, sizeof(node), "%s/%s/state",
+ EXTCON_PATH, result->d_name);
+ _I("checking node (%s)", node);
+ if (access(node, F_OK) != 0)
+ continue;
+
+ ret = config_parse(node, extcon_load_uevent, NULL);
+ if (ret < 0)
+ _E("fail to parse %s data : %d", node, ret);
+ }
+
+ if (dir)
+ closedir(dir);
+
+ return 0;
+}
+
+static DBusMessage *dbus_get_extcon_status(E_DBus_Object *obj,
+ DBusMessage *msg)
+{
+ DBusError err;
+ struct extcon_ops *dev;
+ char *str;
+ int ret;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &str,
+ DBUS_TYPE_INVALID)) {
+ _E("fail to get message : %s - %s", err.name, err.message);
+ dbus_error_free(&err);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ dev = find_extcon(str);
+ if (!dev) {
+ _E("fail to matched extcon device : %s", str);
+ ret = -ENOENT;
+ goto error;
+ }
+
+ ret = dev->status;
+ _D("Extcon device : %s, status : %d", dev->name, dev->status);
+
+error:
+ return make_reply_message(msg, ret);
+}
+
+static DBusMessage *dbus_enable_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ char *device;
+ int ret;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = extcon_update(device, "1");
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static DBusMessage *dbus_disable_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ char *device;
+ int ret;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = extcon_update(device, "0");
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static struct uevent_handler uh = {
+ .subsystem = EXTCON_SUBSYSTEM,
+ .uevent_func = uevent_extcon_handler,
+};
+
+static const struct edbus_method edbus_methods[] = {
+ { "GetStatus", "s", "i", dbus_get_extcon_status },
+ { "enable", "s", NULL, dbus_enable_device }, /* for devicectl */
+ { "disable", "s", NULL, dbus_disable_device }, /* for devicectl */
+};
+
+/* used by HAL */
+static void extcon_changed(struct connection_info *info, void *data)
+{
+ if (!info)
+ return;
+
+ if (!info->name || !info->state)
+ return;
+
+ /* call to update */
+ extcon_update(info->name, info->state);
+}
+
+static int extcon_probe(void *data)
+{
+ struct hw_info *info;
+ int ret;
+
+ if (extcon_dev)
+ return 0;
+
+ ret = hw_get_info(EXTERNAL_CONNECTION_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (ret == 0) {
+ if (!info->open) {
+ _E("Failed to open extcon device; open(NULL)");
+ return -ENODEV;
+ }
+
+ ret = info->open(info, NULL, (struct hw_common **)&extcon_dev);
+ if (ret < 0) {
+ _E("Failed to get extcon device structure (%d)", ret);
+ return ret;
+ }
+
+ _I("extcon device structure load success");
+ return 0;
+ }
+
+ /**
+ * find extcon class.
+ * if there is no extcon class,
+ * deviced does not control extcon devices.
+ */
+ if (access(EXTCON_PATH, R_OK) != 0) {
+ _E("there is no extcon class");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void extcon_init(void *data)
+{
+ int ret;
+ dd_list *l;
+ struct extcon_ops *dev;
+
+ if (!extcon_list)
+ return;
+
+ /* initialize extcon devices */
+ DD_LIST_FOREACH(extcon_list, l, dev) {
+ _I("[extcon] init (%s)", dev->name);
+ if (dev->init)
+ dev->init(data);
+ }
+
+ if (extcon_dev) { /* HAL is used */
+ if (extcon_dev->register_changed_event)
+ extcon_dev->register_changed_event(extcon_changed, NULL);
+
+ if (extcon_dev->get_current_state)
+ extcon_dev->get_current_state(extcon_changed, NULL);
+
+ } else {
+ /* register extcon uevent */
+ ret = register_kernel_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to register extcon uevent : %d", ret);
+
+ /* load the initialize value by accessing the node directly */
+ ret = get_extcon_init_state();
+ if (ret < 0)
+ _E("fail to init extcon nodes : %d", ret);
+ }
+
+ /* register extcon object first */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_EXTCON,
+ DEVICED_INTERFACE_EXTCON,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+}
+
+static void extcon_exit(void *data)
+{
+ dd_list *l;
+ struct extcon_ops *dev;
+ struct hw_info *info;
+ int ret;
+
+ if (extcon_dev) {
+ if (extcon_dev->unregister_changed_event)
+ extcon_dev->unregister_changed_event(extcon_changed);
+
+ info = extcon_dev->common.info;
+ if (!info)
+ free(extcon_dev);
+ else
+ info->close((struct hw_common *)extcon_dev);
+ extcon_dev = NULL;
+
+ } else {
+ /* unreigster extcon uevent */
+ ret = unregister_kernel_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to unregister extcon uevent : %d", ret);
+ }
+
+ /* deinitialize extcon devices */
+ DD_LIST_FOREACH(extcon_list, l, dev) {
+ _I("[extcon] deinit (%s)", dev->name);
+ if (dev->exit)
+ dev->exit(data);
+ }
+}
+
+static const struct device_ops extcon_device_ops = {
+ .name = "extcon",
+ .probe = extcon_probe,
+ .init = extcon_init,
+ .exit = extcon_exit,
+};
+
+DEVICE_OPS_REGISTER(&extcon_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __EXTCON_H__
+#define __EXTCON_H__
+
+#include "core/common.h"
+
+/**
+ * Extcon cable name is shared with kernel extcon class.
+ * So do not change below strings.
+ */
+#define EXTCON_CABLE_USB "USB"
+#define EXTCON_CABLE_USB_HOST "USB-Host"
+#define EXTCON_CABLE_TA "TA"
+#define EXTCON_CABLE_HDMI "HDMI"
+#define EXTCON_CABLE_DOCK "Dock"
+#define EXTCON_CABLE_MIC_IN "Microphone"
+#define EXTCON_CABLE_HEADPHONE_OUT "Headphone"
+
+struct extcon_ops {
+ const char *name;
+ int status;
+ void (*init)(void *data);
+ void (*exit)(void *data);
+ int (*update)(int status);
+};
+
+#define EXTCON_OPS_REGISTER(dev) \
+static void __CONSTRUCTOR__ extcon_init(void) \
+{ \
+ /**
+ * If there is no predefined status value,
+ * default status will set as a negative value(-1).
+ * It will be updated as the initial value in booting time.
+ */ \
+ if (!dev.status) \
+ dev.status = -1; \
+ add_extcon(&dev); \
+} \
+static void __DESTRUCTOR__ extcon_exit(void) \
+{ \
+ remove_extcon(&dev); \
+}
+
+void add_extcon(struct extcon_ops *dev);
+void remove_extcon(struct extcon_ops *dev);
+
+int extcon_get_status(const char *name);
+
+#endif /* __EXTCON_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <vconf.h>
+#include "core/log.h"
+#include "core/device-notifier.h"
+#include "core/edbus-handler.h"
+#include "display/core.h"
+#include "extcon.h"
+
+#define METHOD_GET_HDMI "GetHDMI"
+#define SIGNAL_HDMI_STATE "ChangedHDMI"
+
+static struct extcon_ops hdmi_extcon_ops;
+
+static void hdmi_send_broadcast(int status)
+{
+ static int old;
+ char *arr[1];
+ char str_status[32];
+
+ if (old == status)
+ return;
+
+ _I("broadcast hdmi status %d", status);
+ old = status;
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+
+ broadcast_edbus_signal(DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
+ SIGNAL_HDMI_STATE, "i", arr);
+}
+
+static int hdmi_update(int status)
+{
+ _I("jack - hdmi changed %d", status);
+ pm_change_internal(getpid(), LCD_NORMAL);
+ vconf_set_int(VCONFKEY_SYSMAN_HDMI, status);
+ hdmi_send_broadcast(status);
+
+ if (status == 1)
+ pm_lock_internal(INTERNAL_LOCK_HDMI, LCD_DIM, STAY_CUR_STATE, 0);
+ else
+ pm_unlock_internal(INTERNAL_LOCK_HDMI, LCD_DIM, PM_SLEEP_MARGIN);
+
+ return 0;
+}
+
+static int display_changed(void *data)
+{
+ enum state_t state;
+ int hdmi;
+
+ if (!data)
+ return 0;
+
+ state = *(int *)data;
+ if (state != S_NORMAL)
+ return 0;
+
+ hdmi = hdmi_extcon_ops.status;
+ if (hdmi == 0) {
+ pm_lock_internal(INTERNAL_LOCK_HDMI, LCD_DIM, STAY_CUR_STATE, 0);
+ _I("hdmi is connected! dim lock is on.");
+ }
+ return 0;
+}
+
+static DBusMessage *dbus_hdmi_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ return make_reply_message(msg, hdmi_extcon_ops.status);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { METHOD_GET_HDMI, NULL, "i", dbus_hdmi_handler },
+};
+
+static void hdmi_init(void *data)
+{
+ int ret;
+
+ register_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static void hdmi_exit(void *data)
+{
+ unregister_notifier(DEVICE_NOTIFIER_LCD, display_changed);
+}
+
+static struct extcon_ops hdmi_extcon_ops = {
+ .name = EXTCON_CABLE_HDMI,
+ .init = hdmi_init,
+ .exit = hdmi_exit,
+ .update = hdmi_update,
+};
+
+EXTCON_OPS_REGISTER(hdmi_extcon_ops)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(deviced-vibrator C)
+
+########################################################
+# Build options:
+# -DTIZEN_ENGINEER_MODE -
+########################################################
+IF("${ARCH}" STREQUAL "emulator")
+ OPTION(USE_EMULATOR "Use Emulator" ON)
+ELSEIF("${ARCH}" STREQUAL "arm")
+ OPTION(USE_ARM "Use Arm" ON)
+ENDIF()
+
+IF("${ARCH_BIT}" STREQUAL "32")
+ OPTION(USE_32BIT "Use 32bit architecture" ON)
+ELSEIF("${ARCH_BIT}" STREQUAL "64")
+ OPTION(USE_64BIT "Use 64bit architecture" ON)
+ENDIF()
+
+########################################################
+# Deviced CMakeLists.txt
+########################################################
+SET(VERSION 0.1.0)
+
+IF("${PROFILE}" STREQUAL "wearable")
+ IF("${ARCH}" STREQUAL "arm")
+ SET(CIRCLE "on")
+ ENDIF()
+ENDIF()
+
+SET(SRCS
+ main.c
+ haptic.c
+ external.c
+ emulator.c
+ edbus-handler.c
+ ${CMAKE_SOURCE_DIR}/src/core/common.c
+ ${CMAKE_SOURCE_DIR}/src/core/config-parser.c
+ ${CMAKE_SOURCE_DIR}/src/core/device-idler.c
+ ${CMAKE_SOURCE_DIR}/src/core/device-notifier.c
+ ${CMAKE_SOURCE_DIR}/src/core/devices.c
+ ${CMAKE_SOURCE_DIR}/src/core/execute.c
+ ${CMAKE_SOURCE_DIR}/src/core/log.c
+ ${CMAKE_SOURCE_DIR}/src/shared/dbus.c
+)
+IF(CIRCLE STREQUAL on)
+ SET(SRCS ${SRCS} circle.c standard-vibcore.c)
+ELSE()
+ IF(STANDARD_MIX STREQUAL on)
+ SET(SRCS ${SRCS} standard-mix.c)
+ ELSE()
+ SET(SRCS ${SRCS} standard.c standard-vibcore.c)
+ ENDIF()
+ENDIF()
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src)
+
+SET(PKG_MODULES
+ ecore
+ edbus
+ vconf
+ dlog
+ capi-base-common
+ gio-2.0
+)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs2 REQUIRED ${PKG_MODULES})
+
+FOREACH(flag ${pkgs2_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Werror")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -lrt -fPIE")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
+
+IF(USE_ARM)
+ ADD_DEFINITIONS("-DTARGET")
+ELSEIF(USE_EMULATOR)
+ ADD_DEFINITIONS("-DEMULATOR")
+ENDIF()
+IF(USE_32BIT)
+ ADD_DEFINITIONS("-DARCH_32BIT")
+ELSEIF(USE_64BIT)
+ ADD_DEFINITIONS("-DARCH_64BIT")
+ENDIF()
+ADD_DEFINITIONS("-DDEBUG")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs2_LDFLAGS} "-ldl" "-lm")
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
+
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/scripts/deviced-vibrator.conf DESTINATION /etc/dbus-1/system.d)
+INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/system
+ FILES_MATCHING
+ PATTERN "deviced-vibrator.service")
--- /dev/null
+Standard Force Feedback Information
+
+1. Max effect id is 16.
+ It depends on force feedback driver.
+
+2. Do not increase effect id in case of repeated requests before previous effect finishs.
+ Standard Force Feedback does not reset the effect id on ff_set_effect function.
+ If the effect id is reseted as -1,
+ effect id will be increased until removing the effect from device by ioctl(EVIOCRMFF).
+ In this case Standard Force Feedback can not remove the previous effect id.
+
+3. Do not support to mix each effect.
+ If the request is occurred on the same time, it plays effect as per the last request.
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2016 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 <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <Ecore.h>
+#include <sys/types.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "haptic.h"
+#include "standard-vibcore.h"
+
+#define CIRCLE_ON_PATH "/sys/class/sec/motor/motor_on"
+#define CIRCLE_OFF_PATH "/sys/class/sec/motor/motor_off"
+
+static int fd_play = -1, fd_stop = -1;
+static dd_list *handle_list;
+static Ecore_Timer *stop_timer;
+static int unique_number;
+static bool state = false;
+
+static int stop_device(int device_handle);
+static bool find_from_list(int handle)
+{
+ dd_list *elem;
+
+ elem = DD_LIST_FIND(handle_list, (gpointer)(long)handle);
+ if (elem)
+ return true;
+
+ return false;
+}
+
+static Eina_Bool timer_cb(void *data)
+{
+ int device_handle = (int)(long)data;
+ _I("stop vibration by timer");
+
+ /* stop previous vibration */
+ stop_device(device_handle);
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+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)
+{
+ int n;
+ bool found = false;
+ dd_list *elem;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ /* if it is the first element */
+ n = DD_LIST_LENGTH(handle_list);
+ if (n == 0) {
+ _I("Open");
+ if (fd_play < 0) {
+ fd_play = open(CIRCLE_ON_PATH, O_RDONLY);
+ if (fd_play < 0) {
+ _E("Failed to open %s : %d", CIRCLE_ON_PATH, errno);
+ return -errno;
+ }
+ }
+ if (fd_stop < 0) {
+ fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
+ if (fd_stop < 0) {
+ _E("Failed to open %s : %d", CIRCLE_OFF_PATH, errno);
+ return -errno;
+ }
+ }
+ }
+
+ if (unique_number == INT_MAX)
+ unique_number = 0;
+
+ while (found != true) {
+ ++unique_number;
+ elem = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+ if (!elem)
+ found = true;
+ }
+
+ /* add info to local list */
+ DD_LIST_APPEND(handle_list, (gpointer)(long)unique_number);
+
+ *device_handle = unique_number;
+ return 0;
+}
+
+static int close_device(int device_handle)
+{
+ int r, n;
+ bool found;
+
+ found = find_from_list(device_handle);
+ if (!found)
+ return -EINVAL;
+
+ if (fd_stop < 0) {
+ fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
+ if (fd_stop < 0)
+ return -ENODEV;
+ }
+
+ /* stop vibration */
+ r = stop_device(device_handle);
+ if (r < 0)
+ _I("already stopped or failed to stop effect : %d", r);
+
+ /* unregister existing timer */
+ if (r >= 0) {
+ _D("device handle %d is closed and timer deleted", device_handle);
+ if (stop_timer) {
+ ecore_timer_del(stop_timer);
+ stop_timer = NULL;
+ }
+ }
+
+ standard_vibrate_close();
+
+ DD_LIST_REMOVE(handle_list, (gpointer)(long)device_handle);
+
+ /* if it is the last element */
+ n = DD_LIST_LENGTH(handle_list);
+ if (n == 0) {
+ _I("Close");
+ if (fd_play > 0) {
+ close(fd_play);
+ fd_play = -1;
+ }
+ if (fd_stop > 0) {
+ close(fd_stop);
+ fd_stop = -1;
+ }
+ }
+
+ return 0;
+}
+
+static int vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle)
+{
+ int ret;
+ char buf[8];
+ bool found;
+
+ found = find_from_list(device_handle);
+ if (!found)
+ return -EINVAL;
+
+ if (fd_play < 0) {
+ fd_play = open(CIRCLE_ON_PATH, O_RDONLY);
+ if (fd_play < 0)
+ return -ENODEV;
+ }
+
+ /* Zero(0) is the infinitely vibration value */
+ if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
+ duration = 0;
+
+ if (stop_timer)
+ stop_device(device_handle);
+
+ /* play vibration */
+ ret = read(fd_play, buf, 8);
+ if (ret < 0) {
+ _E("failed to play");
+ return -errno;
+ }
+
+ /* register timer */
+ if (duration) {
+ stop_timer = ecore_timer_add(duration/1000.f, timer_cb, (void *)(long)device_handle);
+ if (!stop_timer)
+ _E("Failed to add timer callback");
+ }
+
+ _D("device handle %d %dms", device_handle, duration);
+
+ return 0;
+}
+
+static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int stop_device(int device_handle)
+{
+ int ret;
+ char buf[8];
+ bool found;
+
+ found = find_from_list(device_handle);
+ if (!found)
+ return -EINVAL;
+
+ if (fd_stop < 0) {
+ fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
+ if (fd_stop < 0)
+ return -ENODEV;
+ }
+ ret = read(fd_stop, buf, 8);
+ if (ret < 0) {
+ _E("failed to stop");
+ return -errno;
+ }
+ if (stop_timer) {
+ ecore_timer_del(stop_timer);
+ stop_timer = NULL;
+ }
+
+ return 0;
+}
+
+static int get_device_state(int device_index, int *effect_state)
+{
+ if (!effect_state)
+ return -EINVAL;
+
+ *effect_state = state;
+ return 0;
+}
+
+static int create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+/* 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,
+ .vibrate_buffer = vibrate_buffer,
+ .vibrate_effect = standard_vibrate_effect,
+ .is_supported = standard_is_supported,
+ .stop_device = stop_device,
+ .get_device_state = get_device_state,
+ .create_effect = create_effect,
+ .get_buffer_duration = get_buffer_duration,
+ .convert_binary = convert_binary,
+};
+
+static bool is_valid(void)
+{
+ int ret;
+
+ if ((access(CIRCLE_ON_PATH, R_OK) != 0) ||
+ (access(CIRCLE_OFF_PATH, R_OK) != 0)) {
+ _E("Do not support wearable haptic device");
+ state = false;
+ return false;
+ }
+
+ ret = standard_config_parse();
+ if (ret < 0)
+ _E("failed to load standard vibration configuration file : %d", ret);
+
+ state = true;
+ _I("Support wearable haptic device");
+ return true;
+}
+
+static const struct haptic_plugin_ops *load(void)
+{
+ standard_set_vib_function(&vibrate_monotone);
+ return &default_plugin;
+}
+
+static const struct haptic_ops std_ops = {
+ .type = HAPTIC_STANDARD,
+ .is_valid = is_valid,
+ .load = load,
+};
+
+HAPTIC_OPS_REGISTER(&std_ops)
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2016 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 <stdbool.h>
+#include <assert.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/device-idler.h"
+#include "core/device-notifier.h"
+#include "core/list.h"
+#include "edbus-handler.h"
+
+#define EDBUS_INIT_RETRY_COUNT 5
+#define NAME_OWNER_CHANGED "NameOwnerChanged"
+#define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus'," \
+ "path='/org/freedesktop/DBus',interface='org.freedesktop.DBus'," \
+ "member='NameOwnerChanged',arg0='%s'"
+
+/* -1 is a default timeout value, it's converted to 25*1000 internally. */
+#define DBUS_REPLY_TIMEOUT (-1)
+#define RETRY_MAX 5
+
+struct edbus_list {
+ char *signal_name;
+ E_DBus_Signal_Handler *handler;
+};
+
+static struct edbus_object {
+ char *path;
+ char *interface;
+ E_DBus_Object *obj;
+ E_DBus_Interface *iface;
+} edbus_objects[] = {
+ { VIBRATOR_PATH_CORE, VIBRATOR_INTERFACE_CORE, NULL, NULL },
+ /* Add new object & interface here*/
+};
+
+struct watch_func_info {
+ bool deleted;
+ void (*func)(const char *sender, void *data);
+ void *data;
+};
+
+struct watch_info {
+ bool deleted;
+ char *sender;
+ dd_list *func_list;
+};
+
+static dd_list *edbus_object_list;
+static dd_list *edbus_owner_list;
+static dd_list *edbus_handler_list;
+static dd_list *edbus_watch_list;
+static int edbus_init_val;
+static DBusConnection *conn;
+static E_DBus_Connection *edbus_conn;
+static DBusPendingCall *edbus_request_name;
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+ DBusMessage *message, void *data);
+static int register_edbus_interface(struct edbus_object *object)
+{
+ if (!object) {
+ _E("object is invalid value!");
+ return -1;
+ }
+
+ object->obj = e_dbus_object_add(edbus_conn, object->path, NULL);
+ if (!object->obj) {
+ _E("fail to add edbus obj");
+ return -1;
+ }
+
+ object->iface = e_dbus_interface_new(object->interface);
+ if (!object->iface) {
+ _E("fail to add edbus interface");
+ return -1;
+ }
+
+ e_dbus_object_interface_attach(object->obj, object->iface);
+
+ return 0;
+}
+
+E_DBus_Interface *get_edbus_interface(const char *path)
+{
+ struct edbus_object *obj;
+ dd_list *elem;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(edbus_objects); i++)
+ if (!strcmp(path, edbus_objects[i].path))
+ return edbus_objects[i].iface;
+
+ /* find matched obj */
+ DD_LIST_FOREACH(edbus_object_list, elem, obj) {
+ if (strncmp(obj->path, path, strlen(obj->path)) == 0)
+ return obj->iface;
+ }
+
+ return NULL;
+}
+
+static void unregister_edbus_signal_handle(void)
+{
+ dd_list *tmp, *next;
+ struct edbus_list *entry;
+
+ DD_LIST_FOREACH_SAFE(edbus_handler_list, tmp, next, entry) {
+ if (!entry->handler)
+ continue;
+ e_dbus_signal_handler_del(edbus_conn, entry->handler);
+ DD_LIST_REMOVE(edbus_handler_list, entry);
+ free(entry->signal_name);
+ free(entry);
+ }
+}
+
+int register_edbus_signal_handler(const char *path, const char *interface,
+ const char *name, E_DBus_Signal_Cb cb)
+{
+ dd_list *tmp;
+ struct edbus_list *entry;
+ E_DBus_Signal_Handler *handler;
+
+ DD_LIST_FOREACH(edbus_handler_list, tmp, entry) {
+ if (strncmp(entry->signal_name, name, strlen(name)) == 0)
+ return -EEXIST;
+ }
+
+ handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
+ interface, name, cb, NULL);
+
+ if (!handler) {
+ _E("fail to add edbus handler");
+ return -ENOMEM;
+ }
+
+ entry = malloc(sizeof(struct edbus_list));
+
+ if (!entry) {
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ entry->signal_name = strndup(name, strlen(name));
+
+ if (!entry->signal_name) {
+ _E("Malloc failed");
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ free(entry);
+ return -ENOMEM;
+ }
+
+ entry->handler = handler;
+ DD_LIST_PREPEND(edbus_handler_list, entry);
+ if (!edbus_handler_list) {
+ _E("dd_list_prepend failed");
+ e_dbus_signal_handler_del(edbus_conn, handler);
+ free(entry->signal_name);
+ free(entry);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int unregister_edbus_signal_handler(const char *path, const char *interface,
+ const char *name)
+{
+ dd_list *tmp, *next;
+ struct edbus_list *entry;
+
+ DD_LIST_FOREACH_SAFE(edbus_handler_list, tmp, next, entry) {
+ if (strncmp(entry->signal_name, name, strlen(name) + 1) == 0) {
+ e_dbus_signal_handler_del(edbus_conn, entry->handler);
+ DD_LIST_REMOVE(edbus_handler_list, entry);
+ free(entry->signal_name);
+ free(entry);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static void print_watch_item(void)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ dd_list *e;
+
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ _D("watch sender : %s, deleted : %d",
+ watch->sender, watch->deleted);
+ DD_LIST_FOREACH(watch->func_list, e, finfo)
+ _D("\tfunc : %p, deleted : %d",
+ finfo->func, finfo->deleted);
+ }
+}
+
+static bool get_valid_watch_item(void)
+{
+ struct watch_info *watch;
+ dd_list *elem;
+
+ DD_LIST_FOREACH(edbus_watch_list, elem, watch) {
+ if (!watch->deleted)
+ return true;
+ }
+
+ return false;
+}
+
+static void watch_idler_cb(void *data)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ dd_list *next;
+ dd_list *elem;
+ dd_list *enext;
+ char match[256];
+
+ DD_LIST_FOREACH_SAFE(edbus_watch_list, n, next, watch) {
+ if (!watch->deleted)
+ continue;
+
+ /* remove dbus match */
+ snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->sender);
+ dbus_bus_remove_match(conn, match, NULL);
+
+ _I("%s is not watched by dbus!", watch->sender);
+
+ /* remove watch func list */
+ DD_LIST_FOREACH_SAFE(watch->func_list, elem, enext, finfo)
+ free(finfo);
+
+ /* remove watch item */
+ DD_LIST_FREE_LIST(watch->func_list);
+ DD_LIST_REMOVE_LIST(edbus_watch_list, n);
+ free(watch->sender);
+ free(watch);
+ }
+
+ /* if the last request, remove message filter */
+ if (!get_valid_watch_item())
+ dbus_connection_remove_filter(conn, message_filter, NULL);
+}
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+ DBusMessage *message, void *data)
+{
+ int ret;
+ const char *iface, *member;
+ const char *sender;
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *n;
+ int len;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ iface = dbus_message_get_interface(message);
+ member = dbus_message_get_member(message);
+
+ if (strncmp(iface, DBUS_INTERFACE_DBUS,
+ sizeof(DBUS_INTERFACE_DBUS)))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (strncmp(member, NAME_OWNER_CHANGED,
+ sizeof(NAME_OWNER_CHANGED)))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ ret = dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &sender,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ len = strlen(sender) + 1;
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ if (!watch->deleted &&
+ !strncmp(watch->sender, sender, len))
+ break;
+ }
+
+ if (!watch)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ DD_LIST_FOREACH(watch->func_list, n, finfo) {
+ if (!finfo->deleted &&
+ finfo->func)
+ finfo->func(watch->sender, finfo->data);
+ }
+
+ /* no interest in this item anymore */
+ watch->deleted = true;
+
+ print_watch_item();
+ add_idle_request(watch_idler_cb, NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static struct watch_info *get_matched_watch_item(const char *sender)
+{
+ int len;
+ dd_list *n;
+ struct watch_info *watch;
+
+ if (!sender)
+ return NULL;
+
+ len = strlen(sender) + 1;
+ /* check the sender&type is already registered */
+ DD_LIST_FOREACH(edbus_watch_list, n, watch) {
+ if (!watch->deleted &&
+ !strncmp(watch->sender, sender, len))
+ return watch;
+ }
+
+ return NULL;
+}
+
+static struct watch_info *add_watch_item(const char *sender)
+{
+ DBusError err;
+ struct watch_info *watch;
+ char match[256];
+ int ret;
+
+ if (!sender)
+ return NULL;
+
+ watch = calloc(1, sizeof(struct watch_info));
+ if (!watch)
+ return NULL;
+
+ watch->sender = strdup(sender);
+ if (!watch->sender)
+ goto out;
+
+ dbus_error_init(&err);
+ /* add name owner changed match string */
+ snprintf(match, sizeof(match), NAME_OWNER_MATCH, watch->sender);
+ dbus_bus_add_match(conn, match, &err);
+
+ if (dbus_error_is_set(&err)) {
+ _E("fail to add match for %s [%s:%s]",
+ sender, err.name, err.message);
+ dbus_error_free(&err);
+ goto out;
+ }
+
+ /* if the first request, add message filter */
+ if (!get_valid_watch_item()) {
+ ret = dbus_connection_add_filter(conn,
+ message_filter, NULL, NULL);
+ if (!ret) {
+ _E("fail to add message filter!");
+ dbus_bus_remove_match(conn, match, NULL);
+ goto out;
+ }
+ _I("success to add message filter!");
+ }
+
+ /* Add watch to watch list */
+ DD_LIST_APPEND(edbus_watch_list, watch);
+ _I("%s is watched by dbus!", sender);
+ return watch;
+
+out:
+ if (watch) {
+ free(watch->sender);
+ free(watch);
+ }
+
+ return NULL;
+}
+
+int register_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data), void *data)
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *elem;
+ bool isnew = false;
+
+ if (!sender || !func) {
+ _E("invalid argument : sender(NULL) || func(NULL)");
+ return -EINVAL;
+ }
+
+ watch = get_matched_watch_item(sender);
+ if (!watch) {
+ /* create new watch item */
+ watch = add_watch_item(sender);
+ if (!watch) {
+ _E("fail to add watch item");
+ return -EPERM;
+ }
+ isnew = true;
+ }
+
+ /* find the same callback */
+ DD_LIST_FOREACH(watch->func_list, elem, finfo) {
+ if (finfo->func == func) {
+ _E("there is already the same callback");
+ goto out;
+ }
+ }
+
+ finfo = calloc(1, sizeof(struct watch_func_info));
+ if (!finfo) {
+ _E("fail to allocate watch func info");
+ goto out;
+ }
+
+ finfo->func = func;
+ finfo->data = data;
+
+ /* add callback function to the watch list */
+ DD_LIST_APPEND(watch->func_list, finfo);
+
+ _I("register watch func(%p) of %s", func, sender);
+ return 0;
+out:
+ if (isnew)
+ watch->deleted = true;
+
+ return -EPERM;
+}
+
+int unregister_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data))
+{
+ struct watch_info *watch;
+ struct watch_func_info *finfo;
+ dd_list *elem;
+ bool matched = false;
+
+ if (!sender || !func) {
+ _E("invalid argument : sender(NULL) || func(NULL)");
+ return -EINVAL;
+ }
+
+ watch = get_matched_watch_item(sender);
+ if (!watch) {
+ _E("fail to get matched watch item");
+ return -ENODEV;
+ }
+
+ /* check the no interest function */
+ DD_LIST_FOREACH(watch->func_list, elem, finfo) {
+ if (finfo->func == func)
+ finfo->deleted = true;
+ if (!finfo->deleted)
+ matched = true;
+ }
+
+ /* if it is the last item */
+ if (!matched)
+ watch->deleted = true;
+
+ _I("unregister watch func(%p) of %s", func, sender);
+ return 0;
+}
+
+static void unregister_edbus_watch_all(void)
+{
+ dd_list *n, *next;
+ struct watch_info *watch;
+
+ DD_LIST_FOREACH_SAFE(edbus_watch_list, n, next, watch)
+ watch->deleted = true;
+
+ add_idle_request(watch_idler_cb, NULL);
+}
+
+static int register_method(E_DBus_Interface *iface,
+ const struct edbus_method *edbus_methods, int size)
+{
+ int ret;
+ int i;
+
+ assert(iface);
+ assert(edbus_methods);
+
+ for (i = 0; i < size; i++) {
+ ret = e_dbus_interface_method_add(iface,
+ edbus_methods[i].member,
+ edbus_methods[i].signature,
+ edbus_methods[i].reply_signature,
+ edbus_methods[i].func);
+ if (!ret) {
+ _E("fail to add method %s!", edbus_methods[i].member);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int register_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size)
+{
+ struct edbus_object *obj;
+ dd_list *elem;
+ int ret;
+
+ if (!path || !interface || !edbus_methods || size < 1) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ /* find matched obj */
+ DD_LIST_FOREACH(edbus_object_list, elem, obj) {
+ if (strncmp(obj->path, path, strlen(obj->path)) == 0 &&
+ strncmp(obj->interface, interface, strlen(obj->interface)) == 0) {
+ _I("found matched item : obj(%p)", obj);
+ break;
+ }
+ }
+
+ /* if there is no matched obj */
+ if (!obj) {
+ obj = malloc(sizeof(struct edbus_object));
+ if (!obj) {
+ _E("fail to allocate %s interface", path);
+ return -ENOMEM;
+ }
+
+ obj->path = strdup(path);
+ obj->interface = strdup(interface);
+
+ ret = register_edbus_interface(obj);
+ if (ret < 0) {
+ _E("fail to register %s interface(%d)", obj->path, ret);
+ free(obj->path);
+ free(obj->interface);
+ free(obj);
+ return ret;
+ }
+
+ DD_LIST_APPEND(edbus_object_list, obj);
+ }
+
+ ret = register_method(obj->iface, edbus_methods, size);
+ if (ret < 0) {
+ _E("fail to register %s method(%d)", obj->path, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int unregister_edbus_interface_all(void)
+{
+ struct edbus_object *obj;
+ dd_list *elem, *n;
+
+ DD_LIST_FOREACH_SAFE(edbus_object_list, elem, n, obj) {
+ DD_LIST_REMOVE(edbus_object_list, obj);
+ free(obj->path);
+ free(obj->interface);
+ free(obj);
+ }
+
+ return 0;
+}
+
+int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size)
+{
+ E_DBus_Interface *iface;
+ int ret;
+
+ if (!path || !edbus_methods || size < 1) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ iface = get_edbus_interface(path);
+ if (!iface) {
+ _E("fail to get edbus interface!");
+ return -ENODEV;
+ }
+
+ ret = register_method(iface, edbus_methods, size);
+ if (ret < 0) {
+ _E("fail to register %s method(%d)", path, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
+{
+ DBusError err;
+ unsigned int val;
+ int r;
+
+ if (!msg) {
+ _D("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
+ if (!r) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+
+ _I("Request Name reply : %d", val);
+}
+
+static void check_owner_name(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char *pa[1];
+ char exe_name[PATH_MAX];
+ char *entry;
+ dd_list *n;
+ int pid;
+
+ DD_LIST_FOREACH(edbus_owner_list, n, entry) {
+ pa[0] = entry;
+ msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
+ E_DBUS_FDO_PATH,
+ E_DBUS_FDO_INTERFACE,
+ "GetConnectionUnixProcessID", "s", pa);
+
+ if (!msg) {
+ _E("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &pid);
+ if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0)
+ goto out;
+ _I("%s(%d)", exe_name, pid);
+
+out:
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+ }
+}
+
+static void check_owner_list(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter array, item;
+ char *pa[1];
+ char *name;
+ char *entry;
+
+ pa[0] = VIBRATOR_BUS_NAME;
+ msg = dbus_method_sync_with_reply(E_DBUS_FDO_BUS,
+ E_DBUS_FDO_PATH,
+ E_DBUS_FDO_INTERFACE,
+ "ListQueuedOwners", "s", pa);
+
+ if (!msg) {
+ _E("invalid DBusMessage!");
+ return;
+ }
+
+ dbus_error_init(&err);
+ dbus_message_iter_init(msg, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ goto out;
+ dbus_message_iter_recurse(&array, &item);
+ while (dbus_message_iter_get_arg_type(&item) == DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(&item, &name);
+ entry = strndup(name, strlen(name));
+ DD_LIST_APPEND(edbus_owner_list, entry);
+ if (!edbus_owner_list) {
+ _E("append failed");
+ free(entry);
+ goto out;
+ }
+ dbus_message_iter_next(&item);
+ }
+
+out:
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+}
+
+void edbus_init(void *data)
+{
+ DBusError error;
+ int retry = 0;
+ int i, ret;
+
+ dbus_threads_init_default();
+ dbus_error_init(&error);
+
+ do {
+ edbus_init_val = e_dbus_init();
+ if (edbus_init_val)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to init edbus");
+ return;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (conn)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get dbus");
+ goto out1;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_conn = e_dbus_connection_setup(conn);
+ if (edbus_conn)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to get edbus");
+ goto out2;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ retry = 0;
+ do {
+ edbus_request_name = e_dbus_request_name(edbus_conn, VIBRATOR_BUS_NAME,
+ DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
+ if (edbus_request_name)
+ break;
+ if (retry == EDBUS_INIT_RETRY_COUNT) {
+ _E("fail to request edbus name");
+ goto out3;
+ }
+ retry++;
+ } while (retry <= EDBUS_INIT_RETRY_COUNT);
+
+ for (i = 0; i < ARRAY_SIZE(edbus_objects); i++) {
+ ret = register_edbus_interface(&edbus_objects[i]);
+ if (ret < 0) {
+ _E("fail to add obj & interface for %s",
+ edbus_objects[i].interface);
+ return;
+ }
+ _D("add new obj for %s", edbus_objects[i].interface);
+ }
+ check_owner_list();
+ check_owner_name();
+ return;
+
+out3:
+ e_dbus_connection_close(edbus_conn);
+out2:
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+out1:
+ e_dbus_shutdown();
+}
+
+void edbus_exit(void *data)
+{
+ unregister_edbus_signal_handle();
+ unregister_edbus_watch_all();
+ unregister_edbus_interface_all();
+ e_dbus_connection_close(edbus_conn);
+ e_dbus_shutdown();
+}
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2016 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 __EDBUS_HANDLE_H__
+#define __EDBUS_HANDLE_H__
+
+#include <E_DBus.h>
+#include "shared/dbus.h"
+
+struct edbus_method {
+ const char *member;
+ const char *signature;
+ const char *reply_signature;
+ E_DBus_Method_Cb func;
+};
+int register_edbus_interface_and_method(const char *path,
+ const char *interface,
+ const struct edbus_method *edbus_methods, int size);
+int register_edbus_method(const char *path, const struct edbus_method *edbus_methods, int size);
+int register_edbus_signal_handler(const char *path, const char *interface,
+ const char *name, E_DBus_Signal_Cb cb);
+int unregister_edbus_signal_handler(const char *path, const char *interface,
+ const char *name);
+E_DBus_Interface *get_edbus_interface(const char *path);
+int register_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data), void *data);
+int unregister_edbus_watch(const char *sender,
+ void (*func)(const char *sender, void *data));
+
+void edbus_init(void *data);
+void edbus_exit(void *data);
+
+#endif /* __EDBUS_HANDLE_H__ */
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2012 - 2013 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 "core/log.h"
+#include "haptic.h"
+
+#define DEFAULT_HAPTIC_HANDLE 0xFFFF
+#define DEFAULT_EFFECT_HANDLE 0xFFFA
+
+/* 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)
+{
+ if (device_handle)
+ *device_handle = DEFAULT_HAPTIC_HANDLE;
+
+ return 0;
+}
+
+static int close_device(int device_handle)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ if (effect_handle)
+ *effect_handle = DEFAULT_EFFECT_HANDLE;
+
+ return 0;
+}
+
+static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ if (effect_handle)
+ *effect_handle = DEFAULT_EFFECT_HANDLE;
+
+ return 0;
+}
+
+static int vibrate_effect(int device_handle, const char *pattern, int feedback, int priority)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int stop_device(int device_handle)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int is_supported(const char *pattern)
+{
+ return 0;
+}
+
+static int get_device_state(int device_index, int *effect_state)
+{
+ if (effect_state)
+ *effect_state = 0;
+
+ return 0;
+}
+
+static int create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+ if (device_handle != DEFAULT_HAPTIC_HANDLE)
+ return -EINVAL;
+
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+/* 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,
+ .vibrate_buffer = vibrate_buffer,
+ .vibrate_effect = vibrate_effect,
+ .is_supported = is_supported,
+ .stop_device = stop_device,
+ .get_device_state = get_device_state,
+ .create_effect = create_effect,
+ .get_buffer_duration = get_buffer_duration,
+ .convert_binary = convert_binary,
+};
+
+static bool is_valid(void)
+{
+#ifdef EMULATOR
+ _I("Support emulator haptic device");
+ return true;
+#else
+ _E("Do not support emulator haptic device");
+ return false;
+#endif
+}
+
+static const struct haptic_plugin_ops *load(void)
+{
+ return &default_plugin;
+}
+
+static const struct haptic_ops emul_ops = {
+ .is_valid = is_valid,
+ .load = load,
+};
+
+HAPTIC_OPS_REGISTER(&emul_ops)
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2012 - 2013 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 "core/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;
+ const struct haptic_plugin_ops *(*get_haptic_plugin_interface) () = NULL;
+
+ if (stat(HAPTIC_MODULE_PATH, &buf)) {
+ _E("file(%s) is not presents", HAPTIC_MODULE_PATH);
+ goto error;
+ }
+
+ dlopen_handle = dlopen(HAPTIC_MODULE_PATH, RTLD_NOW);
+ if (!dlopen_handle) {
+ _E("dlopen failed");
+ goto error;
+ }
+
+ get_haptic_plugin_interface = dlsym(dlopen_handle, "get_haptic_plugin_interface");
+ if (!get_haptic_plugin_interface) {
+ _E("dlsym failed");
+ goto error;
+ }
+
+ plugin_intf = get_haptic_plugin_interface();
+ if (!plugin_intf) {
+ _E("get_haptic_plugin_interface() failed");
+ 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
+[Haptic]
+# level
+# how much does the vibration level to subdivide.
+# The max value of vibration level fixed at 100.
+# The min value of vibration level fixed at 0.
+level=3
+
+[level0]
+value=0
+
+[level1]
+value=80
+
+[level2]
+value=100
--- /dev/null
+[Haptic]
+# level
+# how much does the vibration level to subdivide.
+# The max value of vibration level fixed at 100.
+# The min value of vibration level fixed at 0.
+level=6
+
+[level0]
+value=0
+
+[level1]
+value=20
+
+[level2]
+value=40
+
+[level3]
+value=60
+
+[level4]
+value=80
+
+[level5]
+value=100
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2012 - 2013 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 "core/log.h"
+#include "core/list.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/device-idler.h"
+#include "edbus-handler.h"
+#include "core/device-notifier.h"
+#include "core/config-parser.h"
+#include "haptic.h"
+
+#ifndef DATADIR
+#define DATADIR "/usr/share/deviced"
+#endif
+
+#define HAPTIC_CONF_PATH "/etc/deviced/haptic.conf"
+#define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
+#define SIGNAL_POWEROFF_STATE "ChangeState"
+
+/* hardkey vibration variable */
+#define HARDKEY_VIB_ITERATION 1
+#define HARDKEY_VIB_FEEDBACK 3
+#define HARDKEY_VIB_PRIORITY 2
+#define HARDKEY_VIB_DURATION 30
+#define HAPTIC_FEEDBACK_STEP 20
+#define DEFAULT_FEEDBACK_LEVEL 3
+
+/* 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 CHECK_VALID_OPS(ops, r) ((ops) ? true : !(r = -ENODEV))
+#define RETRY_CNT 3
+
+struct haptic_info {
+ char *sender;
+ dd_list *handle_list;
+};
+
+struct vibrate_effect_info {
+ unsigned int handle;
+ char *pattern;
+ int level;
+ int priority;
+};
+
+/* for playing */
+static int g_handle;
+
+/* haptic operation variable */
+static dd_list *h_head;
+static dd_list *haptic_handle_list;
+static const struct haptic_plugin_ops *h_ops;
+static enum haptic_type h_type;
+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 haptic_internal_init(void);
+static int remove_haptic_info(struct haptic_info *info);
+
+void add_haptic(const struct haptic_ops *ops)
+{
+ DD_LIST_APPEND(h_head, (void *)ops);
+}
+
+void remove_haptic(const struct haptic_ops *ops)
+{
+ DD_LIST_REMOVE(h_head, (void *)ops);
+}
+
+static int haptic_module_load(void)
+{
+ struct haptic_ops *ops;
+ dd_list *elem;
+ int r;
+
+ /* find valid plugin */
+ DD_LIST_FOREACH(h_head, elem, ops) {
+ if (ops->is_valid && ops->is_valid()) {
+ if (ops->load)
+ h_ops = ops->load();
+ h_type = ops->type;
+ break;
+ }
+ }
+
+ if (!CHECK_VALID_OPS(h_ops, r)) {
+ _E("Can't find the valid haptic device");
+ 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. */
+ haptic_internal_init();
+
+ return 0;
+}
+
+static int convert_magnitude_by_conf(int level)
+{
+ int i, step;
+
+ assert(level >= 0 && level <= 100);
+
+ 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;
+}
+
+static DBusMessage *edbus_get_count(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret, val;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ ret = h_ops->get_device_count(&val);
+ if (ret >= 0)
+ ret = val;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static void haptic_name_owner_changed(const char *sender, void *data)
+{
+ dd_list *n;
+ struct haptic_info *info = data;
+ int handle;
+
+ _I("%s (sender:%s)", __func__, sender);
+
+ if (!info)
+ return;
+
+ for (n = info->handle_list; n; n = n->next) {
+ handle = (int)(long)n->data;
+ h_ops->stop_device(handle);
+ h_ops->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);
+ DD_LIST_APPEND(haptic_handle_list, info);
+
+ register_edbus_watch(sender, haptic_name_owner_changed, info);
+
+ return info;
+}
+
+static int remove_haptic_info(struct haptic_info *info)
+{
+ assert(info);
+
+ unregister_edbus_watch(info->sender, haptic_name_owner_changed);
+
+ DD_LIST_REMOVE(haptic_handle_list, info);
+ DD_LIST_FREE_LIST(info->handle_list);
+ free(info->sender);
+ free(info);
+
+ return 0;
+}
+
+static struct haptic_info *get_matched_haptic_info(const char *sender)
+{
+ dd_list *n;
+ struct haptic_info *info;
+ int len;
+
+ assert(sender);
+
+ len = strlen(sender) + 1;
+ DD_LIST_FOREACH(haptic_handle_list, n, info) {
+ if (!strncmp(info->sender, sender, len))
+ return info;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *edbus_open_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int index, handle, ret;
+ struct haptic_info *info;
+ const char *sender;
+
+ /* Load haptic module before booting done */
+ if (!CHECK_VALID_OPS(h_ops, ret)) {
+ ret = haptic_module_load();
+ if (ret < 0)
+ goto exit;
+ }
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->open_device(index, &handle);
+ if (ret < 0)
+ goto exit;
+
+
+ sender = dbus_message_get_sender(msg);
+ if (!sender) {
+ ret = -EPERM;
+ h_ops->close_device(handle);
+ goto exit;
+ }
+
+ info = get_matched_haptic_info(sender);
+ if (!info) {
+ info = add_haptic_info(sender);
+ if (!info) {
+ _E("fail to create haptic information");
+ ret = -EPERM;
+ h_ops->close_device(handle);
+ goto exit;
+ }
+ }
+
+ DD_LIST_APPEND(info->handle_list, (gpointer)(long)handle);
+
+ ret = handle;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_close_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int handle;
+ int ret;
+ struct haptic_info *info;
+ const char *sender;
+ int cnt;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ sender = dbus_message_get_sender(msg);
+ if (!sender) {
+ _E("fail to get sender from dbus message");
+ ret = -EPERM;
+ goto exit;
+ }
+
+ ret = h_ops->close_device(handle);
+ if (ret < 0)
+ goto exit;
+
+ info = get_matched_haptic_info(sender);
+ if (!info) {
+ _E("fail to find the matched haptic info.");
+ goto exit;
+ }
+
+ DD_LIST_REMOVE(info->handle_list, (gpointer)(long)handle);
+ cnt = DD_LIST_LENGTH(info->handle_list);
+ if (cnt == 0)
+ remove_haptic_info(info);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_vibrate_monotone(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int handle;
+ int duration, level, priority, e_handle, ret = 0;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INT32, &duration,
+ DBUS_TYPE_INT32, &level,
+ DBUS_TYPE_INT32, &priority, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* convert as per conf value */
+ level = convert_magnitude_by_conf(level);
+ if (level < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->vibrate_monotone(handle, duration, level, priority, &e_handle);
+ if (ret >= 0)
+ ret = e_handle;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+
+}
+
+static DBusMessage *edbus_vibrate_buffer(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int handle;
+ unsigned char *data;
+ int size, iteration, level, priority, e_handle, ret = 0;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, &size,
+ DBUS_TYPE_INT32, &iteration,
+ DBUS_TYPE_INT32, &level,
+ DBUS_TYPE_INT32, &priority, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* convert as per conf value */
+ level = convert_magnitude_by_conf(level);
+ if (level < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->vibrate_buffer(handle, data, iteration, level, priority, &e_handle);
+ if (ret >= 0)
+ ret = e_handle;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static void vibrate_effect_idler_cb(void *data)
+{
+ struct vibrate_effect_info *vibrate_info = (struct vibrate_effect_info *)data;
+
+ h_ops->vibrate_effect(vibrate_info->handle, vibrate_info->pattern,
+ vibrate_info->level, vibrate_info->priority);
+ free(vibrate_info->pattern);
+ free(vibrate_info);
+}
+
+static DBusMessage *edbus_vibrate_effect(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ struct vibrate_effect_info *vibrate_info;
+ unsigned int handle;
+ char *pattern;
+ int level, priority, ret = 0;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INT32, &level,
+ DBUS_TYPE_INT32, &priority, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* convert as per conf value */
+ level = convert_magnitude_by_conf(level);
+ if (level < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ vibrate_info = calloc(1, sizeof(struct vibrate_effect_info));
+ if (!vibrate_info) {
+ _E("failed to allocate memory for vibrate_info");
+ ret = -errno;
+ goto exit;
+ }
+ vibrate_info->handle = handle;
+ vibrate_info->pattern = strdup(pattern);
+ 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_effect_idler_cb, (void *)vibrate_info);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_stop_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int handle;
+ int ret = 0;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->stop_device(handle);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_get_state(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int index, state, ret;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->get_device_state(index, &state);
+ if (ret >= 0)
+ ret = state;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_create_effect(E_DBus_Object *obj, DBusMessage *msg)
+{
+ static unsigned char data[MAX_EFFECT_BUFFER];
+ static unsigned char *p = data;
+ DBusMessageIter iter, arr;
+ DBusMessage *reply;
+ haptic_module_effect_element *elem_arr;
+ int i, size, cnt, ret, bufsize = sizeof(data);
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &bufsize,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &elem_arr, &size,
+ DBUS_TYPE_INT32, &cnt, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (bufsize > MAX_EFFECT_BUFFER) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ for (i = 0; i < cnt; ++i)
+ _D("[%2d] %d %d", i, elem_arr[i].haptic_duration, elem_arr[i].haptic_level);
+
+ memset(data, 0, MAX_EFFECT_BUFFER);
+ ret = h_ops->create_effect(data, bufsize, elem_arr, cnt);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
+ dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &p, bufsize);
+ dbus_message_iter_close_container(&iter, &arr);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_get_duration(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int handle;
+ unsigned char *data;
+ int size, duration, ret;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, &size,
+ DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->get_buffer_duration(handle, data, &duration);
+ if (ret >= 0)
+ ret = duration;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_save_binary(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned char *data;
+ char *path;
+ int size, ret;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, &size,
+ DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ _D("file path : %s", path);
+ ret = h_ops->convert_binary(data, size, path);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_show_handle_list(E_DBus_Object *obj, DBusMessage *msg)
+{
+ dd_list *n;
+ dd_list *elem;
+ struct haptic_info *info;
+ int cnt = 0;
+
+ _D(" sender handle");
+ DD_LIST_FOREACH(haptic_handle_list, n, info) {
+ for (elem = info->handle_list; elem; elem = elem->next)
+ _D("[%2d]%s %d", cnt++, info->sender, (int)(long)elem->data);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *edbus_pattern_is_supported(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *data;
+ int ret = 0;
+
+ if (!CHECK_VALID_OPS(h_ops, ret))
+ goto exit;
+
+ if (haptic_disabled)
+ goto exit;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &data,
+ DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = h_ops->is_supported(data);
+
+ _I("%s is supported : %d", data, ret);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static int haptic_internal_init(void)
+{
+ int r;
+ if (!CHECK_VALID_OPS(h_ops, r))
+ return r;
+ return h_ops->open_device(HAPTIC_MODULE_DEVICE_ALL, &g_handle);
+}
+
+static int haptic_internal_exit(void)
+{
+ int r;
+ if (!CHECK_VALID_OPS(h_ops, r))
+ return r;
+ return h_ops->close_device(g_handle);
+}
+
+static void haptic_hardkey_changed_cb(void *data, DBusMessage *msg)
+{
+ int level, status, e_handle, ret;
+
+ if (!CHECK_VALID_OPS(h_ops, ret)) {
+ ret = haptic_module_load();
+ if (ret < 0)
+ return;
+ }
+
+ if (!g_handle)
+ haptic_internal_init();
+
+ /* if haptic is stopped, do not play vibration */
+ if (haptic_disabled)
+ return;
+
+ if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &status) < 0) {
+ _E("fail to get VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL");
+ status = 1;
+ }
+
+ /* when turn off haptic feedback option */
+ if (!status)
+ return;
+
+ ret = vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &level);
+ if (ret < 0) {
+ _E("fail to get VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT");
+ level = HARDKEY_VIB_FEEDBACK;
+ }
+
+ ret = h_ops->vibrate_monotone(g_handle, HARDKEY_VIB_DURATION,
+ level*HAPTIC_FEEDBACK_STEP, HARDKEY_VIB_PRIORITY, &e_handle);
+ if (ret < 0)
+ _E("fail to vibrate buffer : %d", ret);
+
+ return;
+}
+
+static void haptic_poweroff_cb(void *data, DBusMessage *msg)
+{
+ int e_handle, ret;
+ struct timespec time = {0,};
+
+ if (!CHECK_VALID_OPS(h_ops, ret)) {
+ ret = haptic_module_load();
+ if (ret < 0)
+ return;
+ }
+
+ if (!g_handle)
+ haptic_internal_init();
+
+ /* power off vibration */
+ ret = h_ops->vibrate_monotone(g_handle, POWER_OFF_VIB_DURATION,
+ POWER_VIB_FEEDBACK, HARDKEY_VIB_PRIORITY, &e_handle);
+ if (ret < 0) {
+ _E("fail 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 struct edbus_method edbus_methods[] = {
+ { "GetCount", NULL, "i", edbus_get_count },
+ { "OpenDevice", "i", "i", edbus_open_device },
+ { "CloseDevice", "u", "i", edbus_close_device },
+ { "StopDevice", "u", "i", edbus_stop_device },
+ { "VibrateMonotone", "uiii", "i", edbus_vibrate_monotone },
+ { "VibrateBuffer", "uayiii", "i", edbus_vibrate_buffer },
+ { "VibrateEffect", "usii", "i", edbus_vibrate_effect },
+ { "GetState", "i", "i", edbus_get_state },
+ { "GetDuration", "uay", "i", edbus_get_duration },
+ { "CreateEffect", "iayi", "ayi", edbus_create_effect },
+ { "SaveBinary", "ays", "i", edbus_save_binary },
+ { "ShowHandleList", NULL, NULL, edbus_show_handle_list },
+ { "IsSupported", "s", "i", edbus_pattern_is_supported },
+ /* Add methods here */
+};
+
+int haptic_probe(void)
+{
+ /**
+ * load haptic module.
+ * if there is no haptic module,
+ * deviced does not activate a haptic interface.
+ */
+ return haptic_module_load();
+}
+
+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 = register_edbus_interface_and_method(VIBRATOR_PATH_HAPTIC,
+ VIBRATOR_INTERFACE_HAPTIC,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (r < 0)
+ _E("fail to init edbus interface and method(%d)", r);
+
+ /* register notifier for below each event */
+ register_edbus_signal_handler(DEVICED_PATH_KEY,
+ DEVICED_INTERFACE_KEY,
+ SIGNAL_CHANGE_HARDKEY,
+ haptic_hardkey_changed_cb);
+
+ register_edbus_signal_handler(DEVICED_PATH_POWEROFF,
+ DEVICED_INTERFACE_POWEROFF,
+ SIGNAL_POWEROFF_STATE,
+ haptic_poweroff_cb);
+
+ /* add watch for sound capturing value */
+ if (haptic_conf.sound_capture)
+ vconf_notify_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb, NULL);
+}
+
+void haptic_exit(void)
+{
+ struct haptic_ops *ops;
+ dd_list *elem;
+ int r;
+
+ /* remove watch */
+ if (haptic_conf.sound_capture)
+ vconf_ignore_key_changed(VCONFKEY_RECORDER_STATE, sound_capturing_cb);
+
+ /* unregister notifier for below each event */
+ unregister_edbus_signal_handler(DEVICED_PATH_KEY,
+ DEVICED_INTERFACE_KEY,
+ SIGNAL_CHANGE_HARDKEY);
+
+ unregister_edbus_signal_handler(DEVICED_PATH_POWEROFF,
+ DEVICED_INTERFACE_POWEROFF,
+ SIGNAL_POWEROFF_STATE);
+
+ /* release haptic data memory */
+ safe_free(haptic_conf.level_arr);
+
+ if (!CHECK_VALID_OPS(h_ops, r))
+ return;
+
+ /* haptic exit for deviced */
+ haptic_internal_exit();
+
+ /* release plugin */
+ DD_LIST_FOREACH(h_head, elem, ops) {
+ if (ops->is_valid && ops->is_valid()) {
+ if (ops->release)
+ ops->release();
+ h_ops = NULL;
+ break;
+ }
+ }
+}
+
+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
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2012 - 2013 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 __HAPTIC_H__
+#define __HAPTIC_H__
+
+#include <stdbool.h>
+#include "core/common.h"
+#include "haptic-plugin-intf.h"
+
+#define HAPTIC_OPS_REGISTER(dev) \
+static void __CONSTRUCTOR__ module_init(void) \
+{ \
+ add_haptic(dev); \
+} \
+static void __DESTRUCTOR__ module_exit(void) \
+{ \
+ remove_haptic(dev); \
+}
+
+enum haptic_type {
+ HAPTIC_STANDARD,
+ HAPTIC_EXTERNAL,
+};
+
+struct haptic_ops {
+ enum haptic_type type;
+ bool (*is_valid)(void);
+ const struct haptic_plugin_ops *(*load)(void);
+ void (*release)(void);
+};
+
+void add_haptic(const struct haptic_ops *ops);
+void remove_haptic(const struct haptic_ops *ops);
+
+int haptic_probe(void);
+void haptic_init(void);
+void haptic_exit(void);
+
+#endif /* __HAPTIC_H__ */
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2016 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 <fcntl.h>
+#include <sys/reboot.h>
+
+#include "display/core.h"
+#include "core/log.h"
+#include "core/common.h"
+#include "shared/dbus.h"
+#include "edbus-handler.h"
+#include "haptic.h"
+
+static void sig_quit(int signo)
+{
+ _D("received SIGTERM signal %d", signo);
+}
+
+static void sig_usr1(int signo)
+{
+ _D("received SIGUSR1 signal %d, deviced'll be finished!", signo);
+
+ ecore_main_loop_quit();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ ecore_init();
+ edbus_init(NULL);
+ ret = haptic_probe();
+ if (ret != 0) {
+ _E("[haptic] probe fail");
+ return ret;
+ }
+ haptic_init();
+
+ signal(SIGTERM, sig_quit);
+ signal(SIGUSR1, sig_usr1);
+
+ ecore_main_loop_begin();
+
+ _D("[haptic] deinitialize");
+ haptic_exit();
+ edbus_exit(NULL);
+ ecore_shutdown();
+ return 0;
+}
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2016 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 <Ecore.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "core/config-parser.h"
+#include "haptic.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 BITS_PER_LONG (sizeof(long) * 8)
+#define OFF(x) ((x)%BITS_PER_LONG)
+#define BIT(x) (1UL<<OFF(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+#define MAX_DATA 16
+#define FF_INFO_MAGIC 0xDEADFEED
+
+#define VIBRATION_CONF_PATH "/usr/share/feedback/vibration_mix.conf"
+#define VIBRATION_DURATION_CONF_PATH "/usr/share/feedback/vibration_duration.conf"
+#define VIBRATION_WAITING_CONF_PATH "/usr/share/feedback/vibration_waiting.conf"
+
+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;
+ Ecore_Timer *timer;
+ struct ff_effect effect;
+ struct ff_info_buffer *ffinfobuffer;
+ int currentindex;
+};
+
+struct vibration_table {
+ char *pattern;
+ char *duration;
+ char *waiting;
+};
+
+struct vibration_config {
+ char *pattern;
+ int *data;
+ int data_len;
+};
+
+struct haptic_data {
+ unsigned int handle;
+ int *duration_config;
+ int *waiting_config;
+ int level;
+ int priority;
+ int duration_len;
+ int waiting_len;
+ int index;
+ bool stop;
+};
+
+static int ff_fd;
+static dd_list *ff_list;
+static dd_list *handle_list;
+static dd_list *vib_conf_list;
+static dd_list *vib_duration_conf_list;
+static dd_list *vib_waiting_conf_list;
+static Ecore_Timer *duration_timer;
+static char ff_path[PATH_MAX];
+static int unique_number;
+
+struct ff_info *read_from_list(int handle)
+{
+ struct ff_info *temp;
+ dd_list *elem;
+
+ DD_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;
+ dd_list *elem;
+
+ DD_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 Eina_Bool timer_cb(void *data)
+{
+ struct ff_info *info = (struct ff_info *)data;
+
+ if (!info)
+ return ECORE_CALLBACK_CANCEL;
+
+ if (!check_valid_handle(info))
+ return ECORE_CALLBACK_CANCEL;
+
+ _I("stop vibration by timer : id(%d)", info->effect.id);
+
+ /* stop previous vibration */
+ ff_stop(ff_fd, &info->effect);
+
+ /* reset timer */
+ info->timer = NULL;
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int ff_find_device(void)
+{
+ DIR *dir;
+ struct dirent entry;
+ 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) {
+ ret = readdir_r(dir, &entry, &dent);
+ if (ret != 0 || 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)
+ 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));
+ 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;
+
+ /*Only rumble supported as of now*/
+ effect->type = FF_RUMBLE;
+ effect->replay.length = 0;
+ effect->replay.delay = 10;
+ effect->id = -1;
+ effect->u.rumble.strong_magnitude = 0x8000;
+ effect->u.rumble.weak_magnitude = 0xc000;
+
+ return 0;
+}
+
+static int ff_set_effect(struct ff_effect *effect, int length, int level)
+{
+ double magnitude;
+
+ if (!effect)
+ return -EINVAL;
+
+ magnitude = (double)level/HAPTIC_MODULE_FEEDBACK_MAX;
+ magnitude *= RUMBLE_MAX_MAGNITUDE;
+
+ _I("info : magnitude(%d) length(%d)", (int)magnitude, length);
+
+ /* set member variables in effect struct */
+ effect->u.rumble.strong_magnitude = (int)magnitude;
+ effect->replay.length = length; /* length millisecond */
+
+ return 0;
+}
+
+static int ff_play(int fd, struct ff_effect *effect)
+{
+ struct input_event play;
+ int ret;
+
+ if (fd < 0 || !effect) {
+ if (fd < 0)
+ _E("fail to check fd");
+ else
+ _E("fail to check effect");
+ return -EINVAL;
+ }
+
+ /* upload an effect */
+ if (ioctl(fd, EVIOCSFF, effect) == -1) {
+ _E("fail to ioctl");
+ return -errno;
+ }
+
+ /* 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("fail 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)
+ return -EINVAL;
+
+ /* 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;
+
+ 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;
+ dd_list *elem;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ /* if it is the first element */
+ n = DD_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) {
+ _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 = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+ if (!elem)
+ found = true;
+ }
+
+ info->handle = unique_number;
+
+ /* add info to local list */
+ DD_LIST_APPEND(ff_list, info);
+ DD_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 r, n;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* stop vibration */
+ r = ff_stop(ff_fd, &info->effect);
+ if (r < 0)
+ _I("already stopped or failed to stop effect : %d", r);
+
+ /* unregister existing timer */
+ if (r >= 0 && info->timer) {
+ _D("device handle %d is closed and timer deleted", device_handle);
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ DD_LIST_REMOVE(handle_list, (gpointer)(long)info->handle);
+
+ safe_free(info->ffinfobuffer);
+ /* remove info from local list */
+ DD_LIST_REMOVE(ff_list, info);
+ safe_free(info);
+
+ /* if it is the last element */
+ n = DD_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 feedback, int priority, int *effect_handle)
+{
+ struct ff_info *info;
+ int ret;
+
+ info = read_from_list(device_handle);
+ if (!info) {
+ _E("fail to check list");
+ return -EINVAL;
+ }
+
+ if (!check_valid_handle(info)) {
+ _E("fail to check handle");
+ return -EINVAL;
+ }
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* 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);
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ /* set effect as per arguments */
+ ff_init_effect(&info->effect);
+ ret = ff_set_effect(&info->effect, duration, feedback);
+ if (ret < 0) {
+ _E("failed to set effect(duration:%d, feedback:%d) : %d",
+ duration, feedback, ret);
+ return ret;
+ }
+
+ /* play effect as per arguments */
+ ret = ff_play(ff_fd, &info->effect);
+ if (ret < 0) {
+ _E("failed to play haptic effect(fd:%d id:%d) : %d",
+ ff_fd, info->effect.id, ret);
+ return ret;
+ }
+
+ /* register timer */
+ if (duration) {
+ info->timer = ecore_timer_add(duration/1000.f, timer_cb, info);
+ if (!info->timer)
+ _E("Failed to add timer callback");
+ }
+
+ _D("device handle %d effect id : %d %dms", device_handle, info->effect.id, duration);
+ if (effect_handle)
+ *effect_handle = info->effect.id;
+
+ return 0;
+}
+
+static Eina_Bool _buffer_play(void *cbdata)
+{
+ struct ff_info *info = (struct ff_info *)cbdata;
+ struct ff_info_header *header = &info->ffinfobuffer->header;
+ struct ff_info_data *data = info->ffinfobuffer->data;
+ int index = info->currentindex;
+ int play_type = (index < header->ff_info_data_count) ? data[index].type : 0;
+ int length = (index < header->ff_info_data_count) ? data[index].length : 1;
+ int ret;
+
+ ff_set_effect(&info->effect, length, 1);
+ if (play_type != 0) {
+ _D("Going to play for %d ms", length);
+ ret = ff_play(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to play the effect %d", ret);
+ } else {
+ _D("Going to stop for %d ms", length);
+ ret = ff_stop(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to stop the effect %d", ret);
+ }
+
+ if (info->currentindex < header->ff_info_data_count) {
+ info->currentindex++;
+ info->timer = ecore_timer_add(length/1000.0f, _buffer_play, info);
+ } else {
+ --header->iteration;
+ if (header->iteration > 0) {
+ info->currentindex = 0;
+ info->timer = ecore_timer_add(0.0, _buffer_play, info);
+ } else
+ info->timer = NULL;
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void print_buffer(const unsigned char *vibe_buffer)
+{
+ struct ff_info_buffer fb;
+ int i = 0;
+ memcpy(&fb.header, vibe_buffer, sizeof(struct ff_info_header));
+ memcpy(&fb.data, (unsigned char *)vibe_buffer+sizeof(struct ff_info_header),
+ sizeof(struct ff_info_data) * fb.header.ff_info_data_count);
+ _D("\nMagic %x\niteration %d\ncount %d\n", fb.header.magic,
+ fb.header.iteration, fb.header.ff_info_data_count);
+
+ for (i = 0; i < fb.header.ff_info_data_count; i++)
+ _D("type %d\nmagn 0x%x\nlen %d\n", fb.data[i].type,
+ fb.data[i].magnitude, fb.data[i].length);
+}
+
+static int vibrate_custom_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ struct ff_info *info;
+ struct ff_info_header *header;
+ struct ff_info_data *data;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ if (!info->ffinfobuffer)
+ info->ffinfobuffer = (struct ff_info_buffer *)calloc(sizeof(struct ff_info_buffer), 1);
+ if (!info->ffinfobuffer)
+ return -ENOMEM;
+
+ header = &info->ffinfobuffer->header;
+ data = info->ffinfobuffer->data;
+
+ memcpy(header, vibe_buffer, sizeof(struct ff_info_header));
+ if (header->ff_info_data_count < 0 || header->ff_info_data_count > MAX_DATA)
+ return -EINVAL;
+
+ memcpy(data, vibe_buffer+sizeof(struct ff_info_header), sizeof(struct ff_info_data) * header->ff_info_data_count);
+
+ info->currentindex = 0;
+ if (info->timer)
+ ecore_timer_del(info->timer);
+
+ if (header->iteration > 0)
+ _buffer_play(info);
+
+ return 0;
+}
+
+static Eina_Bool haptic_duration_play(void *data)
+{
+ struct haptic_data *h_data;
+ double time;
+ int ret = 0;
+ int index;
+ unsigned int v_handle;
+ int level;
+ int priority;
+ int duration;
+
+
+ if (!data)
+ return ECORE_CALLBACK_CANCEL;
+
+ if (duration_timer) {
+ ecore_timer_del(duration_timer);
+ duration_timer = NULL;
+ }
+
+ h_data = (struct haptic_data *)data;
+ if (h_data->stop) {
+ h_data->stop = false;
+ free(h_data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ index = h_data->index;
+ v_handle = h_data->handle;
+ level = h_data->level;
+ priority = h_data->priority;
+
+ if (!h_data->duration_config[index]) {
+ free(h_data);
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ duration = h_data->duration_config[index];
+
+ h_data->index++;
+ if (h_data->index > h_data->duration_len - 1)
+ free(h_data);
+ else {
+ if (h_data->index > h_data->waiting_len - 1)
+ time = duration;
+ else
+ time = duration + h_data->waiting_config[index];
+
+ duration_timer = ecore_timer_add(time/1000.0f, haptic_duration_play, (void *)h_data);
+ _D("timer: %d", time);
+ }
+
+ _D("duration: %d", duration);
+
+ ret = vibrate_monotone(v_handle, duration, level, priority, NULL);
+ if (ret != 0) {
+ _D("auto stop vibration");
+ if (h_data)
+ h_data->stop = true;
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ int magic = 0;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ if (vibe_buffer)
+ magic = *(int *)vibe_buffer;
+
+ if (magic == FF_INFO_MAGIC) {
+ print_buffer(vibe_buffer);
+ return vibrate_custom_buffer(device_handle, vibe_buffer, iteration, feedback, priority, effect_handle);
+ } else
+ return vibrate_monotone(device_handle, 300, feedback, priority, effect_handle);
+}
+
+static int vibrate_effect(int device_handle, const char *pattern, int feedback, int priority)
+{
+ dd_list *elem1, *elem2;
+ struct vibration_table *conf_table;
+ struct vibration_config *conf_duration, *conf_waiting;
+ struct haptic_data *data;
+ char *duration = NULL, *waiting = NULL;
+ int len1, len2;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ if (!pattern)
+ return -EINVAL;
+
+ len1 = strlen(pattern) + 1;
+ DD_LIST_FOREACH(vib_conf_list, elem1, conf_table) {
+ if (!conf_table->pattern)
+ continue;
+ if (strncmp(conf_table->pattern, pattern, len1))
+ continue;
+ duration = conf_table->duration;
+ waiting = conf_table->waiting;
+ break;
+ }
+
+ if (!duration)
+ return -ENOTSUP;
+
+ len1 = strlen(duration) + 1;
+ if (!waiting)
+ len2 = 0;
+ else
+ len2 = strlen(waiting) + 1;
+ DD_LIST_FOREACH(vib_duration_conf_list, elem1, conf_duration) {
+ if (!conf_duration->pattern)
+ continue;
+ if (strncmp(conf_duration->pattern, duration, len1))
+ continue;
+
+ data = (struct haptic_data *)malloc(sizeof(struct haptic_data));
+ if (!data) {
+ _E("fail to alloc");
+ return -ENOMEM;
+ }
+ data->duration_len = 0;
+ data->waiting_len = 0;
+
+ DD_LIST_FOREACH(vib_waiting_conf_list, elem2, conf_waiting) {
+ if (!waiting)
+ break;
+ if (!conf_waiting->pattern)
+ continue;
+ if (strncmp(conf_waiting->pattern, waiting, len2))
+ continue;
+ data->waiting_config = conf_waiting->data;
+ data->waiting_len = conf_waiting->data_len;
+ break;
+ }
+ data->handle = device_handle;
+ data->level = feedback;
+ data->priority = priority;
+ data->duration_config = conf_duration->data;
+ data->duration_len = conf_duration->data_len;
+ data->index = 0;
+
+ haptic_duration_play((void *)data);
+ break;
+ }
+
+ return 0;
+}
+
+static int is_supported(const char *pattern)
+{
+ dd_list *elem;
+ struct vibration_table *conf;
+ int ret = 0;
+ int len;
+
+ if (!pattern)
+ return -EINVAL;
+
+ len = strlen(pattern) + 1;
+ DD_LIST_FOREACH(vib_conf_list, elem, conf) {
+ if (!conf->pattern)
+ continue;
+ if (!strncmp(conf->pattern, pattern, len)) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int stop_device(int device_handle)
+{
+ struct ff_info *info;
+ int r;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* stop effect */
+ r = ff_stop(ff_fd, &info->effect);
+ if (r < 0)
+ _E("failed to stop effect(id:%d) : %d", info->effect.id, r);
+
+ /* unregister existing timer */
+ if (r >= 0 && info->timer) {
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ return 0;
+}
+
+static int get_device_state(int device_index, int *effect_state)
+{
+ struct ff_info *info;
+ dd_list *elem;
+ int status = false;
+
+ if (!effect_state)
+ return -EINVAL;
+
+ /* suppose there is just one haptic device */
+ DD_LIST_FOREACH(ff_list, elem, info) {
+ if (info->effect.id >= 0) {
+ status = true;
+ break;
+ }
+ }
+
+ *effect_state = status;
+ return 0;
+}
+
+static int create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
+{
+ _E("Not supported feature");
+ return -EACCES;
+}
+
+static int get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+ _E("Not supported feature");
+ return -EACCES;
+}
+
+static int convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+ _E("Not supported feature");
+ return -EACCES;
+}
+/* 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,
+ .vibrate_buffer = vibrate_buffer,
+ .vibrate_effect = vibrate_effect,
+ .is_supported = is_supported,
+ .stop_device = stop_device,
+ .get_device_state = get_device_state,
+ .create_effect = create_effect,
+ .get_buffer_duration = get_buffer_duration,
+ .convert_binary = convert_binary,
+};
+
+static int vibration_duration_load_config(struct parse_result *result, void *user_data)
+{
+ struct vibration_config *conf;
+ char *value;
+ char *check;
+ int count = 0;
+ int len;
+ int i;
+
+ 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("fail to alloc");
+ return -ENOMEM;
+ }
+
+ conf->pattern = strdup(result->name);
+ if (!conf->pattern)
+ _E("fail to copy %s pattern data", result->name);
+
+ value = result->value;
+
+ if (!value)
+ len = 0;
+ else
+ len = strlen(value);
+
+ if (len == 0) {
+ DD_LIST_APPEND(vib_duration_conf_list, conf);
+ return 0;
+ }
+
+ check = strchr(value, ',');
+ while (check != NULL) {
+ count++;
+ check = strchr(check + 1, ',');
+ }
+
+ int *duration = (int *)malloc((count + 1) * sizeof(int));
+ for (i = 0; i <= count; i++) {
+ duration[i] = 0;
+ check = strchr(value, ',');
+ if (check) {
+ *check = '\0';
+ duration[i] = strtol(value, NULL, 10);
+ value = check + 1;
+ } else {
+ duration[i] = strtol(value, NULL, 10);
+ break;
+ }
+ if (duration[i] == 0)
+ break;
+ }
+ conf->data = duration;
+ conf->data_len = count + 1;
+
+ DD_LIST_APPEND(vib_duration_conf_list, conf);
+
+ return 0;
+}
+
+static int vibration_waiting_load_config(struct parse_result *result, void *user_data)
+{
+ struct vibration_config *conf;
+ char *value;
+ char *check;
+ int count = 0;
+ int len;
+ int i;
+
+ 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("fail to alloc");
+ return -ENOMEM;
+ }
+
+ conf->pattern = strdup(result->name);
+ if (!conf->pattern)
+ _E("fail to copy %s pattern data", result->name);
+
+ value = result->value;
+
+ if (!value)
+ len = 0;
+ else
+ len = strlen(value);
+
+ if (len == 0) {
+ DD_LIST_APPEND(vib_waiting_conf_list, conf);
+ return 0;
+ }
+
+ check = strchr(value, ',');
+ while (check != NULL) {
+ count++;
+ check = strchr(check + 1, ',');
+ }
+
+ int *waiting = (int *)malloc((count + 1) * sizeof(int));
+ for (i = 0; i <= count; i++) {
+ waiting[i] = 0;
+ check = strchr(value, ',');
+ if (check) {
+ *check = '\0';
+ waiting[i] = strtol(value, NULL, 10);
+ value = check + 1;
+ } else {
+ waiting[i] = strtol(value, NULL, 10);
+ break;
+ }
+ if (waiting[i] == 0)
+ break;
+ }
+ conf->data = waiting;
+ conf->data_len = count + 1;
+
+ DD_LIST_APPEND(vib_waiting_conf_list, conf);
+
+ return 0;
+}
+
+static int vibration_table_load_config(struct parse_result *result, void *user_data)
+{
+ struct vibration_table *conf;
+ char *value;
+ char *check;
+ int len;
+
+ if (!result)
+ return 0;
+
+ if (!MATCH(result->section, "Vibration"))
+ return 0;
+
+
+ if (!result->name || !result->value)
+ return 0;
+
+ conf = (struct vibration_table *)calloc(1, sizeof(struct vibration_table));
+ if (!conf) {
+ _E("fail to alloc");
+ return -ENOMEM;
+ }
+
+ conf->pattern = strdup(result->name);
+ if (!conf->pattern)
+ _E("fail to copy %s pattern data", result->name);
+
+ value = result->value;
+
+ if (!value)
+ len = 0;
+ else
+ len = strlen(value);
+
+ if (len == 0) {
+ DD_LIST_APPEND(vib_conf_list, conf);
+ return 0;
+ }
+
+ check = strchr(value, ',');
+
+ if (check) {
+ *check = '\0';
+ conf->duration = strdup(value);
+ value = check + 1;
+ conf->waiting = strdup(value);
+ } else
+ conf->duration = strdup(value);
+
+ DD_LIST_APPEND(vib_conf_list, conf);
+
+ return 0;
+}
+
+static bool is_valid(void)
+{
+ int ret;
+
+ ret = ff_find_device();
+ if (ret < 0) {
+ _E("Do not support standard haptic device");
+ return false;
+ }
+ ret = config_parse(VIBRATION_CONF_PATH, vibration_table_load_config, NULL);
+ if (ret < 0)
+ _E("failed to load configuration file(%s) : %d", VIBRATION_DURATION_CONF_PATH, ret);
+ ret = config_parse(VIBRATION_DURATION_CONF_PATH, vibration_duration_load_config, NULL);
+ if (ret < 0)
+ _E("failed to load configuration file(%s) : %d", VIBRATION_DURATION_CONF_PATH, ret);
+ ret = config_parse(VIBRATION_WAITING_CONF_PATH, vibration_waiting_load_config, NULL);
+ if (ret < 0)
+ _E("failed to load configuration file(%s) : %d", VIBRATION_WAITING_CONF_PATH, ret);
+
+ _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,
+};
+
+HAPTIC_OPS_REGISTER(&std_ops)
--- /dev/null
+#include <stdlib.h>
+#include <stdbool.h>
+#include <Ecore.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "core/config-parser.h"
+#include "standard-vibcore.h"
+
+#define VIBRATION_CONF_PATH "/usr/share/feedback/vibration.conf"
+
+struct vibration_config {
+ char *pattern;
+ dd_list *data;
+};
+
+struct duration_data {
+ int duration;
+ int wait;
+};
+
+struct haptic_data {
+ dd_list *vibration_data;
+ unsigned int handle;
+ int level;
+ int priority;
+ bool stop;
+};
+
+static dd_list *vib_conf_list;
+static Ecore_Timer *duration_timer;
+
+static t_vibrate_monotone real_vibrate_monotone;
+
+static int vibration_load_config(struct parse_result *result, void *user_data)
+{
+ struct vibration_config *conf;
+ struct duration_data *data;
+ char *value;
+ char *check;
+ int len;
+
+ 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("fail to alloc");
+ return -ENOMEM;
+ }
+
+ conf->pattern = strdup(result->name);
+ if (!conf->pattern)
+ _E("fail to copy %s pattern data", result->name);
+
+ value = result->value;
+
+ if (!value)
+ len = 0;
+ else
+ len = strlen(value);
+
+ if (len == 0) {
+ data = (struct duration_data *)malloc(sizeof(struct duration_data));
+ if (!data) {
+ _E("not enough memory");
+ free(conf->pattern);
+ free(conf);
+ return -ENOMEM;
+ }
+ data->duration = 0;
+ data->wait = 0;
+
+ DD_LIST_APPEND(conf->data, data);
+ DD_LIST_APPEND(vib_conf_list, conf);
+ return 0;
+ }
+
+ do {
+ data = (struct duration_data *)malloc(sizeof(struct duration_data));
+ if (!data) {
+ _E("not enough memory");
+ free(conf->pattern);
+ free(conf);
+ return -ENOMEM;
+ }
+ data->duration = 0;
+ data->wait = 0;
+
+ check = strchr(value, 'D');
+ if (check) {
+ *check = '\0';
+ data->duration = strtol(value, NULL, 10);
+ if (!value)
+ len = len - 1;
+ else
+ len = len - strlen(value) - 1;
+ value = check + 1;
+ }
+ check = strchr(value, 'W');
+ if (check) {
+ *check = '\0';
+ data->wait = strtol(value, NULL, 10);
+ if (!value)
+ len = len - 1;
+ else
+ len = len - strlen(value) - 1;
+ value = check + 1;
+ }
+ DD_LIST_APPEND(conf->data, data);
+ if (data->duration == 0 && data->wait == 0)
+ break;
+ } while (value && len > 0);
+
+ DD_LIST_APPEND(vib_conf_list, conf);
+
+ return 0;
+}
+
+int standard_config_parse()
+{
+ return config_parse(VIBRATION_CONF_PATH, vibration_load_config, NULL);
+}
+
+int standard_is_supported(const char *pattern)
+{
+ dd_list *elem;
+ struct vibration_config *conf;
+ size_t len;
+ int ret;
+
+ if (!pattern)
+ return -EINVAL;
+
+ len = strlen(pattern) + 1;
+ ret = 0;
+ DD_LIST_FOREACH(vib_conf_list, elem, conf) {
+ if (!conf->pattern)
+ continue;
+ if (!strncmp(conf->pattern, pattern, len)) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static Eina_Bool haptic_duration_play(void *data)
+{
+ dd_list *head, *n, *next;
+ struct haptic_data *h_data;
+ struct duration_data *node;
+ int ret = 0;
+
+ if (!data)
+ goto out;
+
+ if (duration_timer) {
+ ecore_timer_del(duration_timer);
+ duration_timer = NULL;
+ }
+
+ h_data = (struct haptic_data *)data;
+ if (h_data->stop) {
+ h_data->stop = false;
+ free(h_data);
+ goto out;
+ }
+
+ head = h_data->vibration_data;
+ DD_LIST_FOREACH_SAFE(head, n, next, node) {
+ _D("Play: %dms and Wait: %dms", node->duration, node->wait);
+ if (!node->duration) {
+ free(h_data);
+ break;
+ }
+
+ if (node->wait && next) {
+ h_data->vibration_data = next;
+ duration_timer = ecore_timer_add((node->duration + node->wait)/1000.0f, haptic_duration_play, (void *)h_data);
+ }
+
+ ret = real_vibrate_monotone(h_data->handle, node->duration, h_data->level, h_data->priority, NULL);
+ if (!next) {
+ free(h_data);
+ goto out;
+ }
+ break;
+ }
+ if (ret != 0) {
+ _D("auto stop vibration");
+ if (h_data)
+ h_data->stop = true;
+ }
+out:
+ return ECORE_CALLBACK_CANCEL;
+}
+
+int standard_set_vib_function(t_vibrate_monotone func)
+{
+ real_vibrate_monotone = func;
+ return 0;
+}
+
+int standard_vibrate_effect(int device_handle, const char *pattern, int feedback, int priority)
+{
+ dd_list *elem;
+ struct vibration_config *conf;
+ struct haptic_data *data;
+ size_t len;
+
+ if (device_handle < 0)
+ return -EINVAL;
+
+ len = strlen(pattern) + 1;
+ DD_LIST_FOREACH(vib_conf_list, elem, conf) {
+ if (!conf->pattern)
+ continue;
+ if (strncmp(conf->pattern, pattern, len))
+ continue;
+
+ data = (struct haptic_data *)malloc(sizeof(struct haptic_data));
+ if (!data) {
+ _E("fail to alloc");
+ return -ENOMEM;
+ }
+ data->vibration_data = conf->data;
+ data->handle = device_handle;
+ data->level = feedback;
+ data->priority = priority;
+ data->stop = false;
+ _D("Play %s", conf->pattern);
+ haptic_duration_play((void *)data);
+ break;
+ }
+
+ return 0;
+}
+
+int standard_vibrate_close()
+{
+ if (duration_timer) {
+ ecore_timer_del(duration_timer);
+ duration_timer = NULL;
+ }
+
+ return 0;
+}
--- /dev/null
+typedef int (*t_vibrate_monotone)(int device_handle, int duration, int feedback, int priority, int *effect_handle);
+
+int standard_config_parse();
+int standard_is_supported(const char *pattern);
+int standard_vibrate_effect(int device_handle, const char *pattern, int feedback, int priority);
+int standard_set_vib_function(t_vibrate_monotone func);
+int standard_vibrate_close();
--- /dev/null
+/*
+ * deviced-vibrator
+ *
+ * Copyright (c) 2012 - 2013 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 <Ecore.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "haptic.h"
+#include "standard-vibcore.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 BITS_PER_LONG (sizeof(long) * 8)
+#define OFF(x) ((x)%BITS_PER_LONG)
+#define BIT(x) (1UL<<OFF(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+#define MAX_DATA 16
+#define FF_INFO_MAGIC 0xDEADFEED
+
+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;
+ Ecore_Timer *timer;
+ struct ff_effect effect;
+ struct ff_info_buffer *ffinfobuffer;
+ int currentindex;
+};
+
+static int ff_fd;
+static dd_list *ff_list;
+static dd_list *handle_list;
+static char ff_path[PATH_MAX];
+static int unique_number;
+
+struct ff_info *read_from_list(int handle)
+{
+ struct ff_info *temp;
+ dd_list *elem;
+
+ DD_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;
+ dd_list *elem;
+
+ DD_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 Eina_Bool timer_cb(void *data)
+{
+ struct ff_info *info = (struct ff_info *)data;
+
+ if (!info)
+ return ECORE_CALLBACK_CANCEL;
+
+ if (!check_valid_handle(info))
+ return ECORE_CALLBACK_CANCEL;
+
+ _I("stop vibration by timer : id(%d)", info->effect.id);
+
+ /* stop previous vibration */
+ ff_stop(ff_fd, &info->effect);
+
+ /* reset timer */
+ info->timer = NULL;
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int ff_find_device(void)
+{
+ DIR *dir;
+ struct dirent entry;
+ 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) {
+ ret = readdir_r(dir, &entry, &dent);
+ if (ret != 0 || 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)
+ 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));
+ 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;
+
+ /*Only rumble supported as of now*/
+ effect->type = FF_RUMBLE;
+ effect->replay.length = 0;
+ effect->replay.delay = 10;
+ effect->id = -1;
+ effect->u.rumble.strong_magnitude = 0x8000;
+ effect->u.rumble.weak_magnitude = 0xc000;
+
+ return 0;
+}
+
+static int ff_set_effect(struct ff_effect *effect, int length, int level)
+{
+ double magnitude;
+
+ if (!effect)
+ return -EINVAL;
+
+ magnitude = (double)level/HAPTIC_MODULE_FEEDBACK_MAX;
+ magnitude *= RUMBLE_MAX_MAGNITUDE;
+
+ _I("info : magnitude(%d) length(%d)", (int)magnitude, length);
+
+ /* set member variables in effect struct */
+ effect->u.rumble.strong_magnitude = (int)magnitude;
+ effect->replay.length = length; /* length millisecond */
+
+ return 0;
+}
+
+static int ff_play(int fd, struct ff_effect *effect)
+{
+ struct input_event play;
+ int ret;
+
+ if (fd < 0 || !effect) {
+ if (fd < 0)
+ _E("fail to check fd");
+ else
+ _E("fail to check effect");
+ return -EINVAL;
+ }
+
+ /* upload an effect */
+ if (ioctl(fd, EVIOCSFF, effect) == -1) {
+ _E("fail to ioctl");
+ return -errno;
+ }
+
+ /* 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("fail 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)
+ return -EINVAL;
+
+ /* 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;
+
+ 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;
+ dd_list *elem;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ /* if it is the first element */
+ n = DD_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) {
+ _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 = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+ if (!elem)
+ found = true;
+ }
+
+ info->handle = unique_number;
+
+ /* add info to local list */
+ DD_LIST_APPEND(ff_list, info);
+ DD_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 r, n;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* stop vibration */
+ r = ff_stop(ff_fd, &info->effect);
+ if (r < 0)
+ _I("already stopped or failed to stop effect : %d", r);
+
+ /* unregister existing timer */
+ if (r >= 0 && info->timer) {
+ _D("device handle %d is closed and timer deleted", device_handle);
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ standard_vibrate_close();
+
+ DD_LIST_REMOVE(handle_list, (gpointer)(long)info->handle);
+
+ safe_free(info->ffinfobuffer);
+ /* remove info from local list */
+ DD_LIST_REMOVE(ff_list, info);
+ safe_free(info);
+
+ /* if it is the last element */
+ n = DD_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 feedback, int priority, int *effect_handle)
+{
+ struct ff_info *info;
+ int ret;
+
+ info = read_from_list(device_handle);
+ if (!info) {
+ _E("fail to check list");
+ return -EINVAL;
+ }
+
+ if (!check_valid_handle(info)) {
+ _E("fail to check handle");
+ return -EINVAL;
+ }
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* 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);
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ /* set effect as per arguments */
+ ff_init_effect(&info->effect);
+ ret = ff_set_effect(&info->effect, duration, feedback);
+ if (ret < 0) {
+ _E("failed to set effect(duration:%d, feedback:%d) : %d",
+ duration, feedback, ret);
+ return ret;
+ }
+
+ /* play effect as per arguments */
+ ret = ff_play(ff_fd, &info->effect);
+ if (ret < 0) {
+ _E("failed to play haptic effect(fd:%d id:%d) : %d",
+ ff_fd, info->effect.id, ret);
+ return ret;
+ }
+
+ /* register timer */
+ if (duration) {
+ info->timer = ecore_timer_add(duration/1000.f, timer_cb, info);
+ if (!info->timer)
+ _E("Failed to add timer callback");
+ }
+
+ _D("device handle %d effect id : %d %dms", device_handle, info->effect.id, duration);
+ if (effect_handle)
+ *effect_handle = info->effect.id;
+
+ return 0;
+}
+
+static Eina_Bool _buffer_play(void *cbdata)
+{
+ struct ff_info *info = (struct ff_info *)cbdata;
+ struct ff_info_header *header = &info->ffinfobuffer->header;
+ struct ff_info_data *data = info->ffinfobuffer->data;
+ int index = info->currentindex;
+ int play_type = (index < header->ff_info_data_count) ? data[index].type : 0;
+ int length = (index < header->ff_info_data_count) ? data[index].length : 1;
+ int ret;
+
+ ff_set_effect(&info->effect, length, 1);
+ if (play_type != 0) {
+ _D("Going to play for %d ms", length);
+ ret = ff_play(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to play the effect %d", ret);
+ } else {
+ _D("Going to stop for %d ms", length);
+ ret = ff_stop(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to stop the effect %d", ret);
+ }
+
+ if (info->currentindex < header->ff_info_data_count) {
+ info->currentindex++;
+ info->timer = ecore_timer_add(length/1000.0f, _buffer_play, info);
+ } else {
+ --header->iteration;
+ if (header->iteration > 0) {
+ info->currentindex = 0;
+ info->timer = ecore_timer_add(0.0, _buffer_play, info);
+ } else
+ info->timer = NULL;
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void print_buffer(const unsigned char *vibe_buffer)
+{
+ struct ff_info_buffer fb;
+ int i = 0;
+ memcpy(&fb.header, vibe_buffer, sizeof(struct ff_info_header));
+ memcpy(&fb.data, (unsigned char *)vibe_buffer+sizeof(struct ff_info_header),
+ sizeof(struct ff_info_data) * fb.header.ff_info_data_count);
+ _D("\nMagic %x\niteration %d\ncount %d\n", fb.header.magic,
+ fb.header.iteration, fb.header.ff_info_data_count);
+
+ for (i = 0; i < fb.header.ff_info_data_count; i++)
+ _D("type %d\nmagn 0x%x\nlen %d\n", fb.data[i].type,
+ fb.data[i].magnitude, fb.data[i].length);
+}
+
+static int vibrate_custom_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ struct ff_info *info;
+ struct ff_info_header *header;
+ struct ff_info_data *data;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ if (!info->ffinfobuffer)
+ info->ffinfobuffer = (struct ff_info_buffer *)calloc(sizeof(struct ff_info_buffer), 1);
+ if (!info->ffinfobuffer)
+ return -ENOMEM;
+
+ header = &info->ffinfobuffer->header;
+ data = info->ffinfobuffer->data;
+
+ memcpy(header, vibe_buffer, sizeof(struct ff_info_header));
+ if (header->ff_info_data_count < 0 || header->ff_info_data_count > MAX_DATA)
+ return -EINVAL;
+
+ memcpy(data, vibe_buffer+sizeof(struct ff_info_header), sizeof(struct ff_info_data) * header->ff_info_data_count);
+
+ info->currentindex = 0;
+ if (info->timer)
+ ecore_timer_del(info->timer);
+
+ if (header->iteration > 0)
+ _buffer_play(info);
+
+ return 0;
+}
+
+static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ int magic = 0;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ if (vibe_buffer)
+ magic = *(int *)vibe_buffer;
+
+ if (magic == FF_INFO_MAGIC) {
+ print_buffer(vibe_buffer);
+ return vibrate_custom_buffer(device_handle, vibe_buffer, iteration, feedback, priority, effect_handle);
+ } else
+ return vibrate_monotone(device_handle, 300, feedback, priority, effect_handle);
+}
+
+static int stop_device(int device_handle)
+{
+ struct ff_info *info;
+ int r;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ /* stop effect */
+ r = ff_stop(ff_fd, &info->effect);
+ if (r < 0)
+ _E("failed to stop effect(id:%d) : %d", info->effect.id, r);
+
+ /* unregister existing timer */
+ if (r >= 0 && info->timer) {
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
+ return 0;
+}
+
+static int get_device_state(int device_index, int *effect_state)
+{
+ struct ff_info *info;
+ dd_list *elem;
+ int status = false;
+
+ if (!effect_state)
+ return -EINVAL;
+
+ /* suppose there is just one haptic device */
+ DD_LIST_FOREACH(ff_list, elem, info) {
+ if (info->effect.id >= 0) {
+ status = true;
+ break;
+ }
+ }
+
+ *effect_state = status;
+ return 0;
+}
+
+static int create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+
+static int convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+ _E("Not support feature");
+ return -EACCES;
+}
+/* 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,
+ .vibrate_buffer = vibrate_buffer,
+ .vibrate_effect = standard_vibrate_effect,
+ .is_supported = standard_is_supported,
+ .stop_device = stop_device,
+ .get_device_state = get_device_state,
+ .create_effect = create_effect,
+ .get_buffer_duration = get_buffer_duration,
+ .convert_binary = convert_binary,
+};
+
+static bool is_valid(void)
+{
+ int ret;
+
+ ret = ff_find_device();
+ if (ret < 0) {
+ _E("Do not support standard haptic device");
+ return false;
+ }
+
+ ret = standard_config_parse();
+ if (ret < 0)
+ _E("failed to load standard vibration configuration file : %d", ret);
+
+ _I("Support standard haptic device");
+ return true;
+}
+
+static const struct haptic_plugin_ops *load(void)
+{
+ standard_set_vib_function(&vibrate_monotone);
+ return &default_plugin;
+}
+
+static const struct haptic_ops std_ops = {
+ .type = HAPTIC_STANDARD,
+ .is_valid = is_valid,
+ .load = load,
+};
+
+HAPTIC_OPS_REGISTER(&std_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014-2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <hw/ir.h>
+#include "core/edbus-handler.h"
+#include "core/devices.h"
+#include "core/common.h"
+#include "core/log.h"
+
+static struct ir_device *ir_dev;
+
+static DBusMessage *edbus_ir_is_available(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ bool val;
+
+ if (!ir_dev) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (!ir_dev->is_available) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = ir_dev->is_available(&val);
+ if (ret >= 0)
+ ret = val;
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_ir_transmit(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret = 0;
+ int size;
+ int *freq_pattern;
+
+ if (!ir_dev) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (!ir_dev->transmit) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &freq_pattern, &size,
+ DBUS_TYPE_INVALID)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ _I("frequency : %d, pattern_size: %d", freq_pattern[0], size);
+
+ ret = ir_dev->transmit(freq_pattern, size);
+
+exit:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_set_ir_command(E_DBus_Object *obj, DBusMessage *msg)
+{
+ int ret = -ENOTSUP;
+
+ _E("The method is not supported. Use device_ir_transmit() of capi-system-device");
+
+ return make_reply_message(msg, ret);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "IRIsAvailable", NULL, "i", edbus_ir_is_available},
+ { "TransmitIR", "ai", "i", edbus_ir_transmit},
+};
+
+static const struct edbus_method edbus_methods_legacy[] = {
+ { "SetIrCommand", "s", "i", edbus_set_ir_command },
+};
+
+static int ir_probe(void *data)
+{
+ struct hw_info *info;
+ int ret;
+
+ if (ir_dev)
+ return 0;
+
+ ret = hw_get_info(IR_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+
+ if (ret < 0) {
+ _E("Fail to load ir(%d)", ret);
+ return -ENODEV;
+ }
+
+ if (!info->open) {
+ _E("Failed to open ir device; open(NULL)");
+ return -ENODEV;
+ }
+
+ ret = info->open(info, NULL, (struct hw_common**)&ir_dev);
+ if (ret < 0) {
+ _E("Failed to get ir device structure (%d)", ret);
+ return ret;
+ }
+
+ _I("ir device structure load success");
+ return 0;
+}
+
+static void ir_init(void *data)
+{
+ int ret;
+
+ ret = register_edbus_interface_and_method(DEVICED_PATH_IR,
+ DEVICED_INTERFACE_IR,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+
+ /* Legacy interfaces */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_LED,
+ DEVICED_INTERFACE_LED,
+ edbus_methods_legacy, ARRAY_SIZE(edbus_methods_legacy));
+ if (ret < 0)
+ _E("fail to init edbus interfce and method(%d)", ret);
+}
+
+static void ir_exit(void *data)
+{
+ struct hw_info *info;
+
+ if (!ir_dev)
+ return;
+
+ info = ir_dev->common.info;
+ if (!info)
+ free(ir_dev);
+ else
+ info->close((struct hw_common *)ir_dev);
+
+ ir_dev = NULL;
+}
+
+static const struct device_ops ir_device_ops = {
+ .name = "ir",
+ .probe = ir_probe,
+ .init = ir_init,
+ .exit = ir_exit,
+};
+
+DEVICE_OPS_REGISTER(&ir_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+
+#include "core/log.h"
+#include "core/edbus-handler.h"
+
+#define METHOD_TORCH_NOTI_ON "TorchNotiOn"
+#define METHOD_TORCH_NOTI_OFF "TorchNotiOff"
+
+static int noti_h;
+
+int ongoing_show(void)
+{
+ int ret_val;
+
+ if (noti_h > 0) {
+ _D("already ongoing noti show : handle(%d)", noti_h);
+ return 0;
+ }
+
+ ret_val = dbus_method_sync(POPUP_BUS_NAME,
+ POPUP_PATH_LED,
+ POPUP_INTERFACE_LED,
+ METHOD_TORCH_NOTI_ON,
+ NULL, NULL);
+
+ noti_h = ret_val;
+ _D("insert noti handle : %d", noti_h);
+ return (ret_val < 0) ? ret_val : 0;
+}
+
+int ongoing_clear(void)
+{
+ char str_h[32];
+ char *arr[1];
+ int ret_val;
+
+ if (noti_h <= 0) {
+ _D("already ongoing noti clear");
+ return 0;
+ }
+
+ snprintf(str_h, sizeof(str_h), "%d", noti_h);
+ arr[0] = str_h;
+
+ ret_val = dbus_method_sync(POPUP_BUS_NAME,
+ POPUP_PATH_LED,
+ POPUP_INTERFACE_LED,
+ METHOD_TORCH_NOTI_OFF,
+ "i", arr);
+
+ _D("delete noti handle : %d", noti_h);
+ noti_h = 0;
+ return ret_val;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <assert.h>
+#include <vconf.h>
+#include <device-node.h>
+#include <hw/led.h>
+
+#include "core/log.h"
+#include "core/edbus-handler.h"
+#include "core/devices.h"
+#include "torch.h"
+
+#define LED_MAX_BRIGHTNESS 100
+#define GET_BRIGHTNESS(x) (((x) >> 24) & 0xFF)
+
+#define SIGNAL_FLASH_STATE "ChangeFlashState"
+
+static struct led_device *led_dev;
+static struct led_state led_state = {
+ .type = LED_TYPE_MANUAL,
+ .color = 0x0,
+ .duty_on = 0,
+ .duty_off = 0,
+};
+
+static void flash_state_broadcast(int val)
+{
+ char *arr[1];
+ char str_state[32];
+
+ snprintf(str_state, sizeof(str_state), "%d", val);
+ arr[0] = str_state;
+
+ broadcast_edbus_signal(DEVICED_PATH_LED, DEVICED_INTERFACE_LED,
+ SIGNAL_FLASH_STATE, "i", arr);
+}
+
+static DBusMessage *edbus_get_brightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret, alpha;
+
+ if (!led_dev) {
+ _E("there is no led device");
+ ret = -ENOENT;
+ goto error;
+ }
+
+ alpha = GET_BRIGHTNESS(led_state.color);
+ ret = alpha * 100.f / 255;
+ if (alpha != 0 && alpha != 0xFF)
+ ret += 1;
+ _D("color : val(%d), color(%x)", ret, led_state.color);
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_get_max_brightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int ret;
+
+ ret = LED_MAX_BRIGHTNESS;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_set_brightness(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ int val, enable, ret;
+ struct led_state tmp = {0,};
+
+ ret = dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &val,
+ DBUS_TYPE_INT32, &enable, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _I("there is no message");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (!led_dev) {
+ _E("there is no led device");
+ ret = -ENOENT;
+ goto error;
+ }
+
+ tmp.color = (((int)(val * 255.f) / LED_MAX_BRIGHTNESS) & 0xFF) << 24;
+ _D("color : val(%d), color(%x)", val, tmp.color);
+
+ ret = led_dev->set_state(&tmp);
+ if (ret < 0)
+ goto error;
+
+ memcpy(&led_state, &tmp, sizeof(led_state));
+
+ /* flash status broadcast */
+ flash_state_broadcast(val);
+
+ /* if enable is ON, noti will be show or hide */
+ if (enable) {
+ if (val)
+ ongoing_show();
+ else
+ ongoing_clear();
+ }
+
+error:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ /**
+ * GetBrightnessForCamera is for camera library.
+ * Currently they do not have a daemon for camera,
+ * but they need to get camera brightness value without led priv.
+ * It's a temporary solution on Tizen 2.4 and will be removed asap.
+ */
+ { "GetBrightnessForCamera", NULL, "i", edbus_get_brightness },
+ { "GetBrightness", NULL, "i", edbus_get_brightness },
+ { "GetMaxBrightness", NULL, "i", edbus_get_max_brightness },
+ { "SetBrightness", "ii", "i", edbus_set_brightness },
+ /* Add methods here */
+};
+
+static int led_service_load(void)
+{
+ struct hw_info *info;
+ int r;
+
+ r = hw_get_info(LED_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (r < 0) {
+ _E("fail to load led shared library : %d", r);
+ return -ENOENT;
+ }
+
+ if (!info->open) {
+ _E("fail to open camera led device : open(NULL)");
+ return -EPERM;
+ }
+
+ r = info->open(info, LED_ID_CAMERA_BACK,
+ (struct hw_common **)&led_dev);
+ if (r < 0) {
+ _E("fail to get camera led device : %d", r);
+ return -EPERM;
+ }
+
+ _D("camera led device structure load success");
+ return 0;
+}
+
+static int led_service_free(void)
+{
+ struct hw_info *info;
+
+ if (!led_dev)
+ return -ENOENT;
+
+ info = led_dev->common.info;
+
+ assert(info);
+
+ info->close((struct hw_common *)led_dev);
+
+ return 0;
+}
+
+static int torch_probe(void *data)
+{
+ /* load led device */
+ return led_service_load();
+}
+
+static void torch_init(void *data)
+{
+ int ret;
+
+ /* init dbus interface */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_LED,
+ DEVICED_INTERFACE_LED,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus interface and method(%d)", ret);
+}
+
+static void torch_exit(void *data)
+{
+ /* free led device */
+ led_service_free();
+}
+
+static const struct device_ops torchled_device_ops = {
+ .name = "torchled",
+ .probe = torch_probe,
+ .init = torch_init,
+ .exit = torch_exit,
+};
+
+DEVICE_OPS_REGISTER(&torchled_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __TORCH_H__
+#define __TORCH_H__
+
+int ongoing_show(void);
+int ongoing_clear(void);
+
+int play_pattern(const char *path, int cnt);
+int stop_pattern(void);
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <vconf.h>
+#include <hw/led.h>
+
+#include "core/log.h"
+#include "core/edbus-handler.h"
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "display/core.h"
+#include "display/setting.h"
+#include "touch-key.h"
+
+#define KEYBACKLIGHT_TIME_90 90 /* 1.5 second */
+#define KEYBACKLIGHT_TIME_360 360 /* 6 second */
+#define KEYBACKLIGHT_TIME_ALWAYS_ON -1 /* always on */
+#define KEYBACKLIGHT_TIME_ALWAYS_OFF 0 /* always off */
+#define KEYBACKLIGHT_BASE_TIME 60 /* 1min = 60sec */
+#define KEYBACKLIGHT_PRESSED_TIME 15 /* 15 second */
+
+#ifndef VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION
+#define VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION VCONFKEY_SETAPPL_PREFIX"/display/touchkey_light_duration"
+#endif
+
+#define GET_BRIGHTNESS(val) (((val) >> 24) & 0xFF)
+#define SET_BRIGHTNESS(val) (((val) & 0xFF) << 24)
+
+struct led_device *touchled_dev;
+static Ecore_Timer *hardkey_timeout_id;
+static int hardkey_duration;
+
+static int touchled_set_state(bool on)
+{
+ struct led_state tmp = {0,};
+ int r;
+
+ if (!touchled_dev || !touchled_dev->set_state) {
+ _E("there is no led device");
+ return -ENOENT;
+ }
+
+ if (on)
+ tmp.color = SET_BRIGHTNESS(255);
+ else
+ tmp.color = SET_BRIGHTNESS(0);
+
+ r = touchled_dev->set_state(&tmp);
+ if (r < 0) {
+ _E("fail to set touch led state : %d", r);
+ return r;
+ }
+
+ return 0;
+}
+
+static Eina_Bool key_backlight_expired(void *data)
+{
+ hardkey_timeout_id = NULL;
+
+ touchled_set_state(false);
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void process_touchkey_press(void)
+{
+ /* release existing timer */
+ if (hardkey_timeout_id > 0) {
+ ecore_timer_del(hardkey_timeout_id);
+ hardkey_timeout_id = NULL;
+ }
+ /* if hardkey option is always off */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
+ return;
+ /* turn on hardkey backlight */
+ touchled_set_state(true);
+ /* start timer */
+ hardkey_timeout_id = ecore_timer_add(
+ KEYBACKLIGHT_PRESSED_TIME,
+ key_backlight_expired, NULL);
+}
+
+static void process_touchkey_release(void)
+{
+ float fduration;
+
+ /* release existing timer */
+ if (hardkey_timeout_id > 0) {
+ ecore_timer_del(hardkey_timeout_id);
+ hardkey_timeout_id = NULL;
+ }
+ /* if hardkey option is always on or off */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON ||
+ hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
+ return;
+ /* start timer */
+ fduration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
+ hardkey_timeout_id = ecore_timer_add(
+ fduration,
+ key_backlight_expired, NULL);
+}
+
+static void process_touchkey_enable(bool enable)
+{
+ /* release existing timer */
+ if (hardkey_timeout_id > 0) {
+ ecore_timer_del(hardkey_timeout_id);
+ hardkey_timeout_id = NULL;
+ }
+
+ /* start timer in case of backlight enabled */
+ if (enable) {
+ /* if hardkey option is always off */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
+ return;
+
+ /* turn on hardkey backlight */
+ touchled_set_state(true);
+
+ /* do not create turnoff timer in case of idle lock state */
+ if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
+ return;
+
+ /* start timer */
+ hardkey_timeout_id = ecore_timer_add(
+ KEYBACKLIGHT_PRESSED_TIME,
+ key_backlight_expired, NULL);
+ } else {
+ /* if hardkey option is always on */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
+ return;
+
+ /* turn off hardkey backlight */
+ touchled_set_state(false);
+ }
+}
+
+static void hardkey_duration_cb(keynode_t *key, void *data)
+{
+ float duration;
+
+ hardkey_duration = vconf_keynode_get_int(key);
+
+ /* release existing timer */
+ if (hardkey_timeout_id > 0) {
+ ecore_timer_del(hardkey_timeout_id);
+ hardkey_timeout_id = NULL;
+ }
+
+ /* if hardkey option is always off */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF) {
+ /* turn off hardkey backlight */
+ touchled_set_state(false);
+ return;
+ }
+
+ /* turn on hardkey backlight */
+ touchled_set_state(true);
+
+ /* if hardkey option is always on */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
+ return;
+
+ /* start timer */
+ duration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
+ hardkey_timeout_id = ecore_timer_add(
+ duration,
+ key_backlight_expired, NULL);
+}
+
+static int hardkey_lcd_changed_cb(void *data)
+{
+ int lcd_state;
+
+ if (!data)
+ return 0;
+
+ lcd_state = *(int*)data;
+ if (lcd_state == S_NORMAL
+ && hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON) {
+ touchled_set_state(true);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int touchled_service_load(void)
+{
+ struct hw_info *info;
+ int r;
+
+ r = hw_get_info(LED_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (r < 0) {
+ _E("fail to load led shared library : %d", r);
+ return -ENOENT;
+ }
+
+ if (!info->open) {
+ _E("fail to open touch led device : open(NULL)");
+ return -EPERM;
+ }
+
+ r = info->open(info, LED_ID_TOUCH_KEY,
+ (struct hw_common **)&touchled_dev);
+ if (r < 0) {
+ _E("fail to get touch led device : %d", r);
+ return -EPERM;
+ }
+
+ _D("touch led device structure load success");
+ return 0;
+}
+
+static int touchled_service_free(void)
+{
+ struct hw_info *info;
+
+ if (!touchled_dev)
+ return -ENOENT;
+
+ info = touchled_dev->common.info;
+ if (!info) {
+ free(touchled_dev);
+ touchled_dev = NULL;
+ return -EPERM;
+ }
+
+ info->close((struct hw_common *)touchled_dev);
+ touchled_dev = NULL;
+
+ return 0;
+}
+
+static int touchled_probe(void *data)
+{
+ /* load led device */
+ return touchled_service_load();
+}
+
+static void touchled_init(void *data)
+{
+ /* get touchkey light duration setting */
+ if (vconf_get_int(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, &hardkey_duration) < 0) {
+ _W("Fail to get VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION!!");
+ hardkey_duration = KEYBACKLIGHT_TIME_90;
+ }
+
+ vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb, NULL);
+
+ /* register notifier */
+ register_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
+
+ /* update touchkey light duration right now */
+ if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
+ touchled_set_state(true);
+}
+
+static void touchled_exit(void *data)
+{
+ /* unregister notifier */
+ unregister_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
+
+ vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb);
+
+ /* free led device */
+ touchled_service_free();
+}
+
+static int touchled_execute(void *data)
+{
+ int opt;
+
+ if (!data)
+ return -EINVAL;
+
+ opt = *(int *)data;
+ if (opt == TOUCHLED_PRESS)
+ process_touchkey_press();
+ else if (opt == TOUCHLED_RELEASE)
+ process_touchkey_release();
+ else if (opt == TOUCHLED_DIRECT_ON)
+ process_touchkey_enable(true);
+ else if (opt == TOUCHLED_DIRECT_OFF)
+ process_touchkey_enable(false);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct device_ops touchled_device_ops = {
+ .name = TOUCHLED_NAME,
+ .probe = touchled_probe,
+ .init = touchled_init,
+ .exit = touchled_exit,
+ .execute = touchled_execute,
+};
+
+DEVICE_OPS_REGISTER(&touchled_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __TOUCH_KEY_H__
+#define __TOUCH_KEY_H__
+
+#define TOUCHLED_NAME "touchled"
+
+enum touchled_opt {
+ TOUCHLED_PRESS,
+ TOUCHLED_RELEASE,
+ TOUCHLED_DIRECT_ON,
+ TOUCHLED_DIRECT_OFF,
+};
+
+#endif
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(libdeviced C)
+
+SET(LIBDEVICED_SRCS
+ display.c
+ dbus.c
+ haptic.c
+ led.c
+ mmc.c
+ storage.c
+ usbhost.c
+ deviced-conf.c
+ deviced-noti.c
+ deviced-util.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/deviced ${CMAKE_SOURCE_DIR}/src/shared)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(libpkgs REQUIRED
+ vconf
+ dlog
+ storage
+ dbus-1
+ dbus-glib-1
+ edbus
+ glib-2.0)
+
+FOREACH(flag ${libpkgs_CFLAGS})
+ SET(EXTRA_LIB_CFLAGS "${EXTRA_LIB_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_LIB_CFLAGS}")
+
+# libdeviced
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${LIBDEVICED_SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${libpkgs_LDFLAGS})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
+# CMake Policy (CMP0002)
+# The logical name of executable and library targes
+# does not have to correspond to the physical file name built.
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME deviced)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "common.h"
+#include "log.h"
+#include "dbus.h"
+
+/* -1 is a default timeout value, it's converted to 25*1000 internally. */
+#define DBUS_REPLY_TIMEOUT (-1)
+
+struct pending_call_data {
+ dbus_pending_cb func;
+ void *data;
+};
+
+int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
+{
+ char *ch;
+ int i;
+ int int_type;
+ dbus_bool_t bool_type;
+ uint64_t int64_type;
+ DBusMessageIter arr;
+ struct dbus_byte *byte;
+
+ if (!sig || !param)
+ return 0;
+
+ for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
+ switch (*ch) {
+ case 'b':
+ bool_type = (atoi(param[i])) ? TRUE : FALSE;
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
+ break;
+ case 'i':
+ int_type = atoi(param[i]);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
+ break;
+ case 'u':
+ int_type = strtoul(param[i], NULL, 10);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
+ break;
+ case 't':
+ int64_type = atoll(param[i]);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
+ break;
+ case 's':
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, ¶m[i]);
+ break;
+ case 'a':
+ ++ch;
+ switch (*ch) {
+ case 'y':
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
+ byte = (struct dbus_byte*)param[i];
+ dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
+ dbus_message_iter_close_container(iter, &arr);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+DBusMessage *dbus_method_sync_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ int r;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return NULL;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return NULL;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ r = append_variant(&iter, sig, param);
+ if (r < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ r, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return NULL;
+ }
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ if (!reply) {
+ _E("dbus_connection_send error(No reply) %s %s:%s-%s",
+ dest, path, interface, method);
+ }
+
+ if (dbus_error_is_set(&err)) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ reply = NULL;
+ }
+
+ dbus_message_unref(msg);
+ return reply;
+}
+
+int dbus_method_sync(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ int ret, result;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ dbus_message_unref(msg);
+ if (!reply) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ECOMM;
+ }
+
+ ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
+ dbus_message_unref(reply);
+ if (!ret) {
+ _E("no message : [%s:%s] %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ENOMSG;
+ }
+
+ return result;
+}
+
+int dbus_method_async(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ int ret;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ ret = dbus_connection_send(conn, msg, NULL);
+ dbus_message_unref(msg);
+ if (ret != TRUE) {
+ _E("dbus_connection_send error(%s %s:%s-%s)",
+ dest, path, interface, method);
+ return -ECOMM;
+ }
+
+ return 0;
+}
+
+static void cb_pending(DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *msg;
+ DBusError err;
+ struct pending_call_data *data = user_data;
+ int ret;
+
+ ret = dbus_pending_call_get_completed(pending);
+ if (!ret) {
+ _I("dbus_pending_call_get_completed() fail");
+ dbus_pending_call_unref(pending);
+ return;
+ }
+
+ dbus_error_init(&err);
+ msg = dbus_pending_call_steal_reply(pending);
+ if (!msg) {
+ _E("no message : [%s:%s]", err.name, err.message);
+
+ if (data->func) {
+ dbus_set_error(&err, "org.tizen.system.deviced.NoReply",
+ "There was no reply to this method call");
+ data->func(data->data, NULL, &err);
+ dbus_error_free(&err);
+ }
+ return;
+ }
+
+ ret = dbus_set_error_from_message(&err, msg);
+ if (ret) {
+ _E("error msg : [%s:%s]", err.name, err.message);
+
+ if (data->func)
+ data->func(data->data, NULL, &err);
+ dbus_error_free(&err);
+ } else {
+ if (data->func)
+ data->func(data->data, msg, &err);
+ }
+
+ dbus_message_unref(msg);
+ dbus_pending_call_unref(pending);
+}
+
+int dbus_method_async_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[], dbus_pending_cb cb, int timeout, void *data)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusPendingCall *pending = NULL;
+ struct pending_call_data *pdata;
+ int ret;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ /* this function should be invoked to receive dbus messages
+ * does nothing if it's already been done */
+ dbus_connection_setup_with_g_main(conn, NULL);
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d)%s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
+ if (!ret) {
+ dbus_message_unref(msg);
+ _E("dbus_connection_send error(%s %s:%s-%s)",
+ dest, path, interface, method);
+ return -ECOMM;
+ }
+
+ dbus_message_unref(msg);
+
+ if (cb && pending) {
+ pdata = malloc(sizeof(struct pending_call_data));
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->func = cb;
+ pdata->data = data;
+
+ ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
+ if (!ret) {
+ free(pdata);
+ dbus_pending_call_cancel(pending);
+ return -ECOMM;
+ }
+ }
+
+ return 0;
+}
+
+static void __CONSTRUCTOR__ dbus_init(void)
+{
+ dbus_threads_init_default();
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "log.h"
+#include "deviced-priv.h"
+#include "dd-deviced.h"
+#include "dbus.h"
+#include "score-defines.h"
+
+#define PERMANENT_DIR "/tmp/permanent"
+#define VIP_DIR "/tmp/vip"
+
+#define OOMADJ_SET "oomadj_set"
+#define PROCESS_GROUP_SET "process_group_set"
+#define PROCESS_VIP "process_vip"
+#define PROCESS_PERMANENT "process_permanent"
+
+enum mp_entry_type {
+ MP_VIP,
+ MP_PERMANENT,
+ MP_NONE
+};
+
+int util_oomadj_set(int pid, int oomadj_val)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *pa[4];
+ char buf1[SYSTEM_NOTI_MAXARG];
+ char buf2[SYSTEM_NOTI_MAXARG];
+ int ret, val;
+
+ snprintf(buf1, sizeof(buf1), "%d", pid);
+ snprintf(buf2, sizeof(buf2), "%d", oomadj_val);
+
+ pa[0] = OOMADJ_SET;
+ pa[1] = "2";
+ pa[2] = buf1;
+ pa[3] = buf2;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
+ pa[0], "siss", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_PROCESS, pa[0], val);
+ return val;
+}
+
+static int util_process_group_set(char* name, int pid)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *pa[4];
+ char buf[SYSTEM_NOTI_MAXARG];
+ int ret, val;
+
+ if (strncmp(PROCESS_VIP, name, strlen(name)) != 0 &&
+ strncmp(PROCESS_PERMANENT, name, strlen(name)) != 0) {
+ _E("fail to insert at %s group", name);
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "%d", pid);
+ _D("pid(%d) is inserted at vip", pid);
+
+ pa[0] = PROCESS_GROUP_SET;
+ pa[1] = "2";
+ pa[2] = buf;
+ pa[3] = name;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
+ pa[0], "siss", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_PROCESS, pa[0], val);
+ return val;
+}
+
+API int deviced_conf_set_mempolicy_bypid(int pid, enum mem_policy mempol)
+{
+ if (pid < 1)
+ return -1;
+
+ int oomadj_val = 0;
+
+ switch (mempol) {
+ case OOM_LIKELY:
+ oomadj_val = OOMADJ_BACKGRD_UNLOCKED;
+ break;
+ case OOM_IGNORE:
+ oomadj_val = OOMADJ_SU;
+ break;
+ default:
+ return -1;
+ }
+
+ return util_oomadj_set(pid, oomadj_val);
+}
+
+API int deviced_conf_set_mempolicy(enum mem_policy mempol)
+{
+ return deviced_conf_set_mempolicy_bypid(getpid(), mempol);
+}
+
+static int already_permanent(int pid)
+{
+ char buf[BUFF_MAX];
+
+ snprintf(buf, BUFF_MAX, "%s/%d", PERMANENT_DIR, pid);
+
+ if (access(buf, R_OK) == 0) {
+ _D("already_permanent process : %d", pid);
+ return 1;
+ }
+ return 0;
+}
+
+static int copy_cmdline(int pid)
+{
+ char buf[PATH_MAX];
+ char filepath[PATH_MAX];
+ int fd;
+ int cnt;
+ int r;
+
+ if (access(PERMANENT_DIR, R_OK) < 0) {
+ _D("no predefined matrix dir = %s, so created", PERMANENT_DIR);
+ r = mkdir(PERMANENT_DIR, 0777);
+ if (r < 0) {
+ _E("permanent directory mkdir is failed");
+ return -1;
+ }
+ }
+
+ snprintf(filepath, PATH_MAX, "/proc/%d/cmdline", pid);
+
+ fd = open(filepath, O_RDONLY);
+ if (fd == -1) {
+ _E("Failed to open");
+ return -1;
+ }
+
+ cnt = read(fd, buf, PATH_MAX);
+ close(fd);
+
+ if (cnt <= 0) {
+ /* Read /proc/<pid>/cmdline error */
+ _E("Failed to read");
+ return -1;
+ }
+
+ snprintf(filepath, PATH_MAX, "%s/%d", PERMANENT_DIR, pid);
+
+ fd = open(filepath, O_CREAT | O_WRONLY, 0644);
+ if (fd == -1) {
+ _E("Failed to open");
+ return -1;
+ }
+
+ if (write(fd, buf, cnt) == -1) {
+ _E("Failed to write");
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+API int deviced_conf_set_vip(int pid)
+{
+ char buf[BUFF_MAX];
+ int fd;
+ int r;
+
+ if (pid < 1)
+ return -1;
+
+ if (access(VIP_DIR, R_OK) < 0) {
+ _D("no predefined matrix dir = %s, so created", VIP_DIR);
+ r = mkdir(VIP_DIR, 0777);
+ if (r < 0) {
+ _E("sysconf_set_vip vip mkdir is failed");
+ return -1;
+ }
+ }
+
+ snprintf(buf, BUFF_MAX, "%s/%d", VIP_DIR, pid);
+ fd = open(buf, O_CREAT | O_RDWR, 0644);
+ if (fd < 0) {
+ _E("sysconf_set_vip fd open failed");
+ return -1;
+ }
+ close(fd);
+ if (util_process_group_set(PROCESS_VIP, pid) < 0) {
+ _E("set vip failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+API int deviced_conf_is_vip(int pid)
+{
+ if (pid < 1)
+ return -1;
+
+ char buf[BUFF_MAX];
+
+ snprintf(buf, BUFF_MAX, "%s/%d", VIP_DIR, pid);
+
+ if (access(buf, R_OK) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+API int deviced_conf_set_permanent_bypid(int pid)
+{
+ if (already_permanent(pid))
+ goto MEMPOL_SET;
+
+ if (copy_cmdline(pid) < 0)
+ return -1;
+
+ if (util_process_group_set(PROCESS_PERMANENT, pid) < 0) {
+ _E("set vip failed");
+ return -1;
+ }
+
+ MEMPOL_SET:
+ util_oomadj_set(pid, OOMADJ_SU);
+
+ return 0;
+}
+
+API int deviced_conf_set_permanent(void)
+{
+ pid_t pid = getpid();
+ return deviced_conf_set_permanent_bypid(pid);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <limits.h>
+
+#include "dd-deviced.h"
+#include "deviced-priv.h"
+#include "log.h"
+#include "dbus.h"
+
+#define PREDEF_PWROFF_POPUP "pwroff-popup"
+#define PREDEF_ENTERSLEEP "entersleep"
+#define PREDEF_LEAVESLEEP "leavesleep"
+#define PREDEF_REBOOT "reboot"
+#define PREDEF_BACKGRD "backgrd"
+#define PREDEF_FOREGRD "foregrd"
+#define PREDEF_ACTIVE "active"
+#define PREDEF_INACTIVE "inactive"
+#define PREDEF_SET_DATETIME "set_datetime"
+#define PREDEF_SET_TIMEZONE "set_timezone"
+
+#define PREDEF_SET_MAX_FREQUENCY "set_max_frequency"
+#define PREDEF_SET_MIN_FREQUENCY "set_min_frequency"
+#define PREDEF_RELEASE_MAX_FREQUENCY "release_max_frequency"
+#define PREDEF_RELEASE_MIN_FREQUENCY "release_min_frequency"
+
+#define ALARM_BUS_NAME "com.samsung.alarm.manager"
+#define ALARM_PATH_NAME "/com/samsung/alarm/manager"
+#define ALARM_INTERFACE_NAME ALARM_BUS_NAME
+#define ALARM_SET_TIME_METHOD "alarm_set_time"
+
+enum deviced_noti_cmd {
+ ADD_deviced_ACTION,
+ CALL_deviced_ACTION
+};
+
+#define SYSTEM_NOTI_SOCKET_PATH "/tmp/sn"
+#define RETRY_READ_COUNT 10
+
+static inline int send_int(int fd, int val)
+{
+ return write(fd, &val, sizeof(int));
+}
+
+static inline int send_str(int fd, char *str)
+{
+ int len;
+ int ret;
+ if (str == NULL) {
+ len = 0;
+ ret = write(fd, &len, sizeof(int));
+ } else {
+ len = strlen(str);
+ if (len > SYSTEM_NOTI_MAXSTR)
+ len = SYSTEM_NOTI_MAXSTR;
+ ret = write(fd, &len, sizeof(int));
+ if (ret < 0)
+ _E("Failed to write (%d)", errno);
+ ret = write(fd, str, len);
+ if (ret < 0)
+ _E("Failed to write (%d)", errno);
+ }
+ return ret;
+}
+
+static int noti_send(struct sysnoti *msg)
+{
+ int client_len;
+ int client_sockfd;
+ int result;
+ int r;
+ int retry_count = 0;
+ struct sockaddr_un clientaddr;
+ int i;
+
+ client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (client_sockfd == -1) {
+ _E("socket create failed");
+ return -1;
+ }
+ bzero(&clientaddr, sizeof(clientaddr));
+ clientaddr.sun_family = AF_UNIX;
+ strncpy(clientaddr.sun_path, SYSTEM_NOTI_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
+ client_len = sizeof(clientaddr);
+
+ if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
+ 0) {
+ _E("connect failed");
+ close(client_sockfd);
+ return -1;
+ }
+
+ send_int(client_sockfd, msg->pid);
+ send_int(client_sockfd, msg->cmd);
+ send_str(client_sockfd, msg->type);
+ send_str(client_sockfd, msg->path);
+ send_int(client_sockfd, msg->argc);
+ for (i = 0; i < msg->argc; i++)
+ send_str(client_sockfd, msg->argv[i]);
+
+ while (retry_count < RETRY_READ_COUNT) {
+ r = read(client_sockfd, &result, sizeof(int));
+ if (r < 0) {
+ if (errno == EINTR) {
+ _E("Re-read for error(EINTR)");
+ retry_count++;
+ continue;
+ }
+ _E("Read fail for str length");
+ result = -1;
+ break;
+
+ }
+ break;
+ }
+ if (retry_count == RETRY_READ_COUNT) {
+ _E("Read retry failed");
+ }
+
+ close(client_sockfd);
+ return result;
+}
+
+API int deviced_call_predef_action(const char *type, int num, ...)
+{
+ struct sysnoti *msg;
+ int ret;
+ va_list argptr;
+ int i;
+ char *args = NULL;
+
+ if (type == NULL || num > SYSTEM_NOTI_MAXARG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ msg = malloc(sizeof(struct sysnoti));
+
+ if (msg == NULL) {
+ /* Do something for not enought memory error */
+ return -1;
+ }
+
+ msg->pid = getpid();
+ msg->cmd = CALL_deviced_ACTION;
+ msg->type = (char *)type;
+ msg->path = NULL;
+
+ msg->argc = num;
+ va_start(argptr, num);
+ for (i = 0; i < num; i++) {
+ args = va_arg(argptr, char *);
+ msg->argv[i] = args;
+ }
+ va_end(argptr);
+
+ ret = noti_send(msg);
+ free(msg);
+
+ return ret;
+}
+
+static int dbus_proc_handler(char* type, char *buf)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *pa[3];
+ int ret, val;
+
+ pa[0] = type;
+ pa[1] = "1";
+ pa[2] = buf;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
+ pa[0], "sis", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_PROCESS, pa[0], val);
+ return val;
+}
+
+API int deviced_inform_foregrd(void)
+{
+ char buf[255];
+ snprintf(buf, sizeof(buf), "%d", getpid());
+ return dbus_proc_handler(PREDEF_FOREGRD, buf);
+}
+
+API int deviced_inform_backgrd(void)
+{
+ char buf[255];
+ snprintf(buf, sizeof(buf), "%d", getpid());
+ return dbus_proc_handler(PREDEF_BACKGRD, buf);
+}
+
+API int deviced_inform_active(pid_t pid)
+{
+ char buf[255];
+ snprintf(buf, sizeof(buf), "%d", pid);
+ return dbus_proc_handler(PREDEF_ACTIVE, buf);
+}
+
+API int deviced_inform_inactive(pid_t pid)
+{
+ char buf[255];
+ snprintf(buf, sizeof(buf), "%d", pid);
+ return dbus_proc_handler(PREDEF_INACTIVE, buf);
+}
+
+static int dbus_power_handler(char* type)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *pa[2];
+ int ret, val;
+
+ pa[0] = type;
+ pa[1] = "0";
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER,
+ pa[0], "si", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_POWER, pa[0], val);
+ return val;
+}
+
+API int deviced_request_poweroff(void)
+{
+ return dbus_power_handler(PREDEF_PWROFF_POPUP);
+}
+
+API int deviced_request_entersleep(void)
+{
+ return dbus_power_handler(PREDEF_ENTERSLEEP);
+}
+
+API int deviced_request_leavesleep(void)
+{
+ return dbus_power_handler(PREDEF_LEAVESLEEP);
+}
+
+API int deviced_request_reboot(void)
+{
+ return dbus_power_handler(PREDEF_REBOOT);
+}
+
+static int dbus_time_handler(char* type, char* buf)
+{
+ DBusError err;
+ DBusMessage *msg;
+ pid_t pid;
+ char name[PATH_MAX];
+ char *pa[3];
+ int ret, val;
+
+ pa[0] = type;
+ pa[1] = "1";
+ pa[2] = buf;
+
+ pid = getpid();
+ ret = deviced_get_cmdline_name(pid, name, sizeof(name));
+ if (ret != 0)
+ snprintf(name, sizeof(name), "%d", pid);
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
+ pa[0], "sis", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _SI("[%s] %s-%s(%s) : %d", name, DEVICED_INTERFACE_SYSNOTI, pa[0], pa[2], val);
+
+ return val;
+}
+
+static DBusMessage *alarm_set_time_sync_with_reply(time_t timet)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return NULL;
+ }
+
+ msg = dbus_message_new_method_call(ALARM_BUS_NAME, ALARM_PATH_NAME, ALARM_INTERFACE_NAME, ALARM_SET_TIME_METHOD);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ ALARM_PATH_NAME, ALARM_INTERFACE_NAME, ALARM_SET_TIME_METHOD);
+ return NULL;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &timet);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+ if (!reply) {
+ _E("dbus_connection_send error(No reply) %s %s:%s-%s",
+ ALARM_BUS_NAME, ALARM_PATH_NAME, ALARM_INTERFACE_NAME, ALARM_SET_TIME_METHOD);
+ }
+
+ if (dbus_error_is_set(&err)) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, ALARM_BUS_NAME, ALARM_PATH_NAME, ALARM_INTERFACE_NAME, ALARM_SET_TIME_METHOD);
+ dbus_error_free(&err);
+ reply = NULL;
+ }
+
+ dbus_message_unref(msg);
+ return reply;
+}
+
+static int alarm_set_time(time_t timet)
+{
+ DBusError err;
+ DBusMessage *msg;
+ pid_t pid;
+ char name[PATH_MAX];
+ int ret, val;
+
+ pid = getpid();
+ ret = deviced_get_cmdline_name(pid, name, sizeof(name));
+ if (ret != 0)
+ snprintf(name, sizeof(name), "%d", pid);
+ _SI("[%s]start %s %ld", name, ALARM_INTERFACE_NAME, timet);
+
+ msg = alarm_set_time_sync_with_reply(timet);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _SI("[%s]end %s %ld, %d", name, ALARM_INTERFACE_NAME, timet, val);
+ return val;
+}
+
+API int deviced_set_datetime(time_t timet)
+{
+ if (timet < 0L)
+ return -1;
+ return alarm_set_time(timet);
+}
+
+API int deviced_set_timezone(char *tzpath_str)
+{
+ if (tzpath_str == NULL)
+ return -1;
+ char buf[255];
+ snprintf(buf, sizeof(buf), "%s", tzpath_str);
+ return dbus_time_handler(PREDEF_SET_TIMEZONE, buf);
+}
+
+static int dbus_cpu_handler(char* type, char* buf_pid, char* buf_freq)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *pa[4];
+ int ret, val;
+
+ pa[0] = type;
+ pa[1] = "2";
+ pa[2] = buf_pid;
+ pa[3] = buf_freq;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
+ pa[0], "siss", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_SYSNOTI, pa[0], val);
+ return val;
+}
+
+API int deviced_request_set_cpu_max_frequency(int val)
+{
+ char buf_pid[8];
+ char buf_freq[256];
+
+ // to do - need to check new frequncy is valid
+ snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
+ snprintf(buf_freq, sizeof(buf_freq), "%d", val * 1000);
+
+ return dbus_cpu_handler(PREDEF_SET_MAX_FREQUENCY, buf_pid, buf_freq);
+}
+
+API int deviced_request_set_cpu_min_frequency(int val)
+{
+ char buf_pid[8];
+ char buf_freq[256];
+
+ // to do - need to check new frequncy is valid
+ snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
+ snprintf(buf_freq, sizeof(buf_freq), "%d", val * 1000);
+
+ return dbus_cpu_handler(PREDEF_SET_MIN_FREQUENCY, buf_pid, buf_freq);
+}
+
+API int deviced_release_cpu_max_frequency()
+{
+ char buf_pid[8];
+
+ snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
+
+ return dbus_cpu_handler(PREDEF_RELEASE_MAX_FREQUENCY, buf_pid, "2");
+}
+
+API int deviced_release_cpu_min_frequency()
+{
+ char buf_pid[8];
+
+ snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
+
+ return dbus_cpu_handler(PREDEF_RELEASE_MIN_FREQUENCY, buf_pid, "2");
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "log.h"
+#include "dd-deviced.h"
+#include "deviced-priv.h"
+
+API int deviced_get_pid(const char *execpath)
+{
+ DIR *dp;
+ struct dirent entry;
+ struct dirent *dentry;
+ int pid = -1, fd;
+ char buf[BUFF_MAX];
+ char buf2[BUFF_MAX];
+ int ret;
+
+ dp = opendir("/proc");
+ if (!dp) {
+ _E("open /proc");
+ return -1;
+ }
+
+ if ((readdir_r(dp, &entry, &dentry)) != 0)
+ dentry = NULL;
+
+ while (dentry != NULL) {
+ if (!isdigit(dentry->d_name[0]))
+ continue;
+
+ pid = atoi(dentry->d_name);
+
+ snprintf(buf, BUFF_MAX, "/proc/%d/cmdline", pid);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ continue;
+
+ ret = read(fd, buf2, BUFF_MAX);
+ close(fd);
+
+ if (ret < 0 || ret >= BUFF_MAX)
+ continue;
+
+ buf2[ret] = '\0';
+
+ if (!strcmp(buf2, execpath)) {
+ closedir(dp);
+ return pid;
+ }
+ }
+
+ errno = ESRCH;
+ closedir(dp);
+ return -1;
+}
+
+API int deviced_get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
+{
+ int fd, ret;
+ char buf[PATH_MAX + 1];
+ char *filename;
+
+ if (cmdline == NULL) {
+ errno = EINVAL;
+ return -EINVAL;
+ }
+
+ snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ errno = ESRCH;
+ return -ESRCH;
+ }
+
+ ret = read(fd, buf, PATH_MAX);
+ close(fd);
+ if (ret < 0) {
+ ret = -errno;
+ _E("read() failed (%d)", ret);
+ return ret;
+ }
+ buf[PATH_MAX] = '\0';
+
+ filename = strrchr(buf, '/');
+ if (filename == NULL)
+ filename = buf;
+ else
+ filename = filename + 1;
+
+ if (cmdline_size < strlen(filename) + 1) {
+ errno = EOVERFLOW;
+ return -EOVERFLOW;
+ }
+
+ strncpy(cmdline, filename, cmdline_size - 1);
+ cmdline[cmdline_size - 1] = '\0';
+ return 0;
+}
+
+API int deviced_get_apppath(pid_t pid, char *app_path, size_t app_path_size)
+{
+ char buf[PATH_MAX];
+ int ret;
+
+ snprintf(buf, PATH_MAX, "/proc/%d/exe", pid);
+ if (app_path == NULL
+ || (ret = readlink(buf, app_path, app_path_size)) == -1)
+ return -1;
+ if (app_path_size == ret) {
+ app_path[ret - 1] = '\0';
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ app_path[ret] = '\0';
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 "log.h"
+#include "dbus.h"
+#include "common.h"
+#include "dd-display.h"
+
+#define DISPLAY_MAX_BRIGHTNESS 100
+#define DISPLAY_MIN_BRIGHTNESS 1
+#define DISPLAY_DIM_BRIGHTNESS 0
+
+#define HOLDKEY_BLOCK_BIT 0x1
+
+#define METHOD_SET_REFRESH_RATE "SetRefreshRate"
+#define METHOD_LOCK_STATE "lockstate"
+#define METHOD_UNLOCK_STATE "unlockstate"
+#define METHOD_CHANGE_STATE "changestate"
+#define METHOD_GET_DISPLAY_COUNT "GetDisplayCount"
+#define METHOD_GET_MAX_BRIGHTNESS "GetMaxBrightness"
+#define METHOD_GET_BRIGHTNESS "GetBrightness"
+#define METHOD_SET_BRIGHTNESS "SetBrightness"
+#define METHOD_HOLD_BRIGHTNESS "HoldBrightness"
+#define METHOD_RELEASE_BRIGHTNESS "ReleaseBrightness"
+#define METHOD_GET_ACL_STATUS "GetAclStatus"
+#define METHOD_SET_ACL_STATUS "SetAclStatus"
+
+#define STR_LCD_OFF "lcdoff"
+#define STR_LCD_DIM "lcddim"
+#define STR_LCD_ON "lcdon"
+#define STR_SUSPEND "suspend"
+
+#define STR_STAYCURSTATE "staycurstate"
+#define STR_GOTOSTATENOW "gotostatenow"
+
+#define STR_HOLDKEYBLOCK "holdkeyblock"
+#define STR_NULL "NULL"
+
+#define STR_SLEEP_MARGIN "sleepmargin"
+#define STR_RESET_TIMER "resettimer"
+#define STR_KEEP_TIMER "keeptimer"
+
+API int display_get_max_brightness(void)
+{
+ int ret;
+
+ ret = dbus_method_sync(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ METHOD_GET_MAX_BRIGHTNESS, NULL, NULL);
+ if (ret < 0)
+ return DISPLAY_MAX_BRIGHTNESS;
+
+ _D("get max brightness : %d", ret);
+ return ret;
+}
+
+API int display_set_brightness_with_setting(int val)
+{
+ char str_val[32];
+ char *arr[1];
+ int ret;
+
+ if (val < 0 || val > 100)
+ return -EINVAL;
+
+ snprintf(str_val, sizeof(str_val), "%d", val);
+ arr[0] = str_val;
+
+ ret = dbus_method_async(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ METHOD_SET_BRIGHTNESS, "i", arr);
+ if (ret < 0)
+ _E("no message : failed to setting");
+
+ return ret;
+}
+
+static inline char *get_lcd_str(unsigned int val)
+{
+ switch (val) {
+ case LCD_NORMAL:
+ return STR_LCD_ON;
+ case LCD_DIM:
+ return STR_LCD_DIM;
+ case LCD_OFF:
+ return STR_LCD_OFF;
+ case SUSPEND:
+ return STR_SUSPEND;
+ default:
+ return NULL;
+ }
+}
+
+static void display_change_cb(void *data, DBusMessage *msg, DBusError *unused)
+{
+ DBusError err;
+ int ret, val;
+
+ if (!msg)
+ return;
+
+ dbus_error_init(&err);
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_CHANGE_STATE, val);
+}
+
+API int display_change_state(unsigned int s_bits)
+{
+ char *p, *pa[1];
+ int ret;
+
+ p = get_lcd_str(s_bits);
+ if (!p)
+ return -EINVAL;
+ pa[0] = p;
+
+ ret = dbus_method_async_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ METHOD_CHANGE_STATE, "s", pa, display_change_cb, -1, NULL);
+ if (ret < 0)
+ _E("no message : failed to change state");
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_CHANGE_STATE, ret);
+
+ return ret;
+}
+
+static void display_lock_cb(void *data, DBusMessage *msg, DBusError *unused)
+{
+ DBusError err;
+ int ret, val;
+
+ if (!msg)
+ return;
+
+ dbus_error_init(&err);
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_LOCK_STATE, val);
+}
+
+API int display_lock_state(unsigned int s_bits, unsigned int flag,
+ unsigned int timeout)
+{
+ char *p, *pa[4];
+ char str_timeout[32];
+ int ret;
+
+ p = get_lcd_str(s_bits);
+ if (!p)
+ return -EINVAL;
+ pa[0] = p;
+
+ if (flag & GOTO_STATE_NOW)
+ /* if the flag is true, go to the locking state directly */
+ p = STR_GOTOSTATENOW;
+ else
+ p = STR_STAYCURSTATE;
+ pa[1] = p;
+
+ if (flag & HOLD_KEY_BLOCK)
+ p = STR_HOLDKEYBLOCK;
+ else
+ p = STR_NULL;
+ pa[2] = p;
+
+ snprintf(str_timeout, sizeof(str_timeout), "%d", timeout);
+ pa[3] = str_timeout;
+
+ ret = dbus_method_async_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ METHOD_LOCK_STATE, "sssi", pa, display_lock_cb, -1, NULL);
+ if (ret < 0)
+ _E("no message : failed to lock state");
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_LOCK_STATE, ret);
+
+ return ret;
+}
+
+static void display_unlock_cb(void *data, DBusMessage *msg, DBusError *unused)
+{
+ DBusError err;
+ int ret, val;
+
+ if (!msg)
+ return;
+
+ dbus_error_init(&err);
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ return;
+ }
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_UNLOCK_STATE, val);
+}
+
+API int display_unlock_state(unsigned int s_bits, unsigned int flag)
+{
+ char *p, *pa[2];
+ int ret;
+
+ p = get_lcd_str(s_bits);
+ if (!p)
+ return -EINVAL;
+ pa[0] = p;
+
+ switch (flag) {
+ case PM_SLEEP_MARGIN:
+ p = STR_SLEEP_MARGIN;
+ break;
+ case PM_RESET_TIMER:
+ p = STR_RESET_TIMER;
+ break;
+ case PM_KEEP_TIMER:
+ p = STR_KEEP_TIMER;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pa[1] = p;
+
+ ret = dbus_method_async_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ METHOD_UNLOCK_STATE, "ss", pa, display_unlock_cb, -1, NULL);
+ if (ret < 0)
+ _E("no message : failed to unlock state");
+
+ _D("%s-%s : %d", DEVICED_INTERFACE_DISPLAY, METHOD_UNLOCK_STATE, ret);
+
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <vconf.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "haptic-plugin-intf.h"
+#include "dd-haptic.h"
+#include "common.h"
+
+#define METHOD_OPEN_DEVICE "OpenDevice"
+#define METHOD_CLOSE_DEVICE "CloseDevice"
+#define METHOD_STOP_DEVICE "StopDevice"
+#define METHOD_VIBRATE_MONOTONE "VibrateMonotone"
+#define METHOD_VIBRATE_BUFFER "VibrateBuffer"
+#define METHOD_GET_COUNT "GetCount"
+#define METHOD_GET_STATE "GetState"
+#define METHOD_GET_DURATION "GetDuration"
+#define METHOD_CREATE_EFFECT "CreateEffect"
+#define METHOD_SAVE_BINARY "SaveBinary"
+
+#define TEMP_BUFFER_SIZE (64*1024)
+
+/* START of Static Function Section */
+static unsigned char *convert_file_to_buffer(const char *file_name, int *size)
+{
+ FILE *pf;
+ long file_size;
+ unsigned char *pdata = NULL;
+
+ if (!file_name)
+ return NULL;
+
+ /* Get File Stream Pointer */
+ pf = fopen(file_name, "rb");
+ if (!pf) {
+ _E("fopen failed : %d", errno);
+ return NULL;
+ }
+
+ if (fseek(pf, 0, SEEK_END))
+ goto error;
+
+ file_size = ftell(pf);
+ if (fseek(pf, 0, SEEK_SET))
+ goto error;
+
+ if (file_size < 0)
+ goto error;
+
+ pdata = (unsigned char *)malloc(file_size);
+ if (!pdata)
+ goto error;
+
+ if (fread(pdata, 1, file_size, pf) != file_size)
+ goto err_free;
+
+ fclose(pf);
+ *size = file_size;
+ return pdata;
+
+err_free:
+ free(pdata);
+
+error:
+ fclose(pf);
+
+ _E("failed to convert file to buffer (%d)", errno);
+ return NULL;
+}
+
+static int save_data(const unsigned char *data, int size, const char *file_path)
+{
+ FILE *file;
+ int fd;
+
+ file = fopen(file_path, "wb+");
+ if (file == NULL) {
+ _E("To open file is failed : %d", errno);
+ return -1;
+ }
+
+ if (fwrite(data, 1, size, file) != size) {
+ _E("To write file is failed : %d", errno);
+ fclose(file);
+ return -1;
+ }
+
+ fd = fileno(file);
+ if (fd < 0) {
+ _E("To get file descriptor is failed : %d", errno);
+ fclose(file);
+ return -1;
+ }
+
+ if (fsync(fd) < 0) {
+ _E("To be synchronized with the disk is failed : %d", errno);
+ fclose(file);
+ return -1;
+ }
+
+ fclose(file);
+ return 0;
+}
+
+static haptic_feedback_e convert_setting_to_module_level(void)
+{
+ int setting_fb_level;
+
+ if (vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &setting_fb_level) < 0) {
+ setting_fb_level = SETTING_VIB_FEEDBACK_LEVEL3;
+ }
+
+ if (setting_fb_level < HAPTIC_FEEDBACK_0 || setting_fb_level > HAPTIC_FEEDBACK_5)
+ return -1;
+
+ switch (setting_fb_level) {
+ case SETTING_VIB_FEEDBACK_LEVEL0:
+ return HAPTIC_FEEDBACK_0;
+ case SETTING_VIB_FEEDBACK_LEVEL1:
+ return HAPTIC_FEEDBACK_1;
+ case SETTING_VIB_FEEDBACK_LEVEL2:
+ return HAPTIC_FEEDBACK_2;
+ case SETTING_VIB_FEEDBACK_LEVEL3:
+ return HAPTIC_FEEDBACK_3;
+ case SETTING_VIB_FEEDBACK_LEVEL4:
+ return HAPTIC_FEEDBACK_4;
+ case SETTING_VIB_FEEDBACK_LEVEL5:
+ return HAPTIC_FEEDBACK_5;
+ default:
+ break;
+ }
+ return -1;
+}
+/* END of Static Function Section */
+
+API int haptic_get_count(int *device_number)
+{
+ int ret;
+
+ /* check if pointer is valid */
+ if (device_number == NULL) {
+ _E("Invalid parameter : device_number(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* request to deviced to get haptic count */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_GET_COUNT, NULL, NULL);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ *device_number = ret;
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_open(haptic_device_e device_index, haptic_device_h *device_handle)
+{
+ char str_index[32];
+ char *arr[1];
+ int ret;
+
+ /* check if index is valid */
+ if (!(device_index == HAPTIC_DEVICE_0 || device_index == HAPTIC_DEVICE_1 ||
+ device_index == HAPTIC_DEVICE_ALL)) {
+ _E("Invalid parameter : device_index(%d)", device_index);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if pointer is valid */
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(str_index, sizeof(str_index), "%d", device_index);
+ arr[0] = str_index;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_OPEN_DEVICE, "i", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ *device_handle = (haptic_device_h)ret;
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_close(haptic_device_h device_handle)
+{
+ char str_handle[32];
+ char *arr[1];
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(str_handle, sizeof(str_handle), "%u", device_handle);
+ arr[0] = str_handle;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_CLOSE_DEVICE, "u", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_vibrate_monotone(haptic_device_h device_handle, int duration, haptic_effect_h *effect_handle)
+{
+ return haptic_vibrate_monotone_with_detail(device_handle,
+ duration,
+ HAPTIC_FEEDBACK_AUTO,
+ HAPTIC_PRIORITY_MIN,
+ effect_handle);
+}
+
+API int haptic_vibrate_monotone_with_detail(haptic_device_h device_handle,
+ int duration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
+{
+ char str_handle[32];
+ char str_duration[32];
+ char str_feedback[32];
+ char str_priority[32];
+ char *arr[4];
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if passed arguments are valid */
+ if (duration < 0 && duration != HAPTIC_DURATION_UNLIMITED) {
+ _E("Invalid parameter : duration(%d)", duration);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (feedback < HAPTIC_FEEDBACK_0 || feedback > HAPTIC_FEEDBACK_AUTO) {
+ _E("Invalid parameter : feedback(%d)", feedback);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (priority < HAPTIC_PRIORITY_MIN || priority > HAPTIC_PRIORITY_HIGH) {
+ _E("Invalid parameter : priority(%d)", priority);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* in case of FEEDBACK_AUTO, should be converted */
+ if (feedback == HAPTIC_FEEDBACK_AUTO)
+ feedback = convert_setting_to_module_level();
+
+ snprintf(str_handle, sizeof(str_handle), "%u", device_handle);
+ arr[0] = str_handle;
+ snprintf(str_duration, sizeof(str_duration), "%d", duration);
+ arr[1] = str_duration;
+ snprintf(str_feedback, sizeof(str_feedback), "%d", feedback);
+ arr[2] = str_feedback;
+ snprintf(str_priority, sizeof(str_priority), "%d", priority);
+ arr[3] = str_priority;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_VIBRATE_MONOTONE, "uiii", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ if (effect_handle != NULL)
+ *effect_handle = (haptic_effect_h)ret;
+
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_vibrate_file(haptic_device_h device_handle, const char *file_path, haptic_effect_h *effect_handle)
+{
+ unsigned char *vibe_buffer;
+ int size, ret;
+
+ vibe_buffer = convert_file_to_buffer(file_path, &size);
+ if (!vibe_buffer) {
+ _E("Convert file to buffer error");
+ return HAPTIC_ERROR_OPERATION_FAILED;
+ }
+
+ ret = haptic_vibrate_buffers_with_detail(device_handle,
+ (const unsigned char *)vibe_buffer,
+ size,
+ HAPTIC_ITERATION_ONCE,
+ HAPTIC_FEEDBACK_AUTO,
+ HAPTIC_PRIORITY_MIN,
+ effect_handle);
+ free(vibe_buffer);
+ return ret;
+}
+
+API int haptic_vibrate_file_with_detail(haptic_device_h device_handle,
+ const char *file_path,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
+{
+ unsigned char *vibe_buffer;
+ int size, ret;
+
+ vibe_buffer = convert_file_to_buffer(file_path, &size);
+ if (!vibe_buffer) {
+ _E("Convert file to buffer error");
+ return HAPTIC_ERROR_OPERATION_FAILED;
+ }
+
+ ret = haptic_vibrate_buffers_with_detail(device_handle,
+ (const unsigned char *)vibe_buffer,
+ size,
+ iteration,
+ feedback,
+ priority,
+ effect_handle);
+ free(vibe_buffer);
+ return ret;
+}
+
+API int haptic_vibrate_buffer(haptic_device_h device_handle, const unsigned char *vibe_buffer, haptic_effect_h *effect_handle)
+{
+ return haptic_vibrate_buffers_with_detail(device_handle,
+ vibe_buffer,
+ TEMP_BUFFER_SIZE,
+ HAPTIC_ITERATION_ONCE,
+ HAPTIC_FEEDBACK_AUTO,
+ HAPTIC_PRIORITY_MIN,
+ effect_handle);
+}
+
+API int haptic_vibrate_buffer_with_detail(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
+{
+ return haptic_vibrate_buffers_with_detail(device_handle,
+ vibe_buffer,
+ TEMP_BUFFER_SIZE,
+ iteration,
+ feedback,
+ priority,
+ effect_handle);
+}
+
+API int haptic_vibrate_buffers(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ int size,
+ haptic_effect_h *effect_handle)
+{
+ return haptic_vibrate_buffers_with_detail(device_handle,
+ vibe_buffer,
+ size,
+ HAPTIC_ITERATION_ONCE,
+ HAPTIC_FEEDBACK_AUTO,
+ HAPTIC_PRIORITY_MIN,
+ effect_handle);
+}
+
+API int haptic_vibrate_buffers_with_detail(haptic_device_h device_handle,
+ const unsigned char *vibe_buffer,
+ int size,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
+{
+ char str_handle[32];
+ char str_iteration[32];
+ char str_feedback[32];
+ char str_priority[32];
+ char *arr[6];
+ struct dbus_byte bytes;
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if passed arguments are valid */
+ if (vibe_buffer == NULL) {
+ _E("Invalid parameter : vibe_buffer(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (iteration < HAPTIC_ITERATION_ONCE || iteration > HAPTIC_ITERATION_INFINITE) {
+ _E("Invalid parameter : iteration(%d)", iteration);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (feedback < HAPTIC_FEEDBACK_0 || feedback > HAPTIC_FEEDBACK_AUTO) {
+ _E("Invalid parameter : feedback(%d)", feedback);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (priority < HAPTIC_PRIORITY_MIN || priority > HAPTIC_PRIORITY_HIGH) {
+ _E("Invalid parameter : priority(%d)", priority);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* in case of FEEDBACK_AUTO, should be converted */
+ if (feedback == HAPTIC_FEEDBACK_AUTO)
+ feedback = convert_setting_to_module_level();
+
+ snprintf(str_handle, sizeof(str_handle), "%u", device_handle);
+ arr[0] = str_handle;
+ bytes.size = size;
+ bytes.data = vibe_buffer;
+ arr[2] = (char *)&bytes;
+ snprintf(str_iteration, sizeof(str_iteration), "%d", iteration);
+ arr[3] = str_iteration;
+ snprintf(str_feedback, sizeof(str_feedback), "%d", feedback);
+ arr[4] = str_feedback;
+ snprintf(str_priority, sizeof(str_priority), "%d", priority);
+ arr[5] = str_priority;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_VIBRATE_BUFFER, "uayiii", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ if (effect_handle != NULL)
+ *effect_handle = (haptic_effect_h)ret;
+
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_stop_effect(haptic_device_h device_handle, haptic_effect_h effect_handle)
+{
+ return haptic_stop_all_effects(device_handle);
+}
+
+API int haptic_stop_all_effects(haptic_device_h device_handle)
+{
+ char str_handle[32];
+ char *arr[1];
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(str_handle, sizeof(str_handle), "%u", device_handle);
+ arr[0] = str_handle;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_STOP_DEVICE, "u", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_get_effect_state(haptic_device_h device_handle, haptic_effect_h effect_handle, haptic_state_e *effect_state)
+{
+ char str_index[32];
+ char *arr[1];
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if pointer is valid */
+ if (effect_state == NULL) {
+ _E("Invalid parameter : effect_state(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(str_index, sizeof(str_index), "%d", HAPTIC_DEVICE_0);
+ arr[0] = str_index;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_GET_STATE, "i", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ *effect_state = (haptic_state_e)ret;
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_create_effect(unsigned char *vibe_buffer,
+ int max_bufsize,
+ haptic_effect_element_s *elem_arr,
+ int max_elemcnt)
+{
+ DBusError err;
+ DBusMessage *msg;
+ dbus_bool_t ret;
+ char str_bufsize[32];
+ char str_elemcnt[32];
+ char *arr[4];
+ char *data;
+ int i, temp, size, ret_val;
+ struct dbus_byte bytes;
+
+ /* check if passed arguments are valid */
+ if (vibe_buffer == NULL) {
+ _E("Invalid parameter : vibe_buffer(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (max_bufsize <= 0) {
+ _E("Invalid parameter : max_bufsize(%d)", max_bufsize);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (elem_arr == NULL) {
+ _E("Invalid parameter : elem_arr(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (max_elemcnt <= 0) {
+ _E("Invalid parameter : max_elemcnt(%d)", max_elemcnt);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* convert to proper feedback level in case of auto */
+ for (i = 0; i < max_elemcnt; i++) {
+ if (elem_arr[i].haptic_level == HAPTIC_FEEDBACK_AUTO) {
+ vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &temp);
+ elem_arr[i].haptic_level = temp*20;
+ }
+ }
+
+ snprintf(str_bufsize, sizeof(str_bufsize), "%d", max_bufsize);
+ arr[0] = str_bufsize;
+ bytes.size = sizeof(haptic_effect_element_s)*max_elemcnt;
+ bytes.data = (unsigned char *)elem_arr;
+ arr[2] = (char *)&bytes;
+ snprintf(str_elemcnt, sizeof(str_elemcnt), "%d", max_elemcnt);
+ arr[3] = str_elemcnt;
+
+ /* request to deviced to open haptic device */
+ msg = dbus_method_sync_with_reply(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_CREATE_EFFECT, "iayi", arr);
+ if (!msg)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, &size,
+ DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ goto err;
+ }
+
+ if (ret_val < 0) {
+ _E("%s-%s failed : %d", VIBRATOR_INTERFACE_HAPTIC, METHOD_CREATE_EFFECT, ret_val);
+ goto err;
+ }
+
+ if (max_bufsize < size) {
+ _E("max_bufsize(%d) is smaller than effect buffer size(%d)", max_bufsize, size);
+ goto err;
+ }
+
+ memcpy(vibe_buffer, data, max_bufsize);
+ dbus_message_unref(msg);
+ return HAPTIC_ERROR_NONE;
+err:
+ dbus_message_unref(msg);
+ return HAPTIC_ERROR_OPERATION_FAILED;
+}
+
+API int haptic_save_effect(const unsigned char *vibe_buffer,
+ int max_bufsize,
+ const char *file_path)
+{
+ struct stat buf;
+ int ret;
+
+ /* check if passed arguments are valid */
+ if (vibe_buffer == NULL) {
+ _E("Invalid parameter : vibe_buffer(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (max_bufsize <= 0) {
+ _E("Invalid parameter : max_bufsize(%d)", max_bufsize);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (file_path == NULL) {
+ _E("Invalid parameter : file_path(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if the file already exists */
+ if (!stat(file_path, &buf)) {
+ _E("Already exist : file_path(%s)", file_path);
+ return HAPTIC_ERROR_FILE_EXISTS;
+ }
+
+ _D("file path : %s", file_path);
+ ret = save_data(vibe_buffer, max_bufsize, file_path);
+ if (ret < 0) {
+ _E("fail to save data");
+ return HAPTIC_MODULE_OPERATION_FAILED;
+ }
+
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_get_file_duration(haptic_device_h device_handle, const char *file_path, int *file_duration)
+{
+ unsigned char *vibe_buffer;
+ int size, ret;
+
+ vibe_buffer = convert_file_to_buffer(file_path, &size);
+ if (!vibe_buffer) {
+ _E("Convert file to buffer error");
+ return HAPTIC_ERROR_OPERATION_FAILED;
+ }
+
+ ret = haptic_get_buffers_duration(device_handle,
+ (const unsigned char *)vibe_buffer,
+ size,
+ file_duration);
+ free(vibe_buffer);
+ return ret;
+}
+
+API int haptic_get_buffer_duration(haptic_device_h device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+ return haptic_get_buffers_duration(device_handle,
+ vibe_buffer,
+ TEMP_BUFFER_SIZE,
+ buffer_duration);
+}
+
+API int haptic_get_buffers_duration(haptic_device_h device_handle, const unsigned char *vibe_buffer, int size, int *buffer_duration)
+{
+ char str_handle[32];
+ char *arr[3];
+ struct dbus_byte bytes;
+ int ret;
+
+ /* check if handle is valid */
+ if (!device_handle) {
+ _E("Invalid parameter : device_handle");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (vibe_buffer == NULL) {
+ _E("Invalid parameter : vibe_buffer(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if pointer is valid */
+ if (buffer_duration == NULL) {
+ _E("Invalid parameter : buffer_duration(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(str_handle, sizeof(str_handle), "%u", device_handle);
+ arr[0] = str_handle;
+ bytes.size = size;
+ bytes.data = vibe_buffer;
+ arr[2] = (char *)&bytes;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_GET_DURATION, "uay", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ *buffer_duration = ret;
+ return HAPTIC_ERROR_NONE;
+}
+
+API int haptic_save_led(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+ struct stat buf;
+ char *arr[3];
+ struct dbus_byte bytes;
+ int ret;
+
+ /* check if passed arguments are valid */
+ if (vibe_buffer == NULL) {
+ _E("Invalid parameter : vibe_buffer(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (max_bufsize <= 0) {
+ _E("Invalid parameter : max_bufsize(%d)", max_bufsize);
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (file_path == NULL) {
+ _E("Invalid parameter : file_path(NULL)");
+ return HAPTIC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* check if the file already exists */
+ if (!stat(file_path, &buf)) {
+ _E("Already exist : file_path(%s)", file_path);
+ return HAPTIC_ERROR_FILE_EXISTS;
+ }
+
+ bytes.size = max_bufsize;
+ bytes.data = vibe_buffer;
+ arr[1] = (char *)&bytes;
+ arr[2] = (char *)file_path;
+
+ /* request to deviced to open haptic device */
+ ret = dbus_method_sync(VIBRATOR_BUS_NAME,
+ VIBRATOR_PATH_HAPTIC, VIBRATOR_INTERFACE_HAPTIC,
+ METHOD_SAVE_BINARY, "ays", arr);
+ if (ret < 0)
+ return HAPTIC_ERROR_OPERATION_FAILED;
+
+ return HAPTIC_ERROR_NONE;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <errno.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "common.h"
+
+#define METHOD_GET_BRIGHTNESS "GetBrightness"
+#define METHOD_GET_MAX_BRIGHTNESS "GetMaxBrightness"
+#define METHOD_SET_BRIGHTNESS "SetBrightness"
+#define METHOD_SET_IR_COMMAND "SetIrCommand"
+
+API int led_get_brightness(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ int ret, ret_val;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_LED, DEVICED_INTERFACE_LED,
+ METHOD_GET_BRIGHTNESS, NULL, NULL);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ ret_val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ return ret_val;
+}
+
+API int led_get_max_brightness(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ int ret, ret_val;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_LED, DEVICED_INTERFACE_LED,
+ METHOD_GET_MAX_BRIGHTNESS, NULL, NULL);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ ret_val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ return ret_val;
+}
+
+API int led_set_brightness_with_noti(int val, bool enable)
+{
+ DBusError err;
+ DBusMessage *msg;
+ char *arr[2];
+ char buf_val[32];
+ char buf_noti[32];
+ int ret, ret_val;
+
+ snprintf(buf_val, sizeof(buf_val), "%d", val);
+ arr[0] = buf_val;
+ snprintf(buf_noti, sizeof(buf_noti), "%d", enable);
+ arr[1] = buf_noti;
+
+ msg = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_LED, DEVICED_INTERFACE_LED,
+ METHOD_SET_BRIGHTNESS, "ii", arr);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]", err.name, err.message);
+ dbus_error_free(&err);
+ ret_val = -EBADMSG;
+ }
+
+ dbus_message_unref(msg);
+ return ret_val;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <vconf.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <storage.h>
+#include <glib.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "common.h"
+#include "dd-mmc.h"
+
+#define METHOD_REQUEST_SECURE_MOUNT "RequestSecureMount"
+#define METHOD_REQUEST_SECURE_UNMOUNT "RequestSecureUnmount"
+
+#define ODE_MOUNT_STATE 1
+
+#define FORMAT_TIMEOUT (120*1000)
+#define STORAGE_MMC 1
+#define BUF_MAX 256
+
+API int mmc_secure_mount(const char *mount_point)
+{
+ if (mount_point == NULL) {
+ return -EINVAL;
+ }
+
+ char *arr[1];
+ arr[0] = (char *)mount_point;
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_MMC,
+ DEVICED_INTERFACE_MMC, METHOD_REQUEST_SECURE_MOUNT, "s", arr);
+}
+
+API int mmc_secure_unmount(const char *mount_point)
+{
+ if (mount_point == NULL) {
+ return -EINVAL;
+ }
+
+ char *arr[1];
+ arr[0] = (char *)mount_point;
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_MMC,
+ DEVICED_INTERFACE_MMC, METHOD_REQUEST_SECURE_UNMOUNT, "s", arr);
+}
+
+static int get_mmc_primary_id()
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter aiter, piter;
+ char *param[1];
+ int type;
+ char *devnode = NULL;
+ bool primary;
+ int ret;
+ int id;
+
+ param[0] = "mmc";
+ reply = dbus_method_sync_with_reply(
+ STORAGE_BUS_NAME,
+ DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER,
+ "GetDeviceList", "s", param);
+ if (!reply) {
+ _E("Failed to get mmc storage list");
+ return -EPERM;
+ }
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &aiter);
+
+ while (dbus_message_iter_get_arg_type(&aiter) != DBUS_TYPE_INVALID) {
+ devnode = NULL;
+ dbus_message_iter_recurse(&aiter, &piter); /*type*/
+ dbus_message_iter_get_basic(&piter, &type);
+ dbus_message_iter_next(&piter); /* devnode */
+ dbus_message_iter_get_basic(&piter, &devnode);
+ dbus_message_iter_next(&piter); /* syspath */
+ dbus_message_iter_next(&piter); /* fsusage */
+ dbus_message_iter_next(&piter); /* fstype */
+ dbus_message_iter_next(&piter); /* fsversion */
+ dbus_message_iter_next(&piter); /* fsuuid */
+ dbus_message_iter_next(&piter); /* readonly */
+ dbus_message_iter_next(&piter); /* mountpath */
+ dbus_message_iter_next(&piter); /* state */
+ dbus_message_iter_next(&piter); /* primary */
+ dbus_message_iter_get_basic(&piter, &primary);
+ dbus_message_iter_next(&piter); /* flags */
+ dbus_message_iter_next(&piter); /* storage id */
+ dbus_message_iter_get_basic(&piter, &id);
+ dbus_message_iter_next(&aiter);
+
+ if (type == STORAGE_MMC && primary && devnode)
+ break;
+ }
+
+ if (devnode)
+ ret = id;
+ else
+ ret = -ENODEV;
+
+ dbus_message_unref(reply);
+ return ret;
+}
+
+static void mount_mmc_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+ struct mmc_contents *mmc_data = (struct mmc_contents*)data;
+ DBusError r_err;
+ int r, mmc_ret;
+
+ _D("mount_mmc_cb called");
+
+ if (!msg) {
+ _E("no message [%s:%s]", err->name, err->message);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ dbus_error_init(&r_err);
+ r = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &mmc_ret, DBUS_TYPE_INVALID);
+ if (!r) {
+ _E("no message [%s:%s]", r_err.name, r_err.message);
+ dbus_error_free(&r_err);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ _I("Mount State : %d", mmc_ret);
+
+exit:
+ (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+
+API int deviced_request_mount_mmc(struct mmc_contents *mmc_data)
+{
+ void (*mount_cb)(void*, DBusMessage*, DBusError*) = NULL;
+ void *data = NULL;
+ int ret;
+ int id;
+ char buf_id[32];
+ char *param[2];
+
+ if (mmc_data && mmc_data->mmc_cb) {
+ _I("Mount callback exists");
+ mount_cb = mount_mmc_cb;
+ data = mmc_data;
+ }
+
+ id = get_mmc_primary_id();
+ if (id < 0)
+ return id;
+
+ snprintf(buf_id, sizeof(buf_id), "%d", id);
+ param[0] = buf_id;
+ param[1] = "";
+ ret = dbus_method_async_with_reply(STORAGE_BUS_NAME, DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER, "Mount", "is", param,
+ mount_cb, -1, data);
+
+ _I("Mount Request %s", ret == 0 ? "Success" : "Failed");
+
+ return ret;
+}
+
+static void unmount_mmc_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+ struct mmc_contents *mmc_data = (struct mmc_contents*)data;
+ DBusError r_err;
+ int r, mmc_ret;
+
+ _D("unmount_mmc_cb called");
+
+ if (!msg) {
+ _E("no message [%s:%s]", err->name, err->message);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ dbus_error_init(&r_err);
+ r = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &mmc_ret, DBUS_TYPE_INVALID);
+ if (!r) {
+ _E("no message [%s:%s]", r_err.name, r_err.message);
+ dbus_error_free(&r_err);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ _I("Unmount State : %d", mmc_ret);
+
+exit:
+ (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+
+API int deviced_request_unmount_mmc(struct mmc_contents *mmc_data, int option)
+{
+ void (*unmount_cb)(void*, DBusMessage*, DBusError*) = NULL;
+ void *data = NULL;
+ char buf_opt[32];
+ char buf_id[32];
+ int ret;
+ int id;
+ char *param[2];
+
+ if (option < 0 || option > 1)
+ return -EINVAL;
+
+ if (mmc_data && mmc_data->mmc_cb) {
+ _I("Mount callback exists");
+ unmount_cb = unmount_mmc_cb;
+ data = mmc_data;
+ }
+
+ id = get_mmc_primary_id();
+ if (id < 0)
+ return id;
+
+ snprintf(buf_id, sizeof(buf_id), "%d", id);
+ param[0] = buf_id;
+ snprintf(buf_opt, sizeof(buf_opt), "%d", option);
+ param[1] = buf_opt;
+ ret = dbus_method_async_with_reply(STORAGE_BUS_NAME, DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER, "Unmount", "ii", param,
+ unmount_cb, -1, data);
+
+ _I("Unmount Request %s", ret == 0 ? "Success" : "Failed");
+
+ return ret;
+}
+
+static void format_mmc_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+ struct mmc_contents *mmc_data = (struct mmc_contents*)data;
+ DBusError r_err;
+ int r, mmc_ret;
+
+ _D("format_mmc_cb called");
+
+ if (!msg) {
+ _E("no message [%s:%s]", err->name, err->message);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ dbus_error_init(&r_err);
+ r = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &mmc_ret, DBUS_TYPE_INVALID);
+ if (!r) {
+ _E("no message [%s:%s]", r_err.name, r_err.message);
+ dbus_error_free(&r_err);
+ mmc_ret = -EBADMSG;
+ goto exit;
+ }
+
+ _I("Format State : %d", mmc_ret);
+
+exit:
+ (mmc_data->mmc_cb)(mmc_ret, mmc_data->user_data);
+}
+
+API int deviced_request_format_mmc(struct mmc_contents *mmc_data)
+{
+ return deviced_format_mmc(mmc_data, 1);
+}
+
+API int deviced_format_mmc(struct mmc_contents *mmc_data, int option)
+{
+ void (*format_cb)(void*, DBusMessage*, DBusError*) = NULL;
+ void *data = NULL;
+ char buf_opt[32];
+ char buf_id[32];
+ int ret;
+ int id;
+ char *param[2];
+
+ if (option < 0 || option > 1)
+ return -EINVAL;
+
+ if (mmc_data && mmc_data->mmc_cb) {
+ _I("Mount callback exists");
+ format_cb = format_mmc_cb;
+ data = mmc_data;
+ }
+
+ id = get_mmc_primary_id();
+ if (id < 0)
+ return id;
+
+ snprintf(buf_id, sizeof(buf_id), "%d", id);
+ param[0] = buf_id;
+ snprintf(buf_opt, sizeof(buf_opt), "%d", option);
+ param[1] = buf_opt;
+ ret = dbus_method_async_with_reply(STORAGE_BUS_NAME, DEVICED_PATH_BLOCK_MANAGER,
+ DEVICED_INTERFACE_BLOCK_MANAGER, "Format", "ii", param,
+ format_cb, FORMAT_TIMEOUT, data);
+
+ _I("Format Request %s", ret == 0 ? "Success" : "Failed");
+
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <sys/stat.h>
+#include <vconf.h>
+#include <errno.h>
+#include <storage.h>
+
+#include "log.h"
+#include "common.h"
+#include "dd-deviced.h"
+#include "dd-storage.h"
+
+struct storage_info {
+ storage_type_e type;
+ char *path;
+ size_t len;
+};
+
+static bool storage_get_info(int storage_id, storage_type_e type,
+ storage_state_e state, const char *path, void *user_data)
+{
+ struct storage_info *info;
+
+ if (storage_id < 0 || !path || !user_data)
+ return true;
+
+ info = (struct storage_info *)user_data;
+ if (type != info->type)
+ return true;
+
+ if (state != STORAGE_STATE_MOUNTED &&
+ state != STORAGE_STATE_MOUNTED_READ_ONLY)
+ return true;
+
+ snprintf(info->path, info->len, "%s", path);
+ return false;
+}
+
+API int storage_get_path(int type, char *path, int size)
+{
+ static char int_path[256] = { 0, };
+ static char ext_path[256] = { 0, };
+ int ret;
+ struct storage_info info;
+
+ if (!path || size <= 0)
+ return -1;
+
+ switch (type) {
+ case STORAGE_DEFAULT:
+ case STORAGE_INTERNAL:
+ if (strlen(int_path) > 0) {
+ snprintf(path, size, "%s", int_path);
+ return 0;
+ }
+ info.path = int_path;
+ info.len = sizeof(int_path);
+ info.type = type;
+ break;
+ case STORAGE_EXTERNAL:
+ if (strlen(ext_path) > 0) {
+ snprintf(path, size, "%s", ext_path);
+ return 0;
+ }
+ info.path = ext_path;
+ info.len = sizeof(ext_path);
+ info.type = type;
+ break;
+ default:
+ _E("Invalid type (%d)", type);
+ return -1;
+ }
+
+ ret = storage_foreach_device_supported(storage_get_info, &info);
+ if (ret != STORAGE_ERROR_NONE) {
+ _E("Failed to get storage information (%d)", ret);
+ return -1;
+ }
+
+ if (strlen(info.path) == 0)
+ return -1;
+
+ snprintf(path, size, "%s", info.path);
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <E_DBus.h>
+
+#include "log.h"
+#include "common.h"
+#include "dbus.h"
+#include "dd-usbhost.h"
+#include "core/list.h"
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+#define METHOD_OPEN_DEVICE "OpenDevice"
+#define METHOD_REQUEST_STORAGE_INFO_ALL "StorageInfoAll"
+#define METHOD_REQUEST_STORAGE_MOUNT "StorageMount"
+#define METHOD_REQUEST_STORAGE_UNMOUNT "StorageUnmount"
+#define METHOD_REQUEST_STORAGE_FORMAT "StorageFormat"
+#define SIGNAL_NAME_USB_STORAGE_CHANGED "usb_storage_changed"
+#define SIGNAL_NAME_USB_DEVICE_CHANGED "ChangedDevice"
+#define RETRY_MAX 5
+
+union action {
+ void (*storage)(char *type, char *path, int mount, void *param);
+ void (*device)(struct usbhost_device *device, int state, void *data);
+};
+
+struct signal_handler {
+ const char *name;
+ E_DBus_Signal_Handler *handler;
+ union action action;
+ void *data;
+};
+
+static dd_list *handlers;
+
+static E_DBus_Connection *conn = NULL;
+
+static int register_edbus_signal_handler(const char *path, const char *interface,
+ const char *name, E_DBus_Signal_Cb cb,
+ union action action,
+ void *data)
+{
+ int ret;
+ struct signal_handler *handler = NULL;
+
+ if (!conn) {
+ _E("Use init_usbhost_signal() first to use this function");
+ ret = -1;
+ goto out;
+ }
+
+ handler = calloc(1, sizeof(*handler));
+ if (!handler) {
+ _E("No memory");
+ ret = -1;
+ goto out;
+ }
+ handler->name = name;
+ handler->handler = e_dbus_signal_handler_add(conn, NULL, path,
+ interface, name, cb, NULL);
+ if (!(handler->handler)) {
+ _E("fail to add edbus handler");
+ ret = -1;
+ goto out;
+ }
+
+ handler->action = action;
+ handler->data = data;
+
+ DD_LIST_APPEND(handlers, handler);
+
+ return 0;
+
+out:
+ free(handler);
+ return ret;
+}
+
+static void storage_signal_handler(void *data, DBusMessage *msg)
+{
+ char *type, *path;
+ int mount;
+ DBusError err;
+ dd_list *elem;
+ struct signal_handler *handler;
+
+ if (dbus_message_is_signal(msg, DEVICED_INTERFACE_USBHOST, SIGNAL_NAME_USB_STORAGE_CHANGED) == 0) {
+ _E("The signal is not for storage changed");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INT32, &mount,
+ DBUS_TYPE_INVALID) == 0) {
+ _E("Failed to get storage info");
+ return;
+ }
+
+ DD_LIST_FOREACH(handlers, elem, handler) {
+ if (strcmp(handler->name, SIGNAL_NAME_USB_STORAGE_CHANGED))
+ continue;
+
+ if (handler->action.storage)
+ handler->action.storage(type, path, mount, handler->data);
+ }
+}
+
+static void device_signal_handler(void *data, DBusMessage *msg)
+{
+ char *path;
+ struct usbhost_device device;
+ int state;
+ DBusError err;
+ struct signal_handler *handler;
+ dd_list *element;
+
+ if (dbus_message_is_signal(msg, DEVICED_INTERFACE_USBHOST, SIGNAL_NAME_USB_DEVICE_CHANGED) == 0) {
+ _E("The signal is not ChangedDevice");
+ return;
+ }
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_INT32, &state,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INT32, &device.baseclass,
+ DBUS_TYPE_INT32, &device.subclass,
+ DBUS_TYPE_INT32, &device.protocol,
+ DBUS_TYPE_INT32, &device.vendorid,
+ DBUS_TYPE_INT32, &device.productid,
+ DBUS_TYPE_STRING, &device.manufacturer,
+ DBUS_TYPE_STRING, &device.product,
+ DBUS_TYPE_STRING, &device.serial,
+ DBUS_TYPE_INVALID) == 0) {
+ _E("Failed to get device info");
+ return;
+ }
+
+ strncpy(device.devpath, path, PATH_MAX);
+
+ DD_LIST_FOREACH(handlers, element, handler) {
+ if (strcmp(handler->name, SIGNAL_NAME_USB_DEVICE_CHANGED))
+ continue;
+
+ if (handler->action.device)
+ handler->action.device(&device, state, handler->data);
+ }
+}
+
+API int init_usbhost_signal(void)
+{
+ int retry;
+
+ if (conn)
+ return 0;
+
+ retry = 0;
+ do {
+ if (e_dbus_init() > 0)
+ break;
+ if (retry >= RETRY_MAX)
+ return -1;
+ } while (retry++ < RETRY_MAX);
+
+ conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+ if (!conn) {
+ _E("Failed to get edbus bus");
+ e_dbus_shutdown();
+ return -1;
+ }
+
+ return 0;
+}
+
+API void deinit_usbhost_signal(void)
+{
+ dd_list *n, *next;
+ struct signal_handler *handler;
+
+ if (!conn)
+ return;
+
+ DD_LIST_FOREACH_SAFE(handlers, n, next, handler) {
+ DD_LIST_REMOVE(handlers, handler);
+ if (handler->handler) {
+ e_dbus_signal_handler_del(conn, handler->handler);
+ handler->handler = NULL;
+ }
+
+ free(handler);
+ }
+
+ e_dbus_connection_close(conn);
+ conn = NULL;
+
+ e_dbus_shutdown();
+}
+
+API int request_usb_storage_info(void)
+{
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST, METHOD_REQUEST_STORAGE_INFO_ALL, NULL, NULL);
+}
+
+API int register_usb_storage_change_handler(
+ void (*storage_changed)(char *type, char *path, int mount, void *param),
+ void *data)
+{
+ union action action;
+ if (!storage_changed)
+ return -EINVAL;
+
+ action.storage = storage_changed;
+ return register_edbus_signal_handler(DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST,
+ SIGNAL_NAME_USB_STORAGE_CHANGED,
+ storage_signal_handler,
+ action,
+ data);
+}
+
+API int register_usb_device_change_handler(
+ void (*device_changed)(struct usbhost_device *device, int state, void *data),
+ void *data)
+{
+ union action action;
+ if (!device_changed)
+ return -EINVAL;
+
+ action.device = device_changed;
+ return register_edbus_signal_handler(DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST,
+ SIGNAL_NAME_USB_DEVICE_CHANGED,
+ device_signal_handler,
+ action,
+ data);
+}
+
+API int unregister_usb_storage_change_handler(void)
+{
+ dd_list *n, *next;
+ struct signal_handler *handler;
+
+ DD_LIST_FOREACH_SAFE(handlers, n, next, handler) {
+ if (strcmp(handler->name, SIGNAL_NAME_USB_STORAGE_CHANGED))
+ continue;
+ if (handler->handler == NULL)
+ continue;
+
+ e_dbus_signal_handler_del(conn, handler->handler);
+ DD_LIST_REMOVE(handlers, handler);
+ free(handler);
+ }
+
+ return 0;
+}
+
+API int unregister_usb_device_change_handler(
+ void (*device_changed)(struct usbhost_device *device, int state, void *data))
+{
+ dd_list *n, *next;
+ struct signal_handler *handler;
+
+ DD_LIST_FOREACH_SAFE(handlers, n, next, handler) {
+ if (strcmp(handler->name, SIGNAL_NAME_USB_DEVICE_CHANGED))
+ continue;
+ if (handler->handler == NULL)
+ continue;
+ if (handler->action.device != device_changed)
+ continue;
+
+ e_dbus_signal_handler_del(conn, handler->handler);
+ DD_LIST_REMOVE(handlers, handler);
+ free(handler);
+ }
+
+ return -1;
+}
+
+API int mount_usb_storage(char *path)
+{
+ char *param[1];
+
+ if (!path)
+ return -1;
+
+ param[0] = path;
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST, METHOD_REQUEST_STORAGE_MOUNT, "s", param);
+}
+
+API int unmount_usb_storage(char *path)
+{
+ char *param[1];
+
+ if (!path)
+ return -1;
+
+ param[0] = path;
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST, METHOD_REQUEST_STORAGE_UNMOUNT, "s", param);
+}
+
+API int format_usb_storage(char *path)
+{
+ char *param[1];
+
+ if (!path)
+ return -1;
+
+ param[0] = path;
+ return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST, METHOD_REQUEST_STORAGE_FORMAT, "s", param);
+}
+
+API int open_usb_device(char *path, int *fd)
+{
+ DBusMessage *reply;
+ DBusError err;
+ int ret, rfd;
+ dbus_bool_t result;
+
+ if (!fd || !path)
+ return -EINVAL;
+
+ dbus_error_init(&err);
+
+ reply = dbus_method_sync_with_reply(DEVICED_BUS_NAME,
+ DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST,
+ METHOD_OPEN_DEVICE,
+ "s", &path);
+
+ if (!reply) {
+ _E("Unable to open USB device");
+ return -1;
+ }
+
+ result = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &ret, DBUS_TYPE_UNIX_FD, &rfd, DBUS_TYPE_INVALID);
+ if (!result) {
+ _E("Failed to get arguments: %s", err.message);
+ return -1;
+ }
+
+ if (ret >= 0)
+ *fd = rfd;
+
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <unistd.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "core/log.h"
+#include "core/device-notifier.h"
+#include "core/common.h"
+#include "display/poll.h"
+#include "core/edbus-handler.h"
+#include "shared/deviced-systemd.h"
+
+#define SIGNAL_BOOTING_DONE "BootingDone"
+
+#define SYSTEMD_DBUS_SIGNAL_STARTUP_FINISHED "StartupFinished"
+#define SYSTEMD_DBUS_METHOD_SYSTEM_STATE "SystemState"
+#define SYSTEMD_STATE_RUNNING "running"
+#define SYSTEMD_STATE_DEGRADED "degraded"
+
+int booting_finished(void)
+{
+ char *state;
+ int ret;
+ size_t len;
+
+ ret = deviced_systemd_get_manager_property_as_string(
+ SYSTEMD_DBUS_IFACE_MANAGER,
+ SYSTEMD_DBUS_METHOD_SYSTEM_STATE,
+ &state);
+ if (ret < 0) {
+ _E("Failed to get System State (%d)", ret);
+ return ret;
+ }
+
+ _I("System State: (%s)", state);
+
+ len = strlen(state) + 1;
+ if (!strncmp(state, SYSTEMD_STATE_RUNNING, len) ||
+ !strncmp(state, SYSTEMD_STATE_DEGRADED, len))
+ ret = 1;
+ else
+ ret = 0;
+
+ free(state);
+
+ return ret;
+}
+
+
+static void boot_complete_send_system_event(void)
+{
+ bundle *b;
+ const char *str = EVT_VAL_BOOT_COMPLETED_TRUE;
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_BOOT_COMPLETED, str);
+ eventsystem_send_system_event(SYS_EVENT_BOOT_COMPLETED, b);
+ bundle_free(b);
+}
+
+
+void remove_booting_done_handler(void *data)
+{
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ SYSTEMD_DBUS_IFACE_MANAGER,
+ SYSTEMD_DBUS_SIGNAL_STARTUP_FINISHED);
+}
+
+static void booting_done_received(void *data, DBusMessage *msg)
+{
+ static int done = 0;
+
+ if (!dbus_message_is_signal(msg, SYSTEMD_DBUS_IFACE_MANAGER,
+ SYSTEMD_DBUS_SIGNAL_STARTUP_FINISHED)) {
+ _E("there is no StartupFinished signal");
+ return;
+ }
+
+ if (done)
+ return;
+
+ done = booting_finished();
+ if (done != TRUE) {
+ _E("Booting is not finished");
+ return;
+ }
+
+ remove_booting_done_handler(NULL);
+
+ _I("real booting done, unlock LCD_OFF");
+ pm_unlock_internal(INTERNAL_LOCK_BOOTING, LCD_OFF, PM_SLEEP_MARGIN);
+
+ _I("signal booting done");
+ broadcast_edbus_signal(DEVICED_PATH_CORE,
+ DEVICED_INTERFACE_CORE,
+ SIGNAL_BOOTING_DONE,
+ NULL, NULL);
+
+ boot_complete_send_system_event();
+
+ device_notify(DEVICE_NOTIFIER_BOOTING_DONE, &done);
+}
+
+void add_booting_done_handler(void *data)
+{
+ /* Normal booting done: System Session is loaded completely */
+ register_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ SYSTEMD_DBUS_IFACE_MANAGER,
+ SYSTEMD_DBUS_SIGNAL_STARTUP_FINISHED,
+ booting_done_received);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 __DEVICED_BOOT_H__
+#define __DEVICED_BOOT_H__
+
+int booting_finished(void);
+void add_booting_done_handler(void *data);
+void remove_booting_done_handler(void *data);
+
+#endif /* __DEVICED_BOOT_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+#include <time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <vconf.h>
+#include <assert.h>
+#include <limits.h>
+#include <time.h>
+#include <vconf.h>
+#include <fcntl.h>
+#include <sys/reboot.h>
+#include <sys/time.h>
+#include <mntent.h>
+#include <sys/mount.h>
+#include <device-node.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "dd-deviced.h"
+#include "core/log.h"
+#include "core/launch.h"
+#include "core/device-notifier.h"
+#include "core/device-idler.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/launch.h"
+#include "display/poll.h"
+#include "display/setting.h"
+#include "core/edbus-handler.h"
+#include "display/core.h"
+#include "power-handler.h"
+#include "apps/apps.h"
+#include "shared/deviced-systemd.h"
+#include "boot.h"
+
+#define POWEROFF_DURATION 2
+#define MAX_RETRY 2
+
+#define SIGNAL_POWEROFF_STATE "ChangeState"
+
+#define UMOUNT_RW_PATH "/opt/usr"
+
+static struct timeval tv_start_poweroff;
+
+static const struct device_ops *telephony = NULL;
+
+static void telephony_init(void)
+{
+ FIND_DEVICE_VOID(telephony, "telephony");
+ _I("telephony (%d)", telephony);
+}
+
+static void telephony_start(void)
+{
+ telephony_init();
+ device_start(telephony);
+}
+
+static void telephony_stop(void)
+{
+ device_stop(telephony);
+}
+
+static int telephony_exit(void *data)
+{
+ int ret;
+
+ ret = device_exit(telephony, data);
+ return ret;
+}
+
+static int app_privileged(pid_t pid)
+{
+ char attr[64];
+ int ret;
+ size_t len;
+
+ ret = get_privilege(pid, attr, sizeof(attr));
+ if (ret < 0) {
+ _E("Failed to get privilege of PID(%d)", pid);
+ return 0;
+ }
+
+ len = strlen(attr);
+
+ if (!strncmp("System::Privileged", attr, len + 1))
+ return 1;
+
+ if (strstr(attr, "User::Pkg::") == attr)
+ return 1;
+
+ return 0;
+}
+
+static void poweroff_stop_systemd_service(void)
+{
+ _D("systemd service stop");
+ umount2("/sys/fs/cgroup", MNT_FORCE |MNT_DETACH);
+}
+
+static int stop_systemd_journald(void)
+{
+ int ret;
+
+ ret = deviced_systemd_stop_unit("systemd-journald.socket");
+ if (ret < 0) {
+ _E("failed to stop 'systemd-journald.socket'");
+ return ret;
+ }
+
+ ret |= deviced_systemd_stop_unit("systemd-journald.service");
+ if (ret < 0) {
+ _E("failed to stop 'systemd-journald.service'");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* umount usr data partition */
+static void unmount_rw_partition()
+{
+ int retry = 0, r;
+ struct timespec time = {0,};
+ sync();
+
+ if (!mount_check(UMOUNT_RW_PATH))
+ return;
+ while (1) {
+ switch (retry++) {
+ case 0:
+ /* Second, kill app with SIGTERM */
+ _I("Kill app with SIGTERM");
+ terminate_process(UMOUNT_RW_PATH, false);
+ time.tv_nsec = 700 * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+ break;
+ case 1:
+ /* Last time, kill app with SIGKILL */
+ _I("Kill app with SIGKILL");
+ terminate_process(UMOUNT_RW_PATH, true);
+ time.tv_nsec = 300 * NANO_SECOND_MULTIPLIER;
+ nanosleep(&time, NULL);
+ sleep(1);
+ break;
+ default:
+ r = umount2(UMOUNT_RW_PATH, 0);
+ if (r != 0)
+ _I("Failed to unmount %s(%d)", UMOUNT_RW_PATH, r);
+ else
+ _I("%s unmounted successfully", UMOUNT_RW_PATH);
+ return;
+ }
+
+ r = umount2(UMOUNT_RW_PATH, 0);
+ if (r == 0) {
+ _I("%s unmounted successfully", UMOUNT_RW_PATH);
+ return;
+ }
+ }
+}
+
+static void powerdown(void)
+{
+ static int wait = 0;
+ static int power_off = 0;
+ struct timeval now;
+ int poweroff_duration = POWEROFF_DURATION;
+ int check_duration = 0;
+ char *buf;
+
+ if (power_off == 1) {
+ _E("during power off");
+ return;
+ }
+
+ stop_systemd_journald();
+
+ /* if this fails, that's OK */
+ power_off = 1;
+ telephony_stop();
+ sync();
+
+ buf = getenv("PWROFF_DUR");
+ if (buf != NULL && strlen(buf) < 1024)
+ poweroff_duration = atoi(buf);
+ if (poweroff_duration < 0 || poweroff_duration > 60)
+ poweroff_duration = POWEROFF_DURATION;
+ gettimeofday(&now, NULL);
+ check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
+ while (check_duration < poweroff_duration) {
+ if (wait == 0) {
+ _I("wait poweroff %d %d", check_duration, poweroff_duration);
+ wait = 1;
+ }
+ usleep(100000);
+ gettimeofday(&now, NULL);
+ check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
+ if (check_duration < 0)
+ break;
+ }
+
+ poweroff_stop_systemd_service();
+
+#ifndef EMULATOR
+ unmount_rw_partition();
+#endif
+}
+
+static void powerdown_ap(void *data)
+{
+ _I("Power off");
+ powerdown();
+ reboot(RB_POWER_OFF);
+}
+
+static void restart_ap(void *data)
+{
+ _I("Restart");
+ powerdown();
+ reboot(RB_AUTOBOOT);
+}
+
+static void system_shutdown_send_system_event(void)
+{
+ bundle *b;
+ const char *str = EVT_VAL_SYSTEM_SHUTDOWN_TRUE;
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_SYSTEM_SHUTDOWN, str);
+ eventsystem_send_system_event(SYS_EVENT_SYSTEM_SHUTDOWN, b);
+ bundle_free(b);
+}
+
+static void poweroff_start_animation(void)
+{
+ int ret;
+
+ ret = deviced_systemd_start_unit("shutdown-animation.service");
+ if (ret < 0)
+ _E("Failed to start shutdown animation");
+
+ gettimeofday(&tv_start_poweroff, NULL);
+}
+
+static int poweroff(void)
+{
+ int ret;
+ static const struct device_ops *display_device_ops = NULL;
+
+ poweroff_start_animation();
+ telephony_start();
+
+ FIND_DEVICE_INT(display_device_ops, "display");
+
+ pm_change_internal(getpid(), LCD_NORMAL);
+ display_device_ops->exit(NULL);
+ sync();
+
+ ret = telephony_exit(POWER_POWEROFF);
+
+ if (ret < 0) {
+ powerdown_ap(NULL);
+ return 0;
+ }
+ return ret;
+}
+
+static int pwroff_popup(void)
+{
+ return launch_system_app(APP_POWERKEY,
+ 2, APP_KEY_TYPE, APP_POWERKEY);
+}
+
+static int power_reboot(void)
+{
+ int ret;
+ const struct device_ops *display_device_ops = NULL;
+
+ poweroff_start_animation();
+ telephony_start();
+
+ FIND_DEVICE_INT(display_device_ops, "display");
+
+ pm_change_internal(getpid(), LCD_NORMAL);
+ display_device_ops->exit(NULL);
+ sync();
+
+ ret = telephony_exit(POWER_REBOOT);
+ if (ret < 0) {
+ restart_ap(NULL);
+ return 0;
+ }
+ return ret;
+}
+
+static int booting_done(void *data)
+{
+ static int done = 0;
+
+ if (data == NULL)
+ goto out;
+
+ done = *(int*)data;
+ telephony_init();
+out:
+ return done;
+}
+
+static void poweroff_send_broadcast(int status)
+{
+ static int old = 0;
+ char *arr[1];
+ char str_status[32];
+
+ if (old == status)
+ return;
+
+ _D("broadcast poweroff %d", status);
+
+ old = status;
+ snprintf(str_status, sizeof(str_status), "%d", status);
+ arr[0] = str_status;
+
+ /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangeState signal for POWER_OFF_DIRECT and POWER_OFF_RESTART */
+ broadcast_edbus_signal(DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF,
+ SIGNAL_POWEROFF_STATE, "i", arr);
+}
+
+static void poweroff_idler_cb(void *data)
+{
+ enum poweroff_type val = (long)data;
+
+ telephony_start();
+
+ pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
+
+ if (val == POWER_OFF_DIRECT || val == POWER_OFF_RESTART) {
+ /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangeState signal for POWER_OFF_DIRECT and POWER_OFF_RESTART */
+ poweroff_send_broadcast(val);
+ system_shutdown_send_system_event();
+ device_notify(DEVICE_NOTIFIER_POWEROFF, &val);
+ }
+
+ /* TODO for notify. will be removed asap. */
+ vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, val);
+
+ switch (val) {
+ case POWER_OFF_DIRECT:
+ poweroff();
+ break;
+ case POWER_OFF_POPUP:
+ pwroff_popup();
+ break;
+ case POWER_OFF_RESTART:
+ power_reboot();
+ break;
+ default:
+ return;
+ }
+
+ if (update_pm_setting)
+ update_pm_setting(SETTING_POWEROFF, val);
+}
+
+static int power_execute_pid(void *data, pid_t pid)
+{
+ int ret;
+ long val;
+ char *str = (char *)data;
+
+ if (!data) {
+ _E("Invalid parameter : data(NULL)");
+ return -EINVAL;
+ }
+
+ if (strncmp(POWER_POWEROFF, str, POWER_POWEROFF_LEN) == 0)
+ val = POWER_OFF_DIRECT;
+ else if (strncmp(PWROFF_POPUP, str, PWROFF_POPUP_LEN) == 0)
+ val = POWER_OFF_POPUP;
+ else if (strncmp(POWER_REBOOT, str, POWER_REBOOT_LEN) == 0) {
+ if (!app_privileged(pid)) {
+ _E("PID(%d) does not have the permission for reboot", pid);
+ return -EPERM;
+ }
+ val = POWER_OFF_RESTART;
+ } else {
+ _E("Invalid parameter : data(%s)", str);
+ return -EINVAL;
+ }
+
+ ret = add_idle_request(poweroff_idler_cb, (void *)val);
+ if (ret < 0) {
+ _E("fail to add poweroff idle request : %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int power_execute(void *data)
+{
+ return power_execute_pid(data, getpid());
+}
+
+static DBusMessage *dbus_power_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret;
+ int argc;
+ char *type_str;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ _I("PID(%d) requests %s", pid, type_str);
+ ret = power_execute_pid(type_str, pid);
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static DBusMessage *request_reboot(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *str;
+ int ret;
+ pid_t pid;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+
+ _I("PID(%d) requests reboot with command : %s", pid, str);
+ ret = power_execute_pid(POWER_REBOOT, pid);
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { POWER_REBOOT, "si", "i", dbus_power_handler },
+ /* Public API device_power_reboot() calls this dbus method. */
+ { "Reboot", "s", "i", request_reboot },
+ /* Add methods here */
+};
+
+static void power_init(void *data)
+{
+ int ret;
+
+ /* init dbus interface */
+ ret = register_edbus_method(DEVICED_PATH_POWER,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+
+ add_booting_done_handler(NULL);
+
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+}
+
+static const struct device_ops power_device_ops = {
+ .name = POWER_OPS_NAME,
+ .init = power_init,
+ .execute = power_execute,
+};
+
+DEVICE_OPS_REGISTER(&power_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __POWER_HANDLE_H__
+#define __POWER_HANDLE_H__
+
+#define POWER_OPS_NAME "power"
+
+#define POWER_POWEROFF "poweroff"
+#define POWER_POWEROFF_LEN 8
+#define POWER_REBOOT "reboot"
+#define POWER_REBOOT_LEN 6
+#define PWROFF_POPUP "pwroff-popup"
+#define PWROFF_POPUP_LEN 12
+
+enum poweroff_type {
+ POWER_OFF_NONE = 0,
+ POWER_OFF_POPUP,
+ POWER_OFF_DIRECT,
+ POWER_OFF_RESTART,
+};
+
+#endif /* __POWER_HANDLE_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <fcntl.h>
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+#include "core/common.h"
+
+#define METHOD_GET_REVISION "GetRevision"
+#define PATH_NAME "/proc/cpuinfo"
+#define REVISION_NAME "Revision"
+#define TOK_DELIMITER ":"
+#define END_DELIMITER " \n"
+
+#define CONVERT_TYPE 10
+#define REVISION_SIZE 4
+#define FILE_BUFF_MAX 1024
+#define NOT_INITIALIZED (-1)
+
+static int read_from_file(const char *path, char *buf, size_t size)
+{
+ int fd;
+ size_t count;
+
+ if (!path)
+ return -1;
+
+ fd = open(path, O_RDONLY, 0);
+ if (fd == -1) {
+ _E("Could not open '%s'", path);
+ return -1;
+ }
+
+ count = read(fd, buf, size);
+
+ if ((int)count != -1 && count > 0) {
+ count = (count < size) ? count : size - 1;
+ while (count > 0 && buf[count - 1] == '\n')
+ count--;
+ buf[count] = '\0';
+ } else {
+ buf[0] = '\0';
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static int get_revision(char *rev, int len)
+{
+ char buf[FILE_BUFF_MAX];
+ char *tag;
+ char *start, *ptr;
+ char *saveptr;
+ long rev_num;
+ const int radix = 16;
+
+ if (rev == NULL || len <= 0) {
+ _E("Invalid argument !\n");
+ return -1;
+ }
+
+ if (read_from_file(PATH_NAME, buf, FILE_BUFF_MAX) < 0) {
+ _E("fail to read %s\n", PATH_NAME);
+ return -1;
+ }
+
+ tag = strstr(buf, REVISION_NAME);
+ if (tag == NULL) {
+ _E("cannot find Hardware in %s\n", PATH_NAME);
+ return -1;
+ }
+
+ start = strstr(tag, TOK_DELIMITER);
+ if (start == NULL) {
+ _E("cannot find Hardware in %s\n", PATH_NAME);
+ return -1;
+ }
+
+ start++;
+ ptr = strtok_r(start, END_DELIMITER, &saveptr);
+ if (!ptr) {
+ _E("fail to extract tokens");
+ return -1;
+ }
+ ptr += strlen(ptr);
+ ptr -= 2;
+
+ memset(rev, 0x00, REVISION_SIZE);
+ rev_num = strtol(ptr, NULL, radix);
+ snprintf(rev, len, "%ld", rev_num);
+
+ return 0;
+}
+
+static DBusMessage *dbus_revision_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char rev[FILE_BUFF_MAX];
+ char *ptr;
+ static int ret = NOT_INITIALIZED;
+
+ if (ret != NOT_INITIALIZED)
+ goto out;
+ ret = get_revision(rev, sizeof(rev));
+ if (ret == 0)
+ ret = strtol(rev, &ptr, CONVERT_TYPE);
+out:
+ _D("rev : %d", ret);
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { METHOD_GET_REVISION, NULL, "i", dbus_revision_handler },
+};
+
+static void cpu_info_init(void *data)
+{
+ int ret;
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI, edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static const struct device_ops cpu_info_device_ops = {
+ .name = "cpu_info",
+ .init = cpu_info_init,
+};
+
+DEVICE_OPS_REGISTER(&cpu_info_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <unistd.h>
+//#include <dirent.h>
+//#include <sys/types.h>
+//#include <device-node.h>
+//#include <sys/un.h>
+//#include <stdarg.h>
+#include <errno.h>
+#include <vconf.h>
+//#include <fcntl.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/device-notifier.h"
+#include "core/edbus-handler.h"
+#include "shared/score-defines.h"
+
+#define OOMADJ_SET "oomadj_set"
+#define OOM_PMQOS_TIME 2000 /* ms */
+#define SIGNAL_PROC_STATUS "ProcStatus"
+
+enum proc_status_type {
+ PROC_STATUS_LAUNCH,
+ PROC_STATUS_RESUME,
+ PROC_STATUS_TERMINATE,
+ PROC_STATUS_FOREGROUND,
+ PROC_STATUS_BACKGROUND,
+};
+
+static void memcg_move_group(int pid, int oom_score_adj)
+{
+ char buf[100];
+ FILE *f;
+ int size;
+ char exe_name[PATH_MAX];
+
+ if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0) {
+ _E("fail to get process name(%d)", pid);
+ return;
+ }
+
+ _SD("memcg_move_group : %s, pid = %d", exe_name, pid);
+ if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED)
+ snprintf(buf, sizeof(buf), "/sys/fs/cgroup/memory/background/cgroup.procs");
+ else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED && oom_score_adj < OOMADJ_BACKGRD_LOCKED)
+ snprintf(buf, sizeof(buf), "/sys/fs/cgroup/memory/foreground/cgroup.procs");
+ else
+ return;
+
+ f = fopen(buf, "w");
+ if (f == NULL)
+ return;
+ size = snprintf(buf, sizeof(buf), "%d", pid);
+ if (fwrite(buf, size, 1, f) != 1)
+ _E("fwrite cgroup tasks : %d", pid);
+ fclose(f);
+}
+
+int set_oom_score_adj_action(int argc, char **argv)
+{
+ FILE *fp;
+ int pid = -1;
+ int new_oom_score_adj = 0;
+
+ if (argc < 2)
+ return -1;
+ pid = atoi(argv[0]);
+ new_oom_score_adj = atoi(argv[1]);
+ if (pid < 0 || new_oom_score_adj <= -20)
+ return -1;
+
+ _I("OOMADJ_SET : pid %d, new_oom_score_adj %d", pid, new_oom_score_adj);
+
+ fp = open_proc_oom_score_adj_file(pid, "w");
+ if (fp == NULL)
+ return -1;
+ if (new_oom_score_adj < OOMADJ_SU)
+ new_oom_score_adj = OOMADJ_SU;
+ fprintf(fp, "%d", new_oom_score_adj);
+ fclose(fp);
+
+ memcg_move_group(pid, new_oom_score_adj);
+ return 0;
+}
+
+static DBusMessage *dbus_oom_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret;
+ int argc;
+ char *type_str;
+ char *argv[2];
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv[0],
+ DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (strncmp(type_str, OOMADJ_SET, strlen(OOMADJ_SET)) == 0)
+ ret = set_oom_score_adj_action(argc, (char **)&argv);
+ else
+ ret = -EINVAL;
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static void proc_signal_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ int ret, type;
+ pid_t pid;
+
+ ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
+ SIGNAL_PROC_STATUS);
+ if (!ret) {
+ _E("It's not active signal!");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &type,
+ DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == 0) {
+ _E("There's no arguments!");
+ return;
+ }
+
+ if (type == PROC_STATUS_BACKGROUND)
+ device_notify(DEVICE_NOTIFIER_PROCESS_BACKGROUND, &pid);
+ if (type == PROC_STATUS_FOREGROUND)
+ device_notify(DEVICE_NOTIFIER_PROCESS_FOREGROUND, &pid);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { OOMADJ_SET, "siss", "i", dbus_oom_handler },
+};
+
+static void proc_change_lowmemory(keynode_t *key, void *data)
+{
+ int state = 0;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &state))
+ return;
+
+ if (state == VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING)
+ device_notify(DEVICE_NOTIFIER_PMQOS_OOM, (void *)OOM_PMQOS_TIME);
+}
+
+static void process_init(void *data)
+{
+ int ret;
+
+ register_edbus_signal_handler(RESOURCED_PATH_PROCESS,
+ RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_STATUS, proc_signal_handler);
+
+ ret = register_edbus_method(DEVICED_PATH_PROCESS, edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+
+ vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY,
+ proc_change_lowmemory, NULL);
+}
+
+static const struct device_ops process_device_ops = {
+ .name = "process",
+ .init = process_init,
+};
+
+DEVICE_OPS_REGISTER(&process_device_ops)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+SET(SHARED_SRCS
+ dbus.c
+ deviced-systemd.c
+)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(libshared REQUIRED
+ gio-2.0
+ dlog
+ dbus-1)
+
+FOREACH(flag ${libshared_CFLAGS})
+ SET(SHARED_LIB_CFLAGS "${SHARED_LIB_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+ADD_LIBRARY(shared STATIC ${SHARED_SRCS})
+TARGET_LINK_LIBRARIES(shared ${libshared_LDFLAGS})
+SET_TARGET_PROPERTIES(shared PROPERTIES COMPILE_FLAGS "-fPIC")
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __DD_COMMON_H__
+#define __DD_COMMON_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef API
+#define API __attribute__ ((visibility("default")))
+#endif
+
+#ifndef DEPRECATED
+#define DEPRECATED __attribute__ ((deprecated))
+#endif
+
+#ifndef __CONSTRUCTOR__
+#define __CONSTRUCTOR__ __attribute__ ((constructor))
+#endif
+
+#ifndef __DESTRUCTOR__
+#define __DESTRUCTOR__ __attribute__ ((destructor))
+#endif
+
+#ifdef __cplusplus
+
+}
+#endif
+#endif /* __DD_COMMON_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "common.h"
+#include "log.h"
+#include "dbus.h"
+
+/* -1 is a default timeout value, it's converted to 25*1000 internally. */
+#define DBUS_REPLY_TIMEOUT (-1)
+
+struct pending_call_data {
+ dbus_pending_cb func;
+ void *data;
+};
+
+int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
+{
+ char *ch;
+ int i;
+ int int_type;
+ dbus_bool_t bool_type;
+ uint64_t int64_type;
+ DBusMessageIter arr;
+ struct dbus_byte *byte;
+
+ if (!sig || !param)
+ return 0;
+
+ for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
+ switch (*ch) {
+ case 'b':
+ bool_type = (atoi(param[i])) ? TRUE : FALSE;
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
+ break;
+ case 'i':
+ int_type = atoi(param[i]);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
+ break;
+ case 'u':
+ int_type = strtoul(param[i], NULL, 10);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
+ break;
+ case 't':
+ int64_type = atoll(param[i]);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
+ break;
+ case 's':
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, ¶m[i]);
+ break;
+ case 'a':
+ ++ch;
+ switch (*ch) {
+ case 'y':
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
+ byte = (struct dbus_byte *)param[i];
+ dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
+ dbus_message_iter_close_container(iter, &arr);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+DBusMessage *dbus_method_sync_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ int r;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return NULL;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return NULL;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ r = append_variant(&iter, sig, param);
+ if (r < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ r, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return NULL;
+ }
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ if (!reply) {
+ _E("dbus_connection_send error(No reply) %s %s:%s-%s",
+ dest, path, interface, method);
+ }
+
+ if (dbus_error_is_set(&err)) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ reply = NULL;
+ }
+
+ dbus_message_unref(msg);
+ return reply;
+}
+
+int dbus_method_sync(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ int ret, result;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ dbus_message_unref(msg);
+ if (!reply) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ECOMM;
+ }
+
+ ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
+ dbus_message_unref(reply);
+ if (!ret) {
+ _E("no message : [%s:%s] %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ENOMSG;
+ }
+
+ return result;
+}
+
+int dbus_method_sync_timeout(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[], int timeout)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ DBusError err;
+ int ret, result;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ dbus_message_unref(msg);
+ if (!reply) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ECOMM;
+ }
+
+ ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
+ dbus_message_unref(reply);
+ if (!ret) {
+ _E("no message : [%s:%s] %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ENOMSG;
+ }
+
+ return result;
+}
+
+int dbus_method_sync_pairs(const char *dest, const char *path,
+ const char *interface, const char *method,
+ int num, va_list args)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter aiter, piter;
+ DBusError err;
+ int ret, result, i;
+ char *key, *value;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
+
+ for (i = 0 ; i < num ; i = i + 2) {
+ key = va_arg(args, char *);
+ value = va_arg(args, char *);
+ _I("key(%s), value(%s)", key, value);
+ dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &piter);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &value);
+ dbus_message_iter_close_container(&aiter, &piter);
+ }
+
+ dbus_message_iter_close_container(&iter, &aiter);
+
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
+ dbus_message_unref(msg);
+ if (!reply) {
+ _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ECOMM;
+ }
+
+ ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
+ dbus_message_unref(reply);
+ if (!ret) {
+ _E("no message : [%s:%s] %s %s:%s-%s",
+ err.name, err.message, dest, path, interface, method);
+ dbus_error_free(&err);
+ return -ENOMSG;
+ }
+
+ return result;
+}
+
+int dbus_method_async(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ int ret;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d) %s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ ret = dbus_connection_send(conn, msg, NULL);
+ dbus_message_unref(msg);
+ if (ret != TRUE) {
+ _E("dbus_connection_send error(%s %s:%s-%s)",
+ dest, path, interface, method);
+ return -ECOMM;
+ }
+
+ return 0;
+}
+
+static void cb_pending(DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *msg;
+ DBusError err;
+ struct pending_call_data *data = user_data;
+ int ret;
+
+ ret = dbus_pending_call_get_completed(pending);
+ if (!ret) {
+ _I("dbus_pending_call_get_completed() fail");
+ dbus_pending_call_unref(pending);
+ return;
+ }
+
+ dbus_error_init(&err);
+ msg = dbus_pending_call_steal_reply(pending);
+ if (!msg) {
+ _E("no message : [%s:%s]", err.name, err.message);
+
+ if (data->func) {
+ dbus_set_error(&err, "org.tizen.system.deviced.NoReply",
+ "There was no reply to this method call");
+ data->func(data->data, NULL, &err);
+ dbus_error_free(&err);
+ }
+ return;
+ }
+
+ ret = dbus_set_error_from_message(&err, msg);
+ if (ret) {
+ _E("error msg : [%s:%s]", err.name, err.message);
+
+ if (data->func)
+ data->func(data->data, NULL, &err);
+ dbus_error_free(&err);
+ } else {
+ if (data->func)
+ data->func(data->data, msg, &err);
+ }
+
+ dbus_message_unref(msg);
+ dbus_pending_call_unref(pending);
+}
+
+int dbus_method_async_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[], dbus_pending_cb cb, int timeout, void *data)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ DBusPendingCall *pending = NULL;
+ struct pending_call_data *pdata;
+ int ret;
+
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn) {
+ _E("dbus_bus_get error");
+ return -EPERM;
+ }
+
+ msg = dbus_message_new_method_call(dest, path, interface, method);
+ if (!msg) {
+ _E("dbus_message_new_method_call(%s:%s-%s)",
+ path, interface, method);
+ return -EBADMSG;
+ }
+
+ dbus_message_iter_init_append(msg, &iter);
+ ret = append_variant(&iter, sig, param);
+ if (ret < 0) {
+ _E("append_variant error(%d)%s %s:%s-%s",
+ ret, dest, path, interface, method);
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
+ if (!ret) {
+ dbus_message_unref(msg);
+ _E("dbus_connection_send error(%s %s:%s-%s)",
+ dest, path, interface, method);
+ return -ECOMM;
+ }
+
+ dbus_message_unref(msg);
+
+ if (cb && pending) {
+ pdata = malloc(sizeof(struct pending_call_data));
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->func = cb;
+ pdata->data = data;
+
+ ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
+ if (!ret) {
+ free(pdata);
+ dbus_pending_call_cancel(pending);
+ return -ECOMM;
+ }
+ }
+
+ return 0;
+}
+
+int check_systemd_active(void)
+{
+ int ret = FALSE;
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter, sub;
+ const char *state;
+ char *pa[2];
+
+ pa[0] = "org.freedesktop.systemd1.Unit";
+ pa[1] = "ActiveState";
+
+ _I("%s %s", pa[0], pa[1]);
+
+ msg = dbus_method_sync_with_reply("org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1/unit/default_2etarget",
+ "org.freedesktop.DBus.Properties",
+ "Get", "ss", pa);
+ if (!msg)
+ return -EBADMSG;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_iter_init(msg, &iter) ||
+ dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ goto out;
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+ ret = -EBADMSG;
+ goto out;
+ }
+
+ dbus_message_iter_get_basic(&sub, &state);
+
+ if (strncmp(state, "active", 6) == 0)
+ ret = TRUE;
+out:
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+ return ret;
+}
+
+static void __CONSTRUCTOR__ dbus_init(void)
+{
+ dbus_threads_init_default();
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __DBUS_H__
+#define __DBUS_H__
+
+#include <dbus/dbus.h>
+#include <stdarg.h>
+
+/*
+ * Template
+ *
+#define XXX_BUS_NAME "org.tizen.system.XXX"
+#define XXX_OBJECT_PATH "/Org/Tizen/System/XXX"
+#define XXX_INTERFACE_NAME XXX_BUS_NAME
+#define XXX_PATH_YYY XXX_OBJECT_PATH"/YYY"
+#define XXX_INTERFACE_YYY XXX_INTERFACE_NAME".YYY"
+#define XXX_SIGNAL_ZZZ "ZZZ"
+#define XXX_METHOD_ZZZ "ZZZ"
+ */
+
+/*
+ * DBus daemon
+ */
+#define DBUS_BUS_NAME "org.freedesktop.DBus"
+#define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
+#define DBUS_INTERFACE_NAME DBUS_BUS_NAME
+
+/*
+ * Device daemon
+ */
+#define DEVICED_BUS_NAME "org.tizen.system.deviced"
+#define DEVICED_OBJECT_PATH "/Org/Tizen/System/DeviceD"
+#define DEVICED_INTERFACE_NAME DEVICED_BUS_NAME
+/* Core service: get/set device status operations about device */
+#define DEVICED_PATH_CORE DEVICED_OBJECT_PATH"/Core"
+#define DEVICED_INTERFACE_CORE DEVICED_INTERFACE_NAME".core"
+/* Display service: start/stop display(pm), get/set brightness operations about display */
+#define DEVICED_PATH_DISPLAY DEVICED_OBJECT_PATH"/Display"
+#define DEVICED_INTERFACE_DISPLAY DEVICED_INTERFACE_NAME".display"
+/* Pass service: start/stop pass operations about pass */
+#define DEVICED_PATH_PASS DEVICED_OBJECT_PATH"/Pass"
+#define DEVICED_INTERFACE_PASS DEVICED_INTERFACE_NAME".pass"
+/* Hall service: get hall status operations about hall */
+#define DEVICED_PATH_HALL DEVICED_OBJECT_PATH"/Hall"
+#define DEVICED_INTERFACE_HALL DEVICED_INTERFACE_NAME".hall"
+/* Power service: set resetkey disable operations about power */
+#define DEVICED_PATH_POWER DEVICED_OBJECT_PATH"/Power"
+#define DEVICED_INTERFACE_POWER DEVICED_INTERFACE_NAME".power"
+/* Storage service: get storage size operatioins about storage */
+#define DEVICED_PATH_STORAGE DEVICED_OBJECT_PATH"/Storage"
+#define DEVICED_INTERFACE_STORAGE DEVICED_INTERFACE_NAME".storage"
+/* ODE service: request ode popup result operatioins about storage */
+#define DEVICED_PATH_ODE DEVICED_OBJECT_PATH"/Ode"
+#define DEVICED_INTERFACE_ODE DEVICED_INTERFACE_NAME".ode"
+/* Lowmem service: get critical low status operations about Lowmem */
+#define DEVICED_PATH_LOWMEM DEVICED_OBJECT_PATH"/Lowmem"
+#define DEVICED_INTERFACE_LOWMEM DEVICED_INTERFACE_NAME".lowmem"
+/* Poweroff service: get power off status operations about Poweroff */
+#define DEVICED_PATH_POWEROFF DEVICED_OBJECT_PATH"/PowerOff"
+#define DEVICED_INTERFACE_POWEROFF DEVICED_INTERFACE_NAME".PowerOff"
+/* Led service: play/stop led operations about led */
+#define DEVICED_PATH_LED DEVICED_OBJECT_PATH"/Led"
+#define DEVICED_INTERFACE_LED DEVICED_INTERFACE_NAME".Led"
+/* Block service: manage block device */
+#define STORAGE_BUS_NAME "org.tizen.system.storage"
+#define STORAGE_OBJECT_PATH "/Org/Tizen/System/Storage"
+#define STORAGE_INTERFACE_NAME STORAGE_BUS_NAME
+#define DEVICED_PATH_BLOCK STORAGE_OBJECT_PATH"/Block"
+#define DEVICED_PATH_BLOCK_MANAGER DEVICED_PATH_BLOCK"/Manager"
+#define DEVICED_INTERFACE_BLOCK_MANAGER STORAGE_INTERFACE_NAME".BlockManager"
+/* MMC service: mount/unmount/format mmc operations about mmc */
+#define DEVICED_PATH_MMC DEVICED_OBJECT_PATH"/Mmc"
+#define DEVICED_INTERFACE_MMC DEVICED_INTERFACE_NAME".Mmc"
+/* Process service: operations about process */
+#define DEVICED_PATH_PROCESS DEVICED_OBJECT_PATH"/Process"
+#define DEVICED_INTERFACE_PROCESS DEVICED_INTERFACE_NAME".Process"
+/* Key service: operations about key */
+#define DEVICED_PATH_KEY DEVICED_OBJECT_PATH"/Key"
+#define DEVICED_INTERFACE_KEY DEVICED_INTERFACE_NAME".Key"
+/* USB client service: change usb connection mode */
+#define DEVICED_PATH_USB DEVICED_OBJECT_PATH"/Usb"
+#define DEVICED_INTERFACE_USB DEVICED_INTERFACE_NAME".Usb"
+/* USB start/stop service: operations about usb start/stop */
+#define DEVICED_PATH_USB_CONTROL DEVICED_OBJECT_PATH"/UsbControl"
+#define DEVICED_INTERFACE_USB_CONTROL DEVICED_INTERFACE_NAME".UsbControl"
+/* USB host service: operations about usb start/stop */
+#define DEVICED_PATH_USBHOST DEVICED_OBJECT_PATH"/Usbhost"
+#define DEVICED_INTERFACE_USBHOST DEVICED_INTERFACE_NAME".Usbhost"
+/* Cpu service: operations about cpu */
+#define DEVICED_PATH_CPU DEVICED_OBJECT_PATH"/Cpu"
+#define DEVICED_INTERFACE_CPU DEVICED_INTERFACE_NAME".Cpu"
+/* PmQos service: operations about pmqos */
+#define DEVICED_PATH_PMQOS DEVICED_OBJECT_PATH"/PmQos"
+#define DEVICED_INTERFACE_PMQOS DEVICED_INTERFACE_NAME".PmQos"
+/* Sysnoti service */
+#define DEVICED_PATH_SYSNOTI DEVICED_OBJECT_PATH"/SysNoti"
+#define DEVICED_INTERFACE_SYSNOTI DEVICED_INTERFACE_NAME".SysNoti"
+/* ExtCon service */
+#define DEVICED_PATH_EXTCON DEVICED_OBJECT_PATH"/ExtCon"
+#define DEVICED_INTERFACE_EXTCON DEVICED_INTERFACE_NAME".ExtCon"
+/* Battery service */
+#define DEVICED_PATH_BATTERY DEVICED_OBJECT_PATH"/Battery"
+#define DEVICED_INTERFACE_BATTERY DEVICED_INTERFACE_NAME".Battery"
+/* Time service */
+#define DEVICED_PATH_TIME DEVICED_OBJECT_PATH"/Time"
+#define DEVICED_INTERFACE_TIME DEVICED_INTERFACE_NAME".Time"
+/* IR service */
+#define DEVICED_PATH_IR DEVICED_OBJECT_PATH"/Ir"
+#define DEVICED_INTERFACE_IR DEVICED_INTERFACE_NAME".ir"
+/* USB_HOST_TEST service */
+#define DEVICED_PATH_USB_HOST_TEST DEVICED_OBJECT_PATH"/UsbHostTest"
+#define DEVICED_INTERFACE_USB_HOST_TEST DEVICED_INTERFACE_NAME".UsbHostTest"
+
+/* Apps service */
+#define DEVICED_PATH_APPS DEVICED_OBJECT_PATH"/Apps"
+#define DEVICED_INTERFACE_APPS DEVICED_INTERFACE_NAME".Apps"
+
+/* GPIO service: status check about gpio */
+#define DEVICED_PATH_GPIO DEVICED_OBJECT_PATH"/Gpio"
+#define DEVICED_INTERFACE_GPIO DEVICED_INTERFACE_NAME".Gpio"
+
+/* HDMICEC service: status check about gpio */
+#define DEVICED_PATH_HDMICEC DEVICED_OBJECT_PATH"/HdmiCec"
+#define DEVICED_INTERFACE_HDMICEC DEVICED_INTERFACE_NAME".HdmiCec"
+
+/* Tzip service: Archive file system */
+#define DEVICED_PATH_TZIP DEVICED_OBJECT_PATH"/Tzip"
+#define DEVICED_INTERFACE_TZIP DEVICED_INTERFACE_NAME".Tzip"
+
+/*
+ * Vibrator daemon
+ */
+#define VIBRATOR_BUS_NAME "org.tizen.system.vibrator"
+#define VIBRATOR_OBJECT_PATH "/Org/Tizen/System/Vibrator"
+#define VIBRATOR_INTERFACE_NAME VIBRATOR_BUS_NAME
+/* Core service: get/set device status operations about device */
+#define VIBRATOR_PATH_CORE VIBRATOR_OBJECT_PATH"/Core"
+#define VIBRATOR_INTERFACE_CORE VIBRATOR_INTERFACE_NAME".core"
+
+#define VIBRATOR_PATH_HAPTIC VIBRATOR_OBJECT_PATH"/Haptic"
+#define VIBRATOR_INTERFACE_HAPTIC VIBRATOR_INTERFACE_NAME".haptic"
+
+/*
+ * Resource daemon
+ */
+#define RESOURCED_BUS_NAME "org.tizen.resourced"
+#define RESOURCED_OBJECT_PATH "/Org/Tizen/ResourceD"
+#define RESOURCED_INTERFACE_NAME RESOURCED_BUS_NAME
+
+#define RESOURCED_PATH_PROCESS RESOURCED_OBJECT_PATH"/Process"
+#define RESOURCED_INTERFACE_PROCESS RESOURCED_INTERFACE_NAME".process"
+#define RESOURCED_METHOD_ACTIVE "Active"
+
+/*
+ * Popup launcher
+ */
+#define POPUP_BUS_NAME "org.tizen.system.popup"
+#define POPUP_OBJECT_PATH "/Org/Tizen/System/Popup"
+#define POPUP_INTERFACE_NAME POPUP_BUS_NAME
+/* LED */
+#define POPUP_PATH_LED POPUP_OBJECT_PATH"/Led"
+#define POPUP_INTERFACE_LED POPUP_INTERFACE_NAME".Led"
+/* Notification */
+#define POPUP_PATH_NOTI POPUP_OBJECT_PATH"/Noti"
+#define POPUP_INTERFACE_NOTI POPUP_INTERFACE_NAME".Noti"
+/* Power key longpress */
+#define POPUP_PATH_POWERKEY POPUP_OBJECT_PATH"/Powerkey"
+#define POPUP_INTERFACE_POWERKEY POPUP_INTERFACE_NAME".Powerkey"
+/* Low battery */
+#define POPUP_PATH_LOWBAT POPUP_OBJECT_PATH"/Lowbat"
+#define POPUP_INTERFACE_LOWBAT POPUP_INTERFACE_NAME".Lowbat"
+/* Low memory */
+#define POPUP_PATH_LOWMEM POPUP_OBJECT_PATH"/Lowmem"
+#define POPUP_INTERFACE_LOWMEM POPUP_INTERFACE_NAME".Lowmem"
+/* MMC */
+#define POPUP_PATH_MMC POPUP_OBJECT_PATH"/Mmc"
+#define POPUP_INTERFACE_MMC POPUP_INTERFACE_NAME".Mmc"
+/* USB */
+#define POPUP_PATH_USB POPUP_OBJECT_PATH"/Usb"
+#define POPUP_INTERFACE_USB POPUP_INTERFACE_NAME".Usb"
+/* USB otg */
+#define POPUP_PATH_USBOTG POPUP_OBJECT_PATH"/Usbotg"
+#define POPUP_INTERFACE_USBOTG POPUP_INTERFACE_NAME".Usbotg"
+/* USB host */
+#define POPUP_PATH_USBHOST POPUP_OBJECT_PATH"/Usbhost"
+#define POPUP_INTERFACE_USBHOST POPUP_INTERFACE_NAME".Usbhost"
+/* System */
+#define POPUP_PATH_SYSTEM POPUP_OBJECT_PATH"/System"
+#define POPUP_INTERFACE_SYSTEM POPUP_INTERFACE_NAME".System"
+/* Crash */
+#define POPUP_PATH_CRASH POPUP_OBJECT_PATH"/Crash"
+#define POPUP_INTERFACE_CRASH POPUP_INTERFACE_NAME".Crash"
+/* ODE */
+#define POPUP_PATH_ODE POPUP_OBJECT_PATH"/Ode"
+#define POPUP_INTERFACE_ODE POPUP_INTERFACE_NAME".Ode"
+/* Servant */
+#define POPUP_PATH_SERVANT POPUP_OBJECT_PATH"/Servant"
+#define POPUP_IFACE_SERVANT POPUP_INTERFACE_NAME".Servant"
+
+#define POPUP_PATH_APP POPUP_OBJECT_PATH"/Apps"
+#define POPUP_IFACE_APP POPUP_BUS_NAME".Apps"
+
+#define POPUP_METHOD_LAUNCH "PopupLaunch"
+#define POPUP_METHOD_TERMINATE "AppTerminateByPid"
+#define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
+
+/*
+ * Crash daemon
+ */
+#define CRASHD_BUS_NAME "org.tizen.system.crashd"
+#define CRASHD_OBJECT_PATH "/Org/Tizen/System/CrashD"
+#define CRASHD_INTERFACE_NAME CRASHD_BUS_NAME
+
+#define CRASHD_PATH_CRASH CRASHD_OBJECT_PATH"/Crash"
+#define CRASHD_INTERFACE_CRASH CRASHD_INTERFACE_NAME".Crash"
+
+struct dbus_byte {
+ const unsigned char *data;
+ int size;
+};
+
+int append_variant(DBusMessageIter *iter, const char *sig, char *param[]);
+
+DBusMessage *dbus_method_sync_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[]);
+
+int dbus_method_sync(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[]);
+
+int dbus_method_sync_timeout(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[], int timeout);
+
+int dbus_method_sync_pairs(const char *dest, const char *path,
+ const char *interface, const char *method,
+ int num, va_list args);
+
+int dbus_method_async(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[]);
+
+typedef void (*dbus_pending_cb)(void *data, DBusMessage *msg, DBusError *err);
+
+int dbus_method_async_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[], dbus_pending_cb cb, int timeout, void *data);
+
+int check_systemd_active(void);
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 ___DEVICED_INTERNAL___
+#define ___DEVICED_INTERNAL___
+#include <sys/types.h>
+#include "dd-deviced.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This file will be removed */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ___DEVICED_INTERNAL___ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __SYSTEM_PRIVATE__
+#define __SYSTEM_PRIVATE__
+
+#include "common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SYSTEM_NOTI_MAXARG 16
+#define SYSTEM_NOTI_MAXSTR 255
+#define BUFF_MAX 255
+
+struct sysnoti {
+ int pid;
+ int cmd;
+ char *type;
+ char *path;
+ int argc;
+ char *argv[SYSTEM_NOTI_MAXARG];
+};
+
+ int util_launch_app_cmd(const char *cmdline);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __SYSTEM_PRIVATE__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <dbus/dbus.h>
+#include <gio/gio.h>
+
+#include "common.h"
+#include "dbus.h"
+#include "deviced-systemd.h"
+
+#include "core/log.h"
+
+
+#define SYSTEMD_UNIT_ESCAPE_CHAR ".-"
+
+typedef unsigned int uint;
+typedef long long int64;
+typedef unsigned long long uint64;
+
+#define g_variant_type_int32 G_VARIANT_TYPE_INT32
+#define g_variant_type_int64 G_VARIANT_TYPE_INT64
+#define g_variant_type_uint32 G_VARIANT_TYPE_UINT32
+#define g_variant_type_uint64 G_VARIANT_TYPE_UINT64
+#define g_variant_type_string G_VARIANT_TYPE_STRING
+
+#define g_variant_get_function_int32(v) g_variant_get_int32(v)
+#define g_variant_get_function_int64(v) g_variant_get_int64(v)
+#define g_variant_get_function_uint32(v) g_variant_get_uint32(v)
+#define g_variant_get_function_uint64(v) g_variant_get_uint64(v)
+#define g_variant_get_function_string(v) g_variant_dup_string(v, NULL)
+
+
+static int deviced_systemd_proxy_call_sync(const char *name,
+ const char *path,
+ const char *iface,
+ const char *method,
+ GVariant *variant,
+ GVariant **reply)
+{
+ GVariant *gvar;
+ GError *error;
+ GDBusProxy *proxy;
+ int ret = 0;
+
+#if (GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION < 36)
+ g_type_init();
+#endif
+
+ error = NULL;
+ proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL, /* GDBusInterfaceInfo */
+ name,
+ path,
+ iface,
+ NULL, /* GCancellable */
+ &error);
+
+ if (proxy == NULL) {
+ _E("Error creating proxy: %s", error->message);
+ ret = error->code;
+ g_error_free(error);
+ return ret;
+ }
+
+ error = NULL;
+ gvar = g_dbus_proxy_call_sync(proxy,
+ method,
+ variant,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+
+ if (error) {
+ _E("Error proxy call sync: %s", error->message);
+ ret = error->code;
+ g_error_free(error);
+ return -ret;
+ }
+
+ g_assert(gvar != NULL);
+ *reply = gvar;
+ g_clear_error(&error);
+ g_object_unref(proxy);
+
+ return 0;
+}
+
+static int deviced_systemd_start_or_stop_unit(char *method, char *name)
+{
+ int ret;
+ GVariant *reply = NULL;
+
+ _I("Starting: %s %s", method, name);
+ ret = deviced_systemd_proxy_call_sync(SYSTEMD_DBUS_DEST,
+ SYSTEMD_DBUS_PATH,
+ SYSTEMD_DBUS_IFACE_MANAGER,
+ method,
+ g_variant_new("(ss)",
+ name,
+ "replace"),
+ &reply);
+ if (ret < 0)
+ goto finish;
+
+ if (!g_variant_is_of_type(reply, G_VARIANT_TYPE("(o)"))) {
+ ret = -EBADMSG;
+ goto finish;
+ }
+
+ ret = 0;
+finish:
+ _I("Finished(%d): %s %s", ret, method, name);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return ret;
+}
+
+int deviced_systemd_start_unit(char *name)
+{
+ assert(name);
+
+ return deviced_systemd_start_or_stop_unit("StartUnit", name);
+}
+
+int deviced_systemd_stop_unit(char *name)
+{
+ assert(name);
+
+ return deviced_systemd_start_or_stop_unit("StopUnit", name);
+}
+
+static char *deviced_systemd_get_unit_dbus_path(const char *unit)
+{
+ char *path = NULL;
+ int i;
+ size_t p, k, prefix_len, unit_len = strlen(unit);
+ size_t path_len, len, escape;
+
+ assert(unit);
+
+ for (escape = 0, p = 0; p < unit_len; escape++) {
+ k = strcspn(unit+p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ if (p+k >= unit_len)
+ break;
+ p += k+1;
+ }
+
+ prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH);
+ /* assume we try to get object path of foo-bar.service then
+ * the object path will be
+ * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In
+ * this case we can find two escape characters, one of escape
+ * char('-') is changed to three of char("_2d"). So the total
+ * length will be: */
+ /* (PREFIX) + (unit - escape + 3*escape) + NULL */
+ path_len = prefix_len + (unit_len - escape)
+ + (escape * 3 * sizeof(char)) + 1;
+ path = (char *)calloc(path_len, sizeof(char));
+ if (!path)
+ return NULL;
+
+ strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len + 1);
+ for (i = 0, p = 0; i <= escape; i++) {
+ k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ strncpy(path + prefix_len, unit + p, k);
+ if (k < strlen(unit + p)) {
+ len = path_len - (prefix_len + k);
+ snprintf(path + prefix_len + k, len,
+ "_%x", *(unit + p + k) & 0xff);
+ prefix_len += k+3;
+ p += k+1;
+ }
+ }
+
+ return path;
+}
+
+static int deviced_systemd_get_property(const char *name,
+ const char *path,
+ const char *iface,
+ const char *method,
+ const char *interface,
+ const char *property,
+ GVariant **reply)
+{
+ int ret;
+ GVariant *variant;
+
+ variant = g_variant_new("(ss)",
+ interface,
+ property);
+
+ ret = deviced_systemd_proxy_call_sync(name,
+ path,
+ iface,
+ method,
+ variant,
+ reply);
+
+ return ret;
+}
+
+int deviced_systemd_get_manager_property(const char *iface,
+ const char *property,
+ GVariant **variant)
+{
+ assert(iface);
+ assert(property);
+
+ return deviced_systemd_get_property(SYSTEMD_DBUS_DEST,
+ SYSTEMD_DBUS_PATH,
+ DBUS_IFACE_DBUS_PROPERTIES,
+ "Get",
+ iface,
+ property,
+ variant);
+}
+
+int deviced_systemd_get_unit_property(const char *unit,
+ const char *property,
+ GVariant **variant)
+{
+ int r;
+ char *escaped;
+
+ assert(unit);
+ assert(property);
+
+ escaped = deviced_systemd_get_unit_dbus_path(unit);
+
+ r = deviced_systemd_get_property(SYSTEMD_DBUS_DEST,
+ escaped,
+ DBUS_IFACE_DBUS_PROPERTIES,
+ "Get",
+ SYSTEMD_DBUS_IFACE_UNIT,
+ property,
+ variant);
+ free(escaped);
+ return r;
+}
+
+int deviced_systemd_get_service_property(const char *unit,
+ const char *property,
+ GVariant **variant)
+{
+ int ret;
+ char *escaped;
+
+ assert(unit);
+ assert(property);
+
+ escaped = deviced_systemd_get_unit_dbus_path(unit);
+
+ ret = deviced_systemd_get_property(SYSTEMD_DBUS_DEST,
+ escaped,
+ DBUS_IFACE_DBUS_PROPERTIES,
+ "Get",
+ SYSTEMD_DBUS_IFACE_SERVICE,
+ property,
+ variant);
+ free(escaped);
+ return ret;
+}
+
+#define DEFINE_SYSTEMD_GET_PROPERTY(iface, type, value) \
+ int deviced_systemd_get_##iface##_property_as_##type( \
+ const char *target, \
+ const char *property, \
+ value*result) \
+ { \
+ \
+ GVariant *var; \
+ GVariant *inner; \
+ int r; \
+ \
+ r = deviced_systemd_get_##iface##_property(target, \
+ property, \
+ &var); \
+ if (r < 0) { \
+ _E("Failed to get property:\n" \
+ " target: %s\n" \
+ " property: %s", \
+ target, property); \
+ return r; \
+ } \
+ \
+ if (!g_variant_is_of_type(var, \
+ G_VARIANT_TYPE("(v)"))) \
+ return -EBADMSG; \
+ \
+ g_variant_get(var, "(v)", &inner); \
+ if (!g_variant_is_of_type(inner, \
+ g_variant_type_##type)) \
+ return -EBADMSG; \
+ \
+ *result = g_variant_get_function_##type(inner); \
+ g_variant_unref(var); \
+ \
+ return 0; \
+ }
+
+/* int deviced_systemd_get_manager_property_as_int32(const char *iface, const char *property, int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(manager, int32, int)
+/* int deviced_systemd_get_manager_property_as_uint32(const char *iface, const char *property, unsigned int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(manager, uint32, uint)
+/* int deviced_systemd_get_manager_property_as_int64(const char *iface, const char *property, long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(manager, int64, long long)
+/* int deviced_systemd_get_manager_property_as_uint64(const char *iface, const char *property, unsigned long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(manager, uint64, unsigned long long)
+/* int deviced_systemd_get_manager_property_as_string(const char *iface, const char *property, char **result); */
+DEFINE_SYSTEMD_GET_PROPERTY(manager, string, char*)
+/* int deviced_systemd_get_unit_property_as_int32(const char *unit, const char *property, int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(unit, int32, int)
+/* int deviced_systemd_get_unit_property_as_uint32(const char *unit, const char *property, unsigned int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(unit, uint32, uint)
+/* int deviced_systemd_get_unit_property_as_int64(const char *unit, const char *property, long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(unit, int64, long long)
+/* int deviced_systemd_get_unit_property_as_uint64(const char *unit, const char *property, unsigned long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(unit, uint64, unsigned long long)
+/* int deviced_systemd_get_unit_property_as_string(const char *unit, const char *property, char **result); */
+DEFINE_SYSTEMD_GET_PROPERTY(unit, string, char*)
+/* int deviced_systemd_get_service_property_as_int32(const char *unit, const char *property, int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(service, int32, int)
+/* int deviced_systemd_get_service_property_as_uint32(const char *unit, const char *property, unsigned int *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(service, uint32, uint)
+/* int deviced_systemd_get_service_property_as_int64(const char *unit, const char *property, long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(service, int64, long long)
+/* int deviced_systemd_get_service_property_as_uint64(const char *unit, const char *property, unsigned long long *result); */
+DEFINE_SYSTEMD_GET_PROPERTY(service, uint64, unsigned long long)
+/* int deviced_systemd_get_service_property_as_string(const char *unit, const char *property, char **result); */
+DEFINE_SYSTEMD_GET_PROPERTY(service, string, char*)
+
+int deviced_systemd_instance_new_from_template(const char *template,
+ const char *instance,
+ const char **name)
+{
+ /* p point '@' */
+ /* e point '.' */
+ const char *p, *e;
+ char *prefix = NULL, *n = NULL;
+ int r;
+
+ assert(template);
+ p = strchr(template, '@');
+ if (!p) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ prefix = strndup(template, p - template + 1);
+ if (!prefix) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ e = strrchr(p + 1, '.');
+ if (!e) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ /* verifying template. prefix@.service */
+ if (e != p + 1) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ r = asprintf(&n, "%s%s%s", prefix, instance, e);
+ if (r < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ *name = n;
+ r = 0;
+finish:
+ if (prefix)
+ free(prefix);
+
+ return r;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 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 __DEVICED_SYSTEMD_H__
+#define __DEVICED_SYSTEMD_H__
+
+#include <dbus/dbus.h>
+#include <gio/gio.h>
+
+#define DBUS_IFACE_DBUS_PROPERTIES DBUS_SERVICE_DBUS ".Properties"
+
+#define SYSTEMD_DBUS_DEST "org.freedesktop.systemd1"
+#define SYSTEMD_DBUS_IFACE_MANAGER SYSTEMD_DBUS_DEST ".Manager"
+#define SYSTEMD_DBUS_IFACE_UNIT SYSTEMD_DBUS_DEST ".Unit"
+#define SYSTEMD_DBUS_IFACE_SERVICE SYSTEMD_DBUS_DEST ".Service"
+#define SYSTEMD_DBUS_IFACE_TARGET SYSTEMD_DBUS_DEST ".Target"
+
+#define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1"
+#define SYSTEMD_DBUS_UNIT_PATH SYSTEMD_DBUS_PATH "/unit/"
+
+int deviced_systemd_start_unit(char *name);
+int deviced_systemd_stop_unit(char *name);
+
+int deviced_systemd_get_manager_property(const char *iface, const char *property, GVariant **variant);
+int deviced_systemd_get_unit_property(const char *unit, const char *property, GVariant **variant);
+int deviced_systemd_get_service_property(const char* unit, const char* property, GVariant **variant);
+
+int deviced_systemd_get_manager_property_as_int32(const char *iface, const char *property, int *result);
+int deviced_systemd_get_manager_property_as_uint32(const char *iface, const char *property, unsigned int *result);
+int deviced_systemd_get_manager_property_as_int64(const char *iface, const char *property, long long *result);
+int deviced_systemd_get_manager_property_as_uint64(const char *iface, const char *property, unsigned long long *result);
+int deviced_systemd_get_manager_property_as_string(const char *iface, const char *property, char **result);
+int deviced_systemd_get_unit_property_as_int32(const char *unit, const char *property, int *result);
+int deviced_systemd_get_unit_property_as_uint32(const char *unit, const char *property, unsigned int *result);
+int deviced_systemd_get_unit_property_as_int64(const char *unit, const char *property, long long *result);
+int deviced_systemd_get_unit_property_as_uint64(const char *unit, const char *property, unsigned long long *result);
+int deviced_systemd_get_unit_property_as_string(const char *unit, const char *property, char **result);
+int deviced_systemd_get_service_property_as_int32(const char *unit, const char *property, int *result);
+int deviced_systemd_get_service_property_as_uint32(const char *unit, const char *property, unsigned int *result);
+int deviced_systemd_get_service_property_as_int64(const char *unit, const char *property, long long *result);
+int deviced_systemd_get_service_property_as_uint64(const char *unit, const char *property, unsigned long long *result);
+int deviced_systemd_get_service_property_as_string(const char *unit, const char *property, char **result);
+
+int deviced_systemd_instance_new_from_template(const char *template, const char *instance, const char **name);
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __LOG_MACRO_H__
+#define __LOG_MACRO_H__
+
+#ifdef ENABLE_DLOG
+#include <dlog.h>
+#define _D(fmt, arg...) \
+ do { SLOGD(fmt, ##arg); } while(0)
+#define _I(fmt, arg...) \
+ do { SLOGI(fmt, ##arg); } while(0)
+#define _W(fmt, arg...) \
+ do { SLOGW(fmt, ##arg); } while(0)
+#define _E(fmt, arg...) \
+ do { SLOGE(fmt, ##arg); } while(0)
+#define _SD(fmt, arg...) \
+ do { SECURE_SLOGD(fmt, ##arg); } while(0)
+#define _SI(fmt, arg...) \
+ do { SECURE_SLOGI(fmt, ##arg); } while(0)
+#define _SW(fmt, arg...) \
+ do { SECURE_SLOGW(fmt, ##arg); } while(0)
+#define _SE(fmt, arg...) \
+ do { SECURE_SLOGE(fmt, ##arg); } while(0)
+#else
+#define _D(...) do { } while (0)
+#define _I(...) do { } while (0)
+#define _W(...) do { } while (0)
+#define _E(...) do { } while (0)
+#define _SD(...) do { } while (0)
+#define _SI(...) do { } while (0)
+#define _SW(...) do { } while (0)
+#define _SE(...) do { } while (0)
+#endif
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 __LOG_H__
+#define __LOG_H__
+
+#ifdef ENABLE_LIBDEVICED_DLOG
+#define ENABLE_DLOG
+#endif
+
+#define LOG_TAG "DEVICED"
+#include "shared/log-macro.h"
+
+#endif
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __OOM_H__
+#define __OOM_H__
+
+#define OOMADJ_SU (0)
+#define OOMADJ_INIT (100)
+#define OOMADJ_FOREGRD_LOCKED (150)
+#define OOMADJ_FOREGRD_UNLOCKED (200)
+#define OOMADJ_BACKGRD_LOCKED (250)
+#define OOMADJ_BACKGRD_UNLOCKED (300)
+#define OOMADJ_APP_LIMIT OOMADJ_INIT
+
+#endif /* __OOM_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2012 - 2013 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 <tzplatform_config.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <vconf.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <linux/rtc.h>
+#include <fcntl.h>
+#include <sys/timerfd.h>
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "display/poll.h"
+#include "display/core.h"
+#include "core/edbus-handler.h"
+#include "core/common.h"
+#include "core/device-notifier.h"
+
+#define PREDEF_SET_DATETIME "set_datetime"
+#define PREDEF_SET_TIMEZONE "set_timezone"
+
+#ifndef TFD_TIMER_CANCELON_SET
+#define TFD_TIMER_CANCELON_SET (1<<1)
+#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0x2000000
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK 0x4000
+#endif
+
+#ifndef TFD_CLOEXEC
+#define TFD_CLOEXEC O_CLOEXEC
+#endif
+
+#ifndef TFD_NONBLOCK
+#define TFD_NONBLOCK O_NONBLOCK
+#endif
+
+#define TIME_CHANGE_SIGNAL "STimeChanged"
+
+static const char default_rtc0[] = "/dev/rtc0";
+static const char default_rtc1[] = "/dev/rtc1";
+
+static const time_t default_time = 2147483645; /* max(32bit) -3sec */
+static Ecore_Fd_Handler *tfdh; /* tfd change noti */
+
+static Eina_Bool tfd_cb(void *data, Ecore_Fd_Handler *fd_handler);
+static int timerfd_check_stop(int fd);
+static int timerfd_check_start(void);
+
+char *substring(const char *str, size_t begin, size_t len)
+{
+ if (str == 0 || strlen(str) == 0 || strlen(str) < begin
+ || strlen(str) < (begin + len))
+ return 0;
+
+ return strndup(str + begin, len);
+}
+
+int handle_timezone(char *str)
+{
+ int ret;
+ struct stat sts;
+ time_t now;
+ struct tm ts;
+ struct tm *ts2;
+ const char *sympath, *tzpath;
+ char buf[256];
+
+ if (str == NULL)
+ return -1;
+
+ tzpath = str;
+ sympath = tzplatform_mkpath(TZ_SYS_ETC, "localtime");
+
+ _D("TZPATH = %s", tzpath);
+
+ if (stat(tzpath, &sts) == -1 && errno == ENOENT) {
+ _E("invalid tzpath(%s)", tzpath);
+ return -EINVAL;
+ }
+
+ /* FIXME for debugging purpose */
+ time(&now);
+ ts2 = localtime_r(&now, &ts);
+ if (ts2) {
+ asctime_r(&ts, buf);
+ _D("cur local time is %s", buf);
+ }
+
+ /* unlink current link
+ * eg. rm /opt/etc/localtime */
+ if (stat(sympath, &sts) == -1 && errno == ENOENT) {
+ /* DO NOTHING */
+ } else {
+ ret = unlink(sympath);
+ if (ret < 0) {
+ _E("unlink error : [%d](errno:%d)", ret, errno);
+ return -1;
+ }
+ _D("unlink success");
+ }
+
+ /* symlink new link
+ * eg. ln -s /usr/share/zoneinfo/Asia/Seoul /opt/etc/localtime */
+ ret = symlink(tzpath, sympath);
+ if (ret < 0) {
+ _E("symlink error : [%d](errno:%d)", ret, errno);
+ return -1;
+ }
+ _D("symlink success");
+
+ tzset();
+
+ /* FIXME for debugging purpose */
+ ts2 = localtime_r(&now, &ts);
+ if (ts2) {
+ asctime_r(&ts, buf);
+ _D("new local time is %s", buf);
+ }
+ return 0;
+}
+
+/*
+ * TODO : error handling code should be added here.
+ */
+int handle_date(char *str)
+{
+ long int tmp = 0;
+ time_t timet = 0;
+
+ if (str == NULL)
+ return -1;
+
+ tmp = (long int)atoi(str);
+ timet = (time_t) tmp;
+
+ _D("ctime = %s", ctime(&timet));
+ vconf_set_int(VCONFKEY_SYSTEM_TIMECHANGE, timet);
+
+ return 0;
+}
+
+int set_datetime_action(int argc, char **argv)
+{
+ int ret = 0;
+ unsigned int pm_state;
+ if (argc < 1)
+ return -1;
+ if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
+ _E("Fail to get vconf value for pm state\n");
+ if (ret == 1)
+ pm_state = 0x1;
+ else if (ret == 2)
+ pm_state = 0x2;
+ else
+ pm_state = 0x4;
+
+ pm_lock_internal(INTERNAL_LOCK_TIME, pm_state, STAY_CUR_STATE, 0);
+ ret = handle_date(argv[0]);
+ pm_unlock_internal(INTERNAL_LOCK_TIME, pm_state, STAY_CUR_STATE);
+ return ret;
+}
+
+int set_timezone_action(int argc, char **argv)
+{
+ int ret;
+ unsigned int pm_state;
+ if (argc < 1)
+ return -1;
+ if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
+ _E("Fail to get vconf value for pm state\n");
+ if (ret == 1)
+ pm_state = 0x1;
+ else if (ret == 2)
+ pm_state = 0x2;
+ else
+ pm_state = 0x4;
+
+ pm_lock_internal(INTERNAL_LOCK_TIME, pm_state, STAY_CUR_STATE, 0);
+ ret = handle_timezone(argv[0]);
+ pm_unlock_internal(INTERNAL_LOCK_TIME, pm_state, STAY_CUR_STATE);
+ return ret;
+}
+
+static void time_changed_broadcast(void)
+{
+ broadcast_edbus_signal(DEVICED_PATH_TIME, DEVICED_INTERFACE_TIME,
+ TIME_CHANGE_SIGNAL, NULL, NULL);
+}
+
+static int timerfd_check_start(void)
+{
+ int tfd;
+ int ret;
+ struct itimerspec tmr;
+
+ tfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (tfd == -1) {
+ _E("error timerfd_create() %d", errno);
+ tfdh = NULL;
+ return -1;
+ }
+
+ tfdh = ecore_main_fd_handler_add(tfd, ECORE_FD_READ, tfd_cb, NULL, NULL, NULL);
+ if (!tfdh) {
+ _E("error ecore_main_fd_handler_add");
+ return -1;
+ }
+ memset(&tmr, 0, sizeof(tmr));
+ tmr.it_value.tv_sec = default_time;
+ ret = timerfd_settime(tfd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCELON_SET, &tmr, NULL);
+ if (ret < 0) {
+ _E("error timerfd_settime() %d", errno);
+ return -1;
+ }
+ return 0;
+}
+
+static int timerfd_check_stop(int tfd)
+{
+ if (tfdh) {
+ ecore_main_fd_handler_del(tfdh);
+ tfdh = NULL;
+ }
+ if (tfd >= 0) {
+ close(tfd);
+ tfd = -1;
+ }
+ return 0;
+}
+
+static Eina_Bool tfd_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ int tfd = -1;
+ u_int64_t ticks;
+ int ret = -1;
+
+ ret = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ);
+ if (!ret) {
+ _E("error ecore_main_fd_handler_get()");
+ goto out;
+ }
+
+ tfd = ecore_main_fd_handler_fd_get(fd_handler);
+ if (tfd == -1) {
+ _E("error ecore_main_fd_handler_fd_get()");
+ goto out;
+ }
+
+ ret = read(tfd, &ticks, sizeof(ticks));
+ if (ret < 0 && errno == ECANCELED) {
+ vconf_set_int(VCONFKEY_SYSMAN_STIME, VCONFKEY_SYSMAN_STIME_CHANGED);
+ time_changed_broadcast();
+ timerfd_check_stop(tfd);
+ _D("NOTIFICATION here");
+ timerfd_check_start();
+ } else {
+ _E("unexpected read (err:%d)", errno);
+ }
+out:
+ return EINA_TRUE;
+}
+
+static DBusMessage *dbus_time_handler(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ pid_t pid;
+ int ret;
+ int argc;
+ char *type_str;
+ char *argv;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &type_str,
+ DBUS_TYPE_INT32, &argc,
+ DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (argc < 0) {
+ _E("message is invalid!");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (kill(pid, 0) == -1) {
+ _E("%d process does not exist, dbus ignored!", pid);
+ ret = -ESRCH;
+ goto out;
+ }
+
+ if (strncmp(type_str, PREDEF_SET_DATETIME, strlen(PREDEF_SET_DATETIME)) == 0)
+ ret = set_datetime_action(argc, (char **)&argv);
+ else if (strncmp(type_str, PREDEF_SET_TIMEZONE, strlen(PREDEF_SET_TIMEZONE)) == 0)
+ ret = set_timezone_action(argc, (char **)&argv);
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { PREDEF_SET_DATETIME, "sis", "i", dbus_time_handler },
+ { PREDEF_SET_TIMEZONE, "sis", "i", dbus_time_handler },
+
+};
+
+static int time_lcd_changed_cb(void *data)
+{
+ int lcd_state;
+ int tfd = -1;
+
+ if (!data)
+ goto out;
+
+ lcd_state = *(int *)data;
+
+ if (lcd_state < S_LCDOFF)
+ goto restart;
+
+ lcd_state = check_lcdoff_lock_state();
+ if (lcd_state || !tfdh)
+ goto out;
+ tfd = ecore_main_fd_handler_fd_get(tfdh);
+ if (tfd == -1)
+ goto out;
+
+ _D("stop tfd");
+ timerfd_check_stop(tfd);
+ goto out;
+restart:
+ if (tfdh)
+ return 0;
+ _D("restart tfd");
+ timerfd_check_start();
+out:
+ return 0;
+}
+
+static void time_init(void *data)
+{
+ int ret;
+
+ ret = register_edbus_method(DEVICED_PATH_SYSNOTI, edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+
+ if (timerfd_check_start() == -1)
+ _E("fail system time change detector init");
+ register_notifier(DEVICE_NOTIFIER_LCD, time_lcd_changed_cb);
+}
+
+static const struct device_ops time_device_ops = {
+ .name = "time",
+ .init = time_init,
+};
+
+DEVICE_OPS_REGISTER(&time_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <hw/touchscreen.h>
+#include "core/devices.h"
+#include "core/common.h"
+#include "core/log.h"
+
+static struct touchscreen_device *touchscreen_dev;
+
+static void touchscreen_init(void *data)
+{
+ struct hw_info *info;
+ int ret;
+
+ if (touchscreen_dev)
+ return;
+
+ ret = hw_get_info(TOUCHSCREEN_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (ret < 0) {
+ _E("Fail to load touchscreen shared library (%d)", ret);
+ return;
+ }
+
+ if (!info->open) {
+ _E("fail to open touchscreen device : open(NULL)");
+ return;
+ }
+
+ ret = info->open(info, NULL, (struct hw_common **)&touchscreen_dev);
+ if (ret < 0) {
+ _E("fail to get touchscreen device structure : (%d)", ret);
+ return;
+ }
+
+ _I("touchscreen device structure load success");
+}
+
+static void touchscreen_exit(void *data)
+{
+ struct hw_info *info;
+
+ if (!touchscreen_dev)
+ return;
+
+ info = touchscreen_dev->common.info;
+ assert(info);
+
+ info->close((struct hw_common *)touchscreen_dev);
+ touchscreen_dev = NULL;
+}
+
+static int touchscreen_set_state(enum touchscreen_state state)
+{
+ int ret;
+ char *act;
+
+ if (!touchscreen_dev) {
+ _E("touchscreen device structure is not loaded");
+ return -ENOENT;
+ }
+
+ if (state != TOUCHSCREEN_ON && state != TOUCHSCREEN_OFF) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ if (!touchscreen_dev->set_state) {
+ _E("touchscreen state change is not supported");
+ return -ENOTSUP;
+ }
+
+ act = (state == TOUCHSCREEN_ON) ? "enable" : "disable";
+
+ ret = touchscreen_dev->set_state(state);
+ if (ret == 0)
+ _I("Success to %s touchscreen", act);
+ else
+ _E("Failed to %s touchscreen (%d)", act, ret);
+
+ return ret;
+}
+
+static int touchscreen_start(enum device_flags flags)
+{
+ return touchscreen_set_state(TOUCHSCREEN_ON);
+}
+
+static int touchscreen_stop(enum device_flags flags)
+{
+ return touchscreen_set_state(TOUCHSCREEN_OFF);
+}
+
+static const struct device_ops touchscreen_device_ops = {
+ .name = "touchscreen",
+ .init = touchscreen_init,
+ .exit = touchscreen_exit,
+ .start = touchscreen_start,
+ .stop = touchscreen_stop,
+};
+
+DEVICE_OPS_REGISTER(&touchscreen_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <unzip.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "core/log.h"
+
+#include "tzip-utility.h"
+
+static sem_t tzip_sem;
+
+static GHashTable *hashmap;
+
+struct tzip_mount_entry *get_mount_entry(const char *mount_path)
+{
+ struct tzip_mount_entry *entry;
+ entry = (struct tzip_mount_entry *)g_hash_table_lookup(
+ hashmap, mount_path);
+ return entry;
+}
+
+struct tzip_mount_entry *find_mount_entry(
+ const char *mount_path, int *dir_status)
+{
+ int len, mlen;
+ GHashTableIter iter;
+ gpointer key, value;
+ char *path;
+
+ *dir_status = -1;
+ len = strlen(mount_path);
+
+ g_hash_table_iter_init(&iter, hashmap);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ path = (char *)key;
+ /*
+ * FUSE checks directory status in recursive passion.
+ * For example if mount path = "/tmp/d1",
+ * FUSE first checks status of "/tmp" and proceeds to check
+ * "/tmp/d1" only if status "/tmp" is success.
+ *
+ * This function takes care of this scenario by setting dir_status = 1
+ * to indicate parent directory of mount path is found
+ */
+ mlen = strlen(path);
+ if (len < mlen) {
+ if (strncmp(mount_path, path, len) == 0) {
+ /*
+ * Dont break, till exact match is found for node->path.
+ * Just mark *dir_status = 1 to indicate
+ * parent directory match is found
+ */
+ *dir_status = 1;
+ }
+ } else if (mlen == len &&
+ strncmp(mount_path, path, mlen) == 0) {
+ /* Break, exact match is found for node->path */
+ *dir_status = 1;
+ return get_mount_entry(path);
+ } else if (strncmp(mount_path, path, mlen) == 0 &&
+ mount_path[mlen] == DIR_DELIMETER) {
+ /* Break, mount directory found for a given file or directory */
+ *dir_status = 1;
+ return get_mount_entry(path);
+ }
+ }
+
+ return NULL;
+}
+
+struct tzip_dir_info *get_dir_list(
+ struct tzip_mount_entry *entry, const char *dir_name)
+{
+ struct tzip_dir_info *dinfo;
+
+ dinfo = (struct tzip_dir_info *)g_hash_table_lookup(
+ entry->dir_hash, dir_name);
+
+ if (!dinfo)
+ _D("Empty Folder %s", dir_name);
+
+ return dinfo;
+}
+
+void fileinfo_to_stat(unz_file_info *file_info, struct stat *file_stat, mode_t mode)
+{
+ struct tm newdate;
+ time_t file_time;
+ struct timeval tv;
+
+ if (file_info) {
+ newdate.tm_sec = file_info->tmu_date.tm_sec;
+ newdate.tm_min = file_info->tmu_date.tm_min;
+ newdate.tm_hour = file_info->tmu_date.tm_hour;
+ newdate.tm_mday = file_info->tmu_date.tm_mday;
+ newdate.tm_mon = file_info->tmu_date.tm_mon;
+ if (file_info->tmu_date.tm_year > 1900)
+ newdate.tm_year = file_info->tmu_date.tm_year - 1900;
+ else
+ newdate.tm_year = file_info->tmu_date.tm_year ;
+ newdate.tm_isdst = -1;
+
+ file_time = mktime(&newdate);
+ } else {
+ /* add current time for mount directory */
+ gettimeofday(&tv, NULL);
+ file_time = tv.tv_sec;
+ }
+
+ file_stat->st_mode = mode;
+ file_stat->st_atime = file_time;
+ file_stat->st_mtime = file_time;
+ file_stat->st_ctime = file_time;
+
+ if (mode & S_IFDIR || !file_info)
+ file_stat->st_size = 4096;
+ else
+ file_stat->st_size = file_info->uncompressed_size;
+}
+
+int add_path_dirs_info(struct tzip_mount_entry *entry, const char *path,
+ unz_file_info *file_info, mode_t mode)
+{
+ char *dir;
+ char *cpy_path;
+ char *next_dir;
+ char *parent_dir;
+ char *save_ptr;
+ int ret = 0;
+
+ if (!strchr(path, '/')) {
+ /* file or directory in root directory */
+ ret = add_dir_info(entry, ".", path, file_info, mode);
+ return ret;
+ }
+ /* add info about each directory in path */
+ parent_dir = malloc(strlen(path) + 1);
+ if (!parent_dir) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ /* needed copy, because of strtok_r modify cstring */
+ cpy_path = strndup(path, strlen(path) + 1);
+ if (!cpy_path) {
+ free(parent_dir);
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ dir = strtok_r(cpy_path, "/", &save_ptr);
+ ret = add_dir_info(entry, ".", dir, file_info, S_IFDIR);
+
+ strncpy(parent_dir, dir, strlen(dir) + 1);
+ dir = strtok_r(NULL, "/", &save_ptr);
+ next_dir = strtok_r(NULL, "/", &save_ptr);
+
+ while (next_dir && !ret) {
+ ret = add_dir_info(entry, parent_dir, dir, file_info, S_IFDIR);
+ strncat(parent_dir, "/", 2);
+ strncat(parent_dir, dir, strlen(dir) + 1);
+ dir = next_dir;
+ next_dir = strtok_r(NULL, "/", &save_ptr);
+ }
+
+ if (ret) {
+ free(cpy_path);
+ free(parent_dir);
+ return ret;
+ }
+
+ ret = add_dir_info(entry, parent_dir, dir, file_info, mode);
+ free(cpy_path);
+ free(parent_dir);
+
+ return ret;
+}
+
+int add_dir_info(struct tzip_mount_entry *entry, const char *parent_dir,
+ const char *filename, unz_file_info *file_info, mode_t mode)
+{
+ struct tzip_file_info *finfo = NULL;
+ struct tzip_dir_info *dinfo = NULL;
+ int len;
+
+ /* create parent directory if does not exist */
+ if (!entry->dir_hash) {
+ /* first entry, initialize dir_hash table */
+ entry->dir_hash = g_hash_table_new_full(
+ g_str_hash, g_str_equal, NULL, NULL);
+ }
+
+ dinfo = (struct tzip_dir_info *)g_hash_table_lookup(
+ entry->dir_hash, parent_dir);
+ if (!dinfo) {
+ /* new parent directory node, add */
+ dinfo = (struct tzip_dir_info *)malloc(
+ sizeof(struct tzip_dir_info));
+ if (!dinfo) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ dinfo->file_hash = g_hash_table_new_full(
+ g_str_hash, g_str_equal, NULL, NULL);
+ if (!dinfo->file_hash) {
+ _E("Malloc failed");
+ free(dinfo);
+ return -ENOMEM;
+ }
+
+ len = strlen(parent_dir) + 1;
+ dinfo->name = (char *)malloc(len);
+ if (!dinfo->name) {
+ _E("Malloc failed");
+ free(dinfo);
+ return -ENOMEM;
+ }
+ snprintf(dinfo->name, len, "%s", parent_dir);
+ g_hash_table_insert(entry->dir_hash, dinfo->name, dinfo);
+ fileinfo_to_stat(NULL, &dinfo->stat, S_IFDIR);
+ }
+
+ finfo = (struct tzip_file_info *)g_hash_table_lookup(
+ dinfo->file_hash, filename);
+
+ if (!finfo) {
+ /* add dir info in parent dir node */
+ finfo = (struct tzip_file_info *)malloc(sizeof(struct tzip_file_info));
+ if (!finfo) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ len = strlen(filename) + 1;
+ finfo->name = (char *)malloc(len);
+ if (!finfo->name) {
+ free(finfo);
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+ strncpy(finfo->name, filename, len);
+
+ fileinfo_to_stat(file_info, &finfo->stat, mode);
+
+ g_hash_table_insert(dinfo->file_hash, finfo->name, finfo);
+ }
+
+ return 0;
+}
+
+int extract_zipfile_details(
+ struct tzip_mount_entry *entry, const char *zip_path)
+{
+ uLong i;
+ int ret = 0;
+ mode_t mode;
+
+ _D("Adding mount (%s, %s) to list", entry->path, zip_path);
+
+ /* Open the zip file */
+ unzFile *zipfile = unzOpen(zip_path);
+ if (!zipfile) {
+ _E("unzOpen Failed %s ", zip_path);
+ return -EINVAL ;
+ }
+
+ /* Get info about the zip file */
+ unz_global_info global_info;
+ if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK) {
+ _E("unzGetGlobalInfo Failed");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Loop to extract all files */
+ for (i = 0; i < global_info.number_entry; ++i) {
+ /* Get info about current file. */
+ unz_file_info file_info = {0,};
+ char filename[MAX_FILENAME_LEN] = {0};
+
+ ret = unzGetCurrentFileInfo(zipfile, &file_info, filename,
+ MAX_FILENAME_LEN, NULL, 0, NULL, 0);
+ if (ret != UNZ_OK) {
+ _E("unzGetCurrentFileInfo Failed");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ _D("unzGetCurrentFileInfo file name - %s", filename);
+
+ /* Check if this entry is a directory or file. */
+ const size_t filename_length = strlen(filename);
+
+ if (filename[filename_length-1] == DIR_DELIMETER) {
+ _D("Entry is a directory");
+ filename[filename_length-1] = 0;
+ mode = S_IFDIR;
+ } else {
+ _D("Entry is a file");
+ mode = S_IFREG;
+ }
+
+ ret = add_path_dirs_info(entry, filename, &file_info, mode);
+ if (ret)
+ break;
+
+ /* Go the the next entry listed in the zip file. */
+ if ((i+1) < global_info.number_entry) {
+ ret = unzGoToNextFile(zipfile);
+ if (ret != UNZ_OK) {
+ _E("unzGoToNextFile Failed");
+ ret = -EINVAL ;
+ break;
+ }
+ }
+ }
+
+out:
+ unzClose(zipfile);
+ return ret;
+}
+
+int add_mount_entry(const char *zip_path, const char *mount_path)
+{
+ struct tzip_mount_entry *entry = NULL;
+ int ret = 0;
+ int len;
+
+ /* check if this mount path is already there, return error if yes */
+ entry = get_mount_entry(mount_path);
+ if (entry) {
+ _E("mount_path : %s already exists ", mount_path);
+ return -EEXIST;
+ }
+
+ entry = (struct tzip_mount_entry *)malloc(
+ sizeof(struct tzip_mount_entry));
+ if (!entry) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+ entry->dir_hash = NULL;
+
+ len = strlen(mount_path) + 1;
+ entry->path = (char *)malloc(len);
+ if (!entry->path) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+ snprintf(entry->path, len, "%s", mount_path);
+
+ len = strlen(zip_path) + 1;
+ entry->zip_path = (char *)malloc(len);
+ if (!entry->zip_path) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ strncpy(entry->zip_path, zip_path, len);
+
+ g_hash_table_insert(hashmap, entry->path, entry);
+
+ /* pasrse zip file and update list */
+ ret = extract_zipfile_details(entry, zip_path);
+ if (ret) {
+ free_mount_node(entry);
+ return ret;
+ }
+
+out:
+ if (ret < 0 && entry) {
+ free(entry->path);
+ free(entry);
+ }
+ return ret;
+}
+
+void copy_file_stat(struct stat *src, struct stat *dest)
+{
+ dest->st_mode = src->st_mode;
+ dest->st_nlink = src->st_nlink;
+ dest->st_atime = src->st_atime;
+ dest->st_mtime = src->st_mtime;
+ dest->st_ctime = src->st_ctime;
+ dest->st_size = src->st_size;
+}
+
+int get_file_info(const char *file_path, struct tzip_file_info *flist)
+{
+ struct tzip_mount_entry *entry;
+ struct tzip_dir_info *dinfo;
+ struct tzip_file_info *finfo;
+ char *file_name;
+ int file_index = 0;
+ int dir_status;
+
+ _D("File path : %s ", file_path);
+
+ /* return file_info for a given file and mount path */
+ entry = find_mount_entry(file_path, &dir_status);
+ if (!entry) {
+ _E("mount_path : %s is not mounted, dir_status %d", file_path, dir_status);
+ return dir_status;
+ }
+
+ _D("Got mount path : %s", entry->path);
+ file_index = strlen(entry->path);
+
+ file_name = strrchr(&file_path[file_index], '/');
+ if (!file_name) {
+ _D("Parent Directory");
+ return 1;
+ } else if (strlen(file_name) == strlen(&file_path[file_index])) {
+ _D("Checking dir : %s", ".");
+ dinfo = get_dir_list(entry, ".");
+ } else {
+ *file_name = 0;
+ _D("Checking dir : %s", &file_path[file_index+1]);
+ dinfo = get_dir_list(entry, &file_path[file_index+1]);
+ }
+ if (!dinfo) {
+ _D(" Empty Folder %s", file_path);
+ return -ENOENT;
+ }
+
+ file_name = file_name+1;
+ _D("File name : %s ", file_name);
+
+ finfo = (struct tzip_file_info *)g_hash_table_lookup(
+ dinfo->file_hash, file_name);
+ if (!finfo) {
+ _E("File %s not found", file_path);
+ return -ENOENT;
+ }
+
+ flist->name = finfo->name;
+ copy_file_stat(&finfo->stat, &flist->stat);
+
+ return 0;
+}
+
+int get_path_prop(const char *path, struct stat *stbuf)
+{
+ int ret = 0;
+ struct tzip_file_info file;
+
+ ret = get_file_info(path, &file);
+ if (ret < 0) {
+ _E("File not found : %s ", path);
+ return -ENOENT;
+ }
+
+ if (ret == 1) {
+ stbuf->st_mode = S_IFDIR | DEFAULT_FILE_MODE;
+ stbuf->st_nlink = 1;
+ stbuf->st_size = 4096;
+ } else {
+ stbuf->st_mode = file.stat.st_mode | DEFAULT_FILE_MODE;
+ stbuf->st_nlink = 1;
+ stbuf->st_atime = file.stat.st_atime;
+ stbuf->st_mtime = file.stat.st_mtime;
+ stbuf->st_ctime = file.stat.st_ctime;
+ stbuf->st_size = file.stat.st_size;
+ }
+
+ return 0;
+}
+
+struct tzip_dir_info *get_dir_files(const char *dir)
+{
+ struct tzip_mount_entry *entry;
+ struct tzip_dir_info *dinfo;
+ int file_index = 0;
+ int dir_status;
+ int dir_len = 0;
+
+ _D("Dir path : %s ", dir);
+
+ entry = find_mount_entry(dir, &dir_status);
+ if (!entry) {
+ _E("mount_path : %s is not mounted, dir_status %d", dir, dir_status);
+ return NULL;
+ }
+
+ _D("Mount path : %s", entry->path);
+ file_index = strlen(entry->path);
+
+ dir_len = strlen(dir);
+ if (file_index == dir_len) {
+ _D("Checking dir : %s", ".");
+ dinfo = get_dir_list(entry, ".");
+ } else {
+ _D("Checking dir : %s", &dir[file_index+1]);
+ dinfo = get_dir_list(entry, &dir[file_index+1]);
+ }
+ if (!dinfo) {
+ _D(" Empty Folder %s ", dir);
+ return NULL;
+ }
+
+ return dinfo;
+}
+
+int remove_mount_entry(const char *mount_path)
+{
+ struct tzip_mount_entry *entry;
+
+ if (!mount_path) {
+ _E("Invalid mount path ");
+ return -ENOENT;
+ }
+
+ entry = (struct tzip_mount_entry *)get_mount_entry(mount_path);
+ if (!entry) {
+ _D("Mount path : %s not found", mount_path);
+ return -ENOENT;
+ }
+
+ free_mount_node(entry);
+ return 0;
+}
+
+void free_mount_node(struct tzip_mount_entry *entry)
+{
+ struct tzip_file_info *finfo;
+ struct tzip_dir_info *dinfo;
+ GHashTableIter f_iter;
+ GHashTableIter d_iter;
+ gpointer fkey, fval;
+ gpointer dkey, dval;
+
+ if (!entry->dir_hash)
+ goto out;
+
+ g_hash_table_iter_init(&d_iter, entry->dir_hash);
+ while (g_hash_table_iter_next(&d_iter, &dkey, &dval)) {
+ dinfo = (struct tzip_dir_info *)dval;
+
+ g_hash_table_iter_init(&f_iter, dinfo->file_hash);
+ while (g_hash_table_iter_next(&f_iter, &fkey, &fval)) {
+ finfo = (struct tzip_file_info *)fval;
+ g_hash_table_remove(dinfo->file_hash, fkey);
+ free(finfo->name);
+ free(finfo);
+ }
+
+ g_hash_table_remove(entry->dir_hash, dkey);
+ free(dinfo->name);
+ if (dinfo->file_hash)
+ g_hash_table_destroy(dinfo->file_hash);
+ free(dinfo);
+ }
+
+out:
+ g_hash_table_remove(hashmap, entry->path);
+ free(entry->path);
+ free(entry->zip_path);
+ if (entry->dir_hash)
+ g_hash_table_destroy(entry->dir_hash);
+ free(entry);
+}
+
+void tzip_lock_init(void)
+{
+ if (sem_init(&tzip_sem, 0, 1) == -1)
+ _E("sem_init failed");
+}
+
+void tzip_lock_deinit(void)
+{
+ if (sem_destroy(&tzip_sem) == -1)
+ _E("sem_destroy failed");
+}
+
+void tzip_lock(void)
+{
+ sem_wait(&tzip_sem);
+}
+
+void tzip_unlock(void)
+{
+ sem_post(&tzip_sem);
+}
+
+int reset_zipfile(struct tzip_handle *handle)
+{
+ int ret;
+
+ ret = unzCloseCurrentFile(handle->zipfile);
+ if (ret != UNZ_OK) {
+ _E("unzOpenCurrentFile Failed");
+ return -EINVAL;
+ }
+ if (unzLocateFile(handle->zipfile, handle->file, CASE_SENSITIVE) != UNZ_OK) {
+ _E("File :[%s] Not Found : unzLocateFile failed", handle->file);
+ return -ENOENT;
+ }
+ ret = unzOpenCurrentFile(handle->zipfile);
+ if (ret != UNZ_OK) {
+ _E("unzOpenCurrentFile Failed");
+ return -EINVAL;
+ }
+ return 0;
+}
+int read_zipfile(struct tzip_handle *handle, char *buf,
+ size_t size, off_t offset)
+{
+ int bytes_read;
+ int ret;
+
+ if (offset > handle->file_info->uncompressed_size) {
+ _E("Invalid Offset (%jd) for file size (%d)", offset, handle->file_info->uncompressed_size);
+ return -EINVAL;
+ }
+
+ if (offset != handle->offset) {
+ int diff_size;
+ /* seek and read buffer */
+ _D("offset (%jd) handle->from(%jd) (offset + size) (%jd) handle->to (%jd) handle->offset (%jd)",
+ offset, handle->from, (offset + size), handle->to, handle->offset);
+ if (offset >= handle->from && (offset + size) <= handle->to && handle->pbuf) {
+ _D("Have already read this chunk");
+ memcpy(buf, handle->pbuf + (offset - handle->from), size);
+ return size;
+ }
+
+ if (offset > handle->offset) {
+ /* read from current position */
+ diff_size = offset - handle->offset;
+ _D("Read from current position (%jd) till offset (%jd)", handle->offset, offset);
+ if (handle->pbuf)
+ free(handle->pbuf);
+
+ handle->pbuf = (char *)malloc(diff_size);
+ if (!handle->pbuf) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ bytes_read = 0;
+ do {
+ ret = unzReadCurrentFile(handle->zipfile,
+ handle->pbuf+bytes_read, diff_size - bytes_read);
+ if (ret < 0) {
+ _E("unzReadCurrentFile Failed");
+ free(handle->pbuf);
+ handle->pbuf = NULL;
+ return -EINVAL;
+ }
+ bytes_read += ret;
+ } while (bytes_read < diff_size && ret != 0);
+
+ if (bytes_read == diff_size) {
+ handle->from = handle->offset;
+ handle->to = offset;
+ } else {
+ free(handle->pbuf);
+ handle->pbuf = NULL;
+ }
+ } else if (offset) {
+ char *tmp_buf;
+ int buf_size;
+ int chunk_count;
+ int i;
+
+ /* read from the begining*/
+ _D("Read from the begining till offset (%jd)", offset);
+ if (offset < 0)
+ diff_size = handle->offset + offset;
+ else
+ diff_size = offset;
+
+ if (reset_zipfile(handle)) {
+ _E("reset_zipfile Failed");
+ return -EINVAL;
+ }
+
+ /* dont read more than MAX_CHUNK_SIZE at once */
+ if (diff_size < MAX_CHUNK_SIZE)
+ buf_size = diff_size;
+ else
+ buf_size = MAX_CHUNK_SIZE;
+
+ tmp_buf = (char *)malloc(buf_size);
+ if (!tmp_buf) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+
+ /* chunk_count will have total number of chunks to read to reach offset position */
+ chunk_count = diff_size/buf_size;
+ if (diff_size % buf_size)
+ chunk_count += 1;
+
+ for (i = 0; i < chunk_count; i++) {
+ /* adjust last chunk size according to offset */
+ if (chunk_count > 1 && chunk_count == i + 1)
+ buf_size = diff_size - (buf_size * i);
+ bytes_read = 0;
+ do {
+ ret = unzReadCurrentFile(handle->zipfile,
+ tmp_buf+bytes_read, buf_size - bytes_read);
+ if (ret < 0) {
+ _E("unzReadCurrentFile Failed");
+ free(tmp_buf);
+ return -EINVAL;
+ }
+ bytes_read += ret;
+ } while (bytes_read < buf_size && ret != 0);
+ if (!ret) {
+ _E("EOF reached");
+ break;
+ }
+ }
+ free(tmp_buf);
+ }
+ }
+
+ bytes_read = 0;
+ do {
+ ret = unzReadCurrentFile(handle->zipfile,
+ buf + bytes_read, size - bytes_read);
+ if (ret < 0) {
+ _E("unzReadCurrentFile Failed");
+ return -EINVAL;
+ }
+ bytes_read += ret;
+ } while (bytes_read < size && ret != 0);
+
+ /* store current zip position for subsequent read */
+ handle->offset = offset + bytes_read;
+
+ _D("bytes_read : %d [offset : %jd, total size : %d]", bytes_read, handle->offset, handle->file_info->uncompressed_size);
+ return bytes_read;
+}
+
+GHashTable *hashmap_init(void)
+{
+ hashmap = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+
+ return hashmap;
+}
+
+GHashTable *get_hashmap(void)
+{
+ return hashmap;
+}
+
+int tzip_store_mount_info(const char *zip_path, const char *mount_path)
+{
+ FILE *fp;
+ int len;
+ int ret = 0;
+ char *file_entry;
+
+ if (!zip_path || !mount_path) {
+ _E("Invalid Arguments path : %p buf %p ", zip_path, mount_path);
+ return -ENOENT;
+ }
+ _D("zip_path - : [%s] mount_path : [%s] ", zip_path, mount_path);
+
+ fp = fopen(TZIP_INFO_FILE, "a+");
+ if (fp == NULL) {
+ _E("fopen() Failed!!!");
+ return -EIO;
+ }
+
+ len = sizeof(char) * (strlen(zip_path) + strlen(mount_path) + 3);
+ file_entry = (char *)malloc(len);
+ if (!file_entry) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+ snprintf(file_entry, len, "%s:%s\n", zip_path, mount_path);
+
+ len = strlen(file_entry);
+ if (fwrite(file_entry, sizeof(char), len, fp) != len) {
+ _E(" fwrite Failed !!!! ");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ free(file_entry);
+ fclose(fp);
+ return ret;
+}
+
+int tzip_remount_zipfs(const char *src_file, const char *mount_point)
+{
+ int ret = 0;
+ char *tzip_path;
+ int path_len, mp_len;
+
+ if (!src_file || !mount_point) {
+ _E("Invalid Arguments src_file : %p mount_point %p ", src_file, mount_point);
+ return -EINVAL;
+ }
+
+ ret = add_mount_entry(src_file, mount_point);
+ if (ret) {
+ _E("Failed to add_mount_entry %s", mount_point);
+ return ret;
+ }
+
+ path_len = sizeof(TZIP_ROOT_PATH); /* strlen(TZIP_ROOT_PATH) + 1 */
+ mp_len = strlen(mount_point);
+ tzip_path = (char *)malloc(path_len + mp_len);
+ if (!tzip_path) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+ strncpy(tzip_path, TZIP_ROOT_PATH, path_len);
+ strncat(tzip_path, mount_point, mp_len);
+
+ _D("creating sym link : %s and %s", tzip_path, mount_point);
+ ret = unlink(mount_point);
+ if (ret) {
+ _E("unlink failed");
+ ret = -errno;
+ goto out;
+ }
+
+ ret = symlink(tzip_path, mount_point);
+ if (ret) {
+ _E("symlink failed");
+ ret = -errno;
+ goto out;
+ }
+
+out:
+ if (ret < 0)
+ remove_mount_entry(mount_point);
+ free(tzip_path);
+ _D("Exit : %d", ret);
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __TZIP_UTILITY_H__
+#define __TZIP_UTILITY_H__
+
+#include <stdio.h>
+#include <glib.h>
+
+#define TZIP_ROOT_PATH "/run/tzip"
+
+#define MAX_FILENAME_LEN 256
+
+#define DIR_DELIMETER '/'
+
+#define DEFAULT_FILE_MODE 0755
+
+#define TZIP_INFO_FILE "/run/.deviced"
+
+#define TZIP_MSGQ_NAME "/tzipmsgq"
+
+#define CASE_SENSITIVE 1
+
+#define MAX_CHUNK_SIZE 4096
+
+/* structure for storing a file info */
+struct tzip_file_info {
+ char *name;
+ struct stat stat;
+};
+
+/* structure for storing a dir info */
+struct tzip_dir_info {
+ char *name;
+ struct stat stat;
+ GHashTable *file_hash; /* hash table for storing all files present in a given directory */
+};
+
+/* table containing mount path and corresponding files */
+struct tzip_mount_entry {
+ char *path;
+ char *zip_path;
+ GHashTable *dir_hash; /* hash table for storing all directory info of a given zip file */
+};
+
+/* Structure containing Zip file handle */
+struct tzip_handle {
+ unzFile *zipfile;
+ unz_file_info *file_info;
+ char *path;
+ char *file;
+ off_t offset;
+ off_t from;
+ off_t to;
+ char *pbuf;
+ sem_t lock;
+};
+
+/* structure containing message queue data */
+struct tzip_msg_data {
+ char type; /* 'm' for mount , 'u' for unmount */
+ char *zippath;
+ char *mountpath;
+ char *smack;
+};
+
+struct tzip_dir_info *get_dir_files(const char *dir);
+int add_mount_entry(const char *zip_path, const char *mount_path);
+int remove_mount_entry(const char *mount_path);
+int get_path_prop(const char *path, struct stat *stbuf);
+struct tzip_mount_entry *get_mount_entry(const char *mount_path);
+struct tzip_mount_entry *find_mount_entry(const char *mount_path, int *dir_status);
+void tzip_lock_init(void);
+void tzip_lock_deinit(void);
+void tzip_lock(void);
+void tzip_unlock(void);
+
+/* local function declrations */
+int get_file_info(const char *file_path, struct tzip_file_info *file_info);
+void copy_file_stat(struct stat *src, struct stat *dest);
+int extract_zipfile_details(struct tzip_mount_entry *node, const char *zip_path);
+int add_path_dirs_info(struct tzip_mount_entry *entry, const char *path, unz_file_info *file_info, mode_t mode);
+int add_dir_info(struct tzip_mount_entry *mnode, const char *parent_dir, const char *dir, unz_file_info *file_info, mode_t mode);
+void fileinfo_to_stat(unz_file_info *file_info, struct stat *file_stat, mode_t mode);
+struct tzip_dir_info *get_dir_list(struct tzip_mount_entry *dir_node, const char *dir_name);
+void free_mount_node(struct tzip_mount_entry *mount_node);
+int reset_zipfile(struct tzip_handle *handle);
+int read_zipfile(struct tzip_handle *handle, char *buf, size_t size, off_t offset);
+GHashTable *hashmap_init(void);
+GHashTable *get_hashmap(void);
+int tzip_store_mount_info(const char* zip_path, const char* mount_path);
+int tzip_remount_zipfs(const char *src_file, const char *mount_point);
+#endif /* __TZIP_UTILITY_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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.
+ */
+
+#define FUSE_USE_VERSION 26
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+#include "core/list.h"
+#include "core/device-notifier.h"
+#include "core/common.h"
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unzip.h>
+#include <pthread.h>
+#include <signal.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <attr/xattr.h>
+#include <linux/limits.h>
+#include <tzplatform_config.h>
+
+#include "tzip.h"
+#include "tzip-utility.h"
+
+
+static pthread_t thread;
+static pthread_t mount_thread;
+static pthread_attr_t attr;
+static struct fuse *fuse_handle = NULL;
+static struct fuse_chan *channel = NULL;
+static GAsyncQueue *async_queue;
+
+static int check_smack_label(pid_t pid)
+{
+ char attr[64];
+ size_t len;
+ int ret;
+
+ ret = get_privilege(pid, attr, sizeof(attr));
+ if (ret < 0) {
+ _E("Failed to get privilege of PID(%d)", pid);
+ return 0;
+ }
+
+ len = strlen(attr) + 1;
+
+ if (!strncmp("System", attr, len))
+ return 1;
+
+ if (!strncmp("User", attr, len))
+ return 1;
+
+ if (!strncmp("System::Privileged", attr, len))
+ return 1;
+
+ return 0;
+}
+
+static int check_path_available(char *mountpath)
+{
+ const char *path;
+
+ if (!mountpath)
+ return 0;
+
+ path = tzplatform_getenv(TZ_SYS_HOME);
+ if (path && !strncmp(mountpath, path, strlen(path)))
+ return 1;
+
+ path = tzplatform_getenv(TZ_SYS_RW_APP);
+ if (path && !strncmp(mountpath, path, strlen(path)))
+ return 1;
+
+ return 0;
+}
+
+static int is_app_privileged(pid_t pid, char *mountpath)
+{
+ int priv;
+
+ priv = check_path_available(mountpath);
+ if (priv == 0) {
+ _E("TZIP mount path is invalid (%s)", mountpath);
+ return priv;
+ }
+
+ priv = check_smack_label(pid);
+ if (priv == 0)
+ _E("PID (%d) cannot use TZIP due to smack label");
+
+ return priv;
+}
+
+static int tzip_getattr(const char *path, struct stat *stbuf)
+{
+ int res = 0;
+
+ if (!path || !stbuf) {
+ _E("Invalid Arguments path : %p stbuf %p ", path, stbuf);
+ return -EINVAL;
+ }
+
+ _D("Get ATTR path [%s]", path);
+
+ tzip_lock();
+ res = get_path_prop(path, stbuf);
+ tzip_unlock();
+
+ _D("Exit : %d \n", res);
+
+ return res;
+}
+
+static int tzip_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ struct tzip_dir_info *flist;
+ GHashTableIter iter;
+ gpointer key, value;
+ char *name;
+ int ret;
+
+ if (!path || !buf) {
+ _E("Invalid Arguments path : %p buf %p ", path, buf);
+ return -EINVAL;
+ }
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+
+ tzip_lock();
+ flist = get_dir_files(path);
+ if (flist == NULL) {
+ _E("No Files in Dir : %s ", path);
+ ret = 0;
+ goto out_unlock;
+ }
+
+ g_hash_table_iter_init(&iter, flist->file_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ name = (char *)key;
+ filler(buf, name, NULL, 0);
+ }
+
+ ret = 0;
+
+out_unlock:
+ tzip_unlock();
+
+ return ret;
+}
+
+static int tzip_open(const char *path, struct fuse_file_info *fi)
+{
+ int ret;
+ char *file = NULL;
+ char *zippath = NULL;
+ int dir_status;
+ struct tzip_mount_entry *entry = NULL;
+ struct tzip_handle *handle = NULL;
+ unz_file_info *file_info = NULL;
+ unz_global_info global_info;
+ unzFile *zipfile = NULL;
+ int len;
+ int file_len;
+
+ if (!path || !fi) {
+ _E("Invalid Arguments path : %p fi : %p", path, fi);
+ return -EINVAL;
+ }
+ _D("Open - Path : %s", path);
+
+ tzip_lock();
+ entry = find_mount_entry(path, &dir_status);
+ if (!entry) {
+ _E("Mount Entry Not Found ");
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ len = strlen(entry->zip_path) + 1;
+ zippath = (char *)malloc(len);
+ if (!zippath) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+ snprintf(zippath, len, "%s", entry->zip_path);
+
+ len = strlen(entry->path);
+ file_len = strlen(path) - len + 1;
+ file = (char *)malloc(file_len);
+ if (!file) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+ strncpy(file, path + len + 1, file_len);
+ tzip_unlock();
+
+ zipfile = unzOpen(zippath);
+ if (!zipfile) {
+ _E("unzOpen Failed");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /* Get info about the zip file */
+ if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK) {
+ _E("unzGetGlobalInfo Failed");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (unzLocateFile(zipfile, file, CASE_SENSITIVE) != UNZ_OK) {
+ _E("File :[%s] Not Found : unzLocateFile failed", file);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ file_info = (unz_file_info *)malloc(sizeof(unz_file_info));
+ if (!file_info) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = unzGetCurrentFileInfo(zipfile, file_info, (char *)file,
+ strlen(file), NULL, 0, NULL, 0);
+ if (ret != UNZ_OK) {
+ _E("unzGetCurrentFileInfo Failed");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = unzOpenCurrentFile(zipfile);
+ if (ret != UNZ_OK) {
+ _E("unzOpenCurrentFile Failed");
+ ret = -EINVAL;
+ goto out;
+ }
+ handle = (struct tzip_handle *)malloc(sizeof(struct tzip_handle));
+ if (!handle) {
+ unzCloseCurrentFile(zipfile);
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+ handle->file_info = file_info;
+ handle->zipfile = zipfile;
+ handle->offset = 0;
+ handle->path = zippath;
+ handle->file = file;
+ handle->pbuf = NULL;
+ handle->from = 0;
+ handle->to = 0;
+ if (sem_init(&handle->lock, 0, 1) == -1)
+ _E("sem_init failed");
+
+#ifdef ARCH_32BIT
+ int hd = (int)handle;
+ fi->fh = (uint64_t)hd;
+#else
+ fi->fh = (uint64_t)handle;
+#endif
+ return 0;
+
+out_unlock:
+ tzip_unlock();
+out:
+ free(zippath);
+ free(file);
+ free(file_info);
+ if (zipfile)
+ unzClose(zipfile);
+ return ret;
+}
+
+static int tzip_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
+{
+ struct tzip_handle *handle;
+ int ret;
+
+ if (!path || !buf) {
+ _E("Invalid Arguments path : %p buf %p ", path, buf);
+ return -EINVAL;
+ }
+ if (!fi || fi->fh == 0) {
+ _E("Invalid Zip Handle ");
+ return -EINVAL;
+ }
+
+#ifdef ARCH_32BIT
+ int hd = (int)fi->fh;
+ handle = (struct tzip_handle *)hd;
+#else
+ handle = (struct tzip_handle *)(fi->fh);
+#endif
+
+ _D("Read - Path : %s size : %zd offset : %jd ", path, size, offset);
+ sem_wait(&handle->lock);
+ ret = read_zipfile(handle, buf, size, offset);
+ sem_post(&handle->lock);
+ _D("Read ret = %d", ret);
+ return ret;
+}
+
+static int tzip_release(const char *path, struct fuse_file_info *fi)
+{
+ struct tzip_handle *handle;
+
+ if (!path) {
+ _E("Invalid Arguments path : %p", path);
+ return -EINVAL;
+ }
+ if (!fi || fi->fh == 0) {
+ _E("Invalid Zip Handle ");
+ return -EINVAL;
+ }
+
+#ifdef ARCH_32BIT
+ int hd = (int)fi->fh;
+ handle = (struct tzip_handle *)hd;
+#else
+ handle = (struct tzip_handle *)(fi->fh);
+#endif
+
+ if (sem_destroy(&handle->lock) == -1)
+ _E("sem_destroy failed");
+
+ unzCloseCurrentFile(handle->zipfile);
+ unzClose(handle->zipfile);
+ free(handle->file);
+ free(handle->path);
+ free(handle->file_info);
+ if (handle->pbuf)
+ free(handle->pbuf);
+ free(handle);
+
+ return 0;
+}
+
+static struct fuse_operations tzip_oper = {
+ .getattr = tzip_getattr,
+ .open = tzip_open,
+ .read = tzip_read,
+ .release = tzip_release,
+ .readdir = tzip_readdir,
+};
+
+static void *tzip_thread(void *arg)
+{
+ int ret;
+ GHashTable *hash;
+ FILE *fp;
+ char *file_path;
+ char *mount_dir;
+ char *mount_info = NULL;
+ size_t len;
+ ssize_t read;
+ char *saveptr = NULL;
+ char *argv[4] = {"deviced", "-o", "allow_other", NULL};
+ struct fuse_args args = FUSE_ARGS_INIT(3, argv);
+
+ ret = mkdir(TZIP_ROOT_PATH, 0755);
+ if (ret < 0 && errno != EEXIST) {
+ _E("fail to make dir %s", TZIP_ROOT_PATH);
+ return NULL;
+ }
+
+ tzip_lock();
+ channel = fuse_mount(TZIP_ROOT_PATH, &args);
+ if (!channel) {
+ _E("Trying to mount after cleaning up previous instance %p ", TZIP_ROOT_PATH);
+ fuse_unmount(TZIP_ROOT_PATH, NULL);
+
+ channel = fuse_mount(TZIP_ROOT_PATH, NULL);
+ if (!channel) {
+ _E("Failed at mount_point %p ", TZIP_ROOT_PATH);
+ goto out_unlock;
+ }
+ }
+
+ fuse_handle = fuse_new(channel, NULL,
+ &tzip_oper, sizeof(tzip_oper), NULL);
+ if (!fuse_handle) {
+ _E("Failed at fuse_new");
+ goto out_unlock;
+ }
+
+ /* initialize string hash table */
+ hash = hashmap_init();
+ if (!hash) {
+ _E("Failed at hashmap_init");
+ goto out_unlock;
+ }
+ fp = fopen(TZIP_INFO_FILE, "r");
+ if (fp) {
+ while ((read = getline(&mount_info, &len, fp)) != -1) {
+ if (mount_info) {
+ mount_info[strcspn(mount_info, "\n")] = '\0';
+ file_path = (char *)strtok_r(mount_info, ":", &saveptr);
+ mount_dir = (char *)strtok_r(NULL, ":", &saveptr);
+
+ if (file_path != NULL && mount_dir != NULL)
+ tzip_remount_zipfs(file_path, mount_dir);
+ free(mount_info);
+ mount_info = NULL;
+ }
+ }
+ fclose(fp);
+ }
+ tzip_unlock();
+
+ if (fuse_loop_mt(fuse_handle)) {
+ _E("Failed at fuse_loop_mt");
+ goto out;
+ }
+
+ tzip_lock();
+ if (fuse_handle) {
+ fuse_destroy(fuse_handle);
+ fuse_handle = NULL;
+ }
+
+out_unlock:
+ tzip_unlock();
+out:
+ return NULL;
+}
+
+static void *tzip_mount_thread(void *arg)
+{
+ struct tzip_msg_data *msgdata;
+ int ret = 0;
+
+ /* if g_async_queue_new() fails, tzip mount/unmount requests can not be handled */
+ async_queue = g_async_queue_new();
+ assert(async_queue);
+
+ while (1) {
+ /* g_async_queue_pop() is a blocking call, it should never return NULL */
+ msgdata = (struct tzip_msg_data *)g_async_queue_pop(async_queue);
+ assert(msgdata);
+
+ if (msgdata->type == 'm') {
+ ret = tzip_mount_zipfs(msgdata->zippath, msgdata->mountpath,
+ msgdata->smack);
+ free(msgdata->zippath);
+ free(msgdata->mountpath);
+ if (msgdata->smack)
+ free(msgdata->smack);
+ } else if (msgdata->type == 'u') {
+ ret = tzip_unmount_zipfs(msgdata->mountpath);
+ free(msgdata->mountpath);
+ }
+ free(msgdata);
+
+ if (ret)
+ _E("Failed to process mount/unmount request");
+ }
+
+ /* dead code, added just to satisfy compiler */
+ return NULL;
+}
+
+void tzip_server_init(void)
+{
+ if (pthread_attr_init(&attr) != 0)
+ _E("pthread_attr_init Failed");
+
+ if (pthread_create(&thread, &attr, &tzip_thread, NULL))
+ _E("pthread_create Failed");
+
+ if (pthread_create(&mount_thread, &attr, &tzip_mount_thread, NULL))
+ _E("pthread_create Failed");
+}
+
+void tzip_server_exit(void)
+{
+ if (!fuse_handle || !channel)
+ return;
+
+ tzip_lock();
+ fuse_exit(fuse_handle);
+ fuse_unmount(TZIP_ROOT_PATH, channel);
+ fuse_destroy(fuse_handle);
+ fuse_handle = NULL;
+ channel = NULL;
+ tzip_unlock();
+}
+
+static int tzip_check_mount_point(const char *mount_point)
+{
+ int ret;
+
+ if (unlink(mount_point) == 0)
+ return 0;
+
+ ret = errno;
+ if (ret == ENOENT)
+ return 0;
+
+ _E("Failed to remove previous symlink file(errno:%d)", ret);
+ return ret;
+}
+
+int tzip_mount_zipfs(const char *src_file, const char *mount_point, const char *smack)
+{
+ int ret = 0;
+ char *tzip_path = NULL;
+ int path_len, mp_len;
+
+ tzip_lock();
+
+ ret = add_mount_entry(src_file, mount_point);
+ if (ret) {
+ _E("Failed to add_mount_entry %s", mount_point);
+ goto out;
+ }
+
+ ret = tzip_check_mount_point(mount_point);
+ if (ret < 0) {
+ _E("Failed to mount via tzip (ret:%d)", ret);
+ remove_mount_entry(mount_point);
+ goto out;
+ }
+
+ path_len = sizeof(TZIP_ROOT_PATH); /* strlen(TZIP_ROOT_PATH) + 1 */
+ mp_len = strlen(mount_point);
+ tzip_path = (char *)malloc(path_len + mp_len);
+ if (!tzip_path) {
+ _E("Malloc failed");
+ remove_mount_entry(mount_point);
+ ret = -ENOMEM;
+ goto out;
+ }
+ strncpy(tzip_path, TZIP_ROOT_PATH, path_len);
+ strncat(tzip_path, mount_point, mp_len);
+
+ _D("creating sym link : %s and %s", tzip_path, mount_point);
+ ret = symlink(tzip_path, mount_point);
+ if (ret) {
+ _E("symlink failed");
+ remove_mount_entry(mount_point);
+ ret = -errno;
+ } else {
+ ret = tzip_store_mount_info(src_file, mount_point);
+ if (ret != 0)
+ _E("Failed to store_mount_info %s", mount_point);
+
+ if (smack) {
+ ret = lsetxattr(mount_point, "security.SMACK64", smack, strlen(smack), 0);
+ if (ret < 0) {
+ _E("setting smack label using lsetxattr() failed");
+ remove_mount_entry(mount_point);
+ ret = -errno;
+ }
+ }
+ }
+
+out:
+ tzip_unlock();
+ free(tzip_path);
+ _D("Exit : %d", ret);
+ return ret;
+}
+
+int tzip_unmount_zipfs(const char *mount_point)
+{
+ int ret = 0;
+ char *tzip_path = NULL;
+ int path_len, mp_len;
+
+ tzip_lock();
+ ret = remove_mount_entry(mount_point);
+ if (ret) {
+ _E("Failed to remove_mount_entry %s", mount_point);
+ goto out_unlock;
+ }
+
+ path_len = sizeof(TZIP_ROOT_PATH); /* strlen(TZIP_ROOT_PATH) + 1 */
+ mp_len = strlen(mount_point);
+ tzip_path = (char *)malloc(path_len + mp_len);
+ if (!tzip_path) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+ strncpy(tzip_path, TZIP_ROOT_PATH, path_len);
+ strncat(tzip_path, mount_point, mp_len);
+
+ _D("deleting sym link : %s and %s", tzip_path, mount_point);
+ ret = unlink(mount_point);
+ if (ret) {
+ _E("unlink failed");
+ ret = -errno;
+ }
+
+out_unlock:
+ tzip_unlock();
+ free(tzip_path);
+ _D("Exit : %d", ret);
+ return ret;
+}
+
+int tzip_is_mounted(const char *mount_point)
+{
+ struct tzip_mount_entry *entry = NULL;
+ int ret = 0;
+ char *tzip_path;
+ struct stat sb;
+ int path_len, mp_len;
+
+ if (!mount_point) {
+ _E("Invalid Arguments mount_point %p ", mount_point);
+ return -EINVAL;
+ }
+
+ if (!get_hashmap()) {
+ _E("tzip init is not done yet");
+ return 0;
+ }
+
+ entry = get_mount_entry(mount_point);
+ if (!entry) {
+ _E("mount_path : %s does not exists ", mount_point);
+ return 0;
+ }
+
+ path_len = sizeof(TZIP_ROOT_PATH); /* strlen(TZIP_ROOT_PATH) + 1 */
+ mp_len = strlen(mount_point);
+ tzip_path = (char *)malloc(path_len + mp_len);
+ if (!tzip_path) {
+ _E("Malloc failed");
+ return -ENOMEM;
+ }
+ strncpy(tzip_path, TZIP_ROOT_PATH, path_len);
+ strncat(tzip_path, mount_point, mp_len);
+
+ if (stat(tzip_path, &sb) == -1 || stat(mount_point, &sb) == -1)
+ ret = 0;
+ else
+ ret = 1;
+
+ free(tzip_path);
+ return ret;
+}
+
+static DBusMessage *edbus_request_mount_tzip(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *zippath;
+ char *mountpath;
+ char *smack;
+ int ret;
+ struct tzip_msg_data *msgdata = NULL;
+ pid_t pid;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &mountpath,
+ DBUS_TYPE_STRING, &zippath,
+ DBUS_TYPE_STRING, &smack,
+ DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!mountpath || !zippath) {
+ _E("invalid input");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (!is_app_privileged(pid, mountpath)) {
+ _E("PID (%d) is not privileged to use tzip", pid);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (!fuse_handle)
+ tzip_server_init();
+
+ msgdata = malloc(sizeof(struct tzip_msg_data));
+ if (!msgdata) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ msgdata->type = 'm';
+ msgdata->zippath = strdup(zippath);
+ msgdata->mountpath = strdup(mountpath);
+ if (!msgdata->zippath ||
+ !msgdata->mountpath) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (smack) {
+ msgdata->smack = strdup(smack);
+ if (!msgdata->smack) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+ } else /* Use default smack */
+ msgdata->smack = NULL;
+
+ if (async_queue) {
+ g_async_queue_push(async_queue, (gpointer)msgdata);
+ ret = 0;
+ } else
+ ret = -EAGAIN;
+
+out:
+ if (ret < 0 && msgdata) {
+ free(msgdata->zippath);
+ free(msgdata->mountpath);
+ if (msgdata->smack)
+ free(msgdata->smack);
+ free(msgdata);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_request_unmount_tzip(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *mountpath;
+ int ret;
+ struct tzip_msg_data *msgdata = NULL;
+ pid_t pid;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &mountpath, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!mountpath) {
+ _E("invalid input");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pid = get_edbus_sender_pid(msg);
+ if (!is_app_privileged(pid, mountpath)) {
+ _E("PID (%d) is not privileged to use tzip", pid);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (!fuse_handle)
+ tzip_server_init();
+
+ msgdata = malloc(sizeof(struct tzip_msg_data));
+ if (!msgdata) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ msgdata->type = 'u';
+ msgdata->mountpath = strdup(mountpath);
+ if (!msgdata->mountpath) {
+ _E("Malloc failed");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (async_queue) {
+ g_async_queue_push(async_queue, (gpointer)msgdata);
+ ret = 0;
+ } else
+ ret = -ENOMEM;
+
+out:
+ if (ret < 0 && msgdata) {
+ free(msgdata->mountpath);
+ free(msgdata);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static DBusMessage *edbus_request_ismounted_tzip(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ char *mountpath;
+ int ret;
+
+ dbus_error_init(&err);
+
+ if (!dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &mountpath, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = tzip_is_mounted(mountpath);
+
+out:
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "Mount", "sss", "i", edbus_request_mount_tzip },
+ { "Unmount", "s", "i", edbus_request_unmount_tzip },
+ { "IsMounted", "s", "i", edbus_request_ismounted_tzip },
+ /* Add methods here */
+};
+
+static int booting_done(void *data)
+{
+ if (!fuse_handle)
+ tzip_server_init();
+
+ return 0;
+}
+
+static int tzip_poweroff(void *data)
+{
+ _I("TZIP poweroff");
+ tzip_server_exit();
+ return 0;
+}
+
+static void tzip_init(void *data)
+{
+ int ret;
+ _D("tzip_init ");
+
+ tzip_lock_init();
+
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ register_notifier(DEVICE_NOTIFIER_POWEROFF, tzip_poweroff);
+
+ ret = register_edbus_interface_and_method(DEVICED_PATH_TZIP,
+ DEVICED_INTERFACE_TZIP,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to init edbus method(%d)", ret);
+}
+
+static void tzip_exit(void *data)
+{
+ _D("tzip_exit ");
+ tzip_server_exit();
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+ unregister_notifier(DEVICE_NOTIFIER_POWEROFF, tzip_poweroff);
+
+ tzip_lock_deinit();
+}
+
+static const struct device_ops tzip_device_ops = {
+ .name = "tzip",
+ .init = tzip_init,
+ .exit = tzip_exit,
+};
+
+DEVICE_OPS_REGISTER(&tzip_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __TZIP_H__
+#define __TZIP_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief mounts a zip file to a particular system path.
+ * @remarks This is asynchronous method, zip file is mounted or not should be checked using tzip_is_mounted(mount_path) before using mounted path.
+ * @since_tizen 3.0
+ * @param[in] zip_file The input zip file
+ * @param[in] mount_path The mount path
+ * @param[in] smack Smack label for mount path
+ * @return @c 0 if the mount operation is successful, \n @c negative error code if the mount operation fails
+ */
+int tzip_mount_zipfs(const char *zip_file, const char *mount_path, const char *smack);
+
+/**
+ * @brief unmounts a already mounted path
+ * @since_tizen 3.0
+ * @param[in] mount_path The mounted path
+ * @return @c 0 if the unmount operation is successful, \n @c negative error code if the unmount operation fails
+ */
+int tzip_unmount_zipfs(const char *mount_path);
+
+/**
+ * @brief checks if given path is mounted
+ * @since_tizen 3.0
+ * @param[in] mount_path The mount path
+ * @return @c 1 if the given path is mounted and 0 if it is not mounted, \n @c negative error code if this operation fails
+ */
+int tzip_is_mounted(const char *mount_path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __TZIP_H__
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(usb-host-ffs-test-daemon C)
+
+SET(SRCS
+ usb-host-ffs-test-daemon.c
+)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions")
+INCLUDE(FindPkgConfig)
+pkg_check_modules(SYSTEMD REQUIRED libsystemd)
+FOREACH(flag ${SYSTEMD_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${SYSTEMD_LDFLAGS})
+
+ADD_EXECUTABLE(descs_gen descs_gen.c)
+ADD_CUSTOM_COMMAND(OUTPUT descs strs
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/descs_gen
+ DEPENDS descs_gen)
+ADD_CUSTOM_TARGET(descriptors ALL DEPENDS descs strs)
+
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/descs DESTINATION /etc/deviced/usb-host-test)
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/strs DESTINATION /etc/deviced/usb-host-test)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin)
--- /dev/null
+#include <linux/usb/functionfs.h>
+#include <linux/usb/ch9.h>
+#include <stdio.h>
+#include <endian.h>
+
+/******************** Descriptors and Strings *******************************/
+
+#define MISSING_DESC_HEAD
+#ifdef MISSING_DESC_HEAD
+enum {
+ FUNCTIONFS_DESCRIPTORS_MAGIC_V2 = 3,
+};
+
+enum functionfs_flags {
+ FUNCTIONFS_HAS_FS_DESC = 1,
+ FUNCTIONFS_HAS_HS_DESC = 2,
+};
+
+struct usb_functionfs_descs_head_v2 {
+ __le32 magic;
+ __le32 length;
+ __le32 flags;
+ /*
+ * __le32 fs_count, hs_count, fs_count; must be included manually in
+ * the structure taking flags into consideration.
+ */
+} __attribute__((packed));
+#endif
+
+static const struct {
+ struct usb_functionfs_descs_head header;
+ struct {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio bulk_in;
+ struct usb_endpoint_descriptor_no_audio bulk_out;
+ } __attribute__ ((__packed__)) fs_descs, hs_descs;
+} __attribute__ ((__packed__)) descriptors = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(descriptors)),
+ .fs_count = htole32(3),
+ .hs_count = htole32(3),
+ },
+ .fs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.fs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_in = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_in),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .bulk_out = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_out),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ },
+ .hs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.hs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_in = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_in),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = htole16(512),
+ },
+ .bulk_out = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_out),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = htole16(512),
+ },
+ },
+};
+
+#define STR_INTERFACE "loop input to output"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE)];
+ } __attribute__ ((__packed__)) lang0;
+} __attribute__ ((__packed__)) strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE,
+ },
+};
+
+int main()
+{
+ int ret;
+ FILE *sfp, *dfp;
+
+ dfp = fopen("descs", "w");
+ if (!dfp) {
+ perror("Could not open descritptors file");
+ return -1;
+ }
+
+ sfp = fopen("strs", "w");
+ if (!sfp) {
+ perror("Could not open strings file");
+ return -1;
+ }
+
+ ret = fwrite(&descriptors, sizeof(descriptors), 1, dfp);
+ if (ret < 0) {
+ perror("Could not write descriptors");
+ goto out;
+ }
+
+ ret = fwrite(&strings, sizeof(strings), 1, sfp);
+ if (ret < 0) {
+ perror("Could not write strings");
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ fclose(sfp);
+ fclose(dfp);
+
+ return ret;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <poll.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/eventfd.h>
+
+#include <linux/usb/functionfs.h>
+#include <systemd/sd-daemon.h>
+
+#define FFS_PATH "/tmp/usb-host-test-ffs"
+
+#define EP_IN_IDX 1
+#define EP_OUT_IDX 2
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define report_error(...) do { \
+ fprintf(stderr, __VA_ARGS__); \
+ putchar('\n'); \
+ } while (0)
+
+char buf[512];
+
+/* Close all ep files */
+void cleanup_ffs(int *ep)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ close(ep[i]);
+}
+
+/* Handle events generated by kernel and provided via ep0 */
+int handle_ep0(int ep0, int *connected)
+{
+ struct usb_functionfs_event event;
+ int ret;
+
+ ret = read(ep0, &event, sizeof(event));
+ if (!ret) {
+ report_error("unable to read event from ep0");
+ return -EIO;
+ }
+
+ switch (event.type) {
+ case FUNCTIONFS_SETUP:
+ /* stall for all setuo requests */
+ if (event.u.setup.bRequestType & USB_DIR_IN) {
+ if (write(ep0, NULL, 0) < 0)
+ report_error("write error %d", errno);
+ } else {
+ if (read(ep0, NULL, 0) < 0)
+ report_error("read error %d", errno);
+ }
+ break;
+
+ case FUNCTIONFS_ENABLE:
+ *connected = 1;
+ break;
+
+ case FUNCTIONFS_DISABLE:
+ *connected = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* main chat function */
+void do_chat(int *ep)
+{
+ int connected = 0;
+ int ret;
+
+ while (1) {
+ while (!connected) {
+ ret = handle_ep0(ep[0], &connected);
+ if (ret < 0)
+ return;
+ }
+ while (connected) {
+ ret = read(ep[EP_OUT_IDX], buf, sizeof(buf));
+ if (ret < 0) {
+ if (ret == -ECONNRESET) {
+ printf("Connection lost.");
+ break;
+ }
+ return;
+ }
+
+ ret = write(ep[EP_IN_IDX], buf, ret);
+ if (ret < 0) {
+ if (ret == -ECONNRESET) {
+ printf("Connection lost.");
+ break;
+ }
+ return;
+ }
+
+ }
+
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ep[3];
+ int i = 0;
+
+ if (sd_listen_fds(0) < 3) {
+ fprintf(stderr, "Expected endpoints not retrieved\n");
+ return -1;
+ }
+
+ for (i = 0; i < 3; ++i)
+ ep[i] = SD_LISTEN_FDS_START + i;
+
+ do_chat(ep);
+ cleanup_ffs(ep);
+
+ return 0;
+}
--- /dev/null
+attrs :
+{
+ bcdUSB = 0x200;
+ bDeviceClass = 0x0;
+ bDeviceSubClass = 0x0;
+ bDeviceProtocol = 0x0;
+ bMaxPacketSize0 = 0x40;
+ idVendor = 0x1D6B;
+ idProduct = 0x104;
+ bcdDevice = 0x1;
+};
+strings = (
+ {
+ lang = 0x409;
+ manufacturer = "Foo Inc.";
+ product = "Bar Gadget";
+ serialnumber = "0123456789";
+ } );
+functions :
+{
+ ffs_instance1 :
+ {
+ instance = "usb-host-test";
+ type = "ffs";
+ attrs :
+ {
+ };
+ };
+};
+configs = (
+ {
+ id = 1;
+ name = "The only one";
+ attrs :
+ {
+ bmAttributes = 0x80;
+ bMaxPower = 0x2;
+ };
+ strings = (
+ {
+ lang = 0x409;
+ configuration = "usb host API test config";
+ } );
+ functions = (
+ {
+ name = "some_name_here";
+ function = "ffs_instance1";
+ });
+ } );
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <libkmod.h>
+#include <usbg/usbg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "core/log.h"
+#include "core/config-parser.h"
+#include "core/device-idler.h"
+#include "core/device-notifier.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+#include "core/list.h"
+#include "shared/deviced-systemd.h"
+
+#define FFS_PATH "/run/usb-host-test-ffs"
+#define GADGET_SCHEME_PATH "/etc/deviced/usb-host-test/test_gadget.gs"
+#define FFS_INSTANCE_NAME "usb-host-test"
+#define GADGET_NAME "g1"
+#define SYSTEMD_UNIT_NAME "usb-host-test.socket"
+#define SYSTEMD_SERVICE_NAME "usb-host-ffs-test-daemon.service"
+#define UDC_NAME "dummy_udc.0"
+#define CONFIGFS_PATH "/sys/kernel/config/"
+
+#define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1"
+#define JOB_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager"
+#define JOB_REMOVED "JobRemoved"
+
+static E_DBus_Connection *reply_conn;
+static DBusMessage *reply;
+static int using_legacy = 0;
+
+static int load_module(const char *name, const char *options)
+{
+ struct kmod_ctx *ctx;
+ struct kmod_module *mod;
+ const char *config = NULL;
+ struct kmod_list *l, *list = NULL;
+ int ret = 0;
+ int n = 0;
+
+ ctx = kmod_new(NULL, &config);
+ if (!ctx)
+ return -1;
+
+ ret = kmod_module_new_from_lookup(ctx, name, &list);
+ if (ret < 0) {
+ _E("Module %s lookup error", name);
+ goto out;
+ }
+
+ kmod_list_foreach(l, list) {
+ mod = kmod_module_get_module(l);
+ if (!mod) {
+ _E("Module %s load error", name);
+ ret = -1;
+ goto out;
+ }
+
+ ret = kmod_module_get_initstate(mod);
+ if (ret >= 0) {
+ _I("module %s already loaded", name);
+ goto out; /* already loaded */
+ }
+
+ ret = kmod_module_insert_module(mod, 0, options);
+ if (ret < 0) {
+ _E("Module %s insert error", name);
+ goto out;
+ }
+
+ ++n;
+ }
+
+ if (n == 0) {
+ _E("Module %s not found", name);
+ ret = -1;
+ goto out;
+ }
+
+ _I("Module %s loaded\n", name);
+ ret = 0;
+
+out:
+ kmod_module_unref_list(list);
+ kmod_unref(ctx);
+ return ret;
+}
+
+static int unload_module(const char *name)
+{
+ struct kmod_ctx *ctx;
+ struct kmod_module *mod;
+ const char *config = NULL;
+ struct kmod_list *l, *list = NULL;
+ int ret = 0;
+ int n = 0;
+
+ ctx = kmod_new(NULL, &config);
+ if (!ctx)
+ return -1;
+
+ ret = kmod_module_new_from_lookup(ctx, name, &list);
+ if (ret < 0) {
+ _E("Module %s lookup error", name);
+ goto out;
+ }
+
+ kmod_list_foreach(l, list) {
+ mod = kmod_module_get_module(l);
+ if (!mod) {
+ _E("Module %s unload error", name);
+ ret = -1;
+ goto out;
+ }
+
+ ret = kmod_module_get_initstate(mod);
+ if (ret < 0)
+ goto out; /* not loaded */
+
+ ret = kmod_module_remove_module(mod, 0);
+ if (ret < 0) {
+ _E("Module %s remove error", name);
+ goto out;
+ }
+
+ ++n;
+ }
+
+ if (n == 0) {
+ _I("Module %s not found", name);
+ ret = -1;
+ goto out;
+ }
+
+ _I("Module %s unloaded\n", name);
+ ret = 0;
+
+out:
+ kmod_module_unref_list(list);
+ kmod_unref(ctx);
+ return ret;
+}
+
+static int load_gadget()
+{
+ usbg_state *s;
+ int ret = 0;
+ FILE *fp;
+
+ ret = usbg_init(CONFIGFS_PATH, &s);
+ if (ret < 0) {
+ _E("could not init libusbg");
+ return ret;
+ }
+
+ fp = fopen(GADGET_SCHEME_PATH, "r");
+ if (!fp) {
+ _E("could not open gadget scheme");
+ ret = -1;
+ goto out;
+ }
+
+ ret = usbg_import_gadget(s, fp, GADGET_NAME, NULL);
+ if (ret < 0) {
+ _E("could not import gadget");
+ goto out;
+ }
+
+out:
+ usbg_cleanup(s);
+ return ret;
+}
+
+int enable_gadget()
+{
+ int ret;
+ usbg_gadget *g;
+ usbg_udc *udc;
+ usbg_state *s;
+
+ if (using_legacy)
+ return 0;
+
+ ret = usbg_init(CONFIGFS_PATH, &s);
+ if (ret < 0)
+ return ret;
+
+ g = usbg_get_gadget(s, GADGET_NAME);
+ if (!g) {
+ _E("could not find gadget");
+ ret = -1;
+ goto out;
+ }
+
+ udc = usbg_get_udc(s, UDC_NAME);
+ if (!udc) {
+ _E("could not find udc");
+ ret = -1;
+ goto out;
+ }
+
+ ret = usbg_enable_gadget(g, udc);
+
+out:
+ usbg_cleanup(s);
+ return ret;
+}
+
+static void service_started_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ uint32_t id;
+ const char *path, *unit, *result;
+ int ret;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &unit,
+ DBUS_TYPE_STRING, &result,
+ DBUS_TYPE_INVALID)) {
+ _E("%s", err.message);
+ return;
+ }
+
+ if (strcmp(unit, SYSTEMD_UNIT_NAME) == 0) {
+ ret = enable_gadget();
+ if (ret < 0)
+ _E("Could not enable gadget");
+ else
+ _I("Start");
+
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED);
+
+
+ e_dbus_message_send(reply_conn, reply, NULL, 0, NULL);
+ }
+}
+
+static void service_stopped_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ uint32_t id;
+ const char *path, *unit, *result;
+ int ret;
+ usbg_state *s;
+ usbg_gadget *g;
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &unit,
+ DBUS_TYPE_STRING, &result,
+ DBUS_TYPE_INVALID)) {
+ _E("%s", err.message);
+ return;
+ }
+
+ if (strcmp(unit, SYSTEMD_SERVICE_NAME) == 0) {
+ ret = umount(FFS_PATH);
+ if (ret < 0) {
+ _E("could not umount functionfs");
+ goto out1;
+ }
+
+ if (!using_legacy) {
+ ret = usbg_init(CONFIGFS_PATH, &s);
+ if (ret < 0) {
+ _E("could not init libusbg");
+ goto out1;
+ }
+
+ g = usbg_get_gadget(s, GADGET_NAME);
+ if (!g) {
+ _E("could not find gadget");
+ ret = -1;
+ goto out;
+ }
+
+ ret = usbg_rm_gadget(g, USBG_RM_RECURSE);
+ if (ret < 0) {
+ _E("could not remove gadget");
+ goto out;
+ }
+ }
+
+ ret = unload_module("dummy_hcd");
+ if (ret < 0) {
+ _E("Error unloading module: %d", ret);
+ goto out1;
+ }
+
+ if (using_legacy) {
+ ret = unload_module("g_ffs");
+ if (ret < 0) {
+ _E("Error unloading module: %d", ret);
+ goto out1;
+ }
+ } else {
+ ret = unload_module("usb_f_fs");
+ if (ret < 0) {
+ _E("Error unloading module: %d", ret);
+ goto out;
+ }
+ }
+
+
+ _I("stop");
+
+out:
+ if (!using_legacy)
+ usbg_cleanup(s);
+out1:
+ e_dbus_message_send(reply_conn, reply, NULL, 0, NULL);
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED);
+ }
+}
+
+int start()
+{
+ struct stat st;
+ int ret;
+
+ ret = load_module("dummy_hcd", NULL);
+ if (ret < 0) {
+ _E("Error loading module: %d", ret);
+ return ret;
+ }
+
+ /* If you need to setup vid, pid or other data use module parameters */
+ ret = load_module("g_ffs",
+ "idVendor=0x1D6B"
+ " idProduct=0x104"
+ " bcdDevice=0x0001"
+ " iManufacturer=\"Foo Inc.\""
+ " iProduct=\"Bar Gadget\""
+ " iSerialNumber=\"0123456789\""
+ " generic_ffs_config_str=\"usb host API test config\""
+ " bmAttrs_overwrite=\"0x80\"");
+ if (ret < 0) {
+ using_legacy = 0;
+ _I("Legacy gadget g_ffs not found. Using ConfigFS.");
+
+ ret = load_module("usb_f_fs", NULL);
+ if (ret < 0) {
+ _E("Error loading module: %d", ret);
+ return ret;
+ }
+
+ ret = load_gadget();
+ if (ret < 0) {
+ _E("Error loading gadget: %d", ret);
+ goto out;
+ }
+ } else {
+ using_legacy = 1;
+ }
+
+ /* TODO make it recusrsive? */
+ if (stat(FFS_PATH, &st) < 0) {
+ ret = mkdir(FFS_PATH, S_IRWXU | S_IRWXG | S_IROTH);
+ if (ret < 0) {
+ _E("Error creating ffs directory");
+ goto out;
+ }
+ }
+
+ ret = mount(FFS_INSTANCE_NAME, FFS_PATH, "functionfs", 0, NULL);
+ if (ret < 0) {
+ _E("Error mounting ffs");
+ goto out;
+ }
+
+ ret = register_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED,
+ service_started_handler);
+ if (ret < 0) {
+ _E("could not register signal handler");
+ goto out;
+ }
+
+ ret = deviced_systemd_start_unit(SYSTEMD_UNIT_NAME);
+ if (ret < 0) {
+ _E("Error starting daemon");
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED);
+ goto out;
+ }
+
+ return 0;
+
+out:
+
+/* It's already a crash, thus we ignore return values here */
+
+ unload_module("dummy_hcd");
+ unload_module("usb_f_fs");
+ if (using_legacy)
+ unload_module("g_ffs");
+
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED);
+
+ return ret;
+}
+
+static int stop()
+{
+ int ret = 0;
+
+ ret = register_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED,
+ service_stopped_handler);
+ if (ret < 0) {
+ _E("could not register signal handler");
+ return ret;
+ }
+
+ ret = deviced_systemd_stop_unit(SYSTEMD_UNIT_NAME);
+ if (ret < 0) {
+ _E("could not stop socket unit");
+ goto out;
+ }
+
+ ret = deviced_systemd_stop_unit(SYSTEMD_SERVICE_NAME);
+ if (ret < 0) {
+ _E("could not stop service unit");
+ goto out;
+ }
+
+ return ret;
+
+out:
+ unregister_edbus_signal_handler(SYSTEMD_DBUS_PATH,
+ JOB_MANAGER_INTERFACE, JOB_REMOVED);
+ return ret;
+}
+
+static DBusMessage *edbus_start(E_DBus_Object *obj, DBusMessage *msg)
+{
+ int ret;
+
+ reply_conn = e_dbus_object_conn_get(obj);
+ reply = dbus_message_new_method_return(msg);
+
+ ret = start();
+ if (ret < 0)
+ return reply;
+
+ return NULL;
+}
+
+static DBusMessage *edbus_stop(E_DBus_Object *obj, DBusMessage *msg)
+{
+ int ret;
+
+ reply_conn = e_dbus_object_conn_get(obj);
+ reply = dbus_message_new_method_return(msg);
+
+ ret = stop();
+ if (ret < 0)
+ return dbus_message_new_method_return(msg);
+
+ return NULL;
+}
+
+static int usb_host_test_start(enum device_flags flags)
+{
+ return start();
+}
+
+static int usb_host_test_stop(enum device_flags flags)
+{
+ return stop();
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "start", NULL, NULL, edbus_start }, /* for devicectl */
+ { "stop", NULL, NULL, edbus_stop }, /* for devicectl */
+};
+
+static void usb_host_test_init(void *data)
+{
+ int ret;
+
+ ret = register_edbus_interface_and_method(DEVICED_PATH_USB_HOST_TEST,
+ DEVICED_INTERFACE_USB_HOST_TEST,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+
+ if (ret < 0) {
+ _E("Failed to register edbus method! %d", ret);
+ return;
+ }
+
+ _I("initialized");
+}
+
+static void usb_host_test_exit(void *data)
+{
+ _I("exited");
+}
+
+static const struct device_ops usb_host_test_device_ops = {
+ .name = "usb-host-test",
+ .init = usb_host_test_init,
+ .exit = usb_host_test_exit,
+ .start = usb_host_test_start,
+ .stop = usb_host_test_stop,
+};
+
+DEVICE_OPS_REGISTER(&usb_host_test_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <error.h>
+#include <stdbool.h>
+#include <device-node.h>
+#include <vconf.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+#include "shared/dbus.h"
+#include "usb.h"
+
+/* Legacy signals */
+#define SIGNAL_STATE_CHANGED "StateChanged"
+#define SIGNAL_MODE_CHANGED "ModeChanged"
+#define SIGNAL_CONFIG_ENABLED "ConfigEnabled"
+#define CHANGE_USB_MODE "ChangeUsbMode"
+
+static int get_usb_current_mode(void)
+{
+ int val, ret;
+
+ ret = vconf_get_int(VCONFKEY_USB_CUR_MODE, &val);
+ if (ret != 0) {
+ _E("Failed to get current mode (%d)", ret);
+ return ret;
+ }
+
+ return val;
+}
+
+static int get_usb_state(void)
+{
+ int ret, val;
+ int result = 0;
+
+ ret = vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val);
+ if (ret != 0) {
+ _E("Failed to get usb_state (%d)", ret);
+ return ret;
+ }
+
+ if (val == VCONFKEY_SYSMAN_USB_DISCONNECTED)
+ result = val;
+ else {
+ result = VCONFKEY_SYSMAN_USB_CONNECTED;
+ if (val == VCONFKEY_SYSMAN_USB_AVAILABLE)
+ result |= VCONFKEY_SYSMAN_USB_AVAILABLE;
+ }
+
+ return result;
+}
+
+/* dbus signals */
+void broadcast_usb_config_enabled(int state)
+{
+ int ret;
+ char *param[1];
+ char buf[2];
+
+ snprintf(buf, sizeof(buf), "%d", state);
+ param[0] = buf;
+
+ _I("USB config enabled (%d)", state);
+
+ ret = broadcast_edbus_signal(DEVICED_PATH_USB,
+ DEVICED_INTERFACE_USB, SIGNAL_CONFIG_ENABLED,
+ "i", param);
+ if (ret < 0)
+ _E("Failed to send dbus signal");
+}
+
+void broadcast_usb_state_changed(void)
+{
+ int ret;
+ char *param[1];
+ char text[16];
+ unsigned int state;
+ static unsigned int prev_state = UINT_MAX;
+
+ state = get_usb_state();
+ if (state == prev_state)
+ return;
+ prev_state = state;
+
+ _I("USB state changed (%u)", state);
+
+ snprintf(text, sizeof(text), "%u", state);
+ param[0] = text;
+
+ ret = broadcast_edbus_signal(DEVICED_PATH_USB,
+ DEVICED_INTERFACE_USB, SIGNAL_STATE_CHANGED,
+ "u", param);
+ if (ret < 0)
+ _E("Failed to send dbus signal");
+}
+
+void broadcast_usb_mode_changed(void)
+{
+ int ret;
+ char *param[1];
+ char text[16];
+ unsigned int mode;
+ static unsigned int prev_mode = UINT_MAX;
+
+ mode = get_usb_current_mode();
+ if (mode == prev_mode)
+ return;
+ prev_mode = mode;
+
+ snprintf(text, sizeof(text), "%u", mode);
+ param[0] = text;
+
+ _I("USB mode changed (%u)", mode);
+
+ ret = broadcast_edbus_signal(DEVICED_PATH_USB,
+ DEVICED_INTERFACE_USB, SIGNAL_MODE_CHANGED,
+ "u", param);
+ if (ret < 0)
+ _E("Failed to send dbus signal");
+}
+
+static void change_usb_client_mode(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ int req, debug;
+ int ret;
+ unsigned mode;
+
+ if (dbus_message_is_signal(msg, DEVICED_INTERFACE_USB, CHANGE_USB_MODE) == 0)
+ return;
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &req, DBUS_TYPE_INVALID) == 0) {
+ _E("FAIL: dbus_message_get_args");
+ goto out;
+ }
+
+ debug = 0;
+ switch (req) {
+ case SET_USB_DEFAULT:
+ case SET_USB_SDB:
+ case SET_USB_SDB_DIAG:
+ mode = USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB;
+ debug = 1;
+ break;
+ case SET_USB_RNDIS:
+ case SET_USB_RNDIS_DIAG:
+ case SET_USB_RNDIS_SDB:
+ mode = USB_FUNCTION_RNDIS | USB_FUNCTION_SDB;
+ debug = 1;
+ break;
+ case 11: /* SET_USB_DIAG_RMNET */
+ case 12: /* SET_USB_ACM_SDB_DM */
+ default:
+ _E("(%d) is unknown usb mode", req);
+ goto out;
+ }
+
+ if (vconf_set_bool(VCONFKEY_SETAPPL_USB_DEBUG_MODE_BOOL, debug) != 0)
+ _E("Failed to set usb debug toggle (%d)", debug);
+
+ ret = usb_change_mode(mode);
+ if (ret < 0)
+ _E("Failed to change usb mode (%d)", ret);
+
+out:
+ dbus_error_free(&err);
+}
+
+/* dbus methods */
+static DBusMessage *get_usb_client_state(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int state;
+
+ state = get_usb_state();
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &state);
+ return reply;
+}
+
+static DBusMessage *get_usb_client_mode(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ unsigned int mode;
+
+ mode = get_usb_current_mode();
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &mode);
+ return reply;
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "GetState", NULL, "u", get_usb_client_state }, /* from Tizen 2.3 */
+ { "GetMode", NULL, "u", get_usb_client_mode }, /* from Tizen 2.3 */
+ /* Add methods here */
+};
+
+int usb_dbus_init(void)
+{
+ int ret;
+
+ ret = register_edbus_method(DEVICED_PATH_USB,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0) {
+ _E("Failed to register dbus method (%d)", ret);
+ return ret;
+ }
+
+ ret = register_edbus_signal_handler(DEVICED_PATH_USB,
+ DEVICED_INTERFACE_USB, "ChangeUsbMode",
+ change_usb_client_mode);
+ if (ret < 0) {
+ _E("Failed to registser dbus signal (%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <string.h>
+#include <stddef.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/config-parser.h"
+#include "core/launch.h"
+#include "shared/deviced-systemd.h"
+#include "usb.h"
+
+#define USB_OPERATION "/etc/deviced/usb-operation.conf"
+
+#define KEY_START_STR "Start"
+#define KEY_STOP_STR "Stop"
+
+#define BUF_MAX 128
+
+typedef enum {
+ OPERATION_STOP,
+ OPERATION_START,
+} operation_e;
+
+struct oper_data {
+ char mode_str[BUF_MAX];
+ operation_e type;
+};
+
+static int load_operation_config(struct parse_result *result, void *user_data)
+{
+ struct oper_data *data = user_data;
+ int ret;
+ operation_e type;
+
+ if (!data || !result)
+ return -EINVAL;
+
+ if (!strstr(data->mode_str, result->section))
+ return 0;
+
+ if (!strncmp(result->name, KEY_START_STR, strlen(KEY_START_STR)))
+ type = OPERATION_START;
+ else if (!strncmp(result->name, KEY_STOP_STR, strlen(KEY_STOP_STR)))
+ type = OPERATION_STOP;
+ else {
+ _E("Invalid name (%s)", result->name);
+ return -EINVAL;
+ }
+
+ if (type != data->type)
+ return 0;
+
+ if (strstr(result->name, "Service")) {
+ if (type == OPERATION_START)
+ ret = deviced_systemd_start_unit(result->value);
+ if (type == OPERATION_STOP)
+ ret = deviced_systemd_stop_unit(result->value);
+ } else
+ ret = launch_app_cmd(result->value);
+
+ _I("Execute(%s %s: %d)", result->name, result->value, ret);
+
+ return 0;
+}
+
+static int usb_execute_operation(unsigned int mode, operation_e type)
+{
+ int ret;
+ struct oper_data data;
+
+ if (mode == USB_FUNCTION_NONE)
+ return -EINVAL;
+
+ usb_state_get_mode_str(mode, data.mode_str, sizeof(data.mode_str));
+
+ data.type = type;
+
+ ret = config_parse(USB_OPERATION,
+ load_operation_config, &data);
+ if (ret < 0)
+ _E("Failed to load usb operation (%d)", ret);
+
+ return ret;
+}
+
+int usb_operation_start(unsigned int mode)
+{
+ return usb_execute_operation(mode, OPERATION_START);
+}
+
+int usb_operation_stop(unsigned int mode)
+{
+ return usb_execute_operation(mode, OPERATION_STOP);
+}
--- /dev/null
+[sdb]
+StartService=sdbd.service
+StopService=sdbd.service
+
+
+[mtp]
+StartService=mtp-responder.service
+StopService=mtp-responder.service
+
+[rndis]
+Start=/sbin/ifconfig usb0 192.168.129.3 up
+Start=/sbin/route add -net 192.168.129.0 netmask 255.255.255.0 dev usb0
+StartService=sshd.service
+StartService=sdbd.service
+StopService=sshd.service
+Stop=/sbin/ifconfig usb0 down
+StopService=sdbd.service
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <vconf.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "core/common.h"
+#include "core/device-notifier.h"
+#include "display/poll.h"
+#include "extcon/extcon.h"
+#include "apps/apps.h"
+#include "usb.h"
+#include "usb-tethering.h"
+
+static usb_connection_state_e usb_connection = USB_DISCONNECTED;
+static unsigned int usb_mode = USB_FUNCTION_NONE;
+static unsigned int usb_selected_mode = USB_FUNCTION_SDB; /* for debugging */
+
+static void usb_state_send_system_event(int status)
+{
+ bundle *b;
+ const char *str;
+
+ switch (status) {
+ case VCONFKEY_SYSMAN_USB_DISCONNECTED:
+ str = EVT_VAL_USB_DISCONNECTED;
+ break;
+ case VCONFKEY_SYSMAN_USB_CONNECTED:
+ str = EVT_VAL_USB_CONNECTED;
+ break;
+ case VCONFKEY_SYSMAN_USB_AVAILABLE:
+ str = EVT_VAL_USB_AVAILABLE;
+ break;
+ default:
+ return;
+ }
+
+ _I("system_event (%s)", str);
+
+ b = bundle_create();
+ bundle_add_str(b, EVT_KEY_USB_STATUS, str);
+ eventsystem_send_system_event(SYS_EVENT_USB_STATUS, b);
+ bundle_free(b);
+}
+
+static void usb_state_set_connection(usb_connection_state_e conn)
+{
+ usb_connection = conn;
+}
+
+usb_connection_state_e usb_state_get_connection(void)
+{
+ return usb_connection;
+}
+
+void usb_state_retrieve_selected_mode(void)
+{
+ int ret, mode;
+ ret = vconf_get_int(VCONFKEY_USB_SEL_MODE, &mode);
+ if (ret != 0) {
+ _E("Failed to retrieve selected mode");
+ return;
+ }
+
+#ifdef ENGINEER_MODE
+ if (!(mode & USB_FUNCTION_SDB)) {
+ mode = USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB;
+ usb_state_set_selected_mode(mode);
+ }
+#endif
+
+ usb_selected_mode = (unsigned int)mode;
+}
+
+void usb_state_set_selected_mode(unsigned int mode)
+{
+ usb_selected_mode = mode;
+ vconf_set_int(VCONFKEY_USB_SEL_MODE, mode);
+}
+
+unsigned int usb_state_get_current_mode(void)
+{
+ return usb_mode;
+}
+
+unsigned int usb_state_get_selected_mode(void)
+{
+ return usb_selected_mode;
+}
+
+char *usb_state_get_mode_str(unsigned int mode, char *str, size_t len)
+{
+ int i;
+ int ret;
+
+ if (mode == USB_FUNCTION_NONE) {
+ snprintf(str, len, "%s", "");
+ } else {
+ for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i) {
+ if (mode & _available_funcs[i]->id) {
+ ret = snprintf(str, len, "%s,",
+ _available_funcs[i]->name);
+ if (ret >= len)
+ return str;
+ str += ret;
+ len -= ret;
+ }
+ }
+ }
+
+ /* eliminate trailing comma */
+ *(str - 1) = '\0';
+ return str;
+}
+
+void usb_state_update_state(usb_connection_state_e state, unsigned int mode)
+{
+ static int old_mode = -1; /* VCONFKEY_USB_CUR_MODE */
+ static int old_status = -1; /* VCONFKEY_SYSMAN_USB_STATUS */
+ static int noti_id = -1;
+ int status;
+
+ if (state == USB_DISCONNECTED && mode != USB_FUNCTION_NONE)
+ mode = USB_FUNCTION_NONE;
+
+ if (mode == USB_FUNCTION_NONE) {
+ if (noti_id >= 0) {
+ remove_notification("MediaDeviceNotiOff", noti_id);
+ noti_id = -1;
+ }
+ } else if (mode | USB_FUNCTION_MTP) {
+ if (noti_id < 0)
+ noti_id = add_notification("MediaDeviceNotiOn");
+ if (noti_id < 0)
+ _E("Failed to show notification for usb connection");
+ }
+
+ usb_state_set_connection(state);
+ if (state == USB_CONNECTED) {
+ if (mode == USB_FUNCTION_NONE)
+ status = VCONFKEY_SYSMAN_USB_CONNECTED;
+ else
+ status = VCONFKEY_SYSMAN_USB_AVAILABLE;
+ } else
+ status = VCONFKEY_SYSMAN_USB_DISCONNECTED;
+
+ if (old_status != status) {
+ usb_state_send_system_event(status);
+ vconf_set_int(VCONFKEY_SYSMAN_USB_STATUS, status);
+ old_status = status;
+ }
+
+ if (old_mode != mode) {
+ vconf_set_int(VCONFKEY_USB_CUR_MODE, mode);
+ usb_mode = mode;
+ old_mode = mode;
+ }
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 <string.h>
+#include <vconf.h>
+
+#include "core/log.h"
+#include "core/common.h"
+#include "core/config-parser.h"
+#include "core/launch.h"
+#include "core/device-notifier.h"
+#include "usb.h"
+
+static bool tethering_state;
+
+bool usb_tethering_state(void)
+{
+ return tethering_state;
+}
+
+static void usb_tethering_changed(keynode_t *key, void *data)
+{
+ int mode;
+ bool curr;
+
+ if (!key)
+ return;
+
+ mode = vconf_keynode_get_int(key);
+ curr = mode & VCONFKEY_MOBILE_HOTSPOT_MODE_USB;
+
+ if (curr == tethering_state)
+ return;
+
+ tethering_state = curr;
+
+ device_notify(DEVICE_NOTIFIER_USB_TETHERING_MODE, (void *)curr);
+}
+
+static int usb_tethering_mode_changed(void *data)
+{
+ bool on;
+ unsigned mode;
+ int ret;
+
+ on = (bool)data;
+
+ /*
+ * TODO.
+ * Preserve gadget mode when tethering is being turned on
+ * and restore it later when tethering is being turned off/
+ */
+ if (on)
+ mode = USB_FUNCTION_RNDIS | USB_FUNCTION_SDB;
+ else
+ mode = USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB;
+
+ ret = usb_change_mode(mode);
+ if (ret < 0)
+ _E("Failed to change usb mode to (%s)", mode);
+
+ return ret;
+}
+
+void add_usb_tethering_handler(void)
+{
+ if (vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE,
+ usb_tethering_changed, NULL) != 0)
+ _E("Failed to add usb tethering handler");
+
+ register_notifier(DEVICE_NOTIFIER_USB_TETHERING_MODE,
+ usb_tethering_mode_changed);
+}
+
+void remove_usb_tethering_handler(void)
+{
+ vconf_ignore_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE,
+ usb_tethering_changed);
+
+ unregister_notifier(DEVICE_NOTIFIER_USB_TETHERING_MODE,
+ usb_tethering_mode_changed);
+}
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2016 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 __USB_TETHERING_H__
+#define __USB_TETHERING_H__
+
+#include <stdio.h>
+
+bool usb_tethering_state(void);
+
+void add_usb_tethering_handler(void);
+void remove_usb_tethering_handler(void);
+
+#endif /* __USB_TETHERING_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 <vconf.h>
+#include <bundle.h>
+#include <eventsystem.h>
+
+#include "core/log.h"
+#include "core/list.h"
+#include "core/common.h"
+#include "core/device-notifier.h"
+#include "display/poll.h"
+#include "extcon/extcon.h"
+#include "apps/apps.h"
+#include "usb.h"
+#include "usb-tethering.h"
+
+static struct usb_gadget_translator *gadget_translator;
+static struct usb_client *usb_client;
+static unsigned current_mode;
+
+struct extcon_ops extcon_usb_ops;
+
+static int usb_probe(void)
+{
+ struct hw_info *info;
+ struct hw_common *common;
+ int ret;
+
+ /* We need both HALs up and running for operating in USB client mode */
+
+ if (!gadget_translator) {
+ ret = hw_get_info(USB_GADGET_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (ret)
+ goto no_gadget_hal;
+
+ if (!info->open) {
+ _E("Failed to open gadget translator; open(NULL)");
+ /* TODO. Shouldn't we free somehow info structure? */
+ return -ENODEV;
+ }
+
+ ret = info->open(info, NULL, &common);
+ if (ret < 0) {
+ _E("Failed to open usb gadget translator (%d)", ret);
+ return ret;
+ }
+
+ gadget_translator = container_of(common,
+ struct usb_gadget_translator,
+ common);
+ if (!gadget_translator->id_to_gadget ||
+ !gadget_translator->cleanup_gadget) {
+ _E("Invalid gadget translator HAL");
+ goto invalid_translator_hal;
+ }
+ }
+
+ if (!usb_client) {
+ ret = hw_get_info(USB_CLIENT_HARDWARE_DEVICE_ID,
+ (const struct hw_info **)&info);
+ if (ret)
+ goto no_client_hal;
+
+ if (!info->open) {
+ _E("Failed to open usb client hw; open(NULL)");
+ /* TODO. Shouldn't we free somehow info structure? */
+ return -ENODEV;
+ }
+
+ ret = info->open(info, NULL, &common);
+ if (ret < 0) {
+ _E("Failed to open usb client hw (%d)", ret);
+ return ret;
+ }
+
+ usb_client = container_of(common, struct usb_client, common);
+
+ if (!usb_client->reconfigure_gadget || !usb_client->enable ||
+ !usb_client->disable)
+ goto invalid_config_hal;
+ }
+
+ return 0;
+
+invalid_config_hal:
+ if (usb_client->common.info->close)
+ usb_client->common.info->close(&usb_client->common);
+
+no_client_hal:
+invalid_translator_hal:
+ if (gadget_translator->common.info)
+ gadget_translator->common.info->close(&gadget_translator->common);
+ gadget_translator = NULL;
+no_gadget_hal:
+ /* TODO. Maybe some default action here? */
+ return -ENOENT;
+}
+
+static void usb_release()
+{
+ if (usb_client)
+ if (usb_client->common.info->close)
+ usb_client->common.info->close(&usb_client->common);
+
+ if (gadget_translator)
+ if (gadget_translator->common.info->close)
+ gadget_translator->common.info->close(
+ &gadget_translator->common);
+}
+
+static int usb_config_init(void)
+{
+ int ret;
+ struct usb_gadget_id gadget_id;
+ struct usb_gadget *gadget;
+
+ if (!gadget_translator || !usb_client)
+ goto no_hal;
+
+ memset(&gadget_id, 0, sizeof(gadget_id));
+
+ gadget_id.function_mask = usb_state_get_selected_mode();
+ ret = gadget_translator->id_to_gadget(&gadget_id, &gadget);
+ if (ret) {
+ _E("Unable to translate id into gadget (%d)", ret);
+ return ret;
+ }
+
+ usb_client->disable(usb_client);
+ ret = usb_client->reconfigure_gadget(usb_client, gadget);
+ gadget_translator->cleanup_gadget(gadget);
+ if (ret)
+ _E("Unable to configure gadget (%d)", ret);
+
+ return ret;
+no_hal:
+ /* TODO. Maybe some default action here? */
+ return -ENODEV;
+}
+
+static void usb_config_deinit(void)
+{
+ if (!usb_client)
+ goto no_hal;
+
+ usb_client->disable(usb_client);
+
+ return;
+no_hal:
+ /* TODO. Maybe some default action here? */
+ return;
+}
+
+static int usb_config_enable(void)
+{
+ if (!usb_client)
+ goto no_hal;
+
+ return usb_client->enable(usb_client);
+
+no_hal:
+ /* TODO. Maybe some default action here? */
+ return -ENODEV;
+}
+
+static int usb_config_disable(void)
+{
+ if (!usb_client)
+ goto no_hal;
+
+ usb_client->disable(usb_client);
+
+ return 0;
+no_hal:
+ /* TODO. Maybe some default action here? */
+ return -ENODEV;
+}
+
+int usb_change_mode(unsigned mode)
+{
+ struct usb_gadget_id gadget_id;
+ struct usb_gadget *gadget;
+ int ret;
+
+ if (!gadget_translator || !usb_client)
+ goto no_hal;
+
+ memset(&gadget_id, 0, sizeof(gadget_id));
+ gadget_id.function_mask = mode;
+
+ ret = gadget_translator->id_to_gadget(&gadget_id, &gadget);
+ if (ret) {
+ _E("Unable to translate id into gadget (%d)", ret);
+ return ret;
+ }
+
+ usb_client->disable(usb_client);
+ ret = usb_client->reconfigure_gadget(usb_client, gadget);
+ gadget_translator->cleanup_gadget(gadget);
+ if (ret) {
+ _E("Unable to configure gadget (%d)", ret);
+ goto out;
+ }
+
+ current_mode = mode;
+out:
+ return ret;
+no_hal:
+ /* TODO. Maybe some default action here? */
+ return -ENODEV;
+}
+
+static int usb_state_changed(int status)
+{
+ static int old = -1; /* to update at the first time */
+ unsigned mode;
+ int ret;
+
+ _I("USB state is changed from (%d) to (%d)", old, status);
+
+ if (old == status)
+ return 0;
+
+ switch (status) {
+ case USB_CONNECTED:
+ _I("USB cable is connected");
+ usb_state_update_state(USB_CONNECTED, USB_FUNCTION_NONE);
+ mode = usb_state_get_selected_mode();
+ if (mode != current_mode)
+ usb_change_mode(mode);
+
+ ret = usb_config_enable();
+ if (ret < 0) {
+ _E("Failed to enable usb config (%d)", ret);
+ break;
+ }
+ usb_operation_start(mode);
+ usb_state_update_state(USB_CONNECTED, mode);
+ pm_lock_internal(INTERNAL_LOCK_USB,
+ LCD_OFF, STAY_CUR_STATE, 0);
+ break;
+ case USB_DISCONNECTED:
+ _I("USB cable is disconnected");
+ usb_operation_stop(usb_state_get_current_mode());
+ usb_state_update_state(USB_DISCONNECTED, USB_FUNCTION_NONE);
+
+ ret = usb_config_disable();
+ if (ret != 0)
+ _E("Failed to disable usb config (%d)", ret);
+ pm_unlock_internal(INTERNAL_LOCK_USB,
+ LCD_OFF, STAY_CUR_STATE);
+ break;
+ default:
+ _E("Invalid USB state(%d)", status);
+ return -EINVAL;
+ }
+ if (ret < 0)
+ _E("Failed to operate usb connection(%d)", ret);
+ else
+ old = status;
+
+ return ret;
+}
+
+static void usb_init(void *data)
+{
+ int ret;
+
+ ret = usb_probe();
+ if (ret < 0) {
+ _E("USB client cannot be used (%d)", ret);
+ return;
+ }
+
+ usb_state_retrieve_selected_mode();
+
+ ret = usb_config_init();
+ if (ret < 0)
+ _E("Failed to initialize usb configuation");
+
+ ret = usb_dbus_init();
+ if (ret < 0)
+ _E("Failed to init dbus (%d)", ret);
+
+ add_usb_tethering_handler();
+
+ ret = usb_state_changed(extcon_usb_ops.status);
+ if (ret < 0)
+ _E("Failed to update usb status(%d)", ret);
+}
+
+static void usb_exit(void *data)
+{
+ remove_usb_tethering_handler();
+ usb_state_update_state(USB_DISCONNECTED, USB_FUNCTION_NONE);
+ usb_config_deinit();
+ usb_release();
+}
+
+struct extcon_ops extcon_usb_ops = {
+ .name = EXTCON_CABLE_USB,
+ .init = usb_init,
+ .exit = usb_exit,
+ .update = usb_state_changed,
+};
+
+EXTCON_OPS_REGISTER(extcon_usb_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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 __DEVICED_USB_H__
+#define __DEVICED_USB_H__
+
+#include <hw/usb_gadget.h>
+#include <hw/usb_client.h>
+
+#define USB_CONFIG_OPS_REGISTER(dev) \
+static void __CONSTRUCTOR__ usb_config_init(void) \
+{ \
+ add_usb_config(dev); \
+} \
+static void __DESTRUCTOR__ usb_config_exit(void) \
+{ \
+ remove_usb_config(dev); \
+}
+
+struct usb_config_ops {
+ bool (*is_valid)(void);
+ const struct usb_config_plugin_ops *(*load)(void);
+ void (*release)(void);
+};
+
+/* TODO
+ * move it to proper location */
+struct usb_config_plugin_ops {
+ int (*init)(char *name);
+ void (*deinit)(char *name);
+ int (*enable)(char *name);
+ int (*disable)(char *name);
+ int (*change)(char *name);
+};
+
+/* Update usb state (usb-state.c) */
+typedef enum {
+ USB_DISCONNECTED,
+ USB_CONNECTED,
+} usb_connection_state_e;
+
+void add_usb_config(const struct usb_config_ops *ops);
+void remove_usb_config(const struct usb_config_ops *ops);
+
+int usb_change_mode(unsigned int mode);
+
+void usb_state_update_state(usb_connection_state_e state, unsigned int mode);
+void usb_state_retrieve_selected_mode(void);
+char *usb_state_get_mode_str(unsigned int mode, char *str, size_t len);
+unsigned int usb_state_get_selected_mode(void);
+void usb_state_set_selected_mode(unsigned int mode);
+unsigned int usb_state_get_current_mode(void);
+
+int usb_operation_start(unsigned int mode);
+int usb_operation_stop(unsigned int mode);
+
+/* dbus methods/signals (usb-dbus.c) */
+enum {
+ DISABLED,
+ ENABLED,
+};
+
+int usb_dbus_init(void);
+
+void broadcast_usb_config_enabled(int state);
+void broadcast_usb_state_changed(void);
+void broadcast_usb_mode_changed(void);
+
+#endif /* __USB_CLIENT_H__ */
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2015 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.
+ */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <tzplatform_config.h>
+
+#include "core/log.h"
+#include "core/devices.h"
+#include "core/edbus-handler.h"
+#include "core/device-notifier.h"
+#include "core/udev.h"
+#include "core/list.h"
+#include "core/device-idler.h"
+#include "apps/apps.h"
+
+#define USB_INTERFACE_CLASS "bInterfaceClass"
+#define USB_INTERFACE_SUBCLASS "bInterfaceSubClass"
+#define USB_INTERFACE_PROTOCOL "bInterfaceProtocol"
+#define USB_VENDOR_ID "idVendor"
+#define USB_PRODUCT_ID "idProduct"
+#define USB_MANUFACTURER "manufacturer"
+#define USB_PRODUCT "product"
+#define USB_SERIAL "serial"
+
+#define USB_HOST_RESULT_SIGNAL "USBHostResult"
+
+#define SIGNAL_USB_HOST_CHANGED "ChangedDevice"
+#define METHOD_GET_CONNECTION_CREDENTIALS "GetConnectionCredentials"
+
+#define ROOTPATH tzplatform_getenv(TZ_SYS_VAR)
+#define POLICY_FILENAME "usbhost-policy"
+
+char *POLICY_FILEPATH;
+
+/**
+ * Below usb host class is defined by www.usb.org.
+ * Please refer to below site.
+ * http://www.usb.org/developers/defined_class
+ * You can find the detail class codes in linux/usb/ch9.h.
+ * Deviced uses kernel defines.
+ */
+#include <linux/usb/ch9.h>
+#define USB_CLASS_ALL 0xffffffff
+#define USB_DEVICE_MAJOR 189
+
+/**
+ * HID Standard protocol information.
+ * Please refer to below site.
+ * http://www.usb.org/developers/hidpage/HID1_11.pdf
+ * Below protocol only has meaning
+ * if the subclass is a boot interface subclass,
+ * otherwise it is 0.
+ */
+enum usbhost_hid_protocol {
+ USB_HOST_HID_KEYBOARD = 1,
+ USB_HOST_HID_MOUSE = 2,
+};
+
+enum usbhost_state {
+ USB_HOST_REMOVED,
+ USB_HOST_ADDED,
+};
+
+struct usbhost_device {
+ char devpath[PATH_MAX]; /* unique info. */
+ int baseclass;
+ int subclass;
+ int protocol;
+ int vendorid;
+ int productid;
+ char *manufacturer;
+ char *product;
+ char *serial;
+};
+
+static dd_list *usbhost_list;
+
+enum policy_value {
+ POLICY_NONE,
+ POLICY_ALLOW_ALWAYS,
+ POLICY_ALLOW_NOW,
+ POLICY_DENY_ALWAYS,
+ POLICY_DENY_NOW,
+};
+
+#define UID_KEY "UnixUserID"
+#define PID_KEY "ProcessID"
+#define SEC_LABEL_KEY "LinuxSecurityLabel"
+#define ENTRY_LINE_SIZE 256
+
+struct user_credentials {
+ uint32_t uid;
+ uint32_t pid;
+ char *sec_label;
+};
+
+struct device_desc{
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+};
+
+struct policy_entry {
+ struct user_credentials creds;
+ union {
+ struct usb_device_descriptor device;
+ /* for temporary policy */
+ char devpath[PATH_MAX];
+ };
+
+ enum policy_value value;
+};
+
+static inline int is_policy_temporary(struct policy_entry *entry) {
+ return entry->value == POLICY_ALLOW_NOW ||
+ entry->value == POLICY_DENY_NOW;
+}
+
+dd_list *access_list;
+
+struct usbhost_open_request {
+ DBusMessage *msg;
+ E_DBus_Connection *reply_conn;
+ char *path;
+ struct user_credentials cred;
+ struct usb_device_descriptor desc;
+ char devpath[PATH_MAX];
+} *current_request = NULL;
+
+static void print_usbhost(struct usbhost_device *usbhost)
+{
+ if (!usbhost)
+ return;
+
+ _I("devpath : %s", usbhost->devpath);
+ _I("interface baseclass : %xh", usbhost->baseclass);
+ _I("interface subclass : %xh", usbhost->subclass);
+ _I("interface protocol : %xh", usbhost->protocol);
+ _I("vendor id : %xh", usbhost->vendorid);
+ _I("product id : %xh", usbhost->productid);
+ _I("manufacturer : %s", usbhost->manufacturer);
+ _I("product : %s", usbhost->product);
+ _I("serial : %s", usbhost->serial);
+}
+
+static void broadcast_usbhost_signal(enum usbhost_state state,
+ struct usbhost_device *usbhost)
+{
+ char *arr[10];
+ char str_state[32];
+ char str_baseclass[32];
+ char str_subclass[32];
+ char str_protocol[32];
+ char str_vendorid[32];
+ char str_productid[32];
+
+ if (!usbhost)
+ return;
+
+ snprintf(str_state, sizeof(str_state), "%d", state);
+ arr[0] = str_state;
+ /* devpath is always valid */
+ arr[1] = usbhost->devpath;
+ snprintf(str_baseclass, sizeof(str_baseclass),
+ "%d", usbhost->baseclass);
+ arr[2] = str_baseclass;
+ snprintf(str_subclass, sizeof(str_subclass),
+ "%d", usbhost->subclass);
+ arr[3] = str_subclass;
+ snprintf(str_protocol, sizeof(str_protocol),
+ "%d", usbhost->protocol);
+ arr[4] = str_protocol;
+ snprintf(str_vendorid, sizeof(str_vendorid),
+ "%d", usbhost->vendorid);
+ arr[5] = str_vendorid;
+ snprintf(str_productid, sizeof(str_productid),
+ "%d", usbhost->productid);
+ arr[6] = str_productid;
+ arr[7] = (!usbhost->manufacturer ? "" : usbhost->manufacturer);
+ arr[8] = (!usbhost->product ? "" : usbhost->product);
+ arr[9] = (!usbhost->serial ? "" : usbhost->serial);
+
+ broadcast_edbus_signal(DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST,
+ SIGNAL_USB_HOST_CHANGED,
+ "isiiiiisss", arr);
+}
+
+static int add_usbhost_list(struct udev_device *dev, const char *devpath)
+{
+ struct usbhost_device *usbhost;
+ const char *str;
+ struct udev_device *parent;
+
+ /* allocate new usbhost device */
+ usbhost = calloc(1, sizeof(struct usbhost_device));
+ if (!usbhost) {
+ _E("fail to allocate usbhost memory : %d", errno);
+ return -errno;
+ }
+
+ /* save the devnode */
+ snprintf(usbhost->devpath, sizeof(usbhost->devpath),
+ "%s", devpath);
+
+ /* get usb interface informations */
+ str = udev_device_get_sysattr_value(dev, USB_INTERFACE_CLASS);
+ if (str)
+ usbhost->baseclass = (int)strtol(str, NULL, 16);
+ str = udev_device_get_sysattr_value(dev, USB_INTERFACE_SUBCLASS);
+ if (str)
+ usbhost->subclass = (int)strtol(str, NULL, 16);
+ str = udev_device_get_sysattr_value(dev, USB_INTERFACE_PROTOCOL);
+ if (str)
+ usbhost->protocol = (int)strtol(str, NULL, 16);
+
+ /* parent has a lot of information about usb_interface */
+ parent = udev_device_get_parent(dev);
+ if (!parent) {
+ _E("fail to get parent");
+ free(usbhost);
+ return -EPERM;
+ }
+
+ /* get usb device informations */
+ str = udev_device_get_sysattr_value(parent, USB_VENDOR_ID);
+ if (str)
+ usbhost->vendorid = (int)strtol(str, NULL, 16);
+ str = udev_device_get_sysattr_value(parent, USB_PRODUCT_ID);
+ if (str)
+ usbhost->productid = (int)strtol(str, NULL, 16);
+ str = udev_device_get_sysattr_value(parent, USB_MANUFACTURER);
+ if (str)
+ usbhost->manufacturer = strdup(str);
+ str = udev_device_get_sysattr_value(parent, USB_PRODUCT);
+ if (str)
+ usbhost->product = strdup(str);
+ str = udev_device_get_sysattr_value(parent, USB_SERIAL);
+ if (str)
+ usbhost->serial = strdup(str);
+
+ DD_LIST_APPEND(usbhost_list, usbhost);
+
+ broadcast_usbhost_signal(USB_HOST_ADDED, usbhost);
+
+ /* for debugging */
+ _I("USB HOST Added");
+ print_usbhost(usbhost);
+
+ return 0;
+}
+
+static int remove_usbhost_list(const char *devpath)
+{
+ struct usbhost_device *usbhost;
+ dd_list *n, *next;
+
+ /* find the matched item */
+ DD_LIST_FOREACH_SAFE(usbhost_list, n, next, usbhost) {
+ if (!strncmp(usbhost->devpath,
+ devpath, sizeof(usbhost->devpath)))
+ break;
+ }
+
+ if (!usbhost) {
+ _E("fail to find the matched usbhost device");
+ return -ENODEV;
+ }
+
+ broadcast_usbhost_signal(USB_HOST_REMOVED, usbhost);
+
+ /* for debugging */
+ _I("USB HOST Removed");
+ _I("devpath : %s", usbhost->devpath);
+
+ DD_LIST_REMOVE(usbhost_list, usbhost);
+ free(usbhost->manufacturer);
+ free(usbhost->product);
+ free(usbhost->serial);
+ free(usbhost);
+
+ return 0;
+}
+
+static void remove_all_usbhost_list(void)
+{
+ struct usbhost_device *usbhost;
+ dd_list *n, *next;
+
+ DD_LIST_FOREACH_SAFE(usbhost_list, n, next, usbhost) {
+
+ /* for debugging */
+ _I("USB HOST Removed");
+ _I("devpath : %s", usbhost->devpath);
+
+ DD_LIST_REMOVE(usbhost_list, usbhost);
+ free(usbhost->manufacturer);
+ free(usbhost->product);
+ free(usbhost->serial);
+ free(usbhost);
+ }
+}
+
+static void uevent_usbhost_handler(struct udev_device *dev)
+{
+ const char *subsystem;
+ const char *devtype;
+ const char *devpath;
+ const char *action;
+ struct policy_entry *entry;
+ dd_list *n, *next;
+
+ /**
+ * Usb host device must have at least one interface.
+ * An interface is matched with a specific usb class.
+ */
+ subsystem = udev_device_get_subsystem(dev);
+ devtype = udev_device_get_devtype(dev);
+ if (!subsystem || !devtype) {
+ _E("fail to get subsystem or devtype");
+ return;
+ }
+
+ /* devpath is an unique information among usb host devices */
+ devpath = udev_device_get_devpath(dev);
+ if (!devpath) {
+ _E("fail to get devpath from udev_device");
+ return;
+ }
+
+ action = udev_device_get_action(dev);
+ _I("subsystem : %s, devtype : %s, action : %s", subsystem, devtype, action);
+ /* Policy is valid for entire device, thus we check this devtype here */
+ if (strncmp(subsystem, USB_SUBSYSTEM, sizeof(USB_SUBSYSTEM)) == 0 &&
+ strncmp(devtype, USB_DEVICE_DEVTYPE, sizeof(USB_DEVICE_DEVTYPE)) == 0 &&
+ strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)) == 0) {
+ DD_LIST_FOREACH_SAFE(access_list, n, next, entry) {
+ if (is_policy_temporary(entry) &&
+ strcmp(devpath, entry->devpath) == 0) {
+ _I("removed temporary policy for %s", devpath);
+ DD_LIST_REMOVE(access_list, entry);
+ free(entry->creds.sec_label);
+ free(entry);
+ }
+ }
+ }
+
+ /**
+ * if devtype is not matched with usb subsystem
+ * and usb_interface devtype, skip.
+ */
+ if (strncmp(subsystem, USB_SUBSYSTEM, sizeof(USB_SUBSYSTEM)) ||
+ strncmp(devtype, USB_INTERFACE_DEVTYPE, sizeof(USB_INTERFACE_DEVTYPE)))
+ return;
+
+ if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)))
+ add_usbhost_list(dev, devpath);
+ else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE)))
+ remove_usbhost_list(devpath);
+}
+
+static int usbhost_init_from_udev_enumerate(void)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *list_entry;
+ struct udev_device *dev;
+ const char *syspath;
+ const char *devpath;
+
+ udev = udev_new();
+ if (!udev) {
+ _E("fail to create udev library context");
+ return -EPERM;
+ }
+
+ /* create a list of the devices in the 'usb' subsystem */
+ enumerate = udev_enumerate_new(udev);
+ if (!enumerate) {
+ _E("fail to create an enumeration context");
+ return -EPERM;
+ }
+
+ udev_enumerate_add_match_subsystem(enumerate, USB_SUBSYSTEM);
+ udev_enumerate_add_match_property(enumerate,
+ UDEV_DEVTYPE, USB_INTERFACE_DEVTYPE);
+ udev_enumerate_scan_devices(enumerate);
+
+ udev_list_entry_foreach(list_entry,
+ udev_enumerate_get_list_entry(enumerate)) {
+ syspath = udev_list_entry_get_name(list_entry);
+ if (!syspath)
+ continue;
+
+ dev = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
+ syspath);
+ if (!dev)
+ continue;
+
+ /* devpath is an unique information among usb host devices */
+ devpath = udev_device_get_devpath(dev);
+ if (!devpath) {
+ _E("fail to get devpath from %s device", syspath);
+ continue;
+ }
+
+ /* add usbhost list */
+ add_usbhost_list(dev, devpath);
+
+ udev_device_unref(dev);
+ }
+
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+ return 0;
+}
+
+static DBusMessage *print_device_list(E_DBus_Object *obj, DBusMessage *msg)
+{
+ dd_list *elem;
+ struct usbhost_device *usbhost;
+ int cnt = 0;
+
+ DD_LIST_FOREACH(usbhost_list, elem, usbhost) {
+ _I("== [%2d USB HOST DEVICE] ===============", cnt++);
+ print_usbhost(usbhost);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_device_list(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusMessageIter iter;
+ DBusMessageIter arr;
+ DBusMessageIter s;
+ DBusMessage *reply;
+ dd_list *elem;
+ struct usbhost_device *usbhost;
+ const char *str;
+ int baseclass;
+
+ reply = dbus_message_new_method_return(msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &baseclass, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ goto out;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter,
+ DBUS_TYPE_ARRAY, "(siiiiisss)", &arr);
+
+ DD_LIST_FOREACH(usbhost_list, elem, usbhost) {
+ if (baseclass != USB_CLASS_ALL && usbhost->baseclass != baseclass)
+ continue;
+ dbus_message_iter_open_container(&arr, DBUS_TYPE_STRUCT, NULL, &s);
+ str = usbhost->devpath;
+ dbus_message_iter_append_basic(&s, DBUS_TYPE_STRING, &str);
+ dbus_message_iter_append_basic(&s,
+ DBUS_TYPE_INT32, &usbhost->baseclass);
+ dbus_message_iter_append_basic(&s,
+ DBUS_TYPE_INT32, &usbhost->subclass);
+ dbus_message_iter_append_basic(&s,
+ DBUS_TYPE_INT32, &usbhost->protocol);
+ dbus_message_iter_append_basic(&s,
+ DBUS_TYPE_INT32, &usbhost->vendorid);
+ dbus_message_iter_append_basic(&s,
+ DBUS_TYPE_INT32, &usbhost->productid);
+ str = (!usbhost->manufacturer ? "" : usbhost->manufacturer);
+ dbus_message_iter_append_basic(&s, DBUS_TYPE_STRING, &str);
+ str = (!usbhost->product ? "" : usbhost->product);
+ dbus_message_iter_append_basic(&s, DBUS_TYPE_STRING, &str);
+ str = (!usbhost->serial ? "" : usbhost->serial);
+ dbus_message_iter_append_basic(&s, DBUS_TYPE_STRING, &str);
+ dbus_message_iter_close_container(&arr, &s);
+ }
+
+ dbus_message_iter_close_container(&iter, &arr);
+
+out:
+ return reply;
+}
+
+static DBusMessage *get_device_list_count(E_DBus_Object *obj, DBusMessage *msg)
+{
+ dd_list *elem;
+ struct usbhost_device *usbhost;
+ int baseclass;
+ int ret = 0;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &baseclass, DBUS_TYPE_INVALID)) {
+ _E("there is no message");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ DD_LIST_FOREACH(usbhost_list, elem, usbhost) {
+ if (baseclass != USB_CLASS_ALL && usbhost->baseclass != baseclass)
+ continue;
+ ret++;
+ }
+
+out:
+ return make_reply_message(msg, ret);
+}
+
+static struct uevent_handler uh = {
+ .subsystem = USB_SUBSYSTEM,
+ .uevent_func = uevent_usbhost_handler,
+};
+
+static const char *policy_value_str(enum policy_value value) {
+ switch (value) {
+ case POLICY_ALLOW_ALWAYS:
+ return "ALLOW";
+ case POLICY_ALLOW_NOW:
+ return "ALLOW_NOW";
+ case POLICY_DENY_ALWAYS:
+ return "DENY";
+ case POLICY_DENY_NOW:
+ return "DENY_NOW";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int get_policy_value_from_str(const char *str) {
+ if (strncmp("ALLOW", str, 5) == 0)
+ return POLICY_ALLOW_ALWAYS;
+ if (strncmp("ALLOW_NOW", str, 5) == 0)
+ return POLICY_ALLOW_NOW;
+ if (strncmp("DENY", str, 4) == 0)
+ return POLICY_DENY_ALWAYS;
+ if (strncmp("DENY_NOW", str, 4) == 0)
+ return POLICY_DENY_NOW;
+ return -1;
+}
+
+static inline int marshal_policy_entry(char *buf, int len, struct policy_entry *entry) {
+ if (is_policy_temporary(entry))
+ return snprintf(buf, len, "%d %s %s %s\n",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->devpath,
+ policy_value_str(entry->value));
+ return snprintf(buf, len, "%d %s %04x %02x %02x %02x %04x %04x %04x %s\n",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->device.bcdUSB,
+ entry->device.bDeviceClass,
+ entry->device.bDeviceSubClass,
+ entry->device.bDeviceProtocol,
+ entry->device.idVendor,
+ entry->device.idProduct,
+ entry->device.bcdDevice,
+ policy_value_str(entry->value));
+}
+
+static DBusMessage *print_policy(E_DBus_Object *obj, DBusMessage *msg) {
+ char line[ENTRY_LINE_SIZE];
+ dd_list *elem;
+ struct policy_entry *entry;
+ int ret;
+
+ _I("USB access policy:");
+ DD_LIST_FOREACH(access_list, elem, entry) {
+ ret = marshal_policy_entry(line, ENTRY_LINE_SIZE, entry);
+ if (ret < 0)
+ break;
+ _I("\t%s", line);
+ }
+
+ return dbus_message_new_method_return(msg);
+}
+
+static int store_policy(void)
+{
+ int fd;
+ dd_list *elem;
+ struct policy_entry *entry;
+ char line[256];
+ int ret;
+
+ fd = open(POLICY_FILEPATH, O_WRONLY | O_CREAT, 0664);
+ if (fd < 0) {
+ _E("Could not open policy file for writing: %m");
+ return -errno;
+ }
+
+ DD_LIST_FOREACH(access_list, elem, entry) {
+ if (is_policy_temporary(entry))
+ continue;
+
+ ret = marshal_policy_entry(line, ENTRY_LINE_SIZE, entry);
+ if (ret < 0) {
+ _E("Serialization failed: %m");
+ goto out;
+ }
+
+ ret = write(fd, line, ret);
+ if (ret < 0) {
+ ret = -errno;
+ _E("Error writing policy entry: %m");
+ goto out;
+ }
+ }
+
+ _I("Policy stored in %s", POLICY_FILEPATH);
+
+ ret = 0;
+
+out:
+ close(fd);
+ return ret;
+}
+
+static int read_policy(void)
+{
+ FILE *fp;
+ struct policy_entry *entry;
+ char *line = NULL, value_str[256];
+ int ret = -1;
+ int count = 0;
+ size_t len;
+
+ fp = fopen(POLICY_FILEPATH, "r");
+ if (!fp) {
+ ret = -errno;
+ _E("Could not open policy file for reading: %m");
+ return ret;
+ }
+
+ while ((ret = getline(&line, &len, fp)) != -1) {
+ entry = malloc(sizeof(*entry));
+ if (!entry) {
+ ret = -ENOMEM;
+ _E("No memory: %m");
+ goto out;
+ }
+
+ entry->creds.sec_label = calloc(ENTRY_LINE_SIZE, 1);
+ if (!entry->creds.sec_label) {
+ _E("No memory: %m");
+ goto out;
+ }
+
+ ret = sscanf(line, "%d %255s %04hx %02hhx %02hhx %02hhx %04hx %04hx %04hx %255s\n",
+ &entry->creds.uid,
+ entry->creds.sec_label,
+ &entry->device.bcdUSB,
+ &entry->device.bDeviceClass,
+ &entry->device.bDeviceSubClass,
+ &entry->device.bDeviceProtocol,
+ &entry->device.idVendor,
+ &entry->device.idProduct,
+ &entry->device.bcdDevice,
+ value_str);
+ if (ret == EOF) {
+ _E("Error reading line: %m");
+ free(entry->creds.sec_label);
+ free(entry);
+ goto out;
+ }
+
+ entry->value = get_policy_value_from_str(value_str);
+ if (entry->value < 0) {
+ _E("Invalid policy value: %s", value_str);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ _I("%04x:%04x : %s", entry->device.idVendor, entry->device.idProduct,
+ value_str);
+
+ DD_LIST_APPEND(access_list, entry);
+ count++;
+ }
+
+ _I("Found %d policy entries", count);
+ ret = 0;
+
+out:
+ fclose(fp);
+ free(line);
+
+ return ret;
+}
+
+static int get_device_desc(const char *filepath, struct usb_device_descriptor *desc, char *devpath)
+{
+ char *path = NULL;
+ const char *rdevpath;
+ struct stat st;
+ int ret;
+ int fd = -1;
+ struct udev *udev = NULL;
+ struct udev_device *udev_device = NULL;
+
+ ret = stat(filepath, &st);
+ if (ret < 0) {
+ ret = -errno;
+ _E("Could not stat %s: %m", filepath);
+ goto out;
+ }
+
+ if (!S_ISCHR(st.st_mode) ||
+ major(st.st_rdev) != USB_DEVICE_MAJOR) {
+ ret = -EINVAL;
+ _E("Not an USB device");
+ goto out;
+ }
+
+ udev = udev_new();
+ if (!udev) {
+ _E("Could not create udev contect");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ udev_device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
+ if (!udev_device) {
+ _E("udev could not find device");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ rdevpath = udev_device_get_devpath(udev_device);
+ strncpy(devpath, rdevpath, PATH_MAX);
+
+ ret = asprintf(&path, "/sys/dev/char/%d:%d/descriptors", major(st.st_rdev), minor(st.st_rdev));
+ if (ret < 0) {
+ ret = -ENOMEM;
+ _E("asprintf failed");
+ goto out;
+ }
+
+ _I("Opening descriptor at %s", path);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ _E("Failed to open %s: %m", path);
+ goto out;
+ }
+
+ ret = read(fd, desc, sizeof(*desc));
+ if (ret < 0) {
+ ret = -errno;
+ _E("Failed to read %s: %m", path);
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if (fd >= 0)
+ close(fd);
+ free(path);
+
+ udev_device_unref(udev_device);
+ udev_unref(udev);
+
+ return ret;
+}
+
+static void store_idler_cb(void *data)
+{
+ store_policy();
+}
+
+static void destroy_open_request(struct usbhost_open_request *req)
+{
+ _D("Destroing request structure");
+ free(req->path);
+ req->path = NULL;
+ req->reply_conn = NULL;
+ dbus_message_unref(req->msg);
+ req->msg = NULL;
+}
+
+static void finish_opening(struct usbhost_open_request *req, int policy)
+{
+ int ret;
+ int fd = -1;
+ DBusMessageIter iter;
+ DBusMessage *reply;
+ const char *err;
+
+ if (req->path == NULL)
+ return;
+
+ switch (policy) {
+ case POLICY_ALLOW_NOW:
+ case POLICY_ALLOW_ALWAYS:
+ fd = open(req->path, O_RDWR);
+ if (fd < 0) {
+ ret = -errno;
+ err = DBUS_ERROR_FAILED;
+ _E("Unable to open file (%s): %m", req->path);
+ } else
+ ret = 0;
+ break;
+ case POLICY_DENY_NOW:
+ case POLICY_DENY_ALWAYS:
+ ret = -EACCES;
+ err = DBUS_ERROR_ACCESS_DENIED;
+ break;
+ default:
+ ret = -EINVAL;
+ err = DBUS_ERROR_FAILED;
+ break;
+ }
+
+ if (ret < 0) {
+ reply = dbus_message_new_error(req->msg, err, NULL);
+ if (!reply) {
+ _E("Cannot allocate memory for error message");
+ goto out;
+ }
+ } else {
+ reply = dbus_message_new_method_return(req->msg);
+ if (!reply) {
+ _E("Cannot allocate memory for message");
+ goto out;
+ }
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+ }
+
+ e_dbus_message_send(req->reply_conn, reply, NULL, 0, NULL);
+
+out:
+ destroy_open_request(req);
+ if(fd >= 0)
+ close(fd);
+ _I("Popup destroyed");
+}
+
+static int spawn_popup(struct usbhost_open_request *req)
+{
+ char pid_str[8];
+ int ret;
+
+ if (!req)
+ return -EINVAL;
+
+ /* Handle for the previous popup */
+ if (current_request) {
+ finish_opening(current_request, POLICY_DENY_NOW);
+ free(current_request);
+ current_request = NULL;
+ }
+
+ _I("Launching popup");
+
+ snprintf(pid_str, sizeof(pid_str), "%d", req->cred.pid);
+ ret = launch_system_app(APP_DEFAULT, 4, APP_KEY_TYPE, "usbhost", "_APP_PID_", pid_str);
+ if (ret < 0) {
+ _E("could not launch system popup");
+ return ret;
+ }
+
+ return ret;
+}
+
+static void popup_result_signal_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ int allow, always;
+ int ret;
+ struct policy_entry *entry;
+ int value;
+ struct usbhost_open_request *req;
+
+ req = current_request;
+
+ if (!dbus_message_is_signal(msg, POPUP_INTERFACE_SYSTEM, USB_HOST_RESULT_SIGNAL))
+ return;
+
+ dbus_error_init(&err);
+ ret = dbus_message_get_args(msg, &err,
+ DBUS_TYPE_INT32, &allow,
+ DBUS_TYPE_INT32, &always,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ _E("no message: [%s:%s]", err.name, err.message);
+ value = POLICY_DENY_NOW;
+ goto out;
+ }
+
+ if (allow && always)
+ value = POLICY_ALLOW_ALWAYS;
+ else if (!allow && always)
+ value = POLICY_DENY_ALWAYS;
+ else if (allow && !always)
+ value = POLICY_ALLOW_NOW;
+ else
+ value = POLICY_DENY_NOW;
+
+ /* Save the policy */
+
+ entry = calloc(sizeof(*entry), 1);
+ if (!entry) {
+ _E("No memory");
+ goto out;
+ }
+
+ entry->creds.uid = req->cred.uid;
+ entry->creds.sec_label = calloc(strlen(req->cred.sec_label)+1, 1);
+ if (!entry->creds.sec_label) {
+ _E("No memory");
+ free(entry);
+ goto out;
+ }
+
+ strncpy(entry->creds.sec_label, req->cred.sec_label, strlen(req->cred.sec_label));
+
+ switch (value) {
+ case POLICY_ALLOW_ALWAYS:
+ case POLICY_DENY_ALWAYS:
+ entry->device.bcdUSB = le16toh(req->desc.bcdUSB);
+ entry->device.bDeviceClass = req->desc.bDeviceClass;
+ entry->device.bDeviceSubClass = req->desc.bDeviceSubClass;
+ entry->device.bDeviceProtocol = req->desc.bDeviceProtocol;
+ entry->device.idVendor = le16toh(req->desc.idVendor);
+ entry->device.idProduct = le16toh(req->desc.idProduct);
+ entry->device.bcdDevice = le16toh(req->desc.bcdDevice);
+
+ _I("Added policy entry: %d %s %04x %02x %02x %02x %04x %04x %04x %s",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->device.bcdUSB,
+ entry->device.bDeviceClass,
+ entry->device.bDeviceSubClass,
+ entry->device.bDeviceProtocol,
+ entry->device.idVendor,
+ entry->device.idProduct,
+ entry->device.bcdDevice,
+ policy_value_str(value));
+ break;
+ case POLICY_ALLOW_NOW:
+ case POLICY_DENY_NOW:
+ strncpy(entry->devpath, req->devpath, strlen(req->devpath));
+ _I("Added temporary policy entry: %d %s %s %s",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->devpath,
+ policy_value_str(value));
+ break;
+ }
+
+ entry->value = value;
+ DD_LIST_APPEND(access_list, entry);
+
+ ret = add_idle_request(store_idler_cb, NULL);
+ if (ret < 0) {
+ _E("fail to add store idle request : %d", ret);
+ store_idler_cb(NULL);
+ }
+
+out:
+ finish_opening(req, value);
+ free(current_request);
+ current_request = NULL;
+ dbus_error_free(&err);
+}
+
+static int get_policy_value(struct usbhost_open_request *req)
+{
+ int ret;
+ dd_list *elem;
+ struct policy_entry *entry;
+
+ memset(&req->desc, 0, sizeof(req->desc));
+
+ _I("Requested access from user %d to %s", req->cred.uid, req->path);
+ ret = get_device_desc(req->path, &req->desc, req->devpath);
+ if (ret < 0) {
+ _E("Could not get device descriptor");
+ return ret;
+ }
+
+ DD_LIST_FOREACH(access_list, elem, entry) {
+ if(entry->creds.uid != req->cred.uid
+ || strncmp(entry->creds.sec_label, req->cred.sec_label, strlen(req->cred.sec_label)) != 0)
+ continue;
+
+ if (is_policy_temporary(entry) ? strncmp(entry->devpath, req->devpath, PATH_MAX) :
+ entry->device.bcdUSB != le16toh(req->desc.bcdUSB)
+ || entry->device.bDeviceClass != req->desc.bDeviceClass
+ || entry->device.bDeviceSubClass != req->desc.bDeviceSubClass
+ || entry->device.bDeviceProtocol != req->desc.bDeviceProtocol
+ || entry->device.idVendor != le16toh(req->desc.idVendor)
+ || entry->device.idProduct != le16toh(req->desc.idProduct)
+ || entry->device.bcdDevice != le16toh(req->desc.bcdDevice))
+ continue;
+
+ _I("Found matching policy entry: %s", policy_value_str(entry->value));
+
+ return entry->value;
+ }
+
+ return POLICY_NONE;
+}
+
+static int creds_read_uint32(DBusMessageIter *iter, uint32_t *dest)
+{
+ int type;
+ DBusMessageIter sub;
+
+ dbus_message_iter_next(iter);
+
+ dbus_message_iter_recurse(iter, &sub);
+ type = dbus_message_iter_get_arg_type(&sub);
+ if (type != DBUS_TYPE_UINT32) {
+ _E("expected uint32");
+ return -EINVAL;
+ }
+
+ dbus_message_iter_get_basic(&sub, dest);
+
+ return 0;
+}
+
+static int creds_read_label(DBusMessageIter *iter, char **dest)
+{
+ int type;
+ DBusMessageIter sub, byte;
+ int n;
+
+ dbus_message_iter_next(iter);
+
+ dbus_message_iter_recurse(iter, &sub);
+ type = dbus_message_iter_get_arg_type(&sub);
+ if (type != DBUS_TYPE_ARRAY) {
+ _E("expected array of bytes");
+ return -EINVAL;
+ }
+
+ dbus_message_iter_recurse(&sub, &byte);
+ dbus_message_iter_get_fixed_array(&byte, dest, &n);
+
+ return n;
+}
+
+static int get_caller_credentials(DBusMessage *msg, struct user_credentials *cred)
+{
+ const char *cid;
+ char *key;
+ char *arr[1];
+ DBusMessage *reply;
+ DBusMessageIter iter, dict, entry;
+ dbus_bool_t ret;
+ int type;
+ int reti;
+
+ cid = dbus_message_get_sender(msg);
+ if (!cid) {
+ _E("Unable to identify client");
+ return -1;
+ }
+
+ arr[0] = (char *)cid;
+ reply = dbus_method_sync_with_reply(DBUS_BUS_NAME,
+ DBUS_OBJECT_PATH,
+ DBUS_INTERFACE_NAME,
+ METHOD_GET_CONNECTION_CREDENTIALS,
+ "s", arr);
+
+ if (!reply) {
+ _E("Cannot get connection credentials for %s", cid);
+ return -1;
+ }
+
+ ret = dbus_message_iter_init(reply, &iter);
+ if (!ret) {
+ _E("could not init msg iterator");
+ reti = -1;
+ goto out;
+ }
+
+ type = dbus_message_iter_get_arg_type(&iter);
+ if (type != DBUS_TYPE_ARRAY) {
+ _E("Expected array (%s)", cid);
+ reti = -EINVAL;
+ goto out;
+ }
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ while ((type = dbus_message_iter_get_arg_type(&dict)) != DBUS_TYPE_INVALID) {
+ if (type != DBUS_TYPE_DICT_ENTRY) {
+ _E("Expected dict entry (%s)", cid);
+ reti = -EINVAL;
+ goto out;
+ }
+
+ dbus_message_iter_recurse(&dict, &entry);
+ type = dbus_message_iter_get_arg_type(&entry);
+ if (type != DBUS_TYPE_STRING) {
+ _E("Expected string (%s)", cid);
+ reti = -EINVAL;
+ goto out;
+ }
+
+ dbus_message_iter_get_basic(&entry, &key);
+ if (strncmp(key, UID_KEY, sizeof(UID_KEY)) == 0) {
+ reti = creds_read_uint32(&entry, &cred->uid);
+ if (reti < 0)
+ goto out;
+ } else if (strncmp(key, SEC_LABEL_KEY, sizeof(SEC_LABEL_KEY)) == 0) {
+ reti = creds_read_label(&entry, &cred->sec_label);
+ if (reti < 0)
+ goto out;
+ } else if (strncmp(key, PID_KEY, sizeof(PID_KEY)) == 0) {
+ reti = creds_read_uint32(&entry, &cred->pid);
+ if (reti < 0)
+ goto out;
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+ reti = 0;
+
+out:
+ dbus_message_unref(reply);
+ return reti;
+}
+
+static void remove_all_access_list(void)
+{
+ struct policy_entry *entry;
+ dd_list *n, *next;
+
+ DD_LIST_FOREACH_SAFE(access_list, n, next, entry) {
+ DD_LIST_REMOVE(access_list, entry);
+ free(entry->creds.sec_label);
+ free(entry);
+ }
+}
+
+static DBusMessage *open_device(E_DBus_Object *obj, DBusMessage *msg)
+{
+ DBusError err;
+ dbus_bool_t dbus_ret;
+ int ret = 0;
+ int policy;
+ char *path;
+ struct usbhost_open_request *req;
+
+ dbus_error_init(&err);
+
+
+ req = calloc(sizeof(*req), 1);
+ if (!req) {
+ _E("no memory");
+ return dbus_message_new_error(msg, DBUS_ERROR_FAILED, "no memory");
+ }
+
+ req->msg = dbus_message_ref(msg);
+ req->reply_conn = e_dbus_object_conn_get(obj);
+
+ ret = get_caller_credentials(msg, &req->cred);
+ if (ret < 0) {
+ _E("Unable to get credentials for caller : %d", ret);
+ goto out;
+ }
+
+ dbus_ret = dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
+ if (!dbus_ret) {
+ _E("Unable to get arguments from message: %s", err.message);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ req->path = strdup(path);
+ policy = get_policy_value(req);
+ if (policy < 0) {
+ _E("Could not get policy value (%d)", policy);
+ ret = -1;
+ goto out;
+ }
+
+ /* Need to ask user */
+ if (policy == POLICY_NONE) {
+ ret = spawn_popup(req);
+ if (ret < 0) {
+ finish_opening(req, POLICY_DENY_NOW);
+ free(req);
+ return NULL;
+ }
+
+ current_request = req;
+ return NULL;
+ }
+
+ /* The policy exists for the app */
+ _D("Policy exists");
+ finish_opening(req, policy);
+ free(req);
+ return NULL;
+
+out:
+ destroy_open_request(req);
+ free(req);
+ return dbus_message_new_error(msg, DBUS_ERROR_FAILED, NULL);
+}
+
+static const struct edbus_method edbus_methods[] = {
+ { "PrintDeviceList", NULL, NULL, print_device_list }, /* for debugging */
+ { "PrintPolicy", NULL, NULL, print_policy }, /* for debugging */
+ { "GetDeviceList", "i", "a(siiiiisss)", get_device_list },
+ { "GetDeviceListCount", "i", "i", get_device_list_count },
+ { "OpenDevice", "s", "ih", open_device },
+};
+
+static int booting_done(void *data)
+{
+ /**
+ * To search the attched usb host device is not an argent task.
+ * So deviced does not load while booting time.
+ * After booting task is done, it tries to find the attached devices.
+ */
+ usbhost_init_from_udev_enumerate();
+
+ /* unregister booting done notifier */
+ unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+
+ return 0;
+}
+
+static void usbhost_init(void *data)
+{
+ int ret;
+
+ /* register usbhost uevent */
+ ret = register_kernel_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to register usb uevent : %d", ret);
+
+ /* register usbhost interface and method */
+ ret = register_edbus_interface_and_method(DEVICED_PATH_USBHOST,
+ DEVICED_INTERFACE_USBHOST,
+ edbus_methods, ARRAY_SIZE(edbus_methods));
+ if (ret < 0)
+ _E("fail to register edbus interface and method! %d", ret);
+
+ /* register notifier */
+ register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
+
+ ret = asprintf(&POLICY_FILEPATH, "%s/%s", ROOTPATH, POLICY_FILENAME);
+ if (ret < 0) {
+ _E("no memory for policy path");
+ return;
+ }
+
+ ret = register_edbus_signal_handler(POPUP_PATH_SYSTEM,
+ POPUP_INTERFACE_SYSTEM, USB_HOST_RESULT_SIGNAL,
+ popup_result_signal_handler);
+ if (ret < 0) {
+ _E("could not register popup signal handler");
+ return;
+ }
+
+ read_policy();
+}
+
+static void usbhost_exit(void *data)
+{
+ int ret;
+
+ /* unreigset usbhost uevent */
+ ret = unregister_kernel_uevent_control(&uh);
+ if (ret < 0)
+ _E("fail to unregister usb uevent : %d", ret);
+
+ /* remove all usbhost list */
+ remove_all_usbhost_list();
+
+ store_policy();
+ remove_all_access_list();
+
+ free(POLICY_FILEPATH);
+}
+
+static const struct device_ops usbhost_device_ops = {
+ .name = "usbhost",
+ .init = usbhost_init,
+ .exit = usbhost_exit,
+};
+
+DEVICE_OPS_REGISTER(&usbhost_device_ops)
--- /dev/null
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", DEVPATH!="/devices/platform/dummy_hcd.*", MODE="0660", GROUP="system_share", SECLABEL{smack}="*"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", DEVPATH=="/devices/platform/dummy_hcd.*", MODE="0666", GROUP="system_share", SECLABEL{smack}="*"