xref: /OK3568_Linux_fs/kernel/tools/laptop/dslm/dslm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * dslm.c
3*4882a593Smuzhiyun  * Simple Disk Sleep Monitor
4*4882a593Smuzhiyun  *  by Bartek Kania
5*4882a593Smuzhiyun  * Licensed under the GPL
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <unistd.h>
8*4882a593Smuzhiyun #include <stdlib.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <fcntl.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun #include <time.h>
13*4882a593Smuzhiyun #include <string.h>
14*4882a593Smuzhiyun #include <signal.h>
15*4882a593Smuzhiyun #include <sys/ioctl.h>
16*4882a593Smuzhiyun #include <linux/hdreg.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #ifdef DEBUG
19*4882a593Smuzhiyun #define D(x) x
20*4882a593Smuzhiyun #else
21*4882a593Smuzhiyun #define D(x)
22*4882a593Smuzhiyun #endif
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun int endit = 0;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* Check if the disk is in powersave-mode
27*4882a593Smuzhiyun  * Most of the code is stolen from hdparm.
28*4882a593Smuzhiyun  * 1 = active, 0 = standby/sleep, -1 = unknown */
check_powermode(int fd)29*4882a593Smuzhiyun static int check_powermode(int fd)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun     unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
32*4882a593Smuzhiyun     int state;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun     if (ioctl(fd, HDIO_DRIVE_CMD, &args)
35*4882a593Smuzhiyun 	&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
36*4882a593Smuzhiyun 	&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
37*4882a593Smuzhiyun 	if (errno != EIO || args[0] != 0 || args[1] != 0) {
38*4882a593Smuzhiyun 	    state = -1; /* "unknown"; */
39*4882a593Smuzhiyun 	} else
40*4882a593Smuzhiyun 	    state = 0; /* "sleeping"; */
41*4882a593Smuzhiyun     } else {
42*4882a593Smuzhiyun 	state = (args[2] == 255) ? 1 : 0;
43*4882a593Smuzhiyun     }
44*4882a593Smuzhiyun     D(printf(" drive state is:  %d\n", state));
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun     return state;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
state_name(int i)49*4882a593Smuzhiyun static char *state_name(int i)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun     if (i == -1) return "unknown";
52*4882a593Smuzhiyun     if (i == 0) return "sleeping";
53*4882a593Smuzhiyun     if (i == 1) return "active";
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun     return "internal error";
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
myctime(time_t time)58*4882a593Smuzhiyun static char *myctime(time_t time)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun     char *ts = ctime(&time);
61*4882a593Smuzhiyun     ts[strlen(ts) - 1] = 0;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun     return ts;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
measure(int fd)66*4882a593Smuzhiyun static void measure(int fd)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun     time_t start_time;
69*4882a593Smuzhiyun     int last_state;
70*4882a593Smuzhiyun     time_t last_time;
71*4882a593Smuzhiyun     int curr_state;
72*4882a593Smuzhiyun     time_t curr_time = 0;
73*4882a593Smuzhiyun     time_t time_diff;
74*4882a593Smuzhiyun     time_t active_time = 0;
75*4882a593Smuzhiyun     time_t sleep_time = 0;
76*4882a593Smuzhiyun     time_t unknown_time = 0;
77*4882a593Smuzhiyun     time_t total_time = 0;
78*4882a593Smuzhiyun     int changes = 0;
79*4882a593Smuzhiyun     float tmp;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun     printf("Starting measurements\n");
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun     last_state = check_powermode(fd);
84*4882a593Smuzhiyun     start_time = last_time = time(0);
85*4882a593Smuzhiyun     printf("  System is in state %s\n\n", state_name(last_state));
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun     while(!endit) {
88*4882a593Smuzhiyun 	sleep(1);
89*4882a593Smuzhiyun 	curr_state = check_powermode(fd);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (curr_state != last_state || endit) {
92*4882a593Smuzhiyun 	    changes++;
93*4882a593Smuzhiyun 	    curr_time = time(0);
94*4882a593Smuzhiyun 	    time_diff = curr_time - last_time;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	    if (last_state == 1) active_time += time_diff;
97*4882a593Smuzhiyun 	    else if (last_state == 0) sleep_time += time_diff;
98*4882a593Smuzhiyun 	    else unknown_time += time_diff;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	    last_state = curr_state;
101*4882a593Smuzhiyun 	    last_time = curr_time;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	    printf("%s: State-change to %s\n", myctime(curr_time),
104*4882a593Smuzhiyun 		   state_name(curr_state));
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun     }
107*4882a593Smuzhiyun     changes--; /* Compensate for SIGINT */
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun     total_time = time(0) - start_time;
110*4882a593Smuzhiyun     printf("\nTotal running time:  %lus\n", curr_time - start_time);
111*4882a593Smuzhiyun     printf(" State changed %d times\n", changes);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun     tmp = (float)sleep_time / (float)total_time * 100;
114*4882a593Smuzhiyun     printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
115*4882a593Smuzhiyun     tmp = (float)active_time / (float)total_time * 100;
116*4882a593Smuzhiyun     printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
117*4882a593Smuzhiyun     tmp = (float)unknown_time / (float)total_time * 100;
118*4882a593Smuzhiyun     printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
ender(int s)121*4882a593Smuzhiyun static void ender(int s)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun     endit = 1;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
usage(void)126*4882a593Smuzhiyun static void usage(void)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun     puts("usage: dslm [-w <time>] <disk>");
129*4882a593Smuzhiyun     exit(0);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
main(int argc,char ** argv)132*4882a593Smuzhiyun int main(int argc, char **argv)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun     int fd;
135*4882a593Smuzhiyun     char *disk = 0;
136*4882a593Smuzhiyun     int settle_time = 60;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun     /* Parse the simple command-line */
139*4882a593Smuzhiyun     if (argc == 2)
140*4882a593Smuzhiyun 	disk = argv[1];
141*4882a593Smuzhiyun     else if (argc == 4) {
142*4882a593Smuzhiyun 	settle_time = atoi(argv[2]);
143*4882a593Smuzhiyun 	disk = argv[3];
144*4882a593Smuzhiyun     } else
145*4882a593Smuzhiyun 	usage();
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun     if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
148*4882a593Smuzhiyun 	printf("Can't open %s, because: %s\n", disk, strerror(errno));
149*4882a593Smuzhiyun 	exit(-1);
150*4882a593Smuzhiyun     }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun     if (settle_time) {
153*4882a593Smuzhiyun 	printf("Waiting %d seconds for the system to settle down to "
154*4882a593Smuzhiyun 	       "'normal'\n", settle_time);
155*4882a593Smuzhiyun 	sleep(settle_time);
156*4882a593Smuzhiyun     } else
157*4882a593Smuzhiyun 	puts("Not waiting for system to settle down");
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun     signal(SIGINT, ender);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun     measure(fd);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun     close(fd);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun     return 0;
166*4882a593Smuzhiyun }
167