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:
@@ -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[] = {
|
||||
|
||||
@@ -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
|
||||
;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user