diff options
author | HyungKyu Song <hk76.song@samsung.com> | 2013-02-16 00:16:31 +0900 |
---|---|---|
committer | HyungKyu Song <hk76.song@samsung.com> | 2013-02-16 00:16:31 +0900 |
commit | 35b76e7f3aa051063a4461062cb31fdf75882c54 (patch) | |
tree | f77d1a3163d94af71eccff5d657a1a3529190082 | |
parent | 91545a9743ec602ae4d8d207836865850a3532f1 (diff) | |
download | power-manager-tizen_2.0.tar.gz power-manager-tizen_2.0.tar.bz2 power-manager-tizen_2.0.zip |
40 files changed, 5011 insertions, 0 deletions
@@ -0,0 +1,2 @@ +Seunghun Pi <sh.pi at samsung dot com>
+Suchang Woo <suchang.woo at samsung dot com>
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c75267d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(power_manager C) + +SET(SRCS + util.c + main.c + pm_llinterface.c + pm_conf.c + pm_setting.c + pm_poll.c + pm_core.c + pm_lsensor.c + pm_device_plugin.c + pm_key_filter.c + pm_battery.c ) + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") +MESSAGE("Build type: ${CMAKE_BUILD_TYPE}") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED vconf glib-2.0 sysman aul dlog heynoti devman_plugin sensor) + +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("-DENABLE_KEY_FILTER") +ADD_DEFINITIONS("-DENABLE_X_LCD_ONOFF") +ADD_DEFINITIONS("-DENABLE_DLOG_OUT") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -ldl) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC ${PROJECT_NAME}) +CONFIGURE_FILE(pmctrl.in pmctrl @ONLY) + +SET(UDEV_RULES_PATH share/power-manager/udev-rules) +SET(UDEV_RULES udev-rules/91-power-manager.rules) + +CONFIGURE_FILE(${UDEV_RULES}.in ${UDEV_RULES} @ONLY) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/pmctrl DESTINATION bin) +INSTALL(FILES ${UDEV_RULES} DESTINATION ${UDEV_RULES_PATH}) +INSTALL(PROGRAMS ${CMAKE_SOURCE_DIR}/pmctrl DESTINATION /etc/rc.d/init.d) + +ADD_SUBDIRECTORY(pm_event) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,202 @@ + + 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. @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, This software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..f2640b9 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,16 @@ +power-manager (1.3.21-96) unstable; urgency=low + + * Update for tizen 2.0 + * Git: magnolia/framework/system/power-manager + * Tag: power-manager_1.3.21-96 + + -- Seunghun Pi <sh.pi@samsung.com> Thu, 23 Aug 2012 10:43:03 +0900 + +power-manager (1.3.21-87) unstable; urgency=low + + * update for new oal layer + * Git: slp/pkgs/p/power-manager + * Tag: power-manager_1.3.21-87 + + -- Jinkun Jang <jinkun.jang@samsung.com> Mon, 09 Apr 2012 14:47:03 +0900 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d74f208 --- /dev/null +++ b/debian/control @@ -0,0 +1,20 @@ +Source: power-manager +Section: system +Priority: extra +Maintainer: Jonghoon Han <jonghoon.han@samsung.com> Jinkun Jang <jinkun.jang@samsung.com> DongGi Jang <dg0402.jang@samsung.com> TAESOO JUN <steve.jun@samsung.com> +Uploaders: Jinkun Jang <jinkun.jang@samsung.com> +Build-Depends: debhelper (>= 5), libglib2.0-dev, libslp-setting-dev, libslp-sysman-dev, libaul-1-dev, dlog-dev, libheynoti-dev, libslp-sensor-dev, libdevman-plugin-dev +Standards-Version: 3.7.2 + +Package: power-manager-bin +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Power manager + Power manager + +Package: power-manager-bin-dbg +Section: debug +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, power-manager-bin (= ${Source-Version}) +Description: Power manager + Power manager (unstripped) diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/debian/copyright @@ -0,0 +1 @@ + diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..ca882bb --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..a0f0008 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +CMakeLists.txt diff --git a/debian/power-manager-bin.install.in b/debian/power-manager-bin.install.in new file mode 100644 index 0000000..f564239 --- /dev/null +++ b/debian/power-manager-bin.install.in @@ -0,0 +1,3 @@ +@PREFIX@/bin/* +@PREFIX@/share/power-manager/* +etc/* diff --git a/debian/power-manager-bin.postinst.in b/debian/power-manager-bin.postinst.in new file mode 100644 index 0000000..7805f53 --- /dev/null +++ b/debian/power-manager-bin.postinst.in @@ -0,0 +1,11 @@ +#!/bin/sh + +vconftool set -t int memory/pm/state 0 -i + +heynotitool set system_wakeup + +mkdir -p /etc/udev/rules.d +if ! [ -L /etc/udev/rules.d/91-power-manager.rules ]; then + ln -s @PREFIX@/share/power-manager/udev-rules/91-power-manager.rules /etc/udev/rules.d/91-power-manager.rules +fi + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..10c3e3d --- /dev/null +++ b/debian/rules @@ -0,0 +1,138 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +CFLAGS ?= -Wall -g +CXXFLAGS ?= -Wall -g +LDFLAGS ?= +PREFIX ?= /usr +DATADIR ?= /opt + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 + CXXFLAGS += -O0 +else + CFLAGS += -O2 + CXXFLAGS += -O2 +endif + +LDFLAGS += -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" cmake . -DCMAKE_INSTALL_PREFIX=$(PREFIX) + + touch configure-stamp + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #docbook-to-man debian/wavplayer.sgml > wavplayer.1 + + for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ + cat $$f > $${f%.in}; \ + sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \ + sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \ + done + + + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + rm -rf CMakeCache.txt + rm -rf CMakeFiles + rm -rf cmake_install.cmake + rm -rf Makefile + rm -rf install_manifest.txt + rm -rf *.so + rm -rf ./pm_event/CMakeCache.txt + rm -rf ./pm_event/CMakeFiles + rm -rf ./pm_event/cmake_install.cmake + rm -rf ./pm_event/Makefile + rm -rf ./pm_event/install_manifest.txt + rm -rf ./pm_event/pm_event + + for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ + rm -f $${f%.in}; \ + done + + for f in `find $(CURDIR)/ -name "*.in"`; do \ + rm -f $${f%.in}; \ + done + + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/wavplayer. + $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + + mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc3.d/ + mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc5.d/ + + ln -s ../init.d/power_manager.sh $(CURDIR)/debian/tmp/etc/rc.d/rc3.d/S35power-manager + ln -s ../init.d/power_manager.sh $(CURDIR)/debian/tmp/etc/rc.d/rc5.d/S00power-manager + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_install --sourcedir=debian/tmp +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_python +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link +# dh_strip + dh_strip --dbg-package=power-manager-bin-dbg + dh_compress + dh_fixperms +# dh_perl + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure patch unpatch @@ -0,0 +1,133 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 main.c + * @version 0.1 + * @brief Power Manager main file + * + * Process the user options, Daemonize the process, Start Main loop + */ + +/** + * @addtogroup POWER_MANAGER + * @{ + * + * @section execution How to execute + * # powermanager {options...} <br> + * + * Options: <br><br> + * -f --foreground<br> + * Run as foreground process<br> <br> + * -d --direct<br> + * Start without notification<br> <br> + * + * @} + */ +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <limits.h> +#include <unistd.h> + +#include "pm_core.h" + +/** + * Print the usage + * + * @internal + */ +void usage() +{ + printf("Options: \n"); + printf(" -f, --foreground Run as foreground process\n"); + printf(" -d, --direct Start without notification\n"); + printf + (" -x, --xdpms With LCD-onoff control by x-dpms \n"); + printf("\n"); + + exit(0); +} + +/** + * Pid file path + */ +#define DEFAULT_PID_PATH "/var/run/power-manager.pid" + +int main(int argc, char *argv[]) +{ + int c; + int runflags = 0; /* run as daemon */ + unsigned int flags = 0x0; /* 0 : start with noti */ + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"foreground", no_argument, NULL, 'f'}, + {"direct", no_argument, NULL, 'd'}, + {"xdpms", no_argument, NULL, 'x'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "fdx", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'f': + runflags = 1; + break; + + case 'd': + flags = flags | WITHOUT_STARTNOTI; /* 0x1 : start without noti */ + break; + + case 'x': + flags = flags | FLAG_X_DPMS; /* 0x2 : X control LCD onoff */ + break; + + default: + usage(); + break; + } + } + + if (optind < argc) + usage(); + + if (access(DEFAULT_PID_PATH, F_OK) == 0) { /* pid file exist */ + printf + ("Check the PM is running. If it isn't, delete \"%s\" and retry.\n", + DEFAULT_PID_PATH); + return -1; + } + + if (!runflags) + daemonize(); + + writepid(DEFAULT_PID_PATH); + + /* this function is main loop, defined in pm_core.c */ + start_main(flags); + + unlink(DEFAULT_PID_PATH); + return 0; +} diff --git a/packaging/power-manager.manifest b/packaging/power-manager.manifest new file mode 100644 index 0000000..e4d4971 --- /dev/null +++ b/packaging/power-manager.manifest @@ -0,0 +1,13 @@ +<manifest> + <define> + <domain name="power_manager"/> + </define> + <request> + <domain name="power_manager"/> + </request> + <assign> + <filesystem path="/etc/rc.d/init.d/pmctrl" label="_" exec_label="none" /> + <filesystem path="/etc/rc.d/rc3.d/S35power-manager" label="_" exec_label="none" /> + </assign> +</manifest> + diff --git a/packaging/power-manager.service b/packaging/power-manager.service new file mode 100644 index 0000000..13609c8 --- /dev/null +++ b/packaging/power-manager.service @@ -0,0 +1,10 @@ +[Unit] +Description=Start the power manager service + +[Service] +Type=forking +ExecStart=/usr/bin/pmctrl start +Environment=DISPLAY=:0 + +[Install] +WantedBy=multi-user.target diff --git a/packaging/power-manager.spec b/packaging/power-manager.spec new file mode 100644 index 0000000..0004a9c --- /dev/null +++ b/packaging/power-manager.spec @@ -0,0 +1,83 @@ +Name: power-manager +Summary: Power manager +Version: 1.3.23 +Release: 8 +Group: framework/system +License: APLv2 +Source0: %{name}-%{version}.tar.gz +Source1001: packaging/power-manager.manifest +Requires(post): /usr/bin/vconftool +Source1: power-manager.service +BuildRequires: cmake +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(sysman) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(sensor) +BuildRequires: pkgconfig(devman) +BuildRequires: pkgconfig(devman_plugin) +BuildRequires: pkgconfig(heynoti) + +%description +Description: Power manager + + +%prep +%setup -q + +%build +cp %{SOURCE1001} . +%ifnarch %arm +%if 0%{?simulator} +#for emulator +CFLAGS+=" -DTIZEN_EMUL" +%else +#for real device +CFLAGS+=" -DX86" +%endif +export CFLAGS +%endif +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants +install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/power-manager.service +ln -s ../power-manager.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/power-manager.service + +mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc3.d/ +mkdir -p %{buildroot}%{_sysconfdir}/rc.d/rc5.d/ +ln -s %{_sysconfdir}/init.d/pmctrl %{buildroot}%{_sysconfdir}/rc.d/rc3.d/S35power-manager +ln -s %{_sysconfdir}/init.d/pmctrl %{buildroot}%{_sysconfdir}/rc.d/rc5.d/S00power-manager + +%post +vconftool set -t int memory/pm/state 0 -i +vconftool set -t int memory/pm/battery_timetofull -1 -i +vconftool set -t int memory/pm/battery_timetoempty -1 -i +vconftool set -t int memory/pm/custom_brightness_status 0 -i -g 5000 +vconftool set -t bool memory/pm/brt_changed_lpm 0 -i + +heynotitool set system_wakeup +heynotitool set pm_event + +mkdir -p /etc/udev/rules.d +if ! [ -L /etc/udev/rules.d/91-power-manager.rules ]; then + ln -s %{_datadir}/power-manager/udev-rules/91-power-manager.rules /etc/udev/rules.d/91-power-manager.rules +fi + +%files +%manifest power-manager.manifest +%{_sysconfdir}/rc.d/init.d/pmctrl +%{_sysconfdir}/rc.d/rc3.d/S35power-manager +%{_sysconfdir}/rc.d/rc5.d/S00power-manager +%{_bindir}/pm_event +%{_bindir}/pmctrl +%{_bindir}/power_manager +%{_libdir}/systemd/system/power-manager.service +%{_libdir}/systemd/system/multi-user.target.wants/power-manager.service +%{_datadir}/power-manager/udev-rules/91-power-manager.rules diff --git a/pm_battery.c b/pm_battery.c new file mode 100644 index 0000000..a413774 --- /dev/null +++ b/pm_battery.c @@ -0,0 +1,424 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include <glib.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include "pm_core.h" +#include "pm_device_plugin.h" +#include "pm_battery.h" + +#define CHARGING_STATE(x) ((x) & CHRGR_FLAG) +#define FULL_CAPACITY_RAW (10000) +#define FULL_CAPACITY (100) +#define BATTERY_FULL_THRESHOLD (98) +#define MAX_COUNT_UNCHARGING (5) +#define MAX_COUNT_CHARGING (5) +#define PRINT_ALL_BATT_NODE(x) /*print_all_batt_node(x)*/ + +int (*get_battery_capacity)(); + +enum state_b { + B_UNCHARGING = 0, + B_CHARGING = 1, + B_END = 2 +}; + +typedef struct _batt_node { + time_t clock; + int capacity; + struct _batt_node *preview; + struct _batt_node *next; +} Batt_node; + +enum state_a { + A_TIMETOEMPTY = 0, + A_TIMETOFULL = 1, + A_END = 2 +}; + +static int timeout_id = 0; +static int noti_fd = 0; + +static Batt_node *batt_head[B_END]; +static 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 full_capacity = 0; +static int old_capacity = 0; +static int charging_state = 0; +static int multiply_value[B_END] = {-1, 1}; + +static void print_all_batt_node(enum state_b b_index) +{ + Batt_node *node = NULL; + int cnt = 0; + + LOGINFO("print_all_batt_node [%d]", b_index); + + if(b_index < 0 || b_index >= B_END) + return; + + if(batt_head[b_index] == NULL) + return; + + node = batt_head[b_index]; + while(node != NULL) { + cnt++; + LOGINFO("[%d] capacity %5d, time %s", cnt, node->capacity, + ctime(&node->clock)); + node = node->next; + } +} + +static int check_value_validity(enum state_b b_index,time_t clock,int capacity) +{ + time_t old_clock = 0; + int old_capacity = 0; + int capadiff = 0; + + if(b_index < 0 || b_index >= B_END) + return -1; + + if(batt_head[b_index] == NULL) + return 0; + + old_capacity = batt_head[b_index]->capacity; + + if(system_wakeup_flag == true) { + LOGERR("check value validity : invalid cuz system suspend!"); + system_wakeup_flag = false; + return -1; + } + /* capacity */ + capadiff = capacity - old_capacity; + if((capadiff * multiply_value[b_index]) <= 0) { + LOGERR("check value validity : capadiff(%d) wrong!", capadiff); + return -1; + } + return 0; +} + +static int add_batt_node(enum state_b b_index, time_t clock, int capacity) +{ + Batt_node *node = NULL; + + PRINT_ALL_BATT_NODE(b_index); + + if(b_index < 0 || b_index >= B_END) + return -1; + + node = (Batt_node *) malloc(sizeof(Batt_node)); + if(node == NULL) { + LOGERR("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) +{ + Batt_node *node = NULL; + 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) +{ + 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) +{ + 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++; + + /*LOGINFO("[%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; + } + } + LOGINFO(" sum = %lf", total_factor); + total_factor /= (float)cnt; + LOGINFO(" avg_factor = %lf", total_factor); + + return total_factor; +} + +static void update_time(enum state_a a_index, int seconds) +{ + int clock; + + if(a_index < 0 || a_index >= A_END) + return; + + if(seconds <= 0) + return; + + switch(a_index) { + case A_TIMETOFULL: + vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOFULL, + seconds); + LOGINFO("update time[%d,%d]", a_index, seconds); + break; + case A_TIMETOEMPTY: + vconf_set_int(VCONFKEY_PM_BATTERY_TIMETOEMPTY, + seconds); + LOGINFO("update time[%d,%d]", a_index, seconds); + break; + } +} + +void battinfo_calculation() +{ + time_t clock; + int capacity = 0; + int estimated_time = 0; + int tmp = 0; + + capacity = get_battery_capacity(); + + if(capacity <= 0) + return; + if(capacity == old_capacity) + return; + + old_capacity = capacity; + + if(get_charging_status(&tmp) == 0) + charging_state = (tmp > 0 ? TRUE : FALSE); + + clock = time(NULL); + if(charging_state == TRUE) { + del_all_batt_node(B_UNCHARGING); + if((capacity * 100 / full_capacity) + >= BATTERY_FULL_THRESHOLD) { + if(battery_charge_full()) { + del_all_batt_node(B_CHARGING); + LOGINFO("battery fully charged!"); + update_time(A_TIMETOFULL, 0); + return; + } + } + 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); + } +} + +static gboolean battinfo_cb(gpointer data) +{ + battinfo_calculation(); + return TRUE; +} + +static int init_battery_func() +{ + int ret = -1; + int value = -1; + + ret = battery_capacity_raw(&value); + if(ret >= 0) { + get_battery_capacity = battery_capacity_raw; + full_capacity = FULL_CAPACITY_RAW; + LOGINFO("init_battery_func : full capacity(%d)", full_capacity); + return 0; + } + + ret = battery_capacity(&value); + if(ret >= 0) { + get_battery_capacity = battery_capacity; + full_capacity = FULL_CAPACITY; + LOGINFO("init_battery_func : full capacity(%d)", full_capacity); + return 0; + } + + LOGERR("init_battery_func : fail to get battery info!"); + return -1; +} + +int start_battinfo_gathering(int timeout) +{ + int ret; + + LOGINFO("Start battery gathering!"); + + if(timeout < 0) { + LOGERR("invalid timeout value [%d]!", timeout); + return -1; + } + if(init_battery_func() != 0) + return -1; + + old_capacity = 0; + battinfo_calculation(); + + if(timeout > 0) { + /* Using g_timer for gathering battery info */ + timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, timeout, + (GSourceFunc)battinfo_cb, NULL, NULL); + } else if(timeout == 0) { + /* Using heynoti from system-server(udev) + for gathering battery info */ + if((noti_fd = heynoti_init()) < 0) { + LOGERR("heynoti init failed!"); + return -1; + } + ret = heynoti_subscribe(noti_fd, "device_charge_chgdet", + (void *)battinfo_calculation, (void *)NULL); + if(ret != 0) { + LOGERR("heynoti subscribe fail!"); + return -1; + } + + ret = heynoti_attach_handler(noti_fd); + if(ret != 0) { + LOGERR("heynoti attach handler fail!"); + return -1; + } + } + return 0; +} + +void end_battinfo_gathering() +{ + LOGINFO("End battery gathering!"); + + if(timeout_id > 0) { + g_source_remove(timeout_id); + timeout_id = 0; + } + if(noti_fd > 0) { + heynoti_close(noti_fd); + noti_fd = 0; + } + + del_all_batt_node(B_UNCHARGING); + del_all_batt_node(B_CHARGING); +} + diff --git a/pm_battery.h b/pm_battery.h new file mode 100644 index 0000000..1d5b0e7 --- /dev/null +++ b/pm_battery.h @@ -0,0 +1,36 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 __PM_BATTERY_H_ +#define __PM_BATTERY_H_ + +#define BATTERY_POLLING_PERIOD 30000 /* ms */ + +/* +* If system is suspend state for a long time, +* it's hard to expect power consumption. +* Therefore, Previous capacity value is ignored +* when system changes from suspend state to resume state. +* This flag indicates phone wakes up from suspend state. +* In this case, all nodes saved are ignored. +*/ +extern int system_wakeup_flag; + +int start_battinfo_gathering(int timeout); +void end_battinfo_gathering(); + +#endif diff --git a/pm_conf.c b/pm_conf.c new file mode 100644 index 0000000..9ee6e54 --- /dev/null +++ b/pm_conf.c @@ -0,0 +1,81 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <string.h> +#include <stdio.h> + +#include "pm_conf.h" + +enum { + IDX_NAME = 0, + IDX_DEFAULT, + IDX_END +}; + +static char *def_values[][IDX_END] = { + {"PM_INPUT", "/dev/event0:/dev/event1"}, + {"PM_TO_START", "0"}, + {"PM_TO_NORMAL", "600"}, + {"PM_TO_LCDDIM", "5"}, + {"PM_TO_LCDOFF", "5"}, + {"PM_TO_SLEEP", "0"}, + {"PM_SYS_POWER", "/sys/power/state"}, + {"PM_SYS_BRIGHT", "/sys/class/backlight/mobile-bl/brightness"}, + {"PM_SYS_BRIGHT", "/sys/class/backlight/mobile-bl/max_brightness"}, + {"PM_SYS_BLPWR", "/sys/class/backlight/mobile-bl/bl_power"}, + {"PM_SYS_DIMBRT", "0"}, + {"PM_SYS_BLON", "0"}, + {"PM_SYS_BLOFF", "4"}, + {"PM_SYS_FB_NORMAL", "1"}, + {"PM_SYS_STATE", "mem"}, + {"PM_EXEC_PRG", NULL}, + {"PM_END", ""}, +}; + +static char *_find_default(char *name) +{ + char *ret = NULL; + int i = 0; + + while (strcmp("PM_END", def_values[i][IDX_NAME])) { + if (!strcmp(name, def_values[i][IDX_NAME])) { + ret = def_values[i][IDX_DEFAULT]; + break; + } + i++; + } + return ret; +} + +int get_env(char *name, char *buf, int size) +{ + char *ret; + + ret = getenv(name); + if ((ret == NULL) || (strlen(ret) > 1024)) { + ret = _find_default(name); + if (ret) + snprintf(buf, size, "%s", ret); + else + snprintf(buf, size, ""); + } else { + snprintf(buf, size, "%s", ret); + } + + return 0; +} diff --git a/pm_conf.h b/pm_conf.h new file mode 100644 index 0000000..8a3894d --- /dev/null +++ b/pm_conf.h @@ -0,0 +1,26 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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_MANAGER_CONF_H__ +#define __POWER_MANAGER_CONF_H__ + +#define EN_SYS_DIMBRT "PM_SYS_DIMBRT" + +extern int get_env(char *, char *, int); + +#endif diff --git a/pm_core.c b/pm_core.c new file mode 100644 index 0000000..d53aa27 --- /dev/null +++ b/pm_core.c @@ -0,0 +1,1356 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_core.c + * @version 0.2 + * @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 <glib.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 <heynoti.h> +#include <sysman.h> +#include <aul.h> +#include <vconf-keys.h> + +#include "pm_device_plugin.h" +#include "pm_core.h" +#include "pm_battery.h" + +#define USB_CON_PIDFILE "/var/run/.system_server.pid" +#define PM_STATE_LOG_FILE "/var/log/pm_state.log" +#define PM_WAKEUP_NOTI_NAME "system_wakeup" +#define PM_EVENT_NOTI_NAME "pm_event" +#define PM_EVENT_NOTI_PATH "/opt/share/noti/"PM_EVENT_NOTI_NAME + +/** + * @addtogroup POWER_MANAGER + * @{ + */ + +#define LOCKSTATUS_TIMEOUT 3 +#define TELEPHONY_SIGNAL_TIMEOUT 10 + +#define SET_BRIGHTNESS_IN_BOOTLOADER "/usr/bin/save_blenv SLP_LCD_BRIGHT" + +/* default transition, action fuctions */ +static int default_trans(int evt); +static int default_action(int timeout); +static int default_check(int next); + +unsigned int status_flag; + +static void (*power_saving_func) (int onoff); +static void reset_timeout(int timeout); + +int cur_state; +int old_state; +static GMainLoop *mainloop; +guint timeout_src_id; +static time_t last_t; +static int pre_suspend_flag = false; +int system_wakeup_flag = false; + +struct state states[S_END] = { + {S_START, default_trans, default_action, default_check,}, + {S_NORMAL, default_trans, default_action, default_check,}, + {S_LCDDIM, default_trans, default_action, default_check,}, + {S_LCDOFF, default_trans, default_action, default_check,}, + {S_SLEEP, default_trans, default_action, default_check,} +}; + +int (*pm_init_extention) (void *data); +void (*pm_exit_extention) (void); + +static char state_string[5][10] = + { "S_START", "S_NORMAL", "S_LCDDIM", "S_LCDOFF", "S_SLEEP" }; + +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 */ +#ifdef TIZEN_EMUL + {S_LCDOFF, S_NORMAL}, /* S_LCDOFF */ +#else + {S_SLEEP, S_NORMAL}, /* S_LCDOFF */ +#endif + {S_LCDOFF, S_NORMAL}, /* S_SLEEP, When wake up by devices, go lcd_off state */ +}; + +#define SHIFT_UNLOCK 4 +#define MASK_RESET_TIMEOUT 0x8 /* 1000 */ +#define MASK_MARGIN_TIMEOUT (0x1 << 8) +#define SHIFT_CHANGE_STATE 7 +#define CHANGE_STATE_BIT 0xF00 /* 1111 0000 0000 */ +#define LOCK_SCREEN_TIMEOUT 5 +#define SHIFT_HOLD_KEY_BLOCK 16 + +#define DEFAULT_NORMAL_TIMEOUT 30 +#define DEFAULT_DIM_TIMEOUT 5 +#define DEFAULT_OFF_TIMEOUT 5 +#define GET_HOLDKEY_BLOCK_STATE(x) ((x >> SHIFT_HOLD_KEY_BLOCK) & 0x1) + +static int received_sleep_cmd = 0; + +typedef struct _node { + pid_t pid; + int timeout_id; + gboolean holdkey_block; + struct _node *next; +} Node; + +static Node *cond_head[S_END]; + +static int refresh_app_cond() +{ + trans_condition = 0; + + if (cond_head[S_LCDDIM] != NULL) + trans_condition = trans_condition | MASK_DIM; + if (cond_head[S_LCDOFF] != NULL) + trans_condition = trans_condition | MASK_OFF; + if (cond_head[S_SLEEP] != NULL) + trans_condition = trans_condition | MASK_SLP; + + return 0; +} + +static Node *find_node(enum state_t s_index, pid_t pid) +{ + Node *t = cond_head[s_index]; + + while (t != NULL) { + if (t->pid == pid) + break; + t = t->next; + } + return t; +} + +static Node *add_node(enum state_t s_index, pid_t pid, int timeout_id, + gboolean holdkey_block) +{ + Node *n; + + n = (Node *) malloc(sizeof(Node)); + if (n == NULL) { + LOGERR("Not enough memory, add cond. fail"); + return NULL; + } + + n->pid = pid; + n->timeout_id = timeout_id; + n->holdkey_block = holdkey_block; + n->next = cond_head[s_index]; + cond_head[s_index] = n; + + refresh_app_cond(); + return n; +} + +static int del_node(enum state_t s_index, Node *n) +{ + Node *t; + Node *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; + free(t); + break; + } + prev = t; + t = t->next; + } + refresh_app_cond(); + return 0; +} + +static gboolean del_dim_cond(gpointer data) +{ + Node *tmp = NULL; + LOGINFO("delete prohibit dim condition by timeout\n"); + + tmp = find_node(S_LCDDIM, (pid_t) data); + del_node(S_LCDDIM, tmp); + + if (timeout_src_id == 0) + states[cur_state].trans(EVENT_TIMEOUT); + + return FALSE; +} + +static gboolean del_off_cond(gpointer data) +{ + Node *tmp = NULL; + LOGINFO("delete prohibit off condition by timeout\n"); + + tmp = find_node(S_LCDOFF, (pid_t) data); + del_node(S_LCDOFF, tmp); + + if (timeout_src_id == 0) + states[cur_state].trans(EVENT_TIMEOUT); + + return FALSE; +} + +static gboolean del_sleep_cond(gpointer data) +{ + Node *tmp = NULL; + LOGINFO("delete prohibit sleep condition by timeout\n"); + + tmp = find_node(S_SLEEP, (pid_t) data); + del_node(S_SLEEP, tmp); + + if (timeout_src_id == 0) + states[cur_state].trans(EVENT_TIMEOUT); + + sysman_inform_inactive((pid_t) data); + return FALSE; +} + +/* update transition condition for application requrements */ +static int proc_condition(PMMsg *data) +{ + Node *tmp = NULL; + unsigned int val = data->cond; + pid_t pid = data->pid; + int cond_timeout_id = -1; + gboolean holdkey_block = 0; + + if (val == 0) + return 0; + /* for debug */ + char pname[PATH_MAX]; + char buf[PATH_MAX]; + int fd_cmdline; + snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid); + fd_cmdline = open(buf, O_RDONLY); + if (fd_cmdline < 0) { + snprintf(pname, PATH_MAX, + "does not exist now(may be dead without unlock)"); + } else { + read(fd_cmdline, pname, PATH_MAX); + close(fd_cmdline); + } + + if (val & MASK_DIM) { + if (data->timeout > 0) { + cond_timeout_id = + g_timeout_add_full(G_PRIORITY_DEFAULT, + data->timeout, + (GSourceFunc) del_dim_cond, + (gpointer) pid, NULL); + } + holdkey_block = GET_HOLDKEY_BLOCK_STATE(val); + tmp = find_node(S_LCDDIM, pid); + if (tmp == NULL) + add_node(S_LCDDIM, pid, cond_timeout_id, holdkey_block); + else if (tmp->timeout_id > 0) { + g_source_remove(tmp->timeout_id); + tmp->timeout_id = cond_timeout_id; + tmp->holdkey_block = holdkey_block; + } + /* for debug */ + LOGINFO("[%s] locked by pid %d - process %s\n", "S_NORMAL", pid, + pname); + } + if (val & MASK_OFF) { + if (data->timeout > 0) { + cond_timeout_id = + g_timeout_add_full(G_PRIORITY_DEFAULT, + data->timeout, + (GSourceFunc) del_off_cond, + (gpointer) pid, NULL); + } + holdkey_block = GET_HOLDKEY_BLOCK_STATE(val); + tmp = find_node(S_LCDOFF, pid); + if (tmp == NULL) + add_node(S_LCDOFF, pid, cond_timeout_id, holdkey_block); + else if (tmp->timeout_id > 0) { + g_source_remove(tmp->timeout_id); + tmp->timeout_id = cond_timeout_id; + tmp->holdkey_block = holdkey_block; + } + /* for debug */ + LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDDIM", pid, + pname); + } + if (val & MASK_SLP) { + if (data->timeout > 0) { + cond_timeout_id = + g_timeout_add_full(G_PRIORITY_DEFAULT, + data->timeout, + (GSourceFunc) del_sleep_cond, + (gpointer) pid, NULL); + } + tmp = find_node(S_SLEEP, pid); + if (tmp == NULL) + add_node(S_SLEEP, pid, cond_timeout_id, 0); + else if (tmp->timeout_id > 0) { + g_source_remove(tmp->timeout_id); + tmp->timeout_id = cond_timeout_id; + tmp->holdkey_block = 0; + } + sysman_inform_active(pid); + /* for debug */ + LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDOFF", pid, + pname); + } + + /* UNLOCK(GRANT) condition processing */ + val = val >> SHIFT_UNLOCK; + if (val & MASK_DIM) { + tmp = find_node(S_LCDDIM, pid); + del_node(S_LCDDIM, tmp); + LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LORMAL", + pid, pname); + } + if (val & MASK_OFF) { + tmp = find_node(S_LCDOFF, pid); + del_node(S_LCDOFF, tmp); + LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDDIM", + pid, pname); + } + if (val & MASK_SLP) { + tmp = find_node(S_SLEEP, pid); + del_node(S_SLEEP, tmp); + sysman_inform_inactive(pid); + LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDOFF", + pid, pname); + } + val = val >> 8; + if (val != 0) { + if ((val & 0x1)) { + reset_timeout(states[cur_state].timeout); + LOGINFO("reset timeout\n", "S_LCDOFF", pid, pname); + } + } else { + /* guard time for suspend */ + if (cur_state == S_LCDOFF) { + reset_timeout(5); + LOGINFO("margin timeout (5 seconds)\n"); + } + } + + if (timeout_src_id == 0) + states[cur_state].trans(EVENT_TIMEOUT); + + return 0; +} + +static int proc_change_state(unsigned int cond) +{ + int next_state = 0; + struct state *st; + int i; + + for (i = S_NORMAL; i < S_END; i++) { + if ((cond >> (SHIFT_CHANGE_STATE + i)) & 0x1) { + next_state = i; + break; + } + } + LOGINFO("Change State to %s", state_string[next_state]); + + switch (next_state) { + case S_NORMAL: + case S_LCDDIM: + case S_LCDOFF: + /* state transition */ + old_state = cur_state; + cur_state = next_state; + st = &states[cur_state]; + + /* enter action */ + if (st->action) { + st->action(st->timeout); + } + break; + case S_SLEEP: + LOGINFO("Dangerous requests."); + /* at first LCD_OFF and then goto sleep */ + /* state transition */ + old_state = cur_state; + cur_state = S_LCDOFF; + st = &states[cur_state]; + if (st->action) { + st->action(0); + } + old_state = cur_state; + cur_state = S_SLEEP; + st = &states[cur_state]; + if (st->action) { + st->action(0); + } + break; + + default: + return -1; + } + + return 0; +} + +/* If some changed, return 1 */ +int check_processes(enum state_t prohibit_state) +{ + Node *t = cond_head[prohibit_state]; + Node *tmp = NULL; + int ret = 0; + + while (t != NULL) { + if (kill(t->pid, 0) == -1) { + LOGERR + ("%d process does not exist, delete the REQ - prohibit state %d ", + t->pid, prohibit_state); + 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) +{ + Node *t = cond_head[state]; + int ret = 0; + + LOGINFO("check holdkey block : state of %s", state_string[state]); + + while(t != NULL) { + if(t->holdkey_block == true) { + ret = 1; + LOGINFO("Hold key blocked by pid(%d)!", t->pid); + break; + } + t = t->next; + } + + return ret; +} + +int delete_condition(enum state_t state) +{ + Node *t = cond_head[state]; + int ret = 0; + Node *tmp = NULL; + + LOGINFO("delete condition : state of %s", state_string[state]); + + while(t != NULL) { + if(t->timeout_id > 0) { + g_source_remove(t->timeout_id); + } + tmp = t; + t = t->next; + LOGINFO("delete node of pid(%d)", tmp->pid); + del_node(state, tmp); + } + + return 0; +} + +/* SIGINT, SIGTERM, SIGQUIT signal handler */ +static void sig_quit(int signo) +{ + LOGINFO("received %d signal : stops a main loop", signo); + if (mainloop) + g_main_loop_quit(mainloop); +} + +void print_info(int fd) +{ + int s_index = 0; + char buf[255]; + int i = 1, ret; + + if (fd < 0) + return; + + snprintf(buf, sizeof(buf), + "\n======================================================================\n"); + write(fd, buf, strlen(buf)); + snprintf(buf, sizeof(buf),"Timeout Info: Run[%d] Dim[%d] Off[%d]\n", + states[S_NORMAL].timeout, + states[S_LCDDIM].timeout, states[S_LCDOFF].timeout); + write(fd, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Tran. Locked : %s %s %s\n", + (trans_condition & MASK_DIM) ? state_string[S_NORMAL] : "-", + (trans_condition & MASK_OFF) ? state_string[S_LCDDIM] : "-", + (trans_condition & MASK_SLP) ? state_string[S_LCDOFF] : "-"); + write(fd, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Current State: %s\n", state_string[cur_state]); + write(fd, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "Current Lock Conditions: \n"); + write(fd, buf, strlen(buf)); + + for (s_index = S_NORMAL; s_index < S_END; s_index++) { + Node *t; + char pname[PATH_MAX]; + int fd_cmdline; + t = cond_head[s_index]; + + while (t != NULL) { + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", t->pid); + fd_cmdline = open(buf, O_RDONLY); + if (fd_cmdline < 0) { + snprintf(pname, PATH_MAX, + "does not exist now(may be dead without unlock)"); + } else { + read(fd_cmdline, pname, PATH_MAX); + close(fd_cmdline); + } + snprintf(buf, sizeof(buf), + " %d: [%s] locked by pid %d - process %s\n", + i++, state_string[s_index - 1], t->pid, pname); + write(fd, buf, strlen(buf)); + t = t->next; + } + } +} + +/* SIGHUP signal handler + * For debug... print info to syslog + */ +static void sig_hup(int signo) +{ + int fd; + char buf[255]; + time_t now_time; + + time(&now_time); + + fd = open(PM_STATE_LOG_FILE, O_CREAT | O_WRONLY, 0644); + if (fd != -1) { + snprintf(buf, sizeof(buf), "\npm_state_log now-time : %d (s)\n\n", + (int)now_time); + write(fd, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "status_flag: %x\n", status_flag); + write(fd, buf, strlen(buf)); + + snprintf(buf, sizeof(buf), "received sleep cmd count : %d\n", + received_sleep_cmd); + write(fd, buf, strlen(buf)); + + print_info(fd); + close(fd); + } + + fd = open("/dev/console", O_WRONLY); + if (fd != -1) { + print_info(fd); + close(fd); + } +} + +/* timeout handler */ +gboolean timeout_handler(gpointer data) +{ + LOGINFO("Time out state %s\n", state_string[cur_state]); + + if (timeout_src_id != 0) { + g_source_remove(timeout_src_id); + timeout_src_id = 0; + } + + if ((status_flag & VCALL_FLAG) + && (cur_state == S_LCDOFF || cur_state == S_SLEEP)) { + status_flag &= ~(VCALL_FLAG); + reset_timeout(TELEPHONY_SIGNAL_TIMEOUT); + return FALSE; + } + states[cur_state].trans(EVENT_TIMEOUT); + return FALSE; +} + +static void reset_timeout(int timeout) +{ + if (timeout_src_id != 0) { + g_source_remove(timeout_src_id); + timeout_src_id = 0; + } + if (timeout > 0) { + timeout_src_id = g_timeout_add_seconds_full(G_PRIORITY_HIGH, + timeout, + (GSourceFunc) + timeout_handler, + NULL, NULL); + } +} + +static void sig_usr(int signo) +{ + status_flag |= VCALL_FLAG; +} + +static void sig_break_block(int signo) +{ + LOGINFO("We got signal to break that pending checking in kernel\n"); +} + +/* + * default transition function + * 1. call check + * 2. transition + * 3. call enter action function + */ +static int default_trans(int evt) +{ + struct state *st = &states[cur_state]; + int next_state; + + if(cur_state == S_NORMAL && st->timeout == 0) { + LOGINFO("LCD always on enabled!"); + return 0; + } + + next_state = (enum state_t)trans_table[cur_state][evt]; + + /* check conditions */ + while (st->check && !st->check(next_state)) { + /* There is a condition. */ + LOGINFO("%s -> %s : check fail", state_string[cur_state], + state_string[next_state]); + if (!check_processes(next_state)) { + /* this is valid condition - the application that sent the condition is running now. */ + return -1; + } + } + + /* state transition */ + old_state = cur_state; + cur_state = next_state; + st = &states[cur_state]; + + /* enter action */ + if (st->action) { + st->action(st->timeout); + } + + return 0; +} + +/* default enter action function */ +static int default_action(int timeout) +{ + int ret; + int wakeup_count = -1; + char buf[NAME_MAX]; + char *pkgname = NULL; + int i = 0; + int lock_state = -1; + struct itimerval val; + + if (cur_state != old_state && cur_state != S_SLEEP) + set_setting_pmstate(cur_state); + + switch (cur_state) { + case S_NORMAL: + /* normal state : backlight on and restore the previous brightness */ + if (old_state == S_LCDOFF || old_state == S_SLEEP) { + if (pre_suspend_flag == true) { + system_post_resume(); + pre_suspend_flag = false; + } + for (i = 0; i < 14; i++) { + vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state); + LOGERR("Idle lock check : %d, vonf : %d", i, lock_state); + if (lock_state) + break; + usleep(50000); + } +#ifndef X86 /* Different with ARM FB driver, IA gfx driver is sensitive to the order. */ + backlight_restore(); + backlight_on(); +#else + backlight_on(); + backlight_restore(); +#endif + } else if (old_state == S_LCDDIM) + backlight_restore(); + break; + + case S_LCDDIM: + if (old_state == S_LCDOFF || old_state == S_SLEEP) { + backlight_on(); + } + /* lcd dim state : dim the brightness */ + backlight_dim(); + break; + + case S_LCDOFF: + if (old_state != S_SLEEP && old_state != S_LCDOFF) { + /* lcd off state : turn off the backlight */ + backlight_off(); + if (pre_suspend_flag == false) { + pre_suspend_flag = true; + system_pre_suspend(); + } + } + break; + + case S_SLEEP: + /* + * We can not always be blocked here because of that + * in-progress checking in kernel for wakeup count, + * if we cannot get the result within some time, then + * just give it up and then retry it in the next time, + * this method would not break that original expected + * 'aggresive suspend' idea, but at the same time make + * the system is 'always' responsible to some keypress + * actions like power button press. + */ + val.it_value.tv_sec = TOLERANCE_SLOT; + val.it_value.tv_usec = 0; + val.it_interval.tv_sec = val.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &val, NULL); + + /* sleep state : set system mode to SUSPEND */ + if (0 > plugin_intf->OEM_sys_get_power_wakeup_count(&wakeup_count)) + LOGERR("wakeup count read error"); + + if (wakeup_count < 0) { + LOGINFO("Wakup Event! Can not enter suspend mode."); + goto go_lcd_off; + } + + if (0 > plugin_intf->OEM_sys_set_power_wakeup_count(wakeup_count)) { + LOGERR("wakeup count write error"); + goto go_lcd_off; + } + + goto go_suspend; + } + + /* set timer with current state timeout */ + reset_timeout(timeout); + LOGINFO("timout set: %s state %d sec", state_string[cur_state], timeout); + + return 0; + +go_suspend: + system_suspend(); + LOGINFO("system wakeup!!"); + system_wakeup_flag = true; + heynoti_publish(PM_WAKEUP_NOTI_NAME); + /* Resume !! */ + if (check_wakeup_src() == EVENT_DEVICE) + /* system waked up by devices */ + states[cur_state].trans(EVENT_DEVICE); + else + /* system waked up by user input */ + states[cur_state].trans(EVENT_INPUT); + return 0; + +go_lcd_off: + heynoti_publish(PM_WAKEUP_NOTI_NAME); + /* Resume !! */ + states[cur_state].trans(EVENT_DEVICE); + return 0; +} + +/* + * default check function + * return + * 0 : can't transit, others : transitable + */ +static int default_check(int next) +{ + int trans_cond = trans_condition & MASK_BIT; + int lock_state = -1; + + LOGINFO("trans_cond : %x", trans_cond); + + vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state); + if(lock_state==VCONFKEY_IDLE_LOCK && next != S_SLEEP) { + LOGINFO("default_check : LOCK STATE, it's transitable"); + return 1; + } + + switch (next) { + case S_LCDDIM: + trans_cond = trans_cond & MASK_DIM; + break; + case S_LCDOFF: + trans_cond = trans_cond & MASK_OFF; + break; + case S_SLEEP: + trans_cond = trans_cond & MASK_SLP; + break; + default: /* S_NORMAL is exceptional */ + trans_cond = 0; + break; + } + + if (trans_cond != 0) + return 0; + + return 1; /* transitable */ +} + +/* get configurations from setting */ +static int get_settings() +{ + int i; + int val = 0; + int ret = -1; + char buf[255]; + + for (i = 0; i < S_END; i++) { + switch (states[i].state) { + case S_NORMAL: + ret = get_run_timeout(&val); + if (ret != 0) { + ret = get_env("PM_TO_NORMAL", buf, 255); + val = atoi(buf); + } + break; + case S_LCDDIM: + ret = get_dim_timeout(&val); + break; + case S_LCDOFF: + ret = get_off_timeout(&val); + break; + default: + /* This state doesn't need to set time out. */ + ret = -1; + break; + } + if (ret == 0 || val < 0) { + states[i].timeout = val; + } else { + switch (states[i].state) { + case S_NORMAL: + states[i].timeout = DEFAULT_NORMAL_TIMEOUT; + break; + case S_LCDDIM: + states[i].timeout = DEFAULT_DIM_TIMEOUT; + break; + case S_LCDOFF: + states[i].timeout = DEFAULT_OFF_TIMEOUT; + break; + default: + states[i].timeout = 0; + break; + } + } + LOGINFO("%s state : %d timeout", state_string[i], states[i].timeout); + } + + return 0; +} + +static void default_saving_mode(int onoff) +{ + if (onoff) { + status_flag |= PWRSV_FLAG; + } else { + status_flag &= ~PWRSV_FLAG; + } + if (cur_state == S_NORMAL) + backlight_restore(); +} + +static int poll_callback(int condition, PMMsg *data) +{ + time_t now; + + if (condition == INPUT_POLL_EVENT) { + if (cur_state == S_LCDOFF || cur_state == S_SLEEP) + LOGINFO("Power key input"); + time(&now); + if (last_t != now) { + states[cur_state].trans(EVENT_INPUT); + last_t = now; + } + } else if (condition == PM_CONTROL_EVENT) { + LOGINFO("process pid(%d) pm_control condition : %x ", data->pid, + data->cond); + + if (data->cond & MASK_BIT + || (data->cond >> SHIFT_UNLOCK) & MASK_BIT) + proc_condition(data); + + if (data->cond & CHANGE_STATE_BIT) { + + LOGINFO("Change state by pid(%d) request.", data->pid); + proc_change_state(data->cond); + } + } + + return 0; +} + +static int update_setting(int key_idx, int val) +{ + char buf[PATH_MAX]; + int ret = -1; + int dim_timeout = -1; + int run_timeout = -1; + int power_saving_stat = -1; + int power_saving_display_stat = -1; + + switch (key_idx) { + case SETTING_TO_NORMAL: + ret = get_dim_timeout(&dim_timeout); + if(ret < 0 || dim_timeout < 0) { + LOGERR("Can not get dim timeout. set default 5 seconds"); + dim_timeout = 5; + } + if(val < 0) { + LOGERR("LCD timeout is wrong, set default 15 seconds"); + val = 15; + } + if(val == 0) { + states[S_NORMAL].timeout = 0; + } else if(val > dim_timeout) { + states[S_NORMAL].timeout = val - dim_timeout; + } else { + states[S_NORMAL].timeout = 1; + } + states[cur_state].trans(EVENT_INPUT); + break; + case SETTING_LOW_BATT: + if (val < VCONFKEY_SYSMAN_BAT_WARNING_LOW) { + if (!(status_flag & CHRGR_FLAG)) + power_saving_func(true); + status_flag |= LOWBT_FLAG; + } else { + if (status_flag & PWRSV_FLAG) + power_saving_func(false); + status_flag &= ~LOWBT_FLAG; + status_flag &= ~BRTCH_FLAG; + vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM, + false); + } + break; + case SETTING_CHARGING: + if (val) { + if (status_flag & LOWBT_FLAG) { + power_saving_func(false); + status_flag &= ~LOWBT_FLAG; + } + status_flag |= CHRGR_FLAG; + } else { + int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL; + vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state); + if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) { + power_saving_func(true); + status_flag |= LOWBT_FLAG; + } + status_flag &= ~CHRGR_FLAG; + } + break; + case SETTING_BRT_LEVEL: + if (status_flag & PWRSV_FLAG) { + status_flag |= BRTCH_FLAG; + vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM, + true); + LOGINFO("brightness changed in low battery, escape dim state"); + } + set_default_brt(val); + snprintf(buf, sizeof(buf), "%s %d", SET_BRIGHTNESS_IN_BOOTLOADER, val); + LOGINFO("Brightness set in bl : %d",val); + system(buf); + break; + case SETTING_LOCK_SCREEN: + if (val == VCONFKEY_IDLE_LOCK) { + states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT; + LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT); + } else { + get_run_timeout(&run_timeout); + if(run_timeout < 0) { + LOGERR("Can not get run timeout. set default 15 seconds(includes dim 5 seconds)"); + run_timeout = 10; + } + states[S_NORMAL].timeout = run_timeout; + LOGINFO("LCD NORMAL timeout is set by %d seconds because phone is unlocked", run_timeout); + } + if (cur_state == S_NORMAL) { + states[cur_state].trans(EVENT_INPUT); + } + break; + case SETTING_POWER_SAVING: + if (val == 1) + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat); + if (power_saving_display_stat != 1) + power_saving_display_stat = 0; + plugin_intf->OEM_sys_set_display_frame_rate(power_saving_display_stat); + backlight_restore(); + break; + case SETTING_POWER_SAVING_DISPLAY: + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat); + if (power_saving_stat == 1) { + if (val == 1) + power_saving_display_stat = 1; + else + power_saving_display_stat = 0; + plugin_intf->OEM_sys_set_display_frame_rate(power_saving_display_stat); + backlight_restore(); + } + 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 max_brt = 0; + int brt = 0; + int lock_state = -1; + + /* Charging check */ + if ((get_charging_status(&tmp) == 0) && (tmp > 0)) { + status_flag |= CHRGR_FLAG; + } + + ret = get_setting_brightness(&tmp); + if (ret != 0 || (tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)) { + LOGINFO("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; + } + LOGINFO("Set brightness from Setting App. %d", tmp); + set_default_brt(tmp); + + vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state); + if (bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) { + if (!(status_flag & CHRGR_FLAG)) { + power_saving_func(true); + status_flag |= LOWBT_FLAG; + } + } + backlight_restore(); + + /* USB connection check + * If connected, add sleep prohibit condition */ + if ((get_usb_status(&tmp) == 0) && (tmp > 0)) { + tmp = readpid(USB_CON_PIDFILE); + if (tmp != -1) { + add_node(S_SLEEP, tmp, -1, 0); + } + } + + /* lock screen check */ + ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state); + if(lock_state == VCONFKEY_IDLE_LOCK) { + states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT; + LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT); + } + + return; +} + +enum { + INIT_SETTING = 0, + INIT_INTERFACE, + INIT_POLL, + INIT_FIFO, + INIT_END +}; + +static 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", +}; + +/* logging indev_list for debug */ +void printglist() +{ + int i; + guint total=0; + indev *tmp; + + total=g_list_length(indev_list); + LOGINFO("***** total list : %d *****",total); + for(i=0;i<total;i++) { + tmp=(indev*)(g_list_nth(indev_list, i)->data); + LOGINFO("* %d | path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd); + if(i==total-1 && g_list_nth(indev_list, i)->next==NULL) + LOGINFO("okokok"); + } + LOGINFO("***************************\n"); +} + +static GList *find_glist(GList *glist, char *path) +{ + int i; + guint total=0; + indev *tmp; + + total=g_list_length(indev_list); + for(i=0;i<total;i++) { + tmp=(indev*)(g_list_nth(indev_list, i)->data); + if(!strcmp(tmp->dev_path, path)){ + LOGINFO("nth : %d, path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd); + return g_list_nth(indev_list, i); + } + } + return NULL; +} + +static void input_cb(void* data) +{ + FILE *fp; + char input_act[NAME_MAX], input_path[MAX_INPUT]; + char args[NAME_MAX + MAX_INPUT]; + int i, ret = -1; + GList *glist = NULL; + + fp = fopen((char *) data, "r"); + if (fp == NULL) { + LOGERR("input file open fail"); + return ; + } + + while (fgets(args, NAME_MAX + MAX_INPUT, fp) != NULL){ + if( args[strlen(args)-1] != '\n'){ + LOGERR("input file must be terminated with new line character\n"); + break; + } + args[strlen(args) - 1] = '\0'; + for(i = 0; i< NAME_MAX + MAX_INPUT; i++){ + if(args[i] == ' '){ + if( i >= NAME_MAX ){ + LOGERR("bsfile name is over the name_max(255)\n"); + break; + } + strncpy(input_act, args, i < NAME_MAX ? i : NAME_MAX); + input_act[i]='\0'; + strncpy(input_path, args + i + 1, MAX_INPUT); + input_path[MAX_INPUT - 1] = '\0'; + + if( !strcmp("add", input_act) ){ + LOGINFO("add input path:%s",input_path); + + ret=init_pm_poll_input(poll_callback, input_path); + + } else if ( !strcmp("remove", input_act) ){ + glist=find_glist(indev_list, input_path); + if(glist != NULL){ + LOGINFO("remove input dev"); + g_source_remove_poll(((indev*)(glist->data))->dev_src, ((indev*)(glist->data))->dev_fd); + g_source_destroy(((indev*)(glist->data))->dev_src); + close(((indev*)(glist->data))->dev_fd->fd); + g_free(((indev*)(glist->data))->dev_fd); + free(((indev*)(glist->data))->dev_path); + indev_list=g_list_remove(indev_list, glist->data); + } + ret=0; + } + /* debug */ + printglist(); + + break; + } + } + if(ret<0) + break; + } + fclose(fp); + + if ( ret != -1) { + fp = fopen((char *) data, "w"); + if (fp == NULL) { + return ; + } + fclose(fp); + } + + return ; +} + +static int set_noti(int noti_fd) +{ + int fd; + char buf[PATH_MAX]; + + noti_fd = heynoti_init(); + if (noti_fd < 0) { + LOGERR("heynoti_init error"); + return -1; + } + + if (heynoti_subscribe(noti_fd, PM_EVENT_NOTI_NAME, input_cb, PM_EVENT_NOTI_PATH) < 0) { + LOGERR("input file change noti add failed(%s). %s", buf, strerror(errno)); + return -1; + } else { + LOGERR("input file change noti add ok"); + } + + if (heynoti_attach_handler(noti_fd) < 0) { + LOGERR("heynoti_attach_handler error"); + return -1; + } + + return 0; +} + +static int unset_noti(int noti_fd) +{ + if (noti_fd < 0) { + LOGINFO("set noti already failed. nothing to do in unset"); + return 0; + } + + if (heynoti_unsubscribe(noti_fd, PM_EVENT_NOTI_NAME, input_cb) < 0 || heynoti_detach_handler(noti_fd) < 0) { + LOGERR("heynoti unsubsribe or detach error"); + return -1; + } + return 0; +} + +/** + * Power manager Main loop + * + * @internal + * @param[in] flags If the first bit of this is set, start managing without Start notification. + * If the second bit of ths is set, use unified device manager functions. + */ +void start_main(unsigned int flags) +{ + int ret, i; + + if (0 > _pm_devman_plugin_init()) { + LOGERR("Device Manager Plugin initialize failed"); + exit (-1); + } + + LOGINFO("Start power manager daemon"); + + signal(SIGHUP, sig_hup); + signal(SIGCHLD, SIG_IGN); + signal(SIGUSR1, sig_usr); + signal(SIGUSR2, sig_quit); + signal(SIGALRM, sig_break_block); + + mainloop = g_main_loop_new(NULL, FALSE); + power_saving_func = default_saving_mode; + + /* noti init for new input device like bt mouse */ + int noti_fd; + indev_list=NULL; + set_noti(noti_fd); + + for (i = INIT_SETTING; i < INIT_END; i++) { + switch (i) { + case INIT_SETTING: + ret = init_setting(update_setting); + break; + case INIT_INTERFACE: + get_settings(); + ret = init_sysfs(flags); + break; + case INIT_POLL: + LOGINFO("poll init"); + ret = init_pm_poll(poll_callback); + break; + } + if (ret != 0) { + LOGERR(errMSG[i]); + break; + } + } + + if (i == INIT_END) { + check_seed_status(); + + if (pm_init_extention != NULL) + pm_init_extention(NULL); + + if (flags & WITHOUT_STARTNOTI) { /* start without noti */ + LOGINFO("Start Power managing without noti"); + cur_state = S_NORMAL; + set_setting_pmstate(cur_state); + reset_timeout(states[S_NORMAL].timeout); + } + if (start_battinfo_gathering(BATTERY_POLLING_PERIOD) < 0) + LOGERR("Start Battery time info failed!"); + + g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); + } + + end_battinfo_gathering(); + 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: + unset_noti(noti_fd); + exit_pm_poll(); + break; + } + } + + if (pm_exit_extention != NULL) + pm_exit_extention(); + + LOGINFO("Terminate power manager daemon"); +} + +/** + * @} + */ diff --git a/pm_core.h b/pm_core.h new file mode 100644 index 0000000..8df792a --- /dev/null +++ b/pm_core.h @@ -0,0 +1,104 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_core.h + * @author Suchang Woo (suchang.woo@samsung.com) + * @modified by Wonil Choi (wonil22.choi@samsung.com) + * @version 0.2 + * @brief Power manager main loop header file + */ +#ifndef __POWER_MANAGER_H__ +#define __POWER_MANAGER_H__ + +#include "util.h" +#include "pm_poll.h" +#include "pm_llinterface.h" +#include "pm_setting.h" +#include "pm_conf.h" + +#define WITHOUT_STARTNOTI 0x1 +#define MASK_BIT 0x7 /* 111 */ +#define MASK_DIM 0x1 /* 001 */ +#define MASK_OFF 0x2 /* 010 */ +#define MASK_SLP 0x4 /* 100 */ + +#define VCALL_FLAG 0x00000001 +#define LOWBT_FLAG 0x00000100 +#define CHRGR_FLAG 0x00000200 +#define PWRSV_FLAG 0x00000400 +#define BRTCH_FLAG 0x00002000 + +#define TOLERANCE_SLOT 2 + +unsigned int status_flag; + +/* + * State enumeration + */ +enum state_t { + S_START = 0, + S_NORMAL, /*< normal state */ + S_LCDDIM, /*< LCD dimming */ + S_LCDOFF, /*< LCD off */ + S_SLEEP, /*< system suspend */ + S_END +}; + +/* + * Global variables + * cur_state : current state + * states : state definitions + * trans_table : state transition table + */ +int cur_state; +int old_state; + +/* + * @brief State structure + */ +struct state { + enum state_t state; /**< state number */ + int (*trans) (int evt); /**< transition function pointer */ + int (*action) (int timeout); /**< enter action */ + int (*check) (int next); /**< transition check function */ + int timeout; +} states[S_END]; + +/* If the bit in a condition variable is set, + * we cannot transit the state until clear this bit. */ +int trans_condition; +pid_t idle_pid; +int (*pm_init_extention) (void *data); /**< extention init function */ +void (*pm_exit_extention) (void); /**< extention exit function */ +int check_processes(enum state_t prohibit_state); + +/* + * Power manager Main loop + * + * @internal + * @param[in] flags If the first bit of this is set, start managing without Start notification. + * If the second bit of ths is set, use unified device manager functions. + */ +void start_main(unsigned int flags); + +/** + * @} + */ + +#endif diff --git a/pm_device_plugin.c b/pm_device_plugin.c new file mode 100644 index 0000000..00663d6 --- /dev/null +++ b/pm_device_plugin.c @@ -0,0 +1,64 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <dlfcn.h> +#include <unistd.h> + +#include "util.h" +#include "pm_device_plugin.h" + +static void *dlopen_handle; + +int _pm_devman_plugin_init() +{ + char *error; + + dlopen_handle = dlopen(DEVMAN_PLUGIN_PATH, RTLD_NOW); + if (!dlopen_handle) { + LOGERR("dlopen() failed"); + return -1; + } + + const OEM_sys_devman_plugin_interface *(*get_devman_plugin_interface) (); + get_devman_plugin_interface = dlsym(dlopen_handle, "OEM_sys_get_devman_plugin_interface"); + if ((error = dlerror()) != NULL) { + LOGERR("dlsym() failed: %s", error); + dlclose(dlopen_handle); + return -1; + } + + plugin_intf = get_devman_plugin_interface(); + if (!plugin_intf) { + LOGERR("get_devman_plugin_interface() failed"); + dlclose(dlopen_handle); + return -1; + } + + return 0; +} + + +int _pm_devman_plugin_fini() +{ + if (dlopen_handle) { + dlclose(dlopen_handle); + } + + return 0; +} + + diff --git a/pm_device_plugin.h b/pm_device_plugin.h new file mode 100644 index 0000000..1cf1b8e --- /dev/null +++ b/pm_device_plugin.h @@ -0,0 +1,31 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 __PM_DEVICE_PLUGIN_H__ +#define __PM_DEVICE_PLUGIN_H__ + +#include "devman_plugin_intf.h" + +#define DEVMAN_PLUGIN_PATH "/usr/lib/libslp_devman_plugin.so" + +int _pm_devman_plugin_init(void); +int _pm_devman_plugin_fini(void); + +const OEM_sys_devman_plugin_interface *plugin_intf; + +#endif /* __PM_DEVICE_PLUGIN_H__ */ diff --git a/pm_event/CMakeLists.txt b/pm_event/CMakeLists.txt new file mode 100644 index 0000000..2b69259 --- /dev/null +++ b/pm_event/CMakeLists.txt @@ -0,0 +1,30 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(pm_event C) + +SET(SRCS pm_event.c) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "\${prefix}") +SET(LIBDIR "\${prefix}/lib") +SET(INCLUDEDIR "\${prefix}/include") +SET(VERSION 0.1.9) +INCLUDE(FindPkgConfig) +FOREACH(flag ${deep_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${deep_pkgs_LDFLAGS}) + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"") +ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/pm_event/pm_event.c b/pm_event/pm_event.c new file mode 100644 index 0000000..14167af --- /dev/null +++ b/pm_event/pm_event.c @@ -0,0 +1,41 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <limits.h> + +#define PM_EVENT_NOTI_PATH "/opt/share/noti/pm_event" + +int main(int argc, char *argv[]) +{ + if(argc != 3) { + return -1; + } + + if(strlen(argv[1]) + strlen(argv[2]) > PATH_MAX) { + return -1; + } + + int i; + char buf[PATH_MAX + 25]; + snprintf(buf, PATH_MAX + 25, "echo %s %s >> %s", argv[1], argv[2], PM_EVENT_NOTI_PATH); + system(buf); + + return 1; +} diff --git a/pm_key_filter.c b/pm_key_filter.c new file mode 100644 index 0000000..2e282a9 --- /dev/null +++ b/pm_key_filter.c @@ -0,0 +1,301 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + + +#include <glib.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include <vconf.h> +#include <sysman.h> + +#include "util.h" +#include "pm_core.h" +#include "pm_poll.h" + +#include <linux/input.h> +#ifndef KEY_SCREENLOCK +#define KEY_SCREENLOCK 0x98 +#endif + +#define PREDEF_PWROFF_POPUP "pwroff-popup" +#define PREDEF_LEAVESLEEP "leavesleep" +#define PREDEF_POWEROFF "poweroff" + +#define USEC_PER_SEC 1000000 +#define LONG_PRESS_INTERVAL 1000000 /* 1000 ms */ +#define COMBINATION_INTERVAL 300000 /* 300 ms */ +#define POWER_KEY_PRESS_IGNORE_TIME 700000 /* 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 + +static struct timeval pressed_time; +static guint longkey_timeout_id = 0; +static guint combination_timeout_id = 0; +static int cancel_lcdoff; +static int key_combination = KEY_COMBINATION_STOP; +static int powerkey_ignored = false; + +void unlock() +{ + vconf_set_int(VCONFKEY_IDLE_LOCK_STATE, VCONFKEY_IDLE_UNLOCK); +} + +static inline int current_state_in_on() +{ + return (cur_state == S_LCDDIM || cur_state == S_NORMAL); +} + +static void longkey_pressed() +{ + int rc = -1, val = 0; + LOGINFO("Power key long pressed!"); + cancel_lcdoff = 1; + + rc = vconf_get_int(VCONFKEY_TESTMODE_POWER_OFF_POPUP, &val); + + if (rc < 0 || val != 1) { + if (sysman_call_predef_action(PREDEF_PWROFF_POPUP, 0) < + 0) + LOGERR("poweroff popup exec failed"); + } else { + if (sysman_call_predef_action(PREDEF_POWEROFF, 0) < 0) { + LOGERR("poweroff exec failed"); + system("poweroff"); + } + + } + (*g_pm_callback) (INPUT_POLL_EVENT, NULL); +} + +static gboolean longkey_pressed_cb(gpointer data) +{ + longkey_pressed(); + longkey_timeout_id = 0; + + return FALSE; +} + +static gboolean combination_failed_cb(gpointer data) +{ + key_combination = KEY_COMBINATION_STOP; + combination_timeout_id = 0; + + return 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() +{ + key_combination = KEY_COMBINATION_STOP; + if (combination_timeout_id > 0) { + g_source_remove(combination_timeout_id); + combination_timeout_id = 0; + } +} + +static int process_power_key(struct input_event *pinput) +{ + int ignore = true; + + switch (pinput->value) { + case KEY_RELEASED: + if (current_state_in_on() && !cancel_lcdoff && + !(key_combination == KEY_COMBINATION_SCREENCAPTURE)) { + check_processes(S_LCDOFF); + check_processes(S_LCDDIM); + + if (!check_holdkey_block(S_LCDOFF) && + !check_holdkey_block(S_LCDDIM)) { + delete_condition(S_LCDOFF); + delete_condition(S_LCDDIM); + /* LCD off forcly */ + recv_data.pid = -1; + recv_data.cond = 0x400; + (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data); + } + } else { + if (!powerkey_ignored) + ignore = false; + } + + stop_key_combination(); + cancel_lcdoff = 0; + if (longkey_timeout_id > 0) { + g_source_remove(longkey_timeout_id); + longkey_timeout_id = 0; + } + break; + case KEY_PRESSED: + if (timediff_usec(pressed_time, pinput->time) < + POWER_KEY_PRESS_IGNORE_TIME) { + LOGINFO("power key double pressed ignored"); + powerkey_ignored = true; + break; + } else { + powerkey_ignored = false; + } + LOGINFO("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 = g_timeout_add_full( + G_PRIORITY_DEFAULT, + LONG_PRESS_INTERVAL / 1000, + (GSourceFunc)longkey_pressed_cb, + NULL, NULL); + key_combination = KEY_COMBINATION_START; + combination_timeout_id = g_timeout_add_full( + G_PRIORITY_DEFAULT, + COMBINATION_INTERVAL / 1000, + (GSourceFunc)combination_failed_cb, + NULL, NULL); + } else if (key_combination == KEY_COMBINATION_START) { + if (combination_timeout_id > 0) { + g_source_remove(combination_timeout_id); + combination_timeout_id = 0; + } + LOGINFO("capture mode"); + key_combination = KEY_COMBINATION_SCREENCAPTURE; + ignore = false; + } + break; + case KEY_BEING_PRESSED: + if (timediff_usec(pressed_time, pinput->time) > + LONG_PRESS_INTERVAL) + longkey_pressed(); + break; + } + + return ignore; +} + +static int process_volumedown_key(struct input_event *pinput) +{ + int ignore = true; + + if (pinput->value == KEY_PRESSED) { + if (key_combination == KEY_COMBINATION_STOP) { + key_combination = KEY_COMBINATION_START; + combination_timeout_id = g_timeout_add_full( + G_PRIORITY_DEFAULT, + COMBINATION_INTERVAL / 1000, + (GSourceFunc)combination_failed_cb, + NULL, NULL); + } else if (key_combination == KEY_COMBINATION_START) { + if (combination_timeout_id > 0) { + g_source_remove(combination_timeout_id); + combination_timeout_id = 0; + } + LOGINFO("capture mode"); + key_combination = KEY_COMBINATION_SCREENCAPTURE; + ignore = false; + } + } else if (pinput->value == KEY_RELEASED) { + if (key_combination != KEY_COMBINATION_SCREENCAPTURE) { + stop_key_combination(); + if (current_state_in_on()) + ignore = false; + } + } + + return ignore; +} + +static int check_key(struct input_event *pinput) +{ + int ignore = true; + + switch (pinput->code) { + case KEY_POWER: + ignore = process_power_key(pinput); + break; + case KEY_VOLUMEDOWN: + ignore = process_volumedown_key(pinput); + break; + case KEY_VOLUMEUP: + case KEY_CAMERA: + case KEY_EXIT: + case KEY_PHONE: + case KEY_CONFIG: + case KEY_SEARCH: + stop_key_combination(); + if (current_state_in_on()) + ignore = false; + break; + case KEY_SCREENLOCK: + case 0x1DB: + case 0x1DC: + case 0x1DD: + case 0x1DE: + stop_key_combination(); + break; + default: + stop_key_combination(); + ignore = false; + } + + return ignore; +} + +int check_key_filter(int length, char buf[]) +{ + struct input_event *pinput; + int ignore = true; + int idx = 0; + + do { + pinput = (struct input_event *)&buf[idx]; + switch (pinput->type) { + case EV_KEY: + ignore = check_key(pinput); + break; + case EV_REL: + ignore = false; + break; + case EV_ABS: + if (current_state_in_on()) + ignore = false; + break; + } + + idx += sizeof(struct input_event); + if (ignore == true && length <= idx) + return 1; + } while (length > idx); + + return 0; +} + diff --git a/pm_llinterface.c b/pm_llinterface.c new file mode 100644 index 0000000..df4ffdc --- /dev/null +++ b/pm_llinterface.c @@ -0,0 +1,333 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "pm_llinterface.h" +#include "pm_device_plugin.h" +#include "util.h" +#include "pm_conf.h" +#include "vconf.h" +#include "pm_core.h" + +typedef struct _PMSys PMSys; +struct _PMSys { + int def_brt; + int dim_brt; + + int (*sys_power_state) (PMSys *, int); + int (*bl_onoff) (PMSys *, int); + int (*bl_brt) (PMSys *, int); + int (*sys_get_battery_capacity) (PMSys *p); + int (*sys_get_battery_capacity_raw) (PMSys *p); + int (*sys_get_battery_charge_full) (PMSys *p); +}; + +static PMSys *pmsys; + +#ifdef ENABLE_X_LCD_ONOFF +#include "pm_x_lcd_onoff.c" +static bool x_dpms_enable = false; +#endif + +/* +static void _update_curbrt(PMSys *p) +{ + int power_saving_stat = -1; + int power_saving_display_stat = -1; + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat); + if (power_saving_stat == 1) + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat); + if (power_saving_display_stat != 1) + power_saving_display_stat = 0; + plugin_intf->OEM_sys_get_backlight_brightness(DEFAULT_DISPLAY, &(p->def_brt), power_saving_display_stat); +} +*/ + +static int _bl_onoff(PMSys *p, int onoff) +{ + return plugin_intf->OEM_sys_set_lcd_power(DEFAULT_DISPLAY, onoff); +} + +static int _bl_brt(PMSys *p, int brightness) +{ + int power_saving_stat = -1; + int power_saving_display_stat = -1; + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat); + if (power_saving_stat == 1) + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat); + if (power_saving_display_stat != 1) + power_saving_display_stat = 0; + int ret = plugin_intf->OEM_sys_set_backlight_brightness(DEFAULT_DISPLAY, brightness, power_saving_display_stat); +LOGERR("set brightness %d,%d(saving %d) %d", DEFAULT_DISPLAY, brightness, power_saving_display_stat, ret); + return ret; +} + +static int _sys_power_state(PMSys *p, int state) +{ + if (state < POWER_STATE_SUSPEND || state > POWER_STATE_POST_RESUME) + return 0; + return plugin_intf->OEM_sys_set_power_state(state); +} + +static int _sys_get_battery_capacity(PMSys *p) +{ + int value = 0; + int ret = -1; + + ret = plugin_intf->OEM_sys_get_battery_capacity(&value); + + if(ret < 0) + return -1; + + if(value < 0) + return 0; + + return value; +} + +static int _sys_get_battery_capacity_raw(PMSys *p) +{ + int value = 0; + int ret = -1; + + ret = plugin_intf->OEM_sys_get_battery_capacity_raw(&value); + + if(ret < 0) + return -1; + + if(value < 0) + return 0; + + return value; +} + +static int _sys_get_battery_charge_full(PMSys *p) +{ + int value = 0; + int ret = -1; + + ret = plugin_intf->OEM_sys_get_battery_charge_full(&value); + + if(ret < 0) + return -1; + + if(value < 0) + return 0; + + return value; +} + +static void _init_bldev(PMSys *p, unsigned int flags) +{ + int ret; + //_update_curbrt(p); + p->bl_brt = _bl_brt; + p->bl_onoff = _bl_onoff; +#ifdef ENABLE_X_LCD_ONOFF + if (flags & FLAG_X_DPMS) { + p->bl_onoff = pm_x_set_lcd_backlight; + x_dpms_enable = true; + } +#endif +} + +static void _init_pmsys(PMSys *p) +{ + char tmp[NAME_MAX]; + + get_env(EN_SYS_DIMBRT, tmp, sizeof(tmp)); + + p->dim_brt = atoi(tmp); + p->sys_power_state = _sys_power_state; + p->sys_get_battery_capacity = _sys_get_battery_capacity; + p->sys_get_battery_capacity_raw = _sys_get_battery_capacity_raw; + p->sys_get_battery_charge_full = _sys_get_battery_charge_full; +} + +int system_suspend() +{ + LOGINFO("enter system suspend"); + if (pmsys && pmsys->sys_power_state) + return pmsys->sys_power_state(pmsys, POWER_STATE_SUSPEND); + + return 0; +} + +int system_pre_suspend() +{ + LOGINFO("enter system pre suspend"); + if (pmsys && pmsys->sys_power_state) + return pmsys->sys_power_state(pmsys, POWER_STATE_PRE_SUSPEND); + + return 0; +} + +int system_post_resume() +{ + LOGINFO("enter system post resume"); + if (pmsys && pmsys->sys_power_state) + return pmsys->sys_power_state(pmsys, POWER_STATE_POST_RESUME); + + return 0; +} + +int battery_capacity() +{ + if (pmsys && pmsys->sys_get_battery_capacity) + return pmsys->sys_get_battery_capacity(pmsys); + + return 0; +} + +int battery_capacity_raw() +{ + if (pmsys && pmsys->sys_get_battery_capacity_raw) + return pmsys->sys_get_battery_capacity_raw(pmsys); + + return 0; +} + +int battery_charge_full() +{ + if (pmsys && pmsys->sys_get_battery_charge_full) + return pmsys->sys_get_battery_charge_full(pmsys); + + return 0; +} + +int backlight_on() +{ + LOGINFO("LCD on"); + + if (pmsys && pmsys->bl_onoff) { + return pmsys->bl_onoff(pmsys, STATUS_ON); + } + + return 0; +} + +int backlight_off() +{ + LOGINFO("LCD off"); + + if (pmsys && pmsys->bl_onoff) { +#ifdef ENABLE_X_LCD_ONOFF + if (x_dpms_enable == false) +#endif + usleep(30000); + return pmsys->bl_onoff(pmsys, STATUS_OFF); + } + + return 0; +} + +int backlight_dim() +{ + int ret = 0; + if (pmsys && pmsys->bl_brt) { + ret = pmsys->bl_brt(pmsys, pmsys->dim_brt); + } + return ret; +} + +int backlight_restore() +{ + int ret = 0; + int val = -1; + + ret = vconf_get_int(VCONFKEY_PM_CUSTOM_BRIGHTNESS_STATUS, &val); + if (ret == 0 && val == VCONFKEY_PM_CUSTOM_BRIGHTNESS_ON) { + LOGINFO("custom brightness mode! brt no restored"); + return 0; + } + if ((status_flag & PWRSV_FLAG) && !(status_flag & BRTCH_FLAG)) + ret = backlight_dim(); + else if (pmsys && pmsys->bl_brt) + ret = pmsys->bl_brt(pmsys, pmsys->def_brt); + + return ret; +} + +int set_default_brt(int level) +{ + if (level < PM_MIN_BRIGHTNESS || level > PM_MAX_BRIGHTNESS) + level = PM_DEFAULT_BRIGHTNESS; + pmsys->def_brt = level; + + return 0; +} + +inline int check_wakeup_src(void) +{ + /* TODO if nedded. + * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT) + */ + return EVENT_DEVICE; +} + +int init_sysfs(unsigned int flags) +{ + int ret; + + pmsys = (PMSys *) malloc(sizeof(PMSys)); + if (pmsys == NULL) { + LOGERR("Not enough memory to alloc PM Sys"); + return -1; + } + + memset(pmsys, 0x0, sizeof(PMSys)); + + _init_pmsys(pmsys); + _init_bldev(pmsys, flags); + + if (pmsys->bl_onoff == NULL && pmsys->sys_power_state == NULL) { + LOGERR + ("We have no managable resource to reduce the power consumption"); + return -1; + } + + return 0; +} + +int exit_sysfs() +{ + int fd = -1; + + fd = open("/tmp/sem.pixmap_1", O_RDONLY); + if (fd == -1) { + LOGERR("X server disable"); + backlight_on(); + } + + backlight_restore(); + free(pmsys); + pmsys = NULL; + if (fd != -1) + close(fd); + + return 0; +} diff --git a/pm_llinterface.h b/pm_llinterface.h new file mode 100644 index 0000000..83b00d6 --- /dev/null +++ b/pm_llinterface.h @@ -0,0 +1,65 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_llinterface.h + * @author Suchang Woo (suchang.woo@samsung.com) + * @version 0.1 + * @brief Power manager low-level interface module header + */ +#ifndef __PM_LLINTERFACE_H__ +#define __PM_LLINTERFACE_H__ + +#define FLAG_X_DPMS 0x2 + +#define DEFAULT_DISPLAY 0 + +#define PM_MAX_BRIGHTNESS 100 +#define PM_MIN_BRIGHTNESS 1 +#ifdef TIZEN_EMUL +# define PM_DEFAULT_BRIGHTNESS 100 +#else +# define PM_DEFAULT_BRIGHTNESS 60 +#endif + +/* + * 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, +}; + +extern int init_sysfs(unsigned int); +extern int exit_sysfs(void); + +extern int system_suspend(void); + +extern int backlight_on(void); +extern int backlight_off(void); + +extern int backlight_dim(void); +extern int backlight_restore(void); + +extern int set_default_brt(int level); + +extern int check_wakeup_src(void); + +#endif diff --git a/pm_lsensor.c b/pm_lsensor.c new file mode 100644 index 0000000..71d6ddb --- /dev/null +++ b/pm_lsensor.c @@ -0,0 +1,286 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <limits.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> +#include <glib.h> +#include <vconf.h> +#include <sensor.h> + +#include "pm_core.h" +#include "pm_device_plugin.h" + +#define SAMPLING_INTERVAL 1 /* 1 sec */ +#define MAX_FAULT 5 + +static int (*prev_init_extention) (void *data); +static int (*_default_action) (int); +static int alc_timeout_id = 0; +static int sf_handle = -1; +static int fault_count = 0; + +static gboolean alc_handler(gpointer data) +{ + int value = 0; + static int cur_index = 1; + static int old_index = 1; + + sensor_data_t light_data; + if (cur_state != S_NORMAL){ + if (alc_timeout_id != 0) + g_source_remove(alc_timeout_id); + alc_timeout_id = 0; + } else { + if (sf_get_data(sf_handle, LIGHT_BASE_DATA_SET, &light_data) < 0) { + fault_count++; + } else { + if (light_data.values[0] < 0.0 || light_data.values[0] > 10.0) { + LOGINFO("fail to load light data : %d", (int)light_data.values[0]); + fault_count++; + } else { + int tmp_value; + int power_saving_stat = -1; + int power_saving_display_stat = -1; + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat); + if (power_saving_stat == 1) + vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat); + if (power_saving_display_stat != 1) + power_saving_display_stat = 0; + value = PM_MAX_BRIGHTNESS * (int)light_data.values[0] / 10; + plugin_intf->OEM_sys_get_backlight_brightness(DEFAULT_DISPLAY, &tmp_value, power_saving_display_stat); + if (tmp_value != value) { + set_default_brt(value); + backlight_restore(); + } + LOGINFO("load light data : %d, brightness : %d", (int)light_data.values[0], value); + } + } + } + + if (fault_count > MAX_FAULT) { + if (alc_timeout_id != 0) + g_source_remove(alc_timeout_id); + alc_timeout_id = 0; + vconf_set_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, SETTING_BRIGHTNESS_AUTOMATIC_OFF); + LOGERR("Fault counts is over 5, disable automatic brightness"); + return FALSE; + } + + if (alc_timeout_id != 0) + return TRUE; + + return FALSE; +} + +static int alc_action(int timeout) +{ + LOGINFO("alc action"); + /* sampling timer add */ + if (alc_timeout_id == 0 && !(status_flag & PWRSV_FLAG)) + alc_timeout_id = + g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, + SAMPLING_INTERVAL, + (GSourceFunc) alc_handler, NULL, + NULL); + + if (_default_action != NULL) + return _default_action(timeout); + + /* unreachable code */ + return -1; +} + +static int connect_sfsvc() +{ + int sf_state = -1; + /* connect with sensor fw */ + LOGINFO("connect with sensor fw"); + sf_handle = sf_connect(LIGHT_SENSOR); + if (sf_handle < 0) { + LOGERR("sensor attach fail"); + return -1; + } + sf_state = sf_start(sf_handle, 0); + if (sf_state < 0) { + LOGERR("sensor attach fail"); + sf_disconnect(sf_handle); + sf_handle = -1; + return -2; + } + fault_count = 0; + return 0; +} + +static int disconnect_sfsvc() +{ + LOGINFO("disconnect with sensor fw"); + if(sf_handle >= 0) + { + sf_stop(sf_handle); + sf_disconnect(sf_handle); + sf_handle = -1; + } + + if (_default_action != NULL) { + states[S_NORMAL].action = _default_action; + _default_action = NULL; + } + if (alc_timeout_id != 0) { + g_source_remove(alc_timeout_id); + alc_timeout_id = 0; + } + + return 0; +} + +static inline void set_brtch_state() +{ + if (status_flag & PWRSV_FLAG) { + status_flag |= BRTCH_FLAG; + vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM, true); + LOGINFO("brightness changed in low battery," + "escape dim state (light)"); + } +} + +static int set_alc_function(keynode_t *key_nodes, void *data) +{ + int onoff = 0; + int ret = -1; + int brt = -1; + int default_brt = -1; + int max_brt = -1; + + if (key_nodes == NULL) { + LOGERR("wrong parameter, key_nodes is null"); + return -1; + } + + onoff = vconf_keynode_get_int(key_nodes); + + if (onoff == SETTING_BRIGHTNESS_AUTOMATIC_ON) { + if(connect_sfsvc() < 0) + return -1; + /* escape dim state if it's in low battery.*/ + set_brtch_state(); + + /* change alc action func */ + if (_default_action == NULL) + _default_action = states[S_NORMAL].action; + states[S_NORMAL].action = alc_action; + alc_timeout_id = + g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, + SAMPLING_INTERVAL, + (GSourceFunc) alc_handler, NULL, + NULL); + } else if (onoff == SETTING_BRIGHTNESS_AUTOMATIC_PAUSE) { + LOGINFO("auto brightness paused!"); + disconnect_sfsvc(); + } else { + disconnect_sfsvc(); + /* escape dim state if it's in low battery.*/ + set_brtch_state(); + + ret = get_setting_brightness(&default_brt); + if (ret != 0 || (default_brt < PM_MIN_BRIGHTNESS || default_brt > PM_MAX_BRIGHTNESS)) { + LOGINFO("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; + } + + set_default_brt(default_brt); + backlight_restore(); + } + + return 0; +} + +static gboolean check_sfsvc(gpointer data) +{ + /* this function will return opposite value for re-callback in fail */ + int vconf_auto; + int sf_state = 0; + + LOGINFO("register sfsvc"); + + vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &vconf_auto); + if (vconf_auto == SETTING_BRIGHTNESS_AUTOMATIC_ON) { + if(connect_sfsvc() < 0) + return TRUE; + + /* change alc action func */ + if (_default_action == NULL) + _default_action = states[S_NORMAL].action; + states[S_NORMAL].action = alc_action; + alc_timeout_id = + g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, + SAMPLING_INTERVAL, + (GSourceFunc) alc_handler, NULL, + NULL); + if (alc_timeout_id != 0) + return FALSE; + disconnect_sfsvc(); + return TRUE; + } + LOGINFO("change vconf value before registering sfsvc"); + return FALSE; +} + +static int prepare_lsensor(void *data) +{ + int alc_conf; + int sf_state = 0; + + vconf_get_int(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, &alc_conf); + + if (alc_conf == SETTING_BRIGHTNESS_AUTOMATIC_ON) { + g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, + SAMPLING_INTERVAL, + (GSourceFunc) check_sfsvc, NULL, + NULL); + } + + /* add auto_brt_setting change handler */ + vconf_notify_key_changed(VCONFKEY_SETAPPL_BRIGHTNESS_AUTOMATIC_INT, + (void *)set_alc_function, NULL); + + if (prev_init_extention != NULL) + return prev_init_extention(data); + + return 0; +} + +static void __attribute__ ((constructor)) pm_lsensor_init() +{ + _default_action = NULL; + if (pm_init_extention != NULL) + prev_init_extention = pm_init_extention; + pm_init_extention = prepare_lsensor; +} + +static void __attribute__ ((destructor)) pm_lsensor_fini() +{ + +} diff --git a/pm_poll.c b/pm_poll.c new file mode 100644 index 0000000..c91ca4d --- /dev/null +++ b/pm_poll.c @@ -0,0 +1,301 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_poll.c + * @version 0.2 + * @brief Power Manager poll implementation (input devices & a domain socket file) + * + * This file includes the input device poll implementation. + * Default input devices are /dev/event0 and /dev/event1 + * User can use "PM_INPUT" for setting another input device poll in an environment file (/etc/profile). + * (ex: PM_INPUT=/dev/event0:/dev/event1:/dev/event5 ) + */ + +#include <glib.h> +#include <stdio.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "util.h" +#include "pm_core.h" +#include "pm_poll.h" + +#define DEV_PATH_DLM ":" + +PMMsg recv_data; +int (*g_pm_callback) (int, PMMsg *); + +#ifdef ENABLE_KEY_FILTER +extern int check_key_filter(int length, char buf[]); +# define CHECK_KEY_FILTER(a, b) do {\ + if (check_key_filter(a, b) != 0)\ + return TRUE;\ + } while (0); + +#else +# define CHECK_KEY_FILTER(a, b) +#endif + +#define DEFAULT_DEV_PATH "/dev/event1:/dev/event0" + +static GSource *src; +static GSourceFuncs *funcs; +static int sockfd; + +static gboolean pm_check(GSource *src) +{ + GSList *fd_list; + GPollFD *tmp; + + fd_list = src->poll_fds; + do { + tmp = (GPollFD *) fd_list->data; + if ((tmp->revents & (POLLIN | POLLPRI))) + return TRUE; + fd_list = fd_list->next; + } while (fd_list); + + return FALSE; +} + +static gboolean pm_dispatch(GSource *src, GSourceFunc callback, gpointer data) +{ + callback(data); + return TRUE; +} + +static gboolean pm_prepare(GSource *src, gint *timeout) +{ + return FALSE; +} + +gboolean pm_handler(gpointer data) +{ + char buf[1024]; + struct sockaddr_un clientaddr; + + GPollFD *gpollfd = (GPollFD *) data; + int ret; + int clilen = sizeof(clientaddr); + + if (g_pm_callback == NULL) { + return FALSE; + } + if (gpollfd->fd == sockfd) { + ret = + recvfrom(gpollfd->fd, &recv_data, sizeof(recv_data), 0, + (struct sockaddr *)&clientaddr, + (socklen_t *)&clilen); + (*g_pm_callback) (PM_CONTROL_EVENT, &recv_data); + } else { + ret = read(gpollfd->fd, buf, sizeof(buf)); + CHECK_KEY_FILTER(ret, buf); + (*g_pm_callback) (INPUT_POLL_EVENT, NULL); + } + + return TRUE; +} + +static int init_sock(char *sock_path) +{ + struct sockaddr_un serveraddr; + int fd; + + LOGINFO("initialize pm_socket for pm_control library"); + + if (sock_path == NULL || strcmp(sock_path, SOCK_PATH)) { + LOGERR("invalid sock_path= %s"); + return -1; + } + + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + LOGERR("socket error"); + return -1; + } + + unlink(sock_path); + + bzero(&serveraddr, sizeof(serveraddr)); + serveraddr.sun_family = AF_UNIX; + strncpy(serveraddr.sun_path, sock_path, sizeof(serveraddr.sun_path) - 1); + + if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { + LOGERR("bind error"); + close(fd); + return -1; + } + + if (chmod(sock_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) /* 0777 */ + LOGERR("failed to change the socket permission"); + + if (!strcmp(sock_path, SOCK_PATH)) + sockfd = fd; + + LOGINFO("init sock() sueccess!"); + return fd; +} + +int init_pm_poll(int (*pm_callback) (int, PMMsg *)) +{ + + guint ret; + char *dev_paths, *path_tok, *pm_input_env, *save_ptr; + int dev_paths_size; + + GPollFD *gpollfd; + + g_pm_callback = pm_callback; + + LOGINFO + ("initialize pm poll - input devices and domain socket(libpmapi)"); + + pm_input_env = getenv("PM_INPUT"); + if ((pm_input_env != NULL) && (strlen(pm_input_env) < 1024)) { + LOGINFO("Getting input device path from environment: %s", + pm_input_env); + /* Add 2 bytes for following strncat() */ + dev_paths_size = strlen(pm_input_env) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1; + dev_paths = (char *)malloc(dev_paths_size); + snprintf(dev_paths, dev_paths_size, "%s", pm_input_env); + } else { + /* Add 2 bytes for following strncat() */ + dev_paths_size = strlen(DEFAULT_DEV_PATH) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1; + dev_paths = (char *)malloc(dev_paths_size); + snprintf(dev_paths, dev_paths_size, "%s", DEFAULT_DEV_PATH); + } + + /* add the UNIX domain socket file path */ + strncat(dev_paths, DEV_PATH_DLM, strlen(DEV_PATH_DLM)); + strncat(dev_paths, SOCK_PATH, strlen(SOCK_PATH)); + dev_paths[dev_paths_size - 1] = '\0'; + + path_tok = strtok_r(dev_paths, DEV_PATH_DLM, &save_ptr); + if (path_tok == NULL) { + LOGERR("Device Path Tokeninzing Failed"); + free(dev_paths); + return -1; + } + + funcs = (GSourceFuncs *) g_malloc(sizeof(GSourceFuncs)); + funcs->prepare = pm_prepare; + funcs->check = pm_check; + funcs->dispatch = pm_dispatch; + funcs->finalize = NULL; + + do { + src = g_source_new(funcs, sizeof(GSource)); + + gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD)); + gpollfd->events = POLLIN; + + if (strcmp(path_tok, SOCK_PATH) == 0) { + gpollfd->fd = init_sock(SOCK_PATH); + LOGINFO("pm_poll domain socket file: %s, fd: %d", + path_tok, gpollfd->fd); + } else { + gpollfd->fd = open(path_tok, O_RDONLY); + LOGINFO("pm_poll input device file: %s, fd: %d", + path_tok, gpollfd->fd); + } + + if (gpollfd->fd == -1) { + LOGERR("Cannot open the file: %s", path_tok); + free(dev_paths); + return -1; + } + g_source_add_poll(src, gpollfd); + g_source_set_callback(src, (GSourceFunc) pm_handler, + (gpointer) gpollfd, NULL); + + g_source_set_priority(src, G_PRIORITY_LOW); + ret = g_source_attach(src, NULL); + if (ret == 0) { + LOGERR("Failed g_source_attach() in init_pm_poll()"); + free(dev_paths); + return -1; + } + g_source_unref(src); + + } while ((path_tok = strtok_r(NULL, DEV_PATH_DLM, &save_ptr))); + + free(dev_paths); + return 0; +} + +int exit_pm_poll() +{ + g_free(funcs); + close(sockfd); + unlink(SOCK_PATH); + LOGINFO("pm_poll is finished"); + return 0; +} + +int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path) +{ + guint ret; + indev *adddev = NULL; + + g_pm_callback = pm_callback; + + GPollFD *gpollfd; + const char *devpath; + GSource *devsrc; + + LOGINFO("initialize pm poll for bt %s",path); + adddev=(indev *)malloc(sizeof(indev)); + adddev->dev_fd = (GPollFD *)g_malloc(sizeof(GPollFD)); + (adddev->dev_fd)->events = POLLIN; + (adddev->dev_fd)->fd = open(path, O_RDONLY); + if((adddev->dev_fd)->fd == -1) { + LOGERR("Cannot open the file for BT: %s",path); + g_free(adddev->dev_fd); + free(adddev); + return -1; + } + adddev->dev_path = (char *)malloc(strlen(path) + 1); + strncpy(adddev->dev_path, path, strlen(path) + 1); + adddev->dev_src = g_source_new(funcs, sizeof(GSource)); + LOGINFO("pm_poll for BT input device file(path: %s, gsource: %d, gpollfd: %d", adddev->dev_path, adddev->dev_src, adddev->dev_fd); + indev_list=g_list_append(indev_list, adddev); + + g_source_add_poll(adddev->dev_src, adddev->dev_fd); + + g_source_set_callback(adddev->dev_src, (GSourceFunc) pm_handler, (gpointer)adddev->dev_fd, NULL); + + + g_source_set_priority(adddev->dev_src, G_PRIORITY_LOW ); + + ret = g_source_attach(adddev->dev_src, NULL); + if(ret == 0) + { + LOGERR("Failed g_source_attach() in init_pm_poll()"); + return -1; + } + g_source_unref(adddev->dev_src); + return 0; +} diff --git a/pm_poll.h b/pm_poll.h new file mode 100644 index 0000000..d1fb454 --- /dev/null +++ b/pm_poll.h @@ -0,0 +1,74 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_poll.h + * @version 0.2 + * @brief Power Manager input device poll implementation + * + * This file includes the input device poll implementation. + * Default input devices are /dev/event0 and /dev/event1 + * User can use "PM_INPUT_DEV" for setting another input device poll in an environment file (/etc/profile). + * (ex: PM_INPUT_DEV=/dev/event0:/dev/event1:/dev/event5 ) + */ + +#ifndef __PM_POLL_H__ +#define __PM_POLL_H__ + +#include<glib.h> + +/** + * @addtogroup POWER_MANAGER + * @{ + */ + +enum { + INPUT_POLL_EVENT = -9, + SIDEKEY_POLL_EVENT, + PWRKEY_POLL_EVENT, + PM_CONTROL_EVENT, +}; + +#define SOCK_PATH "/tmp/pm_sock" + +typedef struct { + pid_t pid; + unsigned int cond; + unsigned int timeout; +} PMMsg; + +typedef struct { + char *dev_path; + GSource *dev_src; + GPollFD *dev_fd; +} indev; + +GList *indev_list; + +PMMsg recv_data; +int (*g_pm_callback) (int, PMMsg *); + +extern int init_pm_poll(int (*pm_callback) (int, PMMsg *)); +extern int exit_pm_poll(); +extern int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path); + +/** + * @} + */ + +#endif /*__PM_POLL_H__ */ diff --git a/pm_setting.c b/pm_setting.c new file mode 100644 index 0000000..c552edb --- /dev/null +++ b/pm_setting.c @@ -0,0 +1,146 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 "pm_setting.h" +#include "pm_conf.h" +#include "util.h" + +static const char *setting_keys[SETTING_GET_END] = { + [SETTING_TO_NORMAL] = VCONFKEY_SETAPPL_LCD_TIMEOUT_NORMAL, + [SETTING_LOW_BATT] = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, + [SETTING_CHARGING] = VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, + [SETTING_BRT_LEVEL] = VCONFKEY_SETAPPL_LCD_BRIGHTNESS, + [SETTING_LOCK_SCREEN] = VCONFKEY_IDLE_LOCK_STATE, + [SETTING_POWER_SAVING] = VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, + [SETTING_POWER_SAVING_DISPLAY] = VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, +}; + +static int (*update_setting) (int key_idx, int val); + +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) +{ + return vconf_set_int(VCONFKEY_PM_STATE, val); +} + +int get_setting_brightness(int *level) +{ + return vconf_get_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, level); +} + +int get_run_timeout(int *timeout) +{ + int dim_timeout = -1, vconf_timeout = -1, ret; + get_dim_timeout(&dim_timeout); + + if(dim_timeout < 0) { + LOGERR("Can not get dim timeout. set default 5 seconds"); + dim_timeout = 5; + } + + ret = vconf_get_int(setting_keys[SETTING_TO_NORMAL], &vconf_timeout); + + if(vconf_timeout == 0) + *timeout = 0; //timeout 0 : Always ON (Do not apply dim_timeout) + else + *timeout = vconf_timeout - dim_timeout; + return ret; + +} + +int get_dim_timeout(int *timeout) +{ + char buf[255]; + /* TODO if needed */ + *timeout = 5; /* default timeout */ + get_env("PM_TO_LCDDIM", buf, sizeof(buf)); + LOGINFO("Get lcddim timeout [%s]", buf); + *timeout = atoi(buf); + return 0; +} + +int get_off_timeout(int *timeout) +{ + char buf[255]; + /* TODO if needed */ + *timeout = 5; /* default timeout */ + get_env("PM_TO_LCDOFF", buf, sizeof(buf)); + LOGINFO("Get lcdoff timeout [%s]", buf); + *timeout = atoi(buf); + return 0; +} + +static int setting_cb(keynode_t *key_nodes, void *data) +{ + keynode_t *tmp = key_nodes; + + if ((int)data > SETTING_END) { + LOGERR("Unknown setting key: %s, idx= %d", + vconf_keynode_get_name, (int)data); + return -1; + } + if (update_setting != NULL) { + if ((int)data >= SETTING_POWER_SAVING) + update_setting((int)data, vconf_keynode_get_bool(tmp)); + else + update_setting((int)data, vconf_keynode_get_int(tmp)); + } + + return 0; +} + +int init_setting(int (*func) (int key_idx, int val)) +{ + int i; + + if (func != NULL) + update_setting = func; + + for (i = SETTING_BEGIN; i < SETTING_GET_END; i++) { + vconf_notify_key_changed(setting_keys[i], (void *)setting_cb, + (void *)i); + } + + return 0; +} + +int exit_setting() +{ + 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/pm_setting.h b/pm_setting.h new file mode 100644 index 0000000..bf2b8e2 --- /dev/null +++ b/pm_setting.h @@ -0,0 +1,131 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 pm_setting.h + * @version 0.1 + * @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_LOW_BATT, + SETTING_CHARGING, + SETTING_BRT_LEVEL, + SETTING_LOCK_SCREEN, + SETTING_POWER_SAVING, + SETTING_POWER_SAVING_DISPLAY, + SETTING_GET_END, + SETTING_PM_STATE = SETTING_GET_END, + SETTING_END +}; + +extern int get_setting_brightness(); + +/* + * @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 + * @return 0 : success, -1 : error + */ +extern int get_run_timeout(int *timeout); + +/* + * get LCD dim state timeout from environment variable. + * + * @internal + * @param[out] timeout timeout variable pointer + * @return 0 : success, -1 : error + */ +extern int get_dim_timeout(int *timeout); + +/* + * get LCD off state timeout from environment variable. + * + * @internal + * @param[out] timeout timeout variable pointer + * @return 0 : success, -1 : error + */ +extern int get_off_timeout(int *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); + +/* + * @} + */ + +#endif diff --git a/pm_x_lcd_onoff.c b/pm_x_lcd_onoff.c new file mode 100644 index 0000000..01200ae --- /dev/null +++ b/pm_x_lcd_onoff.c @@ -0,0 +1,67 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 __PM_X_LCD_ONOFF_C__ +#define __PM_X_LCD_ONOFF_C__ + +#include <string.h> +#include <sys/wait.h> +#include <errno.h> + +#include "pm_device_plugin.h" + +#define CMD_ON "on" +#define CMD_OFF "off" + +static int pm_x_set_lcd_backlight(struct _PMSys *p, int onoff) +{ + pid_t pid; + char cmd_line[32]; + int ret; + + LOGINFO("Backlight onoff=%d", onoff); + if (onoff == STATUS_ON) + snprintf(cmd_line, sizeof(cmd_line), "%s", CMD_ON); + else + snprintf(cmd_line, sizeof(cmd_line), "%s", CMD_OFF); + + signal(SIGCHLD, SIG_DFL); + pid = vfork(); + + if (pid < 0) { + LOGERR("[1] Failed to fork child process for LCD On/Off"); + return -1; + } + + if (pid == 0) { + LOGINFO("[1] Child proccess for LCD %s was created (%s)", + ((onoff == STATUS_ON) ? "ON" : "OFF"), cmd_line); + execl("/usr/bin/xset", "/usr/bin/xset", "dpms", "force", + cmd_line, NULL); + _exit(0); + } else if (pid != (ret = waitpid(pid, NULL, 0))) { + LOGERR + ("[1] Waiting failed for the child process pid: %d, ret: %d, errno: %d", + pid, ret, errno); + } + + signal(SIGCHLD, SIG_IGN); + return 0; +} + +#endif /*__PM_X_LCD_ONOFF_C__ */ diff --git a/pmctrl.in b/pmctrl.in new file mode 100644 index 0000000..e6d8b5d --- /dev/null +++ b/pmctrl.in @@ -0,0 +1,86 @@ +#!/bin/sh + +KERNVER=`uname -r` + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib +export PATH=$PATH:/usr/bin +export ELM_FONT_PATH=@PREFIX@/share/SLP/fonts:@PREFIX@/share/SLP/licensed_fonts:@PREFIX@/share/fonts/truetype/ttf-bitstream-vera +export PM_EXEC_PRG=@PREFIX@/bin/@IDLE_LOCK@ + +export PM_TO_NORMAL=600 # normal state timeout seconds +export PM_TO_LCDDIM=5 # dim state timeout seconds +export PM_TO_LCDOFF=5 # off state timeout seconds +#export PM_TO_LCDOFF=0 # prevent suspend mode + +export PM_SYS_DIMBRT=0 + +DEV_INPUT= +ABS_POSITION_X=0x15 +ABS_POSITION_Y=0x16 +for file in /sys/class/input/event*; do + if [ -e $file ]; then + dev_keytype=`cat ${file}/device/capabilities/key` + if [ "$dev_keytype" != 0 ]; then + DEV_INPUT=$DEV_INPUT:/dev/input/${file#/sys/class/input/} + continue + fi + abs_num=`cat ${file}/device/capabilities/abs | wc -w | cut -d ' ' -f 1` + if [ $abs_num != 2 ]; then + continue + fi + abs_val=`cat ${file}/device/capabilities/abs | cut -d ' ' -f 1` + if [ $(((0x$abs_val >> $ABS_POSITION_X) & 0x1)) != 1 ]; then + continue + fi + if [ $(((0x$abs_val >> $ABS_POSITION_Y) & 0x1)) != 1 ]; then + continue + fi + DEV_INPUT=$DEV_INPUT:/dev/input/${file#/sys/class/input/} + fi +done + +export PM_INPUT=$DEV_INPUT + +PMD=@PREFIX@/bin/@EXEC@ + +echo "Input Event: $PM_INPUT" + OPT_X_DPMS="-x" + echo "LCD Power: X-DPMS enabled" + +case "$1" in + start) + if [ ! -e /opt/etc/.hib_capturing ]; then + $PMD -d $OPT_X_DPMS + fi + ;; + stop) + if [ -e /var/run/power-manager.pid ] ; then + kill -USR2 `cat /var/run/power-manager.pid` + fi + ;; + restart) + if [ -e /var/run/power-manager.pid ] ; then + kill -USR2 `cat /var/run/power-manager.pid` + # sleep 1 second to wait PID file get removed + sleep 1 + fi + if [ ! -e /opt/etc/.hib_capturing ]; then + $PMD -d $OPT_X_DPMS + fi + ;; + log) + if [ -e /var/run/power-manager.pid ] ; then + kill -HUP `cat /var/run/power-manager.pid` + fi + ;; + status) + echo "power manager is $([ ! -e /var/run/power-manager.pid ] && + echo "not ")running" + ;; + *) + echo "Usage: pmctrl {start | stop | restart | log | status}" + exit 1 +esac + +exit 0 + diff --git a/udev-rules/91-power-manager.rules.in b/udev-rules/91-power-manager.rules.in new file mode 100644 index 0000000..45ffb59 --- /dev/null +++ b/udev-rules/91-power-manager.rules.in @@ -0,0 +1,7 @@ +#input(like bt) +ACTION=="add" SUBSYSTEM=="input" DEVPATH=="*/input[0-9]*/event[0-9]*" RUN+="@PREFIX@/bin/pm_event add $DEVNAME" +ACTION=="remove" SUBSYSTEM=="input" DEVPATH=="*/input[0-9]*/event[0-9]*" RUN+="@PREFIX@/bin/pm_event remove $DEVNAME" + +# Since power_manager is running as app user, make sure this user can read the input device nodes +SUBSYSTEM=="input" DEVPATH=="*/input[0-9]*/event[0-9]*" GROUP="video" + @@ -0,0 +1,213 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.tizenopensource.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.c + * @version 0.1 + * @brief Utilities for Power manager + * + * This file includes logging, daemonize + */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdarg.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> +#include <signal.h> +#include <errno.h> + +#ifdef ENABLE_DLOG_OUT +#define LOG_TAG "POWER_MANAGER" +#endif + +#include "util.h" + +/** + * @addtogroup POWER_MANAGER + * @{ + */ + +/** + * @brief logging function + * + * This is log wrapper + * + * @param[in] priority log pritority + * @param[in] fmt format string + */ +void pm_log(int priority, char *fmt, ...) +{ + va_list ap; + char buf[NAME_MAX]; /* NAME_MAX is 255 */ + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); +#ifdef ENABLE_DLOG_OUT + switch (priority) { + case DLOG_DEBUG: + SLOGD("%s", buf); + break; + case DLOG_ERROR: + SLOGE("%s", buf); + break; + case DLOG_INFO: + SLOGI("%s", buf); + break; + default: + SLOGV("%s", buf); + break; + } +#else + syslog(priority, "%s", buf); +#endif + printf("\x1b[1;33;44m[PowerManager] %s\x1b[0m\n\n", buf); +} + +/** + * @brief write the pid + * + * get a pid and write it to pidpath + * + * @param[in] pidpath pid file path + * @return 0 (always) + */ +int writepid(char *pidpath) +{ + FILE *fp; + + fp = fopen(pidpath, "w"); + if (fp != NULL) { + fprintf(fp, "%d", getpid()); + fclose(fp); + } + + return 0; +} + +/** + * @brief read the pid + * + * get a pid and write it to pidpath + * + * @param[in] pidpath pid file path + * @return pid : success, -1 : failed + */ +int readpid(char *pidpath) +{ + FILE *fp; + int ret = -1; + + fp = fopen(pidpath, "r"); + if (fp != NULL) { + fscanf(fp, "%5d", &ret); + fclose(fp); + } + + return ret; +} + +/** + * @brief daemonize function + * + * fork the process, kill the parent process + * and replace all the standard fds to /dev/null. + * + * @return 0 : success, -1 : fork() error + */ +int daemonize(void) +{ + pid_t pid; + + pid = fork(); + if (pid < 0) + return -1; + else if (pid != 0) + exit(0); + + setsid(); + chdir("/"); + + close(0); + close(1); + close(2); + + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDWR); + dup(1); + + return 0; +} + +/** + * @brief function to run a process + * + * fork the process, and run the other process if it is child. + * + * @return new process pid on success, -1 on error + */ + +int exec_process(char *name) +{ + int ret, pid; + int i; + + if (name[0] == '\0') + return 0; + + pid = fork(); + switch (pid) { + case -1: + LOGERR("Fork error"); + ret = -1; + break; + case 0: + for (i = 0; i < _NSIG; i++) + signal(i, SIG_DFL); + execlp(name, name, NULL); + LOGERR("execlp() error : %s\n", strerror(errno)); + exit(-1); + break; + default: + ret = pid; + break; + } + return ret; +} + +char *get_pkgname(char *exepath) +{ + char *filename; + char pkgname[NAME_MAX]; + + filename = strrchr(exepath, '/'); + if (filename == NULL) + filename = exepath; + else + filename = filename + 1; + + snprintf(pkgname, NAME_MAX, "deb.com.samsung.%s", filename); + + return strdup(pkgname); +} + +/** + * @} + */ @@ -0,0 +1,110 @@ +/* + * power-manager + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + * @version 0.1 + * @brief Utilities header for Power manager + */ +#ifndef __DEF_UTIL_H__ +#define __DEF_UTIL_H__ + +/** + * @addtogroup POWER_MANAGER + * @{ + */ + +/* + * @brief write the pid + * + * get a pid and write it to pidpath + * + * @param[in] pidpath pid file path + * @return 0 (always) + */ +extern int writepid(char *pidpath); + +/* + * @brief read the pid + * + * get a pid and write it to pidpath + * + * @param[in] pidpath pid file path + * @return pid : success, -1 : failed + */ +extern int readpid(char *pidpath); + +/* + * @brief daemonize function + * + * fork the process, kill the parent process + * and replace all the standard fds to /dev/null. + * + * @return 0 : success, -1 : fork() error + */ +extern int daemonize(void); + +/** + * @brief function to run a process + * + * fork the process, and run the other process if it is child. + * + * @return new process pid on success, -1 on error + */ +extern int exec_process(char *name); + +/** + * @brief function to get the pkg name for AUL (Application Util Library) + * + * remove the path of exepath and make the "com.samsung.<exe_file_name>" string. + * + * @return new process pid on success, -1 on error + */ +extern char *get_pkgname(char *exepath); + +/* + * @brief logging function + * + * This is log wrapper + * + * @param[in] priority log pritority + * @param[in] fmt format string + */ +extern void pm_log(int priority, char *fmt, ...); + +#if defined(ENABLE_DLOG_OUT) +# include <dlog.h> +/* + * @brief LOG_INFO wrapper + */ +# define LOGINFO(fmt, arg...) pm_log(DLOG_INFO, fmt, ## arg) + +/* + * @brief LOG_ERR wrapper + */ +# define LOGERR(fmt, arg...) pm_log(DLOG_ERROR, fmt, ## arg) +#else +# include <syslog.h> +# define LOGINFO(fmt, arg...) pm_log(LOG_INFO, fmt, ## arg) +# define LOGERR(fmt, arg...) pm_log(LOG_ERR, fmt, ## arg) +#endif + +/** + * @} + */ +#endif |