1967ae586SMatthew Dillon /*-
2967ae586SMatthew Dillon * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
3967ae586SMatthew Dillon * All rights reserved.
4967ae586SMatthew Dillon *
5967ae586SMatthew Dillon * Redistribution and use in source and binary forms, with or without
6967ae586SMatthew Dillon * modification, are permitted provided that the following conditions
7967ae586SMatthew Dillon * are met:
8967ae586SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
9967ae586SMatthew Dillon * notice, this list of conditions and the following disclaimer.
10967ae586SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
11967ae586SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
12967ae586SMatthew Dillon * documentation and/or other materials provided with the distribution.
13967ae586SMatthew Dillon *
14967ae586SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15967ae586SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16967ae586SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17967ae586SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18967ae586SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19967ae586SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20967ae586SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21967ae586SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22967ae586SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23967ae586SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24967ae586SMatthew Dillon * SUCH DAMAGE.
25967ae586SMatthew Dillon *
26967ae586SMatthew Dillon * $Id: acpiconf.c,v 1.5 2000/08/08 14:12:19 iwasaki Exp $
2720cc1873SSascha Wildner * $FreeBSD: head/usr.sbin/acpi/acpiconf/acpiconf.c 211763 2010-08-24 18:07:59Z mav $
28967ae586SMatthew Dillon */
29967ae586SMatthew Dillon
30967ae586SMatthew Dillon #include <sys/param.h>
31967ae586SMatthew Dillon
32967ae586SMatthew Dillon #include <err.h>
33967ae586SMatthew Dillon #include <fcntl.h>
34967ae586SMatthew Dillon #include <stdio.h>
35967ae586SMatthew Dillon #include <sys/ioctl.h>
36967ae586SMatthew Dillon #include <sysexits.h>
37967ae586SMatthew Dillon #include <unistd.h>
38967ae586SMatthew Dillon
39967ae586SMatthew Dillon #include "acpiio.h"
40967ae586SMatthew Dillon #include "acpi.h"
41967ae586SMatthew Dillon
42967ae586SMatthew Dillon #define ACPIDEV "/dev/acpi"
43967ae586SMatthew Dillon
44967ae586SMatthew Dillon static int acpifd;
45967ae586SMatthew Dillon
467d58d14bSHasso Tepper static void
acpi_init(void)47a4c90f86SSascha Wildner acpi_init(void)
48967ae586SMatthew Dillon {
49967ae586SMatthew Dillon acpifd = open(ACPIDEV, O_RDWR);
507d58d14bSHasso Tepper if (acpifd == -1)
51967ae586SMatthew Dillon acpifd = open(ACPIDEV, O_RDONLY);
527d58d14bSHasso Tepper if (acpifd == -1)
53967ae586SMatthew Dillon err(EX_OSFILE, ACPIDEV);
54967ae586SMatthew Dillon }
55967ae586SMatthew Dillon
5677c1a34eSAlexander Polakov /* Prepare to sleep and then wait for the signal that sleeping can occur. */
5777c1a34eSAlexander Polakov static void
acpi_sleep(int sleep_type)58967ae586SMatthew Dillon acpi_sleep(int sleep_type)
59967ae586SMatthew Dillon {
60967ae586SMatthew Dillon int ret;
61967ae586SMatthew Dillon
6277c1a34eSAlexander Polakov /* Notify OS that we want to sleep. devd(8) gets this notify. */
6377c1a34eSAlexander Polakov ret = ioctl(acpifd, ACPIIO_REQSLPSTATE, &sleep_type);
64967ae586SMatthew Dillon if (ret != 0)
6577c1a34eSAlexander Polakov err(EX_IOERR, "request sleep type (%d) failed", sleep_type);
6677c1a34eSAlexander Polakov }
67967ae586SMatthew Dillon
6877c1a34eSAlexander Polakov /* Ack or abort a pending suspend request. */
6977c1a34eSAlexander Polakov static void
acpi_sleep_ack(int err_val)7077c1a34eSAlexander Polakov acpi_sleep_ack(int err_val)
7177c1a34eSAlexander Polakov {
7277c1a34eSAlexander Polakov int ret;
7377c1a34eSAlexander Polakov
7477c1a34eSAlexander Polakov ret = ioctl(acpifd, ACPIIO_ACKSLPSTATE, &err_val);
7577c1a34eSAlexander Polakov if (ret != 0)
7677c1a34eSAlexander Polakov err(EX_IOERR, "ack sleep type failed");
77967ae586SMatthew Dillon }
78967ae586SMatthew Dillon
797d58d14bSHasso Tepper /* should be a acpi define, but doesn't appear to be */
807d58d14bSHasso Tepper #define UNKNOWN_CAP 0xffffffff
817d58d14bSHasso Tepper #define UNKNOWN_VOLTAGE 0xffffffff
827d58d14bSHasso Tepper
83967ae586SMatthew Dillon static int
acpi_battinfo(int num)84967ae586SMatthew Dillon acpi_battinfo(int num)
85967ae586SMatthew Dillon {
86967ae586SMatthew Dillon union acpi_battery_ioctl_arg battio;
87967ae586SMatthew Dillon const char *pwr_units;
885a43d9b0SMagliano Andrea int hours, min, amp;
895a43d9b0SMagliano Andrea uint32_t volt;
90967ae586SMatthew Dillon
91967ae586SMatthew Dillon if (num < 0 || num > 64)
92967ae586SMatthew Dillon err(EX_USAGE, "invalid battery %d", num);
93967ae586SMatthew Dillon
947d58d14bSHasso Tepper /* Print battery design information. */
95967ae586SMatthew Dillon battio.unit = num;
967d58d14bSHasso Tepper if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) == -1)
97967ae586SMatthew Dillon err(EX_IOERR, "get battery info (%d) failed", num);
985a43d9b0SMagliano Andrea amp = battio.bif.units;
995a43d9b0SMagliano Andrea pwr_units = amp ? "mA" : "mW";
1007d58d14bSHasso Tepper if (battio.bif.dcap == UNKNOWN_CAP)
1017d58d14bSHasso Tepper printf("Design capacity:\tunknown\n");
1027d58d14bSHasso Tepper else
1037d58d14bSHasso Tepper printf("Design capacity:\t%d %sh\n", battio.bif.dcap,
1047d58d14bSHasso Tepper pwr_units);
1057d58d14bSHasso Tepper if (battio.bif.lfcap == UNKNOWN_CAP)
1067d58d14bSHasso Tepper printf("Last full capacity:\tunknown\n");
1077d58d14bSHasso Tepper else
1087d58d14bSHasso Tepper printf("Last full capacity:\t%d %sh\n", battio.bif.lfcap,
1097d58d14bSHasso Tepper pwr_units);
110967ae586SMatthew Dillon printf("Technology:\t\t%s\n", battio.bif.btech == 0 ?
111967ae586SMatthew Dillon "primary (non-rechargeable)" : "secondary (rechargeable)");
1127d58d14bSHasso Tepper if (battio.bif.dvol == UNKNOWN_CAP)
1137d58d14bSHasso Tepper printf("Design voltage:\t\tunknown\n");
1147d58d14bSHasso Tepper else
115967ae586SMatthew Dillon printf("Design voltage:\t\t%d mV\n", battio.bif.dvol);
1167d58d14bSHasso Tepper printf("Capacity (warn):\t%d %sh\n", battio.bif.wcap, pwr_units);
1177d58d14bSHasso Tepper printf("Capacity (low):\t\t%d %sh\n", battio.bif.lcap, pwr_units);
1187d58d14bSHasso Tepper printf("Low/warn granularity:\t%d %sh\n", battio.bif.gra1, pwr_units);
1197d58d14bSHasso Tepper printf("Warn/full granularity:\t%d %sh\n", battio.bif.gra2, pwr_units);
120967ae586SMatthew Dillon printf("Model number:\t\t%s\n", battio.bif.model);
121967ae586SMatthew Dillon printf("Serial number:\t\t%s\n", battio.bif.serial);
122967ae586SMatthew Dillon printf("Type:\t\t\t%s\n", battio.bif.type);
123967ae586SMatthew Dillon printf("OEM info:\t\t%s\n", battio.bif.oeminfo);
124967ae586SMatthew Dillon
1255a43d9b0SMagliano Andrea /* Fetch battery voltage information. */
1265a43d9b0SMagliano Andrea volt = UNKNOWN_VOLTAGE;
1275a43d9b0SMagliano Andrea battio.unit = num;
1285a43d9b0SMagliano Andrea if (ioctl(acpifd, ACPIIO_BATT_GET_BST, &battio) == -1)
1295a43d9b0SMagliano Andrea err(EX_IOERR, "get battery status (%d) failed", num);
1305a43d9b0SMagliano Andrea if (battio.bst.state != ACPI_BATT_STAT_NOT_PRESENT)
1315a43d9b0SMagliano Andrea volt = battio.bst.volt;
1325a43d9b0SMagliano Andrea
1337d58d14bSHasso Tepper /* Print current battery state information. */
1347d58d14bSHasso Tepper battio.unit = num;
1357d58d14bSHasso Tepper if (ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1)
1367d58d14bSHasso Tepper err(EX_IOERR, "get battery user info (%d) failed", num);
1377d58d14bSHasso Tepper if (battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) {
1387d58d14bSHasso Tepper printf("State:\t\t\t");
1397d58d14bSHasso Tepper if (battio.battinfo.state == 0)
1407d58d14bSHasso Tepper printf("high ");
1417d58d14bSHasso Tepper if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
1427d58d14bSHasso Tepper printf("critical ");
1437d58d14bSHasso Tepper if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG)
1447d58d14bSHasso Tepper printf("discharging ");
1457d58d14bSHasso Tepper if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
1467d58d14bSHasso Tepper printf("charging ");
1477d58d14bSHasso Tepper printf("\n");
1487d58d14bSHasso Tepper if (battio.battinfo.cap == -1)
1497d58d14bSHasso Tepper printf("Remaining capacity:\tunknown\n");
1507d58d14bSHasso Tepper else
1517d58d14bSHasso Tepper printf("Remaining capacity:\t%d%%\n",
1527d58d14bSHasso Tepper battio.battinfo.cap);
1537d58d14bSHasso Tepper if (battio.battinfo.min == -1)
1547d58d14bSHasso Tepper printf("Remaining time:\t\tunknown\n");
1557d58d14bSHasso Tepper else {
1567d58d14bSHasso Tepper hours = battio.battinfo.min / 60;
1577d58d14bSHasso Tepper min = battio.battinfo.min % 60;
1587d58d14bSHasso Tepper printf("Remaining time:\t\t%d:%02d\n", hours, min);
1597d58d14bSHasso Tepper }
1607d58d14bSHasso Tepper if (battio.battinfo.rate == -1)
1617d58d14bSHasso Tepper printf("Present rate:\t\tunknown\n");
1625a43d9b0SMagliano Andrea else if (amp && volt != UNKNOWN_VOLTAGE) {
1635a43d9b0SMagliano Andrea printf("Present rate:\t\t%d mA (%d mW)\n",
1645a43d9b0SMagliano Andrea battio.battinfo.rate,
1655a43d9b0SMagliano Andrea battio.battinfo.rate * volt / 1000);
1665a43d9b0SMagliano Andrea } else
1677d58d14bSHasso Tepper printf("Present rate:\t\t%d %s\n",
1687d58d14bSHasso Tepper battio.battinfo.rate, pwr_units);
1697d58d14bSHasso Tepper } else
1707d58d14bSHasso Tepper printf("State:\t\t\tnot present\n");
1717d58d14bSHasso Tepper
1727d58d14bSHasso Tepper /* Print battery voltage information. */
17320cc1873SSascha Wildner if (volt == UNKNOWN_VOLTAGE)
17420cc1873SSascha Wildner printf("Present voltage:\tunknown\n");
1757d58d14bSHasso Tepper else
17620cc1873SSascha Wildner printf("Present voltage:\t%d mV\n", volt);
1777d58d14bSHasso Tepper
178967ae586SMatthew Dillon return (0);
179967ae586SMatthew Dillon }
180967ae586SMatthew Dillon
181967ae586SMatthew Dillon static void
usage(const char * prog)182967ae586SMatthew Dillon usage(const char* prog)
183967ae586SMatthew Dillon {
18477c1a34eSAlexander Polakov printf("usage: %s [-h] [-i batt] [-k ack] [-s 1-4]\n", prog);
185967ae586SMatthew Dillon exit(0);
186967ae586SMatthew Dillon }
187967ae586SMatthew Dillon
188967ae586SMatthew Dillon int
main(int argc,char * argv[])189967ae586SMatthew Dillon main(int argc, char *argv[])
190967ae586SMatthew Dillon {
191*2352f0a1SSascha Wildner char c, *prog, *ptr;
192967ae586SMatthew Dillon int sleep_type;
193967ae586SMatthew Dillon
194967ae586SMatthew Dillon prog = argv[0];
195*2352f0a1SSascha Wildner if (strstr((ptr = strrchr(prog, '/')) ? ptr + 1 : prog, "apm") != 0) {
196*2352f0a1SSascha Wildner acpi_init();
197*2352f0a1SSascha Wildner acpi_battinfo(0);
198*2352f0a1SSascha Wildner close(acpifd);
199*2352f0a1SSascha Wildner exit(0);
200*2352f0a1SSascha Wildner } else if (argc < 2) {
201967ae586SMatthew Dillon usage(prog);
202967ae586SMatthew Dillon /* NOTREACHED */
203*2352f0a1SSascha Wildner }
204967ae586SMatthew Dillon
205967ae586SMatthew Dillon sleep_type = -1;
206967ae586SMatthew Dillon acpi_init();
20777c1a34eSAlexander Polakov while ((c = getopt(argc, argv, "hi:k:s:")) != -1) {
208967ae586SMatthew Dillon switch (c) {
209967ae586SMatthew Dillon case 'i':
210967ae586SMatthew Dillon acpi_battinfo(atoi(optarg));
211967ae586SMatthew Dillon break;
21277c1a34eSAlexander Polakov case 'k':
21377c1a34eSAlexander Polakov acpi_sleep_ack(atoi(optarg));
214967ae586SMatthew Dillon break;
215967ae586SMatthew Dillon case 's':
216967ae586SMatthew Dillon if (optarg[0] == 'S')
217967ae586SMatthew Dillon sleep_type = optarg[1] - '0';
218967ae586SMatthew Dillon else
219967ae586SMatthew Dillon sleep_type = optarg[0] - '0';
22077c1a34eSAlexander Polakov if (sleep_type < 1 || sleep_type > 4)
221967ae586SMatthew Dillon errx(EX_USAGE, "invalid sleep type (%d)",
222967ae586SMatthew Dillon sleep_type);
223967ae586SMatthew Dillon break;
224967ae586SMatthew Dillon case 'h':
225967ae586SMatthew Dillon default:
226967ae586SMatthew Dillon usage(prog);
227967ae586SMatthew Dillon /* NOTREACHED */
228967ae586SMatthew Dillon }
229967ae586SMatthew Dillon }
230967ae586SMatthew Dillon argc -= optind;
231967ae586SMatthew Dillon argv += optind;
232967ae586SMatthew Dillon
23377c1a34eSAlexander Polakov if (sleep_type != -1)
234967ae586SMatthew Dillon acpi_sleep(sleep_type);
235967ae586SMatthew Dillon
236967ae586SMatthew Dillon close(acpifd);
237967ae586SMatthew Dillon exit (0);
238967ae586SMatthew Dillon }
239