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)
16 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
24 #include <machine/apm_bios.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 */
46 fprintf(stderr
, "%s\n%s\n",
47 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
48 "[ -h enable ] [-r delta]",
54 * Return 1 for boolean true, and 0 for false, according to the
55 * interpretation of the string argument given.
58 is_true(const char *boolean
)
63 val
= strtoul(boolean
, &endp
, 0);
65 return (val
!= 0 ? 1 : 0);
66 if (strcasecmp(boolean
, "true") == 0 ||
67 strcasecmp(boolean
, "yes") == 0 ||
68 strcasecmp(boolean
, "enable") == 0)
70 if (strcasecmp(boolean
, "false") == 0 ||
71 strcasecmp(boolean
, "no") == 0 ||
72 strcasecmp(boolean
, "disable") == 0)
74 /* Well, I have no idea what the user wants, so... */
75 warnx("invalid boolean argument \"%s\"", boolean
);
92 retval
|= (i
% 10) << base
;
109 retval
+= (bcd
& 0xf) * place
;
119 if (ioctl(fd
, APMIO_SUSPEND
, NULL
) == -1)
120 err(1, "ioctl(APMIO_SUSPEND)");
126 if (ioctl(fd
, APMIO_STANDBY
, NULL
) == -1)
127 err(1, "ioctl(APMIO_STANDBY)");
131 apm_getinfo(int fd
, apm_info_t aip
)
133 if (ioctl(fd
, APMIO_GETINFO
, aip
) == -1)
134 err(1, "ioctl(APMIO_GETINFO)");
138 apm_enable(int fd
, int enable
)
141 if (ioctl(fd
, APMIO_ENABLE
) == -1)
142 err(1, "ioctl(APMIO_ENABLE)");
144 if (ioctl(fd
, APMIO_DISABLE
) == -1)
145 err(1, "ioctl(APMIO_DISABLE)");
150 print_batt_time(int batt_time
)
152 printf("Remaining battery time: ");
163 printf("%2d:%02d:%02d\n", h
, m
, s
);
168 print_batt_life(u_int batt_life
)
170 printf("Remaining battery life: ");
171 if (batt_life
== APM_UNKNOWN
)
173 else if (batt_life
<= 100)
174 printf("%d%%\n", batt_life
);
176 printf("invalid value (0x%x)\n", batt_life
);
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
)
187 else if (batt_stat
> 3)
188 printf("invalid value (0x%x)\n", batt_stat
);
190 printf("%s\n", batt_msg
[batt_stat
]);
194 print_all_info(int fd
, apm_info_t aip
, int bioscall_available
)
196 struct apm_bios_arg args
;
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
)
205 else if (aip
->ai_acline
> 2)
206 printf("invalid value (0x%x)\n", aip
->ai_acline
);
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)
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)
228 printf("Battery %d:\n", i
);
229 if (aps
.ap_batt_flag
& APM_BATT_NOT_PRESENT
) {
230 printf("not present\n");
234 print_batt_stat(aps
.ap_batt_stat
);
236 print_batt_life(aps
.ap_batt_life
);
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
;
251 if (ioctl(fd
, APMIO_BIOS
, &args
)) {
252 printf("Resume timer: unknown\n");
254 apmerr
= APMERR(args
.eax
);
255 if (apmerr
== 0x0d || apmerr
== 0x86)
256 printf("Resume timer: disabled\n");
259 "failed to get the resume timer: APM error0x%x", apmerr
);
262 * OK. We have the time (all bcd).
266 * xh(SI) - month (1-12)
267 * xl(SI) - day of month (1-31)
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;
286 strftime(buf
, sizeof(buf
), "%c", &tm
);
287 printf("Resume timer: %s\n", buf
);
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
;
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)
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 :-).
335 apm_display(int fd
, int newstate
)
337 if (ioctl(fd
, APMIO_DISPLAY
, &newstate
) == -1)
338 err(1, "ioctl(APMIO_DISPLAY)");
342 apm_haltcpu(int fd
, int enable
)
345 if (ioctl(fd
, APMIO_HALTCPU
, NULL
) == -1)
346 err(1, "ioctl(APMIO_HALTCPU)");
348 if (ioctl(fd
, APMIO_NOTHALTCPU
, NULL
) == -1)
349 err(1, "ioctl(APMIO_NOTHALTCPU)");
354 apm_set_timer(int fd
, int delta
)
358 struct apm_bios_arg args
;
360 tmr
= time(NULL
) + delta
;
362 tm
= localtime(&tmr
);
365 bzero(&args
, sizeof(args
));
366 args
.eax
= (APM_BIOS
) << 8 | APM_RESUMETIMER
;
367 args
.ebx
= PMDV_APMBIOS
;
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);
376 if (ioctl(fd
, APMIO_BIOS
, &args
)) {
377 err(1,"set resume timer");
382 main(int argc
, char *argv
[])
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;
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
,
394 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
395 if ((cmdname
= strrchr(argv
[0], '/')) != NULL
)
400 if (strcmp(cmdname
, "zzz") == 0) {
405 while ((c
= getopt(argc
, argv
, "abe:h:lRr:stzd:Z")) != -1) {
416 display
= is_true(optarg
);
427 delta
= atoi(optarg
);
434 enable
= is_true(optarg
);
438 haltcpu
= is_true(optarg
);
461 if (haltcpu
!= -1 || enable
!= -1 || display
!= -1 || delta
|| dosleep
463 fd
= open(APMDEV
, O_RDWR
);
464 bioscall_available
= 1;
465 } else if ((fd
= open(APMDEV
, O_RDWR
)) >= 0)
466 bioscall_available
= 1;
468 fd
= open(APMDEV
, O_RDONLY
);
470 err(1, "can't open %s", APMDEV
);
472 apm_enable(fd
, enable
);
474 apm_haltcpu(fd
, haltcpu
);
476 apm_set_timer(fd
, delta
);
481 else if (delta
== 0) {
482 struct apm_info info
;
484 apm_getinfo(fd
, &info
);
486 print_all_info(fd
, &info
, bioscall_available
);
488 printf("%d\n", info
.ai_acline
);
490 printf("%d\n", info
.ai_batt_stat
);
492 printf("%d\n", info
.ai_batt_life
);
494 printf("%d\n", info
.ai_status
);
496 printf("%d\n", info
.ai_batt_time
);
498 apm_display(fd
, display
);