blob: f5aef94249822e0f3076b6d9152b07800b0677f9 [file] [log] [blame]
Arjan van der Ven9fc3a162007-10-03 20:09:00 +00001/*
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
36struct device_data;
37
38struct device_data {
39 struct device_data *next;
40 char pathname[4096];
41 char human_name[4096];
Arjan van der Vena332b9e2008-03-27 03:40:55 +000042 uint64_t urbs, active, connected;
43 uint64_t previous_urbs, previous_active, previous_connected;
Arjan van der Vene3c78822008-03-27 04:57:39 +000044 int controller;
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000045};
46
47
48static struct device_data *devices;
49
50static void cachunk_urbs(void)
51{
52 struct device_data *ptr;
53 ptr = devices;
54 while (ptr) {
55 ptr->previous_urbs = ptr->urbs;
Arjan van der Vena332b9e2008-03-27 03:40:55 +000056 ptr->previous_active = ptr->active;
57 ptr->previous_connected = ptr->connected;
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000058 ptr = ptr->next;
59 }
60}
61
Arjan van der Vena9aebd62007-10-03 20:20:19 +000062static void update_urbnum(char *path, uint64_t count, char *shortname)
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000063{
64 struct device_data *ptr;
65 FILE *file;
66 char fullpath[4096];
Arjan van der Ven442fddf2007-10-03 20:17:02 +000067 char name[4096], vendor[4096];
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000068 ptr = devices;
Arjan van der Vena332b9e2008-03-27 03:40:55 +000069
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000070 while (ptr) {
71 if (strcmp(ptr->pathname, path)==0) {
72 ptr->urbs = count;
Arjan van der Vena332b9e2008-03-27 03:40:55 +000073 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
Arjan van der Ven9fc3a162007-10-03 20:09:00 +000088 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");
Arjan van der Ven442fddf2007-10-03 20:17:02 +0000102 memset(name, 0, 4096);
Arjan van der Ven9fc3a162007-10-03 20:09:00 +0000103 if (file) {
104 fgets(name, 4096, file);
Arjan van der Ven9fc3a162007-10-03 20:09:00 +0000105 fclose(file);
106 }
Arjan van der Ven442fddf2007-10-03 20:17:02 +0000107 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
Arjan van der Ven0e06dc22007-10-03 20:21:58 +0000123 sprintf(ptr->human_name, _("USB device %4s : %s (%s)"), shortname, name, vendor);
Arjan van der Vene3c78822008-03-27 04:57:39 +0000124
125 if (strstr(ptr->human_name, "Host Controller"))
126 ptr->controller = 1;
Arjan van der Ven9fc3a162007-10-03 20:09:00 +0000127
128}
129
130void 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
140 dir = opendir("/sys/bus/usb/devices");
141 if (!dir)
142 return;
143
144 cachunk_urbs();
145 while ((dirent = readdir(dir))) {
146 if (dirent->d_name[0]=='.')
147 continue;
148 sprintf(pathname, "/sys/bus/usb/devices/%s", dirent->d_name);
149 sprintf(filename, "%s/urbnum", pathname);
150 file = fopen(filename, "r");
151 if (!file)
152 continue;
153 memset(buffer, 0, 4096);
154 fgets(buffer, 4095, file);
Arjan van der Vena9aebd62007-10-03 20:20:19 +0000155 update_urbnum(pathname, strtoull(buffer, NULL, 10), dirent->d_name);
Arjan van der Ven9fc3a162007-10-03 20:09:00 +0000156 fclose(file);
157 }
158
159 closedir(dir);
160
161 dev = devices;
162 while (dev) {
163 if (dev->urbs != dev->previous_urbs) {
164 push_line(dev->human_name, dev->urbs - dev->previous_urbs);
165 }
166 dev = dev->next;
167 }
168}
169
Arjan van der Vena332b9e2008-03-27 03:40:55 +0000170
171void display_usb_activity(void)
172{
173 struct device_data *dev;
174 printf("\n");
175 printf("%s\n", _("Recent USB suspend statistics"));
176 printf("%s\n", _("Active Device name"));
177 dev = devices;
178 while (dev) {
179 printf("%5.1f%%\t%s\n", 100.0*(dev->active - dev->previous_active) /
180 (0.00001 + dev->connected - dev->previous_connected), dev->human_name);
181 dev = dev->next;
182 }
183
Arjan van der Venbe2c50b2008-03-27 04:30:50 +0000184}
Arjan van der Vene3c78822008-03-27 04:57:39 +0000185
186void usb_activity_hint(void)
187{
188 int total_active = 0;
189 int pick;
190 struct device_data *dev;
191 dev = devices;
192 while (dev) {
193 if (dev->active-1 > dev->previous_active && !dev->controller)
194 total_active++;
195 dev = dev->next;
196 }
197 if (!total_active)
198 return;
199
200 pick = rand() % total_active;
201 total_active = 0;
202 dev = devices;
203 while (dev) {
204 if (dev->active-1 > dev->previous_active && !dev->controller) {
205 if (total_active == pick) {
206 char usb_hint[8000];
207 sprintf(usb_hint, _("A USB device is active %4.1f%% of the time:\n%s"),
208 100.0*(dev->active - dev->previous_active) /
209 (0.00001 + dev->connected - dev->previous_connected),
210 dev->human_name);
211 add_suggestion(usb_hint,
212 1, 'U', _(" U - Enable USB suspend "), activate_usb_autosuspend);
213 }
214 total_active++;
215 }
216 dev = dev->next;
217 }
218
219}