power_daemon: use wait_for_objects() instead of polling.

* acpi_button and acpi_lid support select/deselect hooks.
* power_daemon now uses a thread waiting for lid or power button events.
* a power button event is still hardcoded to a shutdown.
* a lid event only displays a message.
This commit is contained in:
Jérôme Duval
2013-11-14 00:33:50 +01:00
parent 28fd553722
commit c9db30cd7f
8 changed files with 208 additions and 61 deletions
@@ -1,5 +1,7 @@
SubDir HAIKU_TOP src add-ons kernel drivers power acpi_button ;
UsePrivateKernelHeaders ;
KernelAddon acpi_button :
acpi_button.cpp
;
@@ -10,6 +10,8 @@
#include <ACPI.h>
#include <fs/select_sync_pool.h>
#include <stdlib.h>
#include <string.h>
@@ -40,6 +42,7 @@ typedef struct acpi_ns_device_info {
uint32 type;
bool fixed;
uint8 last_status;
select_sync_pool* select_pool;
} acpi_button_device_info;
@@ -50,6 +53,8 @@ acpi_button_notify_handler(acpi_handle _device, uint32 value, void *context)
if (value == ACPI_NOTIFY_BUTTON_SLEEP) {
TRACE("sleep\n");
device->last_status = 1;
if (device->select_pool != NULL)
notify_select_event_pool(device->select_pool, B_SELECT_READ);
} else if (value == ACPI_NOTIFY_BUTTON_WAKEUP) {
TRACE("wakeup\n");
} else {
@@ -65,6 +70,8 @@ acpi_button_fixed_handler(void *context)
acpi_button_device_info *device = (acpi_button_device_info *)context;
TRACE("sleep\n");
device->last_status = 1;
if (device->select_pool != NULL)
notify_select_event_pool(device->select_pool, B_SELECT_READ);
return B_OK;
}
@@ -106,6 +113,7 @@ acpi_button_init_device(void *_cookie, void **cookie)
else
return B_ERROR;
device->last_status = 0;
device->select_pool = NULL;
if (device->fixed) {
sAcpi->reset_fixed_event(device->type);
@@ -183,6 +191,41 @@ acpi_button_control(void* _cookie, uint32 op, void* arg, size_t len)
}
static status_t
acpi_button_select(void *_cookie, uint8 event, selectsync *sync)
{
acpi_button_device_info* device = (acpi_button_device_info*)_cookie;
if (event != B_SELECT_READ)
return B_BAD_VALUE;
// add the event to the pool
status_t error = add_select_sync_pool_entry(&device->select_pool, sync,
event);
if (error != B_OK) {
ERROR("add_select_sync_pool_entry() failed: %#lx\n", error);
return error;
}
if (device->last_status != 0)
notify_select_event(sync, event);
return B_OK;
}
static status_t
acpi_button_deselect(void *_cookie, uint8 event, selectsync *sync)
{
acpi_button_device_info* device = (acpi_button_device_info*)_cookie;
if (event != B_SELECT_READ)
return B_BAD_VALUE;
return remove_select_sync_pool_entry(&device->select_pool, sync, event);
}
static status_t
acpi_button_close (void* cookie)
{
@@ -330,9 +373,8 @@ struct device_module_info acpi_button_device_module = {
acpi_button_write,
NULL,
acpi_button_control,
NULL,
NULL
acpi_button_select,
acpi_button_deselect
};
module_info *modules[] = {
@@ -1,5 +1,7 @@
SubDir HAIKU_TOP src add-ons kernel drivers power acpi_lid ;
UsePrivateKernelHeaders ;
KernelAddon acpi_lid :
acpi_lid.cpp
;
@@ -7,6 +7,8 @@
#include <ACPI.h>
#include <fs/select_sync_pool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,13 +18,15 @@
#define ACPI_LID_DEVICE_MODULE_NAME "drivers/power/acpi_lid/device_v1"
#define ACPI_NOTIFY_STATUS_CHANGED 0x80
/* Base Namespace devices are published to */
#define ACPI_LID_BASENAME "power/acpi_lid/%d"
// name of pnp generator of path ids
#define ACPI_LID_PATHID_GENERATOR "acpi_lid/path_id"
#define TRACE_LID
//#define TRACE_LID
#ifdef TRACE_LID
# define TRACE(x...) dprintf("acpi_lid: "x)
#else
@@ -30,6 +34,7 @@
#endif
#define ERROR(x...) dprintf("acpi_lid: "x)
static device_manager_info *sDeviceManager;
@@ -38,16 +43,43 @@ typedef struct acpi_ns_device_info {
acpi_device_module_info *acpi;
acpi_device acpi_cookie;
uint8 last_status;
bool updated;
select_sync_pool* select_pool;
} acpi_lid_device_info;
static void
acpi_lid_notify_handler(acpi_handle device, uint32 value, void *context)
acpi_lid_read_status(acpi_lid_device_info *device)
{
if (value == 0x80) {
dprintf("acpi_lid: status changed\n");
acpi_data buf;
buf.pointer = NULL;
buf.length = ACPI_ALLOCATE_BUFFER;
if (device->acpi->evaluate_method(device->acpi_cookie, "_LID", NULL,
&buf) != B_OK
|| buf.pointer == NULL
|| ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) {
ERROR("couldn't get status\n");
} else {
dprintf("acpi_lid: unknown notification\n");
acpi_object_type* object = (acpi_object_type*)buf.pointer;
device->last_status = object->integer.integer;
device->updated = true;
free(buf.pointer);
TRACE("status %d\n", device->last_status);
}
}
static void
acpi_lid_notify_handler(acpi_handle _device, uint32 value, void *context)
{
acpi_lid_device_info *device = (acpi_lid_device_info *)context;
if (value == ACPI_NOTIFY_STATUS_CHANGED) {
TRACE("status changed\n");
acpi_lid_read_status(device);
if (device->select_pool != NULL)
notify_select_event_pool(device->select_pool, B_SELECT_READ);
} else {
ERROR("unknown notification\n");
}
}
@@ -83,7 +115,14 @@ acpi_lid_open(void *_cookie, const char *path, int flags, void** cookie)
static status_t
acpi_lid_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
{
return B_ERROR;
acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
if (*num_bytes < 1)
return B_IO_ERROR;
*((uint8 *)(buf)) = device->last_status;
*num_bytes = 1;
device->updated = false;
return B_OK;
}
@@ -101,6 +140,41 @@ acpi_lid_control(void* _cookie, uint32 op, void* arg, size_t len)
}
static status_t
acpi_lid_select(void *_cookie, uint8 event, selectsync *sync)
{
acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
if (event != B_SELECT_READ)
return B_BAD_VALUE;
// add the event to the pool
status_t error = add_select_sync_pool_entry(&device->select_pool, sync,
event);
if (error != B_OK) {
ERROR("add_select_sync_pool_entry() failed: %#lx\n", error);
return error;
}
if (device->updated)
notify_select_event(sync, event);
return B_OK;
}
static status_t
acpi_lid_deselect(void *_cookie, uint8 event, selectsync *sync)
{
acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
if (event != B_SELECT_READ)
return B_BAD_VALUE;
return remove_select_sync_pool_entry(&device->select_pool, sync, event);
}
static status_t
acpi_lid_close (void* cookie)
{
@@ -189,20 +263,8 @@ acpi_lid_init_driver(device_node *node, void **_driverCookie)
}
device->last_status = 0;
acpi_data buf;
buf.pointer = NULL;
buf.length = ACPI_ALLOCATE_BUFFER;
if (device->acpi->evaluate_method(device->acpi_cookie, "_LID", NULL,
&buf) != B_OK
|| buf.pointer == NULL
|| ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) {
ERROR("couldn't get status\n");
} else {
acpi_object_type* object = (acpi_object_type*)buf.pointer;
device->last_status = object->integer.integer;
free(buf.pointer);
TRACE("status %d\n", device->last_status);
}
device->updated = false;
device->select_pool = NULL;
*_driverCookie = device;
return B_OK;
@@ -282,9 +344,8 @@ struct device_module_info acpi_lid_device_module = {
acpi_lid_write,
NULL,
acpi_lid_control,
NULL,
NULL
acpi_lid_select,
acpi_lid_deselect
};
module_info *modules[] = {
+1
View File
@@ -5,6 +5,7 @@ UsePrivateHeaders app ;
AddResources power_daemon : power_daemon.rdef ;
Server power_daemon :
lid_monitor.cpp
power_daemon.cpp
power_button_monitor.cpp
;
+6 -11
View File
@@ -16,31 +16,26 @@
PowerButtonMonitor::PowerButtonMonitor()
:
BHandler ("power_button_monitor")
{
fPowerButtonFD = open("/dev/power/button/power", O_RDONLY);
fFD = open("/dev/power/button/power", O_RDONLY);
}
PowerButtonMonitor::~PowerButtonMonitor()
{
if (fPowerButtonFD > 0)
close(fPowerButtonFD);
if (fFD > 0)
close(fFD);
}
void
PowerButtonMonitor::MessageReceived(BMessage *msg)
PowerButtonMonitor::HandleEvent()
{
if (msg->what != POLL_POWER_BUTTON_STATUS)
return;
if (fPowerButtonFD <= 0)
if (fFD <= 0)
return;
uint8 button_pressed;
read(fPowerButtonFD, &button_pressed, 1);
read(fFD, &button_pressed, 1);
if (button_pressed) {
BRoster roster;
+5 -10
View File
@@ -9,21 +9,16 @@
#define _POWER_BUTTON_MONITOR_H
#include <Handler.h>
#define POLL_POWER_BUTTON_STATUS 'ppbs'
class PowerButtonMonitor : public BHandler {
class PowerButtonMonitor {
public:
PowerButtonMonitor();
virtual ~PowerButtonMonitor();
~PowerButtonMonitor();
virtual void MessageReceived(BMessage *msg);
void HandleEvent();
int FD() const { return fFD; }
private:
int fPowerButtonFD;
int fFD;
};
+63 -14
View File
@@ -1,22 +1,30 @@
/*
* Copyright 2005-2013, Haiku, Inc.
* Distributed under the terms of the MIT license.
* Copyright 2013, Jérôme Duval, [email protected].
* Copyright 2005, Nathan Whitehorn.
*
* Authors:
* Nathan Whitehorn
* Distributed under the terms of the MIT License.
*/
#include "lid_monitor.h"
#include "power_button_monitor.h"
#include <Application.h>
#include <MessageRunner.h>
class PowerManagementDaemon : public BApplication {
public:
PowerManagementDaemon();
virtual ~PowerManagementDaemon();
public:
PowerManagementDaemon();
virtual ~PowerManagementDaemon();
private:
void _EventLoop();
static status_t _EventLooper(void *arg);
thread_id fEventThread;
PowerButtonMonitor* fPowerButtonMonitor;
LidMonitor* fLidMonitor;
bool fQuitRequested;
};
@@ -32,16 +40,57 @@ main(void)
PowerManagementDaemon::PowerManagementDaemon()
:
BApplication("application/x-vnd.Haiku-powermanagement")
BApplication("application/x-vnd.Haiku-powermanagement"),
fPowerButtonMonitor(NULL),
fQuitRequested(false)
{
PowerButtonMonitor *powerButtonMonitor = new PowerButtonMonitor();
AddHandler(powerButtonMonitor);
new BMessageRunner(BMessenger(powerButtonMonitor,this),
new BMessage(POLL_POWER_BUTTON_STATUS), 5e5 /* twice a second */);
fPowerButtonMonitor = new PowerButtonMonitor;
fLidMonitor = new LidMonitor;
fEventThread = spawn_thread(_EventLooper, "_power_daemon_event_loop_",
B_NORMAL_PRIORITY, this);
if (fEventThread < B_OK)
return;
if (resume_thread(fEventThread) < B_OK) {
kill_thread(fEventThread);
fEventThread = -1;
return;
}
}
PowerManagementDaemon::~PowerManagementDaemon()
{
fQuitRequested = true;
delete fPowerButtonMonitor;
delete fLidMonitor;
status_t status;
wait_for_thread(fEventThread, &status);
}
status_t
PowerManagementDaemon::_EventLooper(void* arg)
{
PowerManagementDaemon* self = (PowerManagementDaemon*)arg;
self->_EventLoop();
return B_OK;
}
void
PowerManagementDaemon::_EventLoop()
{
while (!fQuitRequested) {
object_wait_info info[] = {
{ fPowerButtonMonitor->FD(), B_OBJECT_TYPE_FD, B_EVENT_READ },
{ fLidMonitor->FD(), B_OBJECT_TYPE_FD, B_EVENT_READ }
};
if (wait_for_objects_etc(info, 2, 0, 1000000LL) < B_OK)
continue;
if (info[0].events & B_EVENT_READ)
fPowerButtonMonitor->HandleEvent();
if (info[1].events & B_EVENT_READ)
fLidMonitor->HandleEvent();
}
}