Minor cleanups
[meego-developer-tools:powertop.git] / alsa-power.c
1 /*
2  * Copyright 2009, Intel Corporation
3  *
4  * This file is part of PowerTOP
5  *
6  * This program file is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program in a file named COPYING; if not, write to the
17  * Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301 USA
20  *
21  * Authors:
22  *      Arjan van de Ven <arjan@linux.intel.com>
23  */
24
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <assert.h>
33
34 #include "powertop.h"
35
36 struct device_data;
37
38 struct device_data {
39         struct device_data *next;
40         char pathname[4096];
41         char human_name[4096];
42         uint64_t power_on, power_off;
43         uint64_t previous_power_on, previous_power_off;
44 };
45
46
47 static struct device_data *devices;
48
49 static void cachunk_data(void)
50 {
51         struct device_data *ptr;
52         ptr = devices;
53         while (ptr) {
54                 ptr->previous_power_on = ptr->power_on;
55                 ptr->previous_power_off = ptr->power_off;
56                 ptr = ptr->next;
57         }
58 }
59
60 static char *long_name(char *path, char *shortname)
61 {
62         static char line[4096];
63         char filename[4096], temp[4096], *c;
64         FILE *file;
65         sprintf(line, "%s ", shortname);
66
67         sprintf(filename, "%s/vendor_name", path);
68         file = fopen(filename, "r");
69         if (file) {
70                 if (fgets(temp, 4096, file))
71                         strcat(line, temp);
72                 fclose(file);
73         }
74
75         sprintf(filename, "%s/chip_name", path);
76         file = fopen(filename, "r");
77         if (file) {
78                 if (fgets(temp, 4096, file))
79                         strcat(line, temp);
80                 fclose(file);
81         }
82
83         while ((c = strchr(line, '\n')))
84                 *c = ' ';
85         return line;
86 }
87 static void update_alsa_device(char *path, char *shortname)
88 {
89         struct device_data *ptr;
90         FILE *file;
91         char fullpath[4096];
92         char name[4096];
93         ptr = devices;
94
95         sprintf(fullpath, "%s/power_off_acct", path);
96
97         if (access(fullpath, R_OK))
98                 return;
99
100         while (ptr) {
101                 if (strcmp(ptr->pathname, path)==0) {
102                         file = fopen(fullpath, "r");
103                         if (!file)
104                                 return;
105                         fgets(name, 4096, file);
106                         ptr->power_off = strtoull(name, NULL, 10);
107                         fclose(file);
108                         sprintf(fullpath, "%s/power_on_acct", path);
109                         file = fopen(fullpath, "r");
110                         if (!file)
111                                 return;
112                         fgets(name, 4096, file);
113                         ptr->power_on = strtoull(name, NULL, 10);
114                         fclose(file);
115
116                         return;
117                 }
118                 ptr = ptr->next;
119         }
120         /* no luck, new one */
121         ptr = malloc(sizeof(struct device_data));
122         assert(ptr!=0);
123         memset(ptr, 0, sizeof(struct device_data));
124         ptr->next = devices;
125         devices = ptr;
126         strcpy(ptr->pathname, path);
127         strcpy(ptr->human_name, long_name(path, shortname));
128 }
129
130 void do_alsa_stats(void)
131 {
132         DIR *dir;
133         struct dirent *dirent;
134         char pathname[PATH_MAX];
135
136         dir = opendir("/sys/class/sound/card0");
137         if (!dir)
138                 return;
139
140         cachunk_data();
141         while ((dirent = readdir(dir))) {
142                 if (dirent->d_name[0]=='.')
143                         continue;
144
145                 sprintf(pathname, "/sys/class/sound/card0/%s", dirent->d_name);
146                 update_alsa_device(pathname, dirent->d_name);
147         }
148
149         closedir(dir);
150 }
151
152
153 void display_alsa_activity(void)
154 {
155         struct device_data *dev;
156         printf("\n");
157         printf("%s\n", _("Recent audio activity statistics"));
158         printf("%s\n", _("Active  Device name"));
159         dev = devices;
160         while (dev) {
161                 printf("%5.1f%%\t%s\n", 100.0*(dev->power_on - dev->previous_power_on) /
162                         (0.00001 + dev->power_on + dev->power_off - dev->previous_power_on - dev->previous_power_off),
163                         dev->human_name);
164                 dev = dev->next;
165         }
166
167 }
168
169 void alsa_activity_hint(void)
170 {
171         int total_active = 0;
172         int pick;
173         struct device_data *dev;
174         dev = devices;
175         while (dev) {
176                 if (dev->power_on-1 > dev->previous_power_on)
177                         total_active++;
178                 dev = dev->next;
179         }
180         if (!total_active)
181                 return;
182
183         pick = rand() % total_active;
184         total_active = 0;
185         dev = devices;
186         while (dev) {
187                 if (dev->power_on-1 > dev->previous_power_on) {
188                         if (total_active == pick) {
189                                 char alsa_hint[8000];
190                                 sprintf(alsa_hint, _("An audio device is active %4.1f%% of the time:\n%s"),
191                                  100.0*(dev->power_on - dev->previous_power_on) /
192                                 (0.00001 + dev->power_on + dev->power_off - dev->previous_power_on - dev->previous_power_off),
193                                 dev->human_name);
194                                 add_suggestion(alsa_hint,
195                                 1, 'A', _(" A - Turn HD audio powersave on "), hda_power_on);
196                         }
197                         total_active++;
198                 }
199                 dev = dev->next;
200         }
201
202 }