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