aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore46
-rw-r--r--Android.mk34
-rw-r--r--LICENSE221
-rw-r--r--Makefile8
-rw-r--r--clocks.c801
-rw-r--r--clocks.h43
-rw-r--r--display.c703
-rw-r--r--display.h29
-rw-r--r--doc.txt20
-rw-r--r--gpio.c280
-rw-r--r--gpio.h17
-rw-r--r--mainloop.c122
-rw-r--r--mainloop.h22
-rw-r--r--powerdebug.c408
-rw-r--r--powerdebug.h59
-rw-r--r--regulator.c360
-rw-r--r--regulator.h31
-rw-r--r--sensor.c327
-rw-r--r--sensor.h10
-rw-r--r--tree.c357
-rw-r--r--tree.h54
-rw-r--r--utils.c55
-rw-r--r--utils.h22
23 files changed, 2738 insertions, 1291 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..217aabb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,46 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.patch
+
+#
+# Top-level generic files
+#
+/tags
+/TAGS
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+*.orig
+*~
+\#*#
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..36c73cd
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libstlport
+
+LOCAL_STATIC_LIBRARIES := libncurses
+
+LOCAL_MODULE := powerdebug
+
+LOCAL_CPPFLAGS += \
+ -DDISABLE_I18N \
+ -DDISABLE_TRYCATCH \
+ -DNCURSES_NOMACROS \
+ -DDISABLE_WSTRING \
+ -DDEFAULT_TERM=\"xterm\" \
+ -DTERMINFO_PATH=\"/system/etc/terminfo\" \
+ -DDEFINE_ETHTOOL_CMD \
+
+LOCAL_C_INCLUDES += external/stlport/stlport/ \
+ external/stlport/stlport/stl \
+ external/stlport/stlport/using/h/ \
+ bionic \
+ external/ncurses \
+ external/ncurses/lib \
+ external/ncurses/include \
+ external/ncurses/include/ncurses
+
+LOCAL_SRC_FILES += \
+ powerdebug.c sensor.c clocks.c regulator.c \
+ display.c tree.c utils.c mainloop.c gpio.c
+
+include $(BUILD_EXECUTABLE)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..be6f09f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,221 @@
+Copyright (C) 2010 Linaro Ltd.
+
+License: EPL-1.0
+ Eclipse Public License - v 1.0
+
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+ PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+ PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+ 1. DEFINITIONS
+
+ "Contribution" means:
+
+ a) in the case of the initial Contributor, the initial code and documentation
+ distributed under this Agreement, and
+ b) in the case of each subsequent Contributor:
+
+ i) changes to the Program, and
+
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+ distributed by that particular Contributor. A Contribution 'originates'
+ from a Contributor if it was added to the Program by such Contributor itself
+ or anyone acting on such Contributor's behalf. Contributions do not include
+ additions to the Program which: (i) are separate modules of software
+ distributed in conjunction with the Program under their own license
+ agreement, and (ii) are not derivative works of the Program.
+
+ "Contributor" means any person or entity that distributes the Program.
+
+ "Licensed Patents " mean patent claims licensable by a Contributor which are
+ necessarily infringed by the use or sale of its Contribution alone or when
+ combined with the Program.
+
+ "Program" means the Contributions distributed in accordance with this
+ Agreement.
+
+ "Recipient" means anyone who receives the Program under this Agreement,
+ including all Contributors.
+
+ 2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to
+ reproduce, prepare derivative works of, publicly display, publicly perform,
+ distribute and sublicense the Contribution of such Contributor, if any,
+ and such derivative works, in source code and object code form.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free patent license under
+ Licensed Patents to make, use, sell, offer to sell, import and otherwise
+ transfer the Contribution of such Contributor, if any, in source code and
+ object code form. This patent license shall apply to the combination of
+ the Contribution and the Program if, at the time the Contribution is added
+ by the Contributor, such addition of the Contribution causes such
+ combination to be covered by the Licensed Patents. The patent license shall
+ not apply to any other combinations which include the Contribution. No
+ hardware per se is licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the licenses
+ to its Contributions set forth herein, no assurances are provided by any
+ Contributor that the Program does not infringe the patent or other
+ intellectual property rights of any other entity. Each Contributor disclaims
+ any liability to Recipient for claims brought by any other entity based on
+ infringement of intellectual property rights or otherwise. As a condition to
+ exercising the rights and licenses granted hereunder, each Recipient hereby
+ assumes sole responsibility to secure any other intellectual property rights
+ needed, if any. For example, if a third party patent license is required to
+ allow Recipient to distribute the Program, it is Recipient's responsibility
+ to acquire that license before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright license
+ set forth in this Agreement.
+
+ 3. REQUIREMENTS
+
+ A Contributor may choose to distribute the Program in object code form under
+ its own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+
+ b) its license agreement:
+
+ i) effectively disclaims on behalf of all Contributors all warranties and
+ conditions, express and implied, including warranties or conditions of title
+ and non-infringement, and implied warranties or conditions of merchantability
+ and fitness for a particular purpose;
+
+ ii) effectively excludes on behalf of all Contributors all liability for
+ damages, including direct, indirect, special, incidental and consequential
+ damages, such as lost profits;
+
+ iii) states that any provisions which differ from this Agreement are offered
+ by that Contributor alone and not by any other party; and
+
+ iv) states that source code for the Program is available from such
+ Contributor, and informs licensees how to obtain it in a reasonable manner on
+ or through a medium customarily used for software exchange.
+
+ When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+
+ b) a copy of this Agreement must be included with each copy of the Program.
+
+ Contributors may not remove or alter any copyright notices contained within
+ the Program.
+
+ Each Contributor must identify itself as the originator of its Contribution,
+ if any, in a manner that reasonably allows subsequent Recipients to identify
+ the originator of the Contribution.
+
+ 4. COMMERCIAL DISTRIBUTION
+
+ Commercial distributors of software may accept certain responsibilities with
+ respect to end users, business partners and the like. While this license is
+ intended to facilitate the commercial use of the Program, the Contributor who
+ includes the Program in a commercial product offering should do so in a
+manner
+ which does not create potential liability for other Contributors. Therefore,
+ if a Contributor includes the Program in a commercial product offering, such
+ Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+ every other Contributor ("Indemnified Contributor") against any losses,
+ damages and costs (collectively "Losses") arising from claims, lawsuits and
+ other legal actions brought by a third party against the Indemnified
+ Contributor to the extent caused by the acts or omissions of such Commercial
+ Contributor in connection with its distribution of the Program in a
+commercial
+ product offering. The obligations in this section do not apply to any claims
+ or Losses relating to any actual or alleged intellectual property
+ infringement. In order to qualify, an Indemnified Contributor must:
+ a) promptly notify the Commercial Contributor in writing of such claim, and
+ b) allow the Commercial Contributor to control, and cooperate with the
+ Commercial Contributor in, the defense and any related settlement
+ negotiations. The Indemnified Contributor may participate in any such claim
+ at its own expense.
+
+ For example, a Contributor might include the Program in a commercial product
+ offering, Product X. That Contributor is then a Commercial Contributor. If
+ that Commercial Contributor then makes performance claims, or offers
+ warranties related to Product X, those performance claims and warranties are
+ such Commercial Contributor's responsibility alone. Under this section, the
+ Commercial Contributor would have to defend claims against the other
+ Contributors related to those performance claims and warranties, and if a
+ court requires any other Contributor to pay any damages as a result, the
+ Commercial Contributor must pay those damages.
+
+ 5. NO WARRANTY
+
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the
+ appropriateness of using and distributing the Program and assumes all
+ risks associated with its exercise of rights under this Agreement ,
+ including but not limited to the risks and costs of program errors,
+ compliance with applicable laws, damage to or loss of data, programs or
+ equipment, and unavailability or interruption of operations.
+
+ 6. DISCLAIMER OF LIABILITY
+
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+ CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
+ LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+ EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGES.
+
+ 7. GENERAL
+
+ If any provision of this Agreement is invalid or unenforceable under
+ applicable law, it shall not affect the validity or enforceability of the
+ remainder of the terms of this Agreement, and without further action by
+ the parties hereto, such provision shall be reformed to the minimum extent
+ necessary to make such provision valid and enforceable.
+
+ If Recipient institutes patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+ (excluding combinations of the Program with other software or hardware)
+ infringes such Recipient's patent(s), then such Recipient's rights granted
+ under Section 2(b) shall terminate as of the date such litigation is filed.
+
+ All Recipient's rights under this Agreement shall terminate if it fails to
+ comply with any of the material terms or conditions of this Agreement and
+ does not cure such failure in a reasonable period of time after becoming
+ aware of such noncompliance. If all Recipient's rights under this Agreement
+ terminate, Recipient agrees to cease use and distribution of the Program as
+ soon as reasonably practicable. However, Recipient's obligations under this
+ Agreement and any licenses granted by Recipient relating to the Program
+ shall continue and survive.
+
+ Everyone is permitted to copy and distribute copies of this Agreement, but
+ in order to avoid inconsistency the Agreement is copyrighted and may only
+ be modified in the following manner. The Agreement Steward reserves the
+ right to publish new versions (including revisions) of this Agreement from
+ time to time. No one other than the Agreement Steward has the right to
+ modify this Agreement. The Eclipse Foundation is the initial Agreement
+ Steward. The Eclipse Foundation may assign the responsibility to serve as
+ the Agreement Steward to a suitable separate entity. Each new version of
+ the Agreement will be given a distinguishing version number. The Program
+ (including Contributions) may always be distributed subject to the version
+ of the Agreement under which it was received. In addition, after a new
+ version of the Agreement is published, Contributor may elect to distribute
+ the Program (including its Contributions) under the new version. Except as
+ expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+ rights or licenses to the intellectual property of any Contributor under
+ this Agreement, whether expressly, by implication, estoppel or otherwise.
+ All rights in the Program not expressly granted under this Agreement are
+ reserved.
+
+ This Agreement is governed by the laws of the State of New York and the
+ intellectual property laws of the United States of America. No party to
+ this Agreement will bring a legal action under this Agreement more than
+ one year after the cause of action arose. Each party waives its rights to
+ a jury trial in any resulting litigation.
+
diff --git a/Makefile b/Makefile
index 0ac486d..2da9d67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
BINDIR=/usr/sbin
MANDIR=/usr/share/man/man8
-WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS?=-O1 -g ${WARNFLAGS}
+CFLAGS?=-O1 -g -Wall -Wshadow
CC?=gcc
-OBJS = powerdebug.o sensor.o clocks.o regulator.o display.o
+OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \
+ display.o tree.o utils.o mainloop.o
default: powerdebug
@@ -23,4 +23,4 @@ install: powerdebug powerdebug.8.gz
all: powerdebug powerdebug.8.gz
clean:
- rm -f powerdebug *.o powerdebug.8.gz
+ rm -f powerdebug ${OBJS} powerdebug.8.gz
diff --git a/clocks.c b/clocks.c
index 9a76c19..95acf57 100644
--- a/clocks.c
+++ b/clocks.c
@@ -11,565 +11,438 @@
* Contributors:
* Amit Arora <amit.arora@linaro.org> (IBM Corporation)
* - initial API and implementation
+ *
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - Rewrote code and API
+ *
*******************************************************************************/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mntent.h>
+#include <sys/stat.h>
+
#include "powerdebug.h"
+#include "display.h"
#include "clocks.h"
-
-static char clk_dir_path[PATH_MAX];
-static char clk_name[NAME_MAX];
-static int bold[MAX_LINES];
-
-int init_clock_details(void)
+#include "tree.h"
+#include "utils.h"
+
+struct clock_info {
+ int flags;
+ int rate;
+ int usecount;
+ bool expanded;
+ char *prefix;
+ int preparecount;
+ int enablecount;
+ int notifiercount;
+} *clocks_info;
+
+enum clock_fw_type{
+ CCF, /* common clock framework */
+ OCF, /* old clock framework */
+ MAX,
+};
+
+static struct tree *clock_tree = NULL;
+static int clock_fw;
+
+static int locate_debugfs(char *clk_path)
{
- char *path = debugfs_locate_mpoint();
- struct stat buf;
-
- if (path)
- strcpy(clk_dir_path, path);
- else {
- if (!dump) {
- create_selectedwindow();
- sprintf(clock_lines[0], "Unable to locate debugfs "
- "mount point. Mount debugfs "
- "and try again..\n");
- print_one_clock(0, clock_lines[0], 1, 0);
- old_clock_line_no = 1;
- return(1);
- } else {
- fprintf(stderr, "powerdebug: Unable to locate debugfs "
- "mount point. Mount debugfs and try "
- "again..\n");
- exit(1);
- }
- }
- sprintf(clk_dir_path, "%s/clock", clk_dir_path);
- //strcpy(clk_dir_path, "/debug/clock"); // Hardcoded for testing..
- if (stat(clk_dir_path, &buf)) {
- if (!dump) {
- create_selectedwindow();
- sprintf(clock_lines[0], "Unable to find clock tree"
- " information at %s.\n", clk_dir_path);
- print_one_clock(0, clock_lines[0], 1, 0);
- old_clock_line_no = 1;
- return(1);
- } else {
- fprintf(stderr, "powerdebug: Unable to find clock tree"
- " information at %s.\n", clk_dir_path);
- exit(1);
- }
- }
- strcpy(clk_name, "");
- return(0);
+ strcpy(clk_path, "/sys/kernel/debug");
+ return 0;
}
-int get_int_from(char *file)
+static struct clock_info *clock_alloc(void)
{
- FILE *filep;
- char result[NAME_MAX];
- int ret;
-
- filep = fopen(file, "r");
+ struct clock_info *ci;
- if (!filep)
- return -1; //TBD : What should we return on failure, here ?
+ ci = malloc(sizeof(*ci));
+ if (ci)
+ memset(ci, 0, sizeof(*ci));
- ret = fscanf(filep, "%s", result);
- fclose(filep);
-
- return atoi(result);
+ return ci;
}
-void find_parents_for_clock(char *clkname, int complete)
+static inline const char *clock_rate(int *rate)
{
- char name[256];
-
- name[0] = '\0';
- if (!complete) {
- char str[256];
-
- strcat(name, clkname);
- sprintf(str, "Enter Clock Name : %s\n", name);
- print_one_clock(2, str, 1, 0);
- return;
- }
- sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
- print_one_clock(0, name, 1, 1);
- dump_all_parents(clkname);
+ int r;
+
+ /* GHZ */
+ r = *rate >> 30;
+ if (r) {
+ *rate = r;
+ return "GHZ";
+ }
+
+ /* MHZ */
+ r = *rate >> 20;
+ if (r) {
+ *rate = r;
+ return "MHZ";
+ }
+
+ /* KHZ */
+ r = *rate >> 10;
+ if (r) {
+ *rate = r;
+ return "KHZ";
+ }
+
+ return "";
}
-int read_and_print_clock_info(int verbose, int hrow, int selected)
+static int dump_clock_cb(struct tree *t, void *data)
{
- print_one_clock(0, "Reading Clock Tree ...", 1, 1);
+ struct clock_info *clk = t->private;
+ struct clock_info *pclk;
+ const char *unit;
+ int ret = 0;
+ int rate = clk->rate;
- if (!old_clock_line_no || selected == REFRESH_WINDOW) {
- destroy_clocks_info();
- read_clock_info(clk_dir_path);
+ if (!t->parent) {
+ printf("/\n");
+ clk->prefix = "";
+ return 0;
}
- if (!clocks_info->num_children) {
- fprintf(stderr, "powerdebug: No clocks found. Exiting..\n");
- exit(1);
- }
+ pclk = t->parent->private;
- if (selected == CLOCK_SELECTED)
- selected = 1;
- else
- selected = 0;
+ if (!clk->prefix)
+ ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
+ t->depth > 1 ? " ": "", t->next ? "|" : " ");
+ if (ret < 0)
+ return -1;
- print_clock_info(verbose, hrow, selected);
- hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1;
+ unit = clock_rate(&rate);
- return hrow;
-}
-
-int calc_delta_screen_size(int hrow)
-{
- if (hrow >= (maxy - 3))
- return hrow - (maxy - 4);
+ printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
+ clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
+ clk->usecount, rate, unit);
return 0;
}
-void print_clock_info(int verbose, int hrow, int selected)
+int dump_clock_info(void)
{
- int i, count = 0, delta;
-
- (void)verbose;
+ return tree_for_each(clock_tree, dump_clock_cb, NULL);
+}
- print_clock_header();
+static int dump_all_parents(char *clkarg)
+{
+ struct tree *tree;
- for (i = 0; i < clocks_info->num_children; i++)
- add_clock_details_recur(clocks_info->children[i],
- hrow, selected);
+ tree = tree_find(clock_tree, clkarg);
+ if (!tree) {
+ printf("Clock NOT found!\n");
+ return -1;
+ }
- delta = calc_delta_screen_size(hrow);
+ return tree_for_each_parent(tree, dump_clock_cb, NULL);
+}
- while (clock_lines[count + delta] &&
- strcmp(clock_lines[count + delta], "")) {
- if (count < delta) {
- count++;
- continue;
- }
- print_one_clock(count - delta, clock_lines[count + delta],
- bold[count + delta], (hrow == (count + delta)));
- count++;
+static inline int read_clock_cb(struct tree *t, void *data)
+{
+ struct clock_info *clk = t->private;
+
+ if(clock_fw == CCF) {
+ file_read_value(t->path, "clk_flags", "%x", &clk->flags);
+ file_read_value(t->path, "clk_rate", "%d", &clk->rate);
+ file_read_value(t->path, "clk_prepare_count", "%d", &clk->preparecount);
+ file_read_value(t->path, "clk_enable_count", "%d", &clk->enablecount);
+ file_read_value(t->path, "clk_notifier_count", "%d", &clk->notifiercount);
+ }
+ else {
+ file_read_value(t->path, "flags", "%x", &clk->flags);
+ file_read_value(t->path, "rate", "%d", &clk->rate);
+ file_read_value(t->path, "usecount", "%d", &clk->usecount);
}
- old_clock_line_no = clock_line_no;
- clock_line_no = 0;
+ return 0;
}
-void prepare_name_str(char *namestr, struct clock_info *clock)
+static int read_clock_info(struct tree *tree)
{
- int i;
-
- strcpy(namestr, "");
- if (clock->level > 1)
- for (i = 0; i < (clock->level - 1); i++)
- strcat(namestr, " ");
- strcat(namestr, clock->name);
+ return tree_for_each(tree, read_clock_cb, NULL);
}
-void add_clock_details_recur(struct clock_info *clock, int hrow, int selected)
+static int fill_clock_cb(struct tree *t, void *data)
{
- int i;
- char *unit = " Hz";
- char rate_str[64];
- char name_str[256];
- double drate = (double)clock->rate;
-
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- if (clock->usecount)
- bold[clock_line_no] = 1;
- else
- bold[clock_line_no] = 0;
-
- sprintf(rate_str, "%.2f %s", drate, unit);
- prepare_name_str(name_str, clock);
- sprintf(clock_lines[clock_line_no++], "%-55s %-4d %-12s %-12d %-12d",
- name_str, clock->flags, rate_str, clock->usecount,
- clock->num_children);
-
- if (selected && (hrow == (clock_line_no - 1))) {
- if (clock->expanded)
- collapse_all_subclocks(clock);
- else
- clock->expanded = 1;
- selected = 0;
+ struct clock_info *clk;
+
+ clk = clock_alloc();
+ if (!clk)
+ return -1;
+ t->private = clk;
+
+ /* we skip the root node but we set it expanded for its children */
+ if (!t->parent) {
+ clk->expanded = true;
+ return 0;
}
- if (clock->expanded && clock->num_children)
- for (i = 0; i < clock->num_children; i++)
- add_clock_details_recur(clock->children[i],
- hrow, selected);
- strcpy(clock_lines[clock_line_no], "");
+ return read_clock_cb(t, data);
}
-void collapse_all_subclocks(struct clock_info *clock)
+static int fill_clock_tree(void)
{
- int i;
-
- clock->expanded = 0;
- if (clock->num_children)
- for (i = 0; i < clock->num_children; i++)
- collapse_all_subclocks(clock->children[i]);
+ return tree_for_each(clock_tree, fill_clock_cb, NULL);
}
-void destroy_clocks_info(void)
+static int is_collapsed(struct tree *t, void *data)
{
- int i;
-
- if (!clocks_info)
- return;
-
- if (clocks_info->num_children) {
- for (i = (clocks_info->num_children - 1); i >= 0 ; i--) {
- destroy_clocks_info_recur(clocks_info->children[i]);
- if (!i) {
- free(clocks_info->children);
- clocks_info->children = NULL;
- }
- }
- }
- clocks_info->num_children = 0;
- free(clocks_info);
- clocks_info = NULL;
+ struct clock_info *clk = t->private;
+
+ if (!clk->expanded)
+ return 1;
+
+ return 0;
}
-void destroy_clocks_info_recur(struct clock_info *clock)
+static char *clock_line(struct tree *t)
{
- int i;
-
- if (clock && clock->num_children) {
- for (i = (clock->num_children - 1); i >= 0; i--) {
- fflush(stdin);
- destroy_clocks_info_recur(clock->children[i]);
- if (!i) {
- free(clock->children);
- clock->children = NULL;
- clock->num_children = 0;
- }
- }
+ struct clock_info *clk;
+ int rate;
+ const char *clkunit;
+ char *clkrate, *clkname, *clkline = NULL;
+
+ clk = t->private;
+ rate = clk->rate;
+ clkunit = clock_rate(&rate);
+
+ if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
+ return NULL;
+
+ if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
+ goto free_clkname;
+
+ if(clock_fw == CCF) {
+ if (asprintf(&clkline, "%-35s 0x%-8x %-12s %-10d %-11d %-15d %-14d %-10d",
+ clkname, clk->flags, clkrate, clk->usecount, t->nrchild,
+ clk->preparecount, clk->enablecount, clk->notifiercount) < 0)
+ goto free_clkrate;
+ }
+ else {
+ if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d",
+ clkname, clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
+ goto free_clkrate;
}
+
+free_clkrate:
+ free(clkrate);
+free_clkname:
+ free(clkname);
+
+ return clkline;
}
-void read_and_dump_clock_info_one(char *clk)
+static int _clock_print_info_cb(struct tree *t, void *data)
{
- printf("\nParents for \"%s\" Clock :\n\n", clk);
- read_clock_info(clk_dir_path);
- dump_all_parents(clk);
- printf("\n\n");
+ struct clock_info *clock = t->private;
+ int *line = data;
+ char *buffer;
+
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ buffer = clock_line(t);
+ if (!buffer)
+ return -1;
+
+ display_print_line(CLOCK, *line, buffer, clock->usecount, t);
+
+ (*line)++;
+
+ free(buffer);
+
+ return 0;
}
-void read_and_dump_clock_info(int verbose)
+static int clock_print_info_cb(struct tree *t, void *data)
{
- (void)verbose;
- printf("\nClock Tree :\n");
- printf("**********\n");
- read_clock_info(clk_dir_path);
- dump_clock_info(clocks_info, 1, 1);
- printf("\n\n");
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ /* show the clock when *all* its parent is expanded */
+ if (tree_for_each_parent(t->parent, is_collapsed, NULL))
+ return 0;
+
+ return _clock_print_info_cb(t, data);
}
-void read_clock_info(char *clkpath)
+static int clock_print_header(void)
{
- DIR *dir;
- struct dirent *item;
- char filename[NAME_MAX], clockname[NAME_MAX];
- struct clock_info *child;
- struct clock_info *cur;
-
- dir = opendir(clkpath);
- if (!dir)
- return;
-
- clocks_info = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(clocks_info, 0, sizeof(clocks_info));
- strcpy(clocks_info->name, "/");
- clocks_info->level = 0;
-
- while ((item = readdir(dir))) {
- /* skip hidden dirs except ".." */
- if (item->d_name[0] == '.')
- continue;
-
- strcpy(clockname, item->d_name);
- sprintf(filename, "%s/%s", clkpath, item->d_name);
- cur = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(cur, 0, sizeof(struct clock_info));
- strcpy(cur->name, clockname);
- cur->parent = clocks_info;
- cur->num_children = 0;
- cur->expanded = 0;
- cur->level = 1;
- insert_children(&clocks_info, cur);
- child = read_clock_info_recur(filename, 2, cur);
+ char *buf;
+ int ret;
+
+ if(clock_fw == CCF) {
+ if (asprintf(&buf, "%-35s %-10s %-12s %-10s %-11s %-15s %-14s %-14s",
+ "Name", "Flags", "Rate", "Usecount", "Children", "Prepare_Count",
+ "Enable_Count", "Notifier_Count") < 0)
+ return -1;
+ }
+ else {
+ if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
+ "Name", "Flags", "Rate", "Usecount", "Children") < 0)
+ return -1;
}
- closedir(dir);
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
}
-struct clock_info *read_clock_info_recur(char *clkpath, int level,
- struct clock_info *parent)
+static int clock_print_info(struct tree *tree)
{
- int ret = 0;
- DIR *dir;
- char filename[PATH_MAX];
- struct dirent *item;
- struct clock_info *cur = NULL;
- struct stat buf;
-
- dir = opendir(clkpath);
- if (!dir)
- return NULL;
+ int ret, line = 0;
- while ((item = readdir(dir))) {
- struct clock_info *child;
- /* skip hidden dirs except ".." */
- if (item->d_name[0] == '.' )
- continue;
-
- sprintf(filename, "%s/%s", clkpath, item->d_name);
-
- ret = stat(filename, &buf);
-
- if (ret < 0) {
- printf("Error doing a stat on %s\n", filename);
- exit(1);
- }
-
- if (S_ISREG(buf.st_mode)) {
- if (!strcmp(item->d_name, "flags"))
- parent->flags = get_int_from(filename);
- if (!strcmp(item->d_name, "rate"))
- parent->rate = get_int_from(filename);
- if (!strcmp(item->d_name, "usecount"))
- parent->usecount = get_int_from(filename);
- continue;
- }
-
- if (!S_ISDIR(buf.st_mode))
- continue;
-
- cur = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(cur, 0, sizeof(cur));
- strcpy(cur->name, item->d_name);
- cur->children = NULL;
- cur->parent = NULL;
- cur->num_children = 0;
- cur->expanded = 0;
- cur->level = level;
- child = read_clock_info_recur(filename, level + 1, cur);
- insert_children(&parent, cur);
- cur->parent = parent;
- }
- closedir(dir);
+ display_reset_cursor(CLOCK);
+
+ clock_print_header();
+
+ ret = tree_for_each(tree, clock_print_info_cb, &line);
- return cur;
+ display_refresh_pad(CLOCK);
+
+ return ret;
}
-void insert_children(struct clock_info **parent, struct clock_info *clk)
+static int clock_select(void)
{
- if (!(*parent)->num_children || (*parent)->children == NULL) {
- (*parent)->children = (struct clock_info **)
- malloc(sizeof(struct clock_info *)*2);
- (*parent)->num_children = 0;
- } else
- (*parent)->children = (struct clock_info **)
- realloc((*parent)->children,
- sizeof(struct clock_info *) *
- ((*parent)->num_children + 2));
- if ((*parent)->num_children > 0)
- (*parent)->children[(*parent)->num_children - 1]->last_child
- = 0;
- clk->last_child = 1;
- (*parent)->children[(*parent)->num_children] = clk;
- (*parent)->children[(*parent)->num_children + 1] = NULL;
- (*parent)->num_children++;
+ struct tree *t = display_get_row_data(CLOCK);
+ struct clock_info *clk = t->private;
+
+ clk->expanded = !clk->expanded;
+
+ return 0;
}
-void dump_parent(struct clock_info *clk, int line)
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then print the result to the text based interface
+ * Return 0 on success, < 0 otherwise
+ */
+static int clock_display(bool refresh)
{
- char *unit = "Hz";
- double drate;
- static char spaces[64];
- char str[256];
- static int maxline;
-
- if (maxline < line)
- maxline = line;
-
- if (clk && clk->parent)
- dump_parent(clk->parent, ++line);
-
- drate = (double)clk->rate;
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- if (clk == clocks_info) {
- line++;
- strcpy(spaces, "");
- sprintf(str, "%s%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- spaces, clk->name, clk->flags, clk->usecount, drate,
- unit);
- } else {
- if (!(clk->parent == clocks_info))
- strcat(spaces, " ");
- sprintf(str, "%s`- %s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- spaces, clk->name, clk->flags, clk->usecount, drate,
- unit);
- }
- if (dump)
- //printf("line=%d:m%d:l%d %s", maxline - line + 2, maxline, line, str);
- printf("%s", str);
- else
- print_one_clock(maxline - line + 2, str, 1, 0);
+ if (refresh && read_clock_info(clock_tree))
+ return -1;
+
+ return clock_print_info(clock_tree);
}
-void dump_all_parents(char *clkarg)
+static int clock_find(const char *name)
{
- struct clock_info *clk;
- char spaces[1024];
+ struct tree **ptree = NULL;
+ int i, nr, line = 0, ret = 0;
- strcpy(spaces, "");
+ nr = tree_finds(clock_tree, name, &ptree);
- clk = find_clock(clocks_info, clkarg);
+ display_reset_cursor(CLOCK);
+
+ for (i = 0; i < nr; i++) {
+
+ ret = _clock_print_info_cb(ptree[i], &line);
+ if (ret)
+ break;
- if (!clk)
- printf("Clock NOT found!\n");
- else {
-// while(clk && clk != clocks_info) {
-// printf("%s\n", clk->name);
-// strcat(spaces, " ");
-// clk = clk->parent;
-// printf("%s <-- ", spaces);
-// }
-// printf(" /\n");
- dump_parent(clk, 1);
}
+
+ display_refresh_pad(CLOCK);
+
+ free(ptree);
+
+ return ret;
}
-struct clock_info *find_clock(struct clock_info *clk, char *clkarg)
+static int clock_selectf(void)
{
- int i;
- struct clock_info *ret = clk;
-
- if (!strcmp(clk->name, clkarg))
- return ret;
-
- if (clk->children) {
- for (i = 0; i < clk->num_children; i++) {
- if (!strcmp(clk->children[i]->name, clkarg))
- return clk->children[i];
- }
- for (i = 0; i < clk->num_children; i++) {
- ret = find_clock(clk->children[i], clkarg);
- if (ret)
- return ret;
- }
- }
+ struct tree *t = display_get_row_data(CLOCK);
+ int line = 0;
- return NULL;
-}
+ display_reset_cursor(CLOCK);
+
+ if (tree_for_each_parent(t, _clock_print_info_cb, &line))
+ return -1;
+ return display_refresh_pad(CLOCK);
+}
-void dump_clock_info(struct clock_info *clk, int level, int bmp)
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then dump to stdout a formatted result.
+ * @clk : a name for a specific clock we want to show
+ * Return 0 on success, < 0 otherwise
+ */
+int clock_dump(char *clk)
{
- int i, j;
+ int ret;
- if (!clk)
- return;
-
- for (i = 1, j = 0; i < level; i++, j = (i - 1)) {
- if (i == (level - 1)) {
- if (clk->last_child)
- printf("`-- ");
- else
- printf("|-- ");
- } else {
- if ((1<<j) & bmp)
- printf("| ");
- else
- printf(" ");
- }
- }
+ if (read_clock_info(clock_tree))
+ return -1;
- if (clk == clocks_info)
- printf("%s\n", clk->name);
- else {
- char *unit = "Hz";
- double drate = (double)clk->rate;
-
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- printf("%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- clk->name, clk->flags, clk->usecount, drate, unit);
- }
- if (clk->children) {
- int tbmp = bmp;
- int xbmp = -1;
-
- if (clk->last_child) {
- xbmp ^= 1 << (level - 2);
-
- xbmp = tbmp & xbmp;
- } else
- xbmp = bmp;
- for (i = 0; i < clk->num_children; i++) {
- tbmp = xbmp | (1 << level);
- dump_clock_info(clk->children[i], level + 1, tbmp);
- }
+ if (clk) {
+ printf("\nParents for \"%s\" Clock :\n\n", clk);
+ ret = dump_all_parents(clk);
+ printf("\n\n");
+ } else {
+ printf("\nClock Tree :\n");
+ printf("**********\n");
+ ret = dump_clock_info();
+ printf("\n\n");
}
+
+ return ret;
}
-char *debugfs_locate_mpoint(void)
+static struct display_ops clock_ops = {
+ .display = clock_display,
+ .select = clock_select,
+ .find = clock_find,
+ .selectf = clock_selectf,
+};
+
+/*
+ * Initialize the clock framework
+ */
+int clock_init(void)
{
- int ret;
- FILE *filep;
- char **path;
- char fsname[64];
- struct statfs sfs;
-
- path = likely_mpoints;
- while (*path) {
- ret = statfs(*path, &sfs);
- if (ret >= 0 && sfs.f_type == (long)DEBUGFS_MAGIC)
- return *path;
- path++;
- }
+ char clk_dir_path[MAX+1][PATH_MAX];
- filep = fopen("/proc/mounts", "r");
- if (filep == NULL) {
- fprintf(stderr, "powerdebug: Error opening /proc/mounts.");
- exit(1);
+ if (locate_debugfs(clk_dir_path[CCF]) || locate_debugfs(clk_dir_path[OCF]))
+ return -1;
+
+ sprintf(clk_dir_path[CCF], "%s/clk", clk_dir_path[CCF]);
+ sprintf(clk_dir_path[OCF], "%s/clock", clk_dir_path[OCF]);
+ if (!access(clk_dir_path[CCF], F_OK)) {
+ clock_fw = CCF;
+ strcpy(clk_dir_path[MAX],clk_dir_path[CCF]);
+ }
+ else if(!access(clk_dir_path[OCF], F_OK)) {
+ clock_fw = OCF;
+ strcpy(clk_dir_path[MAX],clk_dir_path[OCF]);
}
+ else
+ return -1;
- while (fscanf(filep, "%*s %s %s %*s %*d %*d\n",
- debugfs_mntpoint, fsname) == 2)
- if (!strcmp(fsname, "debugfs"))
- break;
- fclose(filep);
+ clock_tree = tree_load(clk_dir_path[MAX], NULL, false);
+ if (!clock_tree)
+ return -1;
- if (strcmp(fsname, "debugfs"))
- return NULL;
+ if (fill_clock_tree())
+ return -1;
- return debugfs_mntpoint;
+ return display_register(CLOCK, &clock_ops);
}
diff --git a/clocks.h b/clocks.h
index e2be430..aa94b3b 100644
--- a/clocks.h
+++ b/clocks.h
@@ -13,44 +13,5 @@
* - initial API and implementation
*******************************************************************************/
-#include <sys/stat.h>
-#include <sys/vfs.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <linux/magic.h>
-
-extern int maxy;
-extern int dump;
-
-#define MAX_LINES 120
-
-struct clock_info {
- char name[NAME_MAX];
- int flags;
- int rate;
- int usecount;
- int num_children;
- int last_child;
- int expanded;
- int level;
- struct clock_info *parent;
- struct clock_info **children;
-} *clocks_info;
-
-char debugfs_mntpoint[1024];
-char clock_lines[MAX_LINES][128];
-int clock_line_no;
-int old_clock_line_no;
-
-char *likely_mpoints[] = {
- "/sys/kernel/debug",
- "/debug",
- NULL
-};
-
-void add_clock_details_recur(struct clock_info *clk, int hrow, int selected);
-void destroy_clocks_info(void);
-void destroy_clocks_info_recur(struct clock_info *clock);
-void collapse_all_subclocks(struct clock_info *clock);
-void dump_all_parents(char *clkarg);
-struct clock_info *find_clock(struct clock_info *clk, char *clkarg);
+extern int clock_init(void);
+extern int clock_dump(char *clk);
diff --git a/display.c b/display.c
index d3ec421..f06387c 100644
--- a/display.c
+++ b/display.c
@@ -13,261 +13,590 @@
* - initial API and implementation
*******************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <ncurses.h>
+#include <sys/types.h>
+#include <regex.h>
#include "powerdebug.h"
+#include "mainloop.h"
#include "regulator.h"
#include "display.h"
-#define print(w, x, y, fmt, args...) do { mvwprintw(w, y, x, fmt, ##args); } while (0)
-#define NUM_FOOTER_ITEMS 5
+enum { PT_COLOR_DEFAULT = 1,
+ PT_COLOR_HEADER_BAR,
+ PT_COLOR_ERROR,
+ PT_COLOR_RED,
+ PT_COLOR_YELLOW,
+ PT_COLOR_GREEN,
+ PT_COLOR_BRIGHT,
+ PT_COLOR_BLUE,
+};
static WINDOW *header_win;
-static WINDOW *regulator_win;
-static WINDOW *clock_win;
-static WINDOW *sensor_win;
-static WINDOW *selected_win;
static WINDOW *footer_win;
+static WINDOW *main_win;
+static int current_win;
+
+/* Number of lines in the virtual window */
+static const int maxrows = 1024;
+
+struct rowdata {
+ int attr;
+ void *data;
+};
+
+struct windata {
+ WINDOW *pad;
+ struct display_ops *ops;
+ struct rowdata *rowdata;
+ char *name;
+ int nrdata;
+ int scrolling;
+ int cursor;
+};
+
+/* Warning this is linked with the enum { CLOCK, REGULATOR, ... } */
+struct windata windata[] = {
+ [CLOCK] = { .name = "Clocks" },
+ [REGULATOR] = { .name = "Regulators" },
+ [SENSOR] = { .name = "Sensors" },
+ [GPIO] = { .name = "Gpio" },
+};
+
+static void display_fini(void)
+{
+ endwin();
+}
+
+static int display_show_header(int win)
+{
+ int i;
+ int curr_pointer = 0;
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
-int maxx, maxy;
-char footer_items[NUM_FOOTER_ITEMS][64];
+ wattrset(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ wbkgd(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ werase(header_win);
+ mvwprintw(header_win, 0, curr_pointer, "PowerDebug %s", VERSION);
+ curr_pointer += 20;
-void fini_curses(void) {
- endwin();
+ for (i = 0; i < array_size; i++) {
+ if (win == i)
+ wattron(header_win, A_REVERSE);
+ else
+ wattroff(header_win, A_REVERSE);
+
+ mvwprintw(header_win, 0, curr_pointer, " %s ", windata[i].name);
+ curr_pointer += strlen(windata[i].name) + 2;
+ }
+ wrefresh(header_win);
+
+ return 0;
}
-/* "all" : Kill header and footer windows too ? */
-void killall_windows(int all)
+#define footer_label " Q (Quit) R (Refresh) Other Keys: 'Left', " \
+ "'Right' , 'Up', 'Down', 'enter', , 'Esc'"
+
+static int display_show_footer(int win, char *string)
{
- if (all && header_win) {
- delwin(header_win);
- header_win = NULL;
- }
- if (regulator_win) {
- delwin(regulator_win);
- regulator_win = NULL;
- }
- if (clock_win) {
- delwin(clock_win);
- clock_win = NULL;
+ werase(footer_win);
+ wattron(footer_win, A_REVERSE);
+ mvwprintw(footer_win, 0, 0, "%s", string ? string : footer_label);
+ wattroff(footer_win, A_REVERSE);
+ wrefresh(footer_win);
+
+ return 0;
+}
+
+static int display_refresh(int win, bool read)
+{
+ /* we are trying to refresh a window which is not showed */
+ if (win != current_win)
+ return 0;
+
+ if (windata[win].ops && windata[win].ops->display)
+ return windata[win].ops->display(read);
+
+ if (werase(main_win))
+ return -1;
+
+ return wrefresh(main_win);
+}
+
+int display_refresh_pad(int win)
+{
+ int maxx, maxy;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ return prefresh(windata[win].pad, windata[win].scrolling,
+ 0, 2, 0, maxy - 2, maxx);
+}
+
+static int display_show_unselection(int win, int line, bool bold)
+{
+ if (mvwchgat(windata[win].pad, line, 0, -1,
+ bold ? WA_BOLD: WA_NORMAL, 0, NULL) < 0)
+ return -1;
+
+ return display_refresh_pad(win);
+}
+
+void *display_get_row_data(int win)
+{
+ return windata[win].rowdata[windata[win].cursor].data;
+}
+
+static int display_select(void)
+{
+ if (windata[current_win].ops && windata[current_win].ops->select)
+ return windata[current_win].ops->select();
+
+ return 0;
+}
+
+static int display_next_panel(void)
+{
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win++;
+ current_win %= array_size;
+
+ return current_win;
+}
+
+static int display_prev_panel(void)
+{
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win--;
+ if (current_win < 0)
+ current_win = array_size - 1;
+
+ return current_win;
+}
+
+static int display_next_line(void)
+{
+ int maxx, maxy;
+ int cursor = windata[current_win].cursor;
+ int nrdata = windata[current_win].nrdata;
+ int scrolling = windata[current_win].scrolling;
+ struct rowdata *rowdata = windata[current_win].rowdata;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ if (cursor >= nrdata)
+ return cursor;
+
+ display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+ if (cursor < nrdata - 1) {
+ if (cursor >= (maxy - 4 + scrolling))
+ scrolling++;
+ cursor++;
}
- if (sensor_win) {
- delwin(sensor_win);
- sensor_win = NULL;
+
+ windata[current_win].scrolling = scrolling;
+ windata[current_win].cursor = cursor;
+
+ return cursor;
+}
+
+static int display_prev_line(void)
+{
+ int cursor = windata[current_win].cursor;
+ int nrdata = windata[current_win].nrdata;
+ int scrolling = windata[current_win].scrolling;
+ struct rowdata *rowdata = windata[current_win].rowdata;
+
+ if (cursor >= nrdata)
+ return cursor;
+
+ display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+ if (cursor > 0) {
+ if (cursor <= scrolling)
+ scrolling--;
+ cursor--;
}
- if (all && footer_win) {
- delwin(footer_win);
- footer_win = NULL;
+
+ windata[current_win].scrolling = scrolling;
+ windata[current_win].cursor = cursor;
+
+ return cursor;
+}
+
+static int display_set_row_data(int win, int line, void *data, int attr)
+{
+ struct rowdata *rowdata = windata[win].rowdata;
+
+ if (line >= windata[win].nrdata) {
+ rowdata = realloc(rowdata, sizeof(struct rowdata) * (line + 1));
+ if (!rowdata)
+ return -1;
+ windata[win].nrdata = line + 1;
}
+
+ rowdata[line].data = data;
+ rowdata[line].attr = attr;
+ windata[win].rowdata = rowdata;
+
+ return 0;
}
-void init_curses(void)
+int display_reset_cursor(int win)
{
- initscr();
- start_color();
- keypad(stdscr, TRUE);
- noecho();
- cbreak();
- curs_set(0);
- nonl();
- use_default_colors();
+ windata[win].nrdata = 0;
+ werase(windata[win].pad);
+ return wmove(windata[win].pad, 0, 0);
+}
+
+int display_print_line(int win, int line, char *str, int bold, void *data)
+{
+ int attr = 0;
+
+ if (bold)
+ attr |= WA_BOLD;
+
+ if (line == windata[win].cursor)
+ attr |= WA_STANDOUT;
- init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
- init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
- init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
- init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
- init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
- init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
+ if (display_set_row_data(win, line, data, attr))
+ return -1;
- atexit(fini_curses);
+ if (attr)
+ wattron(windata[win].pad, attr);
+
+ wprintw(windata[win].pad, "%s\n", str);
+
+ if (attr)
+ wattroff(windata[win].pad, attr);
+
+ return 0;
}
+static int display_find_keystroke(int fd, void *data);
-void create_windows(void)
+struct find_data {
+ size_t len;
+ char *string;
+ regex_t *reg;
+ int ocursor;
+ int oscrolling;
+};
+
+struct find_data *display_find_init(void)
{
+ const char *regexp = "^[a-z|0-9|_|-|.]";
+ struct find_data *findd;
+ const size_t len = 64;
+ regex_t *reg;
+ char *search4;
+ int maxx, maxy;
getmaxyx(stdscr, maxy, maxx);
- killall_windows(1);
- header_win = subwin(stdscr, 1, maxx, 0, 0);
- footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
+ reg = malloc(sizeof(*reg));
+ if (!reg)
+ return NULL;
- strcpy(footer_items[0], " Q (Quit) ");
- strcpy(footer_items[1], " R (Refresh) ");
+ if (regcomp(reg, regexp, REG_ICASE))
+ goto out_free_reg;
- if (selectedwindow == CLOCK)
- strcpy(footer_items[2], " Other Keys: 'Left', 'Right', 'Up', 'Down', 'enter', "
- " '/', 'Esc' ");
- else
- strcpy(footer_items[2], " Other Keys: 'Left', 'Right' ");
+ search4 = malloc(len);
+ if (!search4)
+ goto out_free_regcomp;
+ memset(search4, '\0', len);
- strcpy(footer_items[3], "");
+ findd = malloc(sizeof(*findd));
+ if (!findd)
+ goto out_free_search4;
- werase(stdscr);
- refresh();
+ findd->string = search4;
+ findd->reg = reg;
+ findd->len = len;
+ /* save the location of the cursor on the main window in order to
+ * browse the search result
+ */
+ findd->ocursor = windata[current_win].cursor;
+ findd->oscrolling = windata[current_win].scrolling;
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ curs_set(1);
+out:
+ return findd;
+
+out_free_search4:
+ free(search4);
+out_free_regcomp:
+ regfree(reg);
+out_free_reg:
+ free(reg);
+
+ goto out;
+}
+
+static void display_find_fini(struct find_data *findd)
+{
+ windata[current_win].cursor = findd->ocursor;
+ windata[current_win].scrolling = findd->oscrolling;
+ regfree(findd->reg);
+ free(findd->string);
+ free(findd);
+ curs_set(0);
}
-void create_selectedwindow(void)
+static int display_switch_to_find(int fd)
{
- WINDOW *win;
+ struct find_data *findd;
- killall_windows(0);
+ findd = display_find_init();
+ if (!findd)
+ return -1;
- getmaxyx(stdscr, maxy, maxx);
+ if (mainloop_del(fd))
+ return -1;
+
+ if (mainloop_add(fd, display_find_keystroke, findd))
+ return -1;
+
+ if (display_show_footer(current_win, "find (esc to exit)?"))
+ return -1;
+
+ return 0;
+}
+
+static int display_keystroke(int fd, void *data)
+{
+ int keystroke = getch();
+
+ switch (keystroke) {
+
+ case KEY_RIGHT:
+ case '\t':
+ display_show_header(display_next_panel());
+ break;
- win = subwin(stdscr, maxy - 2, maxx, 1, 0);
+ case KEY_LEFT:
+ case KEY_BTAB:
+ display_show_header(display_prev_panel());
+ break;
- switch (selectedwindow) {
- case REGULATOR: regulator_win = win;
+ case KEY_DOWN:
+ display_next_line();
break;
- case CLOCK: clock_win = win;
+ case KEY_UP:
+ display_prev_line();
break;
- case SENSOR: sensor_win = win;
+ case '\r':
+ display_select();
break;
+
+ case EOF:
+ case 'q':
+ case 'Q':
+ return 1;
+
+ case '/':
+ return display_switch_to_find(fd);
+
+ case 'r':
+ case 'R':
+ return display_refresh(current_win, true);
+ default:
+ return 0;
}
- selected_win = win;
+ display_refresh(current_win, false);
- refresh();
+ return 0;
}
-void show_header(void)
+static int display_switch_to_main(int fd)
{
- int i, j = 0;
- int curr_pointer = 0;
+ if (mainloop_del(fd))
+ return -1;
- wattrset(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- wbkgd(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- werase(header_win);
+ if (mainloop_add(fd, display_keystroke, NULL))
+ return -1;
- print(header_win, curr_pointer, 0, "PowerDebug %s", VERSION);
- curr_pointer += 20;
+ if (display_show_header(current_win))
+ return -1;
- for (i = 0; i < TOTAL_FEATURE_WINS; i++) {
- if (selectedwindow == i)
- wattron(header_win, A_REVERSE);
- else
- wattroff(header_win, A_REVERSE);
+ if (display_show_footer(current_win, NULL))
+ return -1;
- print(header_win, curr_pointer, 0, " %s ", win_names[i]);
- curr_pointer += strlen(win_names[i]) + 2;
- }
- wrefresh(header_win);
- werase(footer_win);
+ return display_refresh(current_win, false);
+}
+
+static int display_find_keystroke(int fd, void *data)
+{
+ struct find_data *findd = data;
+ regex_t *reg = findd->reg;
+ char *string = findd->string;
+ int keystroke = getch();
+ char match[2] = { [0] = (char)keystroke, [1] = '\0' };
+ regmatch_t m[1];
+
+ switch (keystroke) {
+
+ case '\e':
+ display_find_fini(findd);
+ return display_switch_to_main(fd);
+
+ case KEY_DOWN:
+ display_next_line();
+ break;
+
+ case KEY_UP:
+ display_prev_line();
+ break;
+
+ case KEY_BACKSPACE:
+ if (strlen(string))
+ string[strlen(string) - 1] = '\0';
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ break;
+
+ case '\r':
+ if (!windata[current_win].ops || !windata[current_win].ops->selectf)
+ return 0;
+
+ if (windata[current_win].ops->selectf())
+ return -1;
- for (i = 0; i < NUM_FOOTER_ITEMS; i++) {
- if (strlen(footer_items[i]) == 0)
- continue;
- wattron(footer_win, A_REVERSE);
- print(footer_win, j, 0, "%s", footer_items[i]);
- wattroff(footer_win, A_REVERSE);
- j+= strlen(footer_items[i])+1;
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ return 0;
+
+ default:
+
+ /* We don't want invalid characters for a name */
+ if (regexec(reg, match, 1, m, 0))
+ return 0;
+
+ if (strlen(string) < findd->len - 1)
+ string[strlen(string)] = (char)keystroke;
+
+ windata[current_win].cursor = 0;
+ windata[current_win].scrolling = 0;
+
+ break;
}
- wrefresh(footer_win);
-}
+ if (!windata[current_win].ops || !windata[current_win].ops->find)
+ return 0;
+
+ if (windata[current_win].ops->find(string))
+ return -1;
+
+ if (display_show_header(current_win))
+ return -1;
+
+ if (display_show_footer(current_win, strlen(string) ? string :
+ "find (esc to exit)?"))
+ return -1;
-void show_regulator_info(int verbose)
+ return 0;
+}
+
+int display_init(int wdefault)
{
- int i, count = 1;
-
- (void)verbose;
-
- werase(regulator_win);
- wattron(regulator_win, A_BOLD);
- print(regulator_win, 0, 0, "Name");
- print(regulator_win, 12, 0, "Status");
- print(regulator_win, 24, 0, "State");
- print(regulator_win, 36, 0, "Type");
- print(regulator_win, 48, 0, "Users");
- print(regulator_win, 60, 0, "Microvolts");
- print(regulator_win, 72, 0, "Min u-volts");
- print(regulator_win, 84, 0, "Max u-volts");
- wattroff(regulator_win, A_BOLD);
-
- for (i = 0; i < numregulators; i++) {
- int col = 0;
-
- if ((i + 2) > (maxy-2))
- break;
-
- if (regulators_info[i].num_users > 0)
- wattron(regulator_win, WA_BOLD);
- else
- wattroff(regulator_win, WA_BOLD);
-
- print(regulator_win, col, count, "%s",
- regulators_info[i].name);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].status);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].state);
- col += 12;
- print(regulator_win, col, count, "%s",
- regulators_info[i].type);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].num_users);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].microvolts);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].min_microvolts);
- col += 12;
- print(regulator_win, col, count, "%d",
- regulators_info[i].max_microvolts);
-
- count++;
+ int i, maxx, maxy;
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+ current_win = wdefault;
+
+ if (mainloop_add(0, display_keystroke, NULL))
+ return -1;
+
+ if (!initscr())
+ return -1;
+
+ start_color();
+ use_default_colors();
+
+ keypad(stdscr, TRUE);
+ noecho();
+ cbreak();
+ curs_set(0);
+ nonl();
+
+ if (init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED) ||
+ init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW) ||
+ init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN) ||
+ init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK) ||
+ init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE) ||
+ init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED))
+ return -1;
+
+ if (atexit(display_fini))
+ return -1;
+
+ getmaxyx(stdscr, maxy, maxx);
+
+ for (i = 0; i < array_size; i++) {
+
+ main_win = subwin(stdscr, maxy - 2, maxx, 1, 0);
+ if (!main_win)
+ return -1;
+
+ windata[i].pad = newpad(maxrows, maxx);
+ if (!windata[i].pad)
+ return -1;
+
}
- wrefresh(regulator_win);
-}
+ header_win = subwin(stdscr, 1, maxx, 0, 0);
+ if (!header_win)
+ return -1;
-void print_clock_header(void)
-{
- werase(clock_win);
- wattron(clock_win, A_BOLD);
- print(clock_win, 0, 0, "Name");
- print(clock_win, 54, 0, "Flags");
- print(clock_win, 64, 0, "Rate");
- print(clock_win, 72, 0, "Usecount");
- print(clock_win, 84, 0, "Children");
- wattroff(clock_win, A_BOLD);
- wrefresh(clock_win);
+ footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
+ if (!footer_win)
+ return -1;
+
+ if (display_show_header(wdefault))
+ return -1;
+
+ if (display_show_footer(wdefault, NULL))
+ return -1;
+
+ return display_refresh(wdefault, true);
}
-void print_sensor_header(void)
+int display_column_name(const char *line)
{
- werase(sensor_win);
- wattron(sensor_win, A_BOLD);
- print(sensor_win, 0, 0, "Name");
- print(sensor_win, 36, 0, "Temperature");
- wattroff(sensor_win, A_BOLD);
- wattron(sensor_win, A_BLINK);
- print(sensor_win, 0, 1, "Currently Sensor information available"
- " only in Dump mode!");
- wattroff(sensor_win, A_BLINK);
- wrefresh(sensor_win);
+ werase(main_win);
+ wattron(main_win, A_BOLD);
+ mvwprintw(main_win, 0, 0, "%s", line);
+ wattroff(main_win, A_BOLD);
+ wrefresh(main_win);
+
+ return 0;
}
-void print_one_clock(int line, char *str, int bold, int highlight)
+int display_register(int win, struct display_ops *ops)
{
- if (bold)
- wattron(clock_win, WA_BOLD);
- if (highlight)
- wattron(clock_win, WA_STANDOUT);
+ size_t array_size = sizeof(windata) / sizeof(windata[0]);
- print(clock_win, 0, line + 1, "%s", str);
- if (bold)
- wattroff(clock_win, WA_BOLD);
- if (highlight)
- wattroff(clock_win, WA_STANDOUT);
- wrefresh(clock_win);
+ if (win < 0 || win >= array_size)
+ return -1;
+
+ windata[win].ops = ops;
+
+ return 0;
}
diff --git a/display.h b/display.h
index f00a4f8..6362a48 100644
--- a/display.h
+++ b/display.h
@@ -13,15 +13,24 @@
* - initial API and implementation
*******************************************************************************/
-#define VALUE_MAX 16
+enum { CLOCK, REGULATOR, SENSOR, GPIO };
-WINDOW windows[TOTAL_FEATURE_WINS];
+struct display_ops {
+ int (*display)(bool refresh);
+ int (*select)(void);
+ int (*find)(const char *);
+ int (*selectf)(void);
+};
-#define PT_COLOR_DEFAULT 1
-#define PT_COLOR_HEADER_BAR 2
-#define PT_COLOR_ERROR 3
-#define PT_COLOR_RED 4
-#define PT_COLOR_YELLOW 5
-#define PT_COLOR_GREEN 6
-#define PT_COLOR_BRIGHT 7
-#define PT_COLOR_BLUE 8
+extern int display_print_line(int window, int line, char *str,
+ int bold, void *data);
+
+extern int display_refresh_pad(int window);
+extern int display_reset_cursor(int window);
+extern void *display_get_row_data(int window);
+
+extern int display_init(int wdefault);
+extern int display_register(int win, struct display_ops *ops);
+extern int display_column_name(const char *line);
+
+#define NAME_MAX 255
diff --git a/doc.txt b/doc.txt
new file mode 100644
index 0000000..36ffc46
--- /dev/null
+++ b/doc.txt
@@ -0,0 +1,20 @@
+Regulator related information
+=============================
+Regulator fields "state" and "status" give below information about the regulator.
+
+- state: field tell whether regulator is enabled or disabled. Following are the states
+ | - Enabled
+ | - Disabled
+ | - Unknown (if unable to determine)
+ |
+ |
+ ----> status: When enabled, depending on the regulator hardware capability(modes) and runtime requirement; regulators are set to specific modes. The status field gives a little
+ more specific information about the current "state" of the regulator, which operating modes it is in. Following can be the possible status:
+ - Idle
+ - Fast
+ - Normal
+ - Standby
+ - Bypass
+ - Error
+ - Undefined
+ - On/Off
diff --git a/gpio.c b/gpio.c
new file mode 100644
index 0000000..f7d2a10
--- /dev/null
+++ b/gpio.c
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - initial API and implementation
+ *******************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <mntent.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "powerdebug.h"
+#include "display.h"
+#include "tree.h"
+#include "utils.h"
+
+#define SYSFS_GPIO "/sys/class/gpio"
+
+struct gpio_info {
+ bool expanded;
+ int active_low;
+ int value;
+ int direction;
+ int edge;
+ char *prefix;
+} *gpios_info;
+
+static struct tree *gpio_tree = NULL;
+
+static struct gpio_info *gpio_alloc(void)
+{
+ struct gpio_info *gi;
+
+ gi = malloc(sizeof(*gi));
+ if (gi) {
+ memset(gi, -1, sizeof(*gi));
+ gi->prefix = NULL;
+ }
+
+ return gi;
+}
+
+static int gpio_filter_cb(const char *name)
+{
+ /* let's ignore some directories in order to avoid to be
+ * pulled inside the sysfs circular symlinks mess/hell
+ * (choose the word which fit better)
+ */
+ if (!strcmp(name, "device"))
+ return 1;
+
+ if (!strcmp(name, "subsystem"))
+ return 1;
+
+ if (!strcmp(name, "driver"))
+ return 1;
+
+ /* we want to ignore the gpio chips */
+ if (strstr(name, "chip"))
+ return 1;
+
+ /* we are not interested by the power value */
+ if (!strcmp(name, "power"))
+ return 1;
+
+ return 0;
+}
+
+static inline int read_gpio_cb(struct tree *t, void *data)
+{
+ struct gpio_info *gpio = t->private;
+
+ file_read_value(t->path, "active_low", "%d", &gpio->active_low);
+ file_read_value(t->path, "value", "%d", &gpio->value);
+ file_read_value(t->path, "edge", "%d", &gpio->edge);
+ file_read_value(t->path, "direction", "%d", &gpio->direction);
+
+ return 0;
+}
+
+static int read_gpio_info(struct tree *tree)
+{
+ return tree_for_each(tree, read_gpio_cb, NULL);
+}
+
+static int fill_gpio_cb(struct tree *t, void *data)
+{
+ struct gpio_info *gpio;
+
+ gpio = gpio_alloc();
+ if (!gpio)
+ return -1;
+ t->private = gpio;
+
+ /* we skip the root node but we set it expanded for its children */
+ if (!t->parent) {
+ gpio->expanded = true;
+ return 0;
+ }
+
+ return read_gpio_cb(t, data);
+
+}
+
+static int fill_gpio_tree(void)
+{
+ return tree_for_each(gpio_tree, fill_gpio_cb, NULL);
+}
+
+static int dump_gpio_cb(struct tree *t, void *data)
+{
+ struct gpio_info *gpio = t->private;
+ struct gpio_info *pgpio;
+
+ if (!t->parent) {
+ printf("/\n");
+ gpio->prefix = "";
+ return 0;
+ }
+
+ pgpio = t->parent->private;
+
+ if (!gpio->prefix)
+ if (asprintf(&gpio->prefix, "%s%s%s", pgpio->prefix,
+ t->depth > 1 ? " ": "", t->next ? "|" : " ") < 0)
+ return -1;
+
+ printf("%s%s-- %s (", gpio->prefix, !t->next ? "`" : "", t->name);
+
+ if (gpio->active_low != -1)
+ printf(" active_low:%d", gpio->active_low);
+
+ if (gpio->value != -1)
+ printf(", value:%d", gpio->value);
+
+ if (gpio->edge != -1)
+ printf(", edge:%d", gpio->edge);
+
+ if (gpio->direction != -1)
+ printf(", direction:%d", gpio->direction);
+
+ printf(" )\n");
+
+ return 0;
+}
+
+int dump_gpio_info(void)
+{
+ return tree_for_each(gpio_tree, dump_gpio_cb, NULL);
+}
+
+int gpio_dump(void)
+{
+ int ret;
+
+ printf("\nGpio Tree :\n");
+ printf("***********\n");
+ ret = dump_gpio_info();
+ printf("\n\n");
+
+ return ret;
+}
+
+static char *gpio_line(struct tree *t)
+{
+ struct gpio_info *gpio = t->private;
+ char *gpioline;
+
+ if (asprintf(&gpioline, "%-20s %-10d %-10d %-10d %-10d", t-> name,
+ gpio->value, gpio->active_low, gpio->edge, gpio->direction) < 0)
+ return NULL;
+
+ return gpioline;
+}
+
+static int _gpio_print_info_cb(struct tree *t, void *data)
+{
+ int *line = data;
+ char *buffer;
+
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ buffer = gpio_line(t);
+ if (!buffer)
+ return -1;
+
+ display_print_line(GPIO, *line, buffer, 0, t);
+
+ (*line)++;
+
+ free(buffer);
+
+ return 0;
+}
+
+static int gpio_print_info_cb(struct tree *t, void *data)
+{
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ return _gpio_print_info_cb(t, data);
+}
+
+static int gpio_print_header(void)
+{
+ char *buf;
+ int ret;
+
+ if (asprintf(&buf, "%-20s %-10s %-10s %-10s %-10s",
+ "Name", "Value", "Active_low", "Edge", "Direction") < 0)
+ return -1;
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
+}
+
+static int gpio_print_info(struct tree *tree)
+{
+ int ret, line = 0;
+
+ display_reset_cursor(GPIO);
+
+ gpio_print_header();
+
+ ret = tree_for_each(tree, gpio_print_info_cb, &line);
+
+ display_refresh_pad(GPIO);
+
+ return ret;
+}
+
+static int gpio_display(bool refresh)
+{
+ if (refresh && read_gpio_info(gpio_tree))
+ return -1;
+
+ return gpio_print_info(gpio_tree);
+}
+
+static struct display_ops gpio_ops = {
+ .display = gpio_display,
+};
+
+/*
+ * Initialize the gpio framework
+ */
+int gpio_init(void)
+{
+ gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false);
+ if (!gpio_tree)
+ return -1;
+
+ if (fill_gpio_tree())
+ return -1;
+
+ return display_register(GPIO, &gpio_ops);
+}
diff --git a/gpio.h b/gpio.h
new file mode 100644
index 0000000..38f035f
--- /dev/null
+++ b/gpio.h
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - initial API and implementation
+ *******************************************************************************/
+
+extern int gpio_init(void);
+extern int gpio_dump(void);
diff --git a/mainloop.c b/mainloop.c
new file mode 100644
index 0000000..02dda98
--- /dev/null
+++ b/mainloop.c
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ * Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include "mainloop.h"
+
+static int epfd = -1;
+static unsigned short nrhandler;
+
+struct mainloop_data {
+ mainloop_callback_t cb;
+ void *data;
+ int fd;
+};
+
+struct mainloop_data **mds;
+
+#define MAX_EVENTS 10
+
+int mainloop(unsigned int timeout)
+{
+ int i, nfds;
+ struct epoll_event events[MAX_EVENTS];
+ struct mainloop_data *md;
+
+ if (epfd < 0)
+ return -1;
+
+ for (;;) {
+
+ nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
+ if (nfds < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ md = events[i].data.ptr;
+
+ if (md->cb(md->fd, md->data) > 0)
+ return 0;
+ }
+
+ }
+}
+
+int mainloop_add(int fd, mainloop_callback_t cb, void *data)
+{
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ };
+
+ struct mainloop_data *md;
+
+ if (fd >= nrhandler) {
+ mds = realloc(mds, sizeof(*mds) * (fd + 1));
+ if (!mds)
+ return -1;
+ nrhandler = fd + 1;
+ }
+
+ md = malloc(sizeof(*md));
+ if (!md)
+ return -1;
+
+ md->data = data;
+ md->cb = cb;
+ md->fd = fd;
+
+ mds[fd] = md;
+ ev.data.ptr = md;
+
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+ free(md);
+ return -1;
+ }
+
+ return 0;
+}
+
+int mainloop_del(int fd)
+{
+ if (fd >= nrhandler)
+ return -1;
+
+ if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
+ return -1;
+
+ free(mds[fd]);
+
+ return 0;
+}
+
+int mainloop_init(void)
+{
+ epfd = epoll_create(2);
+ if (epfd < 0)
+ return -1;
+
+ return 0;
+}
+
+void mainloop_fini(void)
+{
+ close(epfd);
+}
diff --git a/mainloop.h b/mainloop.h
new file mode 100644
index 0000000..cf03bbb
--- /dev/null
+++ b/mainloop.h
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ * Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+typedef int (*mainloop_callback_t)(int fd, void *data);
+
+extern int mainloop(unsigned int timeout);
+extern int mainloop_add(int fd, mainloop_callback_t cb, void *data);
+extern int mainloop_del(int fd);
+extern int mainloop_init(void);
+extern void mainloop_fini(void);
diff --git a/powerdebug.c b/powerdebug.c
index 3f4d60c..073fd42 100644
--- a/powerdebug.c
+++ b/powerdebug.c
@@ -14,19 +14,20 @@
*******************************************************************************/
#include <getopt.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ncurses.h>
+#include "regulator.h"
+#include "display.h"
+#include "clocks.h"
+#include "sensor.h"
+#include "gpio.h"
+#include "mainloop.h"
#include "powerdebug.h"
-int dump;
-int highlighted_row;
-int selectedwindow = -1;
-double ticktime = 10.0; /* in seconds */
-
-char *win_names[TOTAL_FEATURE_WINS] = {
- "Clocks",
- "Regulators",
- "Sensors"
-};
-
void usage(void)
{
printf("Usage: powerdebug [OPTIONS]\n");
@@ -45,273 +46,224 @@ void usage(void)
" -s)\n");
printf(" -V, --version Show Version\n");
printf(" -h, --help Help\n");
-
- exit(0);
}
void version()
{
printf("powerdebug version %s\n", VERSION);
- exit(0);
}
-int main(int argc, char **argv)
+/*
+ * Options:
+ * -r, --regulator : regulators
+ * -s, --sensor : sensors
+ * -c, --clock : clocks
+ * -g, --gpio : gpios
+ * -p, --findparents : clockname whose parents have to be found
+ * -t, --time : ticktime
+ * -d, --dump : dump
+ * -v, --verbose : verbose
+ * -V, --version : version
+ * -h, --help : help
+ * no option / default : show usage!
+ */
+
+static struct option long_options[] = {
+ { "regulator", 0, 0, 'r' },
+ { "sensor", 0, 0, 's' },
+ { "clock", 0, 0, 'c' },
+ { "gpio", 0, 0, 'g' },
+ { "findparents", 1, 0, 'p' },
+ { "time", 1, 0, 't' },
+ { "dump", 0, 0, 'd' },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+struct powerdebug_options {
+ bool verbose;
+ bool regulators;
+ bool sensors;
+ bool clocks;
+ bool gpios;
+ bool dump;
+ unsigned int ticktime;
+ int selectedwindow;
+ char *clkname;
+};
+
+int getoptions(int argc, char *argv[], struct powerdebug_options *options)
{
- int c, i;
- int firsttime[TOTAL_FEATURE_WINS];
- int enter_hit = 0, verbose = 0, findparent_ncurses = 0, refreshwin = 0;
- int regulators = 0, sensors = 0, clocks = 0, findparent = 0;
- char clkarg[64], clkname_str[64];
-
- for (i = 0; i < TOTAL_FEATURE_WINS; i++)
- firsttime[i] = 1;
-
- /*
- * Options:
- * -r, --regulator : regulator
- * -s, --sensor : sensors
- * -c, --clock : clocks
- * -p, --findparents : clockname whose parents have to be found
- * -t, --time : ticktime
- * -d, --dump : dump
- * -v, --verbose : verbose
- * -V, --version : version
- * -h, --help : help
- * no option / default : show usage!
- */
+ int c;
+
+ memset(options, 0, sizeof(*options));
+ options->ticktime = 10;
+ options->selectedwindow = -1;
while (1) {
int optindex = 0;
- static struct option long_options[] = {
- {"regulator", 0, 0, 'r'},
- {"sensor", 0, 0, 's'},
- {"clock", 0, 0, 'c'},
- {"findparents", 1, 0, 'p'},
- {"time", 1, 0, 't'},
- {"dump", 0, 0, 'd'},
- {"verbose", 0, 0, 'v'},
- {"version", 0, 0, 'V'},
- {"help", 0, 0, 'h'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "rscp:t:dvVh", long_options, &optindex);
+
+ c = getopt_long(argc, argv, "rscgp:t:dvVh",
+ long_options, &optindex);
if (c == -1)
break;
switch (c) {
case 'r':
- regulators = 1;
- selectedwindow = REGULATOR;
+ options->regulators = true;
+ options->selectedwindow = REGULATOR;
break;
case 's':
- sensors = 1;
- selectedwindow = SENSOR;
+ options->sensors = true;
+ options->selectedwindow = SENSOR;
break;
case 'c':
- clocks = 1;
- selectedwindow = CLOCK;
+ options->clocks = true;
+ options->selectedwindow = CLOCK;
+ break;
+ case 'g':
+ options->gpios = true;
+ options->selectedwindow = GPIO;
break;
case 'p':
- findparent = 1;
- strcpy(clkarg, optarg);
+ options->clkname = strdup(optarg);
+ if (!options->clkname) {
+ fprintf(stderr, "failed to allocate memory");
+ return -1;
+ }
+ options->dump = true; /* Assume -dc in case of -p */
+ options->clocks = true;
break;
case 't':
- ticktime = strtod(optarg, NULL);
+ options->ticktime = atoi(optarg);
break;
case 'd':
- dump = 1;
+ options->dump = true;
break;
case 'v':
- verbose = 1;
+ options->verbose = true;
break;
case 'V':
version();
break;
- case 'h':
- usage();
- break;
case '?':
- fprintf (stderr, "%s: Unknown option %c'.\n",
+ fprintf(stderr, "%s: Unknown option %c'.\n",
argv[0], optopt);
- exit(1);
default:
- usage();
- break;
+ return -1;
}
}
- if (dump && !(regulators || clocks || sensors)) {
- //fprintf(stderr, "Dump mode (-d) supported only with -c, -r "
- // "or -s ..\n");
- //usage();
- // By Default lets show everything we have!
- regulators = clocks = sensors = 1;
- }
+ /* No system specified to be dump, let's default to all */
+ if (!options->regulators && !options->clocks &&
+ !options->sensors && !options->gpios)
+ options->regulators = options->clocks =
+ options->sensors = options->gpios = true;
- if (findparent && (!clocks || !dump)) {
- fprintf(stderr, "-p option passed without -c and -d."
- " Exiting...\n");
- usage();
- }
+ if (options->selectedwindow == -1)
+ options->selectedwindow = CLOCK;
- if (!dump && selectedwindow == -1)
- selectedwindow = CLOCK;
+ return 0;
+}
- init_regulator_ds();
+static int powerdebug_dump(struct powerdebug_options *options)
+{
+ if (options->regulators)
+ regulator_dump();
- while (1) {
- int key = 0;
- struct timeval tval;
- fd_set readfds;
-
- if (!dump) {
- if (firsttime[0])
- init_curses();
- create_windows();
- show_header();
- }
+ if (options->clocks)
+ clock_dump(options->clkname);
- if (regulators || selectedwindow == REGULATOR) {
- read_regulator_info();
- if (!dump) {
- create_selectedwindow();
- show_regulator_info(verbose);
- }
- else
- print_regulator_info(verbose);
- }
+ if (options->sensors)
+ sensor_dump();
- if (clocks || selectedwindow == CLOCK) {
- int ret = 0;
- if (firsttime[CLOCK]) {
- ret = init_clock_details();
- if (!ret)
- firsttime[CLOCK] = 0;
- strcpy(clkname_str, "");
- }
- if (!ret && !dump) {
- int hrow;
-
- create_selectedwindow();
- if (!findparent_ncurses) {
- int command = 0;
-
- if (enter_hit)
- command = CLOCK_SELECTED;
- if (refreshwin)
- command = REFRESH_WINDOW;
- hrow = read_and_print_clock_info(
- verbose,
- highlighted_row,
- command);
- highlighted_row = hrow;
- enter_hit = 0;
- } else
- find_parents_for_clock(clkname_str,
- enter_hit);
- }
- if (!ret && dump) {
- if (findparent)
- read_and_dump_clock_info_one(clkarg);
- else
- read_and_dump_clock_info(verbose);
- }
- }
+ if (options->gpios)
+ gpio_dump();
- if (sensors || selectedwindow == SENSOR) {
- if (!dump) {
- create_selectedwindow();
- print_sensor_header();
- } else
- read_and_print_sensor_info(verbose);
- }
+ return 0;
+}
- if (dump)
- break;
+static int powerdebug_display(struct powerdebug_options *options)
+{
+ if (display_init(options->selectedwindow)) {
+ printf("failed to initialize display\n");
+ return -1;
+ }
- FD_ZERO(&readfds);
- FD_SET(0, &readfds);
- tval.tv_sec = ticktime;
- tval.tv_usec = (ticktime - tval.tv_sec) * 1000000;
-
- key = select(1, &readfds, NULL, NULL, &tval);
-
- if (key) {
- char keychar;
- int keystroke = getch();
- int oldselectedwin = selectedwindow;
-
- if (keystroke == EOF)
- exit(0);
-
- if (keystroke == KEY_RIGHT || keystroke == 9)
- selectedwindow++;
-
- if (keystroke == KEY_LEFT || keystroke == 353)
- selectedwindow--;
-
- if (selectedwindow >= TOTAL_FEATURE_WINS)
- selectedwindow = 0;
-
- if (selectedwindow < 0)
- selectedwindow = TOTAL_FEATURE_WINS - 1;
-
- if (selectedwindow == CLOCK) {
- if (keystroke == KEY_DOWN)
- highlighted_row++;
- if (keystroke == KEY_UP && highlighted_row > 0)
- highlighted_row--;
- if (keystroke == 47)
- findparent_ncurses = 1;
-
- if ((keystroke == 27 || oldselectedwin !=
- selectedwindow) && findparent_ncurses) {
- findparent_ncurses = 0;
- clkname_str[0] = '\0';
- }
-
- if (findparent_ncurses && keystroke != 13) {
- int len = strlen(clkname_str);
- char str[2];
-
- if (keystroke == 263) {
- if (len > 0)
- len--;
-
- clkname_str[len] = '\0';
- } else {
- if (strlen(clkname_str) ||
- keystroke != '/') {
- str[0] = keystroke;
- str[1] = '\0';
- if (len < 63)
- strcat(clkname_str,
- str);
- }
- }
- }
- }
+ if (mainloop(options->ticktime * 1000))
+ return -1;
+
+ return 0;
+}
+
+static struct powerdebug_options *powerdebug_init(void)
+{
+ struct powerdebug_options *options;
+
+ options = malloc(sizeof(*options));
+ if (!options)
+ return NULL;
- keychar = toupper(keystroke);
-//#define DEBUG
-#ifdef DEBUG
- killall_windows(1); fini_curses();
- printf("key entered %d:%c\n", keystroke, keychar);
- exit(1);
+ memset(options, 0, sizeof(*options));
+
+ return options;
+}
+
+int main(int argc, char **argv)
+{
+ struct powerdebug_options *options;
+ int ret;
+
+#ifdef __ANDROID__
+ if (setenv("TERM", "xterm", 1) < 0) {
+ fprintf(stderr, "setenv failure");
+ return 1;
+ }
+ if (setenv("TERMINFO", "/system/etc/terminfo", 1) < 0) {
+ fprintf(stderr, "setenv failure");
+ return 1;
+ }
#endif
+ options = powerdebug_init();
+ if (!options) {
+ fprintf(stderr, "not enough memory to allocate options\n");
+ return 1;
+ }
+
+ if (getoptions(argc, argv, options)) {
+ usage();
+ return 1;
+ }
- if (keystroke == 13)
- enter_hit = 1;
+ if (mainloop_init()) {
+ fprintf(stderr, "failed to initialize the mainloop\n");
+ return 1;
+ }
- if (keychar == 'Q' && !findparent_ncurses)
- exit(0);
- if (keychar == 'R') {
- refreshwin = 1;
- ticktime = 3;
- } else
- refreshwin = 0;
- }
+ if (regulator_init()) {
+ printf("not enough memory to allocate regulators info\n");
+ options->regulators = false;
}
- exit(0);
+
+ if (clock_init()) {
+ printf("failed to initialize clock details (check debugfs)\n");
+ options->clocks = false;
+ }
+
+ if (sensor_init()) {
+ printf("failed to initialize sensors\n");
+ options->sensors = false;
+ }
+
+ if (gpio_init()) {
+ printf("failed to initialize gpios\n");
+ options->gpios = false;
+ }
+
+ ret = options->dump ? powerdebug_dump(options) :
+ powerdebug_display(options);
+
+ return ret < 0;
}
diff --git a/powerdebug.h b/powerdebug.h
index f7fdc21..e2c1699 100644
--- a/powerdebug.h
+++ b/powerdebug.h
@@ -13,61 +13,4 @@
* - initial API and implementation
*******************************************************************************/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <getopt.h>
-#include <errno.h>
-#include <ncurses.h>
-
-#define VERSION "0.4"
-
-#define TOTAL_FEATURE_WINS 3 /* Regulator, Clock and Sensor (for now) */
-enum {CLOCK, REGULATOR, SENSOR};
-enum {CLOCK_SELECTED = 1, REFRESH_WINDOW};
-
-extern struct regulator_info *regulators_info;
-
-extern char *win_names[TOTAL_FEATURE_WINS];
-extern int selectedwindow;
-
-extern int numregulators;
-extern int dump;
-extern double ticktime;
-
-extern void version(void);
-
-extern void print_regulator_info(int verbose);
-extern void init_regulator_ds(void);
-extern void read_regulator_info(void);
-extern void print_regulator_info(int verbose);
-
-extern void read_and_dump_clock_info(int verbose);
-extern void read_and_dump_clock_info_one(char *clk);
-extern void read_clock_info(char *clkpath);
-extern struct clock_info *read_clock_info_recur(char *clkpath, int level,
- struct clock_info *parent);
-extern void dump_clock_info(struct clock_info *clk, int level, int bmp);
-extern void insert_children(struct clock_info **parent, struct clock_info *clk);
-extern void find_parents_for_clock(char *clkname, int complete);
-extern int read_and_print_clock_info(int verbose, int hrow, int selected);
-extern void print_clock_info(int verbose, int hrow, int selected);
-extern void print_string_val(char *name, char *val);
-extern int init_clock_details(void);
-extern void print_clock_header(void);
-extern void print_one_clock(int line, char *str, int bold, int highlight);
-extern char *debugfs_locate_mpoint(void);
-
-extern void get_sensor_info(char *path, char *name, char *sensor, int verbose);
-extern int read_and_print_sensor_info(int verbose);
-extern void print_sensor_header(void);
-
-extern void init_curses(void);
-extern void fini_curses(void);
-extern void killall_windows(int all);
-extern void show_header(void);
-extern void create_windows(void);
-extern void create_selectedwindow(void);
-extern void show_regulator_info(int verbose);
+#define VERSION "0.6.2"
diff --git a/regulator.c b/regulator.c
index 18c9777..0da924a 100644
--- a/regulator.c
+++ b/regulator.c
@@ -11,191 +11,241 @@
* Contributors:
* Amit Arora <amit.arora@linaro.org> (IBM Corporation)
* - initial API and implementation
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - rewrote code and API based on the tree
*******************************************************************************/
#include "regulator.h"
-int init_regulator_ds(void)
+#define SYSFS_REGULATOR "/sys/class/regulator"
+#define VALUE_MAX 16
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <sys/types.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include "display.h"
+#include "powerdebug.h"
+#include "tree.h"
+#include "utils.h"
+
+struct regulator_info {
+ char name[NAME_MAX];
+ char state[VALUE_MAX];
+ char status[VALUE_MAX];
+ char type[VALUE_MAX];
+ char opmode[VALUE_MAX];
+ int microvolts;
+ int min_microvolts;
+ int max_microvolts;
+ int microamps;
+ int min_microamps;
+ int max_microamps;
+ int requested_microamps;
+ int num_users;
+};
+
+struct regulator_data {
+ const char *name;
+ const char *ifmt;
+ const char *ofmt;
+ bool derefme;
+};
+
+static struct regulator_data regdata[] = {
+ { "name", "%s", "\tname: %s\n" },
+ { "status", "%s", "\tstatus: %s\n" },
+ { "state", "%s", "\tstate: %s\n" },
+ { "type", "%s", "\ttype: %s\n" },
+ { "num_users", "%d", "\tnum_users: %d\n", true },
+ { "microvolts", "%d", "\tmicrovolts: %d\n", true },
+ { "max_microvolts", "%d", "\tmax_microvolts: %d\n", true },
+ { "min_microvolts", "%d", "\tmin_microvolts: %d\n", true },
+};
+
+static struct tree *reg_tree;
+
+static struct regulator_info *regulator_alloc(void)
{
- DIR *regdir;
- struct dirent *item;
-
- regdir = opendir("/sys/class/regulator");
- if (!regdir)
- return(1);
- while ((item = readdir(regdir))) {
- if (strncmp(item->d_name, "regulator", 9))
+ struct regulator_info *regi;
+
+ regi = malloc(sizeof(*regi));
+ if (regi)
+ memset(regi, 0, sizeof(*regi));
+
+ return regi;
+}
+
+static int regulator_dump_cb(struct tree *tree, void *data)
+{
+ int i;
+ char buffer[NAME_MAX];
+ size_t nregdata = sizeof(regdata) / sizeof(regdata[0]);
+
+ if (!strncmp("regulator.", tree->name, strlen("regulator.")))
+ printf("\n%s:\n", tree->name);
+
+ for (i = 0; i < nregdata; i++) {
+ int val;
+
+ if (file_read_value(tree->path, regdata[i].name,
+ regdata[i].ifmt, buffer))
continue;
- numregulators++;
- }
- closedir(regdir);
-
- regulators_info = (struct regulator_info *)malloc(numregulators*
- sizeof(struct regulator_info));
- if (!regulators_info) {
- fprintf(stderr, "init_regulator_ds: Not enough memory to "
- "read information for %d regulators!\n", numregulators);
- return(1);
+ if (regdata[i].derefme) {
+ val = atoi(buffer);
+ printf(regdata[i].ofmt, val);
+ } else
+ printf(regdata[i].ofmt, buffer);
}
- return(0);
+ return 0;
}
-void print_string_val(char *name, char *val)
+int regulator_dump(void)
{
- printf("\t%s=%s", name, val);
- if (!strchr(val, '\n'))
- printf("\n");
+ printf("\nRegulator Information:\n");
+ printf("*********************\n\n");
+
+ return tree_for_each(reg_tree, regulator_dump_cb, NULL);
}
-void print_regulator_info(int verbose)
+static int regulator_display_cb(struct tree *t, void *data)
{
- int i;
+ struct regulator_info *reg = t->private;
+ int *line = data;
+ char *buf;
- printf("\nRegulator Information:\n");
- printf("*********************\n\n");
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
- for (i = 0; i < numregulators; i++) {
- printf("Regulator %d:\n", i + 1);
- print_string_val("name", regulators_info[i].name);
- if (strcmp(regulators_info[i].status, ""))
- print_string_val("status", regulators_info[i].status);
- if (strcmp(regulators_info[i].state, ""))
- print_string_val("state", regulators_info[i].state);
+ if (!strlen(reg->name))
+ return 0;
- if (!verbose)
- continue;
+ if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11d %-11d %-11d %-12d",
+ reg->name, reg->status, reg->state, reg->type,
+ reg->num_users, reg->microvolts, reg->min_microvolts,
+ reg->max_microvolts) < 0)
+ return -1;
- if (strcmp(regulators_info[i].type, ""))
- print_string_val("type", regulators_info[i].type);
- if (strcmp(regulators_info[i].opmode, ""))
- print_string_val("opmode", regulators_info[i].opmode);
-
- if (regulators_info[i].microvolts)
- printf("\tmicrovolts=%d\n",
- regulators_info[i].microvolts);
- if (regulators_info[i].min_microvolts)
- printf("\tmin_microvolts=%d\n",
- regulators_info[i].min_microvolts);
- if (regulators_info[i].max_microvolts)
- printf("\tmax_microvolts=%d\n",
- regulators_info[i].max_microvolts);
-
- if (regulators_info[i].microamps)
- printf("\tmicroamps=%d\n",
- regulators_info[i].microamps);
- if (regulators_info[i].min_microamps)
- printf("\tmin_microamps=%d\n",
- regulators_info[i].min_microamps);
- if (regulators_info[i].max_microamps)
- printf("\tmax_microamps=%d\n",
- regulators_info[i].max_microamps);
- if (regulators_info[i].requested_microamps)
- printf("\trequested_microamps=%d\n",
- regulators_info[i].requested_microamps);
-
- if (regulators_info[i].num_users)
- printf("\tnum_users=%d\n",
- regulators_info[i].num_users);
- printf("\n");
- }
+ display_print_line(REGULATOR, *line, buf, reg->num_users, t);
- if (!numregulators && verbose) {
- printf("Could not find regulator information!");
- printf(" Looks like /sys/class/regulator is empty.\n\n");
- }
+ (*line)++;
+
+ free(buf);
- printf("\n\n");
+ return 0;
}
-void read_info_from_dirent(struct dirent *ritem, char *str, int idx)
+static int regulator_print_header(void)
{
- if (!strcmp(ritem->d_name, "name"))
- strcpy(regulators_info[idx].name, str);
- if (!strcmp(ritem->d_name, "state"))
- strcpy(regulators_info[idx].state, str);
- if (!strcmp(ritem->d_name, "status"))
- strcpy(regulators_info[idx].status, str);
-
- if (!strcmp(ritem->d_name, "type"))
- strcpy(regulators_info[idx].type, str);
- if (!strcmp(ritem->d_name, "opmode"))
- strcpy(regulators_info[idx].opmode, str);
-
- if (!strcmp(ritem->d_name, "microvolts"))
- regulators_info[idx].microvolts = atoi(str);
- if (!strcmp(ritem->d_name, "min_microvolts"))
- regulators_info[idx].min_microvolts = atoi(str);
- if (!strcmp(ritem->d_name, "max_microvolts"))
- regulators_info[idx].max_microvolts = atoi(str);
-
- if (!strcmp(ritem->d_name, "microamps"))
- regulators_info[idx].microamps = atoi(str);
- if (!strcmp(ritem->d_name, "min_microamps"))
- regulators_info[idx].min_microamps = atoi(str);
- if (!strcmp(ritem->d_name, "max_microamps"))
- regulators_info[idx].max_microamps = atoi(str);
- if (!strcmp(ritem->d_name, "requested_microamps"))
- regulators_info[idx].requested_microamps = atoi(str);
-
- if (!strcmp(ritem->d_name, "num_users"))
- regulators_info[idx].num_users = atoi(str);
+ char *buf;
+ int ret;
+
+ if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11s %-11s %-11s %-12s",
+ "Name", "Status", "State", "Type", "Users", "Microvolts",
+ "Min u-volts", "Max u-volts") < 0)
+ return -1;
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
+
}
-int read_regulator_info(void)
+static int regulator_display(bool refresh)
{
- FILE *file = NULL;
- DIR *regdir, *dir;
- int len, count = 0, ret = 0;
- char line[1024], filename[1024], *fptr;
- struct dirent *item, *ritem;
-
- regdir = opendir("/sys/class/regulator");
- if (!regdir)
- return(1);
- while ((item = readdir(regdir))) {
- if (strlen(item->d_name) < 3)
- continue;
+ int ret, line = 0;
- if (strncmp(item->d_name, "regulator", 9))
- continue;
+ display_reset_cursor(REGULATOR);
- len = sprintf(filename, "/sys/class/regulator/%s",
- item->d_name);
+ regulator_print_header();
- dir = opendir(filename);
- if (!dir)
- continue;
- count++;
-
- if (count > numregulators) {
- ret = 1;
- goto exit;
- }
-
- strcpy(regulators_info[count-1].name, item->d_name);
- while ((ritem = readdir(dir))) {
- if (strlen(ritem->d_name) < 3)
- continue;
-
- sprintf(filename + len, "/%s", ritem->d_name);
- file = fopen(filename, "r");
- if (!file)
- continue;
- memset(line, 0, 1024);
- fptr = fgets(line, 1024, file);
- fclose(file);
- if (!fptr)
- continue;
- read_info_from_dirent(ritem, fptr, count - 1);
- }
- exit:
- closedir(dir);
- if (ret)
- break;
- }
- closedir(regdir);
+ ret = tree_for_each(reg_tree, regulator_display_cb, &line);
+
+ display_refresh_pad(REGULATOR);
return ret;
}
+
+static int regulator_filter_cb(const char *name)
+{
+ /* let's ignore some directories in order to avoid to be
+ * pulled inside the sysfs circular symlinks mess/hell
+ * (choose the word which fit better)
+ */
+ if (!strcmp(name, "device"))
+ return 1;
+
+ if (!strcmp(name, "subsystem"))
+ return 1;
+
+ if (!strcmp(name, "driver"))
+ return 1;
+
+ return 0;
+}
+
+static inline int read_regulator_cb(struct tree *t, void *data)
+{
+ struct regulator_info *reg = t->private;
+
+ file_read_value(t->path, "name", "%s", reg->name);
+ file_read_value(t->path, "state", "%s", reg->state);
+ file_read_value(t->path, "status", "%s", reg->status);
+ file_read_value(t->path, "type", "%s", reg->type);
+ file_read_value(t->path, "opmode", "%s", reg->opmode);
+ file_read_value(t->path, "num_users", "%d", &reg->num_users);
+ file_read_value(t->path, "microvolts", "%d", &reg->microvolts);
+ file_read_value(t->path, "min_microvolts", "%d", &reg->min_microvolts);
+ file_read_value(t->path, "max_microvolts", "%d", &reg->max_microvolts);
+ file_read_value(t->path, "microamps", "%d", &reg->microamps);
+ file_read_value(t->path, "min_microamps", "%d", &reg->min_microamps);
+ file_read_value(t->path, "max_microamps", "%d", &reg->max_microamps);
+
+ return 0;
+}
+
+static int fill_regulator_cb(struct tree *t, void *data)
+{
+ struct regulator_info *reg;
+
+ reg = regulator_alloc();
+ if (!reg)
+ return -1;
+ t->private = reg;
+
+ /* we skip the root node but we set it expanded for its children */
+ if (!t->parent)
+ return 0;
+
+ return read_regulator_cb(t, data);
+}
+
+static int fill_regulator_tree(void)
+{
+ return tree_for_each(reg_tree, fill_regulator_cb, NULL);
+}
+
+static struct display_ops regulator_ops = {
+ .display = regulator_display,
+};
+
+int regulator_init(void)
+{
+ reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb, false);
+ if (!reg_tree)
+ return -1;
+
+ if (fill_regulator_tree())
+ return -1;
+
+ return display_register(REGULATOR, &regulator_ops);
+}
diff --git a/regulator.h b/regulator.h
index 4276933..8b3ec06 100644
--- a/regulator.h
+++ b/regulator.h
@@ -13,32 +13,5 @@
* - initial API and implementation
*******************************************************************************/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <getopt.h>
-
-#define VALUE_MAX 16
-
-int numregulators;
-
-struct regulator_info {
- char name[NAME_MAX];
- char state[VALUE_MAX];
- char status[VALUE_MAX];
- char type[VALUE_MAX];
- char opmode[VALUE_MAX];
- int microvolts;
- int min_microvolts;
- int max_microvolts;
- int microamps;
- int min_microamps;
- int max_microamps;
- int requested_microamps;
- int num_users;
-} *regulators_info;
-
-extern int numregulators;
-extern int dump;
+extern int regulator_init(void);
+extern int regulator_dump(void);
diff --git a/sensor.c b/sensor.c
index f5fcd40..bd8c354 100644
--- a/sensor.c
+++ b/sensor.c
@@ -13,157 +13,270 @@
* - initial API and implementation
*******************************************************************************/
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <sys/types.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+
#include "powerdebug.h"
+#include "display.h"
#include "sensor.h"
+#include "tree.h"
+#include "utils.h"
+
+#define SYSFS_SENSOR "/sys/class/hwmon"
+
+static struct tree *sensor_tree;
+
+struct temp_info {
+ char name[NAME_MAX];
+ int temp;
+};
+
+struct fan_info {
+ char name[NAME_MAX];
+ int rpms;
+};
-char *get_num(char *fname, char *sensor)
+struct sensor_info {
+ char name[NAME_MAX];
+ struct temp_info *temperatures;
+ struct fan_info *fans;
+ short nrtemps;
+ short nrfans;
+};
+
+static int sensor_dump_cb(struct tree *tree, void *data)
{
- char tmpstr[NAME_MAX];
- char *str;
+ int i;
+ struct sensor_info *sensor = tree->private;
+
+ if (!strlen(sensor->name))
+ return 0;
+
+ printf("%s\n", sensor->name);
- strcpy(tmpstr, (fname+strlen(sensor)));
+ for (i = 0; i < sensor->nrtemps; i++)
+ printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
+ (float)sensor->temperatures[i].temp / 1000);
- str = strrchr(tmpstr, '_');
- str[0] = '\0';
+ for (i = 0; i < sensor->nrfans; i++)
+ printf(" %s %d rpm\n", sensor->fans[i].name,
+ sensor->fans[i].rpms);
- str = strdup(tmpstr);
- return str;
+ return 0;
}
-void get_sensor_info(char *path, char *fname, char *sensor, int verbose)
+int sensor_dump(void)
{
- FILE *filep;
- char filename[PATH_MAX];
- char **items = NULL, **suffix = NULL;
- char *item, result[NAME_MAX], *num;
- int ret, count = 0;
+ printf("\nSensor Information:\n");
+ printf("*******************\n\n");
- (void)verbose; // get rid of warning
+ return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
+}
- sprintf(filename, "%s/%s", path, fname);
+static struct sensor_info *sensor_alloc(void)
+{
+ struct sensor_info *sensor;
- if (!strcmp(sensor, "in")) {
- items = (char **)items_in;
- suffix = (char **)suffix_in;
- }
+ sensor = malloc(sizeof(*sensor));
+ if (sensor)
+ memset(sensor, 0, sizeof(*sensor));
- if (!strcmp(sensor, "temp")) {
- items = (char **)items_temp;
- suffix = (char **)suffix_temp;
- }
+ return sensor;
+}
- if (!strcmp(sensor, "fan")) {
- items = (char **)items_fan;
- suffix = (char **)suffix_fan;
- }
- if (!strcmp(sensor, "pwm")) {
- items = (char **)items_pwm;
- suffix = (char **)suffix_pwm;
- }
+static int read_sensor_cb(struct tree *tree, void *data)
+{
+ DIR *dir;
+ int value;
+ struct dirent dirent, *direntp;
+ struct sensor_info *sensor = tree->private;
+
+ int nrtemps = 0;
+ int nrfans = 0;
+ dir = opendir(tree->path);
+ if (!dir)
+ return -1;
+
+ file_read_value(tree->path, "name", "%s", sensor->name);
+
+ while (!readdir_r(dir, &dirent, &direntp)) {
+
+ if (!direntp)
+ break;
+
+ if (direntp->d_type != DT_REG)
+ continue;
- if (!items || !suffix)
- return;
+ if (!strncmp(direntp->d_name, "temp", 4)) {
- item = strrchr(fname, '_');
- if (!item)
- return;
+ if (file_read_value(tree->path, direntp->d_name, "%d",
+ &value))
+ continue;
- if (item)
- item++;
+ sensor->temperatures =
+ realloc(sensor->temperatures,
+ sizeof(struct temp_info) * (nrtemps + 1));
+ if (!sensor->temperatures)
+ continue;
- if (item > (fname + strlen(fname)))
- return;
+ strcpy(sensor->temperatures[nrtemps].name,
+ direntp->d_name);
+ sensor->temperatures[nrtemps].temp = value;
- num = get_num(fname, sensor);
- filep = fopen(filename, "r");
+ nrtemps++;
+ }
- if (!filep)
- goto exit;
- ret = fscanf(filep, "%s", result);
- fclose(filep);
+ if (!strncmp(direntp->d_name, "fan", 3)) {
- if (ret != 1)
- goto exit;
+ if (file_read_value(tree->path, direntp->d_name, "%d",
+ &value))
+ continue;
- while (strcmp(items[count], "")) {
- if (!strcmp(items[count], item))
- printf("\'temp\' %s sensor %s\t\t%d%s\n",
- num, items[count], atoi(result)/1000,
- suffix[count]);
- count++;
+ sensor->fans =
+ realloc(sensor->fans,
+ sizeof(struct temp_info) * (nrfans + 1));
+ if (!sensor->fans)
+ continue;
+
+ strcpy(sensor->fans[nrfans].name,
+ direntp->d_name);
+ sensor->fans[nrfans].rpms = value;
+
+ nrfans++;
+ }
}
-exit:
- free(num);
- return;
+
+ sensor->nrtemps = nrtemps;
+ sensor->nrfans = nrfans;
+
+ closedir(dir);
+
+ return 0;
}
-int read_and_print_sensor_info(int verbose)
+static int fill_sensor_cb(struct tree *t, void *data)
{
- DIR *dir, *subdir;
- int len, found = 0;
- char filename[PATH_MAX], devpath[PATH_MAX];
- char device[PATH_MAX];
- struct dirent *item, *subitem;
+ struct sensor_info *sensor;
- printf("\nSensor Information:\n");
- printf("******************\n");
+ sensor = sensor_alloc();
+ if (!sensor)
+ return -1;
- sprintf(filename, "%s", "/sys/class/hwmon");
- dir = opendir(filename);
- if (!dir)
- return errno;
+ t->private = sensor;
- while ((item = readdir(dir))) {
- if (item->d_name[0] == '.') /* skip the hidden files */
- continue;
+ if (!t->parent)
+ return 0;
- found = 1;
+ return read_sensor_cb(t, data);
+}
- sprintf(filename, "/sys/class/hwmon/%s", item->d_name);
- sprintf(devpath, "%s/device", filename);
+static int fill_sensor_tree(void)
+{
+ return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
+}
- len = readlink(devpath, device, PATH_MAX - 1);
+static int sensor_filter_cb(const char *name)
+{
+ /* let's ignore some directories in order to avoid to be
+ * pulled inside the sysfs circular symlinks mess/hell
+ * (choose the word which fit better)
+ */
+ if (!strcmp(name, "subsystem"))
+ return 1;
- if (len < 0)
- strcpy(devpath, filename);
- else
- device[len] = '\0';
+ if (!strcmp(name, "driver"))
+ return 1;
- subdir = opendir(devpath);
+ if (!strcmp(name, "hwmon"))
+ return 1;
- printf("\nSensor Information for %s :\n", item->d_name);
- fflush(stdin);
+ if (!strcmp(name, "power"))
+ return 1;
- while ((subitem = readdir(subdir))) {
- if (subitem->d_name[0] == '.') /* skip hidden files */
- continue;
+ return 0;
+}
- if (!strncmp(subitem->d_name, "in", 2))
- get_sensor_info(devpath, subitem->d_name, "in",
- verbose);
- else if (!strncmp(subitem->d_name, "temp", 4))
- get_sensor_info(devpath, subitem->d_name,
- "temp", verbose);
- else if (!strncmp(subitem->d_name, "fan", 4))
- get_sensor_info(devpath, subitem->d_name,
- "fan", verbose);
- else if (!strncmp(subitem->d_name, "pwm", 4))
- get_sensor_info(devpath, subitem->d_name,
- "pwm", verbose);
+static int sensor_display_cb(struct tree *t, void *data)
+{
+ struct sensor_info *sensor = t->private;
+ int *line = data;
+ char buf[1024];
+ int i;
- }
+ if (!strlen(sensor->name))
+ return 0;
- closedir(subdir);
- }
- closedir(dir);
+ sprintf(buf, "%s", sensor->name);
+ display_print_line(SENSOR, *line, buf, 1, t);
+
+ (*line)++;
- if (!found && verbose) {
- printf("Could not find sensor information!");
- printf(" Looks like /sys/class/hwmon is empty.\n");
+ for (i = 0; i < sensor->nrtemps; i++) {
+ sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
+ (float)sensor->temperatures[i].temp / 1000);
+ display_print_line(SENSOR, *line, buf, 0, t);
+ (*line)++;
}
- printf("\n");
+ for (i = 0; i < sensor->nrfans; i++) {
+ sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
+ sensor->fans[i].rpms);
+ display_print_line(SENSOR, *line, buf, 0, t);
+ (*line)++;
+ }
return 0;
}
+
+static int sensor_print_header(void)
+{
+ char *buf;
+ int ret;
+
+ if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
+ return -1;
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
+}
+
+static int sensor_display(bool refresh)
+{
+ int ret, line = 0;
+
+ display_reset_cursor(SENSOR);
+
+ sensor_print_header();
+
+ ret = tree_for_each(sensor_tree, sensor_display_cb, &line);
+
+ display_refresh_pad(SENSOR);
+
+ return ret;
+}
+
+static struct display_ops sensor_ops = {
+ .display = sensor_display,
+};
+
+int sensor_init(void)
+{
+ sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
+ if (!sensor_tree)
+ return -1;
+
+ if (fill_sensor_tree())
+ return -1;
+
+ return display_register(SENSOR, &sensor_ops);
+}
diff --git a/sensor.h b/sensor.h
index cca11d1..0a069ce 100644
--- a/sensor.h
+++ b/sensor.h
@@ -13,11 +13,5 @@
* - initial API and implementation
*******************************************************************************/
-char *items_temp[32] = {"min", "max", "input", "label", ""};
-char *suffix_temp[32] = {"°C", "°C", "°C", "", ""};
-char *items_in[32] = {"min", "max", "input", "label", ""};
-char *suffix_in[32] = {"Volts", "Volts", "Volts", "", ""};
-char *items_fan[32] = {"min", "max", "input", "label", "div", "target", ""};
-char *suffix_fan[32] = {"RPM", "RPM", "RPM", "", "", "RPM", ""};
-char *items_pwm[32] = {"freq", "enable", "mode", ""};
-char *suffix_pwm[32] = {"Hz", "", "", ""};
+extern int sensor_dump(void);
+extern int sensor_init(void);
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..d331c60
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ * Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "tree.h"
+
+/*
+ * Allocate a tree structure and initialize the different fields.
+ *
+ * @path : the absolute path to the directory
+ * @depth : the depth in the tree
+ * Returns a tree structure on success, NULL otherwise
+ */
+static inline struct tree *tree_alloc(const char *path, int depth)
+{
+ struct tree *t;
+
+ t = malloc(sizeof(*t));
+ if (!t)
+ return NULL;
+
+ /* Full pathname */
+ t->path = strdup(path);
+ if (!t->path) {
+ free(t);
+ return NULL;
+ }
+
+ /* Basename pointer on the full path name */
+ t->name = strrchr(t->path, '/') + 1;
+
+ t->depth = depth;
+ t->tail = t;
+ t->child = NULL;
+ t->parent = NULL;
+ t->next = NULL;
+ t->prev = NULL;
+ t->private = NULL;
+ t->nrchild = 0;
+
+ return t;
+}
+
+/*
+ * Free a tree structure and the fields we allocated in the
+ * tree_alloc function.
+ *
+ * @t : the tree structure to be freed
+ */
+static inline void tree_free(struct tree *t)
+{
+ free(t->path);
+ free(t);
+}
+
+/*
+ * Add at the end of the list the new list element.
+ *
+ * @head : the list to be appened
+ * @new : the new element to be added at the end of the list
+ */
+static inline void tree_add_tail(struct tree *head, struct tree *new)
+{
+ new->prev = head->tail;
+ head->tail->next = new;
+ head->tail = new;
+}
+
+/*
+ * Add a child in to a parent list, at the end of this list.
+ *
+ * @parent : the parent list to add the child
+ * @child : the child to be added
+ */
+static inline void tree_add_child(struct tree *parent, struct tree *child)
+{
+ child->parent = parent;
+
+ if (parent->child)
+ return tree_add_tail(parent->child, child);
+
+ parent->child = child;
+}
+
+/*
+ * This function will browse the directory structure and build a
+ * tree reflecting the content of the directory tree.
+ *
+ * @tree : the root node of the tree
+ * @filter : a callback to filter out the directories
+ * Returns 0 on success, -1 otherwise
+ */
+static int tree_scan(struct tree *tree, tree_filter_t filter, bool follow)
+{
+ DIR *dir;
+ char *basedir, *newpath;
+ struct dirent dirent, *direntp;
+ struct stat s;
+ int ret = 0;
+
+ dir = opendir(tree->path);
+ if (!dir)
+ return -1;
+
+ while (!readdir_r(dir, &dirent, &direntp)) {
+
+ struct tree *child;
+
+ if (!direntp)
+ break;
+
+ if (direntp->d_name[0] == '.')
+ continue;
+
+ if (filter && filter(direntp->d_name))
+ continue;
+
+ ret = asprintf(&basedir, "%s", tree->path);
+ if (ret < 0)
+ return -1;
+
+ ret = basename(basedir) ? 0 : -1;
+ if (ret < 0)
+ goto out_free_basedir;
+
+ ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
+ if (ret < 0)
+ goto out_free_basedir;
+
+ ret = stat(newpath, &s);
+ if (ret)
+ goto out_free_newpath;
+
+ if (S_ISDIR(s.st_mode) || (S_ISLNK(s.st_mode) && follow)) {
+
+ ret = -1;
+
+ child = tree_alloc(newpath, tree->depth + 1);
+ if (!child)
+ goto out_free_newpath;
+
+ tree_add_child(tree, child);
+
+ tree->nrchild++;
+
+ ret = tree_scan(child, filter, follow);
+ }
+
+ out_free_newpath:
+ free(newpath);
+
+ out_free_basedir:
+ free(basedir);
+
+ if (ret)
+ break;
+ }
+
+ closedir(dir);
+
+ return ret;
+}
+
+/*
+ * This function takes the topmost directory path and populate the
+ * directory tree structures.
+ *
+ * @tree : a path to the topmost directory path
+ * Returns a tree structure corresponding to the root node of the
+ * directory tree representation on success, NULL otherwise
+ */
+struct tree *tree_load(const char *path, tree_filter_t filter, bool follow)
+{
+ struct tree *tree;
+
+ tree = tree_alloc(path, 0);
+ if (!tree)
+ return NULL;
+
+ if (tree_scan(tree, filter, follow)) {
+ tree_free(tree);
+ return NULL;
+ }
+
+ return tree;
+}
+
+/*
+ * This function will go over the tree passed as parameter and
+ * will call the callback passed as parameter for each node.
+ *
+ * @tree : the topmost node where we begin to browse the tree
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
+{
+ if (!tree)
+ return 0;
+
+ if (cb(tree, data))
+ return -1;
+
+ if (tree_for_each(tree->child, cb, data))
+ return -1;
+
+ return tree_for_each(tree->next, cb, data);
+}
+
+/*
+ * This function will go over the tree passed as parameter at the reverse
+ * order and will call the callback passed as parameter for each.
+ * @tree : the lower node where we begin to browse the tree at the reverse
+ * order
+ * cb : a callback for each node the function will go over
+ * data : some private data to be passed across the callbacks
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data)
+{
+ if (!tree)
+ return 0;
+
+ if (cb(tree, data))
+ return -1;
+
+ if (tree_for_each_reverse(tree->prev, cb, data))
+ return -1;
+
+ return tree_for_each_reverse(tree->parent, cb, data);
+}
+
+
+/*
+ * The function will go over all the parent of the specified node passed
+ * as parameter.
+ * @tree : the child node from where we back path to the parent
+ * cb : a callback for each node the function will go over
+ * data : some private data to be passed across the callbacks
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data)
+{
+ if (!tree)
+ return 0;
+
+ if (tree_for_each_parent(tree->parent, cb, data))
+ return -1;
+
+ return cb(tree, data);
+}
+
+/*
+ * The function will return the first node which match with the name as
+ * parameter.
+ * @tree : the tree where we begin to find
+ * @name : the name of the node the function must look for.
+ * Returns a pointer to the tree structure if found, NULL otherwise.
+ */
+struct tree *tree_find(struct tree *tree, const char *name)
+{
+ struct tree *t;
+
+ if (!tree)
+ return NULL;
+
+ if (!strcmp(tree->name, name))
+ return tree;
+
+ t = tree_find(tree->child, name);
+ if (t)
+ return t;
+
+ return tree_find(tree->next, name);
+}
+
+struct struct_find {
+ int nr;
+ const char *name;
+ struct tree ***ptree;
+};
+
+static int tree_finds_cb(struct tree *tree, void *data)
+{
+ struct struct_find *sf = data;
+
+ if (!strlen(sf->name))
+ return 0;
+
+ if (strncmp(sf->name, tree->name, strlen(sf->name)))
+ return 0;
+
+ if (sf->ptree)
+ (*(sf->ptree))[sf->nr] = tree;
+
+ sf->nr++;
+
+ return 0;
+}
+
+/*
+ * This function will search for all the nodes where the name begin
+ * with the name passed as parameter. *Note* the function allocates
+ * the array, it is up to the caller to free this array.
+ * @tree : the topmost node of the tree where we being to search
+ * @name : the name to find in the tree
+ * @ptr : a pointer to a pointer of pointer of tree structure :)
+ * Returns the number of elements found in the tree, < 0 if something
+ * went wrong.
+ */
+int tree_finds(struct tree *tree, const char *name, struct tree ***ptr)
+{
+ struct struct_find sf = { .nr = 0, .ptree = NULL, .name = name };
+ int nmatch;
+
+ /* first pass : count # of matching nodes */
+ tree_for_each(tree, tree_finds_cb, &sf);
+
+ /* no match */
+ if (!sf.nr)
+ return 0;
+
+ *ptr = malloc(sizeof(struct tree *) * sf.nr);
+ if (!*ptr)
+ return -1;
+
+ /* store the result as it will be overwritten by the next call */
+ nmatch = sf.nr;
+ sf.nr = 0;
+ sf.ptree = ptr;
+
+ /* second pass : fill with the matching nodes */
+ tree_for_each(tree, tree_finds_cb, &sf);
+
+ return nmatch;
+}
diff --git a/tree.h b/tree.h
new file mode 100644
index 0000000..5c1c697
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ * Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+/*
+ * Structure describing a node of the clock tree
+ *
+ * tail : points to the last element in the list
+ * next : points to the next element in the list
+ * child : points to the child node
+ * parent : points to the parent node
+ * depth : the recursive level of the node
+ * path : absolute pathname of the directory
+ * name : basename of the directory
+ */
+struct tree {
+ struct tree *tail;
+ struct tree *next;
+ struct tree *prev;
+ struct tree *child;
+ struct tree *parent;
+ char *path;
+ char *name;
+ void *private;
+ int nrchild;
+ unsigned char depth;
+};
+
+typedef int (*tree_cb_t)(struct tree *t, void *data);
+
+typedef int (*tree_filter_t)(const char *name);
+
+extern struct tree *tree_load(const char *path, tree_filter_t filter, bool follow);
+
+extern struct tree *tree_find(struct tree *tree, const char *name);
+
+extern int tree_for_each(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_finds(struct tree *tree, const char *name, struct tree ***ptr);
diff --git a/utils.c b/utils.c
new file mode 100644
index 0000000..e47c58e
--- /dev/null
+++ b/utils.c
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - initial API and implementation
+ *******************************************************************************/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+
+/*
+ * This functions is a helper to read a specific file content and store
+ * the content inside a variable pointer passed as parameter, the format
+ * parameter gives the variable type to be read from the file.
+ *
+ * @path : directory path containing the file
+ * @name : name of the file to be read
+ * @format : the format of the format
+ * @value : a pointer to a variable to store the content of the file
+ * Returns 0 on success, -1 otherwise
+ */
+int file_read_value(const char *path, const char *name,
+ const char *format, void *value)
+{
+ FILE *file;
+ char *rpath;
+ int ret;
+
+ ret = asprintf(&rpath, "%s/%s", path, name);
+ if (ret < 0)
+ return ret;
+
+ file = fopen(rpath, "r");
+ if (!file) {
+ ret = -1;
+ goto out_free;
+ }
+
+ ret = fscanf(file, format, value) == EOF ? -1 : 0;
+
+ fclose(file);
+out_free:
+ free(rpath);
+ return ret;
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..d4ac65a
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - initial API and implementation
+ *******************************************************************************/
+#ifndef __UTILS_H
+#define __UTILS_H
+
+extern int file_read_value(const char *path, const char *name,
+ const char *format, void *value);
+
+
+#endif