xref: /freebsd-src/usr.sbin/apm/apm.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1140cffd3SDavid Greenman /*
2a13f3190SRuslan Ermilov  * APM BIOS utility for FreeBSD
3140cffd3SDavid Greenman  *
496b54d77STatsumi Hosokawa  * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
5140cffd3SDavid Greenman  *
6140cffd3SDavid Greenman  * This software may be used, modified, copied, distributed, and sold,
7140cffd3SDavid Greenman  * in both source and binary form provided that the above copyright and
8140cffd3SDavid Greenman  * these terms are retained. Under no circumstances is the author
9140cffd3SDavid Greenman  * responsible for the proper functioning of this software, nor does
10140cffd3SDavid Greenman  * the author assume any responsibility for damages incurred with its
11140cffd3SDavid Greenman  * use.
12140cffd3SDavid Greenman  *
13140cffd3SDavid Greenman  * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
14140cffd3SDavid Greenman  */
15140cffd3SDavid Greenman 
164cdb6a34SPhilippe Charnier #include <sys/cdefs.h>
1794c8c4fbSBrian Feldman #include <sys/file.h>
1894c8c4fbSBrian Feldman #include <sys/ioctl.h>
1994c8c4fbSBrian Feldman #include <sys/types.h>
2094c8c4fbSBrian Feldman #include <sys/sysctl.h>
2194c8c4fbSBrian Feldman 
2294c8c4fbSBrian Feldman #include <machine/apm_bios.h>
2394c8c4fbSBrian Feldman 
24afe83a1cSPhilippe Charnier #include <err.h>
25140cffd3SDavid Greenman #include <stdio.h>
26e46ea891SNate Williams #include <stdlib.h>
27140cffd3SDavid Greenman #include <string.h>
2894d1a201SWarner Losh #include <time.h>
2994c8c4fbSBrian Feldman #include <unistd.h>
30140cffd3SDavid Greenman 
31ddccc6ecSNate Williams #define APMDEV	"/dev/apm"
32140cffd3SDavid Greenman 
336084486fSWarner Losh #define APM_UNKNOWN	255
346084486fSWarner Losh 
3594d1a201SWarner Losh #define xh(a)	(((a) & 0xff00) >> 8)
3694d1a201SWarner Losh #define xl(a)	((a) & 0xff)
3794d1a201SWarner Losh #define APMERR(a) xh(a)
3894d1a201SWarner Losh 
39*6f344d60SEd Schouten static int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
4094d1a201SWarner Losh 
41a607c5e4SNate Lawson static void
usage(void)42a607c5e4SNate Lawson usage(void)
43e46ea891SNate Williams {
44a13f3190SRuslan Ermilov 	fprintf(stderr,
45295e0cdaSBrian Feldman 		"usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
46a13f3190SRuslan Ermilov 		"[ -h enable ] [-r delta]\n");
47e46ea891SNate Williams 	exit(1);
48e46ea891SNate Williams }
49e46ea891SNate Williams 
50295e0cdaSBrian Feldman /*
51295e0cdaSBrian Feldman  * Return 1 for boolean true, and 0 for false, according to the
52295e0cdaSBrian Feldman  * interpretation of the string argument given.
53295e0cdaSBrian Feldman  */
54a607c5e4SNate Lawson static int
is_true(const char * boolean)55f4732084SMaxime Henrion is_true(const char *boolean)
56f4732084SMaxime Henrion {
57295e0cdaSBrian Feldman 	char *endp;
58295e0cdaSBrian Feldman 	long val;
59295e0cdaSBrian Feldman 
60295e0cdaSBrian Feldman 	val = strtoul(boolean, &endp, 0);
61295e0cdaSBrian Feldman 	if (*endp == '\0')
62295e0cdaSBrian Feldman 		return (val != 0 ? 1 : 0);
63295e0cdaSBrian Feldman 	if (strcasecmp(boolean, "true") == 0 ||
64295e0cdaSBrian Feldman 	    strcasecmp(boolean, "yes") == 0 ||
65295e0cdaSBrian Feldman 	    strcasecmp(boolean, "enable") == 0)
66295e0cdaSBrian Feldman 		return (1);
67295e0cdaSBrian Feldman 	if (strcasecmp(boolean, "false") == 0 ||
68295e0cdaSBrian Feldman 	    strcasecmp(boolean, "no") == 0 ||
69295e0cdaSBrian Feldman 	    strcasecmp(boolean, "disable") == 0)
70295e0cdaSBrian Feldman 		return (0);
71295e0cdaSBrian Feldman 	/* Well, I have no idea what the user wants, so... */
72295e0cdaSBrian Feldman 	warnx("invalid boolean argument \"%s\"", boolean);
73295e0cdaSBrian Feldman 	usage();
74295e0cdaSBrian Feldman 	/* NOTREACHED */
75a607c5e4SNate Lawson 
76a607c5e4SNate Lawson 	return (0);
77295e0cdaSBrian Feldman }
78295e0cdaSBrian Feldman 
79a607c5e4SNate Lawson static int
int2bcd(int i)8094d1a201SWarner Losh int2bcd(int i)
8194d1a201SWarner Losh {
8294d1a201SWarner Losh 	int retval = 0;
8394d1a201SWarner Losh 	int base = 0;
8494d1a201SWarner Losh 
8594d1a201SWarner Losh 	if (i >= 10000)
8694d1a201SWarner Losh 		return -1;
8794d1a201SWarner Losh 
8894d1a201SWarner Losh 	while (i) {
8994d1a201SWarner Losh 		retval |= (i % 10) << base;
9094d1a201SWarner Losh 		i /= 10;
9194d1a201SWarner Losh 		base += 4;
9294d1a201SWarner Losh 	}
9394d1a201SWarner Losh 	return retval;
9494d1a201SWarner Losh }
9594d1a201SWarner Losh 
96a607c5e4SNate Lawson static int
bcd2int(int bcd)9794d1a201SWarner Losh bcd2int(int bcd)
9894d1a201SWarner Losh {
9994d1a201SWarner Losh 	int retval = 0;
100e50479ccSBrian Feldman 	int place = 1;
10194d1a201SWarner Losh 
10294d1a201SWarner Losh 	if (bcd > 0x9999)
10394d1a201SWarner Losh 		return -1;
10494d1a201SWarner Losh 
10594d1a201SWarner Losh 	while (bcd) {
106e50479ccSBrian Feldman 		retval += (bcd & 0xf) * place;
107e50479ccSBrian Feldman 		bcd >>= 4;
108e50479ccSBrian Feldman 		place *= 10;
10994d1a201SWarner Losh 	}
11094d1a201SWarner Losh 	return retval;
11194d1a201SWarner Losh }
11294d1a201SWarner Losh 
113a607c5e4SNate Lawson static void
apm_suspend(int fd)114e46ea891SNate Williams apm_suspend(int fd)
115140cffd3SDavid Greenman {
116afe83a1cSPhilippe Charnier 	if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
117295e0cdaSBrian Feldman 		err(1, "ioctl(APMIO_SUSPEND)");
118140cffd3SDavid Greenman }
119140cffd3SDavid Greenman 
120a607c5e4SNate Lawson static void
apm_standby(int fd)12194d1a201SWarner Losh apm_standby(int fd)
12294d1a201SWarner Losh {
12394d1a201SWarner Losh 	if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
124295e0cdaSBrian Feldman 		err(1, "ioctl(APMIO_STANDBY)");
12594d1a201SWarner Losh }
12694d1a201SWarner Losh 
127a607c5e4SNate Lawson static void
apm_getinfo(int fd,apm_info_t aip)128e46ea891SNate Williams apm_getinfo(int fd, apm_info_t aip)
129140cffd3SDavid Greenman {
130afe83a1cSPhilippe Charnier 	if (ioctl(fd, APMIO_GETINFO, aip) == -1)
131295e0cdaSBrian Feldman 		err(1, "ioctl(APMIO_GETINFO)");
132140cffd3SDavid Greenman }
133140cffd3SDavid Greenman 
134a607c5e4SNate Lawson static void
apm_enable(int fd,int enable)135f4732084SMaxime Henrion apm_enable(int fd, int enable)
136f4732084SMaxime Henrion {
137295e0cdaSBrian Feldman 	if (enable) {
138295e0cdaSBrian Feldman 		if (ioctl(fd, APMIO_ENABLE) == -1)
139295e0cdaSBrian Feldman 			err(1, "ioctl(APMIO_ENABLE)");
140295e0cdaSBrian Feldman 	} else {
141295e0cdaSBrian Feldman 		if (ioctl(fd, APMIO_DISABLE) == -1)
142295e0cdaSBrian Feldman 			err(1, "ioctl(APMIO_DISABLE)");
143295e0cdaSBrian Feldman 	}
144701eaeb3SBrian Feldman }
145701eaeb3SBrian Feldman 
146a607c5e4SNate Lawson static void
print_batt_time(int batt_time)147f4732084SMaxime Henrion print_batt_time(int batt_time)
148f4732084SMaxime Henrion {
149f4732084SMaxime Henrion 	printf("Remaining battery time: ");
150f4732084SMaxime Henrion 	if (batt_time == -1)
151f4732084SMaxime Henrion 		printf("unknown\n");
152f4732084SMaxime Henrion 	else {
153f4732084SMaxime Henrion 		int h, m, s;
154f4732084SMaxime Henrion 
155f4732084SMaxime Henrion 		h = batt_time;
156f4732084SMaxime Henrion 		s = h % 60;
157f4732084SMaxime Henrion 		h /= 60;
158f4732084SMaxime Henrion 		m = h % 60;
159f4732084SMaxime Henrion 		h /= 60;
160f4732084SMaxime Henrion 		printf("%2d:%02d:%02d\n", h, m, s);
161f4732084SMaxime Henrion 	}
162f4732084SMaxime Henrion }
163f4732084SMaxime Henrion 
164f4732084SMaxime Henrion static void
print_batt_life(u_int batt_life)165f4732084SMaxime Henrion print_batt_life(u_int batt_life)
166f4732084SMaxime Henrion {
167f4732084SMaxime Henrion 	printf("Remaining battery life: ");
1686084486fSWarner Losh 	if (batt_life == APM_UNKNOWN)
169f4732084SMaxime Henrion 		printf("unknown\n");
170f4732084SMaxime Henrion 	else if (batt_life <= 100)
171f4732084SMaxime Henrion 		printf("%d%%\n", batt_life);
172f4732084SMaxime Henrion 	else
173f4732084SMaxime Henrion 		printf("invalid value (0x%x)\n", batt_life);
174f4732084SMaxime Henrion }
175f4732084SMaxime Henrion 
176f4732084SMaxime Henrion static void
print_batt_stat(u_int batt_stat)177f4732084SMaxime Henrion print_batt_stat(u_int batt_stat)
178f4732084SMaxime Henrion {
179f4732084SMaxime Henrion 	const char *batt_msg[] = { "high", "low", "critical", "charging" };
180f4732084SMaxime Henrion 
181f4732084SMaxime Henrion 	printf("Battery Status: ");
1826084486fSWarner Losh 	if (batt_stat == APM_UNKNOWN)
183f4732084SMaxime Henrion 		printf("unknown\n");
184f4732084SMaxime Henrion 	else if (batt_stat > 3)
185f4732084SMaxime Henrion 		printf("invalid value (0x%x)\n", batt_stat);
186f4732084SMaxime Henrion 	else
187f4732084SMaxime Henrion 		printf("%s\n", batt_msg[batt_stat]);
188f4732084SMaxime Henrion }
189f4732084SMaxime Henrion 
190f4732084SMaxime Henrion static void
print_all_info(int fd,apm_info_t aip,int bioscall_available)1917e3809fdSHajimu UMEMOTO print_all_info(int fd, apm_info_t aip, int bioscall_available)
192140cffd3SDavid Greenman {
19394d1a201SWarner Losh 	struct apm_bios_arg args;
19494d1a201SWarner Losh 	int apmerr;
195b3d2f94eSWill Andrews 	const char *line_msg[] = { "off-line", "on-line" , "backup power"};
19694d1a201SWarner Losh 
197140cffd3SDavid Greenman 	printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
198a607c5e4SNate Lawson 	printf("APM Management: %s\n", aip->ai_status ? "Enabled" : "Disabled");
199140cffd3SDavid Greenman 	printf("AC Line status: ");
2006084486fSWarner Losh 	if (aip->ai_acline == APM_UNKNOWN)
201f4732084SMaxime Henrion 		printf("unknown\n");
202b3d2f94eSWill Andrews 	else if (aip->ai_acline > 2)
203f4732084SMaxime Henrion 		printf("invalid value (0x%x)\n", aip->ai_acline);
204a607c5e4SNate Lawson 	else
205f4732084SMaxime Henrion 		printf("%s\n", line_msg[aip->ai_acline]);
206ec8f6ad7SJohn Polstra 
207f4732084SMaxime Henrion 	print_batt_stat(aip->ai_batt_stat);
208f4732084SMaxime Henrion 	print_batt_life(aip->ai_batt_life);
209f4732084SMaxime Henrion 	print_batt_time(aip->ai_batt_time);
210f4732084SMaxime Henrion 
21194d1a201SWarner Losh 	if (aip->ai_infoversion >= 1) {
21294d1a201SWarner Losh 		printf("Number of batteries: ");
2136084486fSWarner Losh 		if (aip->ai_batteries == ~0U)
21494d1a201SWarner Losh 			printf("unknown\n");
2158ad6d022SHajimu UMEMOTO 		else {
216a607c5e4SNate Lawson 			u_int i;
2178ad6d022SHajimu UMEMOTO 			struct apm_pwstatus aps;
2188ad6d022SHajimu UMEMOTO 
21994d1a201SWarner Losh 			printf("%d\n", aip->ai_batteries);
2208ad6d022SHajimu UMEMOTO 			for (i = 0; i < aip->ai_batteries; ++i) {
2218ad6d022SHajimu UMEMOTO 				bzero(&aps, sizeof(aps));
2228ad6d022SHajimu UMEMOTO 				aps.ap_device = PMDV_BATT0 + i;
2238ad6d022SHajimu UMEMOTO 				if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1)
2248ad6d022SHajimu UMEMOTO 					continue;
2258ad6d022SHajimu UMEMOTO 				printf("Battery %d:\n", i);
2266084486fSWarner Losh 				if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) {
2278ad6d022SHajimu UMEMOTO 					printf("not present\n");
2288ad6d022SHajimu UMEMOTO 					continue;
2298ad6d022SHajimu UMEMOTO 				}
230e15b31bbSMaxime Henrion 				printf("\t");
231f4732084SMaxime Henrion 				print_batt_stat(aps.ap_batt_stat);
232e15b31bbSMaxime Henrion 				printf("\t");
233f4732084SMaxime Henrion 				print_batt_life(aps.ap_batt_life);
234e15b31bbSMaxime Henrion 				printf("\t");
235f4732084SMaxime Henrion 				print_batt_time(aps.ap_batt_time);
2368ad6d022SHajimu UMEMOTO 			}
2378ad6d022SHajimu UMEMOTO 		}
238140cffd3SDavid Greenman 	}
239140cffd3SDavid Greenman 
2407e3809fdSHajimu UMEMOTO 	if (bioscall_available) {
24194d1a201SWarner Losh 		/*
24294d1a201SWarner Losh 		 * try to get the suspend timer
24394d1a201SWarner Losh 		 */
24494d1a201SWarner Losh 		bzero(&args, sizeof(args));
24594d1a201SWarner Losh 		args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
24694d1a201SWarner Losh 		args.ebx = PMDV_APMBIOS;
24794d1a201SWarner Losh 		args.ecx = 0x0001;
24894d1a201SWarner Losh 		if (ioctl(fd, APMIO_BIOS, &args)) {
24977540b54SMitsuru IWASAKI 			printf("Resume timer: unknown\n");
25094d1a201SWarner Losh 		} else {
25194d1a201SWarner Losh 			apmerr = APMERR(args.eax);
25294d1a201SWarner Losh 			if (apmerr == 0x0d || apmerr == 0x86)
25394d1a201SWarner Losh 				printf("Resume timer: disabled\n");
25494d1a201SWarner Losh 			else if (apmerr)
2554cdb6a34SPhilippe Charnier 				warnx(
2564cdb6a34SPhilippe Charnier 		"failed to get the resume timer: APM error0x%x", apmerr);
25794d1a201SWarner Losh 			else {
25894d1a201SWarner Losh 				/*
25994d1a201SWarner Losh 				 * OK.  We have the time (all bcd).
26094d1a201SWarner Losh 				 * CH - seconds
26194d1a201SWarner Losh 				 * DH - hours
26294d1a201SWarner Losh 				 * DL - minutes
26394d1a201SWarner Losh 				 * xh(SI) - month (1-12)
26494d1a201SWarner Losh 				 * xl(SI) - day of month (1-31)
26594d1a201SWarner Losh 				 * DI - year
26694d1a201SWarner Losh 				 */
26794d1a201SWarner Losh 				struct tm tm;
26894d1a201SWarner Losh 				char buf[1024];
26994d1a201SWarner Losh 				time_t t;
27094d1a201SWarner Losh 
27194d1a201SWarner Losh 				tm.tm_sec = bcd2int(xh(args.ecx));
27294d1a201SWarner Losh 				tm.tm_min = bcd2int(xl(args.edx));
27394d1a201SWarner Losh 				tm.tm_hour = bcd2int(xh(args.edx));
27494d1a201SWarner Losh 				tm.tm_mday = bcd2int(xl(args.esi));
27594d1a201SWarner Losh 				tm.tm_mon = bcd2int(xh(args.esi)) - 1;
27694d1a201SWarner Losh 				tm.tm_year = bcd2int(args.edi) - 1900;
27794d1a201SWarner Losh 				if (cmos_wall)
27894d1a201SWarner Losh 					t = mktime(&tm);
27994d1a201SWarner Losh 				else
28094d1a201SWarner Losh 					t = timegm(&tm);
281bc8aff44SRobert Watson 				if (t != -1) {
28294d1a201SWarner Losh 					tm = *localtime(&t);
28394d1a201SWarner Losh 					strftime(buf, sizeof(buf), "%c", &tm);
28494d1a201SWarner Losh 					printf("Resume timer: %s\n", buf);
285bc8aff44SRobert Watson 				} else
286bc8aff44SRobert Watson 					printf("Resume timer: unknown\n");
28794d1a201SWarner Losh 			}
28894d1a201SWarner Losh 		}
28994d1a201SWarner Losh 
29094d1a201SWarner Losh 		/*
29194d1a201SWarner Losh 		 * Get the ring indicator resume state
29294d1a201SWarner Losh 		 */
29394d1a201SWarner Losh 		bzero(&args, sizeof(args));
29494d1a201SWarner Losh 		args.eax  = (APM_BIOS) << 8 | APM_RESUMEONRING;
29594d1a201SWarner Losh 		args.ebx = PMDV_APMBIOS;
29694d1a201SWarner Losh 		args.ecx = 0x0002;
29794d1a201SWarner Losh 		if (ioctl(fd, APMIO_BIOS, &args) == 0) {
29894d1a201SWarner Losh 			printf("Resume on ring indicator: %sabled\n",
29994d1a201SWarner Losh 			    args.ecx ? "en" : "dis");
30094d1a201SWarner Losh 		}
3017e3809fdSHajimu UMEMOTO 	}
3027e3809fdSHajimu UMEMOTO 
30394d1a201SWarner Losh 	if (aip->ai_infoversion >= 1) {
30494d1a201SWarner Losh 		if (aip->ai_capabilities == 0xff00)
3056084486fSWarner Losh 		    return;
3066084486fSWarner Losh 		printf("APM Capabilities:\n");
30794d1a201SWarner Losh 		if (aip->ai_capabilities & 0x01)
30894d1a201SWarner Losh 			printf("\tglobal standby state\n");
30994d1a201SWarner Losh 		if (aip->ai_capabilities & 0x02)
31094d1a201SWarner Losh 			printf("\tglobal suspend state\n");
31194d1a201SWarner Losh 		if (aip->ai_capabilities & 0x04)
31294d1a201SWarner Losh 			printf("\tresume timer from standby\n");
31394d1a201SWarner Losh 		if (aip->ai_capabilities & 0x08)
31494d1a201SWarner Losh 			printf("\tresume timer from suspend\n");
31594d1a201SWarner Losh 		if (aip->ai_capabilities & 0x10)
31694d1a201SWarner Losh 			printf("\tRI resume from standby\n");
31794d1a201SWarner Losh 		if (aip->ai_capabilities & 0x20)
31894d1a201SWarner Losh 			printf("\tRI resume from suspend\n");
31994d1a201SWarner Losh 		if (aip->ai_capabilities & 0x40)
32094d1a201SWarner Losh 			printf("\tPCMCIA RI resume from standby\n");
32194d1a201SWarner Losh 		if (aip->ai_capabilities & 0x80)
32294d1a201SWarner Losh 			printf("\tPCMCIA RI resume from suspend\n");
32394d1a201SWarner Losh 	}
32494d1a201SWarner Losh 
32594d1a201SWarner Losh }
326140cffd3SDavid Greenman 
327e46ea891SNate Williams /*
328e46ea891SNate Williams  * currently, it can turn off the display, but the display never comes
329e46ea891SNate Williams  * back until the machine suspend/resumes :-).
330e46ea891SNate Williams  */
331a607c5e4SNate Lawson static void
apm_display(int fd,int newstate)332e46ea891SNate Williams apm_display(int fd, int newstate)
333e46ea891SNate Williams {
334afe83a1cSPhilippe Charnier 	if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
335295e0cdaSBrian Feldman 		err(1, "ioctl(APMIO_DISPLAY)");
336e46ea891SNate Williams }
337e46ea891SNate Williams 
338a607c5e4SNate Lawson static void
apm_haltcpu(int fd,int enable)339f4732084SMaxime Henrion apm_haltcpu(int fd, int enable)
340f4732084SMaxime Henrion {
341295e0cdaSBrian Feldman 	if (enable) {
342295e0cdaSBrian Feldman 		if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
343295e0cdaSBrian Feldman 			err(1, "ioctl(APMIO_HALTCPU)");
344295e0cdaSBrian Feldman 	} else {
345295e0cdaSBrian Feldman 		if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
346295e0cdaSBrian Feldman 			err(1, "ioctl(APMIO_NOTHALTCPU)");
347295e0cdaSBrian Feldman 	}
348295e0cdaSBrian Feldman }
349e46ea891SNate Williams 
350a607c5e4SNate Lawson static void
apm_set_timer(int fd,int delta)35194d1a201SWarner Losh apm_set_timer(int fd, int delta)
35294d1a201SWarner Losh {
35394d1a201SWarner Losh 	time_t tmr;
35494d1a201SWarner Losh 	struct tm *tm;
35594d1a201SWarner Losh 	struct apm_bios_arg args;
35694d1a201SWarner Losh 
35794d1a201SWarner Losh 	tmr = time(NULL) + delta;
35894d1a201SWarner Losh 	if (cmos_wall)
35994d1a201SWarner Losh 		tm = localtime(&tmr);
36094d1a201SWarner Losh 	else
36194d1a201SWarner Losh 		tm = gmtime(&tmr);
36294d1a201SWarner Losh 	bzero(&args, sizeof(args));
36394d1a201SWarner Losh 	args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
36494d1a201SWarner Losh 	args.ebx = PMDV_APMBIOS;
36594d1a201SWarner Losh 	if (delta > 0) {
36694d1a201SWarner Losh 		args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02;
36794d1a201SWarner Losh 		args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min);
36894d1a201SWarner Losh 		args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday);
36994d1a201SWarner Losh 		args.edi = int2bcd(tm->tm_year + 1900);
37094d1a201SWarner Losh 	} else {
37194d1a201SWarner Losh 		args.ecx = 0x0000;
37294d1a201SWarner Losh 	}
37394d1a201SWarner Losh 	if (ioctl(fd, APMIO_BIOS, &args)) {
3744cdb6a34SPhilippe Charnier 		err(1,"set resume timer");
37594d1a201SWarner Losh 	}
37694d1a201SWarner Losh }
37794d1a201SWarner Losh 
378e46ea891SNate Williams int
main(int argc,char * argv[])379e46ea891SNate Williams main(int argc, char *argv[])
380e46ea891SNate Williams {
381e46ea891SNate Williams 	int	c, fd;
382a607c5e4SNate Lawson 	int     dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
383295e0cdaSBrian Feldman 	int     display = -1, batt_life = 0, ac_status = 0, standby = 0;
384295e0cdaSBrian Feldman 	int	batt_time = 0, delta = 0, enable = -1, haltcpu = -1;
3857e3809fdSHajimu UMEMOTO 	int	bioscall_available = 0;
38694c8c4fbSBrian Feldman 	size_t	cmos_wall_len = sizeof(cmos_wall);
387afe83a1cSPhilippe Charnier 
38894c8c4fbSBrian Feldman 	if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
38994c8c4fbSBrian Feldman 	    NULL, 0) == -1)
39094c8c4fbSBrian Feldman 		err(1, "sysctlbyname(machdep.wall_cmos_clock)");
391140cffd3SDavid Greenman 
392295e0cdaSBrian Feldman 	while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
393e46ea891SNate Williams 		switch (c) {
394e46ea891SNate Williams 		case 'a':
395e46ea891SNate Williams 			ac_status = 1;
396140cffd3SDavid Greenman 			all_info = 0;
397140cffd3SDavid Greenman 			break;
398140cffd3SDavid Greenman 		case 'b':
399140cffd3SDavid Greenman 			batt_status = 1;
400140cffd3SDavid Greenman 			all_info = 0;
401140cffd3SDavid Greenman 			break;
402e46ea891SNate Williams 		case 'd':
403295e0cdaSBrian Feldman 			display = is_true(optarg);
404140cffd3SDavid Greenman 			all_info = 0;
405140cffd3SDavid Greenman 			break;
406140cffd3SDavid Greenman 		case 'l':
407140cffd3SDavid Greenman 			batt_life = 1;
408140cffd3SDavid Greenman 			all_info = 0;
409e46ea891SNate Williams 			break;
41094d1a201SWarner Losh 		case 'R':
41194d1a201SWarner Losh 			delta = -1;
41294d1a201SWarner Losh 			break;
41394d1a201SWarner Losh 		case 'r':
41494d1a201SWarner Losh 			delta = atoi(optarg);
41594d1a201SWarner Losh 			break;
416b8d133e0SNate Williams 		case 's':
417b8d133e0SNate Williams 			apm_status = 1;
418b8d133e0SNate Williams 			all_info = 0;
419140cffd3SDavid Greenman 			break;
420701eaeb3SBrian Feldman 		case 'e':
421295e0cdaSBrian Feldman 			enable = is_true(optarg);
422c7daa47bSMaxim Sobolev 			all_info = 0;
423295e0cdaSBrian Feldman 			break;
424295e0cdaSBrian Feldman 		case 'h':
425295e0cdaSBrian Feldman 			haltcpu = is_true(optarg);
426c7daa47bSMaxim Sobolev 			all_info = 0;
427701eaeb3SBrian Feldman 			break;
428ec8f6ad7SJohn Polstra 		case 't':
429ec8f6ad7SJohn Polstra 			batt_time = 1;
430ec8f6ad7SJohn Polstra 			all_info = 0;
431ec8f6ad7SJohn Polstra 			break;
432e46ea891SNate Williams 		case 'z':
433a607c5e4SNate Lawson 			dosleep = 1;
434e46ea891SNate Williams 			all_info = 0;
435e46ea891SNate Williams 			break;
43694d1a201SWarner Losh 		case 'Z':
43794d1a201SWarner Losh 			standby = 1;
43894d1a201SWarner Losh 			all_info = 0;
43994d1a201SWarner Losh 			break;
440e46ea891SNate Williams 		case '?':
44119a41dfcSPoul-Henning Kamp 		default:
442e46ea891SNate Williams 			usage();
443140cffd3SDavid Greenman 		}
444e46ea891SNate Williams 		argc -= optind;
445e46ea891SNate Williams 		argv += optind;
446140cffd3SDavid Greenman 	}
447a607c5e4SNate Lawson 	if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
448a607c5e4SNate Lawson 	    || standby) {
449140cffd3SDavid Greenman 		fd = open(APMDEV, O_RDWR);
4507e3809fdSHajimu UMEMOTO 		bioscall_available = 1;
4517e3809fdSHajimu UMEMOTO 	} else if ((fd = open(APMDEV, O_RDWR)) >= 0)
4527e3809fdSHajimu UMEMOTO 		bioscall_available = 1;
453ad5536b5SWarner Losh 	else
454ad5536b5SWarner Losh 		fd = open(APMDEV, O_RDONLY);
455295e0cdaSBrian Feldman 	if (fd == -1)
456295e0cdaSBrian Feldman 		err(1, "can't open %s", APMDEV);
457295e0cdaSBrian Feldman 	if (enable != -1)
458295e0cdaSBrian Feldman 		apm_enable(fd, enable);
459295e0cdaSBrian Feldman 	if (haltcpu != -1)
460295e0cdaSBrian Feldman 		apm_haltcpu(fd, haltcpu);
46194d1a201SWarner Losh 	if (delta)
46294d1a201SWarner Losh 		apm_set_timer(fd, delta);
463a607c5e4SNate Lawson 	if (dosleep)
464140cffd3SDavid Greenman 		apm_suspend(fd);
46594d1a201SWarner Losh 	else if (standby)
46694d1a201SWarner Losh 		apm_standby(fd);
46794d1a201SWarner Losh 	else if (delta == 0) {
468140cffd3SDavid Greenman 		struct apm_info info;
469140cffd3SDavid Greenman 
470140cffd3SDavid Greenman 		apm_getinfo(fd, &info);
471e46ea891SNate Williams 		if (all_info)
4727e3809fdSHajimu UMEMOTO 			print_all_info(fd, &info, bioscall_available);
473ec8f6ad7SJohn Polstra 		if (ac_status)
474ec8f6ad7SJohn Polstra 			printf("%d\n", info.ai_acline);
475e46ea891SNate Williams 		if (batt_status)
476140cffd3SDavid Greenman 			printf("%d\n", info.ai_batt_stat);
477e46ea891SNate Williams 		if (batt_life)
478140cffd3SDavid Greenman 			printf("%d\n", info.ai_batt_life);
479e46ea891SNate Williams 		if (apm_status)
480b8d133e0SNate Williams 			printf("%d\n", info.ai_status);
481ec8f6ad7SJohn Polstra 		if (batt_time)
482ec8f6ad7SJohn Polstra 			printf("%d\n", info.ai_batt_time);
483295e0cdaSBrian Feldman 		if (display != -1)
484295e0cdaSBrian Feldman 			apm_display(fd, display);
485140cffd3SDavid Greenman 	}
486140cffd3SDavid Greenman 	close(fd);
487295e0cdaSBrian Feldman 	exit(0);
488140cffd3SDavid Greenman }
489