]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/apm/apm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / apm / apm.c
1 /*
2  * APM BIOS utility for FreeBSD
3  *
4  * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
5  *
6  * This software may be used, modified, copied, distributed, and sold,
7  * in both source and binary form provided that the above copyright and
8  * these terms are retained. Under no circumstances is the author
9  * responsible for the proper functioning of this software, nor does
10  * the author assume any responsibility for damages incurred with its
11  * use.
12  *
13  * Sep., 1994   Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
14  */
15
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
18
19 #include <sys/file.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
23
24 #include <machine/apm_bios.h>
25
26 #include <err.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #define APMDEV  "/dev/apm"
34
35 #define APM_UNKNOWN     255
36
37 #define xh(a)   (((a) & 0xff00) >> 8)
38 #define xl(a)   ((a) & 0xff)
39 #define APMERR(a) xh(a)
40
41 static int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
42
43 static void
44 usage(void)
45 {
46         fprintf(stderr,
47                 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
48                 "[ -h enable ] [-r delta]\n");
49         exit(1);
50 }
51
52 /*
53  * Return 1 for boolean true, and 0 for false, according to the
54  * interpretation of the string argument given.
55  */
56 static int
57 is_true(const char *boolean)
58 {
59         char *endp;
60         long val;
61
62         val = strtoul(boolean, &endp, 0);
63         if (*endp == '\0')
64                 return (val != 0 ? 1 : 0);
65         if (strcasecmp(boolean, "true") == 0 ||
66             strcasecmp(boolean, "yes") == 0 ||
67             strcasecmp(boolean, "enable") == 0)
68                 return (1);
69         if (strcasecmp(boolean, "false") == 0 ||
70             strcasecmp(boolean, "no") == 0 ||
71             strcasecmp(boolean, "disable") == 0)
72                 return (0);
73         /* Well, I have no idea what the user wants, so... */
74         warnx("invalid boolean argument \"%s\"", boolean);
75         usage();
76         /* NOTREACHED */
77
78         return (0);
79 }
80
81 static int
82 int2bcd(int i)
83 {
84         int retval = 0;
85         int base = 0;
86
87         if (i >= 10000)
88                 return -1;
89     
90         while (i) {
91                 retval |= (i % 10) << base;
92                 i /= 10;
93                 base += 4;
94         }
95         return retval;
96 }
97
98 static int
99 bcd2int(int bcd)
100 {
101         int retval = 0;
102         int place = 1;
103
104         if (bcd > 0x9999)
105                 return -1;
106
107         while (bcd) {
108                 retval += (bcd & 0xf) * place;
109                 bcd >>= 4;
110                 place *= 10;
111         }
112         return retval;
113 }
114
115 static void 
116 apm_suspend(int fd)
117 {
118         if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
119                 err(1, "ioctl(APMIO_SUSPEND)");
120 }
121
122 static void 
123 apm_standby(int fd)
124 {
125         if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
126                 err(1, "ioctl(APMIO_STANDBY)");
127 }
128
129 static void 
130 apm_getinfo(int fd, apm_info_t aip)
131 {
132         if (ioctl(fd, APMIO_GETINFO, aip) == -1)
133                 err(1, "ioctl(APMIO_GETINFO)");
134 }
135
136 static void 
137 apm_enable(int fd, int enable) 
138 {
139         if (enable) {
140                 if (ioctl(fd, APMIO_ENABLE) == -1)
141                         err(1, "ioctl(APMIO_ENABLE)");
142         } else {
143                 if (ioctl(fd, APMIO_DISABLE) == -1)
144                         err(1, "ioctl(APMIO_DISABLE)");
145         }
146 }
147
148 static void
149 print_batt_time(int batt_time)
150 {
151         printf("Remaining battery time: ");
152         if (batt_time == -1)
153                 printf("unknown\n");
154         else {
155                 int h, m, s;
156
157                 h = batt_time;
158                 s = h % 60;
159                 h /= 60;
160                 m = h % 60;
161                 h /= 60;
162                 printf("%2d:%02d:%02d\n", h, m, s);
163         }
164 }
165
166 static void
167 print_batt_life(u_int batt_life)
168 {
169         printf("Remaining battery life: ");
170         if (batt_life == APM_UNKNOWN)
171                 printf("unknown\n");
172         else if (batt_life <= 100)
173                 printf("%d%%\n", batt_life);
174         else
175                 printf("invalid value (0x%x)\n", batt_life);
176 }
177
178 static void
179 print_batt_stat(u_int batt_stat)
180 {
181         const char *batt_msg[] = { "high", "low", "critical", "charging" };
182
183         printf("Battery Status: ");
184         if (batt_stat == APM_UNKNOWN)
185                 printf("unknown\n");
186         else if (batt_stat > 3)
187                 printf("invalid value (0x%x)\n", batt_stat);
188         else
189                 printf("%s\n", batt_msg[batt_stat]);
190 }
191
192 static void 
193 print_all_info(int fd, apm_info_t aip, int bioscall_available)
194 {
195         struct apm_bios_arg args;
196         int apmerr;
197         const char *line_msg[] = { "off-line", "on-line" , "backup power"};
198
199         printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
200         printf("APM Management: %s\n", aip->ai_status ? "Enabled" : "Disabled");
201         printf("AC Line status: ");
202         if (aip->ai_acline == APM_UNKNOWN)
203                 printf("unknown\n");
204         else if (aip->ai_acline > 2)
205                 printf("invalid value (0x%x)\n", aip->ai_acline);
206         else
207                 printf("%s\n", line_msg[aip->ai_acline]);
208
209         print_batt_stat(aip->ai_batt_stat);
210         print_batt_life(aip->ai_batt_life);
211         print_batt_time(aip->ai_batt_time);
212
213         if (aip->ai_infoversion >= 1) {
214                 printf("Number of batteries: ");
215                 if (aip->ai_batteries == ~0U)
216                         printf("unknown\n");
217                 else {
218                         u_int i;
219                         struct apm_pwstatus aps;
220
221                         printf("%d\n", aip->ai_batteries);
222                         for (i = 0; i < aip->ai_batteries; ++i) {
223                                 bzero(&aps, sizeof(aps));
224                                 aps.ap_device = PMDV_BATT0 + i;
225                                 if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1)
226                                         continue;
227                                 printf("Battery %d:\n", i);
228                                 if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) {
229                                         printf("not present\n");
230                                         continue;
231                                 }
232                                 printf("\t");
233                                 print_batt_stat(aps.ap_batt_stat);
234                                 printf("\t");
235                                 print_batt_life(aps.ap_batt_life);
236                                 printf("\t");
237                                 print_batt_time(aps.ap_batt_time);
238                         }
239                 }
240         }
241
242         if (bioscall_available) {
243                 /*
244                  * try to get the suspend timer
245                  */
246                 bzero(&args, sizeof(args));
247                 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
248                 args.ebx = PMDV_APMBIOS;
249                 args.ecx = 0x0001;
250                 if (ioctl(fd, APMIO_BIOS, &args)) {
251                         printf("Resume timer: unknown\n");
252                 } else {
253                         apmerr = APMERR(args.eax);
254                         if (apmerr == 0x0d || apmerr == 0x86)
255                                 printf("Resume timer: disabled\n");
256                         else if (apmerr)
257                                 warnx(
258                 "failed to get the resume timer: APM error0x%x", apmerr);
259                         else {
260                                 /*
261                                  * OK.  We have the time (all bcd).
262                                  * CH - seconds
263                                  * DH - hours
264                                  * DL - minutes
265                                  * xh(SI) - month (1-12)
266                                  * xl(SI) - day of month (1-31)
267                                  * DI - year
268                                  */
269                                 struct tm tm;
270                                 char buf[1024];
271                                 time_t t;
272
273                                 tm.tm_sec = bcd2int(xh(args.ecx));
274                                 tm.tm_min = bcd2int(xl(args.edx));
275                                 tm.tm_hour = bcd2int(xh(args.edx));
276                                 tm.tm_mday = bcd2int(xl(args.esi));
277                                 tm.tm_mon = bcd2int(xh(args.esi)) - 1;
278                                 tm.tm_year = bcd2int(args.edi) - 1900;
279                                 if (cmos_wall)
280                                         t = mktime(&tm);
281                                 else
282                                         t = timegm(&tm);
283                                 if (t != -1) {
284                                         tm = *localtime(&t);
285                                         strftime(buf, sizeof(buf), "%c", &tm);
286                                         printf("Resume timer: %s\n", buf);
287                                 } else
288                                         printf("Resume timer: unknown\n");
289                         }
290                 }
291
292                 /*
293                  * Get the ring indicator resume state
294                  */
295                 bzero(&args, sizeof(args));
296                 args.eax  = (APM_BIOS) << 8 | APM_RESUMEONRING;
297                 args.ebx = PMDV_APMBIOS;
298                 args.ecx = 0x0002;
299                 if (ioctl(fd, APMIO_BIOS, &args) == 0) {
300                         printf("Resume on ring indicator: %sabled\n",
301                             args.ecx ? "en" : "dis");
302                 }
303         }
304
305         if (aip->ai_infoversion >= 1) {
306                 if (aip->ai_capabilities == 0xff00)
307                     return;
308                 printf("APM Capabilities:\n");
309                 if (aip->ai_capabilities & 0x01)
310                         printf("\tglobal standby state\n");
311                 if (aip->ai_capabilities & 0x02)
312                         printf("\tglobal suspend state\n");
313                 if (aip->ai_capabilities & 0x04)
314                         printf("\tresume timer from standby\n");
315                 if (aip->ai_capabilities & 0x08)
316                         printf("\tresume timer from suspend\n");
317                 if (aip->ai_capabilities & 0x10)
318                         printf("\tRI resume from standby\n");
319                 if (aip->ai_capabilities & 0x20)
320                         printf("\tRI resume from suspend\n");
321                 if (aip->ai_capabilities & 0x40)
322                         printf("\tPCMCIA RI resume from standby\n");
323                 if (aip->ai_capabilities & 0x80)
324                         printf("\tPCMCIA RI resume from suspend\n");
325         }
326
327 }
328
329 /*
330  * currently, it can turn off the display, but the display never comes
331  * back until the machine suspend/resumes :-).
332  */
333 static void 
334 apm_display(int fd, int newstate)
335 {
336         if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
337                 err(1, "ioctl(APMIO_DISPLAY)");
338 }
339
340 static void
341 apm_haltcpu(int fd, int enable)
342 {
343         if (enable) {
344                 if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
345                         err(1, "ioctl(APMIO_HALTCPU)");
346         } else {
347                 if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
348                         err(1, "ioctl(APMIO_NOTHALTCPU)");
349         }
350 }
351
352 static void
353 apm_set_timer(int fd, int delta)
354 {
355         time_t tmr;
356         struct tm *tm;
357         struct apm_bios_arg args;
358
359         tmr = time(NULL) + delta;
360         if (cmos_wall)
361                 tm = localtime(&tmr);
362         else
363                 tm = gmtime(&tmr);
364         bzero(&args, sizeof(args));
365         args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
366         args.ebx = PMDV_APMBIOS;
367         if (delta > 0) {
368                 args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02;
369                 args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min);
370                 args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday);
371                 args.edi = int2bcd(tm->tm_year + 1900);
372         } else {
373                 args.ecx = 0x0000;
374         }
375         if (ioctl(fd, APMIO_BIOS, &args)) {
376                 err(1,"set resume timer");
377         }
378 }
379
380 int 
381 main(int argc, char *argv[])
382 {
383         int     c, fd;
384         int     dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
385         int     display = -1, batt_life = 0, ac_status = 0, standby = 0;
386         int     batt_time = 0, delta = 0, enable = -1, haltcpu = -1;
387         int     bioscall_available = 0;
388         size_t  cmos_wall_len = sizeof(cmos_wall);
389
390         if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
391             NULL, 0) == -1)
392                 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
393
394         while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
395                 switch (c) {
396                 case 'a':
397                         ac_status = 1;
398                         all_info = 0;
399                         break;
400                 case 'b':
401                         batt_status = 1;
402                         all_info = 0;
403                         break;
404                 case 'd':
405                         display = is_true(optarg);
406                         all_info = 0;
407                         break;
408                 case 'l':
409                         batt_life = 1;
410                         all_info = 0;
411                         break;
412                 case 'R':
413                         delta = -1;
414                         break;
415                 case 'r':
416                         delta = atoi(optarg);
417                         break;
418                 case 's':
419                         apm_status = 1;
420                         all_info = 0;
421                         break;
422                 case 'e':
423                         enable = is_true(optarg);
424                         all_info = 0;
425                         break;
426                 case 'h':
427                         haltcpu = is_true(optarg);
428                         all_info = 0;
429                         break;
430                 case 't':
431                         batt_time = 1;
432                         all_info = 0;
433                         break;
434                 case 'z':
435                         dosleep = 1;
436                         all_info = 0;
437                         break;
438                 case 'Z':
439                         standby = 1;
440                         all_info = 0;
441                         break;
442                 case '?':
443                 default:
444                         usage();
445                 }
446                 argc -= optind;
447                 argv += optind;
448         }
449         if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
450             || standby) {
451                 fd = open(APMDEV, O_RDWR);
452                 bioscall_available = 1;
453         } else if ((fd = open(APMDEV, O_RDWR)) >= 0)
454                 bioscall_available = 1;
455         else
456                 fd = open(APMDEV, O_RDONLY);
457         if (fd == -1)
458                 err(1, "can't open %s", APMDEV);
459         if (enable != -1)
460                 apm_enable(fd, enable);
461         if (haltcpu != -1)
462                 apm_haltcpu(fd, haltcpu);
463         if (delta)
464                 apm_set_timer(fd, delta);
465         if (dosleep)
466                 apm_suspend(fd);
467         else if (standby)
468                 apm_standby(fd);
469         else if (delta == 0) {
470                 struct apm_info info;
471
472                 apm_getinfo(fd, &info);
473                 if (all_info)
474                         print_all_info(fd, &info, bioscall_available);
475                 if (ac_status)
476                         printf("%d\n", info.ai_acline);
477                 if (batt_status)
478                         printf("%d\n", info.ai_batt_stat);
479                 if (batt_life)
480                         printf("%d\n", info.ai_batt_life);
481                 if (apm_status)
482                         printf("%d\n", info.ai_status);
483                 if (batt_time)
484                         printf("%d\n", info.ai_batt_time);
485                 if (display != -1)
486                         apm_display(fd, display);
487         }
488         close(fd);
489         exit(0);
490 }