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