acpica: add limited support for FUJ02E3 ACPI dev

The keys, mute, touchpad toggle (Fn-F4) and rfkill may be reported by some
Fujitsu machines via the ACPI FUJ02E3 ACPI device. With this commit limited
support to detect the 3 keys are added and will be reported as Genode report.
This commit is contained in:
Alexander Boettcher 2020-12-18 14:45:46 +01:00 committed by Norman Feske
parent d698e0876d
commit 1147f35972
3 changed files with 249 additions and 8 deletions

View File

@ -0,0 +1,195 @@
/*
* \brief Support some Fujitsu ACPI devices
* \author Alexander Boettcher
* \date 2021-01-06
*/
/*
* Copyright (C) 2020-2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
class Fuj02e3 : public Acpica::Reporter, Acpica::Callback<Fuj02e3>
{
private:
enum {
HID_FUJITSU_NOTIFY = 0x80,
};
enum Softkeys {
HID_FUJITSU_FLAG_RFKILL = 1u << 5,
HID_FUJITSU_FLAG_TOUCHPAD_TOGGLE = 1u << 26,
HID_FUJITSU_FLAG_MICROFON_MUTE = 1u << 29,
HID_FUJITSU_FLAG_SOFTKEYS = HID_FUJITSU_FLAG_RFKILL |
HID_FUJITSU_FLAG_TOUCHPAD_TOGGLE |
HID_FUJITSU_FLAG_MICROFON_MUTE
};
enum Operation {
HID_FUJITSU_FUNC_FLAGS = 1u << 12,
HID_FUJITSU_FUNC_BUTTON = HID_FUJITSU_FUNC_FLAGS | 2,
};
Acpica::Reportstate *_report;
Genode::uint64_t _features { 0 };
struct Data
{
Genode::uint64_t count;
Genode::uint64_t data;
bool triggered;
} _data[3] { };
template <typename RESULT>
ACPI_STATUS _call_acpi_function(ACPI_HANDLE const hid,
enum Operation const function,
RESULT &result, unsigned const op,
unsigned const feature,
unsigned const state)
{
ACPI_OBJECT_LIST para_in;
ACPI_OBJECT values[5];
values[0].Type = ACPI_TYPE_INTEGER;
values[0].Integer.Value = function;
values[1].Type = ACPI_TYPE_INTEGER;
values[1].Integer.Value = op;
values[2].Type = ACPI_TYPE_INTEGER;
values[2].Integer.Value = feature;
values[3].Type = ACPI_TYPE_INTEGER;
values[3].Integer.Value = state;
values[4].Type = 0;
values[4].Integer.Value = 0;
para_in.Count = 4;
para_in.Pointer = values;
return AcpiEvaluateObjectTyped(hid, ACPI_STRING("FUNC"),
&para_in, &result,
ACPI_TYPE_INTEGER);
}
template <typename RESULT>
ACPI_STATUS device_features(ACPI_HANDLE const hid, RESULT &result)
{
return _call_acpi_function(hid, HID_FUJITSU_FUNC_FLAGS, result,
0, 0, 0);
}
template <typename RESULT>
ACPI_STATUS soft_keys(ACPI_HANDLE const hid, RESULT &result)
{
return _call_acpi_function(hid, HID_FUJITSU_FUNC_FLAGS, result,
1, 0, 0);
}
template <typename RESULT>
ACPI_STATUS read_button(ACPI_HANDLE const hid, RESULT &result)
{
return _call_acpi_function(hid, HID_FUJITSU_FUNC_BUTTON, result,
1, 0, 0);
}
public:
Fuj02e3(void *report)
: _report(reinterpret_cast<Acpica::Reportstate *>(report))
{
if (_report)
_report->add_notify(this);
}
void handle(ACPI_HANDLE const hid, UINT32 const value)
{
if (value != HID_FUJITSU_NOTIFY)
return;
Acpica::Buffer<ACPI_OBJECT> irb;
ACPI_STATUS res = read_button(hid, irb);
if (ACPI_SUCCESS(res) && irb.object.Integer.Value != 0)
Genode::error("not implemented - irb value=",
Genode::Hex(irb.object.Integer.Value));
if (_features & HID_FUJITSU_FLAG_SOFTKEYS) {
Acpica::Buffer<ACPI_OBJECT> feature;
ACPI_STATUS res = soft_keys(hid, feature);
if (ACPI_SUCCESS(res))
{
UINT64 const value = feature.object.Integer.Value;
if (value & HID_FUJITSU_FLAG_RFKILL) {
_data[0].data = HID_FUJITSU_FLAG_RFKILL;
_data[0].triggered = true;
_data[0].count ++;
}
if (value & HID_FUJITSU_FLAG_TOUCHPAD_TOGGLE) {
_data[1].data = HID_FUJITSU_FLAG_TOUCHPAD_TOGGLE;
_data[1].triggered = true;
_data[1].count ++;
}
if (value & HID_FUJITSU_FLAG_MICROFON_MUTE) {
_data[2].data = HID_FUJITSU_FLAG_MICROFON_MUTE;
_data[2].triggered = true;
_data[2].count ++;
}
if (_report && (value & HID_FUJITSU_FLAG_SOFTKEYS))
_report->hid_event();
}
}
}
static ACPI_STATUS detect(ACPI_HANDLE hid, UINT32, void *m, void **)
{
Acpica::Main *main = reinterpret_cast<Acpica::Main *>(m);
Fuj02e3 *obj = new (main->heap) Fuj02e3(main->report);
ACPI_STATUS res = AcpiInstallNotifyHandler(hid, ACPI_DEVICE_NOTIFY,
handler, obj);
if (ACPI_FAILURE(res)) {
Genode::log("failed - ", __func__, " "
"res=", Genode::Hex(res), " Fujitsu adapter");
delete obj;
return AE_OK;
}
Genode::log("detected - Fujitsu HID");
Acpica::Buffer<ACPI_OBJECT> features;
res = obj->device_features(hid, features);
if (ACPI_FAILURE(res)) {
Genode::error("failed - '", __func__, "' "
"res=", Genode::Hex(res), " features");
}
obj->_features = features.object.Integer.Value;
return AE_OK;
}
void generate(Genode::Xml_generator &xml) override
{
xml.node("hid", [&] {
xml.attribute("device", "Fuj02e3");
for (unsigned i = 0; i < sizeof(_data) / sizeof(_data[0]); i++) {
xml.node("data", [&] {
xml.attribute("value", Genode::String<12>(Genode::Hex(_data[i].data)));
xml.attribute("count", _data[i].count);
if (_data[i].triggered) {
xml.append("triggered");
_data[i].triggered = false;
}
});
}
});
}
};

View File

@ -210,6 +210,7 @@ struct Acpica::Main
#include "sb.h"
#include "ec.h"
#include "bridge.h"
#include "fujitsu.h"
ACPI_STATUS init_pic_mode()
{
@ -250,7 +251,12 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready,
Acpica::init(env, heap, wait_acpi_ready, act_as_acpi_drv);
/* enable debugging: */
/* AcpiDbgLevel |= ACPI_LV_IO | ACPI_LV_INTERRUPTS | ACPI_LV_INIT_NAMES; */
if (false) {
AcpiDbgLevel |= ACPI_LV_IO | ACPI_LV_INTERRUPTS | ACPI_LV_INIT_NAMES;
AcpiDbgLayer |= ACPI_TABLES;
Genode::log("debugging level=", Genode::Hex(AcpiDbgLevel),
" layers=", Genode::Hex(AcpiDbgLayer));
}
ACPI_STATUS status = AcpiInitializeSubsystem();
if (status != AE_OK) {
@ -351,6 +357,13 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready,
return;
}
/* Fujitsu HID device */
status = AcpiGetDevices(ACPI_STRING("FUJ02E3"), Fuj02e3::detect, this, nullptr);
if (status != AE_OK) {
Genode::error("AcpiGetDevices (FUJ02E3) failed, status=", status);
return;
}
if (act_as_acpi_drv.enabled) {
/* lookup PCI root bridge */
void * pci_bridge = (void *)PCI_ROOT_HID_STRING;

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
* Copyright (C) 2016-2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -18,6 +18,22 @@ class Ec;
class Fixed;
class Lid;
namespace Acpica {
class Reportstate;
class Reporter;
};
class Acpica::Reporter : public Genode::List<Acpica::Reporter >::Element
{
public:
Reporter() { }
virtual void generate(Genode::Xml_generator &) = 0;
virtual ~Reporter() { }
};
class Acpica::Reportstate {
private:
@ -27,18 +43,21 @@ class Acpica::Reportstate {
Genode::Reporter _reporter_sb;
Genode::Reporter _reporter_ec;
Genode::Reporter _reporter_fix;
Genode::Reporter _reporter_hid;
bool _changed_lid = false;
bool _changed_ac = false;
bool _changed_sb = false;
bool _changed_ec = false;
bool _changed_fixed = false;
bool _changed_hid = false;
Genode::List<Callback<Battery> > _list_sb;
Genode::List<Callback<Ec> > _list_ec;
Genode::List<Callback<Ac> > _list_ac;
Callback<Fixed> * _fixed;
Callback<Lid> * _lid;
Genode::List<Callback<Battery> > _list_sb;
Genode::List<Callback<Ec> > _list_ec;
Genode::List<Callback<Ac> > _list_ac;
Genode::List<Acpica::Reporter> _list_hid;
Callback<Fixed> * _fixed;
Callback<Lid> * _lid;
public:
@ -48,7 +67,8 @@ class Acpica::Reportstate {
_reporter_ac (env, "acpi_ac"),
_reporter_sb (env, "acpi_battery"),
_reporter_ec (env, "acpi_ec"),
_reporter_fix(env, "acpi_fixed")
_reporter_fix(env, "acpi_fixed"),
_reporter_hid(env, "acpi_hid")
{ }
void add_notify(Acpica::Callback<Battery> * s) { _list_sb.insert(s); }
@ -56,6 +76,7 @@ class Acpica::Reportstate {
void add_notify(Acpica::Callback<Lid> * l) { _lid = l; }
void add_notify(Acpica::Callback<Ec> * e) { _list_ec.insert(e); }
void add_notify(Acpica::Callback<Ac> * a) { _list_ac.insert(a); }
void add_notify(Acpica::Reporter * r) { _list_hid.insert(r); }
void enable() {
_reporter_ac.enabled(true);
@ -63,6 +84,7 @@ class Acpica::Reportstate {
_reporter_sb.enabled(true);
_reporter_lid.enabled(true);
_reporter_fix.enabled(true);
_reporter_hid.enabled(true);
}
void battery_event() { _changed_sb = true; }
@ -70,6 +92,7 @@ class Acpica::Reportstate {
void fixed_event() { _changed_fixed = true; }
void lid_event() { _changed_lid = true; }
void ac_event() { _changed_ac = true; battery_event(); }
void hid_event() { _changed_hid = true; }
bool generate_report(bool force = false)
{
@ -116,6 +139,16 @@ class Acpica::Reportstate {
});
}
if (_changed_hid || force) {
_changed_hid = false;
if (_list_hid.first())
Genode::Reporter::Xml_generator xml(_reporter_hid, [&] () {
for (auto * hid = _list_hid.first(); hid; hid = hid->next())
hid->generate(xml);
});
}
return changed;
}
};