pbbat.c revision 1.2 1 1.2 nat /* $NetBSD: pbbat.c,v 1.2 2025/04/09 00:10:02 nat Exp $ */
2 1.1 nat
3 1.1 nat /*-
4 1.1 nat * Copyright (c) 2025 Nathanial Sloss <nathanialsloss (at) yahoo.com.au>
5 1.1 nat * All rights reserved.
6 1.1 nat *
7 1.1 nat * Redistribution and use in source and binary forms, with or without
8 1.1 nat * modification, are permitted provided that the following conditions
9 1.1 nat * are met:
10 1.1 nat * 1. Redistributions of source code must retain the above copyright
11 1.1 nat * notice, this list of conditions and the following disclaimer.
12 1.1 nat * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 nat * notice, this list of conditions and the following disclaimer in the
14 1.1 nat * documentation and/or other materials provided with the distribution.
15 1.1 nat *
16 1.1 nat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 nat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 nat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 nat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 nat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 nat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 nat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 nat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 nat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 nat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 nat * POSSIBILITY OF SUCH DAMAGE.
27 1.1 nat */
28 1.1 nat
29 1.1 nat /* Based on acpibat(4). */
30 1.1 nat
31 1.1 nat /*-
32 1.1 nat * Copyright (c) 2003 The NetBSD Foundation, Inc.
33 1.1 nat * All rights reserved.
34 1.1 nat *
35 1.1 nat * This code is derived from software contributed to The NetBSD Foundation
36 1.1 nat * by Charles M. Hannum of By Noon Software, Inc.
37 1.1 nat *
38 1.1 nat * Redistribution and use in source and binary forms, with or without
39 1.1 nat * modification, are permitted provided that the following conditions
40 1.1 nat * are met:
41 1.1 nat * 1. Redistributions of source code must retain the above copyright
42 1.1 nat * notice, this list of conditions and the following disclaimer.
43 1.1 nat * 2. Redistributions in binary form must reproduce the above copyright
44 1.1 nat * notice, this list of conditions and the following disclaimer in the
45 1.1 nat * documentation and/or other materials provided with the distribution.
46 1.1 nat *
47 1.1 nat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48 1.1 nat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49 1.1 nat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 1.1 nat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51 1.1 nat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 1.1 nat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 1.1 nat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 1.1 nat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 1.1 nat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 1.1 nat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 1.1 nat * POSSIBILITY OF SUCH DAMAGE.
58 1.1 nat */
59 1.1 nat
60 1.1 nat /*
61 1.1 nat * Copyright 2001 Bill Sommerfeld.
62 1.1 nat * All rights reserved.
63 1.1 nat *
64 1.1 nat * Redistribution and use in source and binary forms, with or without
65 1.1 nat * modification, are permitted provided that the following conditions
66 1.1 nat * are met:
67 1.1 nat * 1. Redistributions of source code must retain the above copyright
68 1.1 nat * notice, this list of conditions and the following disclaimer.
69 1.1 nat * 2. Redistributions in binary form must reproduce the above copyright
70 1.1 nat * notice, this list of conditions and the following disclaimer in the
71 1.1 nat * documentation and/or other materials provided with the distribution.
72 1.1 nat * 3. All advertising materials mentioning features or use of this software
73 1.1 nat * must display the following acknowledgement:
74 1.1 nat * This product includes software developed for the NetBSD Project by
75 1.1 nat * Wasabi Systems, Inc.
76 1.1 nat * 4. The name of Wasabi Systems, Inc. may not be used to endorse
77 1.1 nat * or promote products derived from this software without specific prior
78 1.1 nat * written permission.
79 1.1 nat *
80 1.1 nat * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
81 1.1 nat * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
82 1.1 nat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
83 1.1 nat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
84 1.1 nat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
85 1.1 nat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
86 1.1 nat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
87 1.1 nat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
88 1.1 nat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
89 1.1 nat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
90 1.1 nat * POSSIBILITY OF SUCH DAMAGE.
91 1.1 nat */
92 1.1 nat
93 1.1 nat /* AC Adaptor attachment and logic based on macppc/smartbat(4). */
94 1.1 nat
95 1.1 nat /*-
96 1.1 nat * Copyright (c) 2007 Michael Lorenz
97 1.1 nat * 2008 Magnus Henoch
98 1.1 nat * All rights reserved.
99 1.1 nat *
100 1.1 nat * Redistribution and use in source and binary forms, with or without
101 1.1 nat * modification, are permitted provided that the following conditions
102 1.1 nat * are met:
103 1.1 nat * 1. Redistributions of source code must retain the above copyright
104 1.1 nat * notice, this list of conditions and the following disclaimer.
105 1.1 nat * 2. Redistributions in binary form must reproduce the above copyright
106 1.1 nat * notice, this list of conditions and the following disclaimer in the
107 1.1 nat * documentation and/or other materials provided with the distribution.
108 1.1 nat *
109 1.1 nat * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
110 1.1 nat * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
111 1.1 nat * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
112 1.1 nat * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
113 1.1 nat * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
114 1.1 nat * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
115 1.1 nat * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
116 1.1 nat * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
117 1.1 nat * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
118 1.1 nat * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
119 1.1 nat * POSSIBILITY OF SUCH DAMAGE.
120 1.1 nat */
121 1.1 nat
122 1.1 nat #include <sys/cdefs.h>
123 1.2 nat __KERNEL_RCSID(0, "$NetBSD: pbbat.c,v 1.2 2025/04/09 00:10:02 nat Exp $");
124 1.1 nat
125 1.1 nat #include <sys/param.h>
126 1.1 nat #include <sys/device.h>
127 1.1 nat #include <sys/kmem.h>
128 1.1 nat #include <sys/types.h>
129 1.1 nat #include <sys/systm.h>
130 1.1 nat
131 1.1 nat #include <dev/sysmon/sysmonvar.h>
132 1.1 nat
133 1.1 nat #include <machine/param.h>
134 1.1 nat #include <machine/cpu.h>
135 1.1 nat
136 1.1 nat #include <mac68k/dev/pm_direct.h>
137 1.1 nat
138 1.1 nat static int pbbatmatch(device_t, cfdata_t, void *);
139 1.1 nat static void pbbatattach(device_t, device_t, void *);
140 1.1 nat
141 1.1 nat static void bat_get_pm_limits(device_t);
142 1.1 nat static uint16_t bat_get_status(device_t);
143 1.1 nat static void bat_init_envsys(device_t);
144 1.1 nat static void bat_update_status(void *);
145 1.1 nat
146 1.1 nat extern int pm_pmgrop_pm1(PMData *);
147 1.1 nat
148 1.1 nat struct pbatt_softc {
149 1.1 nat device_t sc_dev;
150 1.1 nat struct sysmon_envsys *sc_ac_sme;
151 1.1 nat envsys_data_t sc_ac_sensor[1];
152 1.1 nat struct sysmon_pswitch sc_sm_acpower;
153 1.1 nat int8_t sc_ac_state;
154 1.1 nat struct sysmon_envsys *sc_bat_sme;
155 1.1 nat envsys_data_t *sc_bat_sensor;
156 1.1 nat struct timeval sc_last;
157 1.1 nat kmutex_t sc_mutex;
158 1.1 nat int32_t sc_dcapacity;
159 1.1 nat int32_t sc_dvoltage;
160 1.1 nat int32_t sc_disrate;
161 1.1 nat int32_t sc_chargerate;
162 1.1 nat int32_t sc_empty;
163 1.1 nat int32_t sc_lcapacity;
164 1.1 nat int32_t sc_wcapacity;
165 1.1 nat int sc_present;
166 1.1 nat };
167 1.1 nat
168 1.1 nat #define PBBAT_AC_PRESENT 0
169 1.1 nat
170 1.1 nat /* AC Adaptor states */
171 1.1 nat #define PBBAT_AC_UNKNOWN -1
172 1.1 nat #define PBBAT_AC_DISCONNECTED 0
173 1.1 nat #define PBBAT_AC_CONNECTED 1
174 1.1 nat
175 1.1 nat enum {
176 1.1 nat PBBAT_PRESENT = 0,
177 1.1 nat PBBAT_DVOLTAGE = 1,
178 1.1 nat PBBAT_VOLTAGE = 2,
179 1.1 nat PBBAT_DCAPACITY = 3,
180 1.1 nat PBBAT_LFCCAPACITY = 4,
181 1.1 nat PBBAT_CAPACITY = 5,
182 1.1 nat PBBAT_CHARGERATE = 6,
183 1.1 nat PBBAT_DISCHARGERATE = 7,
184 1.1 nat PBBAT_CHARGING = 8,
185 1.1 nat PBBAT_CHARGE_STATE = 9,
186 1.1 nat PBBAT_COUNT = 10
187 1.1 nat };
188 1.1 nat
189 1.1 nat /* Driver definition */
190 1.1 nat CFATTACH_DECL_NEW(pbbat, sizeof(struct pbatt_softc),
191 1.1 nat pbbatmatch, pbbatattach, NULL, NULL);
192 1.1 nat
193 1.1 nat /* Battery voltage definitions (mV) */
194 1.1 nat #define VOLTS_DESIGN 6000
195 1.1 nat #define WATTS_DESIGN 60000 /* mW */
196 1.1 nat #define VOLTS_CHARGING 6600
197 1.1 nat #define VOLTS_NOBATT 7700
198 1.1 nat
199 1.1 nat #define VOLTS_MULTI 35 /* PM value multiplier. */
200 1.1 nat #define LIMIT_SCALE (100 * 100 / (VOLTS_DESIGN / 1000))
201 1.1 nat
202 1.1 nat #define PM_BATT_VOLTS 0x68 /* 0x69 is a duplicate. */
203 1.1 nat #define PM_BATT_LIMITS 0x6a
204 1.1 nat
205 1.1 nat static int
206 1.1 nat pbbatmatch(device_t parent, cfdata_t cf, void *aux)
207 1.1 nat {
208 1.1 nat switch (mac68k_machine.machineid) {
209 1.1 nat case MACH_MACPB140:
210 1.1 nat case MACH_MACPB145:
211 1.1 nat case MACH_MACPB160:
212 1.1 nat case MACH_MACPB165:
213 1.1 nat case MACH_MACPB165C:
214 1.1 nat case MACH_MACPB170:
215 1.1 nat case MACH_MACPB180:
216 1.1 nat case MACH_MACPB180C:
217 1.1 nat return 1;
218 1.1 nat break;
219 1.1 nat default:
220 1.1 nat return 0;
221 1.1 nat }
222 1.1 nat
223 1.1 nat return 0;
224 1.1 nat }
225 1.1 nat
226 1.1 nat static void
227 1.1 nat pbbatattach(device_t parent, device_t self, void *aux)
228 1.1 nat {
229 1.1 nat struct pbatt_softc *sc = device_private(self);
230 1.1 nat
231 1.1 nat aprint_naive(": PowerBook Battery\n");
232 1.1 nat aprint_normal(": PowerBook Battery\n");
233 1.1 nat
234 1.1 nat mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
235 1.1 nat sc->sc_bat_sensor = kmem_zalloc(PBBAT_COUNT *
236 1.1 nat sizeof(*sc->sc_bat_sensor), KM_SLEEP);
237 1.1 nat
238 1.1 nat memset(&sc->sc_sm_acpower, 0, sizeof(struct sysmon_pswitch));
239 1.1 nat sc->sc_ac_state = PBBAT_AC_UNKNOWN;
240 1.1 nat sc->sc_sm_acpower.smpsw_name = "AC Power";
241 1.1 nat sc->sc_sm_acpower.smpsw_type = PSWITCH_TYPE_ACADAPTER;
242 1.1 nat if (sysmon_pswitch_register(&sc->sc_sm_acpower) != 0)
243 1.1 nat printf("%s: unable to register AC power status with sysmon\n",
244 1.1 nat device_xname(sc->sc_dev));
245 1.1 nat
246 1.1 nat config_interrupts(self, bat_init_envsys);
247 1.1 nat }
248 1.1 nat
249 1.1 nat static void
250 1.1 nat bat_get_pm_limits(device_t self)
251 1.1 nat {
252 1.1 nat int s;
253 1.1 nat int rval;
254 1.1 nat PMData pmdata;
255 1.1 nat struct pbatt_softc *sc = device_private(self);
256 1.1 nat
257 1.1 nat s = splhigh();
258 1.1 nat
259 1.1 nat pmdata.command = PM_BATT_LIMITS;
260 1.1 nat pmdata.num_data = 0;
261 1.1 nat pmdata.data[0] = pmdata.data[1] = 0;
262 1.1 nat pmdata.s_buf = pmdata.data;
263 1.1 nat pmdata.r_buf = pmdata.data;
264 1.1 nat rval = pm_pmgrop_pm1(&pmdata);
265 1.1 nat if (rval != 0) {
266 1.1 nat #ifdef ADB_DEBUG
267 1.1 nat if (adb_debug)
268 1.1 nat printf("pm: PM is not ready. error code=%08x\n", rval);
269 1.1 nat #endif
270 1.1 nat splx(s);
271 1.1 nat return;
272 1.1 nat }
273 1.1 nat
274 1.1 nat splx(s);
275 1.1 nat
276 1.1 nat sc->sc_empty = (pmdata.data[1] & 0xff) * VOLTS_MULTI;
277 1.1 nat sc->sc_lcapacity = (pmdata.data[0] & 0xff) * VOLTS_MULTI;
278 1.1 nat sc->sc_wcapacity = sc->sc_lcapacity * 12 / 10;
279 1.1 nat
280 1.1 nat return;
281 1.1 nat }
282 1.1 nat
283 1.1 nat static uint16_t
284 1.1 nat bat_get_voltage(void)
285 1.1 nat {
286 1.1 nat int s;
287 1.1 nat int rval;
288 1.1 nat PMData pmdata;
289 1.1 nat
290 1.1 nat s = splhigh();
291 1.1 nat
292 1.1 nat pmdata.command = PM_BATT_VOLTS;
293 1.1 nat pmdata.num_data = 0;
294 1.1 nat pmdata.data[0] = pmdata.data[1] = 0;
295 1.1 nat pmdata.s_buf = pmdata.data;
296 1.1 nat pmdata.r_buf = pmdata.data;
297 1.1 nat rval = pm_pmgrop_pm1(&pmdata);
298 1.1 nat if (rval != 0) {
299 1.1 nat #ifdef ADB_DEBUG
300 1.1 nat if (adb_debug)
301 1.1 nat printf("pm: PM is not ready. error code=%08x\n", rval);
302 1.1 nat #endif
303 1.1 nat splx(s);
304 1.1 nat return 0;
305 1.1 nat }
306 1.1 nat
307 1.1 nat splx(s);
308 1.1 nat
309 1.1 nat return (pmdata.data[1] & 0xff) * VOLTS_MULTI;
310 1.1 nat }
311 1.1 nat
312 1.1 nat static void
313 1.1 nat bat_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
314 1.1 nat {
315 1.1 nat device_t self = sme->sme_cookie;
316 1.1 nat struct pbatt_softc *sc = device_private(self);
317 1.1 nat struct timeval tv, tmp;
318 1.1 nat
319 1.1 nat tmp.tv_sec = 10;
320 1.1 nat tmp.tv_usec = 0;
321 1.1 nat
322 1.1 nat microuptime(&tv);
323 1.1 nat timersub(&tv, &tmp, &tv);
324 1.1 nat if (timercmp(&tv, &sc->sc_last, <) != 0)
325 1.1 nat return;
326 1.1 nat
327 1.1 nat bat_update_status(self);
328 1.1 nat }
329 1.1 nat
330 1.1 nat static void
331 1.1 nat bat_refresh_ac(struct sysmon_envsys *sme, envsys_data_t *edata)
332 1.1 nat {
333 1.1 nat struct pbatt_softc *sc = sme->sme_cookie;
334 1.1 nat int which = edata->sensor;
335 1.1 nat
336 1.1 nat mutex_enter(&sc->sc_mutex);
337 1.1 nat switch (which) {
338 1.1 nat case PBBAT_AC_PRESENT:
339 1.1 nat edata->value_cur =
340 1.1 nat (sc->sc_ac_state == PBBAT_AC_CONNECTED ? 1 : 0);
341 1.1 nat edata->state = ENVSYS_SVALID;
342 1.1 nat break;
343 1.1 nat default:
344 1.1 nat edata->value_cur = 0;
345 1.1 nat edata->state = ENVSYS_SINVALID;
346 1.1 nat }
347 1.1 nat mutex_exit(&sc->sc_mutex);
348 1.1 nat }
349 1.1 nat
350 1.1 nat static void
351 1.1 nat bat_get_info(device_t dv)
352 1.1 nat {
353 1.1 nat struct pbatt_softc *sc = device_private(dv);
354 1.1 nat int capunit;
355 1.1 nat
356 1.1 nat capunit = ENVSYS_SWATTHOUR;
357 1.1 nat
358 1.1 nat sc->sc_bat_sensor[PBBAT_DCAPACITY].units = capunit;
359 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].units = capunit;
360 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].units = capunit;
361 1.1 nat sc->sc_bat_sensor[PBBAT_LFCCAPACITY].units = capunit;
362 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].units = capunit;
363 1.1 nat
364 1.1 nat /* Design capacity. */
365 1.1 nat
366 1.1 nat /*
367 1.1 nat * This is a guesstimate - repacked battery runs at 10 Watts/h for an
368 1.1 nat * 1 hour.
369 1.1 nat */
370 1.1 nat
371 1.1 nat sc->sc_bat_sensor[PBBAT_DCAPACITY].value_cur = WATTS_DESIGN * 1000;
372 1.1 nat sc->sc_bat_sensor[PBBAT_DCAPACITY].state = ENVSYS_SVALID;
373 1.1 nat
374 1.1 nat /* Design voltage. */
375 1.1 nat sc->sc_bat_sensor[PBBAT_DVOLTAGE].value_cur = VOLTS_DESIGN * 1000;
376 1.1 nat sc->sc_bat_sensor[PBBAT_DVOLTAGE].state = ENVSYS_SVALID;
377 1.1 nat
378 1.1 nat sc->sc_bat_sensor[PBBAT_LFCCAPACITY].state = ENVSYS_SINVALID;
379 1.1 nat
380 1.1 nat bat_get_pm_limits(dv);
381 1.1 nat
382 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].value_max = 100 * 1000 * 1000;
383 1.1 nat }
384 1.1 nat
385 1.1 nat static void
386 1.1 nat bat_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
387 1.1 nat sysmon_envsys_lim_t *limits, uint32_t *props)
388 1.1 nat {
389 1.1 nat device_t self = sme->sme_cookie;
390 1.1 nat struct pbatt_softc *sc = device_private(self);
391 1.1 nat
392 1.1 nat if (edata->sensor != PBBAT_CAPACITY)
393 1.1 nat return;
394 1.1 nat
395 1.1 nat limits->sel_critmin = sc->sc_lcapacity * LIMIT_SCALE;
396 1.1 nat limits->sel_warnmin = sc->sc_wcapacity * LIMIT_SCALE;
397 1.1 nat
398 1.1 nat *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS;
399 1.1 nat }
400 1.1 nat
401 1.1 nat static void
402 1.1 nat bat_update_status(void *arg)
403 1.1 nat {
404 1.1 nat device_t dv = arg;
405 1.1 nat struct pbatt_softc *sc = device_private(dv);
406 1.1 nat int i;
407 1.1 nat uint16_t val;
408 1.1 nat
409 1.1 nat mutex_enter(&sc->sc_mutex);
410 1.1 nat
411 1.1 nat val = bat_get_status(dv);
412 1.1 nat if (val != 0) {
413 1.1 nat if (sc->sc_present == 0)
414 1.1 nat bat_get_info(dv);
415 1.1 nat } else {
416 1.1 nat i = PBBAT_DVOLTAGE;
417 1.1 nat while (i < PBBAT_COUNT) {
418 1.1 nat sc->sc_bat_sensor[i].state = ENVSYS_SINVALID;
419 1.1 nat i++;
420 1.1 nat }
421 1.1 nat }
422 1.1 nat
423 1.1 nat sc->sc_present = (val >= VOLTS_NOBATT ? 0 : 1);
424 1.1 nat
425 1.1 nat microuptime(&sc->sc_last);
426 1.1 nat
427 1.1 nat mutex_exit(&sc->sc_mutex);
428 1.1 nat }
429 1.1 nat
430 1.1 nat static void
431 1.1 nat bat_init_envsys(device_t dv)
432 1.1 nat {
433 1.1 nat struct pbatt_softc *sc = device_private(dv);
434 1.1 nat int i;
435 1.1 nat
436 1.1 nat #define INITDATA(index, unit, string) \
437 1.1 nat sc->sc_ac_sensor[index].units = unit; \
438 1.1 nat sc->sc_ac_sensor[index].state = ENVSYS_SINVALID; \
439 1.1 nat snprintf(sc->sc_ac_sensor[index].desc, \
440 1.1 nat sizeof(sc->sc_ac_sensor[index].desc), "%s", string);
441 1.1 nat
442 1.1 nat INITDATA(PBBAT_AC_PRESENT, ENVSYS_INDICATOR, "connected");
443 1.1 nat #undef INITDATA
444 1.1 nat
445 1.1 nat sc->sc_ac_sme = sysmon_envsys_create();
446 1.1 nat
447 1.1 nat if (sysmon_envsys_sensor_attach(sc->sc_ac_sme, &sc->sc_ac_sensor[0])) {
448 1.1 nat sysmon_envsys_destroy(sc->sc_ac_sme);
449 1.1 nat return;
450 1.1 nat }
451 1.1 nat
452 1.1 nat sc->sc_ac_sme->sme_name = "AC Adaptor";
453 1.1 nat sc->sc_ac_sme->sme_cookie = sc;
454 1.1 nat sc->sc_ac_sme->sme_refresh = bat_refresh_ac;
455 1.1 nat sc->sc_ac_sme->sme_class = SME_CLASS_ACADAPTER;
456 1.1 nat
457 1.1 nat if (sysmon_envsys_register(sc->sc_ac_sme)) {
458 1.1 nat aprint_error("%s: unable to register AC with sysmon\n",
459 1.1 nat device_xname(sc->sc_dev));
460 1.1 nat sysmon_envsys_destroy(sc->sc_ac_sme);
461 1.1 nat }
462 1.1 nat
463 1.1 nat #define INITDATA(index, unit, string) \
464 1.1 nat do { \
465 1.1 nat sc->sc_bat_sensor[index].state = ENVSYS_SVALID; \
466 1.1 nat sc->sc_bat_sensor[index].units = unit; \
467 1.1 nat (void)strlcpy(sc->sc_bat_sensor[index].desc, string, \
468 1.1 nat sizeof(sc->sc_bat_sensor[index].desc)); \
469 1.1 nat } while (/* CONSTCOND */ 0)
470 1.1 nat
471 1.1 nat INITDATA(PBBAT_PRESENT, ENVSYS_INDICATOR, "present");
472 1.1 nat INITDATA(PBBAT_DCAPACITY, ENVSYS_SWATTHOUR, "design cap");
473 1.1 nat INITDATA(PBBAT_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap");
474 1.1 nat INITDATA(PBBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
475 1.1 nat INITDATA(PBBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
476 1.1 nat INITDATA(PBBAT_CAPACITY, ENVSYS_SWATTHOUR, "charge");
477 1.1 nat INITDATA(PBBAT_CHARGERATE, ENVSYS_SWATTS, "charge rate");
478 1.1 nat INITDATA(PBBAT_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate");
479 1.1 nat INITDATA(PBBAT_CHARGING, ENVSYS_BATTERY_CHARGE, "charging");
480 1.1 nat INITDATA(PBBAT_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state");
481 1.1 nat
482 1.1 nat #undef INITDATA
483 1.1 nat
484 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur =
485 1.1 nat ENVSYS_BATTERY_CAPACITY_NORMAL;
486 1.1 nat
487 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].flags |=
488 1.1 nat ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS;
489 1.1 nat
490 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].flags |= ENVSYS_FMONSTCHANGED;
491 1.1 nat
492 1.1 nat /* Disable userland monitoring on these sensors. */
493 1.1 nat sc->sc_bat_sensor[PBBAT_VOLTAGE].flags = ENVSYS_FMONNOTSUPP;
494 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].flags = ENVSYS_FMONNOTSUPP;
495 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP;
496 1.1 nat sc->sc_bat_sensor[PBBAT_DCAPACITY].flags = ENVSYS_FMONNOTSUPP;
497 1.1 nat sc->sc_bat_sensor[PBBAT_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP;
498 1.1 nat sc->sc_bat_sensor[PBBAT_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP;
499 1.1 nat
500 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY;
501 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY;
502 1.1 nat
503 1.1 nat sc->sc_bat_sme = sysmon_envsys_create();
504 1.1 nat
505 1.1 nat for (i = 0; i < PBBAT_COUNT; i++) {
506 1.1 nat if (sysmon_envsys_sensor_attach(sc->sc_bat_sme,
507 1.1 nat &sc->sc_bat_sensor[i]))
508 1.1 nat goto fail;
509 1.1 nat }
510 1.1 nat
511 1.1 nat sc->sc_bat_sme->sme_name = device_xname(dv);
512 1.1 nat sc->sc_bat_sme->sme_cookie = dv;
513 1.1 nat sc->sc_bat_sme->sme_refresh = bat_refresh;
514 1.1 nat sc->sc_bat_sme->sme_class = SME_CLASS_BATTERY;
515 1.1 nat sc->sc_bat_sme->sme_flags = SME_POLL_ONLY;
516 1.1 nat sc->sc_bat_sme->sme_get_limits = bat_get_limits;
517 1.1 nat
518 1.1 nat if (sysmon_envsys_register(sc->sc_bat_sme))
519 1.1 nat goto fail;
520 1.1 nat
521 1.1 nat bat_get_pm_limits(dv);
522 1.1 nat bat_update_status(dv);
523 1.1 nat
524 1.1 nat return;
525 1.1 nat fail:
526 1.1 nat aprint_error("failed to initialize sysmon\n");
527 1.1 nat
528 1.1 nat sysmon_envsys_destroy(sc->sc_bat_sme);
529 1.1 nat kmem_free(sc->sc_bat_sensor, PBBAT_COUNT * sizeof(*sc->sc_bat_sensor));
530 1.1 nat
531 1.1 nat sc->sc_bat_sme = NULL;
532 1.1 nat sc->sc_bat_sensor = NULL;
533 1.1 nat }
534 1.1 nat
535 1.1 nat static uint16_t
536 1.1 nat bat_get_status(device_t dv)
537 1.1 nat {
538 1.1 nat struct pbatt_softc *sc = device_private(dv);
539 1.1 nat uint16_t val;
540 1.1 nat
541 1.1 nat val = bat_get_voltage();
542 1.1 nat
543 1.1 nat sc->sc_bat_sensor[PBBAT_PRESENT].state = ENVSYS_SVALID;
544 1.1 nat sc->sc_bat_sensor[PBBAT_PRESENT].value_cur = 1;
545 1.1 nat
546 1.1 nat if (val > VOLTS_NOBATT) {
547 1.1 nat sc->sc_bat_sensor[PBBAT_PRESENT].value_cur = 0;
548 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID;
549 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0;
550 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SINVALID;
551 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
552 1.1 nat if (sc->sc_ac_state != PBBAT_AC_CONNECTED) {
553 1.1 nat sysmon_pswitch_event(&sc->sc_sm_acpower,
554 1.1 nat PSWITCH_EVENT_PRESSED);
555 1.1 nat }
556 1.1 nat sc->sc_ac_state = PBBAT_AC_CONNECTED;
557 1.1 nat } else if (val > VOLTS_CHARGING) {
558 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID;
559 1.2 nat if (sc->sc_chargerate)
560 1.2 nat sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 1;
561 1.2 nat else
562 1.2 nat sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0;
563 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SVALID;
564 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].value_cur =
565 1.1 nat sc->sc_chargerate;
566 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SINVALID;
567 1.1 nat if (sc->sc_ac_state != PBBAT_AC_CONNECTED) {
568 1.1 nat sysmon_pswitch_event(&sc->sc_sm_acpower,
569 1.1 nat PSWITCH_EVENT_PRESSED);
570 1.1 nat }
571 1.1 nat sc->sc_ac_state = PBBAT_AC_CONNECTED;
572 1.1 nat } else {
573 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGING].value_cur = 0;
574 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGING].state = ENVSYS_SVALID;
575 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGERATE].state = ENVSYS_SINVALID;
576 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].state = ENVSYS_SVALID;
577 1.1 nat sc->sc_bat_sensor[PBBAT_DISCHARGERATE].value_cur =
578 1.1 nat sc->sc_disrate;
579 1.1 nat if (sc->sc_ac_state != PBBAT_AC_DISCONNECTED) {
580 1.1 nat sysmon_pswitch_event(&sc->sc_sm_acpower,
581 1.1 nat PSWITCH_EVENT_RELEASED);
582 1.1 nat }
583 1.1 nat sc->sc_ac_state = PBBAT_AC_DISCONNECTED;
584 1.1 nat }
585 1.1 nat
586 1.1 nat /* Remaining capacity. */
587 1.1 nat sc->sc_chargerate = sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur;
588 1.1 nat sc->sc_disrate = sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur;
589 1.1 nat
590 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur =
591 1.1 nat (val - sc->sc_empty) * 10 * LIMIT_SCALE;
592 1.1 nat
593 1.1 nat sc->sc_chargerate =
594 1.1 nat (sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur - sc->sc_chargerate) * 10;
595 1.1 nat sc->sc_disrate =
596 1.1 nat (sc->sc_disrate - sc->sc_bat_sensor[PBBAT_CAPACITY].value_cur) * 10;
597 1.1 nat
598 1.1 nat /* Battery voltage. */
599 1.1 nat sc->sc_bat_sensor[PBBAT_VOLTAGE].value_cur = val * 1000;
600 1.1 nat sc->sc_bat_sensor[PBBAT_VOLTAGE].state =
601 1.1 nat (val >= VOLTS_NOBATT ? ENVSYS_SINVALID : ENVSYS_SVALID);
602 1.1 nat
603 1.1 nat if (val < sc->sc_lcapacity) {
604 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].state = ENVSYS_SCRITUNDER;
605 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur =
606 1.1 nat ENVSYS_BATTERY_CAPACITY_CRITICAL;
607 1.1 nat } else if (val < sc->sc_wcapacity) {
608 1.1 nat sc->sc_bat_sensor[PBBAT_CAPACITY].state = ENVSYS_SWARNUNDER;
609 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur =
610 1.1 nat ENVSYS_BATTERY_CAPACITY_WARNING;
611 1.1 nat } else {
612 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].value_cur =
613 1.1 nat ENVSYS_BATTERY_CAPACITY_NORMAL;
614 1.1 nat }
615 1.1 nat
616 1.1 nat sc->sc_bat_sensor[PBBAT_CHARGE_STATE].state = ENVSYS_SVALID;
617 1.1 nat
618 1.1 nat return val;
619 1.1 nat }
620