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
13 * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
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.3 2004/08/13 18:41:45 asmodai Exp $
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
24 #include <machine/apm_bios.h>
31 #include <sys/ioctl.h>
35 #define APMDEV "/dev/apm"
37 #define xh(a) (((a) & 0xff00) >> 8)
38 #define xl(a) ((a) & 0xff)
39 #define APMERR(a) xh(a)
41 void apm_display(int, int);
42 void apm_enable(int, int);
43 void apm_getinfo(int, apm_info_t);
44 void apm_haltcpu(int, int);
45 void apm_set_timer(int, int);
46 void apm_standby(int);
47 void apm_suspend(int);
50 int is_true(const char *);
51 void print_all_info(int, apm_info_t, int);
54 int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
59 fprintf(stderr, "%s\n%s\n",
60 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
61 "[ -h enable ] [-r delta]",
67 * Return 1 for boolean true, and 0 for false, according to the
68 * interpretation of the string argument given.
71 is_true(const char *boolean) {
75 val = strtoul(boolean, &endp, 0);
77 return (val != 0 ? 1 : 0);
78 if (strcasecmp(boolean, "true") == 0 ||
79 strcasecmp(boolean, "yes") == 0 ||
80 strcasecmp(boolean, "enable") == 0)
82 if (strcasecmp(boolean, "false") == 0 ||
83 strcasecmp(boolean, "no") == 0 ||
84 strcasecmp(boolean, "disable") == 0)
86 /* Well, I have no idea what the user wants, so... */
87 warnx("invalid boolean argument \"%s\"", boolean);
102 retval |= (i % 10) << base;
119 retval += (bcd & 0xf) * place;
129 if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
130 err(1, "ioctl(APMIO_SUSPEND)");
136 if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
137 err(1, "ioctl(APMIO_STANDBY)");
141 apm_getinfo(int fd, apm_info_t aip)
143 if (ioctl(fd, APMIO_GETINFO, aip) == -1)
144 err(1, "ioctl(APMIO_GETINFO)");
148 apm_enable(int fd, int enable) {
151 if (ioctl(fd, APMIO_ENABLE) == -1)
152 err(1, "ioctl(APMIO_ENABLE)");
154 if (ioctl(fd, APMIO_DISABLE) == -1)
155 err(1, "ioctl(APMIO_DISABLE)");
160 print_all_info(int fd, apm_info_t aip, int bioscall_available)
162 struct apm_bios_arg args;
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)
170 else if (aip->ai_acline > 1)
171 printf("invalid value (0x%x)", aip->ai_acline);
173 char *messages[] = { "off-line", "on-line" };
174 printf("%s", messages[aip->ai_acline]);
177 printf("Battery status: ");
178 if (aip->ai_batt_stat == 255)
180 else if (aip->ai_batt_stat > 3)
181 printf("invalid value (0x%x)", aip->ai_batt_stat);
183 char *messages[] = { "high", "low", "critical", "charging" };
184 printf("%s", messages[aip->ai_batt_stat]);
187 printf("Remaining battery life: ");
188 if (aip->ai_batt_life == 255)
190 else if (aip->ai_batt_life <= 100)
191 printf("%d%%\n", aip->ai_batt_life);
193 printf("invalid value (0x%x)\n", aip->ai_batt_life);
194 printf("Remaining battery time: ");
195 if (aip->ai_batt_time == -1)
200 t = aip->ai_batt_time;
206 printf("%2d:%02d:%02d\n", h, m, s);
208 if (aip->ai_infoversion >= 1) {
209 printf("Number of batteries: ");
210 if (aip->ai_batteries == (u_int) -1)
214 struct apm_pwstatus aps;
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)
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");
229 if (aps.ap_batt_stat == 255)
231 else if (aps.ap_batt_stat > 3)
232 printf("invalid value (0x%x)\n",
235 char *messages[] = { "high",
240 messages[aps.ap_batt_stat]);
242 printf("\tRemaining battery life: ");
243 if (aps.ap_batt_life == 255)
245 else if (aps.ap_batt_life <= 100)
246 printf("%d%%\n", aps.ap_batt_life);
248 printf("invalid value (0x%x)\n",
250 printf("\tRemaining battery time: ");
251 if (aps.ap_batt_time == -1)
256 t = aps.ap_batt_time;
262 printf("%2d:%02d:%02d\n", h, m, s);
268 if (bioscall_available) {
270 * try to get the suspend timer
272 bzero(&args, sizeof(args));
273 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
274 args.ebx = PMDV_APMBIOS;
276 if (ioctl(fd, APMIO_BIOS, &args)) {
277 printf("Resume timer: unknown\n");
279 apmerr = APMERR(args.eax);
280 if (apmerr == 0x0d || apmerr == 0x86)
281 printf("Resume timer: disabled\n");
284 "Failed to get the resume timer: APM error0x%x\n",
288 * OK. We have the time (all bcd).
292 * xh(SI) - month (1-12)
293 * xl(SI) - day of month (1-31)
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;
311 strftime(buf, sizeof(buf), "%c", &tm);
312 printf("Resume timer: %s\n", buf);
317 * Get the ring indicator resume state
319 bzero(&args, sizeof(args));
320 args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING;
321 args.ebx = PMDV_APMBIOS;
323 if (ioctl(fd, APMIO_BIOS, &args) == 0) {
324 printf("Resume on ring indicator: %sabled\n",
325 args.ecx ? "en" : "dis");
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");
354 * currently, it can turn off the display, but the display never comes
355 * back until the machine suspend/resumes :-).
358 apm_display(int fd, int newstate)
360 if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
361 err(1, "ioctl(APMIO_DISPLAY)");
365 apm_haltcpu(int fd, int enable) {
368 if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
369 err(1, "ioctl(APMIO_HALTCPU)");
371 if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
372 err(1, "ioctl(APMIO_NOTHALTCPU)");
377 apm_set_timer(int fd, int delta)
381 struct apm_bios_arg args;
383 tmr = time(NULL) + delta;
385 tm = localtime(&tmr);
388 bzero(&args, sizeof(args));
389 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
390 args.ebx = PMDV_APMBIOS;
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);
399 if (ioctl(fd, APMIO_BIOS, &args)) {
400 err(1,"Set resume timer");
405 main(int argc, char *argv[])
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;
412 int bioscall_available = 0;
413 size_t cmos_wall_len = sizeof(cmos_wall);
415 if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
417 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
418 if ((cmdname = strrchr(argv[0], '/')) != NULL)
423 if (strcmp(cmdname, "zzz") == 0) {
428 while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
439 display = is_true(optarg);
450 delta = atoi(optarg);
457 enable = is_true(optarg);
461 haltcpu = is_true(optarg);
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;
490 fd = open(APMDEV, O_RDONLY);
492 err(1, "can't open %s", APMDEV);
494 apm_enable(fd, enable);
496 apm_haltcpu(fd, haltcpu);
498 apm_set_timer(fd, delta);
503 else if (delta == 0) {
504 struct apm_info info;
506 apm_getinfo(fd, &info);
508 print_all_info(fd, &info, bioscall_available);
510 printf("%d\n", info.ai_acline);
512 printf("%d\n", info.ai_batt_stat);
514 printf("%d\n", info.ai_batt_life);
516 printf("%d\n", info.ai_status);
518 printf("%d\n", info.ai_batt_time);
520 apm_display(fd, display);