1bcde4861SRafael Vanoni Polanczyk /*
2b47b5b34SRafael Vanoni  * Copyright 2009, Intel Corporation
3b47b5b34SRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
4bcde4861SRafael Vanoni Polanczyk  *
5bcde4861SRafael Vanoni Polanczyk  * This file is part of PowerTOP
6bcde4861SRafael Vanoni Polanczyk  *
7bcde4861SRafael Vanoni Polanczyk  * This program file is free software; you can redistribute it and/or modify it
8bcde4861SRafael Vanoni Polanczyk  * under the terms of the GNU General Public License as published by the
9bcde4861SRafael Vanoni Polanczyk  * Free Software Foundation; version 2 of the License.
10bcde4861SRafael Vanoni Polanczyk  *
11bcde4861SRafael Vanoni Polanczyk  * This program is distributed in the hope that it will be useful, but WITHOUT
12bcde4861SRafael Vanoni Polanczyk  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13bcde4861SRafael Vanoni Polanczyk  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14bcde4861SRafael Vanoni Polanczyk  * for more details.
15bcde4861SRafael Vanoni Polanczyk  *
16bcde4861SRafael Vanoni Polanczyk  * You should have received a copy of the GNU General Public License
17bcde4861SRafael Vanoni Polanczyk  * along with this program in a file named COPYING; if not, write to the
18bcde4861SRafael Vanoni Polanczyk  * Free Software Foundation, Inc.,
19bcde4861SRafael Vanoni Polanczyk  * 51 Franklin Street, Fifth Floor,
20bcde4861SRafael Vanoni Polanczyk  * Boston, MA 02110-1301 USA
21bcde4861SRafael Vanoni Polanczyk  *
22bcde4861SRafael Vanoni Polanczyk  * Authors:
23bcde4861SRafael Vanoni Polanczyk  *      Arjan van de Ven <arjan@linux.intel.com>
24bcde4861SRafael Vanoni Polanczyk  *      Eric C Saxe <eric.saxe@sun.com>
25bcde4861SRafael Vanoni Polanczyk  *      Aubrey Li <aubrey.li@intel.com>
26bcde4861SRafael Vanoni Polanczyk  */
27bcde4861SRafael Vanoni Polanczyk 
28bcde4861SRafael Vanoni Polanczyk /*
29bcde4861SRafael Vanoni Polanczyk  * GPL Disclaimer
30bcde4861SRafael Vanoni Polanczyk  *
31bcde4861SRafael Vanoni Polanczyk  * For the avoidance of doubt, except that if any license choice other
32bcde4861SRafael Vanoni Polanczyk  * than GPL or LGPL is available it will apply instead, Sun elects to
33bcde4861SRafael Vanoni Polanczyk  * use only the General Public License version 2 (GPLv2) at this time
34bcde4861SRafael Vanoni Polanczyk  * for any software where a choice of GPL license versions is made
35bcde4861SRafael Vanoni Polanczyk  * available with the language indicating that GPLv2 or any later
36bcde4861SRafael Vanoni Polanczyk  * version may be used, or where a choice of which version of the GPL
37bcde4861SRafael Vanoni Polanczyk  * is applied is otherwise unspecified.
38bcde4861SRafael Vanoni Polanczyk  */
39bcde4861SRafael Vanoni Polanczyk 
40bcde4861SRafael Vanoni Polanczyk #include <unistd.h>
41bcde4861SRafael Vanoni Polanczyk #include <stdio.h>
42bcde4861SRafael Vanoni Polanczyk #include <stdlib.h>
43bcde4861SRafael Vanoni Polanczyk #include <string.h>
44bcde4861SRafael Vanoni Polanczyk #include "powertop.h"
45bcde4861SRafael Vanoni Polanczyk 
469bbf5ba1SRafael Vanoni /*
479bbf5ba1SRafael Vanoni  * Default number of intervals we display a suggestion before moving
489bbf5ba1SRafael Vanoni  * to the next.
499bbf5ba1SRafael Vanoni  */
509bbf5ba1SRafael Vanoni #define	PT_SUGG_DEF_SLICE	3
51bcde4861SRafael Vanoni Polanczyk 
529bbf5ba1SRafael Vanoni /*
539bbf5ba1SRafael Vanoni  * Global pointer to the current suggestion.
549bbf5ba1SRafael Vanoni  */
559bbf5ba1SRafael Vanoni sugg_t	*g_curr_sugg;
56bcde4861SRafael Vanoni Polanczyk 
579bbf5ba1SRafael Vanoni /*
589bbf5ba1SRafael Vanoni  * Head of the list of suggestions.
599bbf5ba1SRafael Vanoni  */
609bbf5ba1SRafael Vanoni static sugg_t *sugg;
61bcde4861SRafael Vanoni Polanczyk 
629bbf5ba1SRafael Vanoni /*
639bbf5ba1SRafael Vanoni  * Add a new suggestion. Only one suggestion per text allowed.
649bbf5ba1SRafael Vanoni  */
65bcde4861SRafael Vanoni Polanczyk void
pt_sugg_add(char * text,int weight,char key,char * sb_msg,sugg_func_t * func)669bbf5ba1SRafael Vanoni pt_sugg_add(char *text, int weight, char key, char *sb_msg, sugg_func_t *func)
67bcde4861SRafael Vanoni Polanczyk {
689bbf5ba1SRafael Vanoni 	sugg_t *new, *n, *pos = NULL;
69bcde4861SRafael Vanoni Polanczyk 
709bbf5ba1SRafael Vanoni 	/*
719bbf5ba1SRafael Vanoni 	 * Text is a required field for suggestions
729bbf5ba1SRafael Vanoni 	 */
739bbf5ba1SRafael Vanoni 	if (text == NULL)
749bbf5ba1SRafael Vanoni 		return;
75bcde4861SRafael Vanoni Polanczyk 
769bbf5ba1SRafael Vanoni 	if (sugg == NULL) {
779bbf5ba1SRafael Vanoni 		/*
789bbf5ba1SRafael Vanoni 		 * Creating first element
799bbf5ba1SRafael Vanoni 		 */
809bbf5ba1SRafael Vanoni 		if ((new = calloc(1, sizeof (sugg_t))) == NULL)
819bbf5ba1SRafael Vanoni 			return;
82bcde4861SRafael Vanoni Polanczyk 
839bbf5ba1SRafael Vanoni 		if (sb_msg != NULL)
849bbf5ba1SRafael Vanoni 			new->sb_msg = strdup(sb_msg);
85bcde4861SRafael Vanoni Polanczyk 
869bbf5ba1SRafael Vanoni 		if (text != NULL)
879bbf5ba1SRafael Vanoni 			new->text = strdup(text);
88bcde4861SRafael Vanoni Polanczyk 
899bbf5ba1SRafael Vanoni 		new->weight = weight;
909bbf5ba1SRafael Vanoni 		new->key = key;
919bbf5ba1SRafael Vanoni 		new->func = func;
929bbf5ba1SRafael Vanoni 		new->slice = 0;
93bcde4861SRafael Vanoni Polanczyk 
949bbf5ba1SRafael Vanoni 		sugg = new;
959bbf5ba1SRafael Vanoni 		new->prev = NULL;
969bbf5ba1SRafael Vanoni 		new->next = NULL;
979bbf5ba1SRafael Vanoni 	} else {
989bbf5ba1SRafael Vanoni 		for (n = sugg; n != NULL; n = n->next) {
999bbf5ba1SRafael Vanoni 			if (strcmp(n->text, text) == 0)
1009bbf5ba1SRafael Vanoni 				return;
101bcde4861SRafael Vanoni Polanczyk 
1029bbf5ba1SRafael Vanoni 			if (weight > n->weight && pos == NULL)
1039bbf5ba1SRafael Vanoni 				pos = n;
1049bbf5ba1SRafael Vanoni 		}
1059bbf5ba1SRafael Vanoni 		/*
1069bbf5ba1SRafael Vanoni 		 * Create a new element
1079bbf5ba1SRafael Vanoni 		 */
1089bbf5ba1SRafael Vanoni 		if ((new = calloc(1, sizeof (sugg_t))) == NULL)
1099bbf5ba1SRafael Vanoni 			return;
110bcde4861SRafael Vanoni Polanczyk 
1119bbf5ba1SRafael Vanoni 		if (sb_msg != NULL)
1129bbf5ba1SRafael Vanoni 			new->sb_msg = strdup(sb_msg);
1139bbf5ba1SRafael Vanoni 
1149bbf5ba1SRafael Vanoni 		new->text = strdup(text);
1159bbf5ba1SRafael Vanoni 
1169bbf5ba1SRafael Vanoni 		new->weight = weight;
1179bbf5ba1SRafael Vanoni 		new->key = key;
1189bbf5ba1SRafael Vanoni 		new->func = func;
1199bbf5ba1SRafael Vanoni 		new->slice = 0;
1209bbf5ba1SRafael Vanoni 
1219bbf5ba1SRafael Vanoni 		if (pos == NULL) {
1229bbf5ba1SRafael Vanoni 			/*
1239bbf5ba1SRafael Vanoni 			 * Ordering placed the new element at the end
1249bbf5ba1SRafael Vanoni 			 */
1259bbf5ba1SRafael Vanoni 			for (n = sugg; n->next != NULL; n = n->next)
1269bbf5ba1SRafael Vanoni 				;
1279bbf5ba1SRafael Vanoni 
1289bbf5ba1SRafael Vanoni 			n->next = new;
1299bbf5ba1SRafael Vanoni 			new->prev = n;
1309bbf5ba1SRafael Vanoni 			new->next = NULL;
1319bbf5ba1SRafael Vanoni 		} else {
1329bbf5ba1SRafael Vanoni 			if (pos == sugg) {
1339bbf5ba1SRafael Vanoni 				/*
1349bbf5ba1SRafael Vanoni 				 * Ordering placed the new element at the start
1359bbf5ba1SRafael Vanoni 				 */
1369bbf5ba1SRafael Vanoni 				new->next = sugg;
1379bbf5ba1SRafael Vanoni 				new->prev = sugg;
1389bbf5ba1SRafael Vanoni 				sugg->prev = new;
1399bbf5ba1SRafael Vanoni 				sugg = new;
1409bbf5ba1SRafael Vanoni 			} else {
1419bbf5ba1SRafael Vanoni 				/*
1429bbf5ba1SRafael Vanoni 				 * Ordering placed the new element somewhere in
1439bbf5ba1SRafael Vanoni 				 * the middle
1449bbf5ba1SRafael Vanoni 				 */
1459bbf5ba1SRafael Vanoni 				new->next = pos;
1469bbf5ba1SRafael Vanoni 				new->prev = pos->prev;
1479bbf5ba1SRafael Vanoni 				pos->prev->next = new;
1489bbf5ba1SRafael Vanoni 				pos->prev = new;
1499bbf5ba1SRafael Vanoni 			}
1509bbf5ba1SRafael Vanoni 		}
1519bbf5ba1SRafael Vanoni 	}
1529bbf5ba1SRafael Vanoni }
153bcde4861SRafael Vanoni Polanczyk 
1549bbf5ba1SRafael Vanoni /*
1559bbf5ba1SRafael Vanoni  * Removes a suggestion, returning 0 if not found and 1 if so.
1569bbf5ba1SRafael Vanoni  */
1579bbf5ba1SRafael Vanoni int
pt_sugg_remove(sugg_func_t * func)1589bbf5ba1SRafael Vanoni pt_sugg_remove(sugg_func_t *func)
1599bbf5ba1SRafael Vanoni {
1609bbf5ba1SRafael Vanoni 	sugg_t *n;
1619bbf5ba1SRafael Vanoni 	int ret = 0;
1629bbf5ba1SRafael Vanoni 
1639bbf5ba1SRafael Vanoni 	for (n = sugg; n != NULL; n = n->next) {
1649bbf5ba1SRafael Vanoni 		if (n->func == func) {
1659bbf5ba1SRafael Vanoni 			/* Removing the first element */
1669bbf5ba1SRafael Vanoni 			if (n == sugg) {
1679bbf5ba1SRafael Vanoni 				if (sugg->next == NULL) {
1689bbf5ba1SRafael Vanoni 					/* Removing the only element */
1699bbf5ba1SRafael Vanoni 					sugg = NULL;
1709bbf5ba1SRafael Vanoni 				} else {
1719bbf5ba1SRafael Vanoni 					sugg = n->next;
1729bbf5ba1SRafael Vanoni 					sugg->prev = NULL;
1739bbf5ba1SRafael Vanoni 				}
1749bbf5ba1SRafael Vanoni 			} else {
1759bbf5ba1SRafael Vanoni 				if (n->next == NULL) {
1769bbf5ba1SRafael Vanoni 					/* Removing the last element */
1779bbf5ba1SRafael Vanoni 					n->prev->next = NULL;
1789bbf5ba1SRafael Vanoni 				} else {
1799bbf5ba1SRafael Vanoni 					/* Removing an intermediate element */
1809bbf5ba1SRafael Vanoni 					n->prev->next = n->next;
1819bbf5ba1SRafael Vanoni 					n->next->prev = n->prev;
1829bbf5ba1SRafael Vanoni 				}
1839bbf5ba1SRafael Vanoni 			}
184bcde4861SRafael Vanoni Polanczyk 
1859bbf5ba1SRafael Vanoni 			/*
1869bbf5ba1SRafael Vanoni 			 * If this suggestions is currently being suggested,
1879bbf5ba1SRafael Vanoni 			 * remove it and update the screen.
1889bbf5ba1SRafael Vanoni 			 */
1899bbf5ba1SRafael Vanoni 			if (n == g_curr_sugg) {
1909bbf5ba1SRafael Vanoni 				if (n->sb_msg != NULL) {
1919bbf5ba1SRafael Vanoni 					pt_display_mod_status_bar(n->sb_msg);
1929bbf5ba1SRafael Vanoni 					pt_display_status_bar();
1939bbf5ba1SRafael Vanoni 				}
1949bbf5ba1SRafael Vanoni 				if (n->text != NULL)
1959bbf5ba1SRafael Vanoni 					pt_display_suggestions(NULL);
1969bbf5ba1SRafael Vanoni 			}
197bcde4861SRafael Vanoni Polanczyk 
1989bbf5ba1SRafael Vanoni 			free(n);
1999bbf5ba1SRafael Vanoni 			ret = 1;
2009bbf5ba1SRafael Vanoni 		}
2019bbf5ba1SRafael Vanoni 	}
202bcde4861SRafael Vanoni Polanczyk 
2039bbf5ba1SRafael Vanoni 	return (ret);
204bcde4861SRafael Vanoni Polanczyk }
205bcde4861SRafael Vanoni Polanczyk 
2069bbf5ba1SRafael Vanoni /*
2079bbf5ba1SRafael Vanoni  * Chose a suggestion to display. The list of suggestions is ordered by weight,
2089bbf5ba1SRafael Vanoni  * so we only worry about fariness here. Each suggestion, starting with the
2099bbf5ba1SRafael Vanoni  * first (the 'heaviest') is displayed during PT_SUGG_DEF_SLICE intervals.
2109bbf5ba1SRafael Vanoni  */
211bcde4861SRafael Vanoni Polanczyk void
pt_sugg_pick(void)2129bbf5ba1SRafael Vanoni pt_sugg_pick(void)
213bcde4861SRafael Vanoni Polanczyk {
2149bbf5ba1SRafael Vanoni 	sugg_t *n;
215bcde4861SRafael Vanoni Polanczyk 
2169bbf5ba1SRafael Vanoni 	if (sugg == NULL) {
2179bbf5ba1SRafael Vanoni 		g_curr_sugg = NULL;
218bcde4861SRafael Vanoni Polanczyk 		return;
219bcde4861SRafael Vanoni Polanczyk 	}
220bcde4861SRafael Vanoni Polanczyk 
2219bbf5ba1SRafael Vanoni search:
2229bbf5ba1SRafael Vanoni 	for (n = sugg; n != NULL; n = n->next) {
2239bbf5ba1SRafael Vanoni 
2249bbf5ba1SRafael Vanoni 		if (n->slice++ < PT_SUGG_DEF_SLICE) {
2259bbf5ba1SRafael Vanoni 
2269bbf5ba1SRafael Vanoni 			/*
2279bbf5ba1SRafael Vanoni 			 * Don't need to re-suggest the current suggestion.
2289bbf5ba1SRafael Vanoni 			 */
2292d83778aSRafael Vanoni 			if (g_curr_sugg == n && !g_sig_resize)
2309bbf5ba1SRafael Vanoni 				return;
2319bbf5ba1SRafael Vanoni 
2329bbf5ba1SRafael Vanoni 			/*
2339bbf5ba1SRafael Vanoni 			 * Remove the current suggestion from screen.
2349bbf5ba1SRafael Vanoni 			 */
2359bbf5ba1SRafael Vanoni 			if (g_curr_sugg != NULL) {
2369bbf5ba1SRafael Vanoni 				if (g_curr_sugg->sb_msg != NULL) {
2379bbf5ba1SRafael Vanoni 					pt_display_mod_status_bar(
2389bbf5ba1SRafael Vanoni 					    g_curr_sugg->sb_msg);
2399bbf5ba1SRafael Vanoni 					pt_display_status_bar();
2409bbf5ba1SRafael Vanoni 				}
2419bbf5ba1SRafael Vanoni 				if (g_curr_sugg->text != NULL)
2429bbf5ba1SRafael Vanoni 					pt_display_suggestions(NULL);
2439bbf5ba1SRafael Vanoni 			}
244bcde4861SRafael Vanoni Polanczyk 
2459bbf5ba1SRafael Vanoni 			if (n->sb_msg != NULL) {
2469bbf5ba1SRafael Vanoni 				pt_display_mod_status_bar(n->sb_msg);
2479bbf5ba1SRafael Vanoni 				pt_display_status_bar();
2489bbf5ba1SRafael Vanoni 			}
249bcde4861SRafael Vanoni Polanczyk 
2509bbf5ba1SRafael Vanoni 			pt_display_suggestions(n->text);
251bcde4861SRafael Vanoni Polanczyk 
2529bbf5ba1SRafael Vanoni 			g_curr_sugg = n;
253bcde4861SRafael Vanoni Polanczyk 
254bcde4861SRafael Vanoni Polanczyk 			return;
255bcde4861SRafael Vanoni Polanczyk 		}
256bcde4861SRafael Vanoni Polanczyk 	}
257bcde4861SRafael Vanoni Polanczyk 
2589bbf5ba1SRafael Vanoni 	/*
2599bbf5ba1SRafael Vanoni 	 * All suggestions have run out of slice quotas, so we restart.
2609bbf5ba1SRafael Vanoni 	 */
2619bbf5ba1SRafael Vanoni 	for (n = sugg; n != NULL; n = n->next)
2629bbf5ba1SRafael Vanoni 		n->slice = 0;
2639bbf5ba1SRafael Vanoni 
2649bbf5ba1SRafael Vanoni 	goto search;
265bcde4861SRafael Vanoni Polanczyk }
266bcde4861SRafael Vanoni Polanczyk 
267bcde4861SRafael Vanoni Polanczyk void
pt_sugg_as_root(void)2689bbf5ba1SRafael Vanoni pt_sugg_as_root(void)
269bcde4861SRafael Vanoni Polanczyk {
2709bbf5ba1SRafael Vanoni 	pt_sugg_add("Suggestion: run as root to get suggestions"
271*f795e601SToomas Soome 	    " for reducing system power consumption",  40, 0, NULL,
2729bbf5ba1SRafael Vanoni 	    NULL);
273bcde4861SRafael Vanoni Polanczyk }
274