apm.c revision 48938
13259Sdg/* 221363Snate * apm / zzz APM BIOS utility for FreeBSD 33259Sdg * 433657Shosokawa * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 53259Sdg * 63259Sdg * This software may be used, modified, copied, distributed, and sold, 73259Sdg * in both source and binary form provided that the above copyright and 88857Srgrimes * these terms are retained. Under no circumstances is the author 98857Srgrimes * responsible for the proper functioning of this software, nor does 108857Srgrimes * the author assume any responsibility for damages incurred with its 113259Sdg * use. 123259Sdg * 133259Sdg * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) 143259Sdg */ 153259Sdg 1629030Scharnier#ifndef lint 1729030Scharnierstatic const char rcsid[] = 1848938Sgreen "$Id: apm.c,v 1.14 1998/09/04 16:08:54 imp Exp $"; 1929030Scharnier#endif /* not lint */ 2029030Scharnier 2148938Sgreen#include <sys/file.h> 2248938Sgreen#include <sys/ioctl.h> 2348938Sgreen#include <sys/types.h> 2448938Sgreen#include <sys/sysctl.h> 2548938Sgreen 2648938Sgreen#include <machine/apm_bios.h> 2748938Sgreen 2829030Scharnier#include <err.h> 293259Sdg#include <stdio.h> 3021363Snate#include <stdlib.h> 313259Sdg#include <string.h> 323259Sdg#include <sys/file.h> 333259Sdg#include <sys/ioctl.h> 3448938Sgreen#include <time.h> 3521363Snate#include <unistd.h> 363259Sdg 3714674Snate#define APMDEV "/dev/apm" 383259Sdg 3938809Simp#define xh(a) (((a) & 0xff00) >> 8) 4038809Simp#define xl(a) ((a) & 0xff) 4138809Simp#define APMERR(a) xh(a) 4238809Simp 4338809Simpint cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */ 4438809Simp 4521363Snatevoid 4621363Snateusage() 473259Sdg{ 4829030Scharnier fprintf(stderr, "%s\n%s\n", 4938809Simp "usage: apm [-ablstzZ] [-d 1|0] [-r delta]", 5029030Scharnier " zzz"); 5121363Snate exit(1); 5221363Snate} 5321363Snate 5438809Simpint 5538809Simpint2bcd(int i) 5638809Simp{ 5738809Simp int retval = 0; 5838809Simp int base = 0; 5938809Simp 6038809Simp if (i >= 10000) 6138809Simp return -1; 6238809Simp 6338809Simp while (i) { 6438809Simp retval |= (i % 10) << base; 6538809Simp i /= 10; 6638809Simp base += 4; 6738809Simp } 6838809Simp return retval; 6938809Simp} 7038809Simp 7138809Simpint 7238809Simpbcd2int(int bcd) 7338809Simp{ 7438809Simp int retval = 0; 7538809Simp 7638809Simp if (bcd > 0x9999) 7738809Simp return -1; 7838809Simp 7938809Simp while (bcd) { 8038809Simp retval = retval * 10 + ((bcd & 0xf000) >> 12); 8138809Simp bcd = (bcd & 0xfff) << 4; 8238809Simp } 8338809Simp return retval; 8438809Simp} 8538809Simp 8621363Snatevoid 8721363Snateapm_suspend(int fd) 8821363Snate{ 8929030Scharnier if (ioctl(fd, APMIO_SUSPEND, NULL) == -1) 9029030Scharnier err(1, NULL); 913259Sdg} 923259Sdg 9321363Snatevoid 9438809Simpapm_standby(int fd) 9538809Simp{ 9638809Simp if (ioctl(fd, APMIO_STANDBY, NULL) == -1) 9738809Simp err(1, NULL); 9838809Simp} 9938809Simp 10038809Simpvoid 10121363Snateapm_getinfo(int fd, apm_info_t aip) 1023259Sdg{ 10329030Scharnier if (ioctl(fd, APMIO_GETINFO, aip) == -1) 10429030Scharnier err(1, NULL); 1053259Sdg} 1063259Sdg 10721363Snatevoid 10838809Simpprint_all_info(int fd, apm_info_t aip) 1093259Sdg{ 11038809Simp struct apm_bios_arg args; 11138809Simp int apmerr; 11238809Simp 1133259Sdg printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor); 11421363Snate printf("APM Managment: %s\n", (aip->ai_status ? "Enabled" : "Disabled")); 1153259Sdg printf("AC Line status: "); 11621363Snate if (aip->ai_acline == 255) 1173259Sdg printf("unknown"); 11821363Snate else if (aip->ai_acline > 1) 1193259Sdg printf("invalid value (0x%x)", aip->ai_acline); 1203259Sdg else { 12121364Snate char messages[][10] = {"off-line", "on-line"}; 1223259Sdg printf("%s", messages[aip->ai_acline]); 1233259Sdg } 1243259Sdg printf("\n"); 1253259Sdg printf("Battery status: "); 12621363Snate if (aip->ai_batt_stat == 255) 1273259Sdg printf("unknown"); 12821363Snate else if (aip->ai_batt_stat > 3) 12921363Snate printf("invalid value (0x%x)", aip->ai_batt_stat); 1303259Sdg else { 13121363Snate char messages[][10] = {"high", "low", "critical", "charging"}; 1323259Sdg printf("%s", messages[aip->ai_batt_stat]); 1333259Sdg } 1343259Sdg printf("\n"); 1353259Sdg printf("Remaining battery life: "); 13621363Snate if (aip->ai_batt_life == 255) 1373259Sdg printf("unknown"); 13821363Snate else if (aip->ai_batt_life <= 100) 13930996Simp printf("%d%%", aip->ai_batt_life); 14021363Snate else 1413259Sdg printf("invalid value (0x%x)", aip->ai_batt_life); 1423259Sdg printf("\n"); 14331127Sjdp printf("Remaining battery time: "); 14431127Sjdp if (aip->ai_batt_time == -1) 14531127Sjdp printf("unknown"); 14631127Sjdp else { 14731127Sjdp int t, h, m, s; 14831127Sjdp 14931127Sjdp t = aip->ai_batt_time; 15031127Sjdp s = t % 60; 15131127Sjdp t /= 60; 15231127Sjdp m = t % 60; 15331127Sjdp t /= 60; 15431127Sjdp h = t; 15531127Sjdp printf("%2d:%02d:%02d", h, m, s); 15631127Sjdp } 15731127Sjdp printf("\n"); 15838809Simp if (aip->ai_infoversion >= 1) { 15938809Simp printf("Number of batteries: "); 16038809Simp if (aip->ai_batteries == (u_int) -1) 16138809Simp printf("unknown\n"); 16238809Simp else 16338809Simp printf("%d\n", aip->ai_batteries); 16438809Simp } 16538809Simp 16638809Simp /* 16738809Simp * try to get the suspend timer 16838809Simp */ 16938809Simp bzero(&args, sizeof(args)); 17038809Simp args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 17138809Simp args.ebx = PMDV_APMBIOS; 17238809Simp args.ecx = 0x0001; 17338809Simp if (ioctl(fd, APMIO_BIOS, &args)) { 17438809Simp err(1,"Get resume timer"); 17538809Simp } else { 17638809Simp apmerr = APMERR(args.eax); 17738809Simp if (apmerr == 0x0d || apmerr == 0x86) 17838809Simp printf("Resume timer: disabled\n"); 17938809Simp else if (apmerr) 18038809Simp fprintf(stderr, 18138809Simp "Failed to get the resume timer: APM error0x%x\n", 18238809Simp apmerr); 18338809Simp else { 18438809Simp /* 18538809Simp * OK. We have the time (all bcd). 18638809Simp * CH - seconds 18738809Simp * DH - hours 18838809Simp * DL - minutes 18938809Simp * xh(SI) - month (1-12) 19038809Simp * xl(SI) - day of month (1-31) 19138809Simp * DI - year 19238809Simp */ 19338809Simp struct tm tm; 19438809Simp char buf[1024]; 19538809Simp time_t t; 19638809Simp 19738809Simp tm.tm_sec = bcd2int(xh(args.ecx)); 19838809Simp tm.tm_min = bcd2int(xl(args.edx)); 19938809Simp tm.tm_hour = bcd2int(xh(args.edx)); 20038809Simp tm.tm_mday = bcd2int(xl(args.esi)); 20138809Simp tm.tm_mon = bcd2int(xh(args.esi)) - 1; 20238809Simp tm.tm_year = bcd2int(args.edi) - 1900; 20338809Simp if (cmos_wall) 20438809Simp t = mktime(&tm); 20538809Simp else 20638809Simp t = timegm(&tm); 20738809Simp tm = *localtime(&t); 20838809Simp strftime(buf, sizeof(buf), "%c", &tm); 20938809Simp printf("Resume timer: %s\n", buf); 21038809Simp } 21138809Simp } 21238809Simp 21338809Simp /* 21438809Simp * Get the ring indicator resume state 21538809Simp */ 21638809Simp bzero(&args, sizeof(args)); 21738809Simp args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING; 21838809Simp args.ebx = PMDV_APMBIOS; 21938809Simp args.ecx = 0x0002; 22038809Simp if (ioctl(fd, APMIO_BIOS, &args) == 0) { 22138809Simp printf("Resume on ring indicator: %sabled\n", 22238809Simp args.ecx ? "en" : "dis"); 22338809Simp } 22438809Simp 22538809Simp if (aip->ai_infoversion >= 1) { 22638809Simp printf("APM Capacities:\n", aip->ai_capabilities); 22738809Simp if (aip->ai_capabilities == 0xff00) 22838809Simp printf("\tunknown\n"); 22938809Simp if (aip->ai_capabilities & 0x01) 23038809Simp printf("\tglobal standby state\n"); 23138809Simp if (aip->ai_capabilities & 0x02) 23238809Simp printf("\tglobal suspend state\n"); 23338809Simp if (aip->ai_capabilities & 0x04) 23438809Simp printf("\tresume timer from standby\n"); 23538809Simp if (aip->ai_capabilities & 0x08) 23638809Simp printf("\tresume timer from suspend\n"); 23738809Simp if (aip->ai_capabilities & 0x10) 23838809Simp printf("\tRI resume from standby\n"); 23938809Simp if (aip->ai_capabilities & 0x20) 24038809Simp printf("\tRI resume from suspend\n"); 24138809Simp if (aip->ai_capabilities & 0x40) 24238809Simp printf("\tPCMCIA RI resume from standby\n"); 24338809Simp if (aip->ai_capabilities & 0x80) 24438809Simp printf("\tPCMCIA RI resume from suspend\n"); 24538809Simp } 24638809Simp 2473259Sdg} 2483259Sdg 24921363Snate/* 25021363Snate * currently, it can turn off the display, but the display never comes 25121363Snate * back until the machine suspend/resumes :-). 25221363Snate */ 25321363Snatevoid 25421363Snateapm_display(int fd, int newstate) 2553259Sdg{ 25629030Scharnier if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1) 25729030Scharnier err(1, NULL); 25821363Snate} 2598857Srgrimes 26021363Snate 26138809Simpvoid 26238809Simpapm_set_timer(int fd, int delta) 26338809Simp{ 26438809Simp time_t tmr; 26538809Simp struct tm *tm; 26638809Simp struct apm_bios_arg args; 26738809Simp 26838809Simp tmr = time(NULL) + delta; 26938809Simp if (cmos_wall) 27038809Simp tm = localtime(&tmr); 27138809Simp else 27238809Simp tm = gmtime(&tmr); 27338809Simp bzero(&args, sizeof(args)); 27438809Simp args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 27538809Simp args.ebx = PMDV_APMBIOS; 27638809Simp if (delta > 0) { 27738809Simp args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02; 27838809Simp args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min); 27938809Simp args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday); 28038809Simp args.edi = int2bcd(tm->tm_year + 1900); 28138809Simp } else { 28238809Simp args.ecx = 0x0000; 28338809Simp } 28438809Simp if (ioctl(fd, APMIO_BIOS, &args)) { 28538809Simp err(1,"Set resume timer"); 28638809Simp } 28738809Simp} 28838809Simp 28921363Snateint 29021363Snatemain(int argc, char *argv[]) 29121363Snate{ 29221363Snate int c, fd; 29321363Snate int sleep = 0, all_info = 1, apm_status = 0, batt_status = 0; 29438809Simp int display = 0, batt_life = 0, ac_status = 0, standby = 0; 29538809Simp int batt_time = 0, delta = 0; 29629030Scharnier char *cmdname; 29748938Sgreen size_t cmos_wall_len = sizeof(cmos_wall); 29821363Snate 29948938Sgreen if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len, 30048938Sgreen NULL, 0) == -1) 30148938Sgreen err(1, "sysctlbyname(machdep.wall_cmos_clock)"); 30221363Snate if ((cmdname = strrchr(argv[0], '/')) != NULL) 3033259Sdg cmdname++; 30421363Snate else 3053259Sdg cmdname = argv[0]; 3063259Sdg 3073259Sdg if (strcmp(cmdname, "zzz") == 0) { 3083259Sdg sleep = 1; 3093259Sdg all_info = 0; 3103259Sdg goto finish_option; 3113259Sdg } 31238809Simp while ((c = getopt(argc, argv, "ablRr:stzd:Z")) != -1) { 31321363Snate switch (c) { 31421363Snate case 'a': 31521363Snate ac_status = 1; 31621363Snate all_info = 0; 31721363Snate break; 31821363Snate case 'b': 31921363Snate batt_status = 1; 32021363Snate all_info = 0; 32121363Snate break; 32221363Snate case 'd': 32321363Snate display = *optarg - '0'; 32421363Snate if (display < 0 || display > 1) { 32529030Scharnier warnx("argument of option '-%c' is invalid", c); 32621363Snate usage(); 3273259Sdg } 32821363Snate display++; 32921363Snate all_info = 0; 33021363Snate break; 33121363Snate case 'l': 33221363Snate batt_life = 1; 33321363Snate all_info = 0; 33421363Snate break; 33538809Simp case 'R': 33638809Simp delta = -1; 33738809Simp break; 33838809Simp case 'r': 33938809Simp delta = atoi(optarg); 34038809Simp break; 34121363Snate case 's': 34221363Snate apm_status = 1; 34321363Snate all_info = 0; 34421363Snate break; 34531127Sjdp case 't': 34631127Sjdp batt_time = 1; 34731127Sjdp all_info = 0; 34831127Sjdp break; 34921363Snate case 'z': 35021363Snate sleep = 1; 35121363Snate all_info = 0; 35221363Snate break; 35338809Simp case 'Z': 35438809Simp standby = 1; 35538809Simp all_info = 0; 35638809Simp break; 35721363Snate case '?': 35821363Snate default: 35921363Snate usage(); 3603259Sdg } 36121363Snate argc -= optind; 36221363Snate argv += optind; 3633259Sdg } 3643259Sdgfinish_option: 3653259Sdg fd = open(APMDEV, O_RDWR); 3663259Sdg if (fd == -1) { 36730996Simp warn("can't open %s", APMDEV); 3683259Sdg return 1; 3693259Sdg } 37038809Simp if (delta) 37138809Simp apm_set_timer(fd, delta); 37221363Snate if (sleep) 3733259Sdg apm_suspend(fd); 37438809Simp else if (standby) 37538809Simp apm_standby(fd); 37638809Simp else if (delta == 0) { 37721363Snate struct apm_info info; 3783259Sdg 3793259Sdg apm_getinfo(fd, &info); 38021363Snate if (all_info) 38138809Simp print_all_info(fd, &info); 38231127Sjdp if (ac_status) 38331127Sjdp printf("%d\n", info.ai_acline); 38421363Snate if (batt_status) 3853259Sdg printf("%d\n", info.ai_batt_stat); 38621363Snate if (batt_life) 3873259Sdg printf("%d\n", info.ai_batt_life); 38821363Snate if (apm_status) 38914609Snate printf("%d\n", info.ai_status); 39031127Sjdp if (batt_time) 39131127Sjdp printf("%d\n", info.ai_batt_time); 39221363Snate if (display) 39321363Snate apm_display(fd, display - 1); 3943259Sdg } 3953259Sdg close(fd); 3963259Sdg return 0; 3973259Sdg} 398