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