power_daemon: Refactor to handle multiple exported power devices.

- Each PowerMonitor now exports a set of descriptors rather than
  only a single one. This allows e.g. PowerButtonMonitor to watch
  multiple possible button event sources rather than one.

This gets power button working again on some hardware that exports
multiple ACPI power buttons, but offers no obvious way to determine
which one is actually active/being used. In the long term though, it'd
be nice to have a well-defined kernel power event interface that an app
could subscribe to, rather than having to watch individual devfs
descriptors.

Thanks to tqh and korli for advice/review.
This commit is contained in:
Rene Gollent 2014-08-24 14:16:21 -04:00
parent 74f7623716
commit bf29cdd777
7 changed files with 83 additions and 39 deletions

View File

@ -10,4 +10,4 @@ Server power_daemon :
power_button_monitor.cpp
;
LinkAgainst power_daemon : be [ TargetLibsupc++ ] ;
LinkAgainst power_daemon : be [ TargetLibstdc++ TargetLibsupc++ ] ;

View File

@ -18,27 +18,26 @@
LidMonitor::LidMonitor()
{
fFD = open("/dev/power/acpi_lid/0", O_RDONLY);
int fd = open("/dev/power/acpi_lid/0", O_RDONLY);
if (fd > 0)
fFDs.insert(fd);
}
LidMonitor::~LidMonitor()
{
if (fFD > 0)
close(fFD);
for (std::set<int>::iterator it = fFDs.begin(); it != fFDs.end(); ++it)
close(*it);
}
void
LidMonitor::HandleEvent()
LidMonitor::HandleEvent(int fd)
{
if (fFD <= 0)
uint8 status;
if (read(fd, &status, 1) != 1)
return;
uint8 status;
read(fFD, &status, 1);
if (status == 1) {
if (status == 1)
printf("lid status 1\n");
}
}

View File

@ -17,11 +17,12 @@ public:
LidMonitor();
virtual ~LidMonitor();
virtual void HandleEvent();
virtual void HandleEvent(int fd);
virtual int FD() const { return fFD; }
virtual const std::set<int>&
FDs() const { return fFDs; }
private:
int fFD;
std::set<int> fFDs;
};

View File

@ -1,41 +1,62 @@
/*
* Copyright 2005-2013, Haiku, Inc.
* Copyright 2005-2014, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Rene Gollent
* Nathan Whitehorn
*/
#include "power_button_monitor.h"
#include <string.h>
#include <Directory.h>
#include <Messenger.h>
#include <Roster.h>
#include <String.h>
#include <RosterPrivate.h>
static const char* kBasePath = "/dev/power/button";
PowerButtonMonitor::PowerButtonMonitor()
:
fFDs()
{
fFD = open("/dev/power/button/power", O_RDONLY);
BDirectory dir;
if (dir.SetTo(kBasePath) != B_OK)
return;
entry_ref ref;
while (dir.GetNextRef(&ref) == B_OK) {
if (strncmp(ref.name, "power", 5) == 0) {
BString path;
path.SetToFormat("%s/%s", kBasePath, ref.name);
int fd = open(path.String(), O_RDONLY);
if (fd > 0)
fFDs.insert(fd);
}
}
}
PowerButtonMonitor::~PowerButtonMonitor()
{
if (fFD > 0)
close(fFD);
for (std::set<int>::iterator it = fFDs.begin(); it != fFDs.end(); ++it)
close(*it);
}
void
PowerButtonMonitor::HandleEvent()
PowerButtonMonitor::HandleEvent(int fd)
{
if (fFD <= 0)
return;
uint8 button_pressed;
read(fFD, &button_pressed, 1);
if (read(fd, &button_pressed, 1) != 1)
return;
if (button_pressed) {
BRoster roster;

View File

@ -1,8 +1,9 @@
/*
* Copyright 2005-2013, Haiku, Inc.
* Copyright 2005-2014, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Rene Gollent
* Nathan Whitehorn
*/
#ifndef _POWER_BUTTON_MONITOR_H
@ -17,11 +18,12 @@ public:
PowerButtonMonitor();
virtual ~PowerButtonMonitor();
virtual void HandleEvent();
virtual void HandleEvent(int fd);
virtual int FD() const { return fFD; }
virtual const std::set<int>&
FDs() const { return fFDs; }
private:
int fFD;
std::set<int> fFDs;
};

View File

@ -1,5 +1,6 @@
/*
* Copyright 2013, Jérôme Duval, korli@users.berlios.de.
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2005, Nathan Whitehorn.
*
* Distributed under the terms of the MIT License.
@ -11,6 +12,8 @@
#include <Application.h>
#include <map>
class PowerManagementDaemon : public BApplication {
public:
@ -45,13 +48,13 @@ PowerManagementDaemon::PowerManagementDaemon()
fQuitRequested(false)
{
PowerMonitor* powerButtonMonitor = new PowerButtonMonitor;
if (powerButtonMonitor->FD() > 0)
if (powerButtonMonitor->FDs().size() > 0)
fPowerMonitors[fMonitorCount++] = powerButtonMonitor;
else
delete powerButtonMonitor;
PowerMonitor* lidMonitor = new LidMonitor;
if (lidMonitor->FD() > 0)
if (lidMonitor->FDs().size() > 0)
fPowerMonitors[fMonitorCount++] = lidMonitor;
else
delete lidMonitor;
@ -92,19 +95,32 @@ PowerManagementDaemon::_EventLoop()
{
if (fMonitorCount == 0)
return;
object_wait_info info[fMonitorCount];
std::map<int, PowerMonitor*> descriptorMap;
size_t fdCount = 0;
for (uint32 i = 0; i < fMonitorCount; i++)
fdCount += fPowerMonitors[i]->FDs().size();
object_wait_info info[fdCount];
uint32 index = 0;
for (uint32 i = 0; i < fMonitorCount; i++) {
info[i].object = fPowerMonitors[i]->FD();
info[i].type = B_OBJECT_TYPE_FD;
info[i].events = B_EVENT_READ;
const std::set<int>& fds = fPowerMonitors[i]->FDs();
for (std::set<int>::iterator it = fds.begin(); it != fds.end(); ++it) {
info[index].object = *it;
info[index].type = B_OBJECT_TYPE_FD;
info[index].events = B_EVENT_READ;
descriptorMap[*it] = fPowerMonitors[i];
++index;
}
}
while (!fQuitRequested) {
if (wait_for_objects(info, fMonitorCount) < B_OK)
if (wait_for_objects(info, fdCount) < B_OK)
continue;
// handle events and reset events
for (uint32 i = 0; i < fMonitorCount; i++) {
for (uint32 i = 0; i < fdCount; i++) {
if (info[i].events & B_EVENT_READ)
fPowerMonitors[i]->HandleEvent();
descriptorMap[info[i].object]->HandleEvent(info[i].object);
else
info[i].events = B_EVENT_READ;
}

View File

@ -1,21 +1,26 @@
/*
* Copyright 2013, Haiku, Inc.
* Copyright 2013-2014, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Jérôme Duval, korli@users.berlios.de.
* Rene Gollent, rene@gollent.com.
*/
#ifndef _POWER_MONITOR_H
#define _POWER_MONITOR_H
#include <set>
class PowerMonitor {
public:
virtual ~PowerMonitor() {};
virtual void HandleEvent() = 0;
virtual void HandleEvent(int fd) = 0;
virtual int FD() const = 0;
virtual const std::set<int>&
FDs() const = 0;
};