Changeset 27264 in vbox
- Timestamp:
- Mar 11, 2010 8:48:15 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DrvACPI.cpp
r26173 r27264 36 36 37 37 #ifdef RT_OS_LINUX 38 # include <iprt/ string.h>39 # include < sys/types.h>40 # include < dirent.h>41 # include < stdio.h>38 # include <iprt/critsect.h> 39 # include <iprt/dir.h> 40 # include <iprt/semaphore.h> 41 # include <iprt/stream.h> 42 42 #endif 43 43 … … 78 78 /** Pointer to the driver instance. */ 79 79 PPDMDRVINS pDrvIns; 80 81 #ifdef RT_OS_LINUX 82 /** The current power source. */ 83 PDMACPIPOWERSOURCE enmPowerSource; 84 /** true = one or more batteries preset, false = no battery present. */ 85 bool fBatteryPresent; 86 /** Remaining battery capacity. */ 87 PDMACPIBATCAPACITY enmBatteryRemainingCapacity; 88 /** Battery state. */ 89 PDMACPIBATSTATE enmBatteryState; 90 /** Preset battery charging/discharging rate. */ 91 uint32_t u32BatteryPresentRate; 92 /** The poller thread. */ 93 PPDMTHREAD pPollerThread; 94 /** Synchronize access to the above fields. 95 * XXX A spinlock is probaly cheaper ... */ 96 RTCRITSECT CritSect; 97 /** Event semaphore the poller thread is sleeping on. */ 98 RTSEMEVENT hPollerSleepEvent; 99 #endif 100 80 101 } DRVACPI, *PDRVACPI; 81 102 … … 133 154 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN; 134 155 } 135 #elif defined (RT_OS_LINUX) /* !RT_OS_WINDOWS */ 136 DIR *dfd; 137 struct dirent *dp; 138 FILE *statusFile = NULL; 139 char buff[NAME_MAX+50]; 140 141 /* start with no result */ 142 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN; 143 144 dfd = opendir("/proc/acpi/ac_adapter/"); 145 if (dfd) 146 { 147 for (;;) 148 { 149 dp = readdir(dfd); 150 if (dp == 0) 151 break; 152 if (strcmp(dp->d_name, ".") == 0 || 153 strcmp(dp->d_name, "..") == 0) 154 continue; 155 strcpy(buff, "/proc/acpi/ac_adapter/"); 156 strcat(buff, dp->d_name); 157 strcat(buff, "/status"); 158 statusFile = fopen(buff, "r"); 159 /* there's another possible name for this file */ 160 if (!statusFile) 161 { 162 strcpy(buff, "/proc/acpi/ac_adapter/"); 163 strcat(buff, dp->d_name); 164 strcat(buff, "/state"); 165 statusFile = fopen(buff, "r"); 166 } 167 if (statusFile) 168 break; 169 } 170 closedir(dfd); 171 } 172 173 if (statusFile) 174 { 175 for (;;) 176 { 177 char buff2[1024]; 178 if (fgets(buff2, sizeof(buff), statusFile) == NULL) 179 break; 180 if (strstr(buff2, "Status:") != NULL || 181 strstr(buff2, "state:") != NULL) 182 { 183 if (strstr(buff2, "on-line") != NULL) 184 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET; 185 else 186 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY; 187 } 188 } 189 fclose(statusFile); 190 } 191 #elif defined (RT_OS_DARWIN) /* !RT_OS_LINUX */ 156 157 #elif defined (RT_OS_LINUX) 158 PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector); 159 RTCritSectEnter(&pThis->CritSect); 160 *pPowerSource = pThis->enmPowerSource, pPowerSource; 161 RTCritSectLeave(&pThis->CritSect); 162 163 #elif defined (RT_OS_DARWIN) 192 164 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN; 193 165 … … 197 169 CFDictionaryRef pSource = NULL; 198 170 const void *psValue; 199 bool result;171 bool fResult; 200 172 201 173 if (CFArrayGetCount(pSources) > 0) 202 174 { 203 for (int i = 0; i < CFArrayGetCount(pSources); ++i)175 for (int i = 0; i < CFArrayGetCount(pSources); ++i) 204 176 { 205 177 pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i)); … … 212 184 continue; 213 185 /* Only internal power types are of interest. */ 214 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);215 if ( result &&216 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)186 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue); 187 if ( fResult 188 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo) 217 189 { 218 190 /* Check which power source we are connect on. */ 219 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);220 if ( result &&221 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)191 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue); 192 if ( fResult 193 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo) 222 194 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET; 223 else if ( result &&224 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)195 else if ( fResult 196 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) 225 197 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY; 226 198 } … … 229 201 CFRelease(pBlob); 230 202 CFRelease(pSources); 231 #elif defined(RT_OS_FREEBSD) /* !RT_OS_DARWIN */ 203 204 #elif defined(RT_OS_FREEBSD) 232 205 int fAcLine = 0; 233 206 size_t cbParameter = sizeof(fAcLine); … … 251 224 #else /* !RT_OS_FREEBSD either - what could this be? */ 252 225 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET; 253 #endif /* !RT_OS_WINDOWS */ 226 227 #endif /* !RT_OS_FREEBSD */ 254 228 return VINF_SUCCESS; 255 229 } … … 294 268 GetLastError())); 295 269 } 270 296 271 #elif defined(RT_OS_LINUX) 297 DIR *dfd; 298 struct dirent *dp; 299 FILE *statusFile = NULL; 300 FILE *infoFile = NULL; 301 char buff[NAME_MAX+50]; 302 /* the summed up maximum capacity */ 303 int maxCapacityTotal = ~0; 304 /* the summed up total capacity */ 305 int currentCapacityTotal = ~0; 306 int presentRate = 0; 307 int presentRateTotal = 0; 308 bool fBatteryPresent = false, fCharging=false, fDischarging=false, fCritical=false; 309 310 dfd = opendir("/proc/acpi/battery/"); 311 if (dfd) 312 { 313 for (;;) 314 { 315 dp = readdir(dfd); 316 if (dp == 0) 317 break; 318 if (strcmp(dp->d_name, ".") == 0 || 319 strcmp(dp->d_name, "..") == 0) 320 continue; 321 strcpy(buff, "/proc/acpi/battery/"); 322 strcat(buff, dp->d_name); 323 strcat(buff, "/status"); 324 statusFile = fopen(buff, "r"); 325 /* there is a 2nd variant of that file */ 326 if (!statusFile) 327 { 328 strcpy(buff, "/proc/acpi/battery/"); 329 strcat(buff, dp->d_name); 330 strcat(buff, "/state"); 331 statusFile = fopen(buff, "r"); 332 } 333 strcpy(buff, "/proc/acpi/battery/"); 334 strcat(buff, dp->d_name); 335 strcat(buff, "/info"); 336 infoFile = fopen(buff, "r"); 337 /* we need both files */ 338 if (!statusFile || !infoFile) 339 { 340 if (statusFile) 341 fclose(statusFile); 342 if (infoFile) 343 fclose(infoFile); 344 break; 345 } 346 347 /* get 'present' status from the info file */ 348 for (;;) 349 { 350 char buff2[1024]; 351 if (fgets(buff2, sizeof(buff), infoFile) == NULL) 352 break; 353 354 if (strstr(buff2, "present:") != NULL) 355 { 356 if (strstr(buff2, "yes") != NULL) 357 fBatteryPresent = true; 358 } 359 } 360 361 /* move file pointer back to start of file */ 362 fseek(infoFile, 0, SEEK_SET); 363 364 if (fBatteryPresent) 365 { 366 /* get the maximum capacity from the info file */ 367 for (;;) 368 { 369 char buff2[1024]; 370 int maxCapacity = ~0; 371 if (fgets(buff2, sizeof(buff), infoFile) == NULL) 372 break; 373 if (strstr(buff2, "last full capacity:") != NULL) 374 { 375 if (sscanf(buff2 + 19, "%d", &maxCapacity) <= 0) 376 maxCapacity = ~0; 377 378 /* did we get a valid capacity and it's the first value we got? */ 379 if (maxCapacityTotal < 0 && maxCapacity > 0) 380 { 381 /* take this as the maximum capacity */ 382 maxCapacityTotal = maxCapacity; 383 } 384 else 385 { 386 /* sum up the maximum capacity */ 387 if (maxCapacityTotal > 0 && maxCapacity > 0) 388 maxCapacityTotal += maxCapacity; 389 } 390 /* we got all we need */ 391 break; 392 } 393 } 394 395 /* get the current capacity/state from the status file */ 396 bool gotRemainingCapacity=false, gotBatteryState=false, 397 gotCapacityState=false, gotPresentRate=false; 398 while (!gotRemainingCapacity || !gotBatteryState || 399 !gotCapacityState || !gotPresentRate) 400 { 401 char buff2[1024]; 402 int currentCapacity = ~0; 403 if (fgets(buff2, sizeof(buff), statusFile) == NULL) 404 break; 405 if (strstr(buff2, "remaining capacity:") != NULL) 406 { 407 if (sscanf(buff2 + 19, "%d", ¤tCapacity) <= 0) 408 currentCapacity = ~0; 409 410 /* is this the first valid value we see? If so, take it! */ 411 if (currentCapacityTotal < 0 && currentCapacity >= 0) 412 { 413 currentCapacityTotal = currentCapacity; 414 } 415 else 416 { 417 /* just sum up the current value */ 418 if (currentCapacityTotal > 0 && currentCapacity > 0) 419 currentCapacityTotal += currentCapacity; 420 } 421 gotRemainingCapacity = true; 422 } 423 if (strstr(buff2, "charging state:") != NULL) 424 { 425 if (strstr(buff2 + 15, "discharging") != NULL) 426 fDischarging = true; 427 else if (strstr(buff2 + 15, "charging") != NULL) 428 fCharging = true; 429 gotBatteryState = true; 430 } 431 if (strstr(buff2, "capacity state:") != NULL) 432 { 433 if (strstr(buff2 + 15, "critical") != NULL) 434 fCritical = true; 435 gotCapacityState = true; 436 } 437 if (strstr(buff2, "present rate:") != NULL) 438 { 439 if (sscanf(buff2 + 13, "%d", &presentRate) <= 0) 440 presentRate = 0; 441 gotPresentRate = true; 442 } 443 } 444 } 445 446 if (presentRate) 447 { 448 if (fDischarging) 449 presentRateTotal -= presentRate; 450 else 451 presentRateTotal += presentRate; 452 } 453 454 if (statusFile) 455 fclose(statusFile); 456 if (infoFile) 457 fclose(infoFile); 458 459 } 460 closedir(dfd); 461 } 462 463 *pfPresent = fBatteryPresent; 464 465 /* charging/discharging bits are mutual exclusive */ 466 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED; 467 if (fDischarging) 468 uBs = PDM_ACPI_BAT_STATE_DISCHARGING; 469 else if (fCharging) 470 uBs = PDM_ACPI_BAT_STATE_CHARGING; 471 if (fCritical) 472 uBs |= PDM_ACPI_BAT_STATE_CRITICAL; 473 *penmBatteryState = (PDMACPIBATSTATE)uBs; 474 475 if (presentRateTotal < 0) 476 presentRateTotal = -presentRateTotal; 477 478 if (maxCapacityTotal > 0 && currentCapacityTotal > 0) 479 { 480 /* calculate the percentage */ 481 *penmRemainingCapacity = (PDMACPIBATCAPACITY)(((float)currentCapacityTotal / (float)maxCapacityTotal) 482 * PDM_ACPI_BAT_CAPACITY_MAX); 483 *pu32PresentRate = (uint32_t)(((float)presentRateTotal / (float)maxCapacityTotal) * 1000); 484 } 272 PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector); 273 RTCritSectEnter(&pThis->CritSect); 274 *pfPresent = pThis->fBatteryPresent; 275 *penmRemainingCapacity = pThis->enmBatteryRemainingCapacity; 276 *penmBatteryState = pThis->enmBatteryState, penmBatteryState; 277 *pu32PresentRate = pThis->u32BatteryPresentRate; 278 RTCritSectLeave(&pThis->CritSect); 279 485 280 #elif defined(RT_OS_DARWIN) 486 281 CFTypeRef pBlob = IOPSCopyPowerSourcesInfo(); … … 489 284 CFDictionaryRef pSource = NULL; 490 285 const void *psValue; 491 bool result;286 bool fResult; 492 287 493 288 if (CFArrayGetCount(pSources) > 0) 494 289 { 495 for (int i = 0; i < CFArrayGetCount(pSources); ++i)290 for (int i = 0; i < CFArrayGetCount(pSources); ++i) 496 291 { 497 292 pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i)); … … 504 299 continue; 505 300 /* Only internal power types are of interest. */ 506 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);507 if ( result &&508 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)301 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue); 302 if ( fResult 303 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo) 509 304 { 510 305 PDMACPIPOWERSOURCE powerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN; 511 306 /* First check which power source we are connect on. */ 512 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);513 if ( result &&514 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)307 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue); 308 if ( fResult 309 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo) 515 310 powerSource = PDM_ACPI_POWER_SOURCE_OUTLET; 516 else if ( result &&517 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)311 else if ( fResult 312 && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) 518 313 powerSource = PDM_ACPI_POWER_SOURCE_BATTERY; 519 314 … … 527 322 528 323 /* Fetch the current capacity value of the power source */ 529 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);530 if ( result)324 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue); 325 if (fResult) 531 326 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity); 532 327 /* Fetch the maximum capacity value of the power source */ 533 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);534 if ( result)328 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue); 329 if (fResult) 535 330 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity); 536 331 … … 546 341 int timeToEmpty = -1; 547 342 /* Get the time till the battery source will be empty */ 548 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue);549 if ( result)343 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue); 344 if (fResult) 550 345 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToEmpty); 551 346 if (timeToEmpty != -1) … … 554 349 } 555 350 556 if ( powerSource == PDM_ACPI_POWER_SOURCE_OUTLET &&557 CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue))351 if ( powerSource == PDM_ACPI_POWER_SOURCE_OUTLET 352 && CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue)) 558 353 { 559 354 /* We are running on an AC power source, but we also have a … … 565 360 int timeToFull = -1; 566 361 /* Get the time till the battery source will be charged */ 567 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue);568 if ( result)362 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue); 363 if (fResult) 569 364 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToFull); 570 365 if (timeToFull != -1) … … 576 371 /* Check for critical */ 577 372 int criticalValue = 20; 578 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);579 if ( result)373 fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue); 374 if (fResult) 580 375 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue); 581 376 if (remCapacity < criticalValue) … … 586 381 CFRelease(pBlob); 587 382 CFRelease(pSources); 383 588 384 #elif defined(RT_OS_FREEBSD) 589 385 /* We try to use /dev/acpi first and if that fails use the sysctls. */ … … 650 446 * The current power rate can be calculated with P = U * I 651 447 */ 652 *pu32PresentRate = (uint32_t)((((float)BatteryIo.bst.volt/1000.0) * ((float)BatteryIo.bst.rate/1000.0)) * 1000.0); 448 *pu32PresentRate = (uint32_t)( ( ((float)BatteryIo.bst.volt/1000.0) 449 * ((float)BatteryIo.bst.rate/1000.0)) 450 * 1000.0); 653 451 } 654 452 } … … 690 488 cbParameter = sizeof(curCapacity); 691 489 rc = sysctlbyname("hw.acpi.battery.life", &curCapacity, &cbParameter, NULL, NULL); 692 if ( (!rc) && (curCapacity >= 0))490 if (!rc && curCapacity >= 0) 693 491 *penmRemainingCapacity = (PDMACPIBATCAPACITY)curCapacity; 694 492 … … 697 495 } 698 496 } 497 699 498 #endif /* RT_OS_FREEBSD */ 499 700 500 return VINF_SUCCESS; 701 501 } 502 503 #ifdef RT_OS_LINUX 504 /** 505 * Poller thread for /proc/acpi status files. 506 * 507 * Reading these files takes ages (several seconds) on some hosts, therefore 508 * start this thread. The termination of this thread may take some seconds 509 * on such a hosts! 510 * 511 * @param pDrvIns The driver instance data. 512 * @param pThread The thread. 513 */ 514 static DECLCALLBACK(int) drvACPIPoller(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 515 { 516 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI); 517 518 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 519 return VINF_SUCCESS; 520 521 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 522 { 523 /* 524 * Read the status of the powerline-adapter. 525 */ 526 527 PDMACPIPOWERSOURCE enmPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN; 528 PRTSTREAM pStrmStatus; 529 PRTDIR pDir = NULL; 530 RTDIRENTRY DirEntry; 531 char szLine[1024]; 532 int rc = RTDirOpen(&pDir, "/proc/acpi/ac_adapter/"); 533 if (RT_SUCCESS(rc)) 534 { 535 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 536 { 537 rc = RTDirRead(pDir, &DirEntry, NULL); 538 if (RT_FAILURE(rc)) 539 break; 540 if ( strcmp(DirEntry.szName, ".") == 0 541 || strcmp(DirEntry.szName, "..") == 0) 542 continue; 543 rc = RTStrmOpenF("r", &pStrmStatus, 544 "/proc/acpi/ac_adapter/%s/status", DirEntry.szName); 545 if (RT_FAILURE(rc)) 546 rc = RTStrmOpenF("r", &pStrmStatus, 547 "/proc/acpi/ac_adapter/%s/state", DirEntry.szName); 548 if (RT_SUCCESS(rc)) 549 { 550 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 551 { 552 rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine)); 553 if (RT_FAILURE(rc)) 554 break; 555 if ( strstr(szLine, "Status:") != NULL 556 || strstr(szLine, "state:") != NULL) 557 { 558 if (strstr(szLine, "on-line") != NULL) 559 enmPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET; 560 else 561 enmPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY; 562 break; 563 } 564 } 565 RTStrmClose(pStrmStatus); 566 break; 567 } 568 } 569 RTDirClose(pDir); 570 } 571 572 /* 573 * Read the status of all batteries and collect it into one. 574 */ 575 576 int32_t maxCapacityTotal = INT32_MIN; /* the summed up maximum capacity */ 577 int32_t currentCapacityTotal = INT32_MIN; /* the summed up total capacity */ 578 int32_t presentRate = 0; 579 int32_t presentRateTotal = 0; 580 bool fBatteryPresent = false; 581 bool fCharging = false; 582 bool fDischarging = false; 583 bool fCritical = false; 584 585 rc = RTDirOpen(&pDir, "/proc/acpi/battery/"); 586 if (RT_SUCCESS(rc)) 587 { 588 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 589 { 590 rc = RTDirRead(pDir, &DirEntry, NULL); 591 if (RT_FAILURE(rc)) 592 break; 593 if ( strcmp(DirEntry.szName, ".") == 0 594 || strcmp(DirEntry.szName, "..") == 0) 595 continue; 596 597 pStrmStatus; 598 rc = RTStrmOpenF("r", &pStrmStatus, 599 "/proc/acpi/battery/%s/status", DirEntry.szName); 600 /* there is a 2nd variant of that file */ 601 if (RT_FAILURE(rc)) 602 { 603 rc = RTStrmOpenF("r", &pStrmStatus, 604 "/proc/acpi/battery/%s/state", DirEntry.szName); 605 } 606 if (RT_FAILURE(rc)) 607 continue; 608 609 PRTSTREAM pStrmInfo; 610 rc = RTStrmOpenF("r", &pStrmInfo, 611 "/proc/acpi/battery/%s/info", DirEntry.szName); 612 if (RT_FAILURE(rc)) 613 { 614 RTStrmClose(pStrmStatus); 615 continue; 616 } 617 618 /* get 'present' status from the info file */ 619 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 620 { 621 rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine)); 622 if (RT_FAILURE(rc)) 623 break; 624 if (strstr(szLine, "present:") != NULL) 625 { 626 if (strstr(szLine, "yes") != NULL) 627 { 628 fBatteryPresent = true; 629 break; 630 } 631 } 632 } 633 634 RTStrmRewind(pStrmInfo); 635 if (fBatteryPresent) 636 { 637 /* get the maximum capacity from the info file */ 638 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 639 { 640 int32_t maxCapacity = INT32_MIN; 641 rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine)); 642 if (RT_FAILURE(rc)) 643 break; 644 if (strstr(szLine, "last full capacity:") != NULL) 645 { 646 rc = RTStrToInt32Full(szLine + 19, 0, &maxCapacity); 647 if (RT_FAILURE(rc)) 648 maxCapacity = INT32_MIN; 649 650 /* did we get a valid capacity and it's the first value we got? */ 651 if (maxCapacityTotal < 0 && maxCapacity > 0) 652 { 653 /* take this as the maximum capacity */ 654 maxCapacityTotal = maxCapacity; 655 } 656 else 657 { 658 /* sum up the maximum capacity */ 659 if (maxCapacityTotal > 0 && maxCapacity > 0) 660 maxCapacityTotal += maxCapacity; 661 } 662 /* we got all we need */ 663 break; 664 } 665 } 666 667 /* get the current capacity/state from the status file */ 668 bool fGotRemainingCapacity = false; 669 bool fGotBatteryState = false; 670 bool fGotCapacityState = false; 671 bool fGotPresentRate = false; 672 while ( ( !fGotRemainingCapacity 673 || !fGotBatteryState 674 || !fGotCapacityState 675 || !fGotPresentRate) 676 && pThread->enmState == PDMTHREADSTATE_RUNNING) 677 { 678 int32_t currentCapacity = INT32_MIN; 679 rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine)); 680 if (RT_FAILURE(rc)) 681 break; 682 if (strstr(szLine, "remaining capacity:") != NULL) 683 { 684 rc = RTStrToInt32Full(szLine + 19, 0, ¤tCapacity); 685 if (RT_FAILURE(rc)) 686 currentCapacity = INT32_MIN; 687 688 /* is this the first valid value we see? If so, take it! */ 689 if (currentCapacityTotal < 0 && currentCapacity >= 0) 690 { 691 currentCapacityTotal = currentCapacity; 692 } 693 else 694 { 695 /* just sum up the current value */ 696 if (currentCapacityTotal > 0 && currentCapacity > 0) 697 currentCapacityTotal += currentCapacity; 698 } 699 fGotRemainingCapacity = true; 700 } 701 else if (strstr(szLine, "charging state:") != NULL) 702 { 703 if (strstr(szLine + 15, "discharging") != NULL) 704 fDischarging = true; 705 else if (strstr(szLine + 15, "charging") != NULL) 706 fCharging = true; 707 fGotBatteryState = true; 708 } 709 else if (strstr(szLine, "capacity state:") != NULL) 710 { 711 if (strstr(szLine + 15, "critical") != NULL) 712 fCritical = true; 713 fGotCapacityState = true; 714 } 715 if (strstr(szLine, "present rate:") != NULL) 716 { 717 rc = RTStrToInt32Full(szLine + 13, 0, &presentRate); 718 if (RT_FAILURE(rc)) 719 presentRate = 0; 720 fGotPresentRate = true; 721 } 722 } 723 } 724 725 if (presentRate) 726 { 727 if (fDischarging) 728 presentRateTotal -= presentRate; 729 else 730 presentRateTotal += presentRate; 731 } 732 733 RTStrmClose(pStrmStatus); 734 RTStrmClose(pStrmInfo); 735 } 736 RTDirClose(pDir); 737 } 738 739 /* atomic update of the state */ 740 RTCritSectEnter(&pThis->CritSect); 741 pThis->enmPowerSource = enmPowerSource; 742 pThis->fBatteryPresent = fBatteryPresent; 743 744 /* charging/discharging bits are mutual exclusive */ 745 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED; 746 if (fDischarging) 747 uBs = PDM_ACPI_BAT_STATE_DISCHARGING; 748 else if (fCharging) 749 uBs = PDM_ACPI_BAT_STATE_CHARGING; 750 if (fCritical) 751 uBs |= PDM_ACPI_BAT_STATE_CRITICAL; 752 pThis->enmBatteryState = (PDMACPIBATSTATE)uBs; 753 754 if (maxCapacityTotal > 0 && currentCapacityTotal > 0) 755 { 756 if (presentRateTotal < 0) 757 presentRateTotal = -presentRateTotal; 758 759 /* calculate the percentage */ 760 pThis->enmBatteryRemainingCapacity = 761 (PDMACPIBATCAPACITY)( ( (float)currentCapacityTotal 762 / (float)maxCapacityTotal) 763 * PDM_ACPI_BAT_CAPACITY_MAX); 764 pThis->u32BatteryPresentRate = 765 (uint32_t)(( (float)presentRateTotal 766 / (float)maxCapacityTotal) * 1000); 767 } 768 RTCritSectLeave(&pThis->CritSect); 769 770 /* wait a bit (e.g. Ubuntu/GNOME polls every 30 seconds) */ 771 rc = RTSemEventWait(pThis->hPollerSleepEvent, 20000); 772 } 773 774 return VINF_SUCCESS; 775 } 776 777 static DECLCALLBACK(int) drvACPIPollerWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 778 { 779 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI); 780 781 RTSemEventSignal(pThis->hPollerSleepEvent); 782 RTThreadPoke(pThread->Thread); 783 return VINF_SUCCESS; 784 } 785 #endif /* RT_OS_LINUX */ 786 702 787 703 788 /** … … 711 796 static DECLCALLBACK(void) drvACPIDestruct(PPDMDRVINS pDrvIns) 712 797 { 798 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI); 799 713 800 LogFlow(("drvACPIDestruct\n")); 714 801 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 802 803 RTSemEventDestroy(pThis->hPollerSleepEvent); 804 pThis->hPollerSleepEvent = NIL_RTSEMEVENT; 805 RTCritSectDelete(&pThis->CritSect); 715 806 } 716 807 … … 724 815 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI); 725 816 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); 817 int rc = VINF_SUCCESS; 726 818 727 819 /* … … 758 850 } 759 851 760 return VINF_SUCCESS; 852 #ifdef RT_OS_LINUX 853 /* 854 * Start the poller thread. 855 */ 856 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pPollerThread, pThis, drvACPIPoller, 857 drvACPIPollerWakeup, 0, RTTHREADTYPE_INFREQUENT_POLLER, "ACPI Poller"); 858 if (RT_FAILURE(rc)) 859 return rc; 860 861 rc = RTCritSectInit(&pThis->CritSect); 862 if (RT_FAILURE(rc)) 863 return rc; 864 865 rc = RTSemEventCreate(&pThis->hPollerSleepEvent); 866 #endif 867 868 return rc; 761 869 } 762 870
Note:
See TracChangeset
for help on using the changeset viewer.