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