apm.c revision 48939
1/* 2 * apm / zzz APM BIOS utility for FreeBSD 3 * 4 * Copyright (C) 1994-1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 5 * 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 11 * use. 12 * 13 * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) 14 */ 15 16#ifndef lint 17static const char rcsid[] = 18 "$Id: apm.c,v 1.15 1999/07/20 15:31:23 green Exp $"; 19#endif /* not lint */ 20 21#include <sys/file.h> 22#include <sys/ioctl.h> 23#include <sys/types.h> 24#include <sys/sysctl.h> 25 26#include <machine/apm_bios.h> 27 28#include <err.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <sys/file.h> 33#include <sys/ioctl.h> 34#include <time.h> 35#include <unistd.h> 36 37#define APMDEV "/dev/apm" 38 39#define xh(a) (((a) & 0xff00) >> 8) 40#define xl(a) ((a) & 0xff) 41#define APMERR(a) xh(a) 42 43int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */ 44 45void 46usage() 47{ 48 fprintf(stderr, "%s\n%s\n", 49 "usage: apm [-ablstzZ] [-d 1|0] [-r delta]", 50 " zzz"); 51 exit(1); 52} 53 54int 55int2bcd(int i) 56{ 57 int retval = 0; 58 int base = 0; 59 60 if (i >= 10000) 61 return -1; 62 63 while (i) { 64 retval |= (i % 10) << base; 65 i /= 10; 66 base += 4; 67 } 68 return retval; 69} 70 71int 72bcd2int(int bcd) 73{ 74 int retval = 0; 75 int place = 1; 76 77 if (bcd > 0x9999) 78 return -1; 79 80 while (bcd) { 81 retval += (bcd & 0xf) * place; 82 bcd >>= 4; 83 place *= 10; 84 } 85 return retval; 86} 87 88void 89apm_suspend(int fd) 90{ 91 if (ioctl(fd, APMIO_SUSPEND, NULL) == -1) 92 err(1, NULL); 93} 94 95void 96apm_standby(int fd) 97{ 98 if (ioctl(fd, APMIO_STANDBY, NULL) == -1) 99 err(1, NULL); 100} 101 102void 103apm_getinfo(int fd, apm_info_t aip) 104{ 105 if (ioctl(fd, APMIO_GETINFO, aip) == -1) 106 err(1, NULL); 107} 108 109void 110print_all_info(int fd, apm_info_t aip) 111{ 112 struct apm_bios_arg args; 113 int apmerr; 114 115 printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor); 116 printf("APM Managment: %s\n", (aip->ai_status ? "Enabled" : "Disabled")); 117 printf("AC Line status: "); 118 if (aip->ai_acline == 255) 119 printf("unknown"); 120 else if (aip->ai_acline > 1) 121 printf("invalid value (0x%x)", aip->ai_acline); 122 else { 123 char messages[][10] = {"off-line", "on-line"}; 124 printf("%s", messages[aip->ai_acline]); 125 } 126 printf("\n"); 127 printf("Battery status: "); 128 if (aip->ai_batt_stat == 255) 129 printf("unknown"); 130 else if (aip->ai_batt_stat > 3) 131 printf("invalid value (0x%x)", aip->ai_batt_stat); 132 else { 133 char messages[][10] = {"high", "low", "critical", "charging"}; 134 printf("%s", messages[aip->ai_batt_stat]); 135 } 136 printf("\n"); 137 printf("Remaining battery life: "); 138 if (aip->ai_batt_life == 255) 139 printf("unknown"); 140 else if (aip->ai_batt_life <= 100) 141 printf("%d%%", aip->ai_batt_life); 142 else 143 printf("invalid value (0x%x)", aip->ai_batt_life); 144 printf("\n"); 145 printf("Remaining battery time: "); 146 if (aip->ai_batt_time == -1) 147 printf("unknown"); 148 else { 149 int t, h, m, s; 150 151 t = aip->ai_batt_time; 152 s = t % 60; 153 t /= 60; 154 m = t % 60; 155 t /= 60; 156 h = t; 157 printf("%2d:%02d:%02d", h, m, s); 158 } 159 printf("\n"); 160 if (aip->ai_infoversion >= 1) { 161 printf("Number of batteries: "); 162 if (aip->ai_batteries == (u_int) -1) 163 printf("unknown\n"); 164 else 165 printf("%d\n", aip->ai_batteries); 166 } 167 168 /* 169 * try to get the suspend timer 170 */ 171 bzero(&args, sizeof(args)); 172 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 173 args.ebx = PMDV_APMBIOS; 174 args.ecx = 0x0001; 175 if (ioctl(fd, APMIO_BIOS, &args)) { 176 err(1,"Get resume timer"); 177 } else { 178 apmerr = APMERR(args.eax); 179 if (apmerr == 0x0d || apmerr == 0x86) 180 printf("Resume timer: disabled\n"); 181 else if (apmerr) 182 fprintf(stderr, 183 "Failed to get the resume timer: APM error0x%x\n", 184 apmerr); 185 else { 186 /* 187 * OK. We have the time (all bcd). 188 * CH - seconds 189 * DH - hours 190 * DL - minutes 191 * xh(SI) - month (1-12) 192 * xl(SI) - day of month (1-31) 193 * DI - year 194 */ 195 struct tm tm; 196 char buf[1024]; 197 time_t t; 198 199 tm.tm_sec = bcd2int(xh(args.ecx)); 200 tm.tm_min = bcd2int(xl(args.edx)); 201 tm.tm_hour = bcd2int(xh(args.edx)); 202 tm.tm_mday = bcd2int(xl(args.esi)); 203 tm.tm_mon = bcd2int(xh(args.esi)) - 1; 204 tm.tm_year = bcd2int(args.edi) - 1900; 205 if (cmos_wall) 206 t = mktime(&tm); 207 else 208 t = timegm(&tm); 209 tm = *localtime(&t); 210 strftime(buf, sizeof(buf), "%c", &tm); 211 printf("Resume timer: %s\n", buf); 212 } 213 } 214 215 /* 216 * Get the ring indicator resume state 217 */ 218 bzero(&args, sizeof(args)); 219 args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING; 220 args.ebx = PMDV_APMBIOS; 221 args.ecx = 0x0002; 222 if (ioctl(fd, APMIO_BIOS, &args) == 0) { 223 printf("Resume on ring indicator: %sabled\n", 224 args.ecx ? "en" : "dis"); 225 } 226 227 if (aip->ai_infoversion >= 1) { 228 printf("APM Capacities:\n", aip->ai_capabilities); 229 if (aip->ai_capabilities == 0xff00) 230 printf("\tunknown\n"); 231 if (aip->ai_capabilities & 0x01) 232 printf("\tglobal standby state\n"); 233 if (aip->ai_capabilities & 0x02) 234 printf("\tglobal suspend state\n"); 235 if (aip->ai_capabilities & 0x04) 236 printf("\tresume timer from standby\n"); 237 if (aip->ai_capabilities & 0x08) 238 printf("\tresume timer from suspend\n"); 239 if (aip->ai_capabilities & 0x10) 240 printf("\tRI resume from standby\n"); 241 if (aip->ai_capabilities & 0x20) 242 printf("\tRI resume from suspend\n"); 243 if (aip->ai_capabilities & 0x40) 244 printf("\tPCMCIA RI resume from standby\n"); 245 if (aip->ai_capabilities & 0x80) 246 printf("\tPCMCIA RI resume from suspend\n"); 247 } 248 249} 250 251/* 252 * currently, it can turn off the display, but the display never comes 253 * back until the machine suspend/resumes :-). 254 */ 255void 256apm_display(int fd, int newstate) 257{ 258 if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1) 259 err(1, NULL); 260} 261 262 263void 264apm_set_timer(int fd, int delta) 265{ 266 time_t tmr; 267 struct tm *tm; 268 struct apm_bios_arg args; 269 270 tmr = time(NULL) + delta; 271 if (cmos_wall) 272 tm = localtime(&tmr); 273 else 274 tm = gmtime(&tmr); 275 bzero(&args, sizeof(args)); 276 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER; 277 args.ebx = PMDV_APMBIOS; 278 if (delta > 0) { 279 args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02; 280 args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min); 281 args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday); 282 args.edi = int2bcd(tm->tm_year + 1900); 283 } else { 284 args.ecx = 0x0000; 285 } 286 if (ioctl(fd, APMIO_BIOS, &args)) { 287 err(1,"Set resume timer"); 288 } 289} 290 291int 292main(int argc, char *argv[]) 293{ 294 int c, fd; 295 int sleep = 0, all_info = 1, apm_status = 0, batt_status = 0; 296 int display = 0, batt_life = 0, ac_status = 0, standby = 0; 297 int batt_time = 0, delta = 0; 298 char *cmdname; 299 size_t cmos_wall_len = sizeof(cmos_wall); 300 301 if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len, 302 NULL, 0) == -1) 303 err(1, "sysctlbyname(machdep.wall_cmos_clock)"); 304 if ((cmdname = strrchr(argv[0], '/')) != NULL) 305 cmdname++; 306 else 307 cmdname = argv[0]; 308 309 if (strcmp(cmdname, "zzz") == 0) { 310 sleep = 1; 311 all_info = 0; 312 goto finish_option; 313 } 314 while ((c = getopt(argc, argv, "ablRr:stzd:Z")) != -1) { 315 switch (c) { 316 case 'a': 317 ac_status = 1; 318 all_info = 0; 319 break; 320 case 'b': 321 batt_status = 1; 322 all_info = 0; 323 break; 324 case 'd': 325 display = *optarg - '0'; 326 if (display < 0 || display > 1) { 327 warnx("argument of option '-%c' is invalid", c); 328 usage(); 329 } 330 display++; 331 all_info = 0; 332 break; 333 case 'l': 334 batt_life = 1; 335 all_info = 0; 336 break; 337 case 'R': 338 delta = -1; 339 break; 340 case 'r': 341 delta = atoi(optarg); 342 break; 343 case 's': 344 apm_status = 1; 345 all_info = 0; 346 break; 347 case 't': 348 batt_time = 1; 349 all_info = 0; 350 break; 351 case 'z': 352 sleep = 1; 353 all_info = 0; 354 break; 355 case 'Z': 356 standby = 1; 357 all_info = 0; 358 break; 359 case '?': 360 default: 361 usage(); 362 } 363 argc -= optind; 364 argv += optind; 365 } 366finish_option: 367 fd = open(APMDEV, O_RDWR); 368 if (fd == -1) { 369 warn("can't open %s", APMDEV); 370 return 1; 371 } 372 if (delta) 373 apm_set_timer(fd, delta); 374 if (sleep) 375 apm_suspend(fd); 376 else if (standby) 377 apm_standby(fd); 378 else if (delta == 0) { 379 struct apm_info info; 380 381 apm_getinfo(fd, &info); 382 if (all_info) 383 print_all_info(fd, &info); 384 if (ac_status) 385 printf("%d\n", info.ai_acline); 386 if (batt_status) 387 printf("%d\n", info.ai_batt_stat); 388 if (batt_life) 389 printf("%d\n", info.ai_batt_life); 390 if (apm_status) 391 printf("%d\n", info.ai_status); 392 if (batt_time) 393 printf("%d\n", info.ai_batt_time); 394 if (display) 395 apm_display(fd, display - 1); 396 } 397 close(fd); 398 return 0; 399} 400