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 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 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 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 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 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 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 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 301 acpi_battery_init_device(void *driverCookie, void **cookie) 302 { 303 *cookie = driverCookie; 304 return B_OK; 305 } 306 307 308 static void 309 acpi_battery_uninit_device(void *_cookie) 310 { 311 312 } 313 314 315 static status_t 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 333 acpi_battery_close(void* cookie) 334 { 335 return B_OK; 336 } 337 338 339 static status_t 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 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 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 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 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 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 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 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 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