mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-11 21:32:57 +00:00
parent
d48219138c
commit
7556663e7e
@ -12,7 +12,9 @@ set build_components {
|
||||
core init
|
||||
drivers/input
|
||||
drivers/timer
|
||||
server/acpi_input
|
||||
server/dynamic_rom
|
||||
server/input_merger
|
||||
server/report_rom
|
||||
app/acpica
|
||||
test/input
|
||||
@ -91,6 +93,11 @@ append config {
|
||||
</provides>
|
||||
<config verbose="yes">
|
||||
<policy label="platform_drv -> acpi_ready" report="acpica -> acpi_ready"/>
|
||||
<policy label="acpi_input -> acpi_ac" report="acpica -> acpi_ac"/>
|
||||
<policy label="acpi_input -> acpi_battery" report="acpica -> acpi_battery"/>
|
||||
<policy label="acpi_input -> acpi_ec" report="acpica -> acpi_ec"/>
|
||||
<policy label="acpi_input -> acpi_fixed" report="acpica -> acpi_fixed"/>
|
||||
<policy label="acpi_input -> acpi_lid" report="acpica -> acpi_lid"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
@ -123,6 +130,21 @@ append config {
|
||||
</config>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="input_merger">
|
||||
<resource name="RAM" quantum="1M" />
|
||||
<provides> <service name="Input" /> </provides>
|
||||
<config>
|
||||
<input label="ps2" />
|
||||
<input label="acpi" />
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Input" label="ps2"> <child name="ps2_drv" /> </service>
|
||||
<service name="Input" label="acpi"> <child name="acpi_input" /> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
@ -141,11 +163,38 @@ append config {
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
|
||||
<service name="Input"> <child name="ps2_drv"/> </service>
|
||||
<service name="Input"> <child name="input_merger"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="acpi_input">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config>
|
||||
<!-- example mapping - adapt to your target notebook !!! -->
|
||||
<!-- as="PRESS_RELEASE" is default if nothing specified -->
|
||||
<map acpi="ec" value="25" to_key="KEY_VENDOR"/>
|
||||
<map acpi="ec" value="20" to_key="KEY_BRIGHTNESSUP"/>
|
||||
<map acpi="ec" value="21" to_key="KEY_BRIGHTNESSDOWN"/>
|
||||
<map acpi="fixed" value="0" to_key="KEY_POWER" as="PRESS_RELEASE"/>
|
||||
<map acpi="lid" value="CLOSED" to_key="KEY_SLEEP" as="PRESS"/>
|
||||
<map acpi="lid" value="OPEN" to_key="KEY_SLEEP" as="RELEASE"/>
|
||||
<map acpi="ac" value="ONLINE" to_key="KEY_WAKEUP"/>
|
||||
<map acpi="ac" value="OFFLINE" to_key="KEY_SLEEP"/>
|
||||
<map acpi="battery" value="0" to_key="KEY_BATTERY"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="ROM" label="acpi_ac"> <child name="acpi_state"/> </service>
|
||||
<service name="ROM" label="acpi_battery"> <child name="acpi_state"/> </service>
|
||||
<service name="ROM" label="acpi_ec"> <child name="acpi_state"/> </service>
|
||||
<service name="ROM" label="acpi_fixed"> <child name="acpi_state"/> </service>
|
||||
<service name="ROM" label="acpi_lid"> <child name="acpi_state"/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append config {
|
||||
@ -159,9 +208,11 @@ set boot_modules {
|
||||
ld.lib.so libc.lib.so
|
||||
timer
|
||||
ps2_drv
|
||||
input_merger
|
||||
report_rom
|
||||
dynamic_rom
|
||||
acpica
|
||||
acpi_input
|
||||
debug-acpica
|
||||
test-input
|
||||
}
|
||||
|
404
repos/libports/src/server/acpi_input/main.cc
Normal file
404
repos/libports/src/server/acpi_input/main.cc
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* \brief Component reading the reported ACPI ROMs and transforming it
|
||||
* to Genode Input events. The actual mapping must be configured
|
||||
* explicitly externally.
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* base includes */
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
#include <util/avl_tree.h>
|
||||
|
||||
/* os includes */
|
||||
#include <input/component.h>
|
||||
#include <input/root.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
|
||||
namespace Transform {
|
||||
using Genode::Xml_node;
|
||||
using Genode::String;
|
||||
|
||||
struct Main;
|
||||
class Keys;
|
||||
};
|
||||
|
||||
|
||||
class Transform::Keys : public Genode::Avl_node<Transform::Keys> {
|
||||
|
||||
public:
|
||||
|
||||
enum Type { PRESS_RELEASE, PRESS, RELEASE };
|
||||
|
||||
private:
|
||||
|
||||
const Input::Keycode _code;
|
||||
const long _acpi_value;
|
||||
unsigned long _acpi_count = 0;
|
||||
bool _first = true;
|
||||
Type _type;
|
||||
|
||||
static Genode::Avl_tree<Keys> _map_ec;
|
||||
static Genode::Avl_tree<Keys> _map_special;
|
||||
|
||||
Keys *_find_by_acpi_value(long acpi_value)
|
||||
{
|
||||
if (acpi_value == _acpi_value) return this;
|
||||
Keys *key = this->child(acpi_value > _acpi_value);
|
||||
return key ? key->_find_by_acpi_value(acpi_value) : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Keys(Input::Keycode code, long acpi_value, Type type)
|
||||
: _code(code), _acpi_value(acpi_value), _type(type) { }
|
||||
|
||||
Input::Keycode key_code() const { return _code; }
|
||||
|
||||
bool higher(Keys *k) const { return k->_acpi_value > _acpi_value; }
|
||||
|
||||
Type const type() { return _type; }
|
||||
|
||||
unsigned long update_count(unsigned long acpi_count)
|
||||
{
|
||||
unsigned long diff = acpi_count > _acpi_count ?
|
||||
acpi_count - _acpi_count : 0;
|
||||
|
||||
/*
|
||||
* If we get the first time this ACPI event, than we don't
|
||||
* use the diff value, because it could be arbitrarily.
|
||||
*/
|
||||
if (_first) {
|
||||
_first = false;
|
||||
diff = 1;
|
||||
}
|
||||
|
||||
_acpi_count = acpi_count;
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static Keys * find_by_ec(long acpi_code)
|
||||
{
|
||||
Keys * head = _map_ec.first();
|
||||
if (!head)
|
||||
return head;
|
||||
|
||||
return head->_find_by_acpi_value(acpi_code);
|
||||
}
|
||||
|
||||
static Keys * find_by_fixed(long acpi_code)
|
||||
{
|
||||
Keys * head = _map_special.first();
|
||||
if (!head)
|
||||
return head;
|
||||
|
||||
return head->_find_by_acpi_value(acpi_code);
|
||||
}
|
||||
|
||||
static void insert_ec(Keys * key) { _map_ec.insert(key); }
|
||||
static void insert_special(Keys * key) { _map_special.insert(key); }
|
||||
};
|
||||
|
||||
|
||||
Genode::Avl_tree<Transform::Keys> Transform::Keys::_map_ec;
|
||||
Genode::Avl_tree<Transform::Keys> Transform::Keys::_map_special;
|
||||
|
||||
|
||||
struct Transform::Main {
|
||||
|
||||
enum {
|
||||
ACPI_POWER_BUTTON, ACPI_LID_OPEN, ACPI_LID_CLOSED,
|
||||
ACPI_AC_ONLINE, ACPI_AC_OFFLINE, ACPI_BATTERY
|
||||
};
|
||||
|
||||
Genode::Heap _heap;
|
||||
|
||||
Genode::Attached_rom_dataspace _config;
|
||||
Genode::Attached_rom_dataspace _acpi_ac;
|
||||
Genode::Attached_rom_dataspace _acpi_battery;
|
||||
Genode::Attached_rom_dataspace _acpi_ec;
|
||||
Genode::Attached_rom_dataspace _acpi_fixed;
|
||||
Genode::Attached_rom_dataspace _acpi_lid;
|
||||
|
||||
Genode::Signal_handler<Main> _dispatch_acpi_ac;
|
||||
Genode::Signal_handler<Main> _dispatch_acpi_battery;
|
||||
Genode::Signal_handler<Main> _dispatch_acpi_ec;
|
||||
Genode::Signal_handler<Main> _dispatch_acpi_fixed;
|
||||
Genode::Signal_handler<Main> _dispatch_acpi_lid;
|
||||
|
||||
Input::Session_component _session;
|
||||
Input::Root_component _root;
|
||||
|
||||
Main(Genode::Env &env)
|
||||
:
|
||||
_heap(env.ram(), env.rm()),
|
||||
_config(env, "config"),
|
||||
_acpi_ac(env, "acpi_ac"),
|
||||
_acpi_battery(env, "acpi_battery"),
|
||||
_acpi_ec(env, "acpi_ec"),
|
||||
_acpi_fixed(env, "acpi_fixed"),
|
||||
_acpi_lid(env, "acpi_lid"),
|
||||
_dispatch_acpi_ac(env.ep(), *this, &Main::check_acpi_ac),
|
||||
_dispatch_acpi_battery(env.ep(), *this, &Main::check_acpi_battery),
|
||||
_dispatch_acpi_ec(env.ep(), *this, &Main::check_acpi_ec),
|
||||
_dispatch_acpi_fixed(env.ep(), *this, &Main::check_acpi_fixed),
|
||||
_dispatch_acpi_lid(env.ep(), *this, &Main::check_acpi_lid),
|
||||
_root(env.ep().rpc_ep(), _session)
|
||||
{
|
||||
Xml_node config(_config.local_addr<char>(), _config.size());
|
||||
config.for_each_sub_node("map", [&] (Xml_node map_node) {
|
||||
try {
|
||||
long acpi_value = 0;
|
||||
Genode::String<8> acpi_type;
|
||||
Genode::String<8> acpi_value_string;
|
||||
Genode::String<32> to_key;
|
||||
|
||||
Genode::String<16> key_type("PRESS_RELEASE");
|
||||
Keys::Type press_release = Keys::Type::PRESS_RELEASE;
|
||||
|
||||
map_node.attribute("acpi").value(&acpi_type);
|
||||
map_node.attribute("to_key").value(&to_key);
|
||||
try {
|
||||
map_node.attribute("as").value(&key_type);
|
||||
if (key_type == "PRESS")
|
||||
press_release = Keys::Type::PRESS;
|
||||
else if (key_type == "RELEASE")
|
||||
press_release = Keys::Type::RELEASE;
|
||||
else if (key_type != "PRESS_RELEASE")
|
||||
throw 0;
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
if (acpi_type == "lid" || acpi_type == "ac") {
|
||||
map_node.attribute("value").value(&acpi_value_string);
|
||||
|
||||
if (acpi_type == "lid") {
|
||||
if (acpi_value_string == "OPEN")
|
||||
acpi_value = ACPI_LID_OPEN;
|
||||
else if (acpi_value_string == "CLOSED")
|
||||
acpi_value = ACPI_LID_CLOSED;
|
||||
else throw 1;
|
||||
} else
|
||||
if (acpi_type == "ac") {
|
||||
if (acpi_value_string == "ONLINE")
|
||||
acpi_value = ACPI_AC_ONLINE;
|
||||
else if (acpi_value_string == "OFFLINE")
|
||||
acpi_value = ACPI_AC_OFFLINE;
|
||||
else throw 2;
|
||||
} else
|
||||
throw 3;
|
||||
} else
|
||||
map_node.attribute("value").value(&acpi_value);
|
||||
|
||||
Input::Keycode key_code = Input::Keycode::KEY_UNKNOWN;
|
||||
|
||||
if (to_key == "KEY_VENDOR")
|
||||
key_code = Input::Keycode::KEY_VENDOR;
|
||||
else if (to_key == "KEY_POWER")
|
||||
key_code = Input::Keycode::KEY_POWER;
|
||||
else if (to_key == "KEY_SLEEP")
|
||||
key_code = Input::Keycode::KEY_SLEEP;
|
||||
else if (to_key == "KEY_WAKEUP")
|
||||
key_code = Input::Keycode::KEY_WAKEUP;
|
||||
else if (to_key == "KEY_BATTERY")
|
||||
key_code = Input::Keycode::KEY_BATTERY;
|
||||
else if (to_key == "KEY_BRIGHTNESSUP")
|
||||
key_code = Input::Keycode::KEY_BRIGHTNESSUP;
|
||||
else if (to_key == "KEY_BRIGHTNESSDOWN")
|
||||
key_code = Input::Keycode::KEY_BRIGHTNESSDOWN;
|
||||
|
||||
if (key_code == Input::Keycode::KEY_UNKNOWN)
|
||||
throw 4;
|
||||
|
||||
if (acpi_type == "ec")
|
||||
Keys::insert_ec(new (_heap) Keys(key_code, acpi_value,
|
||||
press_release));
|
||||
else if (acpi_type == "fixed")
|
||||
Keys::insert_special(new (_heap) Keys(key_code,
|
||||
ACPI_POWER_BUTTON,
|
||||
press_release));
|
||||
else if (acpi_type == "lid" || acpi_type == "ac")
|
||||
Keys::insert_special(new (_heap) Keys(key_code, acpi_value,
|
||||
press_release));
|
||||
else if (acpi_type == "battery")
|
||||
Keys::insert_special(new (_heap) Keys(key_code,
|
||||
ACPI_BATTERY,
|
||||
press_release));
|
||||
else
|
||||
throw 5;
|
||||
} catch (...) {
|
||||
String<64> invalid_node(map_node.addr(), map_node.size());
|
||||
Genode::error("map item : '", invalid_node.string(), "'");
|
||||
/* we want a well formated configuration ! - die */
|
||||
class Invalid_config {} exception;
|
||||
throw exception;
|
||||
}
|
||||
});
|
||||
|
||||
_acpi_ac.sigh(_dispatch_acpi_ac);
|
||||
_acpi_battery.sigh(_dispatch_acpi_battery);
|
||||
_acpi_ec.sigh(_dispatch_acpi_ec);
|
||||
_acpi_fixed.sigh(_dispatch_acpi_fixed);
|
||||
_acpi_lid.sigh(_dispatch_acpi_lid);
|
||||
|
||||
env.parent().announce(env.ep().manage(_root));
|
||||
|
||||
/* check for initial valid ACPI data */
|
||||
check_acpi_ac();
|
||||
check_acpi_battery();
|
||||
check_acpi_ec();
|
||||
check_acpi_fixed();
|
||||
check_acpi_lid();
|
||||
}
|
||||
|
||||
void check_acpi_ec()
|
||||
{
|
||||
_acpi_ec.update();
|
||||
|
||||
if (!_acpi_ec.is_valid()) return;
|
||||
|
||||
Xml_node ec_event(_acpi_ec.local_addr<char>(), _acpi_ec.size());
|
||||
|
||||
ec_event.for_each_sub_node("ec", [&] (Xml_node ec_node) {
|
||||
ec_node.for_each_sub_node("data", [&] (Xml_node data_node) {
|
||||
try {
|
||||
long acpi_value = 0;
|
||||
unsigned long acpi_count = 0;
|
||||
|
||||
data_node.attribute("value").value(&acpi_value);
|
||||
data_node.attribute("count").value(&acpi_count);
|
||||
|
||||
Keys * key = Keys::find_by_ec(acpi_value);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
if (!key->update_count(acpi_count))
|
||||
return;
|
||||
|
||||
submit_input(key);
|
||||
} catch (...) { /* be robust - ignore ill-formated ACPI data */ }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void submit_input(Keys * key)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
if (key->type() == Keys::Type::PRESS_RELEASE ||
|
||||
key->type() == Keys::Type::PRESS)
|
||||
_session.submit(Input::Event(Input::Event::PRESS, key->key_code(),
|
||||
0, 0, 0, 0));
|
||||
if (key->type() == Keys::Type::PRESS_RELEASE ||
|
||||
key->type() == Keys::Type::RELEASE)
|
||||
_session.submit(Input::Event(Input::Event::RELEASE,
|
||||
key->key_code(), 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
void check_acpi_fixed()
|
||||
{
|
||||
_acpi_fixed.update();
|
||||
|
||||
if (!_acpi_fixed.is_valid()) return;
|
||||
|
||||
Xml_node fixed_event(_acpi_fixed.local_addr<char>(), _acpi_fixed.size());
|
||||
|
||||
fixed_event.for_each_sub_node("power_button", [&] (Xml_node pw_node) {
|
||||
try {
|
||||
bool pressed = false;
|
||||
unsigned long acpi_count = 0;
|
||||
|
||||
pw_node.attribute("value").value(&pressed);
|
||||
pw_node.attribute("count").value(&acpi_count);
|
||||
|
||||
Keys * key = Keys::find_by_fixed(ACPI_POWER_BUTTON);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
if (!key->update_count(acpi_count) && pressed)
|
||||
return;
|
||||
|
||||
submit_input(key);
|
||||
} catch (...) { /* be robust - ignore ill-formated ACPI data */ }
|
||||
});
|
||||
}
|
||||
|
||||
void check_acpi_battery()
|
||||
{
|
||||
_acpi_battery.update();
|
||||
|
||||
if (!_acpi_battery.is_valid()) return;
|
||||
|
||||
/* make use of it if we need to ... */
|
||||
Xml_node battery_node(_acpi_battery.local_addr<char>(),
|
||||
_acpi_battery.size());
|
||||
|
||||
submit_input(Keys::find_by_fixed(ACPI_BATTERY));
|
||||
}
|
||||
|
||||
void check_acpi_ac()
|
||||
{
|
||||
_acpi_ac.update();
|
||||
|
||||
if (!_acpi_ac.is_valid()) return;
|
||||
|
||||
Xml_node ac_node(_acpi_ac.local_addr<char>(), _acpi_ac.size());
|
||||
|
||||
_check_acpi(ac_node, "ac", ACPI_AC_ONLINE, ACPI_AC_OFFLINE);
|
||||
}
|
||||
|
||||
void check_acpi_lid()
|
||||
{
|
||||
_acpi_lid.update();
|
||||
|
||||
if (!_acpi_lid.is_valid()) return;
|
||||
|
||||
Xml_node lid_node(_acpi_lid.local_addr<char>(), _acpi_lid.size());
|
||||
|
||||
_check_acpi(lid_node, "lid", ACPI_LID_OPEN, ACPI_LID_CLOSED);
|
||||
}
|
||||
|
||||
void _check_acpi(Xml_node &xml_node, const char * sub_name,
|
||||
const unsigned state_o, const unsigned state_c)
|
||||
{
|
||||
xml_node.for_each_sub_node(sub_name, [&] (Xml_node node) {
|
||||
try {
|
||||
unsigned acpi_value = 0;
|
||||
unsigned long acpi_count = 0;
|
||||
|
||||
node.attribute("value").value(&acpi_value);
|
||||
node.attribute("count").value(&acpi_count);
|
||||
|
||||
enum { STATE_C = 0, STATE_O = 1 };
|
||||
|
||||
Keys * key = nullptr;
|
||||
if (acpi_value == STATE_O)
|
||||
key = Keys::find_by_fixed(state_o);
|
||||
if (acpi_value == STATE_C)
|
||||
key = Keys::find_by_fixed(state_c);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
if (!key->update_count(acpi_count))
|
||||
return;
|
||||
|
||||
if (acpi_value == STATE_C)
|
||||
submit_input(key);
|
||||
|
||||
if (acpi_value == STATE_O)
|
||||
submit_input(key);
|
||||
} catch (...) { /* be robust - ignore ill-formated ACPI data */ }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Genode::size_t Component::stack_size() { return 2 * 1024*sizeof(Genode::addr_t); }
|
||||
void Component::construct(Genode::Env &env) { static Transform::Main main(env); }
|
3
repos/libports/src/server/acpi_input/target.mk
Normal file
3
repos/libports/src/server/acpi_input/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = acpi_input
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
Loading…
x
Reference in New Issue
Block a user