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 ; SubDir HAIKU_TOP src add-ons kernel drivers power acpi_button ;
UsePrivateKernelHeaders ;
KernelAddon acpi_button : KernelAddon acpi_button :
acpi_button.cpp acpi_button.cpp
; ;
@@ -10,6 +10,8 @@
#include <ACPI.h> #include <ACPI.h>
#include <fs/select_sync_pool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -40,6 +42,7 @@ typedef struct acpi_ns_device_info {
uint32 type; uint32 type;
bool fixed; bool fixed;
uint8 last_status; uint8 last_status;
select_sync_pool* select_pool;
} acpi_button_device_info; } 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) { if (value == ACPI_NOTIFY_BUTTON_SLEEP) {
TRACE("sleep\n"); TRACE("sleep\n");
device->last_status = 1; 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) { } else if (value == ACPI_NOTIFY_BUTTON_WAKEUP) {
TRACE("wakeup\n"); TRACE("wakeup\n");
} else { } else {
@@ -65,6 +70,8 @@ acpi_button_fixed_handler(void *context)
acpi_button_device_info *device = (acpi_button_device_info *)context; acpi_button_device_info *device = (acpi_button_device_info *)context;
TRACE("sleep\n"); TRACE("sleep\n");
device->last_status = 1; device->last_status = 1;
if (device->select_pool != NULL)
notify_select_event_pool(device->select_pool, B_SELECT_READ);
return B_OK; return B_OK;
} }
@@ -106,6 +113,7 @@ acpi_button_init_device(void *_cookie, void **cookie)
else else
return B_ERROR; return B_ERROR;
device->last_status = 0; device->last_status = 0;
device->select_pool = NULL;
if (device->fixed) { if (device->fixed) {
sAcpi->reset_fixed_event(device->type); 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 static status_t
acpi_button_close (void* cookie) acpi_button_close (void* cookie)
{ {
@@ -330,9 +373,8 @@ struct device_module_info acpi_button_device_module = {
acpi_button_write, acpi_button_write,
NULL, NULL,
acpi_button_control, acpi_button_control,
acpi_button_select,
NULL, acpi_button_deselect
NULL
}; };
module_info *modules[] = { module_info *modules[] = {
@@ -1,5 +1,7 @@
SubDir HAIKU_TOP src add-ons kernel drivers power acpi_lid ; SubDir HAIKU_TOP src add-ons kernel drivers power acpi_lid ;
UsePrivateKernelHeaders ;
KernelAddon acpi_lid : KernelAddon acpi_lid :
acpi_lid.cpp acpi_lid.cpp
; ;
@@ -7,6 +7,8 @@
#include <ACPI.h> #include <ACPI.h>
#include <fs/select_sync_pool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -16,13 +18,15 @@
#define ACPI_LID_DEVICE_MODULE_NAME "drivers/power/acpi_lid/device_v1" #define ACPI_LID_DEVICE_MODULE_NAME "drivers/power/acpi_lid/device_v1"
#define ACPI_NOTIFY_STATUS_CHANGED 0x80
/* Base Namespace devices are published to */ /* Base Namespace devices are published to */
#define ACPI_LID_BASENAME "power/acpi_lid/%d" #define ACPI_LID_BASENAME "power/acpi_lid/%d"
// name of pnp generator of path ids // name of pnp generator of path ids
#define ACPI_LID_PATHID_GENERATOR "acpi_lid/path_id" #define ACPI_LID_PATHID_GENERATOR "acpi_lid/path_id"
#define TRACE_LID //#define TRACE_LID
#ifdef TRACE_LID #ifdef TRACE_LID
# define TRACE(x...) dprintf("acpi_lid: "x) # define TRACE(x...) dprintf("acpi_lid: "x)
#else #else
@@ -30,6 +34,7 @@
#endif #endif
#define ERROR(x...) dprintf("acpi_lid: "x) #define ERROR(x...) dprintf("acpi_lid: "x)
static device_manager_info *sDeviceManager; static device_manager_info *sDeviceManager;
@@ -38,16 +43,43 @@ typedef struct acpi_ns_device_info {
acpi_device_module_info *acpi; acpi_device_module_info *acpi;
acpi_device acpi_cookie; acpi_device acpi_cookie;
uint8 last_status; uint8 last_status;
bool updated;
select_sync_pool* select_pool;
} acpi_lid_device_info; } acpi_lid_device_info;
static void 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) { acpi_data buf;
dprintf("acpi_lid: status changed\n"); 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 { } 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 static status_t
acpi_lid_read(void* _cookie, off_t position, void *buf, size_t* num_bytes) 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 static status_t
acpi_lid_close (void* cookie) acpi_lid_close (void* cookie)
{ {
@@ -189,20 +263,8 @@ acpi_lid_init_driver(device_node *node, void **_driverCookie)
} }
device->last_status = 0; device->last_status = 0;
acpi_data buf; device->updated = false;
buf.pointer = NULL; device->select_pool = 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);
}
*_driverCookie = device; *_driverCookie = device;
return B_OK; return B_OK;
@@ -282,9 +344,8 @@ struct device_module_info acpi_lid_device_module = {
acpi_lid_write, acpi_lid_write,
NULL, NULL,
acpi_lid_control, acpi_lid_control,
acpi_lid_select,
NULL, acpi_lid_deselect
NULL
}; };
module_info *modules[] = { module_info *modules[] = {
+1
View File
@@ -5,6 +5,7 @@ UsePrivateHeaders app ;
AddResources power_daemon : power_daemon.rdef ; AddResources power_daemon : power_daemon.rdef ;
Server power_daemon : Server power_daemon :
lid_monitor.cpp
power_daemon.cpp power_daemon.cpp
power_button_monitor.cpp power_button_monitor.cpp
; ;
+6 -11
View File
@@ -16,31 +16,26 @@
PowerButtonMonitor::PowerButtonMonitor() PowerButtonMonitor::PowerButtonMonitor()
:
BHandler ("power_button_monitor")
{ {
fPowerButtonFD = open("/dev/power/button/power", O_RDONLY); fFD = open("/dev/power/button/power", O_RDONLY);
} }
PowerButtonMonitor::~PowerButtonMonitor() PowerButtonMonitor::~PowerButtonMonitor()
{ {
if (fPowerButtonFD > 0) if (fFD > 0)
close(fPowerButtonFD); close(fFD);
} }
void void
PowerButtonMonitor::MessageReceived(BMessage *msg) PowerButtonMonitor::HandleEvent()
{ {
if (msg->what != POLL_POWER_BUTTON_STATUS) if (fFD <= 0)
return;
if (fPowerButtonFD <= 0)
return; return;
uint8 button_pressed; uint8 button_pressed;
read(fPowerButtonFD, &button_pressed, 1); read(fFD, &button_pressed, 1);
if (button_pressed) { if (button_pressed) {
BRoster roster; BRoster roster;
+5 -10
View File
@@ -9,21 +9,16 @@
#define _POWER_BUTTON_MONITOR_H #define _POWER_BUTTON_MONITOR_H
#include <Handler.h> class PowerButtonMonitor {
#define POLL_POWER_BUTTON_STATUS 'ppbs'
class PowerButtonMonitor : public BHandler {
public: public:
PowerButtonMonitor(); PowerButtonMonitor();
virtual ~PowerButtonMonitor(); ~PowerButtonMonitor();
virtual void MessageReceived(BMessage *msg); void HandleEvent();
int FD() const { return fFD; }
private: private:
int fPowerButtonFD; int fFD;
}; };
+63 -14
View File
@@ -1,22 +1,30 @@
/* /*
* Copyright 2005-2013, Haiku, Inc. * Copyright 2013, Jérôme Duval, korli@users.berlios.de.
* Distributed under the terms of the MIT license. * Copyright 2005, Nathan Whitehorn.
* *
* Authors: * Distributed under the terms of the MIT License.
* Nathan Whitehorn
*/ */
#include "lid_monitor.h"
#include "power_button_monitor.h" #include "power_button_monitor.h"
#include <Application.h> #include <Application.h>
#include <MessageRunner.h>
class PowerManagementDaemon : public BApplication { class PowerManagementDaemon : public BApplication {
public: public:
PowerManagementDaemon(); PowerManagementDaemon();
virtual ~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() PowerManagementDaemon::PowerManagementDaemon()
: :
BApplication("application/x-vnd.Haiku-powermanagement") BApplication("application/x-vnd.Haiku-powermanagement"),
fPowerButtonMonitor(NULL),
fQuitRequested(false)
{ {
PowerButtonMonitor *powerButtonMonitor = new PowerButtonMonitor(); fPowerButtonMonitor = new PowerButtonMonitor;
AddHandler(powerButtonMonitor); fLidMonitor = new LidMonitor;
fEventThread = spawn_thread(_EventLooper, "_power_daemon_event_loop_",
new BMessageRunner(BMessenger(powerButtonMonitor,this), B_NORMAL_PRIORITY, this);
new BMessage(POLL_POWER_BUTTON_STATUS), 5e5 /* twice a second */); if (fEventThread < B_OK)
return;
if (resume_thread(fEventThread) < B_OK) {
kill_thread(fEventThread);
fEventThread = -1;
return;
}
} }
PowerManagementDaemon::~PowerManagementDaemon() 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();
}
} }