diff options
-rw-r--r-- | .gitignore | 46 | ||||
-rw-r--r-- | LICENSE | 221 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | clocks.c | 763 | ||||
-rw-r--r-- | clocks.h | 43 | ||||
-rw-r--r-- | display.c | 702 | ||||
-rw-r--r-- | display.h | 27 | ||||
-rw-r--r-- | mainloop.c | 122 | ||||
-rw-r--r-- | mainloop.h | 22 | ||||
-rw-r--r-- | powerdebug.c | 384 | ||||
-rw-r--r-- | powerdebug.h | 59 | ||||
-rw-r--r-- | regulator.c | 356 | ||||
-rw-r--r-- | regulator.h | 31 | ||||
-rw-r--r-- | sensor.c | 327 | ||||
-rw-r--r-- | sensor.h | 10 | ||||
-rw-r--r-- | tree.c | 356 | ||||
-rw-r--r-- | tree.h | 54 | ||||
-rw-r--r-- | utils.c | 55 | ||||
-rw-r--r-- | utils.h | 22 |
19 files changed, 2322 insertions, 1286 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 +*~ +\#*# @@ -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. + @@ -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 \ + 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 @@ -11,565 +11,414 @@ * 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" +#include "tree.h" +#include "utils.h" -static char clk_dir_path[PATH_MAX]; -static char clk_name[NAME_MAX]; -static int bold[MAX_LINES]; +struct clock_info { + int flags; + int rate; + int usecount; + bool expanded; + char *prefix; +} *clocks_info; -int init_clock_details(void) -{ - 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); -} +static struct tree *clock_tree = NULL; -int get_int_from(char *file) +static int locate_debugfs(char *clk_path) { - FILE *filep; - char result[NAME_MAX]; - int ret; + const char *mtab = "/proc/mounts"; + struct mntent *mntent; + int ret = -1; + FILE *file = NULL; - filep = fopen(file, "r"); + file = setmntent(mtab, "r"); + if (!file) + return -1; - if (!filep) - return -1; //TBD : What should we return on failure, here ? + while ((mntent = getmntent(file))) { - ret = fscanf(filep, "%s", result); - fclose(filep); + if (strcmp(mntent->mnt_type, "debugfs")) + continue; - return atoi(result); + strcpy(clk_path, mntent->mnt_dir); + ret = 0; + break; + } + + fclose(file); + return ret; } -void find_parents_for_clock(char *clkname, int complete) +static struct clock_info *clock_alloc(void) { - char name[256]; + struct clock_info *ci; - name[0] = '\0'; - if (!complete) { - char str[256]; + ci = malloc(sizeof(*ci)); + if (ci) + memset(ci, 0, sizeof(*ci)); - 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); + return ci; } -int read_and_print_clock_info(int verbose, int hrow, int selected) +static inline const char *clock_rate(int *rate) { - print_one_clock(0, "Reading Clock Tree ...", 1, 1); + 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 ""; +} - if (!old_clock_line_no || selected == REFRESH_WINDOW) { - destroy_clocks_info(); - read_clock_info(clk_dir_path); - } +static int dump_clock_cb(struct tree *t, void *data) +{ + struct clock_info *clk = t->private; + struct clock_info *pclk; + const char *unit; + int ret = 0; + int rate = clk->rate; - if (!clocks_info->num_children) { - fprintf(stderr, "powerdebug: No clocks found. Exiting..\n"); - exit(1); + if (!t->parent) { + printf("/\n"); + clk->prefix = ""; + return 0; } - if (selected == CLOCK_SELECTED) - selected = 1; - else - selected = 0; + pclk = t->parent->private; - print_clock_info(verbose, hrow, selected); - hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1; + if (!clk->prefix) + ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix, + t->depth > 1 ? " ": "", t->next ? "|" : " "); + if (ret < 0) + return -1; - return hrow; -} + unit = clock_rate(&rate); -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; - - print_clock_header(); - - for (i = 0; i < clocks_info->num_children; i++) - add_clock_details_recur(clocks_info->children[i], - hrow, selected); + return tree_for_each(clock_tree, dump_clock_cb, NULL); +} - delta = calc_delta_screen_size(hrow); +static int dump_all_parents(char *clkarg) +{ + struct tree *tree; - 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++; + tree = tree_find(clock_tree, clkarg); + if (!tree) { + printf("Clock NOT found!\n"); + return -1; } - old_clock_line_no = clock_line_no; - clock_line_no = 0; + return tree_for_each_parent(tree, dump_clock_cb, NULL); } -void prepare_name_str(char *namestr, struct clock_info *clock) +static inline int read_clock_cb(struct tree *t, void *data) { - int i; + struct clock_info *clk = t->private; + + 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); - strcpy(namestr, ""); - if (clock->level > 1) - for (i = 0; i < (clock->level - 1); i++) - strcat(namestr, " "); - strcat(namestr, clock->name); + return 0; } -void add_clock_details_recur(struct clock_info *clock, int hrow, int selected) +static int read_clock_info(struct tree *tree) { - 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; - } - - 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 tree_for_each(tree, read_clock_cb, NULL); } -void collapse_all_subclocks(struct clock_info *clock) +static int fill_clock_cb(struct tree *t, void *data) { - int i; + struct clock_info *clk; - clock->expanded = 0; - if (clock->num_children) - for (i = 0; i < clock->num_children; i++) - collapse_all_subclocks(clock->children[i]); + 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; + } + + return read_clock_cb(t, data); } -void destroy_clocks_info(void) +static int fill_clock_tree(void) { - 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; + return tree_for_each(clock_tree, fill_clock_cb, NULL); } -void destroy_clocks_info_recur(struct clock_info *clock) +static int is_collapsed(struct tree *t, void *data) { - 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 = t->private; + + if (!clk->expanded) + return 1; + + return 0; } -void read_and_dump_clock_info_one(char *clk) +static char *clock_line(struct tree *t) { - printf("\nParents for \"%s\" Clock :\n\n", clk); - read_clock_info(clk_dir_path); - dump_all_parents(clk); - printf("\n\n"); + 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 (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(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"); + 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_clock_info(char *clkpath) +static int clock_print_info_cb(struct tree *t, void *data) { - 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; + /* we skip the root node of the tree */ + if (!t->parent) + return 0; - 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); - } - closedir(dir); + /* 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); } -struct clock_info *read_clock_info_recur(char *clkpath, int level, - struct clock_info *parent) +static int clock_print_header(void) { - 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; + char *buf; + int ret; - while ((item = readdir(dir))) { - struct clock_info *child; - /* skip hidden dirs except ".." */ - if (item->d_name[0] == '.' ) - continue; + if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s", + "Name", "Flags", "Rate", "Usecount", "Children") < 0) + return -1; - sprintf(filename, "%s/%s", clkpath, item->d_name); + ret = display_column_name(buf); - ret = stat(filename, &buf); + free(buf); - if (ret < 0) { - printf("Error doing a stat on %s\n", filename); - exit(1); - } + return ret; +} - 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; - } +static int clock_print_info(struct tree *tree) +{ + int ret, line = 0; - if (!S_ISDIR(buf.st_mode)) - continue; + display_reset_cursor(CLOCK); - 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); + clock_print_header(); + + ret = tree_for_each(tree, clock_print_info_cb, &line); + + display_refresh_pad(CLOCK); - return cur; + 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; -void dump_clock_info(struct clock_info *clk, int level, int bmp) + return display_refresh_pad(CLOCK); +} + +/* + * 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[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)) + return -1; - while (fscanf(filep, "%*s %s %s %*s %*d %*d\n", - debugfs_mntpoint, fsname) == 2) - if (!strcmp(fsname, "debugfs")) - break; - fclose(filep); + sprintf(clk_dir_path, "%s/clock", clk_dir_path); - if (strcmp(fsname, "debugfs")) - return NULL; + if (access(clk_dir_path, F_OK)) + return -1; + + clock_tree = tree_load(clk_dir_path, NULL); + if (!clock_tree) + return -1; + + if (fill_clock_tree()) + return -1; - return debugfs_mntpoint; + return display_register(CLOCK, &clock_ops); } @@ -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); @@ -13,261 +13,589 @@ * - 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" }, +}; + +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; } @@ -13,15 +13,22 @@ * - initial API and implementation *******************************************************************************/ -#define VALUE_MAX 16 +enum { CLOCK, REGULATOR, SENSOR }; -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); 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..b4575c4 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -14,19 +14,19 @@ *******************************************************************************/ #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 "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 +45,197 @@ 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 : 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! + */ + +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 } +}; + +struct powerdebug_options { + bool verbose; + bool regulators; + bool sensors; + bool clocks; + 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, "rscp: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 '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->regulators = options->clocks = options->sensors = true; - if (findparent && (!clocks || !dump)) { - fprintf(stderr, "-p option passed without -c and -d." - " Exiting...\n"); - usage(); + if (options->selectedwindow == -1) + options->selectedwindow = CLOCK; + + return 0; +} + +static int powerdebug_dump(struct powerdebug_options *options) +{ + if (options->regulators) + regulator_dump(); + + if (options->clocks) + clock_dump(options->clkname); + + if (options->sensors) + sensor_dump(); + + return 0; +} + +static int powerdebug_display(struct powerdebug_options *options) +{ + if (display_init(options->selectedwindow)) { + printf("failed to initialize display\n"); + return -1; } - if (!dump && selectedwindow == -1) - selectedwindow = CLOCK; + if (mainloop(options->ticktime * 1000)) + return -1; - init_regulator_ds(); + return 0; +} - while (1) { - int key = 0; - struct timeval tval; - fd_set readfds; - - if (!dump) { - if (firsttime[0]) - init_curses(); - create_windows(); - show_header(); - } +static struct powerdebug_options *powerdebug_init(void) +{ + struct powerdebug_options *options; - if (regulators || selectedwindow == REGULATOR) { - read_regulator_info(); - if (!dump) { - create_selectedwindow(); - show_regulator_info(verbose); - } - else - print_regulator_info(verbose); - } + options = malloc(sizeof(*options)); + if (!options) + return NULL; - 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); - } - } + memset(options, 0, sizeof(*options)); - if (sensors || selectedwindow == SENSOR) { - if (!dump) { - create_selectedwindow(); - print_sensor_header(); - } else - read_and_print_sensor_info(verbose); - } + return options; +} - if (dump) - break; +int main(int argc, char **argv) +{ + struct powerdebug_options *options; + int ret; - 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); - } - } - } - } + options = powerdebug_init(); + if (!options) { + fprintf(stderr, "not enough memory to allocate options\n"); + return 1; + } - keychar = toupper(keystroke); -//#define DEBUG -#ifdef DEBUG - killall_windows(1); fini_curses(); - printf("key entered %d:%c\n", keystroke, keychar); - exit(1); -#endif - - if (keystroke == 13) - enter_hit = 1; - - if (keychar == 'Q' && !findparent_ncurses) - exit(0); - if (keychar == 'R') { - refreshwin = 1; - ticktime = 3; - } else - refreshwin = 0; - } + if (getoptions(argc, argv, options)) { + usage(); + return 1; + } + + if (mainloop_init()) { + fprintf(stderr, "failed to initialize the mainloop\n"); + return 1; + } + + 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; + } + + ret = options->dump ? powerdebug_dump(options) : + powerdebug_display(options); + + return ret < 0; } diff --git a/powerdebug.h b/powerdebug.h index f7fdc21..05d919b 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.5.1" diff --git a/regulator.c b/regulator.c index 18c9777..e9b01bb 100644 --- a/regulator.c +++ b/regulator.c @@ -11,191 +11,237 @@ * 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++) { + + 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); + printf(regdata[i].ofmt, regdata[i].derefme ? + *((int *)buffer) : 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", ®->num_users); + file_read_value(t->path, "microvolts", "%d", ®->microvolts); + file_read_value(t->path, "min_microvolts", "%d", ®->min_microvolts); + file_read_value(t->path, "max_microvolts", "%d", ®->max_microvolts); + file_read_value(t->path, "microamps", "%d", ®->microamps); + file_read_value(t->path, "min_microamps", "%d", ®->min_microamps); + file_read_value(t->path, "max_microamps", "%d", ®->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); + if (!reg_tree) + return -1; + + if (fill_regulator_tree()) + return -1; + + return display_register(REGULATOR, ®ulator_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); @@ -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\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 °C", 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); + if (!sensor_tree) + return -1; + + if (fill_sensor_tree()) + return -1; + + return display_register(SENSOR, &sensor_ops); +} @@ -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); @@ -0,0 +1,356 @@ +/******************************************************************************* + * 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 <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) +{ + 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)) { + + 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); + } + + 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) +{ + struct tree *tree; + + tree = tree_alloc(path, 0); + if (!tree) + return NULL; + + if (tree_scan(tree, filter)) { + 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; +} @@ -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); + +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); @@ -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; +} @@ -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 |