From 8ca57645543d928602faf4b2b7f311e9c2c1be29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 16 May 2007 15:22:23 +0000 Subject: [PATCH] * Implemented APM generic syscall API to query the current power status. * PowerStatus is now using this API when compiled for Haiku. * Note, I'm not sure why yet, but running PowerStatus in the background crashes at least my laptop after some time. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21154 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/arch/x86/apm.h | 11 +++++ src/apps/powerstatus/Jamfile | 1 + src/apps/powerstatus/PowerStatusView.cpp | 30 +++++++++++-- src/system/kernel/arch/x86/apm.cpp | 54 +++++++++++++++++++++++- 4 files changed, 91 insertions(+), 5 deletions(-) diff --git a/headers/private/kernel/arch/x86/apm.h b/headers/private/kernel/arch/x86/apm.h index 910f0bfa44..47a1762a6c 100644 --- a/headers/private/kernel/arch/x86/apm.h +++ b/headers/private/kernel/arch/x86/apm.h @@ -47,6 +47,17 @@ typedef struct apm_info { } apm_info; +// temporary generic syscall interface +#define APM_SYSCALLS "apm" +#define APM_GET_BATTERY_INFO 1 + +struct battery_info { + bool online; + int32 percent; + time_t time_left; +}; + + #ifndef _BOOT_MODE #ifdef __cplusplus extern "C" { diff --git a/src/apps/powerstatus/Jamfile b/src/apps/powerstatus/Jamfile index dc62de8c59..67705a04c5 100644 --- a/src/apps/powerstatus/Jamfile +++ b/src/apps/powerstatus/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src apps powerstatus ; SetSubDirSupportedPlatformsBeOSCompatible ; UsePrivateHeaders shared ; +UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; Application PowerStatus : PowerStatusWindow.cpp diff --git a/src/apps/powerstatus/PowerStatusView.cpp b/src/apps/powerstatus/PowerStatusView.cpp index 64ee67a5ff..9c4339c93c 100644 --- a/src/apps/powerstatus/PowerStatusView.cpp +++ b/src/apps/powerstatus/PowerStatusView.cpp @@ -10,6 +10,11 @@ #include "PowerStatusView.h" #include "PowerStatus.h" +#include +#include +#include + // temporary, as long as there is no real power state API + #include #include #include @@ -110,7 +115,19 @@ PowerStatusView::_Init() fTimeLeft = 0; #ifdef HAIKU_TARGET_PLATFORM_HAIKU - // TODO: implement me + uint32 version = 0; + status_t status = _kern_generic_syscall(APM_SYSCALLS, B_SYSCALL_INFO, + &version, sizeof(version)); + if (status == B_OK) { + battery_info info; + status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO, &info, + sizeof(battery_info)); + } + + if (status != B_OK) { + fprintf(stderr, "No power interface found.\n"); + _Quit(); + } #else fDevice = open("/dev/misc/apm", O_RDONLY); if (fDevice < 0) { @@ -422,9 +439,14 @@ PowerStatusView::_Update(bool force) #ifdef HAIKU_TARGET_PLATFORM_HAIKU // TODO: retrieve data from APM/ACPI kernel interface - fPercent = 42; - fTimeLeft = 1500; - fOnline = true; + battery_info info; + status_t status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO, &info, + sizeof(battery_info)); + if (status == B_OK) { + fPercent = info.percent; + fTimeLeft = info.time_left; + fOnline = info.online; + } #else if (fDevice < 0) return; diff --git a/src/system/kernel/arch/x86/apm.cpp b/src/system/kernel/arch/x86/apm.cpp index bd5b27b1b0..9e25b88533 100644 --- a/src/system/kernel/arch/x86/apm.cpp +++ b/src/system/kernel/arch/x86/apm.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -196,6 +197,56 @@ apm_daemon(void *arg, int iteration) } +static status_t +get_battery_info(battery_info *info) +{ + bios_regs regs; + regs.eax = BIOS_APM_GET_POWER_STATUS; + regs.ebx = APM_ALL_DEVICES; + regs.ecx = 0; + + status_t status = call_apm_bios(®s); + if (status != B_OK) + return status; + + uint16 lineStatus = (regs.ebx >> 8) & 0xff; + if (lineStatus == 0xff) + return B_NOT_SUPPORTED; + + info->online = lineStatus != 0 && lineStatus != 2; + info->percent = regs.ecx & 0xff; + if (info->percent > 100 || info->percent < 0) + info->percent = -1; + + info->time_left = info->percent >= 0 ? (int32)(regs.edx & 0xffff) : -1; + if (info->time_left & 0x8000) + info->time_left = (info->time_left & 0x7fff) * 60; + + return B_OK; +} + + +static status_t +apm_control(const char *subsystem, uint32 function, + void *buffer, size_t bufferSize) +{ + struct battery_info info; + if (bufferSize != sizeof(struct battery_info)) + return B_BAD_VALUE; + + switch (function) { + case APM_GET_BATTERY_INFO: + status_t status = get_battery_info(&info); + if (status < B_OK) + return status; + + return user_memcpy(buffer, &info, sizeof(struct battery_info)); + } + + return B_BAD_VALUE; +} + + // #pragma mark - @@ -304,6 +355,7 @@ apm_init(kernel_args *args) register_kernel_daemon(apm_daemon, NULL, 10); // run the daemon once every second + register_generic_syscall(APM_SYSCALLS, apm_control, 1, 0); sAPMEnabled = true; return B_OK; }