apm.c revision 48938
14Srgrimes/* 21690Sdg * apm / zzz APM BIOS utility for FreeBSD 31690Sdg * 41690Sdg * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 54Srgrimes * 64Srgrimes * This software may be used, modified, copied, distributed, and sold, 74Srgrimes * in both source and binary form provided that the above copyright and 84Srgrimes * these terms are retained. Under no circumstances is the author 94Srgrimes * responsible for the proper functioning of this software, nor does 104Srgrimes * the author assume any responsibility for damages incurred with its 114Srgrimes * use. 124Srgrimes * 134Srgrimes * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) 144Srgrimes */ 154Srgrimes 164Srgrimes#ifndef lint 174Srgrimesstatic const char rcsid[] = 184Srgrimes "$Id: apm.c,v 1.14 1998/09/04 16:08:54 imp Exp $"; 194Srgrimes#endif /* not lint */ 204Srgrimes 214Srgrimes#include <sys/file.h> 224Srgrimes#include <sys/ioctl.h> 234Srgrimes#include <sys/types.h> 244Srgrimes#include <sys/sysctl.h> 254Srgrimes 264Srgrimes#include <machine/apm_bios.h> 274Srgrimes 284Srgrimes#include <err.h> 294Srgrimes#include <stdio.h> 304Srgrimes#include <stdlib.h> 314Srgrimes#include <string.h> 324Srgrimes#include <sys/file.h> 334Srgrimes#include <sys/ioctl.h> 344Srgrimes#include <time.h> 354Srgrimes#include <unistd.h> 364Srgrimes 37608Srgrimes#define APMDEV "/dev/apm" 3850477Speter 394Srgrimes#define xh(a) (((a) & 0xff00) >> 8) 404Srgrimes#define xl(a) ((a) & 0xff) 414Srgrimes#define APMERR(a) xh(a) 421704Sdg 434Srgrimesint cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */ 444Srgrimes 4571257Spetervoid 4631544Sjmgusage() 4731544Sjmg{ 4813203Swollman fprintf(stderr, "%s\n%s\n", 4971257Speter "usage: apm [-ablstzZ] [-d 1|0] [-r delta]", 5032925Seivind " zzz"); 5113203Swollman exit(1); 521549Srgrimes} 5365557Sjasone 541549Srgrimesint 551549Srgrimesint2bcd(int i) 5631564Ssef{ 5767365Sjhb int retval = 0; 581549Srgrimes int base = 0; 5965557Sjasone 6067365Sjhb if (i >= 10000) 6131389Sbde return -1; 6231389Sbde 631549Srgrimes while (i) { 6464294Sps retval |= (i % 10) << base; 652257Ssos i /= 10; 6634924Sbde base += 4; 6712662Sdg } 684Srgrimes return retval; 691549Srgrimes} 704Srgrimes 714Srgrimesint 7212662Sdgbcd2int(int bcd) 731549Srgrimes{ 7422521Sdyson int retval = 0; 751549Srgrimes 767090Sbde if (bcd > 0x9999) 771549Srgrimes return -1; 781549Srgrimes 7912662Sdg while (bcd) { 804Srgrimes retval = retval * 10 + ((bcd & 0xf000) >> 12); 811549Srgrimes bcd = (bcd & 0xfff) << 4; 827090Sbde } 8331389Sbde return retval; 8431389Sbde} 8525164Speter 8631389Sbdevoid 8730275Speterapm_suspend(int fd) 881549Srgrimes{ 8965557Sjasone if (ioctl(fd, APMIO_SUSPEND, NULL) == -1) 9031389Sbde err(1, NULL); 9131389Sbde} 929545Sjoerg 9318207Sbdevoid 9418207Sbdeapm_standby(int fd) 959545Sjoerg{ 969545Sjoerg if (ioctl(fd, APMIO_STANDBY, NULL) == -1) 9730275Speter err(1, NULL); 9830275Speter} 9955823Syokota 10042135Smsmithvoid 1011549Srgrimesapm_getinfo(int fd, apm_info_t aip) 1021549Srgrimes{ 10365557Sjasone if (ioctl(fd, APMIO_GETINFO, aip) == -1) 10465557Sjasone err(1, NULL); 10512817Sphk} 10612817Sphk 10711343Sbdevoid 10811343Sbdeprint_all_info(int fd, apm_info_t aip) 10958717Sdillon{ 11065557Sjasone struct apm_bios_arg args; 11111343Sbde int apmerr; 11241454Skato 11341454Skato printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor); 11412929Sdg printf("APM Managment: %s\n", (aip->ai_status ? "Enabled" : "Disabled")); 1154Srgrimes printf("AC Line status: "); 11611163Sjulian if (aip->ai_acline == 255) 11711163Sjulian printf("unknown"); 11817521Sdg else if (aip->ai_acline > 1) 11912702Sphk printf("invalid value (0x%x)", aip->ai_acline); 1205603Sbde else { 121757Sdg char messages[][10] = {"off-line", "on-line"}; 1225603Sbde printf("%s", messages[aip->ai_acline]); 123757Sdg } 124757Sdg printf("\n"); 1255603Sbde printf("Battery status: "); 126757Sdg if (aip->ai_batt_stat == 255) 127757Sdg printf("unknown"); 1285603Sbde else if (aip->ai_batt_stat > 3) 1291690Sdg printf("invalid value (0x%x)", aip->ai_batt_stat); 130757Sdg else { 131757Sdg char messages[][10] = {"high", "low", "critical", "charging"}; 132757Sdg printf("%s", messages[aip->ai_batt_stat]); 1335603Sbde } 134757Sdg printf("\n"); 1355603Sbde printf("Remaining battery life: "); 1365603Sbde if (aip->ai_batt_life == 255) 1375603Sbde printf("unknown"); 138757Sdg else if (aip->ai_batt_life <= 100) 139757Sdg printf("%d%%", aip->ai_batt_life); 140757Sdg else 141757Sdg printf("invalid value (0x%x)", aip->ai_batt_life); 142757Sdg printf("\n"); 143757Sdg printf("Remaining battery time: "); 144757Sdg if (aip->ai_batt_time == -1) 145757Sdg printf("unknown"); 146757Sdg else { 147757Sdg int t, h, m, s; 14817521Sdg 149757Sdg t = aip->ai_batt_time; 1504Srgrimes s = t % 60; 15131535Sjkh t /= 60; 15231507Ssef m = t % 60; 15331507Ssef t /= 60; 15431507Ssef h = t; 15564294Sps printf("%2d:%02d:%02d", h, m, s); 15664294Sps } 15764294Sps printf("\n"); 15864294Sps if (aip->ai_infoversion >= 1) { 15964294Sps printf("Number of batteries: "); 16064294Sps if (aip->ai_batteries == (u_int) -1) 16164294Sps printf("unknown\n"); 16264294Sps else 16364294Sps printf("%d\n", aip->ai_batteries); 16469881Sjake } 16569881Sjake 16669881Sjake /* 16769881Sjake * try to get the suspend timer 16871527Sjhb */ 16971527Sjhb bzero(&args, sizeof(args)); 1701690Sdg args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 1711690Sdg args.ebx = PMDV_APMBIOS; 1721690Sdg args.ecx = 0x0001; 1731690Sdg if (ioctl(fd, APMIO_BIOS, &args)) { 17471527Sjhb err(1,"Get resume timer"); 175757Sdg } else { 17658717Sdillon apmerr = APMERR(args.eax); 17771527Sjhb if (apmerr == 0x0d || apmerr == 0x86) 17865557Sjasone printf("Resume timer: disabled\n"); 1791690Sdg else if (apmerr) 18058717Sdillon fprintf(stderr, 18128013Sdyson "Failed to get the resume timer: APM error0x%x\n", 18271527Sjhb apmerr); 1831690Sdg else { 18458717Sdillon /* 1851690Sdg * OK. We have the time (all bcd). 1861690Sdg * CH - seconds 1871690Sdg * DH - hours 1881690Sdg * DL - minutes 1891690Sdg * xh(SI) - month (1-12) 1901690Sdg * xl(SI) - day of month (1-31) 1911690Sdg * DI - year 1921690Sdg */ 19368808Sjhb struct tm tm; 1941690Sdg char buf[1024]; 1951690Sdg time_t t; 1961690Sdg 19765557Sjasone tm.tm_sec = bcd2int(xh(args.ecx)); 19868808Sjhb tm.tm_min = bcd2int(xl(args.edx)); 19965557Sjasone tm.tm_hour = bcd2int(xh(args.edx)); 20071527Sjhb tm.tm_mday = bcd2int(xl(args.esi)); 20165557Sjasone tm.tm_mon = bcd2int(xh(args.esi)) - 1; 2021690Sdg tm.tm_year = bcd2int(args.edi) - 1900; 20365557Sjasone if (cmos_wall) 20471527Sjhb t = mktime(&tm); 2051690Sdg else 20671527Sjhb t = timegm(&tm); 2076296Sdg tm = *localtime(&t); 2086296Sdg strftime(buf, sizeof(buf), "%c", &tm); 2096296Sdg printf("Resume timer: %s\n", buf); 21071527Sjhb } 21171527Sjhb } 21271527Sjhb 21371527Sjhb /* 21465557Sjasone * Get the ring indicator resume state 21571527Sjhb */ 21616725Sbde bzero(&args, sizeof(args)); 21716725Sbde args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING; 21858717Sdillon args.ebx = PMDV_APMBIOS; 2191690Sdg args.ecx = 0x0002; 22071527Sjhb if (ioctl(fd, APMIO_BIOS, &args) == 0) { 2211690Sdg printf("Resume on ring indicator: %sabled\n", 2221690Sdg args.ecx ? "en" : "dis"); 2234Srgrimes } 22411343Sbde 2251690Sdg if (aip->ai_infoversion >= 1) { 2264Srgrimes printf("APM Capacities:\n", aip->ai_capabilities); 2271690Sdg if (aip->ai_capabilities == 0xff00) 2284Srgrimes printf("\tunknown\n"); 2294Srgrimes if (aip->ai_capabilities & 0x01) 230798Swollman printf("\tglobal standby state\n"); 2314Srgrimes if (aip->ai_capabilities & 0x02) 2324Srgrimes printf("\tglobal suspend state\n"); 2334Srgrimes if (aip->ai_capabilities & 0x04) 2341690Sdg printf("\tresume timer from standby\n"); 2351549Srgrimes if (aip->ai_capabilities & 0x08) 2363436Sphk printf("\tresume timer from suspend\n"); 23741454Skato if (aip->ai_capabilities & 0x10) 23865557Sjasone printf("\tRI resume from standby\n"); 23965557Sjasone if (aip->ai_capabilities & 0x20) 24065557Sjasone printf("\tRI resume from suspend\n"); 2414Srgrimes if (aip->ai_capabilities & 0x40) 24265557Sjasone printf("\tPCMCIA RI resume from standby\n"); 24365557Sjasone if (aip->ai_capabilities & 0x80) 24465557Sjasone printf("\tPCMCIA RI resume from suspend\n"); 24541454Skato } 24665557Sjasone 24765557Sjasone} 24865557Sjasone 24965557Sjasone/* 25071527Sjhb * currently, it can turn off the display, but the display never comes 25171527Sjhb * back until the machine suspend/resumes :-). 25241454Skato */ 25341454Skatovoid 25441454Skatoapm_display(int fd, int newstate) 25541454Skato{ 25641454Skato if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1) 25741454Skato err(1, NULL); 25841454Skato} 25941454Skato 26041454Skato 26141454Skatovoid 26241454Skatoapm_set_timer(int fd, int delta) 26341454Skato{ 26441454Skato time_t tmr; 26571527Sjhb struct tm *tm; 26671527Sjhb struct apm_bios_arg args; 26771527Sjhb 26871527Sjhb tmr = time(NULL) + delta; 26941454Skato if (cmos_wall) 27041454Skato tm = localtime(&tmr); 27141454Skato else 27241454Skato tm = gmtime(&tmr); 27341454Skato bzero(&args, sizeof(args)); 27441454Skato args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 27565557Sjasone args.ebx = PMDV_APMBIOS; 27665557Sjasone if (delta > 0) { 27765557Sjasone args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02; 27865557Sjasone args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min); 27965557Sjasone args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday); 28041454Skato args.edi = int2bcd(tm->tm_year + 1900); 28141454Skato } else { 28241454Skato args.ecx = 0x0000; 28365557Sjasone } 28441454Skato if (ioctl(fd, APMIO_BIOS, &args)) { 28565811Sbde err(1,"Set resume timer"); 28665557Sjasone } 28731535Sjkh} 28831507Ssef 28931507Ssefint 29065557Sjasonemain(int argc, char *argv[]) 2914Srgrimes{ 2921690Sdg int c, fd; 2938876Srgrimes int sleep = 0, all_info = 1, apm_status = 0, batt_status = 0; 29465557Sjasone int display = 0, batt_life = 0, ac_status = 0, standby = 0; 29565557Sjasone int batt_time = 0, delta = 0; 2961690Sdg char *cmdname; 297200Sdg size_t cmos_wall_len = sizeof(cmos_wall); 29871527Sjhb 2991690Sdg if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len, 30071527Sjhb NULL, 0) == -1) 30125555Speter err(1, "sysctlbyname(machdep.wall_cmos_clock)"); 3024Srgrimes if ((cmdname = strrchr(argv[0], '/')) != NULL) 3031690Sdg cmdname++; 3041690Sdg else 3051690Sdg cmdname = argv[0]; 3061690Sdg 3071690Sdg if (strcmp(cmdname, "zzz") == 0) { 308974Sdg sleep = 1; 3091690Sdg all_info = 0; 3101690Sdg goto finish_option; 3111690Sdg } 3121690Sdg while ((c = getopt(argc, argv, "ablRr:stzd:Z")) != -1) { 3131690Sdg switch (c) { 314974Sdg case 'a': 3151690Sdg ac_status = 1; 3161690Sdg all_info = 0; 3171690Sdg break; 3181690Sdg case 'b': 3194Srgrimes batt_status = 1; 32027993Sdyson all_info = 0; 32127993Sdyson break; 32227993Sdyson case 'd': 32327993Sdyson display = *optarg - '0'; 32427993Sdyson if (display < 0 || display > 1) { 3251690Sdg warnx("argument of option '-%c' is invalid", c); 32627993Sdyson usage(); 32728872Sjlemon } 32828872Sjlemon display++; 32927993Sdyson all_info = 0; 33065557Sjasone break; 33127993Sdyson case 'l': 33227993Sdyson batt_life = 1; 33327993Sdyson all_info = 0; 33427993Sdyson break; 3351690Sdg case 'R': 3365603Sbde delta = -1; 3375603Sbde break; 3385603Sbde case 'r': 3391690Sdg delta = atoi(optarg); 3401690Sdg break; 3411690Sdg case 's': 3424Srgrimes apm_status = 1; 3431690Sdg all_info = 0; 34441454Skato break; 34531535Sjkh case 't': 34665557Sjasone batt_time = 1; 34765557Sjasone all_info = 0; 34865557Sjasone break; 34965557Sjasone case 'z': 35065557Sjasone sleep = 1; 35165557Sjasone all_info = 0; 35231507Ssef break; 35365557Sjasone case 'Z': 35431507Ssef standby = 1; 35565557Sjasone all_info = 0; 35665557Sjasone break; 3571690Sdg case '?': 35865557Sjasone default: 3594Srgrimes usage(); 3601690Sdg } 3611690Sdg argc -= optind; 3624Srgrimes argv += optind; 3631690Sdg } 36449081Scracauerfinish_option: 3651690Sdg fd = open(APMDEV, O_RDWR); 3661690Sdg if (fd == -1) { 3674Srgrimes warn("can't open %s", APMDEV); 3681690Sdg return 1; 3691690Sdg } 3709545Sjoerg if (delta) 37165557Sjasone apm_set_timer(fd, delta); 37265557Sjasone if (sleep) 37365557Sjasone apm_suspend(fd); 37465557Sjasone else if (standby) 37565557Sjasone apm_standby(fd); 37665557Sjasone else if (delta == 0) { 37765557Sjasone struct apm_info info; 37865557Sjasone 37965557Sjasone apm_getinfo(fd, &info); 3809545Sjoerg if (all_info) 38163140Sps print_all_info(fd, &info); 38263140Sps if (ac_status) 3832320Sdg printf("%d\n", info.ai_acline); 38464294Sps if (batt_status) 38564294Sps printf("%d\n", info.ai_batt_stat); 38664294Sps if (batt_life) 38764294Sps printf("%d\n", info.ai_batt_life); 38864294Sps if (apm_status) 38964294Sps printf("%d\n", info.ai_status); 39064294Sps if (batt_time) 39164294Sps printf("%d\n", info.ai_batt_time); 39263140Sps if (display) 39365557Sjasone apm_display(fd, display - 1); 39464294Sps } 39564294Sps close(fd); 39664294Sps return 0; 3979545Sjoerg} 3989545Sjoerg