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