pass: Fork from deviced
authorWook Song <wook16.song@samsung.com>
Thu, 17 Nov 2016 04:21:15 +0000 (13:21 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 16 Jan 2017 11:35:36 +0000 (20:35 +0900)
This patch adds a bunch of files forked from deviced. In order to make
pass work as a separte systemd daemon, we start from the specific
snapshot of deviced.

Originates from:

ssh://review.tizen.org:29418/platform/core/system/deviced
(branch: accepted/tizen_3.0_mobile)
commit: 41f1d655807502f88027873a4509a50180fb1196

Note: since some of files including CMakeLists.txt,
packaging/deviced.spec are excluded for the technical reasons, you
cannot build it as deviced.

Signed-off-by: Wook Song <wook16.song@samsung.com>
164 files changed:
CREDITS [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.error.code [new file with mode: 0644]
src/apps/apps.c [new file with mode: 0755]
src/apps/apps.h [new file with mode: 0755]
src/battery/battery-time.c [new file with mode: 0644]
src/battery/battery.conf [new file with mode: 0644]
src/battery/battery.h [new file with mode: 0644]
src/battery/config.c [new file with mode: 0644]
src/battery/config.h [new file with mode: 0644]
src/battery/lowbat-handler.c [new file with mode: 0644]
src/battery/power-supply.c [new file with mode: 0644]
src/battery/power-supply.h [new file with mode: 0644]
src/block/block.c [new file with mode: 0644]
src/block/block.conf [new file with mode: 0644]
src/block/block.h [new file with mode: 0644]
src/block/ext4.c [new file with mode: 0644]
src/block/mmc.c [new file with mode: 0644]
src/block/storage.c [new file with mode: 0755]
src/block/storage.conf [new file with mode: 0644]
src/block/vfat.c [new file with mode: 0644]
src/control/control.c [new file with mode: 0644]
src/core/common.c [new file with mode: 0644]
src/core/common.h [new file with mode: 0644]
src/core/config-parser.c [new file with mode: 0644]
src/core/config-parser.h [new file with mode: 0644]
src/core/device-idler.c [new file with mode: 0644]
src/core/device-idler.h [new file with mode: 0644]
src/core/device-notifier.c [new file with mode: 0644]
src/core/device-notifier.h [new file with mode: 0644]
src/core/devices.c [new file with mode: 0644]
src/core/devices.h [new file with mode: 0644]
src/core/edbus-handler.c [new file with mode: 0644]
src/core/edbus-handler.h [new file with mode: 0644]
src/core/execute.c [new file with mode: 0755]
src/core/launch.c [new file with mode: 0644]
src/core/launch.h [new file with mode: 0644]
src/core/list.h [new file with mode: 0644]
src/core/log.c [new file with mode: 0644]
src/core/log.h [new file with mode: 0644]
src/core/main.c [new file with mode: 0644]
src/core/sig-handler.c [new file with mode: 0644]
src/core/udev.c [new file with mode: 0644]
src/core/udev.h [new file with mode: 0644]
src/devicectl/CMakeLists.txt [new file with mode: 0755]
src/devicectl/devicectl.c [new file with mode: 0644]
src/devicectl/usb.c [new file with mode: 0644]
src/devicectl/usb.h [new file with mode: 0644]
src/deviced/dd-common.h [new file with mode: 0644]
src/deviced/dd-control.h [new file with mode: 0644]
src/deviced/dd-deviced-managed.h [new file with mode: 0755]
src/deviced/dd-deviced.h [new file with mode: 0755]
src/deviced/dd-display.h [new file with mode: 0644]
src/deviced/dd-haptic.h [new file with mode: 0644]
src/deviced/dd-led.h [new file with mode: 0644]
src/deviced/dd-mmc.h [new file with mode: 0644]
src/deviced/dd-storage.h [new file with mode: 0644]
src/deviced/dd-usbhost.h [new file with mode: 0644]
src/deviced/deviced_doc.h [new file with mode: 0644]
src/deviced/haptic-module.h [new file with mode: 0644]
src/deviced/haptic-plugin-intf.h [new file with mode: 0644]
src/display/auto-brightness.c [new file with mode: 0644]
src/display/core.c [new file with mode: 0644]
src/display/core.h [new file with mode: 0644]
src/display/device-interface.c [new file with mode: 0644]
src/display/device-interface.h [new file with mode: 0644]
src/display/display-actor.c [new file with mode: 0644]
src/display/display-actor.h [new file with mode: 0644]
src/display/display-common.conf [new file with mode: 0644]
src/display/display-dbus.c [new file with mode: 0644]
src/display/display-ivi.conf [new file with mode: 0644]
src/display/display-mobile.conf [new file with mode: 0644]
src/display/display-ops.c [new file with mode: 0644]
src/display/display-ops.h [new file with mode: 0644]
src/display/display-tv.conf [new file with mode: 0644]
src/display/display-wearable.conf [new file with mode: 0644]
src/display/dpms-wayland-none.c [new file with mode: 0644]
src/display/dpms-x-none.c [new file with mode: 0644]
src/display/input.c [new file with mode: 0644]
src/display/key-filter.c [new file with mode: 0644]
src/display/lock-detector.c [new file with mode: 0644]
src/display/lock-detector.h [new file with mode: 0644]
src/display/poll.c [new file with mode: 0644]
src/display/poll.h [new file with mode: 0644]
src/display/setting.c [new file with mode: 0644]
src/display/setting.h [new file with mode: 0644]
src/display/state-tv.c [new file with mode: 0644]
src/display/util.h [new file with mode: 0644]
src/extcon/cradle.c [new file with mode: 0644]
src/extcon/earjack.c [new file with mode: 0644]
src/extcon/extcon.c [new file with mode: 0755]
src/extcon/extcon.h [new file with mode: 0755]
src/extcon/hdmi.c [new file with mode: 0644]
src/haptic/CMakeLists.txt [new file with mode: 0755]
src/haptic/README.standard [new file with mode: 0644]
src/haptic/circle.c [new file with mode: 0644]
src/haptic/edbus-handler.c [new file with mode: 0644]
src/haptic/edbus-handler.h [new file with mode: 0644]
src/haptic/emulator.c [new file with mode: 0644]
src/haptic/external.c [new file with mode: 0644]
src/haptic/haptic-micro.conf [new file with mode: 0644]
src/haptic/haptic-mobile.conf [new file with mode: 0644]
src/haptic/haptic.c [new file with mode: 0644]
src/haptic/haptic.h [new file with mode: 0644]
src/haptic/main.c [new file with mode: 0644]
src/haptic/standard-mix.c [new file with mode: 0644]
src/haptic/standard-vibcore.c [new file with mode: 0644]
src/haptic/standard-vibcore.h [new file with mode: 0644]
src/haptic/standard.c [new file with mode: 0644]
src/ir/ir.c [new file with mode: 0644]
src/led/noti.c [new file with mode: 0644]
src/led/torch.c [new file with mode: 0644]
src/led/torch.h [new file with mode: 0644]
src/led/touch-key.c [new file with mode: 0644]
src/led/touch-key.h [new file with mode: 0644]
src/libdeviced/CMakeLists.txt [new file with mode: 0755]
src/libdeviced/dbus.c [new file with mode: 0644]
src/libdeviced/deviced-conf.c [new file with mode: 0644]
src/libdeviced/deviced-noti.c [new file with mode: 0644]
src/libdeviced/deviced-util.c [new file with mode: 0644]
src/libdeviced/display.c [new file with mode: 0644]
src/libdeviced/haptic.c [new file with mode: 0644]
src/libdeviced/led.c [new file with mode: 0644]
src/libdeviced/mmc.c [new file with mode: 0644]
src/libdeviced/storage.c [new file with mode: 0644]
src/libdeviced/usbhost.c [new file with mode: 0644]
src/power/boot.c [new file with mode: 0644]
src/power/boot.h [new file with mode: 0644]
src/power/power-handler.c [new file with mode: 0644]
src/power/power-handler.h [new file with mode: 0644]
src/proc/cpu-info.c [new file with mode: 0644]
src/proc/proc-handler.c [new file with mode: 0644]
src/shared/CMakeLists.txt [new file with mode: 0755]
src/shared/common.h [new file with mode: 0644]
src/shared/dbus.c [new file with mode: 0644]
src/shared/dbus.h [new file with mode: 0644]
src/shared/deviced-internal.h [new file with mode: 0644]
src/shared/deviced-priv.h [new file with mode: 0644]
src/shared/deviced-systemd.c [new file with mode: 0644]
src/shared/deviced-systemd.h [new file with mode: 0644]
src/shared/log-macro.h [new file with mode: 0644]
src/shared/log.h [new file with mode: 0644]
src/shared/score-defines.h [new file with mode: 0644]
src/time/time-handler.c [new file with mode: 0644]
src/touchscreen/touchscreen.c [new file with mode: 0644]
src/tzip/tzip-utility.c [new file with mode: 0644]
src/tzip/tzip-utility.h [new file with mode: 0644]
src/tzip/tzip.c [new file with mode: 0644]
src/tzip/tzip.h [new file with mode: 0644]
src/usb-host-ffs-test-daemon/CMakeLists.txt [new file with mode: 0755]
src/usb-host-ffs-test-daemon/descs_gen.c [new file with mode: 0644]
src/usb-host-ffs-test-daemon/usb-host-ffs-test-daemon.c [new file with mode: 0644]
src/usb-host-test/test_gadget.gs [new file with mode: 0644]
src/usb-host-test/usb-host-test.c [new file with mode: 0644]
src/usb/usb-dbus.c [new file with mode: 0644]
src/usb/usb-operation.c [new file with mode: 0644]
src/usb/usb-operation.conf [new file with mode: 0644]
src/usb/usb-state.c [new file with mode: 0644]
src/usb/usb-tethering.c [new file with mode: 0644]
src/usb/usb-tethering.h [new file with mode: 0644]
src/usb/usb.c [new file with mode: 0644]
src/usb/usb.h [new file with mode: 0644]
src/usbhost/usb-host.c [new file with mode: 0644]
udev/99-usbhost.rules [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..c06cb19
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,15 @@
+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>
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..247c97d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+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.
diff --git a/README.error.code b/README.error.code
new file mode 100644 (file)
index 0000000..61cd9c6
--- /dev/null
@@ -0,0 +1,9 @@
+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
diff --git a/src/apps/apps.c b/src/apps/apps.c
new file mode 100755 (executable)
index 0000000..3e2433b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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);
+}
diff --git a/src/apps/apps.h b/src/apps/apps.h
new file mode 100755 (executable)
index 0000000..2d7b35a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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__ */
diff --git a/src/battery/battery-time.c b/src/battery/battery-time.c
new file mode 100644 (file)
index 0000000..125e658
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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)
diff --git a/src/battery/battery.conf b/src/battery/battery.conf
new file mode 100644 (file)
index 0000000..c882320
--- /dev/null
@@ -0,0 +1,9 @@
+[LOWBAT]
+#low battery level
+Normal=100
+Warning=15
+Critical=5
+PowerOff=1
+RealOff=0
+WarningMethod=warning
+CriticalMethod=critical
diff --git a/src/battery/battery.h b/src/battery/battery.h
new file mode 100644 (file)
index 0000000..f1496bb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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__ */
diff --git a/src/battery/config.c b/src/battery/config.c
new file mode 100644 (file)
index 0000000..4dd42c1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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);
+}
diff --git a/src/battery/config.h b/src/battery/config.h
new file mode 100644 (file)
index 0000000..77ca856
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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__ */
diff --git a/src/battery/lowbat-handler.c b/src/battery/lowbat-handler.c
new file mode 100644 (file)
index 0000000..cad1bf7
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * 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)
diff --git a/src/battery/power-supply.c b/src/battery/power-supply.c
new file mode 100644 (file)
index 0000000..bd98f9a
--- /dev/null
@@ -0,0 +1,1292 @@
+/*
+ * 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)
diff --git a/src/battery/power-supply.h b/src/battery/power-supply.h
new file mode 100644 (file)
index 0000000..24fb949
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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__ */
diff --git a/src/block/block.c b/src/block/block.c
new file mode 100644 (file)
index 0000000..47f2e8c
--- /dev/null
@@ -0,0 +1,2964 @@
+/*
+ * 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)
diff --git a/src/block/block.conf b/src/block/block.conf
new file mode 100644 (file)
index 0000000..8898468
--- /dev/null
@@ -0,0 +1,7 @@
+[Block]
+
+[MMC]
+Multimount=no # yes or no
+
+[SCSI]
+Multimount=yes # yes or no
diff --git a/src/block/block.h b/src/block/block.h
new file mode 100644 (file)
index 0000000..22ea223
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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__ */
diff --git a/src/block/ext4.c b/src/block/ext4.c
new file mode 100644 (file)
index 0000000..24f7e7e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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);
+}
+*/
diff --git a/src/block/mmc.c b/src/block/mmc.c
new file mode 100644 (file)
index 0000000..b3990cf
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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)
diff --git a/src/block/storage.c b/src/block/storage.c
new file mode 100755 (executable)
index 0000000..c5fb269
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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)
diff --git a/src/block/storage.conf b/src/block/storage.conf
new file mode 100644 (file)
index 0000000..331e786
--- /dev/null
@@ -0,0 +1,7 @@
+[LOWSTORAGE]
+#5%
+WARNING_LEVEL=5
+#0.1%
+CRITICAL_LEVEL=0.1
+#0.0%
+FULL_LEVEL=0
diff --git a/src/block/vfat.c b/src/block/vfat.c
new file mode 100644 (file)
index 0000000..5ad8e07
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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);
+}
+*/
diff --git a/src/control/control.c b/src/control/control.c
new file mode 100644 (file)
index 0000000..ffc09d2
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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)
diff --git a/src/core/common.c b/src/core/common.c
new file mode 100644 (file)
index 0000000..3cb598f
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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;
+}
diff --git a/src/core/common.h b/src/core/common.h
new file mode 100644 (file)
index 0000000..c0096b8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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__ */
diff --git a/src/core/config-parser.c b/src/core/config-parser.c
new file mode 100644 (file)
index 0000000..4018b88
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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;
+}
diff --git a/src/core/config-parser.h b/src/core/config-parser.h
new file mode 100644 (file)
index 0000000..7df70e6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
diff --git a/src/core/device-idler.c b/src/core/device-idler.c
new file mode 100644 (file)
index 0000000..e399bf2
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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;
+}
diff --git a/src/core/device-idler.h b/src/core/device-idler.h
new file mode 100644 (file)
index 0000000..411e4bb
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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__ */
diff --git a/src/core/device-notifier.c b/src/core/device-notifier.c
new file mode 100644 (file)
index 0000000..ff066c0
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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);
+}
diff --git a/src/core/device-notifier.h b/src/core/device-notifier.h
new file mode 100644 (file)
index 0000000..567e6bf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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__ */
diff --git a/src/core/devices.c b/src/core/devices.c
new file mode 100644 (file)
index 0000000..3ff5a8d
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/core/devices.h b/src/core/devices.h
new file mode 100644 (file)
index 0000000..c49499a
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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
diff --git a/src/core/edbus-handler.c b/src/core/edbus-handler.c
new file mode 100644 (file)
index 0000000..5c00b89
--- /dev/null
@@ -0,0 +1,1101 @@
+/*
+ * 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();
+}
diff --git a/src/core/edbus-handler.h b/src/core/edbus-handler.h
new file mode 100644 (file)
index 0000000..17eb956
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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__ */
diff --git a/src/core/execute.c b/src/core/execute.c
new file mode 100755 (executable)
index 0000000..1996c4d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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;
+}
diff --git a/src/core/launch.c b/src/core/launch.c
new file mode 100644 (file)
index 0000000..f481357
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * 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;
+
+}
diff --git a/src/core/launch.h b/src/core/launch.h
new file mode 100644 (file)
index 0000000..7c6d0dd
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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__ */
diff --git a/src/core/list.h b/src/core/list.h
new file mode 100644 (file)
index 0000000..bac4bbd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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
diff --git a/src/core/log.c b/src/core/log.c
new file mode 100644 (file)
index 0000000..86310cd
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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
diff --git a/src/core/log.h b/src/core/log.h
new file mode 100644 (file)
index 0000000..9684f38
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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
diff --git a/src/core/main.c b/src/core/main.c
new file mode 100644 (file)
index 0000000..f0ba440
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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);
+}
diff --git a/src/core/sig-handler.c b/src/core/sig-handler.c
new file mode 100644 (file)
index 0000000..17b0dfc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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)
diff --git a/src/core/udev.c b/src/core/udev.c
new file mode 100644 (file)
index 0000000..f11ea9b
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * 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)
diff --git a/src/core/udev.h b/src/core/udev.h
new file mode 100644 (file)
index 0000000..494e905
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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__ */
diff --git a/src/devicectl/CMakeLists.txt b/src/devicectl/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..a99104f
--- /dev/null
@@ -0,0 +1,33 @@
+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)
diff --git a/src/devicectl/devicectl.c b/src/devicectl/devicectl.c
new file mode 100644 (file)
index 0000000..4a06f99
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * 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);
+}
diff --git a/src/devicectl/usb.c b/src/devicectl/usb.c
new file mode 100644 (file)
index 0000000..9c3403f
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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;
+}
diff --git a/src/devicectl/usb.h b/src/devicectl/usb.h
new file mode 100644 (file)
index 0000000..e2285d8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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__*/
diff --git a/src/deviced/dd-common.h b/src/deviced/dd-common.h
new file mode 100644 (file)
index 0000000..fdfc2ac
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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__ */
diff --git a/src/deviced/dd-control.h b/src/deviced/dd-control.h
new file mode 100644 (file)
index 0000000..120ed6c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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
diff --git a/src/deviced/dd-deviced-managed.h b/src/deviced/dd-deviced-managed.h
new file mode 100755 (executable)
index 0000000..ba0af77
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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__ */
diff --git a/src/deviced/dd-deviced.h b/src/deviced/dd-deviced.h
new file mode 100755 (executable)
index 0000000..be62a03
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * 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__ */
diff --git a/src/deviced/dd-display.h b/src/deviced/dd-display.h
new file mode 100644 (file)
index 0000000..f7a7101
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * 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
diff --git a/src/deviced/dd-haptic.h b/src/deviced/dd-haptic.h
new file mode 100644 (file)
index 0000000..a3ee1ea
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * 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
diff --git a/src/deviced/dd-led.h b/src/deviced/dd-led.h
new file mode 100644 (file)
index 0000000..86cce22
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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
diff --git a/src/deviced/dd-mmc.h b/src/deviced/dd-mmc.h
new file mode 100644 (file)
index 0000000..af09714
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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
diff --git a/src/deviced/dd-storage.h b/src/deviced/dd-storage.h
new file mode 100644 (file)
index 0000000..9181e91
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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
diff --git a/src/deviced/dd-usbhost.h b/src/deviced/dd-usbhost.h
new file mode 100644 (file)
index 0000000..9bae8ae
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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
diff --git a/src/deviced/deviced_doc.h b/src/deviced/deviced_doc.h
new file mode 100644 (file)
index 0000000..6a478a3
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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__ */
diff --git a/src/deviced/haptic-module.h b/src/deviced/haptic-module.h
new file mode 100644 (file)
index 0000000..68d171e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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__ */
diff --git a/src/deviced/haptic-plugin-intf.h b/src/deviced/haptic-plugin-intf.h
new file mode 100644 (file)
index 0000000..6fe854d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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__ */
diff --git a/src/display/auto-brightness.c b/src/display/auto-brightness.c
new file mode 100644 (file)
index 0000000..6740d61
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ * 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)
diff --git a/src/display/core.c b/src/display/core.c
new file mode 100644 (file)
index 0000000..0aa2bd2
--- /dev/null
@@ -0,0 +1,2342 @@
+/*
+ * 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)
+
+/**
+ * @}
+ */
diff --git a/src/display/core.h b/src/display/core.h
new file mode 100644 (file)
index 0000000..45e96d6
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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
diff --git a/src/display/device-interface.c b/src/display/device-interface.c
new file mode 100644 (file)
index 0000000..f43256b
--- /dev/null
@@ -0,0 +1,767 @@
+/*
+ * 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;
+}
diff --git a/src/display/device-interface.h b/src/display/device-interface.h
new file mode 100644 (file)
index 0000000..d5b05fb
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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
diff --git a/src/display/display-actor.c b/src/display/display-actor.c
new file mode 100644 (file)
index 0000000..cf84602
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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;
+}
diff --git a/src/display/display-actor.h b/src/display/display-actor.h
new file mode 100644 (file)
index 0000000..e0dd570
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
diff --git a/src/display/display-common.conf b/src/display/display-common.conf
new file mode 100644 (file)
index 0000000..0457f54
--- /dev/null
@@ -0,0 +1,10 @@
+[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
diff --git a/src/display/display-dbus.c b/src/display/display-dbus.c
new file mode 100644 (file)
index 0000000..49ffee4
--- /dev/null
@@ -0,0 +1,1028 @@
+/*
+ * 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;
+}
diff --git a/src/display/display-ivi.conf b/src/display/display-ivi.conf
new file mode 100644 (file)
index 0000000..b10488c
--- /dev/null
@@ -0,0 +1,17 @@
+[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
diff --git a/src/display/display-mobile.conf b/src/display/display-mobile.conf
new file mode 100644 (file)
index 0000000..5abea3e
--- /dev/null
@@ -0,0 +1,31 @@
+[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
diff --git a/src/display/display-ops.c b/src/display/display-ops.c
new file mode 100644 (file)
index 0000000..df6cca8
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/display/display-ops.h b/src/display/display-ops.h
new file mode 100644 (file)
index 0000000..1c1102d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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
diff --git a/src/display/display-tv.conf b/src/display/display-tv.conf
new file mode 100644 (file)
index 0000000..20d092c
--- /dev/null
@@ -0,0 +1,14 @@
+[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
diff --git a/src/display/display-wearable.conf b/src/display/display-wearable.conf
new file mode 100644 (file)
index 0000000..237c2a0
--- /dev/null
@@ -0,0 +1,37 @@
+[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
diff --git a/src/display/dpms-wayland-none.c b/src/display/dpms-wayland-none.c
new file mode 100644 (file)
index 0000000..52b0ea6
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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;
+}
diff --git a/src/display/dpms-x-none.c b/src/display/dpms-x-none.c
new file mode 100644 (file)
index 0000000..5acdd2e
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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;
+}
diff --git a/src/display/input.c b/src/display/input.c
new file mode 100644 (file)
index 0000000..a65e5f4
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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;
+}
diff --git a/src/display/key-filter.c b/src/display/key-filter.c
new file mode 100644 (file)
index 0000000..eaafc9b
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * 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;
diff --git a/src/display/lock-detector.c b/src/display/lock-detector.c
new file mode 100644 (file)
index 0000000..62623f0
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * 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);
+       }
+}
diff --git a/src/display/lock-detector.h b/src/display/lock-detector.h
new file mode 100644 (file)
index 0000000..6900f3f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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_
diff --git a/src/display/poll.c b/src/display/poll.c
new file mode 100644 (file)
index 0000000..1381f98
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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;
+}
diff --git a/src/display/poll.h b/src/display/poll.h
new file mode 100644 (file)
index 0000000..7beb910
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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__ */
diff --git a/src/display/setting.c b/src/display/setting.c
new file mode 100644 (file)
index 0000000..fbc0359
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * 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;
+}
diff --git a/src/display/setting.h b/src/display/setting.h
new file mode 100644 (file)
index 0000000..9763c97
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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
diff --git a/src/display/state-tv.c b/src/display/state-tv.c
new file mode 100644 (file)
index 0000000..d496f16
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * 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);
+}
diff --git a/src/display/util.h b/src/display/util.h
new file mode 100644 (file)
index 0000000..a55f130
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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
diff --git a/src/extcon/cradle.c b/src/extcon/cradle.c
new file mode 100644 (file)
index 0000000..9b83013
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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)
diff --git a/src/extcon/earjack.c b/src/extcon/earjack.c
new file mode 100644 (file)
index 0000000..eb73b22
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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)
diff --git a/src/extcon/extcon.c b/src/extcon/extcon.c
new file mode 100755 (executable)
index 0000000..dd55e74
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * 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)
diff --git a/src/extcon/extcon.h b/src/extcon/extcon.h
new file mode 100755 (executable)
index 0000000..eb10fc9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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__ */
diff --git a/src/extcon/hdmi.c b/src/extcon/hdmi.c
new file mode 100644 (file)
index 0000000..9cdfb48
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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)
diff --git a/src/haptic/CMakeLists.txt b/src/haptic/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..537c938
--- /dev/null
@@ -0,0 +1,98 @@
+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")
diff --git a/src/haptic/README.standard b/src/haptic/README.standard
new file mode 100644 (file)
index 0000000..52cf000
--- /dev/null
@@ -0,0 +1,13 @@
+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.
diff --git a/src/haptic/circle.c b/src/haptic/circle.c
new file mode 100644 (file)
index 0000000..b9b2aa0
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * 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)
diff --git a/src/haptic/edbus-handler.c b/src/haptic/edbus-handler.c
new file mode 100644 (file)
index 0000000..37d5bdb
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * 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();
+}
diff --git a/src/haptic/edbus-handler.h b/src/haptic/edbus-handler.h
new file mode 100644 (file)
index 0000000..e933f48
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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__ */
diff --git a/src/haptic/emulator.c b/src/haptic/emulator.c
new file mode 100644 (file)
index 0000000..3dab6ae
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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)
diff --git a/src/haptic/external.c b/src/haptic/external.c
new file mode 100644 (file)
index 0000000..384d2e4
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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)
diff --git a/src/haptic/haptic-micro.conf b/src/haptic/haptic-micro.conf
new file mode 100644 (file)
index 0000000..464c6b4
--- /dev/null
@@ -0,0 +1,15 @@
+[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
diff --git a/src/haptic/haptic-mobile.conf b/src/haptic/haptic-mobile.conf
new file mode 100644 (file)
index 0000000..84271f1
--- /dev/null
@@ -0,0 +1,24 @@
+[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
diff --git a/src/haptic/haptic.c b/src/haptic/haptic.c
new file mode 100644 (file)
index 0000000..b04e671
--- /dev/null
@@ -0,0 +1,975 @@
+/*
+ * 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;
+}
diff --git a/src/haptic/haptic.h b/src/haptic/haptic.h
new file mode 100644 (file)
index 0000000..4ff97c6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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__ */
diff --git a/src/haptic/main.c b/src/haptic/main.c
new file mode 100644 (file)
index 0000000..ba12a7d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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;
+}
diff --git a/src/haptic/standard-mix.c b/src/haptic/standard-mix.c
new file mode 100644 (file)
index 0000000..d810955
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * 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)
diff --git a/src/haptic/standard-vibcore.c b/src/haptic/standard-vibcore.c
new file mode 100644 (file)
index 0000000..a458ce4
--- /dev/null
@@ -0,0 +1,256 @@
+#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;
+}
diff --git a/src/haptic/standard-vibcore.h b/src/haptic/standard-vibcore.h
new file mode 100644 (file)
index 0000000..ea54e14
--- /dev/null
@@ -0,0 +1,7 @@
+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();
diff --git a/src/haptic/standard.c b/src/haptic/standard.c
new file mode 100644 (file)
index 0000000..0558e63
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * 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)
diff --git a/src/ir/ir.c b/src/ir/ir.c
new file mode 100644 (file)
index 0000000..0921781
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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)
diff --git a/src/led/noti.c b/src/led/noti.c
new file mode 100644 (file)
index 0000000..da9970b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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;
+}
diff --git a/src/led/torch.c b/src/led/torch.c
new file mode 100644 (file)
index 0000000..4bf581d
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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)
diff --git a/src/led/torch.h b/src/led/torch.h
new file mode 100644 (file)
index 0000000..8a8a8d3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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
diff --git a/src/led/touch-key.c b/src/led/touch-key.c
new file mode 100644 (file)
index 0000000..f2b0ced
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * 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)
diff --git a/src/led/touch-key.h b/src/led/touch-key.h
new file mode 100644 (file)
index 0000000..02af982
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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
diff --git a/src/libdeviced/CMakeLists.txt b/src/libdeviced/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..8ca1402
--- /dev/null
@@ -0,0 +1,42 @@
+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)
diff --git a/src/libdeviced/dbus.c b/src/libdeviced/dbus.c
new file mode 100644 (file)
index 0000000..c26711e
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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, &param[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();
+}
diff --git a/src/libdeviced/deviced-conf.c b/src/libdeviced/deviced-conf.c
new file mode 100644 (file)
index 0000000..4a45690
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * 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);
+}
diff --git a/src/libdeviced/deviced-noti.c b/src/libdeviced/deviced-noti.c
new file mode 100644 (file)
index 0000000..812f63c
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * 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");
+}
diff --git a/src/libdeviced/deviced-util.c b/src/libdeviced/deviced-util.c
new file mode 100644 (file)
index 0000000..8071c7a
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/display.c b/src/libdeviced/display.c
new file mode 100644 (file)
index 0000000..f9174b2
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/haptic.c b/src/libdeviced/haptic.c
new file mode 100644 (file)
index 0000000..6971fe7
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/led.c b/src/libdeviced/led.c
new file mode 100644 (file)
index 0000000..b27c3f3
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/mmc.c b/src/libdeviced/mmc.c
new file mode 100644 (file)
index 0000000..6178cf9
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/storage.c b/src/libdeviced/storage.c
new file mode 100644 (file)
index 0000000..23fbe8d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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;
+}
diff --git a/src/libdeviced/usbhost.c b/src/libdeviced/usbhost.c
new file mode 100644 (file)
index 0000000..1cb0d1d
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 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;
+}
diff --git a/src/power/boot.c b/src/power/boot.c
new file mode 100644 (file)
index 0000000..33a72ce
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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);
+}
diff --git a/src/power/boot.h b/src/power/boot.h
new file mode 100644 (file)
index 0000000..ff20fac
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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__ */
diff --git a/src/power/power-handler.c b/src/power/power-handler.c
new file mode 100644 (file)
index 0000000..b2679d5
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * 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)
diff --git a/src/power/power-handler.h b/src/power/power-handler.h
new file mode 100644 (file)
index 0000000..b7d7c28
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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__ */
diff --git a/src/proc/cpu-info.c b/src/proc/cpu-info.c
new file mode 100644 (file)
index 0000000..48795f1
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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)
diff --git a/src/proc/proc-handler.c b/src/proc/proc-handler.c
new file mode 100644 (file)
index 0000000..6d3f43c
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * 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)
diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5c6284f
--- /dev/null
@@ -0,0 +1,20 @@
+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")
diff --git a/src/shared/common.h b/src/shared/common.h
new file mode 100644 (file)
index 0000000..5a3ef23
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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__ */
diff --git a/src/shared/dbus.c b/src/shared/dbus.c
new file mode 100644 (file)
index 0000000..e97d8d5
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * 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, &param[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();
+}
diff --git a/src/shared/dbus.h b/src/shared/dbus.h
new file mode 100644 (file)
index 0000000..deabf95
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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
diff --git a/src/shared/deviced-internal.h b/src/shared/deviced-internal.h
new file mode 100644 (file)
index 0000000..b26d67e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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___ */
diff --git a/src/shared/deviced-priv.h b/src/shared/deviced-priv.h
new file mode 100644 (file)
index 0000000..0adb00f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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__ */
diff --git a/src/shared/deviced-systemd.c b/src/shared/deviced-systemd.c
new file mode 100644 (file)
index 0000000..8358256
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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;
+}
diff --git a/src/shared/deviced-systemd.h b/src/shared/deviced-systemd.h
new file mode 100644 (file)
index 0000000..4dabe0a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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
diff --git a/src/shared/log-macro.h b/src/shared/log-macro.h
new file mode 100644 (file)
index 0000000..407995e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
diff --git a/src/shared/log.h b/src/shared/log.h
new file mode 100644 (file)
index 0000000..29b6c85
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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
diff --git a/src/shared/score-defines.h b/src/shared/score-defines.h
new file mode 100644 (file)
index 0000000..44638e7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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__ */
diff --git a/src/time/time-handler.c b/src/time/time-handler.c
new file mode 100644 (file)
index 0000000..bd49904
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * 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)
diff --git a/src/touchscreen/touchscreen.c b/src/touchscreen/touchscreen.c
new file mode 100644 (file)
index 0000000..c9160fd
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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)
diff --git a/src/tzip/tzip-utility.c b/src/tzip/tzip-utility.c
new file mode 100644 (file)
index 0000000..3553788
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * 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;
+}
diff --git a/src/tzip/tzip-utility.h b/src/tzip/tzip-utility.h
new file mode 100644 (file)
index 0000000..9045638
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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__ */
diff --git a/src/tzip/tzip.c b/src/tzip/tzip.c
new file mode 100644 (file)
index 0000000..42816f4
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * 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)
diff --git a/src/tzip/tzip.h b/src/tzip/tzip.h
new file mode 100644 (file)
index 0000000..6a33050
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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__
diff --git a/src/usb-host-ffs-test-daemon/CMakeLists.txt b/src/usb-host-ffs-test-daemon/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..360958f
--- /dev/null
@@ -0,0 +1,27 @@
+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)
diff --git a/src/usb-host-ffs-test-daemon/descs_gen.c b/src/usb-host-ffs-test-daemon/descs_gen.c
new file mode 100644 (file)
index 0000000..3e7763a
--- /dev/null
@@ -0,0 +1,147 @@
+#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;
+}
diff --git a/src/usb-host-ffs-test-daemon/usb-host-ffs-test-daemon.c b/src/usb-host-ffs-test-daemon/usb-host-ffs-test-daemon.c
new file mode 100644 (file)
index 0000000..af17f97
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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;
+}
diff --git a/src/usb-host-test/test_gadget.gs b/src/usb-host-test/test_gadget.gs
new file mode 100644 (file)
index 0000000..86fc895
--- /dev/null
@@ -0,0 +1,49 @@
+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";
+            });
+    } );
diff --git a/src/usb-host-test/usb-host-test.c b/src/usb-host-test/usb-host-test.c
new file mode 100644 (file)
index 0000000..e87e05d
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * 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)
diff --git a/src/usb/usb-dbus.c b/src/usb/usb-dbus.c
new file mode 100644 (file)
index 0000000..ccd0393
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * 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;
+}
diff --git a/src/usb/usb-operation.c b/src/usb/usb-operation.c
new file mode 100644 (file)
index 0000000..0484cd3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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);
+}
diff --git a/src/usb/usb-operation.conf b/src/usb/usb-operation.conf
new file mode 100644 (file)
index 0000000..32db01a
--- /dev/null
@@ -0,0 +1,17 @@
+[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
diff --git a/src/usb/usb-state.c b/src/usb/usb-state.c
new file mode 100644 (file)
index 0000000..28b2af0
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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;
+       }
+}
diff --git a/src/usb/usb-tethering.c b/src/usb/usb-tethering.c
new file mode 100644 (file)
index 0000000..e675b24
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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);
+}
diff --git a/src/usb/usb-tethering.h b/src/usb/usb-tethering.h
new file mode 100644 (file)
index 0000000..998be13
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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__ */
diff --git a/src/usb/usb.c b/src/usb/usb.c
new file mode 100644 (file)
index 0000000..18f1949
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 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)
diff --git a/src/usb/usb.h b/src/usb/usb.h
new file mode 100644 (file)
index 0000000..fe55917
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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__ */
diff --git a/src/usbhost/usb-host.c b/src/usbhost/usb-host.c
new file mode 100644 (file)
index 0000000..2679cac
--- /dev/null
@@ -0,0 +1,1321 @@
+/*
+ * 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)
diff --git a/udev/99-usbhost.rules b/udev/99-usbhost.rules
new file mode 100644 (file)
index 0000000..a719bec
--- /dev/null
@@ -0,0 +1,2 @@
+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}="*"