]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/apm/apm.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / apm / apm.c
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 #include <sys/cdefs.h>
17 __FBSDID("$FreeBSD$");
18
19 #include <sys/file.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
23
24 #include <machine/apm_bios.h>
25
26 #include <err.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #define APMDEV  "/dev/apm"
34
35 #define APM_UNKNOWN     255
36
37 #define xh(a)   (((a) & 0xff00) >> 8)
38 #define xl(a)   ((a) & 0xff)
39 #define APMERR(a) xh(a)
40
41 int cmos_wall = 0;      /* True when wall time is in cmos clock, else UTC */
42
43 static void
44 usage(void)
45 {
46         fprintf(stderr, "%s\n%s\n",
47                 "usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
48                 "[ -h enable ] [-r delta]",
49                 "       zzz");
50         exit(1);
51 }
52
53 /*
54  * Return 1 for boolean true, and 0 for false, according to the
55  * interpretation of the string argument given.
56  */
57 static int
58 is_true(const char *boolean)
59 {
60         char *endp;
61         long val;
62
63         val = strtoul(boolean, &endp, 0);
64         if (*endp == '\0')
65                 return (val != 0 ? 1 : 0);
66         if (strcasecmp(boolean, "true") == 0 ||
67             strcasecmp(boolean, "yes") == 0 ||
68             strcasecmp(boolean, "enable") == 0)
69                 return (1);
70         if (strcasecmp(boolean, "false") == 0 ||
71             strcasecmp(boolean, "no") == 0 ||
72             strcasecmp(boolean, "disable") == 0)
73                 return (0);
74         /* Well, I have no idea what the user wants, so... */
75         warnx("invalid boolean argument \"%s\"", boolean);
76         usage();
77         /* NOTREACHED */
78
79         return (0);
80 }
81
82 static int
83 int2bcd(int i)
84 {
85         int retval = 0;
86         int base = 0;
87
88         if (i >= 10000)
89                 return -1;
90     
91         while (i) {
92                 retval |= (i % 10) << base;
93                 i /= 10;
94                 base += 4;
95         }
96         return retval;
97 }
98
99 static int
100 bcd2int(int bcd)
101 {
102         int retval = 0;
103         int place = 1;
104
105         if (bcd > 0x9999)
106                 return -1;
107
108         while (bcd) {
109                 retval += (bcd & 0xf) * place;
110                 bcd >>= 4;
111                 place *= 10;
112         }
113         return retval;
114 }
115
116 static void 
117 apm_suspend(int fd)
118 {
119         if (ioctl(fd, APMIO_SUSPEND, NULL) == -1)
120                 err(1, "ioctl(APMIO_SUSPEND)");
121 }
122
123 static void 
124 apm_standby(int fd)
125 {
126         if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
127                 err(1, "ioctl(APMIO_STANDBY)");
128 }
129
130 static void 
131 apm_getinfo(int fd, apm_info_t aip)
132 {
133         if (ioctl(fd, APMIO_GETINFO, aip) == -1)
134                 err(1, "ioctl(APMIO_GETINFO)");
135 }
136
137 static void 
138 apm_enable(int fd, int enable) 
139 {
140         if (enable) {
141                 if (ioctl(fd, APMIO_ENABLE) == -1)
142                         err(1, "ioctl(APMIO_ENABLE)");
143         } else {
144                 if (ioctl(fd, APMIO_DISABLE) == -1)
145                         err(1, "ioctl(APMIO_DISABLE)");
146         }
147 }
148
149 static void
150 print_batt_time(int batt_time)
151 {
152         printf("Remaining battery time: ");
153         if (batt_time == -1)
154                 printf("unknown\n");
155         else {
156                 int h, m, s;
157
158                 h = batt_time;
159                 s = h % 60;
160                 h /= 60;
161                 m = h % 60;
162                 h /= 60;
163                 printf("%2d:%02d:%02d\n", h, m, s);
164         }
165 }
166
167 static void
168 print_batt_life(u_int batt_life)
169 {
170         printf("Remaining battery life: ");
171         if (batt_life == APM_UNKNOWN)
172                 printf("unknown\n");
173         else if (batt_life <= 100)
174                 printf("%d%%\n", batt_life);
175         else
176                 printf("invalid value (0x%x)\n", batt_life);
177 }
178
179 static void
180 print_batt_stat(u_int batt_stat)
181 {
182         const char *batt_msg[] = { "high", "low", "critical", "charging" };
183
184         printf("Battery Status: ");
185         if (batt_stat == APM_UNKNOWN)
186                 printf("unknown\n");
187         else if (batt_stat > 3)
188                 printf("invalid value (0x%x)\n", batt_stat);
189         else
190                 printf("%s\n", batt_msg[batt_stat]);
191 }
192
193 static void 
194 print_all_info(int fd, apm_info_t aip, int bioscall_available)
195 {
196         struct apm_bios_arg args;
197         int apmerr;
198         const char *line_msg[] = { "off-line", "on-line" , "backup power"};
199
200         printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
201         printf("APM Management: %s\n", aip->ai_status ? "Enabled" : "Disabled");
202         printf("AC Line status: ");
203         if (aip->ai_acline == APM_UNKNOWN)
204                 printf("unknown\n");
205         else if (aip->ai_acline > 2)
206                 printf("invalid value (0x%x)\n", aip->ai_acline);
207         else
208                 printf("%s\n", line_msg[aip->ai_acline]);
209
210         print_batt_stat(aip->ai_batt_stat);
211         print_batt_life(aip->ai_batt_life);
212         print_batt_time(aip->ai_batt_time);
213
214         if (aip->ai_infoversion >= 1) {
215                 printf("Number of batteries: ");
216                 if (aip->ai_batteries == ~0U)
217                         printf("unknown\n");
218                 else {
219                         u_int i;
220                         struct apm_pwstatus aps;
221
222                         printf("%d\n", aip->ai_batteries);
223                         for (i = 0; i < aip->ai_batteries; ++i) {
224                                 bzero(&aps, sizeof(aps));
225                                 aps.ap_device = PMDV_BATT0 + i;
226                                 if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1)
227                                         continue;
228                                 printf("Battery %d:\n", i);
229                                 if (aps.ap_batt_flag & APM_BATT_NOT_PRESENT) {
230                                         printf("not present\n");
231                                         continue;
232                                 }
233                                 printf("\t");
234                                 print_batt_stat(aps.ap_batt_stat);
235                                 printf("\t");
236                                 print_batt_life(aps.ap_batt_life);
237                                 printf("\t");
238                                 print_batt_time(aps.ap_batt_time);
239                         }
240                 }
241         }
242
243         if (bioscall_available) {
244                 /*
245                  * try to get the suspend timer
246                  */
247                 bzero(&args, sizeof(args));
248                 args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
249                 args.ebx = PMDV_APMBIOS;
250                 args.ecx = 0x0001;
251                 if (ioctl(fd, APMIO_BIOS, &args)) {
252                         printf("Resume timer: unknown\n");
253                 } else {
254                         apmerr = APMERR(args.eax);
255                         if (apmerr == 0x0d || apmerr == 0x86)
256                                 printf("Resume timer: disabled\n");
257                         else if (apmerr)
258                                 warnx(
259                 "failed to get the resume timer: APM error0x%x", apmerr);
260                         else {
261                                 /*
262                                  * OK.  We have the time (all bcd).
263                                  * CH - seconds
264                                  * DH - hours
265                                  * DL - minutes
266                                  * xh(SI) - month (1-12)
267                                  * xl(SI) - day of month (1-31)
268                                  * DI - year
269                                  */
270                                 struct tm tm;
271                                 char buf[1024];
272                                 time_t t;
273
274                                 tm.tm_sec = bcd2int(xh(args.ecx));
275                                 tm.tm_min = bcd2int(xl(args.edx));
276                                 tm.tm_hour = bcd2int(xh(args.edx));
277                                 tm.tm_mday = bcd2int(xl(args.esi));
278                                 tm.tm_mon = bcd2int(xh(args.esi)) - 1;
279                                 tm.tm_year = bcd2int(args.edi) - 1900;
280                                 if (cmos_wall)
281                                         t = mktime(&tm);
282                                 else
283                                         t = timegm(&tm);
284                                 if (t != -1) {
285                                         tm = *localtime(&t);
286                                         strftime(buf, sizeof(buf), "%c", &tm);
287                                         printf("Resume timer: %s\n", buf);
288                                 } else
289                                         printf("Resume timer: unknown\n");
290                         }
291                 }
292
293                 /*
294                  * Get the ring indicator resume state
295                  */
296                 bzero(&args, sizeof(args));
297                 args.eax  = (APM_BIOS) << 8 | APM_RESUMEONRING;
298                 args.ebx = PMDV_APMBIOS;
299                 args.ecx = 0x0002;
300                 if (ioctl(fd, APMIO_BIOS, &args) == 0) {
301                         printf("Resume on ring indicator: %sabled\n",
302                             args.ecx ? "en" : "dis");
303                 }
304         }
305
306         if (aip->ai_infoversion >= 1) {
307                 if (aip->ai_capabilities == 0xff00)
308                     return;
309                 printf("APM Capabilities:\n");
310                 if (aip->ai_capabilities & 0x01)
311                         printf("\tglobal standby state\n");
312                 if (aip->ai_capabilities & 0x02)
313                         printf("\tglobal suspend state\n");
314                 if (aip->ai_capabilities & 0x04)
315                         printf("\tresume timer from standby\n");
316                 if (aip->ai_capabilities & 0x08)
317                         printf("\tresume timer from suspend\n");
318                 if (aip->ai_capabilities & 0x10)
319                         printf("\tRI resume from standby\n");
320                 if (aip->ai_capabilities & 0x20)
321                         printf("\tRI resume from suspend\n");
322                 if (aip->ai_capabilities & 0x40)
323                         printf("\tPCMCIA RI resume from standby\n");
324                 if (aip->ai_capabilities & 0x80)
325                         printf("\tPCMCIA RI resume from suspend\n");
326         }
327
328 }
329
330 /*
331  * currently, it can turn off the display, but the display never comes
332  * back until the machine suspend/resumes :-).
333  */
334 static void 
335 apm_display(int fd, int newstate)
336 {
337         if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
338                 err(1, "ioctl(APMIO_DISPLAY)");
339 }
340
341 static void
342 apm_haltcpu(int fd, int enable)
343 {
344         if (enable) {
345                 if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
346                         err(1, "ioctl(APMIO_HALTCPU)");
347         } else {
348                 if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
349                         err(1, "ioctl(APMIO_NOTHALTCPU)");
350         }
351 }
352
353 static void
354 apm_set_timer(int fd, int delta)
355 {
356         time_t tmr;
357         struct tm *tm;
358         struct apm_bios_arg args;
359
360         tmr = time(NULL) + delta;
361         if (cmos_wall)
362                 tm = localtime(&tmr);
363         else
364                 tm = gmtime(&tmr);
365         bzero(&args, sizeof(args));
366         args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
367         args.ebx = PMDV_APMBIOS;
368         if (delta > 0) {
369                 args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02;
370                 args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min);
371                 args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday);
372                 args.edi = int2bcd(tm->tm_year + 1900);
373         } else {
374                 args.ecx = 0x0000;
375         }
376         if (ioctl(fd, APMIO_BIOS, &args)) {
377                 err(1,"set resume timer");
378         }
379 }
380
381 int 
382 main(int argc, char *argv[])
383 {
384         int     c, fd;
385         int     dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
386         int     display = -1, batt_life = 0, ac_status = 0, standby = 0;
387         int     batt_time = 0, delta = 0, enable = -1, haltcpu = -1;
388         char    *cmdname;
389         int     bioscall_available = 0;
390         size_t  cmos_wall_len = sizeof(cmos_wall);
391
392         if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
393             NULL, 0) == -1)
394                 err(1, "sysctlbyname(machdep.wall_cmos_clock)");
395         if ((cmdname = strrchr(argv[0], '/')) != NULL)
396                 cmdname++;
397         else
398                 cmdname = argv[0];
399
400         if (strcmp(cmdname, "zzz") == 0) {
401                 dosleep = 1;
402                 all_info = 0;
403                 goto finish_option;
404         }
405         while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
406                 switch (c) {
407                 case 'a':
408                         ac_status = 1;
409                         all_info = 0;
410                         break;
411                 case 'b':
412                         batt_status = 1;
413                         all_info = 0;
414                         break;
415                 case 'd':
416                         display = is_true(optarg);
417                         all_info = 0;
418                         break;
419                 case 'l':
420                         batt_life = 1;
421                         all_info = 0;
422                         break;
423                 case 'R':
424                         delta = -1;
425                         break;
426                 case 'r':
427                         delta = atoi(optarg);
428                         break;
429                 case 's':
430                         apm_status = 1;
431                         all_info = 0;
432                         break;
433                 case 'e':
434                         enable = is_true(optarg);
435                         all_info = 0;
436                         break;
437                 case 'h':
438                         haltcpu = is_true(optarg);
439                         all_info = 0;
440                         break;
441                 case 't':
442                         batt_time = 1;
443                         all_info = 0;
444                         break;
445                 case 'z':
446                         dosleep = 1;
447                         all_info = 0;
448                         break;
449                 case 'Z':
450                         standby = 1;
451                         all_info = 0;
452                         break;
453                 case '?':
454                 default:
455                         usage();
456                 }
457                 argc -= optind;
458                 argv += optind;
459         }
460 finish_option:
461         if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
462             || standby) {
463                 fd = open(APMDEV, O_RDWR);
464                 bioscall_available = 1;
465         } else if ((fd = open(APMDEV, O_RDWR)) >= 0)
466                 bioscall_available = 1;
467         else
468                 fd = open(APMDEV, O_RDONLY);
469         if (fd == -1)
470                 err(1, "can't open %s", APMDEV);
471         if (enable != -1)
472                 apm_enable(fd, enable);
473         if (haltcpu != -1)
474                 apm_haltcpu(fd, haltcpu);
475         if (delta)
476                 apm_set_timer(fd, delta);
477         if (dosleep)
478                 apm_suspend(fd);
479         else if (standby)
480                 apm_standby(fd);
481         else if (delta == 0) {
482                 struct apm_info info;
483
484                 apm_getinfo(fd, &info);
485                 if (all_info)
486                         print_all_info(fd, &info, bioscall_available);
487                 if (ac_status)
488                         printf("%d\n", info.ai_acline);
489                 if (batt_status)
490                         printf("%d\n", info.ai_batt_stat);
491                 if (batt_life)
492                         printf("%d\n", info.ai_batt_life);
493                 if (apm_status)
494                         printf("%d\n", info.ai_status);
495                 if (batt_time)
496                         printf("%d\n", info.ai_batt_time);
497                 if (display != -1)
498                         apm_display(fd, display);
499         }
500         close(fd);
501         exit(0);
502 }