2 * 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)
16 #include <sys/cdefs.h>
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/sysctl.h>
22 #include <machine/apm_bios.h>
31 #define APMDEV "/dev/apm"
33 #define APM_UNKNOWN 255
35 #define xh(a) (((a) & 0xff00) >> 8)
36 #define xl(a) ((a) & 0xff)
37 #define APMERR(a) xh(a)
39 static int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
45 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
46 "[ -h enable ] [-r delta]\n");
51 * Return 1 for boolean true, and 0 for false, according to the
52 * interpretation of the string argument given.
55 is_true(const char *boolean)
60 val = strtoul(boolean, &endp, 0);
62 return (val != 0 ? 1 : 0);
63 if (strcasecmp(boolean, "true") == 0 ||
64 strcasecmp(boolean, "yes") == 0 ||
65 strcasecmp(boolean, "enable") == 0)
67 if (strcasecmp(boolean, "false") == 0 ||
68 strcasecmp(boolean, "no") == 0 ||
69 strcasecmp(boolean, "disable") == 0)
71 /* Well, I have no idea what the user wants, so... */
72 warnx("invalid boolean argument \"%s\"", boolean);
89 retval |= (i % 10) << base;
106 retval += (bcd & 0xf) * place;
116 if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
117 err(1, "ioctl(APMIO_SUSPEND)");
123 if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
124 err(1, "ioctl(APMIO_STANDBY)");
128 apm_getinfo(int fd, apm_info_t aip)
130 if (ioctl(fd, APMIO_GETINFO, aip) == -1)
131 err(1, "ioctl(APMIO_GETINFO)");
135 apm_enable(int fd, int enable)
138 if (ioctl(fd, APMIO_ENABLE) == -1)
139 err(1, "ioctl(APMIO_ENABLE)");
141 if (ioctl(fd, APMIO_DISABLE) == -1)
142 err(1, "ioctl(APMIO_DISABLE)");
147 print_batt_time(int batt_time)
149 printf("Remaining battery time: ");
160 printf("%2d:%02d:%02d\n", h, m, s);
165 print_batt_life(u_int batt_life)
167 printf("Remaining battery life: ");
168 if (batt_life == APM_UNKNOWN)
170 else if (batt_life <= 100)
171 printf("%d%%\n", batt_life);
173 printf("invalid value (0x%x)\n", batt_life);
177 print_batt_stat(u_int batt_stat)
179 const char *batt_msg[] = { "high", "low", "critical", "charging" };
181 printf("Battery Status: ");
182 if (batt_stat == APM_UNKNOWN)
184 else if (batt_stat > 3)
185 printf("invalid value (0x%x)\n", batt_stat);
187 printf("%s\n", batt_msg[batt_stat]);
191 print_all_info(int fd, apm_info_t aip, int bioscall_available)
193 struct apm_bios_arg args;
195 const char *line_msg[] = { "off-line", "on-line" , "backup power"};
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)
202 else if (aip->ai_acline > 2)
203 printf("invalid value (0x%x)\n", aip->ai_acline);
205 printf("%s\n", line_msg[aip->ai_acline]);
207 print_batt_stat(aip->ai_batt_stat);
208 print_batt_life(aip->ai_batt_life);
209 print_batt_time(aip->ai_batt_time);
211 if (aip->ai_infoversion >= 1) {
212 printf("Number of batteries: ");
213 if (aip->ai_batteries == ~0U)
217 struct apm_pwstatus aps;
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)
225 printf("Battery %d:\n", i);
226 if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) {
227 printf("not present\n");
231 print_batt_stat(aps.ap_batt_stat);
233 print_batt_life(aps.ap_batt_life);
235 print_batt_time(aps.ap_batt_time);
240 if (bioscall_available) {
242 * try to get the suspend timer
244 bzero(&args, sizeof(args));
245 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
246 args.ebx = PMDV_APMBIOS;
248 if (ioctl(fd, APMIO_BIOS, &args)) {
249 printf("Resume timer: unknown\n");
251 apmerr = APMERR(args.eax);
252 if (apmerr == 0x0d || apmerr == 0x86)
253 printf("Resume timer: disabled\n");
256 "failed to get the resume timer: APM error0x%x", apmerr);
259 * OK. We have the time (all bcd).
263 * xh(SI) - month (1-12)
264 * xl(SI) - day of month (1-31)
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;
283 strftime(buf, sizeof(buf), "%c", &tm);
284 printf("Resume timer: %s\n", buf);
286 printf("Resume timer: unknown\n");
291 * Get the ring indicator resume state
293 bzero(&args, sizeof(args));
294 args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING;
295 args.ebx = PMDV_APMBIOS;
297 if (ioctl(fd, APMIO_BIOS, &args) == 0) {
298 printf("Resume on ring indicator: %sabled\n",
299 args.ecx ? "en" : "dis");
303 if (aip->ai_infoversion >= 1) {
304 if (aip->ai_capabilities == 0xff00)
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");
328 * currently, it can turn off the display, but the display never comes
329 * back until the machine suspend/resumes :-).
332 apm_display(int fd, int newstate)
334 if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
335 err(1, "ioctl(APMIO_DISPLAY)");
339 apm_haltcpu(int fd, int enable)
342 if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
343 err(1, "ioctl(APMIO_HALTCPU)");
345 if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
346 err(1, "ioctl(APMIO_NOTHALTCPU)");
351 apm_set_timer(int fd, int delta)
355 struct apm_bios_arg args;
357 tmr = time(NULL) + delta;
359 tm = localtime(&tmr);
362 bzero(&args, sizeof(args));
363 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
364 args.ebx = PMDV_APMBIOS;
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);
373 if (ioctl(fd, APMIO_BIOS, &args)) {
374 err(1,"set resume timer");
379 main(int argc, char *argv[])
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);
388 if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
390 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
392 while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
403 display = is_true(optarg);
414 delta = atoi(optarg);
421 enable = is_true(optarg);
425 haltcpu = is_true(optarg);
447 if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
449 fd = open(APMDEV, O_RDWR);
450 bioscall_available = 1;
451 } else if ((fd = open(APMDEV, O_RDWR)) >= 0)
452 bioscall_available = 1;
454 fd = open(APMDEV, O_RDONLY);
456 err(1, "can't open %s", APMDEV);
458 apm_enable(fd, enable);
460 apm_haltcpu(fd, haltcpu);
462 apm_set_timer(fd, delta);
467 else if (delta == 0) {
468 struct apm_info info;
470 apm_getinfo(fd, &info);
472 print_all_info(fd, &info, bioscall_available);
474 printf("%d\n", info.ai_acline);
476 printf("%d\n", info.ai_batt_stat);
478 printf("%d\n", info.ai_batt_life);
480 printf("%d\n", info.ai_status);
482 printf("%d\n", info.ai_batt_time);
484 apm_display(fd, display);