diff options
Diffstat (limited to 'usr.sbin/apm')
| -rw-r--r-- | usr.sbin/apm/Makefile | 8 | ||||
| -rw-r--r-- | usr.sbin/apm/Makefile.depend | 15 | ||||
| -rw-r--r-- | usr.sbin/apm/apm.8 | 151 | ||||
| -rw-r--r-- | usr.sbin/apm/apm.c | 488 | 
4 files changed, 662 insertions, 0 deletions
| diff --git a/usr.sbin/apm/Makefile b/usr.sbin/apm/Makefile new file mode 100644 index 000000000000..f6c42194401f --- /dev/null +++ b/usr.sbin/apm/Makefile @@ -0,0 +1,8 @@ +PROG=	apm +MAN=	apm.8 +MLINKS=	apm.8 apmconf.8 +MANSUBDIR= /${MACHINE_CPUARCH} + +PACKAGE=apm + +.include <bsd.prog.mk> diff --git a/usr.sbin/apm/Makefile.depend b/usr.sbin/apm/Makefile.depend new file mode 100644 index 000000000000..6ef78fac5cbf --- /dev/null +++ b/usr.sbin/apm/Makefile.depend @@ -0,0 +1,15 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/apm/apm.8 b/usr.sbin/apm/apm.8 new file mode 100644 index 000000000000..d6ede22066da --- /dev/null +++ b/usr.sbin/apm/apm.8 @@ -0,0 +1,151 @@ +.\" LP (Laptop Package) +.\" +.\" Copyright (c) 1994 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> +.\" +.\" This software may be used, modified, copied, and distributed, in +.\" both source and binary form provided that the above copyright and +.\" these terms are retained. Under no circumstances is the author +.\" responsible for the proper functioning of this software, nor does +.\" the author assume any responsibility for damages incurred with its +.\" use. +.\" +.Dd December 22, 2009 +.Dt APM 8 i386 +.Os +.Sh NAME +.Nm apm +.Nd control the APM BIOS and display its information +.Sh SYNOPSIS +.Nm +.Op Fl ablstzZ +.Op Fl d Ar enable +.Op Fl e Ar enable +.Op Fl h Ar enable +.Op Fl r Ar delta +.Sh DESCRIPTION +The +.Nm +utility +controls the Intel / Microsoft APM (Advanced Power Management) BIOS and +displays the current status of APM on laptop PCs. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a +Display the current AC-line status as an integer value. +The values +0, 1 and 2 correspond to the +.Dq off-line +state, +.Dq on-line +state or +.Dq backup power +state, respectively. +.It Fl b +Display an integer value reflecting the current battery status. +The values 0, 1, 2, 3, correspond to the +.Dq high +status, +.Dq low +status, +.Dq critical +status, +.Dq charging +status respectively. +.It Fl d Ar enable +Disable/enable suspending of the display separately from a normal suspend +using the boolean value for +.Ar enable . +This feature seems to not work on many different laptops, +including the Libretto 30CT and 50CT. +.It Fl e Ar enable +Enable or disable APM functions of the computer, +depending on the boolean +.Ar enable +argument. +.It Fl h Ar enable +Depending on the boolean value of +.Ar enable , +enable or disable the HLT instruction in the kernel context switch routine. +These options are not necessary for almost all APM implementations, +but for some implementations whose +.Dq Pa Idle CPU +call executes both CPU clock slowdown and HLT instruction, +.Fl h Cm false +is necessary to prevent the system from reducing its peak performance. +See +.Xr apm 4 +for details. +.It Fl l +Display the remaining battery percentage. +If your laptop does not +support this function, 255 is displayed. +.It Fl r Ar delta +Enable the resume wakeup timer, if the laptop supports it. +This +does not actually suspend the laptop, but if the laptop is suspended, +and it supports resume from suspend, then it will be resumed after +.Ar delta +seconds (from when you run this command, not from when you suspend). +.It Fl s +Display the status of the APM support as an integer value. +The values +0 and 1 correspond to the +.Dq disabled +state or +.Dq enabled +state respectively. +.It Fl t +Display the estimated remaining battery lifetime in seconds. +If +it is unknown, -1 is displayed. +.It Fl Z +Transition the system into standby mode. +This mode uses less power than +full power mode, but more than suspend mode. +Some laptops support +resuming from this state on timer or Ring Indicator events. +The +output of +.Nm +tells what your laptop claims to support. +.It Fl z +Suspend the system. +It is used by +.Xr zzz 8 . +.El +.Pp +If no options are specified, +.Nm +displays information and current status of APM in verbose mode. +If multiple display options are given, the values are displayed one +per line in the order given here. +.Sh NOTES +.Xr apmconf 8 +has been merged in +.Nm +and thus +.Nm +replaces all of its functionality. +.Sh SEE ALSO +.Xr apm 4 , +.Xr zzz 8 +.Sh AUTHORS +.An Tatsumi Hosokawa Aq Mt hosokawa@jp.FreeBSD.org +.Sh BUGS +Some APM implementations do not support parameters needed by +.Nm . +On such systems, +.Nm +displays them as unknown. +.Pp +Some APM implementations cannot handle events such as pushing the +power button or closing the cover. +On such implementations, the system +.Ar must +be suspended +.Ar only +by using +.Nm +or +.Nm zzz . diff --git a/usr.sbin/apm/apm.c b/usr.sbin/apm/apm.c new file mode 100644 index 000000000000..01e75eb1f8b1 --- /dev/null +++ b/usr.sbin/apm/apm.c @@ -0,0 +1,488 @@ +/* + * APM BIOS utility for FreeBSD + * + * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include <sys/cdefs.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <machine/apm_bios.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#define APMDEV	"/dev/apm" + +#define APM_UNKNOWN	255 + +#define xh(a)	(((a) & 0xff00) >> 8) +#define xl(a)	((a) & 0xff) +#define APMERR(a) xh(a) + +static int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */ + +static void +usage(void) +{ +	fprintf(stderr, +		"usage: apm [-ablstzZ] [-d enable ] [ -e enable ] " +		"[ -h enable ] [-r delta]\n"); +	exit(1); +} + +/* + * Return 1 for boolean true, and 0 for false, according to the + * interpretation of the string argument given. + */ +static int +is_true(const char *boolean) +{ +	char *endp; +	long val; + +	val = strtoul(boolean, &endp, 0); +	if (*endp == '\0') +		return (val != 0 ? 1 : 0); +	if (strcasecmp(boolean, "true") == 0 || +	    strcasecmp(boolean, "yes") == 0 || +	    strcasecmp(boolean, "enable") == 0) +		return (1); +	if (strcasecmp(boolean, "false") == 0 || +	    strcasecmp(boolean, "no") == 0 || +	    strcasecmp(boolean, "disable") == 0) +		return (0); +	/* Well, I have no idea what the user wants, so... */ +	warnx("invalid boolean argument \"%s\"", boolean); +	usage(); +	/* NOTREACHED */ + +	return (0); +} + +static int +int2bcd(int i) +{ +	int retval = 0; +	int base = 0; + +	if (i >= 10000) +		return -1; +     +	while (i) { +		retval |= (i % 10) << base; +		i /= 10; +		base += 4; +	} +	return retval; +} + +static int +bcd2int(int bcd) +{ +	int retval = 0; +	int place = 1; + +	if (bcd > 0x9999) +		return -1; + +	while (bcd) { +		retval += (bcd & 0xf) * place; +		bcd >>= 4; +		place *= 10; +	} +	return retval; +} + +static void  +apm_suspend(int fd) +{ +	if (ioctl(fd, APMIO_SUSPEND, NULL) == -1) +		err(1, "ioctl(APMIO_SUSPEND)"); +} + +static void  +apm_standby(int fd) +{ +	if (ioctl(fd, APMIO_STANDBY, NULL) == -1) +		err(1, "ioctl(APMIO_STANDBY)"); +} + +static void  +apm_getinfo(int fd, apm_info_t aip) +{ +	if (ioctl(fd, APMIO_GETINFO, aip) == -1) +		err(1, "ioctl(APMIO_GETINFO)"); +} + +static void  +apm_enable(int fd, int enable)  +{ +	if (enable) { +		if (ioctl(fd, APMIO_ENABLE) == -1) +			err(1, "ioctl(APMIO_ENABLE)"); +	} else { +		if (ioctl(fd, APMIO_DISABLE) == -1) +			err(1, "ioctl(APMIO_DISABLE)"); +	} +} + +static void +print_batt_time(int batt_time) +{ +	printf("Remaining battery time: "); +	if (batt_time == -1) +		printf("unknown\n"); +	else { +		int h, m, s; + +		h = batt_time; +		s = h % 60; +		h /= 60; +		m = h % 60; +		h /= 60; +		printf("%2d:%02d:%02d\n", h, m, s); +	} +} + +static void +print_batt_life(u_int batt_life) +{ +	printf("Remaining battery life: "); +	if (batt_life == APM_UNKNOWN) +		printf("unknown\n"); +	else if (batt_life <= 100) +		printf("%d%%\n", batt_life); +	else +		printf("invalid value (0x%x)\n", batt_life); +} + +static void +print_batt_stat(u_int batt_stat) +{ +	const char *batt_msg[] = { "high", "low", "critical", "charging" }; + +	printf("Battery Status: "); +	if (batt_stat == APM_UNKNOWN) +		printf("unknown\n"); +	else if (batt_stat > 3) +		printf("invalid value (0x%x)\n", batt_stat); +	else +		printf("%s\n", batt_msg[batt_stat]); +} + +static void  +print_all_info(int fd, apm_info_t aip, int bioscall_available) +{ +	struct apm_bios_arg args; +	int apmerr; +	const char *line_msg[] = { "off-line", "on-line" , "backup power"}; + +	printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor); +	printf("APM Management: %s\n", aip->ai_status ? "Enabled" : "Disabled"); +	printf("AC Line status: "); +	if (aip->ai_acline == APM_UNKNOWN) +		printf("unknown\n"); +	else if (aip->ai_acline > 2) +		printf("invalid value (0x%x)\n", aip->ai_acline); +	else +		printf("%s\n", line_msg[aip->ai_acline]); + +	print_batt_stat(aip->ai_batt_stat); +	print_batt_life(aip->ai_batt_life); +	print_batt_time(aip->ai_batt_time); + +	if (aip->ai_infoversion >= 1) { +		printf("Number of batteries: "); +		if (aip->ai_batteries == ~0U) +			printf("unknown\n"); +		else { +			u_int i; +			struct apm_pwstatus aps; + +			printf("%d\n", aip->ai_batteries); +			for (i = 0; i < aip->ai_batteries; ++i) { +				bzero(&aps, sizeof(aps)); +				aps.ap_device = PMDV_BATT0 + i; +				if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1) +					continue; +				printf("Battery %d:\n", i); +				if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) { +					printf("not present\n"); +					continue; +				} +				printf("\t"); +				print_batt_stat(aps.ap_batt_stat); +				printf("\t"); +				print_batt_life(aps.ap_batt_life); +				printf("\t"); +				print_batt_time(aps.ap_batt_time); +			} +		} +	} + +	if (bioscall_available) { +		/* +		 * try to get the suspend timer +		 */ +		bzero(&args, sizeof(args)); +		args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; +		args.ebx = PMDV_APMBIOS; +		args.ecx = 0x0001; +		if (ioctl(fd, APMIO_BIOS, &args)) { +			printf("Resume timer: unknown\n"); +		} else { +			apmerr = APMERR(args.eax); +			if (apmerr == 0x0d || apmerr == 0x86) +				printf("Resume timer: disabled\n"); +			else if (apmerr) +				warnx( +		"failed to get the resume timer: APM error0x%x", apmerr); +			else { +				/* +				 * OK.  We have the time (all bcd). +				 * CH - seconds +				 * DH - hours +				 * DL - minutes +				 * xh(SI) - month (1-12) +				 * xl(SI) - day of month (1-31) +				 * DI - year +				 */ +				struct tm tm; +				char buf[1024]; +				time_t t; + +				tm.tm_sec = bcd2int(xh(args.ecx)); +				tm.tm_min = bcd2int(xl(args.edx)); +				tm.tm_hour = bcd2int(xh(args.edx)); +				tm.tm_mday = bcd2int(xl(args.esi)); +				tm.tm_mon = bcd2int(xh(args.esi)) - 1; +				tm.tm_year = bcd2int(args.edi) - 1900; +				if (cmos_wall) +					t = mktime(&tm); +				else +					t = timegm(&tm); +				if (t != -1) { +					tm = *localtime(&t); +					strftime(buf, sizeof(buf), "%c", &tm); +					printf("Resume timer: %s\n", buf); +				} else +					printf("Resume timer: unknown\n"); +			} +		} + +		/* +		 * Get the ring indicator resume state +		 */ +		bzero(&args, sizeof(args)); +		args.eax  = (APM_BIOS) << 8 | APM_RESUMEONRING; +		args.ebx = PMDV_APMBIOS; +		args.ecx = 0x0002; +		if (ioctl(fd, APMIO_BIOS, &args) == 0) { +			printf("Resume on ring indicator: %sabled\n", +			    args.ecx ? "en" : "dis"); +		} +	} + +	if (aip->ai_infoversion >= 1) { +		if (aip->ai_capabilities == 0xff00) +		    return; +		printf("APM Capabilities:\n"); +		if (aip->ai_capabilities & 0x01) +			printf("\tglobal standby state\n"); +		if (aip->ai_capabilities & 0x02) +			printf("\tglobal suspend state\n"); +		if (aip->ai_capabilities & 0x04) +			printf("\tresume timer from standby\n"); +		if (aip->ai_capabilities & 0x08) +			printf("\tresume timer from suspend\n"); +		if (aip->ai_capabilities & 0x10) +			printf("\tRI resume from standby\n"); +		if (aip->ai_capabilities & 0x20) +			printf("\tRI resume from suspend\n"); +		if (aip->ai_capabilities & 0x40) +			printf("\tPCMCIA RI resume from standby\n"); +		if (aip->ai_capabilities & 0x80) +			printf("\tPCMCIA RI resume from suspend\n"); +	} + +} + +/* + * currently, it can turn off the display, but the display never comes + * back until the machine suspend/resumes :-). + */ +static void  +apm_display(int fd, int newstate) +{ +	if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1) +		err(1, "ioctl(APMIO_DISPLAY)"); +} + +static void +apm_haltcpu(int fd, int enable) +{ +	if (enable) { +		if (ioctl(fd, APMIO_HALTCPU, NULL) == -1) +			err(1, "ioctl(APMIO_HALTCPU)"); +	} else { +		if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1) +			err(1, "ioctl(APMIO_NOTHALTCPU)"); +	} +} + +static void +apm_set_timer(int fd, int delta) +{ +	time_t tmr; +	struct tm *tm; +	struct apm_bios_arg args; + +	tmr = time(NULL) + delta; +	if (cmos_wall) +		tm = localtime(&tmr); +	else +		tm = gmtime(&tmr); +	bzero(&args, sizeof(args)); +	args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; +	args.ebx = PMDV_APMBIOS; +	if (delta > 0) { +		args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02; +		args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min); +		args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday); +		args.edi = int2bcd(tm->tm_year + 1900); +	} else { +		args.ecx = 0x0000; +	} +	if (ioctl(fd, APMIO_BIOS, &args)) { +		err(1,"set resume timer"); +	} +} + +int  +main(int argc, char *argv[]) +{ +	int	c, fd; +	int     dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0; +	int     display = -1, batt_life = 0, ac_status = 0, standby = 0; +	int	batt_time = 0, delta = 0, enable = -1, haltcpu = -1; +	int	bioscall_available = 0; +	size_t	cmos_wall_len = sizeof(cmos_wall); + +	if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len, +	    NULL, 0) == -1) +		err(1, "sysctlbyname(machdep.wall_cmos_clock)"); + +	while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) { +		switch (c) { +		case 'a': +			ac_status = 1; +			all_info = 0; +			break; +		case 'b': +			batt_status = 1; +			all_info = 0; +			break; +		case 'd': +			display = is_true(optarg); +			all_info = 0; +			break; +		case 'l': +			batt_life = 1; +			all_info = 0; +			break; +		case 'R': +			delta = -1; +			break; +		case 'r': +			delta = atoi(optarg); +			break; +		case 's': +			apm_status = 1; +			all_info = 0; +			break; +		case 'e': +			enable = is_true(optarg); +			all_info = 0; +			break; +		case 'h': +			haltcpu = is_true(optarg); +			all_info = 0; +			break; +		case 't': +			batt_time = 1; +			all_info = 0; +			break; +		case 'z': +			dosleep = 1; +			all_info = 0; +			break; +		case 'Z': +			standby = 1; +			all_info = 0; +			break; +		case '?': +		default: +			usage(); +		} +		argc -= optind; +		argv += optind; +	} +	if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep +	    || standby) { +		fd = open(APMDEV, O_RDWR); +		bioscall_available = 1; +	} else if ((fd = open(APMDEV, O_RDWR)) >= 0) +		bioscall_available = 1; +	else +		fd = open(APMDEV, O_RDONLY); +	if (fd == -1) +		err(1, "can't open %s", APMDEV); +	if (enable != -1) +		apm_enable(fd, enable); +	if (haltcpu != -1) +		apm_haltcpu(fd, haltcpu); +	if (delta) +		apm_set_timer(fd, delta); +	if (dosleep) +		apm_suspend(fd); +	else if (standby) +		apm_standby(fd); +	else if (delta == 0) { +		struct apm_info info; + +		apm_getinfo(fd, &info); +		if (all_info) +			print_all_info(fd, &info, bioscall_available); +		if (ac_status) +			printf("%d\n", info.ai_acline); +		if (batt_status) +			printf("%d\n", info.ai_batt_stat); +		if (batt_life) +			printf("%d\n", info.ai_batt_life); +		if (apm_status) +			printf("%d\n", info.ai_status); +		if (batt_time) +			printf("%d\n", info.ai_batt_time); +		if (display != -1) +			apm_display(fd, display); +	} +	close(fd); +	exit(0); +} | 
