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