| @@ -1,888 +1,885 @@ | | | @@ -1,888 +1,885 @@ |
1 | /* $NetBSD: acpi_bat.c,v 1.116 2018/08/10 17:11:56 riastradh Exp $ */ | | 1 | /* $NetBSD: acpi_bat.c,v 1.117 2021/01/29 15:20:13 thorpej Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2003 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2003 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum of By Noon Software, Inc. | | 8 | * by Charles M. Hannum of By Noon Software, Inc. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright 2001 Bill Sommerfeld. | | 33 | * Copyright 2001 Bill Sommerfeld. |
34 | * All rights reserved. | | 34 | * All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. All advertising materials mentioning features or use of this software | | 44 | * 3. All advertising materials mentioning features or use of this software |
45 | * must display the following acknowledgement: | | 45 | * must display the following acknowledgement: |
46 | * This product includes software developed for the NetBSD Project by | | 46 | * This product includes software developed for the NetBSD Project by |
47 | * Wasabi Systems, Inc. | | 47 | * Wasabi Systems, Inc. |
48 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 48 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
49 | * or promote products derived from this software without specific prior | | 49 | * or promote products derived from this software without specific prior |
50 | * written permission. | | 50 | * written permission. |
51 | * | | 51 | * |
52 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 52 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
54 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 54 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
55 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 55 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
56 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 56 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
57 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 57 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
58 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 58 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
59 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 59 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
60 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 60 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
61 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 61 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
62 | * POSSIBILITY OF SUCH DAMAGE. | | 62 | * POSSIBILITY OF SUCH DAMAGE. |
63 | */ | | 63 | */ |
64 | | | 64 | |
65 | /* | | 65 | /* |
66 | * ACPI Battery Driver. | | 66 | * ACPI Battery Driver. |
67 | * | | 67 | * |
68 | * ACPI defines two different battery device interfaces: "Control | | 68 | * ACPI defines two different battery device interfaces: "Control |
69 | * Method" batteries, in which AML methods are defined in order to get | | 69 | * Method" batteries, in which AML methods are defined in order to get |
70 | * battery status and set battery alarm thresholds, and a "Smart | | 70 | * battery status and set battery alarm thresholds, and a "Smart |
71 | * Battery" device, which is an SMbus device accessed through the ACPI | | 71 | * Battery" device, which is an SMbus device accessed through the ACPI |
72 | * Embedded Controller device. | | 72 | * Embedded Controller device. |
73 | * | | 73 | * |
74 | * This driver is for the "Control Method"-style battery only. | | 74 | * This driver is for the "Control Method"-style battery only. |
75 | */ | | 75 | */ |
76 | | | 76 | |
77 | #include <sys/cdefs.h> | | 77 | #include <sys/cdefs.h> |
78 | __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.116 2018/08/10 17:11:56 riastradh Exp $"); | | 78 | __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.117 2021/01/29 15:20:13 thorpej Exp $"); |
79 | | | 79 | |
80 | #include <sys/param.h> | | 80 | #include <sys/param.h> |
81 | #include <sys/condvar.h> | | 81 | #include <sys/condvar.h> |
82 | #include <sys/device.h> | | 82 | #include <sys/device.h> |
83 | #include <sys/kernel.h> | | 83 | #include <sys/kernel.h> |
84 | #include <sys/kmem.h> | | 84 | #include <sys/kmem.h> |
85 | #include <sys/module.h> | | 85 | #include <sys/module.h> |
86 | #include <sys/mutex.h> | | 86 | #include <sys/mutex.h> |
87 | #include <sys/systm.h> | | 87 | #include <sys/systm.h> |
88 | | | 88 | |
89 | #include <dev/acpi/acpireg.h> | | 89 | #include <dev/acpi/acpireg.h> |
90 | #include <dev/acpi/acpivar.h> | | 90 | #include <dev/acpi/acpivar.h> |
91 | | | 91 | |
92 | #define _COMPONENT ACPI_BAT_COMPONENT | | 92 | #define _COMPONENT ACPI_BAT_COMPONENT |
93 | ACPI_MODULE_NAME ("acpi_bat") | | 93 | ACPI_MODULE_NAME ("acpi_bat") |
94 | | | 94 | |
95 | #define ACPI_NOTIFY_BAT_STATUS 0x80 | | 95 | #define ACPI_NOTIFY_BAT_STATUS 0x80 |
96 | #define ACPI_NOTIFY_BAT_INFO 0x81 | | 96 | #define ACPI_NOTIFY_BAT_INFO 0x81 |
97 | | | 97 | |
98 | /* | | 98 | /* |
99 | * Sensor indexes. | | 99 | * Sensor indexes. |
100 | */ | | 100 | */ |
101 | enum { | | 101 | enum { |
102 | ACPIBAT_PRESENT = 0, | | 102 | ACPIBAT_PRESENT = 0, |
103 | ACPIBAT_DVOLTAGE = 1, | | 103 | ACPIBAT_DVOLTAGE = 1, |
104 | ACPIBAT_VOLTAGE = 2, | | 104 | ACPIBAT_VOLTAGE = 2, |
105 | ACPIBAT_DCAPACITY = 3, | | 105 | ACPIBAT_DCAPACITY = 3, |
106 | ACPIBAT_LFCCAPACITY = 4, | | 106 | ACPIBAT_LFCCAPACITY = 4, |
107 | ACPIBAT_CAPACITY = 5, | | 107 | ACPIBAT_CAPACITY = 5, |
108 | ACPIBAT_CHARGERATE = 6, | | 108 | ACPIBAT_CHARGERATE = 6, |
109 | ACPIBAT_DISCHARGERATE = 7, | | 109 | ACPIBAT_DISCHARGERATE = 7, |
110 | ACPIBAT_CHARGING = 8, | | 110 | ACPIBAT_CHARGING = 8, |
111 | ACPIBAT_CHARGE_STATE = 9, | | 111 | ACPIBAT_CHARGE_STATE = 9, |
112 | ACPIBAT_COUNT = 10 | | 112 | ACPIBAT_COUNT = 10 |
113 | }; | | 113 | }; |
114 | | | 114 | |
115 | /* | | 115 | /* |
116 | * Battery Information, _BIF | | 116 | * Battery Information, _BIF |
117 | * (ACPI 3.0, sec. 10.2.2.1). | | 117 | * (ACPI 3.0, sec. 10.2.2.1). |
118 | */ | | 118 | */ |
119 | enum { | | 119 | enum { |
120 | ACPIBAT_BIF_UNIT = 0, | | 120 | ACPIBAT_BIF_UNIT = 0, |
121 | ACPIBAT_BIF_DCAPACITY = 1, | | 121 | ACPIBAT_BIF_DCAPACITY = 1, |
122 | ACPIBAT_BIF_LFCCAPACITY = 2, | | 122 | ACPIBAT_BIF_LFCCAPACITY = 2, |
123 | ACPIBAT_BIF_TECHNOLOGY = 3, | | 123 | ACPIBAT_BIF_TECHNOLOGY = 3, |
124 | ACPIBAT_BIF_DVOLTAGE = 4, | | 124 | ACPIBAT_BIF_DVOLTAGE = 4, |
125 | ACPIBAT_BIF_WCAPACITY = 5, | | 125 | ACPIBAT_BIF_WCAPACITY = 5, |
126 | ACPIBAT_BIF_LCAPACITY = 6, | | 126 | ACPIBAT_BIF_LCAPACITY = 6, |
127 | ACPIBAT_BIF_GRANULARITY1 = 7, | | 127 | ACPIBAT_BIF_GRANULARITY1 = 7, |
128 | ACPIBAT_BIF_GRANULARITY2 = 8, | | 128 | ACPIBAT_BIF_GRANULARITY2 = 8, |
129 | ACPIBAT_BIF_MODEL = 9, | | 129 | ACPIBAT_BIF_MODEL = 9, |
130 | ACPIBAT_BIF_SERIAL = 10, | | 130 | ACPIBAT_BIF_SERIAL = 10, |
131 | ACPIBAT_BIF_TYPE = 11, | | 131 | ACPIBAT_BIF_TYPE = 11, |
132 | ACPIBAT_BIF_OEM = 12, | | 132 | ACPIBAT_BIF_OEM = 12, |
133 | ACPIBAT_BIF_COUNT = 13 | | 133 | ACPIBAT_BIF_COUNT = 13 |
134 | }; | | 134 | }; |
135 | | | 135 | |
136 | /* | | 136 | /* |
137 | * Battery Status, _BST | | 137 | * Battery Status, _BST |
138 | * (ACPI 3.0, sec. 10.2.2.3). | | 138 | * (ACPI 3.0, sec. 10.2.2.3). |
139 | */ | | 139 | */ |
140 | enum { | | 140 | enum { |
141 | ACPIBAT_BST_STATE = 0, | | 141 | ACPIBAT_BST_STATE = 0, |
142 | ACPIBAT_BST_RATE = 1, | | 142 | ACPIBAT_BST_RATE = 1, |
143 | ACPIBAT_BST_CAPACITY = 2, | | 143 | ACPIBAT_BST_CAPACITY = 2, |
144 | ACPIBAT_BST_VOLTAGE = 3, | | 144 | ACPIBAT_BST_VOLTAGE = 3, |
145 | ACPIBAT_BST_COUNT = 4 | | 145 | ACPIBAT_BST_COUNT = 4 |
146 | }; | | 146 | }; |
147 | | | 147 | |
148 | struct acpibat_softc { | | 148 | struct acpibat_softc { |
149 | struct acpi_devnode *sc_node; | | 149 | struct acpi_devnode *sc_node; |
150 | struct sysmon_envsys *sc_sme; | | 150 | struct sysmon_envsys *sc_sme; |
151 | struct timeval sc_last; | | 151 | struct timeval sc_last; |
152 | envsys_data_t *sc_sensor; | | 152 | envsys_data_t *sc_sensor; |
153 | kmutex_t sc_mutex; | | 153 | kmutex_t sc_mutex; |
154 | kcondvar_t sc_condvar; | | 154 | kcondvar_t sc_condvar; |
155 | int32_t sc_dcapacity; | | 155 | int32_t sc_dcapacity; |
156 | int32_t sc_dvoltage; | | 156 | int32_t sc_dvoltage; |
157 | int32_t sc_lcapacity; | | 157 | int32_t sc_lcapacity; |
158 | int32_t sc_wcapacity; | | 158 | int32_t sc_wcapacity; |
159 | int sc_present; | | 159 | int sc_present; |
160 | }; | | 160 | }; |
161 | | | 161 | |
162 | static const char * const bat_hid[] = { | | 162 | static const struct device_compatible_entry compat_data[] = { |
163 | "PNP0C0A", | | 163 | { .compat = "PNP0C0A" }, |
164 | NULL | | 164 | DEVICE_COMPAT_EOL |
165 | }; | | 165 | }; |
166 | | | 166 | |
167 | #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ | | 167 | #define ACPIBAT_PWRUNIT_MA 0x00000001 /* mA not mW */ |
168 | #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ | | 168 | #define ACPIBAT_ST_DISCHARGING 0x00000001 /* battery is discharging */ |
169 | #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ | | 169 | #define ACPIBAT_ST_CHARGING 0x00000002 /* battery is charging */ |
170 | #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ | | 170 | #define ACPIBAT_ST_CRITICAL 0x00000004 /* battery is critical */ |
171 | | | 171 | |
172 | /* | | 172 | /* |
173 | * A value used when _BST or _BIF is temporarily unknown. | | 173 | * A value used when _BST or _BIF is temporarily unknown. |
174 | */ | | 174 | */ |
175 | #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF | | 175 | #define ACPIBAT_VAL_UNKNOWN 0xFFFFFFFF |
176 | | | 176 | |
177 | #define ACPIBAT_VAL_ISVALID(x) \ | | 177 | #define ACPIBAT_VAL_ISVALID(x) \ |
178 | (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) | | 178 | (((x) != ACPIBAT_VAL_UNKNOWN) ? ENVSYS_SVALID : ENVSYS_SINVALID) |
179 | | | 179 | |
180 | static int acpibat_match(device_t, cfdata_t, void *); | | 180 | static int acpibat_match(device_t, cfdata_t, void *); |
181 | static void acpibat_attach(device_t, device_t, void *); | | 181 | static void acpibat_attach(device_t, device_t, void *); |
182 | static int acpibat_detach(device_t, int); | | 182 | static int acpibat_detach(device_t, int); |
183 | static int acpibat_get_sta(device_t); | | 183 | static int acpibat_get_sta(device_t); |
184 | static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, uint32_t); | | 184 | static ACPI_OBJECT *acpibat_get_object(ACPI_HANDLE, const char *, uint32_t); |
185 | static void acpibat_get_info(device_t); | | 185 | static void acpibat_get_info(device_t); |
186 | static void acpibat_print_info(device_t, ACPI_OBJECT *); | | 186 | static void acpibat_print_info(device_t, ACPI_OBJECT *); |
187 | static void acpibat_get_status(device_t); | | 187 | static void acpibat_get_status(device_t); |
188 | static void acpibat_update_info(void *); | | 188 | static void acpibat_update_info(void *); |
189 | static void acpibat_update_status(void *); | | 189 | static void acpibat_update_status(void *); |
190 | static void acpibat_init_envsys(device_t); | | 190 | static void acpibat_init_envsys(device_t); |
191 | static void acpibat_notify_handler(ACPI_HANDLE, uint32_t, void *); | | 191 | static void acpibat_notify_handler(ACPI_HANDLE, uint32_t, void *); |
192 | static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); | | 192 | static void acpibat_refresh(struct sysmon_envsys *, envsys_data_t *); |
193 | static bool acpibat_resume(device_t, const pmf_qual_t *); | | 193 | static bool acpibat_resume(device_t, const pmf_qual_t *); |
194 | static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *, | | 194 | static void acpibat_get_limits(struct sysmon_envsys *, envsys_data_t *, |
195 | sysmon_envsys_lim_t *, uint32_t *); | | 195 | sysmon_envsys_lim_t *, uint32_t *); |
196 | | | 196 | |
197 | CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), | | 197 | CFATTACH_DECL_NEW(acpibat, sizeof(struct acpibat_softc), |
198 | acpibat_match, acpibat_attach, acpibat_detach, NULL); | | 198 | acpibat_match, acpibat_attach, acpibat_detach, NULL); |
199 | | | 199 | |
200 | /* | | 200 | /* |
201 | * acpibat_match: | | 201 | * acpibat_match: |
202 | * | | 202 | * |
203 | * Autoconfiguration `match' routine. | | 203 | * Autoconfiguration `match' routine. |
204 | */ | | 204 | */ |
205 | static int | | 205 | static int |
206 | acpibat_match(device_t parent, cfdata_t match, void *aux) | | 206 | acpibat_match(device_t parent, cfdata_t match, void *aux) |
207 | { | | 207 | { |
208 | struct acpi_attach_args *aa = aux; | | 208 | struct acpi_attach_args *aa = aux; |
209 | | | 209 | |
210 | if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) | | 210 | return acpi_compatible_match(aa, compat_data); |
211 | return 0; | | | |
212 | | | | |
213 | return acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid); | | | |
214 | } | | 211 | } |
215 | | | 212 | |
216 | /* | | 213 | /* |
217 | * acpibat_attach: | | 214 | * acpibat_attach: |
218 | * | | 215 | * |
219 | * Autoconfiguration `attach' routine. | | 216 | * Autoconfiguration `attach' routine. |
220 | */ | | 217 | */ |
221 | static void | | 218 | static void |
222 | acpibat_attach(device_t parent, device_t self, void *aux) | | 219 | acpibat_attach(device_t parent, device_t self, void *aux) |
223 | { | | 220 | { |
224 | struct acpibat_softc *sc = device_private(self); | | 221 | struct acpibat_softc *sc = device_private(self); |
225 | struct acpi_attach_args *aa = aux; | | 222 | struct acpi_attach_args *aa = aux; |
226 | ACPI_HANDLE tmp; | | 223 | ACPI_HANDLE tmp; |
227 | ACPI_STATUS rv; | | 224 | ACPI_STATUS rv; |
228 | | | 225 | |
229 | aprint_naive(": ACPI Battery\n"); | | 226 | aprint_naive(": ACPI Battery\n"); |
230 | aprint_normal(": ACPI Battery\n"); | | 227 | aprint_normal(": ACPI Battery\n"); |
231 | | | 228 | |
232 | sc->sc_node = aa->aa_node; | | 229 | sc->sc_node = aa->aa_node; |
233 | | | 230 | |
234 | sc->sc_present = 0; | | 231 | sc->sc_present = 0; |
235 | sc->sc_dvoltage = 0; | | 232 | sc->sc_dvoltage = 0; |
236 | sc->sc_dcapacity = 0; | | 233 | sc->sc_dcapacity = 0; |
237 | sc->sc_lcapacity = 0; | | 234 | sc->sc_lcapacity = 0; |
238 | sc->sc_wcapacity = 0; | | 235 | sc->sc_wcapacity = 0; |
239 | | | 236 | |
240 | sc->sc_sme = NULL; | | 237 | sc->sc_sme = NULL; |
241 | sc->sc_sensor = NULL; | | 238 | sc->sc_sensor = NULL; |
242 | | | 239 | |
243 | mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); | | 240 | mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); |
244 | cv_init(&sc->sc_condvar, device_xname(self)); | | 241 | cv_init(&sc->sc_condvar, device_xname(self)); |
245 | | | 242 | |
246 | (void)pmf_device_register(self, NULL, acpibat_resume); | | 243 | (void)pmf_device_register(self, NULL, acpibat_resume); |
247 | (void)acpi_register_notify(sc->sc_node, acpibat_notify_handler); | | 244 | (void)acpi_register_notify(sc->sc_node, acpibat_notify_handler); |
248 | | | 245 | |
249 | sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * | | 246 | sc->sc_sensor = kmem_zalloc(ACPIBAT_COUNT * |
250 | sizeof(*sc->sc_sensor), KM_SLEEP); | | 247 | sizeof(*sc->sc_sensor), KM_SLEEP); |
251 | | | 248 | |
252 | if (sc->sc_sensor == NULL) | | 249 | if (sc->sc_sensor == NULL) |
253 | return; | | 250 | return; |
254 | | | 251 | |
255 | config_interrupts(self, acpibat_init_envsys); | | 252 | config_interrupts(self, acpibat_init_envsys); |
256 | | | 253 | |
257 | /* | | 254 | /* |
258 | * If this is ever seen, the driver should be extended. | | 255 | * If this is ever seen, the driver should be extended. |
259 | */ | | 256 | */ |
260 | rv = AcpiGetHandle(sc->sc_node->ad_handle, "_BIX", &tmp); | | 257 | rv = AcpiGetHandle(sc->sc_node->ad_handle, "_BIX", &tmp); |
261 | | | 258 | |
262 | if (ACPI_SUCCESS(rv)) | | 259 | if (ACPI_SUCCESS(rv)) |
263 | aprint_verbose_dev(self, "ACPI 4.0 functionality present\n"); | | 260 | aprint_verbose_dev(self, "ACPI 4.0 functionality present\n"); |
264 | } | | 261 | } |
265 | | | 262 | |
266 | /* | | 263 | /* |
267 | * acpibat_detach: | | 264 | * acpibat_detach: |
268 | * | | 265 | * |
269 | * Autoconfiguration `detach' routine. | | 266 | * Autoconfiguration `detach' routine. |
270 | */ | | 267 | */ |
271 | static int | | 268 | static int |
272 | acpibat_detach(device_t self, int flags) | | 269 | acpibat_detach(device_t self, int flags) |
273 | { | | 270 | { |
274 | struct acpibat_softc *sc = device_private(self); | | 271 | struct acpibat_softc *sc = device_private(self); |
275 | | | 272 | |
276 | acpi_deregister_notify(sc->sc_node); | | 273 | acpi_deregister_notify(sc->sc_node); |
277 | | | 274 | |
278 | cv_destroy(&sc->sc_condvar); | | 275 | cv_destroy(&sc->sc_condvar); |
279 | mutex_destroy(&sc->sc_mutex); | | 276 | mutex_destroy(&sc->sc_mutex); |
280 | | | 277 | |
281 | if (sc->sc_sme != NULL) | | 278 | if (sc->sc_sme != NULL) |
282 | sysmon_envsys_unregister(sc->sc_sme); | | 279 | sysmon_envsys_unregister(sc->sc_sme); |
283 | | | 280 | |
284 | if (sc->sc_sensor != NULL) | | 281 | if (sc->sc_sensor != NULL) |
285 | kmem_free(sc->sc_sensor, ACPIBAT_COUNT * | | 282 | kmem_free(sc->sc_sensor, ACPIBAT_COUNT * |
286 | sizeof(*sc->sc_sensor)); | | 283 | sizeof(*sc->sc_sensor)); |
287 | | | 284 | |
288 | pmf_device_deregister(self); | | 285 | pmf_device_deregister(self); |
289 | | | 286 | |
290 | return 0; | | 287 | return 0; |
291 | } | | 288 | } |
292 | | | 289 | |
293 | /* | | 290 | /* |
294 | * acpibat_get_sta: | | 291 | * acpibat_get_sta: |
295 | * | | 292 | * |
296 | * Evaluate whether the battery is present or absent. | | 293 | * Evaluate whether the battery is present or absent. |
297 | * | | 294 | * |
298 | * Returns: 0 for no battery, 1 for present, and -1 on error. | | 295 | * Returns: 0 for no battery, 1 for present, and -1 on error. |
299 | */ | | 296 | */ |
300 | static int | | 297 | static int |
301 | acpibat_get_sta(device_t dv) | | 298 | acpibat_get_sta(device_t dv) |
302 | { | | 299 | { |
303 | struct acpibat_softc *sc = device_private(dv); | | 300 | struct acpibat_softc *sc = device_private(dv); |
304 | ACPI_INTEGER val; | | 301 | ACPI_INTEGER val; |
305 | ACPI_STATUS rv; | | 302 | ACPI_STATUS rv; |
306 | | | 303 | |
307 | rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); | | 304 | rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val); |
308 | | | 305 | |
309 | if (ACPI_FAILURE(rv)) { | | 306 | if (ACPI_FAILURE(rv)) { |
310 | aprint_error_dev(dv, "failed to evaluate _STA\n"); | | 307 | aprint_error_dev(dv, "failed to evaluate _STA\n"); |
311 | return -1; | | 308 | return -1; |
312 | } | | 309 | } |
313 | | | 310 | |
314 | sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; | | 311 | sc->sc_sensor[ACPIBAT_PRESENT].state = ENVSYS_SVALID; |
315 | | | 312 | |
316 | if ((val & ACPI_STA_BATTERY_PRESENT) == 0) { | | 313 | if ((val & ACPI_STA_BATTERY_PRESENT) == 0) { |
317 | sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; | | 314 | sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 0; |
318 | return 0; | | 315 | return 0; |
319 | } | | 316 | } |
320 | | | 317 | |
321 | sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; | | 318 | sc->sc_sensor[ACPIBAT_PRESENT].value_cur = 1; |
322 | | | 319 | |
323 | return 1; | | 320 | return 1; |
324 | } | | 321 | } |
325 | | | 322 | |
326 | static ACPI_OBJECT * | | 323 | static ACPI_OBJECT * |
327 | acpibat_get_object(ACPI_HANDLE hdl, const char *pth, uint32_t count) | | 324 | acpibat_get_object(ACPI_HANDLE hdl, const char *pth, uint32_t count) |
328 | { | | 325 | { |
329 | ACPI_OBJECT *obj; | | 326 | ACPI_OBJECT *obj; |
330 | ACPI_BUFFER buf; | | 327 | ACPI_BUFFER buf; |
331 | ACPI_STATUS rv; | | 328 | ACPI_STATUS rv; |
332 | | | 329 | |
333 | rv = acpi_eval_struct(hdl, pth, &buf); | | 330 | rv = acpi_eval_struct(hdl, pth, &buf); |
334 | | | 331 | |
335 | if (ACPI_FAILURE(rv)) | | 332 | if (ACPI_FAILURE(rv)) |
336 | return NULL; | | 333 | return NULL; |
337 | | | 334 | |
338 | obj = buf.Pointer; | | 335 | obj = buf.Pointer; |
339 | | | 336 | |
340 | if (obj->Type != ACPI_TYPE_PACKAGE) { | | 337 | if (obj->Type != ACPI_TYPE_PACKAGE) { |
341 | ACPI_FREE(buf.Pointer); | | 338 | ACPI_FREE(buf.Pointer); |
342 | return NULL; | | 339 | return NULL; |
343 | } | | 340 | } |
344 | | | 341 | |
345 | if (obj->Package.Count != count) { | | 342 | if (obj->Package.Count != count) { |
346 | ACPI_FREE(buf.Pointer); | | 343 | ACPI_FREE(buf.Pointer); |
347 | return NULL; | | 344 | return NULL; |
348 | } | | 345 | } |
349 | | | 346 | |
350 | return obj; | | 347 | return obj; |
351 | } | | 348 | } |
352 | | | 349 | |
353 | /* | | 350 | /* |
354 | * acpibat_get_info: | | 351 | * acpibat_get_info: |
355 | * | | 352 | * |
356 | * Get the battery info. | | 353 | * Get the battery info. |
357 | */ | | 354 | */ |
358 | static void | | 355 | static void |
359 | acpibat_get_info(device_t dv) | | 356 | acpibat_get_info(device_t dv) |
360 | { | | 357 | { |
361 | struct acpibat_softc *sc = device_private(dv); | | 358 | struct acpibat_softc *sc = device_private(dv); |
362 | ACPI_HANDLE hdl = sc->sc_node->ad_handle; | | 359 | ACPI_HANDLE hdl = sc->sc_node->ad_handle; |
363 | ACPI_OBJECT *elm, *obj; | | 360 | ACPI_OBJECT *elm, *obj; |
364 | ACPI_STATUS rv = AE_OK; | | 361 | ACPI_STATUS rv = AE_OK; |
365 | int capunit, i, rateunit; | | 362 | int capunit, i, rateunit; |
366 | uint64_t val; | | 363 | uint64_t val; |
367 | | | 364 | |
368 | obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); | | 365 | obj = acpibat_get_object(hdl, "_BIF", ACPIBAT_BIF_COUNT); |
369 | | | 366 | |
370 | if (obj == NULL) { | | 367 | if (obj == NULL) { |
371 | rv = AE_ERROR; | | 368 | rv = AE_ERROR; |
372 | goto out; | | 369 | goto out; |
373 | } | | 370 | } |
374 | | | 371 | |
375 | elm = obj->Package.Elements; | | 372 | elm = obj->Package.Elements; |
376 | | | 373 | |
377 | for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { | | 374 | for (i = ACPIBAT_BIF_UNIT; i < ACPIBAT_BIF_MODEL; i++) { |
378 | | | 375 | |
379 | if (elm[i].Type != ACPI_TYPE_INTEGER) { | | 376 | if (elm[i].Type != ACPI_TYPE_INTEGER) { |
380 | rv = AE_TYPE; | | 377 | rv = AE_TYPE; |
381 | goto out; | | 378 | goto out; |
382 | } | | 379 | } |
383 | | | 380 | |
384 | if (elm[i].Integer.Value != ACPIBAT_VAL_UNKNOWN && | | 381 | if (elm[i].Integer.Value != ACPIBAT_VAL_UNKNOWN && |
385 | elm[i].Integer.Value >= INT_MAX) { | | 382 | elm[i].Integer.Value >= INT_MAX) { |
386 | rv = AE_LIMIT; | | 383 | rv = AE_LIMIT; |
387 | goto out; | | 384 | goto out; |
388 | } | | 385 | } |
389 | } | | 386 | } |
390 | | | 387 | |
391 | switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { | | 388 | switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { |
392 | case ACPIBAT_PWRUNIT_MA: | | 389 | case ACPIBAT_PWRUNIT_MA: |
393 | capunit = ENVSYS_SAMPHOUR; | | 390 | capunit = ENVSYS_SAMPHOUR; |
394 | rateunit = ENVSYS_SAMPS; | | 391 | rateunit = ENVSYS_SAMPS; |
395 | break; | | 392 | break; |
396 | default: | | 393 | default: |
397 | capunit = ENVSYS_SWATTHOUR; | | 394 | capunit = ENVSYS_SWATTHOUR; |
398 | rateunit = ENVSYS_SWATTS; | | 395 | rateunit = ENVSYS_SWATTS; |
399 | break; | | 396 | break; |
400 | } | | 397 | } |
401 | | | 398 | |
402 | sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; | | 399 | sc->sc_sensor[ACPIBAT_DCAPACITY].units = capunit; |
403 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; | | 400 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].units = capunit; |
404 | sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; | | 401 | sc->sc_sensor[ACPIBAT_CHARGERATE].units = rateunit; |
405 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; | | 402 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].units = rateunit; |
406 | sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; | | 403 | sc->sc_sensor[ACPIBAT_CAPACITY].units = capunit; |
407 | | | 404 | |
408 | /* Design capacity. */ | | 405 | /* Design capacity. */ |
409 | val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; | | 406 | val = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; |
410 | sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000; | | 407 | sc->sc_sensor[ACPIBAT_DCAPACITY].value_cur = val * 1000; |
411 | sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); | | 408 | sc->sc_sensor[ACPIBAT_DCAPACITY].state = ACPIBAT_VAL_ISVALID(val); |
412 | | | 409 | |
413 | /* Last full charge capacity. */ | | 410 | /* Last full charge capacity. */ |
414 | val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value; | | 411 | val = elm[ACPIBAT_BIF_LFCCAPACITY].Integer.Value; |
415 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000; | | 412 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur = val * 1000; |
416 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); | | 413 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].state = ACPIBAT_VAL_ISVALID(val); |
417 | | | 414 | |
418 | /* Design voltage. */ | | 415 | /* Design voltage. */ |
419 | val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; | | 416 | val = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; |
420 | sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000; | | 417 | sc->sc_sensor[ACPIBAT_DVOLTAGE].value_cur = val * 1000; |
421 | sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); | | 418 | sc->sc_sensor[ACPIBAT_DVOLTAGE].state = ACPIBAT_VAL_ISVALID(val); |
422 | | | 419 | |
423 | /* Design low and warning capacity. */ | | 420 | /* Design low and warning capacity. */ |
424 | sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; | | 421 | sc->sc_lcapacity = elm[ACPIBAT_BIF_LCAPACITY].Integer.Value * 1000; |
425 | sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; | | 422 | sc->sc_wcapacity = elm[ACPIBAT_BIF_WCAPACITY].Integer.Value * 1000; |
426 | | | 423 | |
427 | /* | | 424 | /* |
428 | * Initialize the maximum of current capacity | | 425 | * Initialize the maximum of current capacity |
429 | * to the last known full charge capacity. | | 426 | * to the last known full charge capacity. |
430 | */ | | 427 | */ |
431 | val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; | | 428 | val = sc->sc_sensor[ACPIBAT_LFCCAPACITY].value_cur; |
432 | sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; | | 429 | sc->sc_sensor[ACPIBAT_CAPACITY].value_max = val; |
433 | | | 430 | |
434 | acpibat_print_info(dv, elm); | | 431 | acpibat_print_info(dv, elm); |
435 | | | 432 | |
436 | out: | | 433 | out: |
437 | if (obj != NULL) | | 434 | if (obj != NULL) |
438 | ACPI_FREE(obj); | | 435 | ACPI_FREE(obj); |
439 | | | 436 | |
440 | if (ACPI_FAILURE(rv)) | | 437 | if (ACPI_FAILURE(rv)) |
441 | aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", | | 438 | aprint_error_dev(dv, "failed to evaluate _BIF: %s\n", |
442 | AcpiFormatException(rv)); | | 439 | AcpiFormatException(rv)); |
443 | } | | 440 | } |
444 | | | 441 | |
445 | /* | | 442 | /* |
446 | * acpibat_print_info: | | 443 | * acpibat_print_info: |
447 | * | | 444 | * |
448 | * Display the battery info. | | 445 | * Display the battery info. |
449 | */ | | 446 | */ |
450 | static void | | 447 | static void |
451 | acpibat_print_info(device_t dv, ACPI_OBJECT *elm) | | 448 | acpibat_print_info(device_t dv, ACPI_OBJECT *elm) |
452 | { | | 449 | { |
453 | struct acpibat_softc *sc = device_private(dv); | | 450 | struct acpibat_softc *sc = device_private(dv); |
454 | const char *tech, *unit; | | 451 | const char *tech, *unit; |
455 | int32_t dcap, dvol; | | 452 | int32_t dcap, dvol; |
456 | int i; | | 453 | int i; |
457 | | | 454 | |
458 | for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { | | 455 | for (i = ACPIBAT_BIF_OEM; i > ACPIBAT_BIF_GRANULARITY2; i--) { |
459 | | | 456 | |
460 | if (elm[i].Type != ACPI_TYPE_STRING) | | 457 | if (elm[i].Type != ACPI_TYPE_STRING) |
461 | return; | | 458 | return; |
462 | | | 459 | |
463 | if (elm[i].String.Pointer == NULL) | | 460 | if (elm[i].String.Pointer == NULL) |
464 | return; | | 461 | return; |
465 | | | 462 | |
466 | if (elm[i].String.Pointer[0] == '\0') | | 463 | if (elm[i].String.Pointer[0] == '\0') |
467 | return; | | 464 | return; |
468 | } | | 465 | } |
469 | | | 466 | |
470 | dcap = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; | | 467 | dcap = elm[ACPIBAT_BIF_DCAPACITY].Integer.Value; |
471 | dvol = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; | | 468 | dvol = elm[ACPIBAT_BIF_DVOLTAGE].Integer.Value; |
472 | | | 469 | |
473 | /* | | 470 | /* |
474 | * Try to detect whether the battery was switched. | | 471 | * Try to detect whether the battery was switched. |
475 | */ | | 472 | */ |
476 | if (sc->sc_dcapacity == dcap && sc->sc_dvoltage == dvol) | | 473 | if (sc->sc_dcapacity == dcap && sc->sc_dvoltage == dvol) |
477 | return; | | 474 | return; |
478 | else { | | 475 | else { |
479 | sc->sc_dcapacity = dcap; | | 476 | sc->sc_dcapacity = dcap; |
480 | sc->sc_dvoltage = dvol; | | 477 | sc->sc_dvoltage = dvol; |
481 | } | | 478 | } |
482 | | | 479 | |
483 | tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ? | | 480 | tech = (elm[ACPIBAT_BIF_TECHNOLOGY].Integer.Value != 0) ? |
484 | "rechargeable" : "non-rechargeable"; | | 481 | "rechargeable" : "non-rechargeable"; |
485 | | | 482 | |
486 | aprint_normal_dev(dv, "%s %s %s battery\n", | | 483 | aprint_normal_dev(dv, "%s %s %s battery\n", |
487 | elm[ACPIBAT_BIF_OEM].String.Pointer, | | 484 | elm[ACPIBAT_BIF_OEM].String.Pointer, |
488 | elm[ACPIBAT_BIF_TYPE].String.Pointer, tech); | | 485 | elm[ACPIBAT_BIF_TYPE].String.Pointer, tech); |
489 | | | 486 | |
490 | aprint_debug_dev(dv, "model number %s, serial number %s\n", | | 487 | aprint_debug_dev(dv, "model number %s, serial number %s\n", |
491 | elm[ACPIBAT_BIF_MODEL].String.Pointer, | | 488 | elm[ACPIBAT_BIF_MODEL].String.Pointer, |
492 | elm[ACPIBAT_BIF_SERIAL].String.Pointer); | | 489 | elm[ACPIBAT_BIF_SERIAL].String.Pointer); |
493 | | | 490 | |
494 | #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000) | | 491 | #define SCALE(x) (((int)x) / 1000000), ((((int)x) % 1000000) / 1000) |
495 | | | 492 | |
496 | /* | | 493 | /* |
497 | * These values are defined as follows (ACPI 4.0, p. 388): | | 494 | * These values are defined as follows (ACPI 4.0, p. 388): |
498 | * | | 495 | * |
499 | * Granularity 1. "Battery capacity granularity between low | | 496 | * Granularity 1. "Battery capacity granularity between low |
500 | * and warning in [mAh] or [mWh]. That is, | | 497 | * and warning in [mAh] or [mWh]. That is, |
501 | * this is the smallest increment in capacity | | 498 | * this is the smallest increment in capacity |
502 | * that the battery is capable of measuring." | | 499 | * that the battery is capable of measuring." |
503 | * | | 500 | * |
504 | * Granularity 2. "Battery capacity granularity between warning | | 501 | * Granularity 2. "Battery capacity granularity between warning |
505 | * and full in [mAh] or [mWh]. [...]" | | 502 | * and full in [mAh] or [mWh]. [...]" |
506 | */ | | 503 | */ |
507 | switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { | | 504 | switch (elm[ACPIBAT_BIF_UNIT].Integer.Value) { |
508 | case ACPIBAT_PWRUNIT_MA: | | 505 | case ACPIBAT_PWRUNIT_MA: |
509 | unit = "Ah"; | | 506 | unit = "Ah"; |
510 | break; | | 507 | break; |
511 | default: | | 508 | default: |
512 | unit = "Wh"; | | 509 | unit = "Wh"; |
513 | break; | | 510 | break; |
514 | } | | 511 | } |
515 | | | 512 | |
516 | aprint_verbose_dev(dv, "granularity: " | | 513 | aprint_verbose_dev(dv, "granularity: " |
517 | "low->warn %d.%03d %s, warn->full %d.%03d %s\n", | | 514 | "low->warn %d.%03d %s, warn->full %d.%03d %s\n", |
518 | SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit, | | 515 | SCALE(elm[ACPIBAT_BIF_GRANULARITY1].Integer.Value * 1000), unit, |
519 | SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit); | | 516 | SCALE(elm[ACPIBAT_BIF_GRANULARITY2].Integer.Value * 1000), unit); |
520 | } | | 517 | } |
521 | | | 518 | |
522 | /* | | 519 | /* |
523 | * acpibat_get_status: | | 520 | * acpibat_get_status: |
524 | * | | 521 | * |
525 | * Get the current battery status. | | 522 | * Get the current battery status. |
526 | */ | | 523 | */ |
527 | static void | | 524 | static void |
528 | acpibat_get_status(device_t dv) | | 525 | acpibat_get_status(device_t dv) |
529 | { | | 526 | { |
530 | struct acpibat_softc *sc = device_private(dv); | | 527 | struct acpibat_softc *sc = device_private(dv); |
531 | ACPI_HANDLE hdl = sc->sc_node->ad_handle; | | 528 | ACPI_HANDLE hdl = sc->sc_node->ad_handle; |
532 | ACPI_OBJECT *elm, *obj; | | 529 | ACPI_OBJECT *elm, *obj; |
533 | ACPI_STATUS rv = AE_OK; | | 530 | ACPI_STATUS rv = AE_OK; |
534 | int i, rate, state; | | 531 | int i, rate, state; |
535 | uint64_t val; | | 532 | uint64_t val; |
536 | | | 533 | |
537 | obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); | | 534 | obj = acpibat_get_object(hdl, "_BST", ACPIBAT_BST_COUNT); |
538 | | | 535 | |
539 | if (obj == NULL) { | | 536 | if (obj == NULL) { |
540 | rv = AE_ERROR; | | 537 | rv = AE_ERROR; |
541 | goto out; | | 538 | goto out; |
542 | } | | 539 | } |
543 | | | 540 | |
544 | elm = obj->Package.Elements; | | 541 | elm = obj->Package.Elements; |
545 | | | 542 | |
546 | for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { | | 543 | for (i = ACPIBAT_BST_STATE; i < ACPIBAT_BST_COUNT; i++) { |
547 | | | 544 | |
548 | if (elm[i].Type != ACPI_TYPE_INTEGER) { | | 545 | if (elm[i].Type != ACPI_TYPE_INTEGER) { |
549 | rv = AE_TYPE; | | 546 | rv = AE_TYPE; |
550 | goto out; | | 547 | goto out; |
551 | } | | 548 | } |
552 | } | | 549 | } |
553 | | | 550 | |
554 | state = elm[ACPIBAT_BST_STATE].Integer.Value; | | 551 | state = elm[ACPIBAT_BST_STATE].Integer.Value; |
555 | | | 552 | |
556 | if ((state & ACPIBAT_ST_CHARGING) != 0) { | | 553 | if ((state & ACPIBAT_ST_CHARGING) != 0) { |
557 | /* XXX rate can be invalid */ | | 554 | /* XXX rate can be invalid */ |
558 | rate = elm[ACPIBAT_BST_RATE].Integer.Value; | | 555 | rate = elm[ACPIBAT_BST_RATE].Integer.Value; |
559 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; | | 556 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SVALID; |
560 | sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; | | 557 | sc->sc_sensor[ACPIBAT_CHARGERATE].value_cur = rate * 1000; |
561 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; | | 558 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; |
562 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; | | 559 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; |
563 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; | | 560 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 1; |
564 | } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { | | 561 | } else if ((state & ACPIBAT_ST_DISCHARGING) != 0) { |
565 | rate = elm[ACPIBAT_BST_RATE].Integer.Value; | | 562 | rate = elm[ACPIBAT_BST_RATE].Integer.Value; |
566 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; | | 563 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SVALID; |
567 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; | | 564 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].value_cur = rate * 1000; |
568 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; | | 565 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; |
569 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; | | 566 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; |
570 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; | | 567 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; |
571 | } else { | | 568 | } else { |
572 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; | | 569 | sc->sc_sensor[ACPIBAT_CHARGING].state = ENVSYS_SVALID; |
573 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; | | 570 | sc->sc_sensor[ACPIBAT_CHARGING].value_cur = 0; |
574 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; | | 571 | sc->sc_sensor[ACPIBAT_CHARGERATE].state = ENVSYS_SINVALID; |
575 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; | | 572 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].state = ENVSYS_SINVALID; |
576 | } | | 573 | } |
577 | | | 574 | |
578 | /* Remaining capacity. */ | | 575 | /* Remaining capacity. */ |
579 | val = elm[ACPIBAT_BST_CAPACITY].Integer.Value; | | 576 | val = elm[ACPIBAT_BST_CAPACITY].Integer.Value; |
580 | sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000; | | 577 | sc->sc_sensor[ACPIBAT_CAPACITY].value_cur = val * 1000; |
581 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); | | 578 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ACPIBAT_VAL_ISVALID(val); |
582 | | | 579 | |
583 | /* Battery voltage. */ | | 580 | /* Battery voltage. */ |
584 | val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value; | | 581 | val = elm[ACPIBAT_BST_VOLTAGE].Integer.Value; |
585 | sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000; | | 582 | sc->sc_sensor[ACPIBAT_VOLTAGE].value_cur = val * 1000; |
586 | sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); | | 583 | sc->sc_sensor[ACPIBAT_VOLTAGE].state = ACPIBAT_VAL_ISVALID(val); |
587 | | | 584 | |
588 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; | | 585 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].state = ENVSYS_SVALID; |
589 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = | | 586 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = |
590 | ENVSYS_BATTERY_CAPACITY_NORMAL; | | 587 | ENVSYS_BATTERY_CAPACITY_NORMAL; |
591 | | | 588 | |
592 | if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) { | | 589 | if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_wcapacity) { |
593 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; | | 590 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SWARNUNDER; |
594 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = | | 591 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = |
595 | ENVSYS_BATTERY_CAPACITY_WARNING; | | 592 | ENVSYS_BATTERY_CAPACITY_WARNING; |
596 | } | | 593 | } |
597 | | | 594 | |
598 | if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) { | | 595 | if (sc->sc_sensor[ACPIBAT_CAPACITY].value_cur < sc->sc_lcapacity) { |
599 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; | | 596 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITUNDER; |
600 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = | | 597 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = |
601 | ENVSYS_BATTERY_CAPACITY_LOW; | | 598 | ENVSYS_BATTERY_CAPACITY_LOW; |
602 | } | | 599 | } |
603 | | | 600 | |
604 | if ((state & ACPIBAT_ST_CRITICAL) != 0) { | | 601 | if ((state & ACPIBAT_ST_CRITICAL) != 0) { |
605 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; | | 602 | sc->sc_sensor[ACPIBAT_CAPACITY].state = ENVSYS_SCRITICAL; |
606 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = | | 603 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = |
607 | ENVSYS_BATTERY_CAPACITY_CRITICAL; | | 604 | ENVSYS_BATTERY_CAPACITY_CRITICAL; |
608 | } | | 605 | } |
609 | | | 606 | |
610 | out: | | 607 | out: |
611 | if (obj != NULL) | | 608 | if (obj != NULL) |
612 | ACPI_FREE(obj); | | 609 | ACPI_FREE(obj); |
613 | | | 610 | |
614 | if (ACPI_FAILURE(rv)) | | 611 | if (ACPI_FAILURE(rv)) |
615 | aprint_error_dev(dv, "failed to evaluate _BST: %s\n", | | 612 | aprint_error_dev(dv, "failed to evaluate _BST: %s\n", |
616 | AcpiFormatException(rv)); | | 613 | AcpiFormatException(rv)); |
617 | } | | 614 | } |
618 | | | 615 | |
619 | static void | | 616 | static void |
620 | acpibat_update_info(void *arg) | | 617 | acpibat_update_info(void *arg) |
621 | { | | 618 | { |
622 | device_t dv = arg; | | 619 | device_t dv = arg; |
623 | struct acpibat_softc *sc = device_private(dv); | | 620 | struct acpibat_softc *sc = device_private(dv); |
624 | int i, rv; | | 621 | int i, rv; |
625 | | | 622 | |
626 | mutex_enter(&sc->sc_mutex); | | 623 | mutex_enter(&sc->sc_mutex); |
627 | | | 624 | |
628 | rv = acpibat_get_sta(dv); | | 625 | rv = acpibat_get_sta(dv); |
629 | | | 626 | |
630 | if (rv > 0) { | | 627 | if (rv > 0) { |
631 | acpibat_get_info(dv); | | 628 | acpibat_get_info(dv); |
632 | | | 629 | |
633 | /* | | 630 | /* |
634 | * If the status changed, update the limits. | | 631 | * If the status changed, update the limits. |
635 | */ | | 632 | */ |
636 | if (sc->sc_present == 0 && | | 633 | if (sc->sc_present == 0 && |
637 | sc->sc_sensor[ACPIBAT_CAPACITY].value_max > 0) | | 634 | sc->sc_sensor[ACPIBAT_CAPACITY].value_max > 0) |
638 | sysmon_envsys_update_limits(sc->sc_sme, | | 635 | sysmon_envsys_update_limits(sc->sc_sme, |
639 | &sc->sc_sensor[ACPIBAT_CAPACITY]); | | 636 | &sc->sc_sensor[ACPIBAT_CAPACITY]); |
640 | } else { | | 637 | } else { |
641 | i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; | | 638 | i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; |
642 | | | 639 | |
643 | while (i < ACPIBAT_COUNT) { | | 640 | while (i < ACPIBAT_COUNT) { |
644 | sc->sc_sensor[i].state = ENVSYS_SINVALID; | | 641 | sc->sc_sensor[i].state = ENVSYS_SINVALID; |
645 | i++; | | 642 | i++; |
646 | } | | 643 | } |
647 | } | | 644 | } |
648 | | | 645 | |
649 | sc->sc_present = rv; | | 646 | sc->sc_present = rv; |
650 | | | 647 | |
651 | mutex_exit(&sc->sc_mutex); | | 648 | mutex_exit(&sc->sc_mutex); |
652 | } | | 649 | } |
653 | | | 650 | |
654 | static void | | 651 | static void |
655 | acpibat_update_status(void *arg) | | 652 | acpibat_update_status(void *arg) |
656 | { | | 653 | { |
657 | device_t dv = arg; | | 654 | device_t dv = arg; |
658 | struct acpibat_softc *sc = device_private(dv); | | 655 | struct acpibat_softc *sc = device_private(dv); |
659 | int i, rv; | | 656 | int i, rv; |
660 | | | 657 | |
661 | mutex_enter(&sc->sc_mutex); | | 658 | mutex_enter(&sc->sc_mutex); |
662 | | | 659 | |
663 | rv = acpibat_get_sta(dv); | | 660 | rv = acpibat_get_sta(dv); |
664 | | | 661 | |
665 | if (rv > 0) { | | 662 | if (rv > 0) { |
666 | | | 663 | |
667 | if (sc->sc_present == 0) | | 664 | if (sc->sc_present == 0) |
668 | acpibat_get_info(dv); | | 665 | acpibat_get_info(dv); |
669 | | | 666 | |
670 | acpibat_get_status(dv); | | 667 | acpibat_get_status(dv); |
671 | } else { | | 668 | } else { |
672 | i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; | | 669 | i = (rv < 0) ? 0 : ACPIBAT_DVOLTAGE; |
673 | | | 670 | |
674 | while (i < ACPIBAT_COUNT) { | | 671 | while (i < ACPIBAT_COUNT) { |
675 | sc->sc_sensor[i].state = ENVSYS_SINVALID; | | 672 | sc->sc_sensor[i].state = ENVSYS_SINVALID; |
676 | i++; | | 673 | i++; |
677 | } | | 674 | } |
678 | } | | 675 | } |
679 | | | 676 | |
680 | sc->sc_present = rv; | | 677 | sc->sc_present = rv; |
681 | microtime(&sc->sc_last); | | 678 | microtime(&sc->sc_last); |
682 | | | 679 | |
683 | cv_broadcast(&sc->sc_condvar); | | 680 | cv_broadcast(&sc->sc_condvar); |
684 | mutex_exit(&sc->sc_mutex); | | 681 | mutex_exit(&sc->sc_mutex); |
685 | } | | 682 | } |
686 | | | 683 | |
687 | /* | | 684 | /* |
688 | * acpibat_notify_handler: | | 685 | * acpibat_notify_handler: |
689 | * | | 686 | * |
690 | * Callback from ACPI interrupt handler to notify us of an event. | | 687 | * Callback from ACPI interrupt handler to notify us of an event. |
691 | */ | | 688 | */ |
692 | static void | | 689 | static void |
693 | acpibat_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) | | 690 | acpibat_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) |
694 | { | | 691 | { |
695 | static const int handler = OSL_NOTIFY_HANDLER; | | 692 | static const int handler = OSL_NOTIFY_HANDLER; |
696 | device_t dv = context; | | 693 | device_t dv = context; |
697 | | | 694 | |
698 | switch (notify) { | | 695 | switch (notify) { |
699 | | | 696 | |
700 | case ACPI_NOTIFY_BUS_CHECK: | | 697 | case ACPI_NOTIFY_BUS_CHECK: |
701 | break; | | 698 | break; |
702 | | | 699 | |
703 | case ACPI_NOTIFY_BAT_INFO: | | 700 | case ACPI_NOTIFY_BAT_INFO: |
704 | case ACPI_NOTIFY_DEVICE_CHECK: | | 701 | case ACPI_NOTIFY_DEVICE_CHECK: |
705 | (void)AcpiOsExecute(handler, acpibat_update_info, dv); | | 702 | (void)AcpiOsExecute(handler, acpibat_update_info, dv); |
706 | break; | | 703 | break; |
707 | | | 704 | |
708 | case ACPI_NOTIFY_BAT_STATUS: | | 705 | case ACPI_NOTIFY_BAT_STATUS: |
709 | (void)AcpiOsExecute(handler, acpibat_update_status, dv); | | 706 | (void)AcpiOsExecute(handler, acpibat_update_status, dv); |
710 | break; | | 707 | break; |
711 | | | 708 | |
712 | default: | | 709 | default: |
713 | aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify); | | 710 | aprint_error_dev(dv, "unknown notify: 0x%02X\n", notify); |
714 | } | | 711 | } |
715 | } | | 712 | } |
716 | | | 713 | |
717 | static void | | 714 | static void |
718 | acpibat_init_envsys(device_t dv) | | 715 | acpibat_init_envsys(device_t dv) |
719 | { | | 716 | { |
720 | struct acpibat_softc *sc = device_private(dv); | | 717 | struct acpibat_softc *sc = device_private(dv); |
721 | int i; | | 718 | int i; |
722 | | | 719 | |
723 | #define INITDATA(index, unit, string) \ | | 720 | #define INITDATA(index, unit, string) \ |
724 | do { \ | | 721 | do { \ |
725 | sc->sc_sensor[index].state = ENVSYS_SVALID; \ | | 722 | sc->sc_sensor[index].state = ENVSYS_SVALID; \ |
726 | sc->sc_sensor[index].units = unit; \ | | 723 | sc->sc_sensor[index].units = unit; \ |
727 | (void)strlcpy(sc->sc_sensor[index].desc, string, \ | | 724 | (void)strlcpy(sc->sc_sensor[index].desc, string, \ |
728 | sizeof(sc->sc_sensor[index].desc)); \ | | 725 | sizeof(sc->sc_sensor[index].desc)); \ |
729 | } while (/* CONSTCOND */ 0) | | 726 | } while (/* CONSTCOND */ 0) |
730 | | | 727 | |
731 | INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); | | 728 | INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present"); |
732 | INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); | | 729 | INITDATA(ACPIBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); |
733 | INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); | | 730 | INITDATA(ACPIBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); |
734 | INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); | | 731 | INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); |
735 | INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); | | 732 | INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); |
736 | INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); | | 733 | INITDATA(ACPIBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate"); |
737 | INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); | | 734 | INITDATA(ACPIBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); |
738 | INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); | | 735 | INITDATA(ACPIBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge"); |
739 | INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); | | 736 | INITDATA(ACPIBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); |
740 | INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); | | 737 | INITDATA(ACPIBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); |
741 | | | 738 | |
742 | #undef INITDATA | | 739 | #undef INITDATA |
743 | | | 740 | |
744 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = | | 741 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].value_cur = |
745 | ENVSYS_BATTERY_CAPACITY_NORMAL; | | 742 | ENVSYS_BATTERY_CAPACITY_NORMAL; |
746 | | | 743 | |
747 | sc->sc_sensor[ACPIBAT_CAPACITY].flags |= | | 744 | sc->sc_sensor[ACPIBAT_CAPACITY].flags |= |
748 | ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; | | 745 | ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; |
749 | | | 746 | |
750 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; | | 747 | sc->sc_sensor[ACPIBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED; |
751 | | | 748 | |
752 | /* Disable userland monitoring on these sensors. */ | | 749 | /* Disable userland monitoring on these sensors. */ |
753 | sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; | | 750 | sc->sc_sensor[ACPIBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; |
754 | sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; | | 751 | sc->sc_sensor[ACPIBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; |
755 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; | | 752 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; |
756 | sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; | | 753 | sc->sc_sensor[ACPIBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; |
757 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; | | 754 | sc->sc_sensor[ACPIBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; |
758 | sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; | | 755 | sc->sc_sensor[ACPIBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; |
759 | | | 756 | |
760 | /* Attach rnd(9) to the (dis)charge rates. */ | | 757 | /* Attach rnd(9) to the (dis)charge rates. */ |
761 | sc->sc_sensor[ACPIBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; | | 758 | sc->sc_sensor[ACPIBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; |
762 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; | | 759 | sc->sc_sensor[ACPIBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; |
763 | | | 760 | |
764 | sc->sc_sme = sysmon_envsys_create(); | | 761 | sc->sc_sme = sysmon_envsys_create(); |
765 | | | 762 | |
766 | for (i = 0; i < ACPIBAT_COUNT; i++) { | | 763 | for (i = 0; i < ACPIBAT_COUNT; i++) { |
767 | | | 764 | |
768 | if (sysmon_envsys_sensor_attach(sc->sc_sme, | | 765 | if (sysmon_envsys_sensor_attach(sc->sc_sme, |
769 | &sc->sc_sensor[i])) | | 766 | &sc->sc_sensor[i])) |
770 | goto fail; | | 767 | goto fail; |
771 | } | | 768 | } |
772 | | | 769 | |
773 | sc->sc_sme->sme_name = device_xname(dv); | | 770 | sc->sc_sme->sme_name = device_xname(dv); |
774 | sc->sc_sme->sme_cookie = dv; | | 771 | sc->sc_sme->sme_cookie = dv; |
775 | sc->sc_sme->sme_refresh = acpibat_refresh; | | 772 | sc->sc_sme->sme_refresh = acpibat_refresh; |
776 | sc->sc_sme->sme_class = SME_CLASS_BATTERY; | | 773 | sc->sc_sme->sme_class = SME_CLASS_BATTERY; |
777 | sc->sc_sme->sme_flags = SME_POLL_ONLY | SME_INIT_REFRESH; | | 774 | sc->sc_sme->sme_flags = SME_POLL_ONLY | SME_INIT_REFRESH; |
778 | sc->sc_sme->sme_get_limits = acpibat_get_limits; | | 775 | sc->sc_sme->sme_get_limits = acpibat_get_limits; |
779 | | | 776 | |
780 | acpibat_update_info(dv); | | 777 | acpibat_update_info(dv); |
781 | acpibat_update_status(dv); | | 778 | acpibat_update_status(dv); |
782 | | | 779 | |
783 | if (sysmon_envsys_register(sc->sc_sme)) | | 780 | if (sysmon_envsys_register(sc->sc_sme)) |
784 | goto fail; | | 781 | goto fail; |
785 | | | 782 | |
786 | return; | | 783 | return; |
787 | | | 784 | |
788 | fail: | | 785 | fail: |
789 | aprint_error_dev(dv, "failed to initialize sysmon\n"); | | 786 | aprint_error_dev(dv, "failed to initialize sysmon\n"); |
790 | | | 787 | |
791 | sysmon_envsys_destroy(sc->sc_sme); | | 788 | sysmon_envsys_destroy(sc->sc_sme); |
792 | kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); | | 789 | kmem_free(sc->sc_sensor, ACPIBAT_COUNT * sizeof(*sc->sc_sensor)); |
793 | | | 790 | |
794 | sc->sc_sme = NULL; | | 791 | sc->sc_sme = NULL; |
795 | sc->sc_sensor = NULL; | | 792 | sc->sc_sensor = NULL; |
796 | } | | 793 | } |
797 | | | 794 | |
798 | static void | | 795 | static void |
799 | acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 796 | acpibat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
800 | { | | 797 | { |
801 | device_t self = sme->sme_cookie; | | 798 | device_t self = sme->sme_cookie; |
802 | struct acpibat_softc *sc; | | 799 | struct acpibat_softc *sc; |
803 | struct timeval tv, tmp; | | 800 | struct timeval tv, tmp; |
804 | ACPI_STATUS rv; | | 801 | ACPI_STATUS rv; |
805 | | | 802 | |
806 | sc = device_private(self); | | 803 | sc = device_private(self); |
807 | | | 804 | |
808 | tmp.tv_sec = 10; | | 805 | tmp.tv_sec = 10; |
809 | tmp.tv_usec = 0; | | 806 | tmp.tv_usec = 0; |
810 | | | 807 | |
811 | microtime(&tv); | | 808 | microtime(&tv); |
812 | timersub(&tv, &tmp, &tv); | | 809 | timersub(&tv, &tmp, &tv); |
813 | | | 810 | |
814 | if (timercmp(&tv, &sc->sc_last, <) != 0) | | 811 | if (timercmp(&tv, &sc->sc_last, <) != 0) |
815 | return; | | 812 | return; |
816 | | | 813 | |
817 | if (mutex_tryenter(&sc->sc_mutex) == 0) | | 814 | if (mutex_tryenter(&sc->sc_mutex) == 0) |
818 | return; | | 815 | return; |
819 | | | 816 | |
820 | rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, self); | | 817 | rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, self); |
821 | | | 818 | |
822 | if (ACPI_SUCCESS(rv)) | | 819 | if (ACPI_SUCCESS(rv)) |
823 | cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); | | 820 | cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz); |
824 | | | 821 | |
825 | mutex_exit(&sc->sc_mutex); | | 822 | mutex_exit(&sc->sc_mutex); |
826 | } | | 823 | } |
827 | | | 824 | |
828 | static bool | | 825 | static bool |
829 | acpibat_resume(device_t dv, const pmf_qual_t *qual) | | 826 | acpibat_resume(device_t dv, const pmf_qual_t *qual) |
830 | { | | 827 | { |
831 | | | 828 | |
832 | (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); | | 829 | (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_info, dv); |
833 | (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); | | 830 | (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpibat_update_status, dv); |
834 | | | 831 | |
835 | return true; | | 832 | return true; |
836 | } | | 833 | } |
837 | | | 834 | |
838 | static void | | 835 | static void |
839 | acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, | | 836 | acpibat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, |
840 | sysmon_envsys_lim_t *limits, uint32_t *props) | | 837 | sysmon_envsys_lim_t *limits, uint32_t *props) |
841 | { | | 838 | { |
842 | device_t dv = sme->sme_cookie; | | 839 | device_t dv = sme->sme_cookie; |
843 | struct acpibat_softc *sc = device_private(dv); | | 840 | struct acpibat_softc *sc = device_private(dv); |
844 | | | 841 | |
845 | if (edata->sensor != ACPIBAT_CAPACITY) | | 842 | if (edata->sensor != ACPIBAT_CAPACITY) |
846 | return; | | 843 | return; |
847 | | | 844 | |
848 | limits->sel_critmin = sc->sc_lcapacity; | | 845 | limits->sel_critmin = sc->sc_lcapacity; |
849 | limits->sel_warnmin = sc->sc_wcapacity; | | 846 | limits->sel_warnmin = sc->sc_wcapacity; |
850 | | | 847 | |
851 | *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; | | 848 | *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; |
852 | } | | 849 | } |
853 | | | 850 | |
854 | MODULE(MODULE_CLASS_DRIVER, acpibat, "sysmon_envsys"); | | 851 | MODULE(MODULE_CLASS_DRIVER, acpibat, "sysmon_envsys"); |
855 | | | 852 | |
856 | #ifdef _MODULE | | 853 | #ifdef _MODULE |
857 | #include "ioconf.c" | | 854 | #include "ioconf.c" |
858 | #endif | | 855 | #endif |
859 | | | 856 | |
860 | static int | | 857 | static int |
861 | acpibat_modcmd(modcmd_t cmd, void *aux) | | 858 | acpibat_modcmd(modcmd_t cmd, void *aux) |
862 | { | | 859 | { |
863 | int rv = 0; | | 860 | int rv = 0; |
864 | | | 861 | |
865 | switch (cmd) { | | 862 | switch (cmd) { |
866 | | | 863 | |
867 | case MODULE_CMD_INIT: | | 864 | case MODULE_CMD_INIT: |
868 | | | 865 | |
869 | #ifdef _MODULE | | 866 | #ifdef _MODULE |
870 | rv = config_init_component(cfdriver_ioconf_acpibat, | | 867 | rv = config_init_component(cfdriver_ioconf_acpibat, |
871 | cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); | | 868 | cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); |
872 | #endif | | 869 | #endif |
873 | break; | | 870 | break; |
874 | | | 871 | |
875 | case MODULE_CMD_FINI: | | 872 | case MODULE_CMD_FINI: |
876 | | | 873 | |
877 | #ifdef _MODULE | | 874 | #ifdef _MODULE |
878 | rv = config_fini_component(cfdriver_ioconf_acpibat, | | 875 | rv = config_fini_component(cfdriver_ioconf_acpibat, |
879 | cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); | | 876 | cfattach_ioconf_acpibat, cfdata_ioconf_acpibat); |
880 | #endif | | 877 | #endif |
881 | break; | | 878 | break; |
882 | | | 879 | |
883 | default: | | 880 | default: |
884 | rv = ENOTTY; | | 881 | rv = ENOTTY; |
885 | } | | 882 | } |
886 | | | 883 | |
887 | return rv; | | 884 | return rv; |
888 | } | | 885 | } |