Minor cleanups
[meego-developer-tools:powertop.git] / urbnum.c
1 /*
2  * Copyright 2007, 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 urbs, active, connected;
43         uint64_t previous_urbs, previous_active, previous_connected;
44         int controller;
45 };
46
47
48 static struct device_data *devices;
49
50 static void cachunk_urbs(void)
51 {
52         struct device_data *ptr;
53         ptr = devices;
54         while (ptr) {
55                 ptr->previous_urbs = ptr->urbs;
56                 ptr->previous_active = ptr->active;
57                 ptr->previous_connected = ptr->connected;
58                 ptr = ptr->next;
59         }
60 }
61
62 static void update_urbnum(char *path, uint64_t count, char *shortname)
63 {
64         struct device_data *ptr;
65         FILE *file;
66         char fullpath[4096];
67         char name[4096], vendor[4096];
68         ptr = devices;
69
70         while (ptr) {
71                 if (strcmp(ptr->pathname, path)==0) {
72                         ptr->urbs = count;
73                         sprintf(fullpath, "%s/power/active_duration", path);
74                         file = fopen(fullpath, "r");
75                         if (!file)
76                                 return;
77                         fgets(name, 4096, file);
78                         ptr->active = strtoull(name, NULL, 10);
79                         fclose(file);
80                         sprintf(fullpath, "%s/power/connected_duration", path);
81                         file = fopen(fullpath, "r");
82                         if (!file)
83                                 return;
84                         fgets(name, 4096, file);
85                         ptr->connected = strtoull(name, NULL, 10);
86                         fclose(file);
87
88                         return;
89                 }
90                 ptr = ptr->next;
91         }
92         /* no luck, new one */
93         ptr = malloc(sizeof(struct device_data));
94         assert(ptr!=0);
95         memset(ptr, 0, sizeof(struct device_data));
96         ptr->next = devices;
97         devices = ptr;
98         strcpy(ptr->pathname, path);
99         ptr->urbs = ptr->previous_urbs = count;
100         sprintf(fullpath, "%s/product", path);
101         file = fopen(fullpath, "r");
102         memset(name, 0, 4096);
103         if (file) {
104                 fgets(name, 4096, file);
105                 fclose(file);
106         }
107         sprintf(fullpath, "%s/manufacturer", path);
108         file = fopen(fullpath, "r");
109         memset(vendor, 0, 4096);
110         if (file) {
111                 fgets(vendor, 4096, file);
112                 fclose(file);
113         }
114
115         if (strlen(name)>0 && name[strlen(name)-1]=='\n')
116                 name[strlen(name)-1]=0;
117         if (strlen(vendor)>0 && vendor[strlen(vendor)-1]=='\n')
118                 vendor[strlen(vendor)-1]=0;
119         /* some devices have bogus names */
120         if (strlen(name)<4)
121                 strcpy(ptr->human_name, path);
122         else
123                 sprintf(ptr->human_name, _("USB device %4s : %s (%s)"), shortname, name, vendor);
124
125         if (strstr(ptr->human_name, "Host Controller"))
126                 ptr->controller = 1;
127
128 }
129
130 void count_usb_urbs(void)
131 {
132         DIR *dir;
133         struct dirent *dirent;
134         FILE *file;
135         char filename[PATH_MAX];
136         char pathname[PATH_MAX];
137         char buffer[4096];
138         struct device_data *dev;
139         char linkto[PATH_MAX];
140
141         memset(linkto, 0, sizeof(linkto));
142
143         dir = opendir("/sys/bus/usb/devices");
144         if (!dir)
145                 return;
146
147         cachunk_urbs();
148         while ((dirent = readdir(dir))) {
149                 if (dirent->d_name[0]=='.')
150                         continue;
151
152                 sprintf(pathname, "/sys/bus/usb/devices/%s", dirent->d_name);
153                 sprintf(filename, "%s/urbnum", pathname);
154                 file = fopen(filename, "r");
155                 if (!file)
156                         continue;
157
158                 memset(buffer, 0, 4096);
159                 fgets(buffer, 4095, file);
160                 update_urbnum(pathname, strtoull(buffer, NULL, 10), dirent->d_name);
161                 fclose(file);
162         }
163
164         closedir(dir);
165
166         dev = devices;
167         while (dev) {
168                 if (dev->urbs != dev->previous_urbs) {
169                         push_line(dev->human_name, dev->urbs - dev->previous_urbs);
170                 }
171                 dev = dev->next;
172         }
173 }
174
175
176 void display_usb_activity(void)
177 {
178         struct device_data *dev;
179         printf("\n");
180         printf("%s\n", _("Recent USB suspend statistics"));
181         printf("%s\n", _("Active  Device name"));
182         dev = devices;
183         while (dev) {
184                 printf("%5.1f%%\t%s\n", 100.0*(dev->active - dev->previous_active) /
185                         (0.00001 + dev->connected - dev->previous_connected), dev->human_name);
186                 dev = dev->next;
187         }
188
189 }
190
191 void usb_activity_hint(void)
192 {
193         int total_active = 0;
194         int pick;
195         struct device_data *dev;
196         dev = devices;
197         while (dev) {
198                 if (dev->active-1 > dev->previous_active && !dev->controller)
199                         total_active++;
200                 dev = dev->next;
201         }
202         if (!total_active)
203                 return;
204
205         pick = rand() % total_active;
206         total_active = 0;
207         dev = devices;
208         while (dev) {
209                 if (dev->active-1 > dev->previous_active && !dev->controller) {
210                         if (total_active == pick) {
211                                 char usb_hint[8000];
212                                 memset(usb_hint, 0, sizeof(usb_hint));
213                                 sprintf(usb_hint, _("A USB device is active %4.1f%% of the time:\n%s"),
214                                  100.0*(dev->active - dev->previous_active) /
215                                 (0.00001 + dev->connected - dev->previous_connected),
216                                 dev->human_name);
217                                 add_suggestion(usb_hint,
218                                 1, 'U', _(" U - Enable USB suspend "), activate_usb_autosuspend);
219                         }
220                         total_active++;
221                 }
222                 dev = dev->next;
223         }
224
225 }