Merge commit 'brent/register_phys_mem'
[freebsd-src/fkvm-freebsd.git] / usr.sbin / apm / apm.c
blob56432a4ab7a234c6e7e2f5f1423036907e4586cb
1 /*
2 * apm / zzz APM BIOS utility for FreeBSD
4 * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
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.
13 * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
19 #include <sys/file.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
24 #include <machine/apm_bios.h>
26 #include <err.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
33 #define APMDEV "/dev/apm"
35 #define APM_UNKNOWN 255
37 #define xh(a) (((a) & 0xff00) >> 8)
38 #define xl(a) ((a) & 0xff)
39 #define APMERR(a) xh(a)
41 int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
43 static void
44 usage(void)
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);
54 * Return 1 for boolean true, and 0 for false, according to the
55 * interpretation of the string argument given.
57 static int
58 is_true(const char *boolean)
60 char *endp;
61 long val;
63 val = strtoul(boolean, &endp, 0);
64 if (*endp == '\0')
65 return (val != 0 ? 1 : 0);
66 if (strcasecmp(boolean, "true") == 0 ||
67 strcasecmp(boolean, "yes") == 0 ||
68 strcasecmp(boolean, "enable") == 0)
69 return (1);
70 if (strcasecmp(boolean, "false") == 0 ||
71 strcasecmp(boolean, "no") == 0 ||
72 strcasecmp(boolean, "disable") == 0)
73 return (0);
74 /* Well, I have no idea what the user wants, so... */
75 warnx("invalid boolean argument \"%s\"", boolean);
76 usage();
77 /* NOTREACHED */
79 return (0);
82 static int
83 int2bcd(int i)
85 int retval = 0;
86 int base = 0;
88 if (i >= 10000)
89 return -1;
91 while (i) {
92 retval |= (i % 10) << base;
93 i /= 10;
94 base += 4;
96 return retval;
99 static int
100 bcd2int(int bcd)
102 int retval = 0;
103 int place = 1;
105 if (bcd > 0x9999)
106 return -1;
108 while (bcd) {
109 retval += (bcd & 0xf) * place;
110 bcd >>= 4;
111 place *= 10;
113 return retval;
116 static void
117 apm_suspend(int fd)
119 if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
120 err(1, "ioctl(APMIO_SUSPEND)");
123 static void
124 apm_standby(int fd)
126 if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
127 err(1, "ioctl(APMIO_STANDBY)");
130 static void
131 apm_getinfo(int fd, apm_info_t aip)
133 if (ioctl(fd, APMIO_GETINFO, aip) == -1)
134 err(1, "ioctl(APMIO_GETINFO)");
137 static void
138 apm_enable(int fd, int enable)
140 if (enable) {
141 if (ioctl(fd, APMIO_ENABLE) == -1)
142 err(1, "ioctl(APMIO_ENABLE)");
143 } else {
144 if (ioctl(fd, APMIO_DISABLE) == -1)
145 err(1, "ioctl(APMIO_DISABLE)");
149 static void
150 print_batt_time(int batt_time)
152 printf("Remaining battery time: ");
153 if (batt_time == -1)
154 printf("unknown\n");
155 else {
156 int h, m, s;
158 h = batt_time;
159 s = h % 60;
160 h /= 60;
161 m = h % 60;
162 h /= 60;
163 printf("%2d:%02d:%02d\n", h, m, s);
167 static void
168 print_batt_life(u_int batt_life)
170 printf("Remaining battery life: ");
171 if (batt_life == APM_UNKNOWN)
172 printf("unknown\n");
173 else if (batt_life <= 100)
174 printf("%d%%\n", batt_life);
175 else
176 printf("invalid value (0x%x)\n", batt_life);
179 static void
180 print_batt_stat(u_int batt_stat)
182 const char *batt_msg[] = { "high", "low", "critical", "charging" };
184 printf("Battery Status: ");
185 if (batt_stat == APM_UNKNOWN)
186 printf("unknown\n");
187 else if (batt_stat > 3)
188 printf("invalid value (0x%x)\n", batt_stat);
189 else
190 printf("%s\n", batt_msg[batt_stat]);
193 static void
194 print_all_info(int fd, apm_info_t aip, int bioscall_available)
196 struct apm_bios_arg args;
197 int apmerr;
198 const char *line_msg[] = { "off-line", "on-line" , "backup power"};
200 printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
201 printf("APM Management: %s\n", aip->ai_status ? "Enabled" : "Disabled");
202 printf("AC Line status: ");
203 if (aip->ai_acline == APM_UNKNOWN)
204 printf("unknown\n");
205 else if (aip->ai_acline > 2)
206 printf("invalid value (0x%x)\n", aip->ai_acline);
207 else
208 printf("%s\n", line_msg[aip->ai_acline]);
210 print_batt_stat(aip->ai_batt_stat);
211 print_batt_life(aip->ai_batt_life);
212 print_batt_time(aip->ai_batt_time);
214 if (aip->ai_infoversion >= 1) {
215 printf("Number of batteries: ");
216 if (aip->ai_batteries == ~0U)
217 printf("unknown\n");
218 else {
219 u_int i;
220 struct apm_pwstatus aps;
222 printf("%d\n", aip->ai_batteries);
223 for (i = 0; i < aip->ai_batteries; ++i) {
224 bzero(&aps, sizeof(aps));
225 aps.ap_device = PMDV_BATT0 + i;
226 if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1)
227 continue;
228 printf("Battery %d:\n", i);
229 if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) {
230 printf("not present\n");
231 continue;
233 printf("\t");
234 print_batt_stat(aps.ap_batt_stat);
235 printf("\t");
236 print_batt_life(aps.ap_batt_life);
237 printf("\t");
238 print_batt_time(aps.ap_batt_time);
243 if (bioscall_available) {
245 * try to get the suspend timer
247 bzero(&args, sizeof(args));
248 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
249 args.ebx = PMDV_APMBIOS;
250 args.ecx = 0x0001;
251 if (ioctl(fd, APMIO_BIOS, &args)) {
252 printf("Resume timer: unknown\n");
253 } else {
254 apmerr = APMERR(args.eax);
255 if (apmerr == 0x0d || apmerr == 0x86)
256 printf("Resume timer: disabled\n");
257 else if (apmerr)
258 warnx(
259 "failed to get the resume timer: APM error0x%x", apmerr);
260 else {
262 * OK. We have the time (all bcd).
263 * CH - seconds
264 * DH - hours
265 * DL - minutes
266 * xh(SI) - month (1-12)
267 * xl(SI) - day of month (1-31)
268 * DI - year
270 struct tm tm;
271 char buf[1024];
272 time_t t;
274 tm.tm_sec = bcd2int(xh(args.ecx));
275 tm.tm_min = bcd2int(xl(args.edx));
276 tm.tm_hour = bcd2int(xh(args.edx));
277 tm.tm_mday = bcd2int(xl(args.esi));
278 tm.tm_mon = bcd2int(xh(args.esi)) - 1;
279 tm.tm_year = bcd2int(args.edi) - 1900;
280 if (cmos_wall)
281 t = mktime(&tm);
282 else
283 t = timegm(&tm);
284 if (t != -1) {
285 tm = *localtime(&t);
286 strftime(buf, sizeof(buf), "%c", &tm);
287 printf("Resume timer: %s\n", buf);
288 } else
289 printf("Resume timer: unknown\n");
294 * Get the ring indicator resume state
296 bzero(&args, sizeof(args));
297 args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING;
298 args.ebx = PMDV_APMBIOS;
299 args.ecx = 0x0002;
300 if (ioctl(fd, APMIO_BIOS, &args) == 0) {
301 printf("Resume on ring indicator: %sabled\n",
302 args.ecx ? "en" : "dis");
306 if (aip->ai_infoversion >= 1) {
307 if (aip->ai_capabilities == 0xff00)
308 return;
309 printf("APM Capabilities:\n");
310 if (aip->ai_capabilities & 0x01)
311 printf("\tglobal standby state\n");
312 if (aip->ai_capabilities & 0x02)
313 printf("\tglobal suspend state\n");
314 if (aip->ai_capabilities & 0x04)
315 printf("\tresume timer from standby\n");
316 if (aip->ai_capabilities & 0x08)
317 printf("\tresume timer from suspend\n");
318 if (aip->ai_capabilities & 0x10)
319 printf("\tRI resume from standby\n");
320 if (aip->ai_capabilities & 0x20)
321 printf("\tRI resume from suspend\n");
322 if (aip->ai_capabilities & 0x40)
323 printf("\tPCMCIA RI resume from standby\n");
324 if (aip->ai_capabilities & 0x80)
325 printf("\tPCMCIA RI resume from suspend\n");
331 * currently, it can turn off the display, but the display never comes
332 * back until the machine suspend/resumes :-).
334 static void
335 apm_display(int fd, int newstate)
337 if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
338 err(1, "ioctl(APMIO_DISPLAY)");
341 static void
342 apm_haltcpu(int fd, int enable)
344 if (enable) {
345 if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
346 err(1, "ioctl(APMIO_HALTCPU)");
347 } else {
348 if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
349 err(1, "ioctl(APMIO_NOTHALTCPU)");
353 static void
354 apm_set_timer(int fd, int delta)
356 time_t tmr;
357 struct tm *tm;
358 struct apm_bios_arg args;
360 tmr = time(NULL) + delta;
361 if (cmos_wall)
362 tm = localtime(&tmr);
363 else
364 tm = gmtime(&tmr);
365 bzero(&args, sizeof(args));
366 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
367 args.ebx = PMDV_APMBIOS;
368 if (delta > 0) {
369 args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02;
370 args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min);
371 args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday);
372 args.edi = int2bcd(tm->tm_year + 1900);
373 } else {
374 args.ecx = 0x0000;
376 if (ioctl(fd, APMIO_BIOS, &args)) {
377 err(1,"set resume timer");
381 int
382 main(int argc, char *argv[])
384 int c, fd;
385 int dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
386 int display = -1, batt_life = 0, ac_status = 0, standby = 0;
387 int batt_time = 0, delta = 0, enable = -1, haltcpu = -1;
388 char *cmdname;
389 int bioscall_available = 0;
390 size_t cmos_wall_len = sizeof(cmos_wall);
392 if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
393 NULL, 0) == -1)
394 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
395 if ((cmdname = strrchr(argv[0], '/')) != NULL)
396 cmdname++;
397 else
398 cmdname = argv[0];
400 if (strcmp(cmdname, "zzz") == 0) {
401 dosleep = 1;
402 all_info = 0;
403 goto finish_option;
405 while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
406 switch (c) {
407 case 'a':
408 ac_status = 1;
409 all_info = 0;
410 break;
411 case 'b':
412 batt_status = 1;
413 all_info = 0;
414 break;
415 case 'd':
416 display = is_true(optarg);
417 all_info = 0;
418 break;
419 case 'l':
420 batt_life = 1;
421 all_info = 0;
422 break;
423 case 'R':
424 delta = -1;
425 break;
426 case 'r':
427 delta = atoi(optarg);
428 break;
429 case 's':
430 apm_status = 1;
431 all_info = 0;
432 break;
433 case 'e':
434 enable = is_true(optarg);
435 all_info = 0;
436 break;
437 case 'h':
438 haltcpu = is_true(optarg);
439 all_info = 0;
440 break;
441 case 't':
442 batt_time = 1;
443 all_info = 0;
444 break;
445 case 'z':
446 dosleep = 1;
447 all_info = 0;
448 break;
449 case 'Z':
450 standby = 1;
451 all_info = 0;
452 break;
453 case '?':
454 default:
455 usage();
457 argc -= optind;
458 argv += optind;
460 finish_option:
461 if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
462 || standby) {
463 fd = open(APMDEV, O_RDWR);
464 bioscall_available = 1;
465 } else if ((fd = open(APMDEV, O_RDWR)) >= 0)
466 bioscall_available = 1;
467 else
468 fd = open(APMDEV, O_RDONLY);
469 if (fd == -1)
470 err(1, "can't open %s", APMDEV);
471 if (enable != -1)
472 apm_enable(fd, enable);
473 if (haltcpu != -1)
474 apm_haltcpu(fd, haltcpu);
475 if (delta)
476 apm_set_timer(fd, delta);
477 if (dosleep)
478 apm_suspend(fd);
479 else if (standby)
480 apm_standby(fd);
481 else if (delta == 0) {
482 struct apm_info info;
484 apm_getinfo(fd, &info);
485 if (all_info)
486 print_all_info(fd, &info, bioscall_available);
487 if (ac_status)
488 printf("%d\n", info.ai_acline);
489 if (batt_status)
490 printf("%d\n", info.ai_batt_stat);
491 if (batt_life)
492 printf("%d\n", info.ai_batt_life);
493 if (apm_status)
494 printf("%d\n", info.ai_status);
495 if (batt_time)
496 printf("%d\n", info.ai_batt_time);
497 if (display != -1)
498 apm_display(fd, display);
500 close(fd);
501 exit(0);