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