* 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
This commit is contained in:
Axel Dörfler 2007-05-16 15:22:23 +00:00
parent 8536d82fb6
commit 8ca5764554
4 changed files with 91 additions and 5 deletions

View File

@ -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" {

View File

@ -3,6 +3,7 @@ SubDir HAIKU_TOP src apps powerstatus ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders shared ;
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
Application PowerStatus :
PowerStatusWindow.cpp

View File

@ -10,6 +10,11 @@
#include "PowerStatusView.h"
#include "PowerStatus.h"
#include <arch/x86/apm.h>
#include <generic_syscall.h>
#include <syscalls.h>
// temporary, as long as there is no real power state API
#include <Alert.h>
#include <Application.h>
#include <Deskbar.h>
@ -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;

View File

@ -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 <apm.h>
#include <descriptors.h>
#include <generic_syscall.h>
#include <safemode.h>
#include <boot/kernel_args.h>
@ -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(&regs);
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;
}