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.13 2006/08/13 02:18:51 swildner Exp $
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 xh(a) (((a) & 0xff00) >> 8)
36 #define xl(a) ((a) & 0xff)
37 #define APMERR(a) xh(a)
39 static void apm_display(int, int);
40 static void apm_enable(int, int);
41 static void apm_getinfo(int, apm_info_t
);
42 static void apm_haltcpu(int, int);
43 static void apm_set_timer(int, int);
44 static void apm_standby(int);
45 static void apm_suspend(int);
46 static int bcd2int(int);
47 static int int2bcd(int);
48 static int is_true(const char *);
49 static void print_all_info(int, apm_info_t
, int);
50 static void print_batt_life(u_int
);
51 static void print_batt_stat(u_int
);
52 static void print_batt_time(int);
53 static void usage(void) __dead2
;
55 int cmos_wall
= 0; /* True when wall time is in cmos clock, else UTC */
60 fprintf(stderr
, "%s\n%s\n",
61 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
62 "[ -h enable ] [-r delta]",
68 * Return 1 for boolean true, and 0 for false, according to the
69 * interpretation of the string argument given.
72 is_true(const char *boolean
)
77 val
= strtoul(boolean
, &endp
, 0);
79 return (val
!= 0 ? 1 : 0);
80 if (strcasecmp(boolean
, "true") == 0 ||
81 strcasecmp(boolean
, "yes") == 0 ||
82 strcasecmp(boolean
, "enable") == 0)
84 if (strcasecmp(boolean
, "false") == 0 ||
85 strcasecmp(boolean
, "no") == 0 ||
86 strcasecmp(boolean
, "disable") == 0)
88 /* Well, I have no idea what the user wants, so... */
89 warnx("invalid boolean argument \"%s\"", boolean
);
104 retval
|= (i
% 10) << base
;
121 retval
+= (bcd
& 0xf) * place
;
131 if (ioctl(fd
, APMIO_SUSPEND
, NULL
) == -1)
132 err(1, "ioctl(APMIO_SUSPEND)");
138 if (ioctl(fd
, APMIO_STANDBY
, NULL
) == -1)
139 err(1, "ioctl(APMIO_STANDBY)");
143 apm_getinfo(int fd
, apm_info_t aip
)
145 if (ioctl(fd
, APMIO_GETINFO
, aip
) == -1)
146 err(1, "ioctl(APMIO_GETINFO)");
150 apm_enable(int fd
, int enable
)
154 if (ioctl(fd
, APMIO_ENABLE
) == -1)
155 err(1, "ioctl(APMIO_ENABLE)");
157 if (ioctl(fd
, APMIO_DISABLE
) == -1)
158 err(1, "ioctl(APMIO_DISABLE)");
163 print_batt_life(u_int batt_life
)
165 printf("Remaining battery life: ");
166 if (batt_life
>= 255)
168 else if (batt_life
<= 100)
169 printf("%d%%\n", batt_life
);
171 printf("invalid value (0x%x)\n", batt_life
);
175 print_batt_stat(u_int batt_stat
)
177 const char *batt_msg
[] = { "high", "low", "critical", "charging" };
179 printf("Battery Status: ");
180 if (batt_stat
>= 255)
182 else if (batt_stat
> 3)
183 printf("invalid value (0x%x)\n", batt_stat
);
185 printf("%s\n", batt_msg
[batt_stat
]);
189 print_batt_time(int batt_time
)
191 printf("Remaining battery time: ");
202 printf("%2d:%02d:%02d\n", h
, m
, s
);
207 print_all_info(int fd
, apm_info_t aip
, int bioscall_available
)
209 struct apm_bios_arg args
;
211 const char *line_msg
[] = { "off-line", "on-line" , "backup power"};
213 printf("APM version: %d.%d\n", aip
->ai_major
, aip
->ai_minor
);
214 printf("APM Management: %s\n", (aip
->ai_status
? "Enabled" : "Disabled"));
215 printf("AC Line status: ");
216 if (aip
->ai_acline
== 255)
218 else if (aip
->ai_acline
> 2)
219 printf("invalid value (0x%x)\n", aip
->ai_acline
);
221 printf("%s\n", line_msg
[aip
->ai_acline
]);
223 print_batt_stat(aip
->ai_batt_stat
);
224 print_batt_life(aip
->ai_batt_life
);
225 print_batt_time(aip
->ai_batt_time
);
227 if (aip
->ai_infoversion
>= 1) {
228 printf("Number of batteries: ");
229 if (aip
->ai_batteries
== (u_int
) -1)
233 struct apm_pwstatus aps
;
235 printf("%d\n", aip
->ai_batteries
);
236 for (i
= 0; i
< aip
->ai_batteries
; ++i
) {
237 bzero(&aps
, sizeof(aps
));
238 aps
.ap_device
= PMDV_BATT0
+ i
;
239 if (ioctl(fd
, APMIO_GETPWSTATUS
, &aps
) == -1)
241 printf("Battery %d:\n", i
);
242 if (aps
.ap_batt_flag
!= 255 &&
243 (aps
.ap_batt_flag
& APM_BATT_NOT_PRESENT
)) {
244 printf("\tnot present\n");
249 print_batt_stat(aps
.ap_batt_stat
);
251 print_batt_life(aps
.ap_batt_life
);
253 print_batt_time(aps
.ap_batt_time
);
258 if (bioscall_available
) {
260 * try to get the suspend timer
262 bzero(&args
, sizeof(args
));
263 args
.eax
= (APM_BIOS
) << 8 | APM_RESUMETIMER
;
264 args
.ebx
= PMDV_APMBIOS
;
266 if (ioctl(fd
, APMIO_BIOS
, &args
)) {
267 printf("Resume timer: unknown\n");
269 apmerr
= APMERR(args
.eax
);
270 if (apmerr
== 0x0d || apmerr
== 0x86)
271 printf("Resume timer: disabled\n");
274 "Failed to get the resume timer: APM error0x%x\n",
278 * OK. We have the time (all bcd).
282 * xh(SI) - month (1-12)
283 * xl(SI) - day of month (1-31)
290 tm
.tm_sec
= bcd2int(xh(args
.ecx
));
291 tm
.tm_min
= bcd2int(xl(args
.edx
));
292 tm
.tm_hour
= bcd2int(xh(args
.edx
));
293 tm
.tm_mday
= bcd2int(xl(args
.esi
));
294 tm
.tm_mon
= bcd2int(xh(args
.esi
)) - 1;
295 tm
.tm_year
= bcd2int(args
.edi
) - 1900;
301 strftime(buf
, sizeof(buf
), "%s", &tm
);
302 printf("Resume timer: %s\n", buf
);
307 * Get the ring indicator resume state
309 bzero(&args
, sizeof(args
));
310 args
.eax
= (APM_BIOS
) << 8 | APM_RESUMEONRING
;
311 args
.ebx
= PMDV_APMBIOS
;
313 if (ioctl(fd
, APMIO_BIOS
, &args
) == 0) {
314 printf("Resume on ring indicator: %sabled\n",
315 args
.ecx
? "en" : "dis");
319 if (aip
->ai_infoversion
>= 1) {
320 printf("APM Capacities:\n");
321 if (aip
->ai_capabilities
== 0xff00)
322 printf("\tunknown\n");
323 if (aip
->ai_capabilities
& 0x01)
324 printf("\tglobal standby state\n");
325 if (aip
->ai_capabilities
& 0x02)
326 printf("\tglobal suspend state\n");
327 if (aip
->ai_capabilities
& 0x04)
328 printf("\tresume timer from standby\n");
329 if (aip
->ai_capabilities
& 0x08)
330 printf("\tresume timer from suspend\n");
331 if (aip
->ai_capabilities
& 0x10)
332 printf("\tRI resume from standby\n");
333 if (aip
->ai_capabilities
& 0x20)
334 printf("\tRI resume from suspend\n");
335 if (aip
->ai_capabilities
& 0x40)
336 printf("\tPCMCIA RI resume from standby\n");
337 if (aip
->ai_capabilities
& 0x80)
338 printf("\tPCMCIA RI resume from suspend\n");
344 * currently, it can turn off the display, but the display never comes
345 * back until the machine suspend/resumes :-).
348 apm_display(int fd
, int newstate
)
350 if (ioctl(fd
, APMIO_DISPLAY
, &newstate
) == -1)
351 err(1, "ioctl(APMIO_DISPLAY)");
355 apm_haltcpu(int fd
, int enable
)
359 if (ioctl(fd
, APMIO_HALTCPU
, NULL
) == -1)
360 err(1, "ioctl(APMIO_HALTCPU)");
362 if (ioctl(fd
, APMIO_NOTHALTCPU
, NULL
) == -1)
363 err(1, "ioctl(APMIO_NOTHALTCPU)");
368 apm_set_timer(int fd
, int delta
)
372 struct apm_bios_arg args
;
374 tmr
= time(NULL
) + delta
;
376 tm
= localtime(&tmr
);
379 bzero(&args
, sizeof(args
));
380 args
.eax
= (APM_BIOS
) << 8 | APM_RESUMETIMER
;
381 args
.ebx
= PMDV_APMBIOS
;
383 args
.ecx
= (int2bcd(tm
->tm_sec
) << 8) | 0x02;
384 args
.edx
= (int2bcd(tm
->tm_hour
) << 8) | int2bcd(tm
->tm_min
);
385 args
.esi
= (int2bcd(tm
->tm_mon
+ 1) << 8) | int2bcd(tm
->tm_mday
);
386 args
.edi
= int2bcd(tm
->tm_year
+ 1900);
390 if (ioctl(fd
, APMIO_BIOS
, &args
)) {
391 err(1,"Set resume timer");
396 main(int argc
, char *argv
[])
399 int apm_sleep
= 0, all_info
= 1, apm_status
= 0, batt_status
= 0;
400 int display
= -1, batt_life
= 0, ac_status
= 0, standby
= 0;
401 int batt_time
= 0, delta
= 0, enable
= -1, haltcpu
= -1;
403 int bioscall_available
= 0;
404 size_t cmos_wall_len
= sizeof(cmos_wall
);
406 if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall
, &cmos_wall_len
,
408 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
409 if ((cmdname
= strrchr(argv
[0], '/')) != NULL
)
414 if (strcmp(cmdname
, "zzz") == 0) {
419 while ((c
= getopt(argc
, argv
, "abe:h:lRr:stzd:Z")) != -1) {
430 display
= is_true(optarg
);
441 delta
= atoi(optarg
);
448 enable
= is_true(optarg
);
452 haltcpu
= is_true(optarg
);
474 if (haltcpu
!= -1 || enable
!= -1 || display
!= -1 || delta
|| apm_sleep
|| standby
) {
475 fd
= open(APMDEV
, O_RDWR
);
476 bioscall_available
= 1;
477 } else if ((fd
= open(APMDEV
, O_RDWR
)) >= 0)
478 bioscall_available
= 1;
480 fd
= open(APMDEV
, O_RDONLY
);
482 err(1, "can't open %s", APMDEV
);
484 apm_enable(fd
, enable
);
486 apm_haltcpu(fd
, haltcpu
);
488 apm_set_timer(fd
, delta
);
493 else if (delta
== 0) {
494 struct apm_info info
;
496 apm_getinfo(fd
, &info
);
498 print_all_info(fd
, &info
, bioscall_available
);
500 printf("%d\n", info
.ai_acline
);
502 printf("%d\n", info
.ai_batt_stat
);
504 printf("%d\n", info
.ai_batt_life
);
506 printf("%d\n", info
.ai_status
);
508 printf("%d\n", info
.ai_batt_time
);
510 apm_display(fd
, display
);