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