Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpica/acpi_battery.c
39507 views
1
/*-
2
* Copyright (c) 2005 Nate Lawson
3
* Copyright (c) 2000 Mitsuru IWASAKI <[email protected]>
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/cdefs.h>
29
#include "opt_acpi.h"
30
#include <sys/param.h>
31
#include <sys/kernel.h>
32
#include <sys/malloc.h>
33
#include <sys/bus.h>
34
#include <sys/ioccom.h>
35
#include <sys/sysctl.h>
36
37
#include <contrib/dev/acpica/include/acpi.h>
38
39
#include <dev/acpica/acpivar.h>
40
#include <dev/acpica/acpiio.h>
41
42
/* Default seconds before re-sampling the battery state. */
43
#define ACPI_BATTERY_INFO_EXPIRE 5
44
45
static int acpi_batteries_initialized;
46
static int acpi_battery_info_expire = ACPI_BATTERY_INFO_EXPIRE;
47
static struct acpi_battinfo acpi_battery_battinfo;
48
static struct sysctl_ctx_list acpi_battery_sysctl_ctx;
49
static struct sysctl_oid *acpi_battery_sysctl_tree;
50
51
ACPI_SERIAL_DECL(battery, "ACPI generic battery");
52
53
static void acpi_reset_battinfo(struct acpi_battinfo *info);
54
static void acpi_battery_clean_str(char *str, int len);
55
static device_t acpi_battery_find_dev(u_int logical_unit);
56
static int acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg);
57
static int acpi_battery_sysctl(SYSCTL_HANDLER_ARGS);
58
static int acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS);
59
static int acpi_battery_init(void);
60
61
int
62
acpi_battery_register(device_t dev)
63
{
64
int error;
65
66
ACPI_SERIAL_BEGIN(battery);
67
error = acpi_battery_init();
68
ACPI_SERIAL_END(battery);
69
70
return (error);
71
}
72
73
int
74
acpi_battery_remove(device_t dev)
75
{
76
77
return (0);
78
}
79
80
int
81
acpi_battery_get_units(void)
82
{
83
devclass_t batt_dc;
84
85
batt_dc = devclass_find("battery");
86
if (batt_dc == NULL)
87
return (0);
88
return (devclass_get_count(batt_dc));
89
}
90
91
int
92
acpi_battery_get_info_expire(void)
93
{
94
95
return (acpi_battery_info_expire);
96
}
97
98
/* Check _BST results for validity. */
99
int
100
acpi_battery_bst_valid(struct acpi_bst *bst)
101
{
102
103
return (bst->state != ACPI_BATT_STAT_NOT_PRESENT &&
104
bst->cap != ACPI_BATT_UNKNOWN && bst->volt != ACPI_BATT_UNKNOWN);
105
}
106
107
/* Check _BI[FX] results for validity. */
108
int
109
acpi_battery_bix_valid(struct acpi_bix *bix)
110
{
111
112
return (bix->lfcap != 0);
113
}
114
115
/* Get info about one or all batteries. */
116
int
117
acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *battinfo)
118
{
119
int batt_stat, devcount, dev_idx, error, i;
120
int total_cap, total_lfcap, total_min, valid_rate, valid_units;
121
devclass_t batt_dc;
122
device_t batt_dev;
123
struct acpi_bst *bst;
124
struct acpi_bix *bix;
125
struct acpi_battinfo *bi;
126
127
/*
128
* Get the battery devclass and max unit for battery devices. If there
129
* are none or error, return immediately.
130
*/
131
batt_dc = devclass_find("battery");
132
if (batt_dc == NULL)
133
return (ENXIO);
134
devcount = devclass_get_maxunit(batt_dc);
135
if (devcount == 0)
136
return (ENXIO);
137
138
/*
139
* Allocate storage for all _BST data, their derived battinfo data,
140
* and the current battery's _BIX (or _BIF) data.
141
*/
142
bst = malloc(devcount * sizeof(*bst), M_TEMP, M_WAITOK | M_ZERO);
143
bi = malloc(devcount * sizeof(*bi), M_TEMP, M_WAITOK | M_ZERO);
144
bix = malloc(sizeof(*bix), M_TEMP, M_WAITOK | M_ZERO);
145
146
/*
147
* Pass 1: for each battery that is present and valid, get its status,
148
* calculate percent capacity remaining, and sum all the current
149
* discharge rates.
150
*/
151
dev_idx = -1;
152
batt_stat = valid_rate = valid_units = 0;
153
total_cap = total_lfcap = 0;
154
for (i = 0; i < devcount; i++) {
155
/* Default info for every battery is "not present". */
156
acpi_reset_battinfo(&bi[i]);
157
158
/*
159
* Find the device. Since devcount is in terms of max units, this
160
* may be a sparse array so skip devices that aren't present.
161
*/
162
batt_dev = devclass_get_device(batt_dc, i);
163
if (batt_dev == NULL)
164
continue;
165
166
/* If examining a specific battery and this is it, record its index. */
167
if (dev != NULL && dev == batt_dev)
168
dev_idx = i;
169
170
/*
171
* Be sure we can get various info from the battery.
172
*/
173
if (ACPI_BATT_GET_STATUS(batt_dev, &bst[i]) != 0 ||
174
ACPI_BATT_GET_INFO(batt_dev, bix, sizeof(*bix)) != 0)
175
continue;
176
177
/* If a battery is not installed, we sometimes get strange values. */
178
if (!acpi_battery_bst_valid(&bst[i]) ||
179
!acpi_battery_bix_valid(bix))
180
continue;
181
182
/*
183
* Record current state. If both charging and discharging are set,
184
* ignore the charging flag.
185
*/
186
valid_units++;
187
if ((bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0)
188
bst[i].state &= ~ACPI_BATT_STAT_CHARGING;
189
batt_stat |= bst[i].state;
190
bi[i].state = bst[i].state;
191
192
/*
193
* If the battery info is in terms of mA, convert to mW by
194
* multiplying by the design voltage. If the design voltage
195
* is 0 (due to some error reading the battery), skip this
196
* conversion.
197
*/
198
if (bix->units == ACPI_BIX_UNITS_MA && bix->dvol != 0 && dev == NULL) {
199
bst[i].rate = (bst[i].rate * bix->dvol) / 1000;
200
bst[i].cap = (bst[i].cap * bix->dvol) / 1000;
201
bix->lfcap = (bix->lfcap * bix->dvol) / 1000;
202
}
203
204
/*
205
* The calculation above may set bix->lfcap to zero. This was
206
* seen on a laptop with a broken battery. The result of the
207
* division was rounded to zero.
208
*/
209
if (!acpi_battery_bix_valid(bix))
210
continue;
211
212
/*
213
* Some laptops report the "design-capacity" instead of the
214
* "real-capacity" when the battery is fully charged. That breaks
215
* the above arithmetic as it needs to be 100% maximum.
216
*/
217
if (bst[i].cap > bix->lfcap)
218
bst[i].cap = bix->lfcap;
219
220
/* Calculate percent capacity remaining. */
221
bi[i].cap = (100 * bst[i].cap) / bix->lfcap;
222
223
/* If this battery is not present, don't use its capacity. */
224
if (bi[i].cap != -1) {
225
total_cap += bst[i].cap;
226
total_lfcap += bix->lfcap;
227
}
228
229
/*
230
* On systems with more than one battery, they may get used
231
* sequentially, thus bst.rate may only signify the one currently
232
* in use. For the remaining batteries, bst.rate will be zero,
233
* which makes it impossible to calculate the total remaining time.
234
* Therefore, we sum the bst.rate for batteries in the discharging
235
* state and use the sum to calculate the total remaining time.
236
*/
237
if (bst[i].rate != ACPI_BATT_UNKNOWN &&
238
(bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0)
239
valid_rate += bst[i].rate;
240
}
241
242
/* If the caller asked for a device but we didn't find it, error. */
243
if (dev != NULL && dev_idx == -1) {
244
error = ENXIO;
245
goto out;
246
}
247
248
/* Pass 2: calculate capacity and remaining time for all batteries. */
249
total_min = 0;
250
for (i = 0; i < devcount; i++) {
251
/*
252
* If any batteries are discharging, use the sum of the bst.rate
253
* values. Otherwise, we are on AC power, and there is infinite
254
* time remaining for this battery until we go offline.
255
*/
256
if (valid_rate > 0)
257
bi[i].min = (60 * bst[i].cap) / valid_rate;
258
else
259
bi[i].min = 0;
260
total_min += bi[i].min;
261
}
262
263
/*
264
* Return total battery percent and time remaining. If there are
265
* no valid batteries, report values as unknown.
266
*/
267
if (valid_units > 0) {
268
if (dev == NULL) {
269
/*
270
* Avoid division by zero if none of the batteries had valid
271
* capacity info.
272
*/
273
if (total_lfcap > 0)
274
battinfo->cap = (total_cap * 100) / total_lfcap;
275
else
276
battinfo->cap = 0;
277
battinfo->min = total_min;
278
battinfo->state = batt_stat;
279
battinfo->rate = valid_rate;
280
} else {
281
battinfo->cap = bi[dev_idx].cap;
282
battinfo->min = bi[dev_idx].min;
283
battinfo->state = bi[dev_idx].state;
284
battinfo->rate = bst[dev_idx].rate;
285
}
286
287
/*
288
* If the queried battery has no discharge rate or is charging,
289
* report that we don't know the remaining time.
290
*/
291
if (valid_rate == 0 || (battinfo->state & ACPI_BATT_STAT_CHARGING))
292
battinfo->min = -1;
293
} else
294
acpi_reset_battinfo(battinfo);
295
296
error = 0;
297
298
out:
299
free(bi, M_TEMP);
300
free(bix, M_TEMP);
301
free(bst, M_TEMP);
302
return (error);
303
}
304
305
static void
306
acpi_reset_battinfo(struct acpi_battinfo *info)
307
{
308
info->cap = -1;
309
info->min = -1;
310
info->state = ACPI_BATT_STAT_NOT_PRESENT;
311
info->rate = -1;
312
}
313
314
/* Make string printable, removing invalid chars. */
315
static void
316
acpi_battery_clean_str(char *str, int len)
317
{
318
int i;
319
320
for (i = 0; i < len && *str != '\0'; i++, str++) {
321
if (!isprint(*str))
322
*str = '?';
323
}
324
325
/* NUL-terminate the string if we reached the end. */
326
if (i == len)
327
*str = '\0';
328
}
329
330
/*
331
* The battery interface deals with devices and methods but userland
332
* expects a logical unit number. Convert a logical unit to a device_t.
333
*/
334
static device_t
335
acpi_battery_find_dev(u_int logical_unit)
336
{
337
int found_unit, i, maxunit;
338
device_t dev;
339
devclass_t batt_dc;
340
341
dev = NULL;
342
found_unit = 0;
343
batt_dc = devclass_find("battery");
344
maxunit = devclass_get_maxunit(batt_dc);
345
for (i = 0; i < maxunit; i++) {
346
dev = devclass_get_device(batt_dc, i);
347
if (dev == NULL)
348
continue;
349
if (logical_unit == found_unit)
350
break;
351
found_unit++;
352
dev = NULL;
353
}
354
355
return (dev);
356
}
357
358
static int
359
acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
360
{
361
union acpi_battery_ioctl_arg *ioctl_arg;
362
int error, unit;
363
device_t dev;
364
365
/* For commands that use the ioctl_arg struct, validate it first. */
366
error = ENXIO;
367
unit = 0;
368
dev = NULL;
369
ioctl_arg = NULL;
370
if (IOCPARM_LEN(cmd) == sizeof(union acpi_battery_ioctl_arg) ||
371
IOCPARM_LEN(cmd) == sizeof(union acpi_battery_ioctl_arg_v1)) {
372
ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
373
unit = ioctl_arg->unit;
374
if (unit != ACPI_BATTERY_ALL_UNITS)
375
dev = acpi_battery_find_dev(unit);
376
}
377
378
/*
379
* No security check required: information retrieval only. If
380
* new functions are added here, a check might be required.
381
*/
382
/* Unit check */
383
switch (cmd) {
384
case ACPIIO_BATT_GET_UNITS:
385
*(int *)addr = acpi_battery_get_units();
386
error = 0;
387
break;
388
case ACPIIO_BATT_GET_BATTINFO:
389
case ACPIIO_BATT_GET_BATTINFO_V1:
390
if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) {
391
bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo));
392
error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo);
393
}
394
break;
395
case ACPIIO_BATT_GET_BIF:
396
if (dev != NULL) {
397
bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif));
398
error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif,
399
sizeof(ioctl_arg->bif));
400
}
401
break;
402
case ACPIIO_BATT_GET_BIX:
403
if (dev != NULL) {
404
bzero(&ioctl_arg->bix, sizeof(ioctl_arg->bix));
405
error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bix,
406
sizeof(ioctl_arg->bix));
407
}
408
break;
409
case ACPIIO_BATT_GET_BST:
410
case ACPIIO_BATT_GET_BST_V1:
411
if (dev != NULL) {
412
bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst));
413
error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst);
414
}
415
break;
416
default:
417
error = EINVAL;
418
}
419
420
/* Sanitize the string members. */
421
switch (cmd) {
422
case ACPIIO_BATT_GET_BIX:
423
case ACPIIO_BATT_GET_BIF:
424
/*
425
* Remove invalid characters. Perhaps this should be done
426
* within a convenience function so all callers get the
427
* benefit.
428
*/
429
acpi_battery_clean_str(ioctl_arg->bix.model,
430
sizeof(ioctl_arg->bix.model));
431
acpi_battery_clean_str(ioctl_arg->bix.serial,
432
sizeof(ioctl_arg->bix.serial));
433
acpi_battery_clean_str(ioctl_arg->bix.type,
434
sizeof(ioctl_arg->bix.type));
435
acpi_battery_clean_str(ioctl_arg->bix.oeminfo,
436
sizeof(ioctl_arg->bix.oeminfo));
437
};
438
439
return (error);
440
}
441
442
static int
443
acpi_battery_sysctl(SYSCTL_HANDLER_ARGS)
444
{
445
int val, error;
446
447
acpi_battery_get_battinfo(NULL, &acpi_battery_battinfo);
448
val = *(u_int *)oidp->oid_arg1;
449
error = sysctl_handle_int(oidp, &val, 0, req);
450
return (error);
451
}
452
453
static int
454
acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS)
455
{
456
int count, error;
457
458
count = acpi_battery_get_units();
459
error = sysctl_handle_int(oidp, &count, 0, req);
460
return (error);
461
}
462
463
static int
464
acpi_battery_init(void)
465
{
466
struct acpi_softc *sc;
467
device_t dev;
468
int error;
469
470
ACPI_SERIAL_ASSERT(battery);
471
472
if (acpi_batteries_initialized)
473
return(0);
474
475
error = ENXIO;
476
dev = devclass_get_device(devclass_find("acpi"), 0);
477
if (dev == NULL)
478
goto out;
479
sc = device_get_softc(dev);
480
481
#define ACPI_REGISTER_IOCTL(a, b, c) do { \
482
error = acpi_register_ioctl(a, b, c); \
483
if (error) \
484
goto out; \
485
} while (0)
486
487
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl, NULL);
488
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl, NULL);
489
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BATTINFO_V1, acpi_battery_ioctl, NULL);
490
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL);
491
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BIX, acpi_battery_ioctl, NULL);
492
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL);
493
ACPI_REGISTER_IOCTL(ACPIIO_BATT_GET_BST_V1, acpi_battery_ioctl, NULL);
494
#undef ACPI_REGISTER_IOCTL
495
496
sysctl_ctx_init(&acpi_battery_sysctl_ctx);
497
acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&acpi_battery_sysctl_ctx,
498
SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "battery",
499
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "battery status and info");
500
SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
501
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
502
OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
503
&acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I",
504
"percent capacity remaining");
505
SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
506
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
507
OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
508
&acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I",
509
"remaining time in minutes");
510
SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
511
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
512
OID_AUTO, "rate", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
513
&acpi_battery_battinfo.rate, 0, acpi_battery_sysctl, "I",
514
"present rate in mW");
515
SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
516
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
517
OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
518
&acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I",
519
"current status flags");
520
SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
521
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
522
OID_AUTO, "units", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
523
NULL, 0, acpi_battery_units_sysctl, "I", "number of batteries");
524
SYSCTL_ADD_INT(&acpi_battery_sysctl_ctx,
525
SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
526
OID_AUTO, "info_expire", CTLFLAG_RW,
527
&acpi_battery_info_expire, 0,
528
"time in seconds until info is refreshed");
529
530
acpi_batteries_initialized = TRUE;
531
532
out:
533
if (error) {
534
acpi_deregister_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl);
535
acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl);
536
acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO_V1, acpi_battery_ioctl);
537
acpi_deregister_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl);
538
acpi_deregister_ioctl(ACPIIO_BATT_GET_BIX, acpi_battery_ioctl);
539
acpi_deregister_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl);
540
acpi_deregister_ioctl(ACPIIO_BATT_GET_BST_V1, acpi_battery_ioctl);
541
}
542
return (error);
543
}
544
545