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