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