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