1 /*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Clemens Zeidler, haiku@clemens-zeidler.de
7 * Alexander von Gluck, kallisti5@unixzen.com
8 */
9
10
11 #include <ACPI.h>
12 #include <condition_variable.h>
13 #include <Drivers.h>
14 #include <Errors.h>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include <kernel.h>
21
22 #include "device/power_managment.h"
23
24
25 struct battery_driver_cookie {
26 device_node* node;
27 acpi_device_module_info* acpi;
28 acpi_device acpi_cookie;
29 };
30
31
32 struct battery_device_cookie {
33 battery_driver_cookie* driver_cookie;
34 int32 stop_watching;
35 };
36
37
38 #define ACPI_BATTERY_DRIVER_NAME "drivers/power/acpi_battery/driver_v1"
39 #define ACPI_BATTERY_DEVICE_NAME "drivers/power/acpi_battery/device_v1"
40
41 /* Base Namespace devices are published to */
42 #define ACPI_BATTERY_BASENAME "power/acpi_battery/%d"
43
44 // name of pnp generator of path ids
45 #define ACPI_BATTERY_PATHID_GENERATOR "acpi_battery/path_id"
46
47 #define ACPI_NAME_BATTERY "PNP0C0A"
48
49 //#define TRACE_BATTERY
50 #ifdef TRACE_BATTERY
51 # define TRACE(x...) dprintf("acpi_battery: " x)
52 #else
53 # define TRACE(x...)
54 #endif
55 #define ERROR(x...) dprintf("acpi_battery: " x)
56
57
58 static device_manager_info *sDeviceManager;
59 static ConditionVariable sBatteryCondition;
60
61
62 inline uint32
GetUint32(acpi_object_type * pointer)63 GetUint32(acpi_object_type* pointer)
64 {
65 return (pointer->object_type == ACPI_TYPE_INTEGER)
66 ? pointer->integer.integer : UINT32_MAX;
67 }
68
69
70 inline void
GetString(char * buffer,size_t length,acpi_object_type * pointer)71 GetString(char* buffer, size_t length, acpi_object_type* pointer)
72 {
73 strlcpy(buffer, (pointer->object_type == ACPI_TYPE_STRING)
74 ? pointer->string.string : "", length);
75 }
76
77
78 status_t
ReadBatteryStatus(battery_driver_cookie * cookie,acpi_battery_info * batteryStatus)79 ReadBatteryStatus(battery_driver_cookie* cookie,
80 acpi_battery_info* batteryStatus)
81 {
82 TRACE("ReadBatteryStatus\n");
83 status_t status = B_ERROR;
84
85 acpi_data buffer;
86 buffer.pointer = NULL;
87 buffer.length = ACPI_ALLOCATE_BUFFER;
88
89 acpi_object_type* object;
90 acpi_object_type* pointer;
91
92 status = cookie->acpi->evaluate_method(cookie->acpi_cookie, "_BST", NULL,
93 &buffer);
94 if (status != B_OK)
95 goto exit;
96
97 object = (acpi_object_type*)buffer.pointer;
98 if (object->object_type != ACPI_TYPE_PACKAGE
99 || object->package.count < 4) {
100 status = B_ERROR;
101 goto exit;
102 }
103
104 pointer = object->package.objects;
105 batteryStatus->state = GetUint32(pointer++);
106 if (batteryStatus->state == UINT32_MAX)
107 batteryStatus->state = BATTERY_CRITICAL_STATE;
108 batteryStatus->current_rate = GetUint32(pointer++);
109 if (batteryStatus->state == BATTERY_DISCHARGING && batteryStatus->current_rate == 0)
110 batteryStatus->state = BATTERY_NOT_CHARGING;
111 batteryStatus->capacity = GetUint32(pointer++);
112 batteryStatus->voltage = GetUint32(pointer++);
113
114 /* If key values are all < 0, it is likely that the battery slot is empty
115 * or the battery is damaged. Set BATTERY_CRITICAL_STATE
116 */
117 if (batteryStatus->voltage == UINT32_MAX
118 && batteryStatus->current_rate == UINT32_MAX
119 && batteryStatus->capacity == UINT32_MAX) {
120 batteryStatus->state = BATTERY_CRITICAL_STATE;
121 }
122
123
124 exit:
125 free(buffer.pointer);
126 return status;
127 }
128
129
130 status_t
ReadBatteryInfo(battery_driver_cookie * cookie,acpi_extended_battery_info * batteryInfo)131 ReadBatteryInfo(battery_driver_cookie* cookie,
132 acpi_extended_battery_info* batteryInfo)
133 {
134 TRACE("ReadBatteryInfo\n");
135 acpi_data buffer;
136 buffer.pointer = NULL;
137 buffer.length = ACPI_ALLOCATE_BUFFER;
138
139 acpi_object_type* object;
140 acpi_object_type* pointer;
141
142 bool isBIF = false;
143 status_t status = cookie->acpi->evaluate_method(cookie->acpi_cookie,
144 "_BIX", NULL, &buffer);
145 if (status != B_OK) {
146 isBIF = true;
147 free(buffer.pointer);
148 buffer.pointer = NULL;
149 buffer.length = ACPI_ALLOCATE_BUFFER;
150 status = cookie->acpi->evaluate_method(cookie->acpi_cookie,
151 "_BIF", NULL, &buffer);
152 if (status != B_OK)
153 goto exit;
154 }
155
156 object = (acpi_object_type*)buffer.pointer;
157 TRACE("ReadBatteryInfo %d %u\n", object->object_type,
158 object->package.count);
159 if (object->object_type != ACPI_TYPE_PACKAGE
160 || (isBIF && object->package.count < 13)) {
161 status = B_ERROR;
162 goto exit;
163 }
164
165 pointer = object->package.objects;
166 if (isBIF) {
167 batteryInfo->revision = ACPI_BATTERY_REVISION_BIF;
168 } else {
169 batteryInfo->revision = GetUint32(pointer++);
170 TRACE("ReadBatteryInfo revision %u\n", batteryInfo->revision);
171
172 if (object->package.count < 20) {
173 status = B_ERROR;
174 goto exit;
175 }
176 }
177
178 batteryInfo->power_unit = GetUint32(pointer++);
179 batteryInfo->design_capacity = GetUint32(pointer++);
180 batteryInfo->last_full_charge = GetUint32(pointer++);
181 batteryInfo->technology = GetUint32(pointer++);
182 batteryInfo->design_voltage = GetUint32(pointer++);
183 batteryInfo->design_capacity_warning = GetUint32(pointer++);
184 batteryInfo->design_capacity_low = GetUint32(pointer++);
185
186 if (batteryInfo->revision != ACPI_BATTERY_REVISION_BIF) {
187 batteryInfo->cycles = GetUint32(pointer++);
188 batteryInfo->accuracy = GetUint32(pointer++);
189 batteryInfo->max_sampling_time = GetUint32(pointer++);
190 batteryInfo->min_sampling_time = GetUint32(pointer++);
191 batteryInfo->max_average_interval = GetUint32(pointer++);
192 batteryInfo->min_average_interval = GetUint32(pointer++);
193 }
194
195 batteryInfo->capacity_granularity_1 = GetUint32(pointer++);
196 batteryInfo->capacity_granularity_2 = GetUint32(pointer++);
197 GetString(batteryInfo->model_number, sizeof(batteryInfo->model_number),
198 pointer++);
199 GetString(batteryInfo->serial_number, sizeof(batteryInfo->serial_number),
200 pointer++);
201 GetString(batteryInfo->type, sizeof(batteryInfo->type), pointer++);
202 GetString(batteryInfo->oem_info, sizeof(batteryInfo->oem_info), pointer++);
203
204 if (batteryInfo->revision != ACPI_BATTERY_REVISION_BIF
205 && batteryInfo->revision >= ACPI_BATTERY_REVISION_1
206 && object->package.count > 20) {
207 batteryInfo->swapping_capability = GetUint32(pointer++);
208 }
209 exit:
210 free(buffer.pointer);
211 return status;
212 }
213
214
215 int
EstimatedRuntime(battery_driver_cookie * cookie,acpi_battery_info * info)216 EstimatedRuntime(battery_driver_cookie* cookie, acpi_battery_info* info)
217 {
218 status_t status = B_ERROR;
219
220 acpi_object_type argument;
221 argument.object_type = ACPI_TYPE_INTEGER;
222 argument.integer.integer = info->current_rate;
223
224 acpi_objects arguments;
225 arguments.count = 1;
226 arguments.pointer = &argument;
227
228 acpi_object_type object;
229
230 acpi_data buffer;
231 buffer.pointer = &object;
232 buffer.length = sizeof(object);
233
234 acpi_object_type* returnObject;
235
236 status = cookie->acpi->evaluate_method(cookie->acpi_cookie, "_BTM",
237 &arguments, &buffer);
238 if (status != B_OK)
239 return -1;
240
241 returnObject = (acpi_object_type*)buffer.pointer;
242
243 if (returnObject->object_type != ACPI_TYPE_INTEGER)
244 return -1;
245
246 int result = returnObject->integer.integer;
247
248 return result;
249 }
250
251
252 void
battery_notify_handler(acpi_handle device,uint32 value,void * context)253 battery_notify_handler(acpi_handle device, uint32 value, void *context)
254 {
255 TRACE("battery_notify_handler event 0x%x\n", int(value));
256 sBatteryCondition.NotifyAll();
257 }
258
259
260 void
TraceBatteryInfo(acpi_extended_battery_info * batteryInfo)261 TraceBatteryInfo(acpi_extended_battery_info* batteryInfo)
262 {
263 TRACE("BIF power unit %i\n", batteryInfo->power_unit);
264 TRACE("BIF design capacity %i\n", batteryInfo->design_capacity);
265 TRACE("BIF last full charge %i\n", batteryInfo->last_full_charge);
266 TRACE("BIF technology %i\n", batteryInfo->technology);
267 TRACE("BIF design voltage %i\n", batteryInfo->design_voltage);
268 TRACE("BIF design capacity warning %i\n",
269 batteryInfo->design_capacity_warning);
270 TRACE("BIF design capacity low %i\n", batteryInfo->design_capacity_low);
271 TRACE("BIF capacity granularity 1 %i\n",
272 batteryInfo->capacity_granularity_1);
273 TRACE("BIF capacity granularity 2 %i\n",
274 batteryInfo->capacity_granularity_2);
275 if (batteryInfo->revision != ACPI_BATTERY_REVISION_BIF) {
276 TRACE("BIX cycles %i\n", batteryInfo->cycles);
277 TRACE("BIX accuracy %i\n", batteryInfo->accuracy);
278 TRACE("BIX max_sampling_time %i\n", batteryInfo->max_sampling_time);
279 TRACE("BIX min_sampling_time %i\n", batteryInfo->min_sampling_time);
280 TRACE("BIX max_average_interval %i\n",
281 batteryInfo->max_average_interval);
282 TRACE("BIX min_average_interval %i\n",
283 batteryInfo->min_average_interval);
284 }
285 TRACE("BIF model number %s\n", batteryInfo->model_number);
286 TRACE("BIF serial number %s\n", batteryInfo->serial_number);
287 TRACE("BIF type %s\n", batteryInfo->type);
288 TRACE("BIF oem info %s\n", batteryInfo->oem_info);
289 if (batteryInfo->revision != ACPI_BATTERY_REVISION_BIF
290 && batteryInfo->revision >= ACPI_BATTERY_REVISION_1) {
291 TRACE("BIX swapping_capability %i\n",
292 batteryInfo->swapping_capability);
293 }
294 }
295
296
297 // #pragma mark - device module API
298
299
300 static status_t
acpi_battery_init_device(void * driverCookie,void ** cookie)301 acpi_battery_init_device(void *driverCookie, void **cookie)
302 {
303 *cookie = driverCookie;
304 return B_OK;
305 }
306
307
308 static void
acpi_battery_uninit_device(void * _cookie)309 acpi_battery_uninit_device(void *_cookie)
310 {
311
312 }
313
314
315 static status_t
acpi_battery_open(void * initCookie,const char * path,int flags,void ** cookie)316 acpi_battery_open(void *initCookie, const char *path, int flags, void** cookie)
317 {
318 battery_device_cookie *device;
319 device = (battery_device_cookie*)calloc(1, sizeof(battery_device_cookie));
320 if (device == NULL)
321 return B_NO_MEMORY;
322
323 device->driver_cookie = (battery_driver_cookie*)initCookie;
324 device->stop_watching = 0;
325
326 *cookie = device;
327
328 return B_OK;
329 }
330
331
332 static status_t
acpi_battery_close(void * cookie)333 acpi_battery_close(void* cookie)
334 {
335 return B_OK;
336 }
337
338
339 static status_t
acpi_battery_read(void * _cookie,off_t position,void * buffer,size_t * numBytes)340 acpi_battery_read(void* _cookie, off_t position, void *buffer, size_t* numBytes)
341 {
342 if (*numBytes < 1)
343 return B_IO_ERROR;
344
345 battery_device_cookie *device = (battery_device_cookie*)_cookie;
346
347 acpi_battery_info batteryStatus;
348 ReadBatteryStatus(device->driver_cookie, &batteryStatus);
349
350 acpi_extended_battery_info batteryInfo;
351 ReadBatteryInfo(device->driver_cookie, &batteryInfo);
352
353 if (position == 0) {
354 char string[512];
355 char *str = string;
356 ssize_t max_len = sizeof(string);
357 snprintf(str, max_len, "Battery Status:\n");
358 max_len -= strlen(str);
359 str += strlen(str);
360
361 snprintf(str, max_len, " State %" B_PRIu32 ", Current Rate %" B_PRIu32
362 ", Capacity %" B_PRIu32 ", Voltage %" B_PRIu32 "\n",
363 batteryStatus.state, batteryStatus.current_rate,
364 batteryStatus.capacity, batteryStatus.voltage);
365 max_len -= strlen(str);
366 str += strlen(str);
367
368 snprintf(str, max_len, "\nBattery Info:\n");
369 max_len -= strlen(str);
370 str += strlen(str);
371
372 snprintf(str, max_len, " Power Unit %" B_PRIu32 ", Design Capacity %"
373 B_PRIu32 ", Last Full Charge %" B_PRIu32 ", Technology %" B_PRIu32
374 "\n", batteryInfo.power_unit, batteryInfo.design_capacity,
375 batteryInfo.last_full_charge, batteryInfo.technology);
376 max_len -= strlen(str);
377 str += strlen(str);
378 snprintf(str, max_len, " Design Voltage %" B_PRIu32 ", Design Capacity"
379 " Warning %" B_PRIu32 ", Design Capacity Low %" B_PRIu32 ", "
380 "Capacity Granularity1 %" B_PRIu32 ", Capacity Granularity2 %"
381 B_PRIu32 "\n", batteryInfo.design_voltage,
382 batteryInfo.design_capacity_warning,
383 batteryInfo.design_capacity_low,
384 batteryInfo.capacity_granularity_1,
385 batteryInfo.capacity_granularity_2);
386 max_len -= strlen(str);
387 str += strlen(str);
388 snprintf(str, max_len, " Model Number %s, Serial Number %s, "
389 "Type %s, OEM Info %s\n", batteryInfo.model_number,
390 batteryInfo.serial_number, batteryInfo.type, batteryInfo.oem_info);
391 max_len -= strlen(str);
392 str += strlen(str);
393
394 max_len = user_strlcpy((char*)buffer, string, *numBytes);
395 if (max_len < B_OK)
396 return B_BAD_ADDRESS;
397 *numBytes = max_len;
398 } else
399 *numBytes = 0;
400
401 return B_OK;
402 }
403
404
405 static status_t
acpi_battery_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)406 acpi_battery_write(void* cookie, off_t position, const void* buffer,
407 size_t* numBytes)
408 {
409 return B_ERROR;
410 }
411
412
413 static status_t
acpi_battery_control(void * _cookie,uint32 op,void * arg,size_t len)414 acpi_battery_control(void* _cookie, uint32 op, void* arg, size_t len)
415 {
416 battery_device_cookie* device = (battery_device_cookie*)_cookie;
417 status_t err;
418
419 switch (op) {
420 case IDENTIFY_DEVICE: {
421 if (len < sizeof(uint32))
422 return B_BAD_VALUE;
423
424 uint32 magicId = kMagicACPIBatteryID;
425 if (!IS_USER_ADDRESS(arg)
426 || user_memcpy(arg, &magicId, sizeof(magicId)) < B_OK) {
427 return B_BAD_ADDRESS;
428 }
429 return B_OK;
430 }
431
432 case GET_BATTERY_INFO: {
433 if (len < sizeof(acpi_battery_info))
434 return B_BAD_VALUE;
435
436 acpi_battery_info batteryInfo;
437 err = ReadBatteryStatus(device->driver_cookie, &batteryInfo);
438 if (err != B_OK)
439 return err;
440 if (!IS_USER_ADDRESS(arg)
441 || user_memcpy(arg, &batteryInfo, sizeof(batteryInfo))
442 < B_OK) {
443 return B_BAD_ADDRESS;
444 }
445 return B_OK;
446 }
447
448 case GET_EXTENDED_BATTERY_INFO: {
449 if (len < sizeof(acpi_extended_battery_info))
450 return B_BAD_VALUE;
451
452 acpi_extended_battery_info extBatteryInfo;
453 err = ReadBatteryInfo(device->driver_cookie, &extBatteryInfo);
454 if (err != B_OK)
455 return err;
456 if (!IS_USER_ADDRESS(arg)
457 || user_memcpy(arg, &extBatteryInfo, sizeof(extBatteryInfo))
458 < B_OK) {
459 return B_BAD_ADDRESS;
460 }
461 return B_OK;
462 }
463
464 case WATCH_BATTERY:
465 sBatteryCondition.Wait();
466 if (atomic_get(&(device->stop_watching))) {
467 atomic_set(&(device->stop_watching), 0);
468 return B_ERROR;
469 }
470 return B_OK;
471
472 case STOP_WATCHING_BATTERY:
473 atomic_set(&(device->stop_watching), 1);
474 sBatteryCondition.NotifyAll();
475 return B_OK;
476 }
477
478 return B_DEV_INVALID_IOCTL;
479 }
480
481
482 static status_t
acpi_battery_free(void * cookie)483 acpi_battery_free(void* cookie)
484 {
485 battery_device_cookie* device = (battery_device_cookie*)cookie;
486 free(device);
487 return B_OK;
488 }
489
490
491 // #pragma mark - driver module API
492
493
494 static float
acpi_battery_support(device_node * parent)495 acpi_battery_support(device_node *parent)
496 {
497 // make sure parent is really the ACPI bus manager
498 const char *bus;
499 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
500 return -1;
501
502 if (strcmp(bus, "acpi"))
503 return 0.0;
504
505 // check whether it's really a device
506 uint32 device_type;
507 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
508 &device_type, false) != B_OK
509 || device_type != ACPI_TYPE_DEVICE) {
510 return 0.0;
511 }
512
513 // check whether it's a battery device
514 const char *name;
515 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
516 false) != B_OK || strcmp(name, ACPI_NAME_BATTERY)) {
517 return 0.0;
518 }
519
520 return 0.6;
521 }
522
523
524 static status_t
acpi_battery_register_device(device_node * node)525 acpi_battery_register_device(device_node *node)
526 {
527 device_attr attrs[] = {
528 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI Battery" }},
529 { NULL }
530 };
531
532 return sDeviceManager->register_node(node, ACPI_BATTERY_DRIVER_NAME, attrs,
533 NULL, NULL);
534 }
535
536
537 static status_t
acpi_battery_init_driver(device_node * node,void ** driverCookie)538 acpi_battery_init_driver(device_node *node, void **driverCookie)
539 {
540 battery_driver_cookie *device;
541 device = (battery_driver_cookie *)calloc(1, sizeof(battery_driver_cookie));
542 if (device == NULL)
543 return B_NO_MEMORY;
544
545 *driverCookie = device;
546
547 device->node = node;
548
549 device_node *parent;
550 parent = sDeviceManager->get_parent_node(node);
551 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
552 (void **)&device->acpi_cookie);
553
554 #ifdef TRACE_BATTERY
555 const char* device_path;
556 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM,
557 &device_path, false) == B_OK) {
558 TRACE("acpi_battery_init_driver %s\n", device_path);
559 }
560 #endif
561
562 sDeviceManager->put_node(parent);
563
564 // install notify handler
565 device->acpi->install_notify_handler(device->acpi_cookie,
566 ACPI_ALL_NOTIFY, battery_notify_handler, device);
567
568 return B_OK;
569 }
570
571
572 static void
acpi_battery_uninit_driver(void * driverCookie)573 acpi_battery_uninit_driver(void *driverCookie)
574 {
575 TRACE("acpi_battery_uninit_driver\n");
576 battery_driver_cookie *device = (battery_driver_cookie*)driverCookie;
577
578 device->acpi->remove_notify_handler(device->acpi_cookie,
579 ACPI_ALL_NOTIFY, battery_notify_handler);
580
581 free(device);
582 }
583
584
585 static status_t
acpi_battery_register_child_devices(void * cookie)586 acpi_battery_register_child_devices(void *cookie)
587 {
588 battery_driver_cookie *device = (battery_driver_cookie*)cookie;
589
590 int pathID = sDeviceManager->create_id(ACPI_BATTERY_PATHID_GENERATOR);
591 if (pathID < 0) {
592 ERROR("register_child_devices: couldn't create a path_id\n");
593 return B_ERROR;
594 }
595
596 char name[128];
597 snprintf(name, sizeof(name), ACPI_BATTERY_BASENAME, pathID);
598
599 return sDeviceManager->publish_device(device->node, name,
600 ACPI_BATTERY_DEVICE_NAME);
601 }
602
603
604
605
606
607
608 module_dependency module_dependencies[] = {
609 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
610 {}
611 };
612
613
614 driver_module_info acpi_battery_driver_module = {
615 {
616 ACPI_BATTERY_DRIVER_NAME,
617 0,
618 NULL
619 },
620
621 acpi_battery_support,
622 acpi_battery_register_device,
623 acpi_battery_init_driver,
624 acpi_battery_uninit_driver,
625 acpi_battery_register_child_devices,
626 NULL, // rescan
627 NULL, // removed
628 };
629
630
631 struct device_module_info acpi_battery_device_module = {
632 {
633 ACPI_BATTERY_DEVICE_NAME,
634 0,
635 NULL
636 },
637
638 acpi_battery_init_device,
639 acpi_battery_uninit_device,
640 NULL,
641
642 acpi_battery_open,
643 acpi_battery_close,
644 acpi_battery_free,
645 acpi_battery_read,
646 acpi_battery_write,
647 NULL,
648 acpi_battery_control,
649
650 NULL,
651 NULL
652 };
653
654 module_info *modules[] = {
655 (module_info *)&acpi_battery_driver_module,
656 (module_info *)&acpi_battery_device_module,
657 NULL
658 };
659