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