From Jérôme Duval <jerome.duval@xxxxxxxxx>:
Jérôme Duval has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/2485 ;)
Change subject: wmi: add ACPI WMI implementation
......................................................................
wmi: add ACPI WMI implementation
add a WMI Asus driver, to control keyboard backlight brightness.
---
A headers/private/wmi/wmi.h
A src/add-ons/kernel/drivers/wmi/Jamfile
A src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
A src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
A src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
A src/add-ons/kernel/drivers/wmi/WMIPrivate.h
6 files changed, 1,150 insertions(+), 0 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/85/2485/1
diff --git a/headers/private/wmi/wmi.h b/headers/private/wmi/wmi.h
new file mode 100644
index 0000000..b82676d
--- /dev/null
+++ b/headers/private/wmi/wmi.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _WMI_H_
+#define _WMI_H_
+
+
+#include <ACPI.h>
+#include <device_manager.h>
+#include <KernelExport.h>
+
+
+
+// Device node
+
+// guid (string)
+#define WMI_GUID_STRING_ITEM "wmi/guid_string"
+
+// node type
+#define WMI_DEVICE_TYPE_NAME "wmi/device/v1"
+
+// device cookie, issued by wmi bus manager
+typedef void* wmi_device;
+
+
+// bus manager device interface for peripheral driver
+typedef struct {
+ driver_module_info info;
+
+ status_t (*evaluate_method)(wmi_device device, uint8 instance,
+ uint32 methodId, const acpi_data* in, acpi_data* out);
+ status_t (*install_event_handler)(wmi_device device,
+ const char* guidString, acpi_notify_handler handler, void*
context);
+ status_t (*remove_event_handler)(wmi_device device,
+ const char* guidString);
+ status_t (*get_event_data)(wmi_device device, uint32 notify,
+ acpi_data* out);
+ const char* (*get_uid)(wmi_device device);
+} wmi_device_interface;
+
+
+#endif /* _WMI_H_ */
diff --git a/src/add-ons/kernel/drivers/wmi/Jamfile
b/src/add-ons/kernel/drivers/wmi/Jamfile
new file mode 100644
index 0000000..dcb773e
--- /dev/null
+++ b/src/add-ons/kernel/drivers/wmi/Jamfile
@@ -0,0 +1,11 @@
+SubDir HAIKU_TOP src add-ons kernel drivers wmi ;
+
+UsePrivateHeaders wmi ;
+UsePrivateKernelHeaders ;
+
+KernelAddon wmi :
+ WMIACPI.cpp
+ WMIAsus.cpp
+ WMIDevice.cpp
+ ;
+
diff --git a/src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
b/src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
new file mode 100644
index 0000000..5b59b5f
--- /dev/null
+++ b/src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2020, Jérôme Duval, jerome.duval@xxxxxxxxx.
+ * Distributed under the terms of the MIT license.
+ */
+
+
+#define DRIVER_NAME "wmi_acpi"
+#include "WMIPrivate.h"
+
+
+#define ACPI_NAME_ACPI_WMI "PNP0C14"
+
+#define ACPI_WMI_REGFLAG_EXPENSIVE (1 << 0)
+#define ACPI_WMI_REGFLAG_METHOD (1 << 1)
+#define ACPI_WMI_REGFLAG_STRING (1 << 2)
+#define ACPI_WMI_REGFLAG_EVENT (1 << 3)
+
+
+device_manager_info *gDeviceManager;
+
+
+acpi_status wmi_acpi_adr_space_handler(uint32 function,
+ acpi_physical_address address, uint32 bitWidth, int *value,
+ void *handlerContext, void *regionContext)
+{
+ return B_OK;
+}
+
+
+WMIACPI::WMIACPI(device_node *node)
+ :
+ fNode(node)
+{
+ CALLED();
+
+ device_node *parent;
+ parent = gDeviceManager->get_parent_node(node);
+ gDeviceManager->get_driver(parent, (driver_module_info **)&acpi,
+ (void **)&acpi_cookie);
+ gDeviceManager->get_attr_string(parent, ACPI_DEVICE_UID_ITEM, &fUid,
+ false);
+ gDeviceManager->put_node(parent);
+
+ // install notify handler
+ fStatus = acpi->install_notify_handler(acpi_cookie,
+ ACPI_ALL_NOTIFY, _NotifyHandler, this);
+ if (fStatus != B_OK) {
+ ERROR("install_notify_handler failed\n");
+ return;
+ }
+
+ fStatus = acpi->install_address_space_handler(acpi_cookie,
+ ACPI_ADR_SPACE_EC, wmi_acpi_adr_space_handler, NULL, this);
+ if (fStatus != B_OK) {
+ ERROR("wmi_acpi_adr_space_handler failed\n");
+ return;
+ }
+
+ acpi_data buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ fStatus = acpi->evaluate_method(acpi_cookie, "_WDG", NULL, &buffer);
+ if (fStatus != B_OK) {
+ ERROR("Method call _WDG failed\n");
+ return;
+ }
+
+ acpi_object_type* object = (acpi_object_type*)buffer.pointer;
+ fWMIInfoCount = object->buffer.length / sizeof(guid_info);
+ guid_info *info = (guid_info*)object->buffer.buffer;
+ fWMIInfos = (wmi_info *)calloc(fWMIInfoCount, sizeof(wmi_info));
+ TRACE("found %" B_PRIu32 " objects\n", fWMIInfoCount);
+ for (uint32 i = 0; i < fWMIInfoCount; i++, info++) {
+ wmi_info *wmi = &fWMIInfos[i];
+ wmi->guid = *info;
+ fList.Add(wmi);
+ }
+ free(object);
+}
+
+
+WMIACPI::~WMIACPI()
+{
+ free(fWMIInfos);
+
+ acpi->remove_notify_handler(acpi_cookie,
+ ACPI_ALL_NOTIFY, _NotifyHandler);
+}
+
+
+status_t
+WMIACPI::InitCheck()
+{
+ return fStatus;
+}
+
+
+status_t
+WMIACPI::Scan()
+{
+ CALLED();
+ status_t status;
+ wmi_info* wmiInfo = NULL;
+ uint32 index = 0;
+ for (WMIInfoList::Iterator it = fList.GetIterator();
+ (wmiInfo = it.Next()) != NULL; index++) {
+ uint8* guid = wmiInfo->guid.guid;
+ char guidString[37] = {};
+ _GuidToGuidString(guid, guidString);
+ device_attr attrs[] = {
+ // connection
+ { WMI_GUID_STRING_ITEM, B_STRING_TYPE, { string:
guidString }},
+
+ { WMI_BUS_COOKIE, B_UINT32_TYPE, { ui32: index }},
+
+ // description of peripheral drivers
+ { B_DEVICE_BUS, B_STRING_TYPE, { string: "wmi" }},
+
+ { B_DEVICE_FLAGS, B_UINT32_TYPE, { ui32:
B_FIND_MULTIPLE_CHILDREN }},
+
+ { NULL }
+ };
+
+ status = gDeviceManager->register_node(fNode,
WMI_DEVICE_MODULE_NAME, attrs,
+ NULL, NULL);
+ if (status != B_OK)
+ return status;
+ }
+
+ return B_OK;
+
+}
+
+
+status_t
+WMIACPI::GetBlock(uint32 busCookie, uint8 instance, uint32 methodId,
+ acpi_data* out)
+{
+ CALLED();
+ if (busCookie >= fWMIInfoCount)
+ return B_BAD_VALUE;
+ wmi_info* info = &fWMIInfos[busCookie];
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_METHOD) != 0
+ || (info->guid.flags & ACPI_WMI_REGFLAG_EVENT) != 0) {
+ return B_BAD_VALUE;
+ } else if (instance > info->guid.max_instance)
+ return B_BAD_VALUE;
+
+ char method[5] = "WQ";
+ strncat(method, info->guid.oid, 2);
+ char wcMethod[5] = "WC";
+ strncat(wcMethod, info->guid.oid, 2);
+ status_t wcStatus = B_OK;
+ status_t status = B_OK;
+
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_EXPENSIVE) != 0)
+ wcStatus = _EvaluateMethodSimple(wcMethod, 1);
+
+ acpi_object_type object;
+ object.object_type = ACPI_TYPE_INTEGER;
+ object.integer.integer = instance;
+ acpi_objects objects = { 1, &object};
+ TRACE("GetBlock calling %s\n", method);
+ status = acpi->evaluate_method(acpi_cookie, method, &objects, out);
+
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_EXPENSIVE) != 0
+ && wcStatus == B_OK) {
+ _EvaluateMethodSimple(wcMethod, 0);
+ }
+
+ return status;
+}
+
+
+status_t
+WMIACPI::SetBlock(uint32 busCookie, uint8 instance, uint32 methodId,
+ const acpi_data* in)
+{
+ CALLED();
+ if (busCookie >= fWMIInfoCount)
+ return B_BAD_VALUE;
+ wmi_info* info = &fWMIInfos[busCookie];
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_METHOD) != 0
+ || (info->guid.flags & ACPI_WMI_REGFLAG_EVENT) != 0) {
+ return B_BAD_VALUE;
+ } else if (instance > info->guid.max_instance)
+ return B_BAD_VALUE;
+
+ char method[5] = "WS";
+ strncat(method, info->guid.oid, 2);
+
+ acpi_object_type object[2];
+ object[0].object_type = ACPI_TYPE_INTEGER;
+ object[0].integer.integer = instance;
+ object[1].object_type = ACPI_TYPE_BUFFER;
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_STRING) != 0)
+ object[1].object_type = ACPI_TYPE_STRING;
+ object[1].buffer.buffer = in->pointer;
+ object[1].buffer.length = in->length;
+ acpi_objects objects = { 2, object};
+ TRACE("SetBlock calling %s\n", method);
+ return acpi->evaluate_method(acpi_cookie, method, &objects, NULL);
+}
+
+
+status_t
+WMIACPI::EvaluateMethod(uint32 busCookie, uint8 instance, uint32 methodId,
+ const acpi_data* in, acpi_data* out)
+{
+ CALLED();
+ if (busCookie >= fWMIInfoCount)
+ return B_BAD_VALUE;
+ wmi_info* info = &fWMIInfos[busCookie];
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_METHOD) == 0)
+ return B_BAD_VALUE;
+
+ char method[5] = "WM";
+ strncat(method, info->guid.oid, 2);
+
+ acpi_object_type object[3];
+ object[0].object_type = ACPI_TYPE_INTEGER;
+ object[0].integer.integer = instance;
+ object[1].object_type = ACPI_TYPE_INTEGER;
+ object[1].integer.integer = methodId;
+ uint32 count = 2;
+ if (in != NULL) {
+ object[2].object_type = ACPI_TYPE_BUFFER;
+ if ((info->guid.flags & ACPI_WMI_REGFLAG_STRING) != 0)
+ object[2].object_type = ACPI_TYPE_STRING;
+ object[2].buffer.buffer = in->pointer;
+ object[2].buffer.length = in->length;
+ count++;
+ }
+ acpi_objects objects = { count, object};
+ TRACE("EvaluateMethod calling %s\n", method);
+ return acpi->evaluate_method(acpi_cookie, method, &objects, out);
+}
+
+
+status_t
+WMIACPI::InstallEventHandler(const char* guidString,
+ acpi_notify_handler handler, void* context)
+{
+ CALLED();
+ char string[37] = {};
+ for (uint32 i = 0; i < fWMIInfoCount; i++) {
+ wmi_info* info = &fWMIInfos[i];
+ _GuidToGuidString(info->guid.guid, string);
+ if (strcmp(guidString, string) == 0) {
+ status_t status = B_OK;
+ if (info->handler == NULL)
+ status = _SetEventGeneration(info, true);
+ if (status == B_OK) {
+ info->handler = handler;
+ info->handler_context = context;
+ }
+ return status;
+ }
+ }
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+status_t
+WMIACPI::RemoveEventHandler(const char* guidString)
+{
+ CALLED();
+ char string[37] = {};
+ for (uint32 i = 0; i < fWMIInfoCount; i++) {
+ wmi_info* info = &fWMIInfos[i];
+ _GuidToGuidString(info->guid.guid, string);
+ if (strcmp(guidString, string) == 0) {
+ status_t status = _SetEventGeneration(info, false);
+ info->handler = NULL;
+ info->handler_context = NULL;
+ return status;
+ }
+ }
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+status_t
+WMIACPI::GetEventData(uint32 notify, acpi_data* out)
+{
+ CALLED();
+
+ acpi_object_type object;
+ object.object_type = ACPI_TYPE_INTEGER;
+ object.integer.integer = notify;
+ acpi_objects objects = { 1, &object };
+
+ for (uint32 i = 0; i < fWMIInfoCount; i++) {
+ wmi_info* info = &fWMIInfos[i];
+ if (info->guid.notify_id == notify
+ && (info->guid.flags & ACPI_WMI_REGFLAG_EVENT) != 0) {
+ return acpi->evaluate_method(acpi_cookie, "_WED",
&objects, out);
+ }
+ }
+ return B_ENTRY_NOT_FOUND;
+}
+
+
+const char*
+WMIACPI::GetUid(uint32 busCookie)
+{
+ return fUid;
+}
+
+
+status_t
+WMIACPI::_SetEventGeneration(wmi_info* info, bool enabled)
+{
+ char method[5];
+ sprintf(method, "WE%02X", info->guid.notify_id);
+ TRACE("_SetEventGeneration calling %s\n", method);
+ status_t status = _EvaluateMethodSimple(method, enabled ? 1 : 0);
+ // the method is allowed not to exist
+ if (status == B_ERROR)
+ status = B_OK;
+ return status;
+}
+
+
+status_t
+WMIACPI::_EvaluateMethodSimple(const char* method, uint64 integer)
+{
+ acpi_object_type object;
+ object.object_type = ACPI_TYPE_INTEGER;
+ object.integer.integer = integer;
+ acpi_objects objects = { 1, &object};
+ return acpi->evaluate_method(acpi_cookie, method, &objects, NULL);
+}
+
+
+void
+WMIACPI::_NotifyHandler(acpi_handle device, uint32 value, void *context)
+{
+ WMIACPI* bus = (WMIACPI*)context;
+ bus->_Notify(device, value);
+}
+
+
+void
+WMIACPI::_Notify(acpi_handle device, uint32 value)
+{
+ for (uint32 i = 0; i < fWMIInfoCount; i++) {
+ wmi_info* wmi = &fWMIInfos[i];
+ if (wmi->guid.notify_id == value) {
+ TRACE("_Notify found event 0x%" B_PRIx32 "\n", value);
+ if (wmi->handler != NULL) {
+ TRACE("_Notify found handler for event 0x%"
B_PRIx32 "\n", value);
+ wmi->handler(device, value,
wmi->handler_context);
+ }
+ break;
+ }
+ }
+}
+
+
+void
+WMIACPI::_GuidToGuidString(uint8 guid[16], char* guidString)
+{
+ sprintf(guidString,
+
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ guid[3], guid[2], guid[1], guid[0], guid[5], guid[4], guid[7],
guid[6],
+ guid[8], guid[9], guid[10], guid[11], guid[12], guid[13],
guid[14], guid[15]);
+}
+
+
+// #pragma mark - driver module API
+
+
+static float
+wmi_acpi_support(device_node *parent)
+{
+ CALLED();
+
+ // make sure parent is really the ACPI bus manager
+ const char *bus;
+ if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
+ return -1;
+
+ if (strcmp(bus, "acpi"))
+ return 0.0;
+
+ // check whether it's really a device
+ uint32 device_type;
+ if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
+ &device_type, false) != B_OK
+ || device_type != ACPI_TYPE_DEVICE) {
+ return 0.0;
+ }
+
+ // check whether it's an acpi wmi device
+ const char *name;
+ if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
+ false) != B_OK || strcmp(name, ACPI_NAME_ACPI_WMI) != 0) {
+ return 0.0;
+ }
+
+ TRACE("found an acpi wmi device\n");
+
+ return 0.6;
+}
+
+
+static status_t
+wmi_acpi_register_device(device_node *node)
+{
+ CALLED();
+ device_attr attrs[] = {
+ { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "WMI ACPI" }},
+ { NULL }
+ };
+
+ return gDeviceManager->register_node(node, WMI_ACPI_DRIVER_NAME, attrs,
+ NULL, NULL);
+}
+
+
+static status_t
+wmi_acpi_init_driver(device_node *node, void **driverCookie)
+{
+ CALLED();
+ WMIACPI* device = new(std::nothrow) WMIACPI(node);
+ if (device == NULL)
+ return B_NO_MEMORY;
+
+ *driverCookie = device;
+
+ return B_OK;
+}
+
+
+static void
+wmi_acpi_uninit_driver(void *driverCookie)
+{
+ CALLED();
+ WMIACPI *device = (WMIACPI*)driverCookie;
+
+ delete device;
+}
+
+
+static status_t
+wmi_acpi_register_child_devices(void *cookie)
+{
+ CALLED();
+ WMIACPI *device = (WMIACPI*)cookie;
+ return device->Scan();
+}
+
+
+
+module_dependency module_dependencies[] = {
+ { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
+ {}
+};
+
+
+static driver_module_info sWMIACPIDriverModule = {
+ {
+ WMI_ACPI_DRIVER_NAME,
+ 0,
+ NULL
+ },
+
+ wmi_acpi_support,
+ wmi_acpi_register_device,
+ wmi_acpi_init_driver,
+ wmi_acpi_uninit_driver,
+ wmi_acpi_register_child_devices,
+ NULL, // rescan
+ NULL, // removed
+};
+
+
+module_info *modules[] = {
+ (module_info *)&sWMIACPIDriverModule,
+ (module_info *)&gWMIAsusDriverModule,
+ (module_info *)&gWMIDeviceModule,
+ NULL
+};
diff --git a/src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
b/src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
new file mode 100644
index 0000000..fb18150
--- /dev/null
+++ b/src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2020, Jérôme Duval, jerome.duval@xxxxxxxxx.
+ * Distributed under the terms of the MIT license.
+ */
+
+
+#define DRIVER_NAME "wmi_asus"
+#include "WMIPrivate.h"
+
+
+#define ACPI_ASUS_WMI_MGMT_GUID
"97845ED0-4E6D-11DE-8A39-0800200C9A66"
+#define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+#define ACPI_ASUS_UID_ASUSWMI "ASUSWMI"
+
+#define ASUS_WMI_METHODID_INIT 0x54494E49
+#define ASUS_WMI_METHODID_SPEC 0x43455053
+#define ASUS_WMI_METHODID_SFUN 0x4E554653
+#define ASUS_WMI_METHODID_DCTS 0x53544344
+#define ASUS_WMI_METHODID_DSTS 0x53545344
+#define ASUS_WMI_METHODID_DEVS 0x53564544
+
+#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
+#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
+
+
+class WMIAsus {
+public:
+
WMIAsus(device_node *node);
+ ~WMIAsus();
+
+private:
+ status_t _EvaluateMethod(uint32
methodId, uint32 arg0,
+ uint32
arg1, uint32 *returnValue);
+ status_t _GetDevState(uint32
devId, uint32* value);
+ status_t _SetDevState(uint32
devId, uint32 arg,
+ uint32*
value);
+ static void _NotifyHandler(acpi_handle
handle, uint32 notify,
+ void
*context);
+ void _Notify(acpi_handle
handle, uint32 notify);
+private:
+ device_node* fNode;
+ wmi_device_interface* wmi;
+ wmi_device wmi_cookie;
+ uint32 fDstsID;
+ const char* fEventGuidString;
+};
+
+
+
+WMIAsus::WMIAsus(device_node *node)
+ :
+ fNode(node),
+ fDstsID(ASUS_WMI_METHODID_DSTS),
+ fEventGuidString(NULL)
+{
+ CALLED();
+
+ device_node *parent;
+ parent = gDeviceManager->get_parent_node(node);
+ gDeviceManager->get_driver(parent, (driver_module_info **)&wmi,
+ (void **)&wmi_cookie);
+
+ gDeviceManager->put_node(parent);
+
+ const char* uid = wmi->get_uid(wmi_cookie);
+ if (uid != NULL && strcmp(uid, ACPI_ASUS_UID_ASUSWMI) == 0)
+ fDstsID = ASUS_WMI_METHODID_DCTS;
+ TRACE("WMIAsus using _UID %s\n", uid);
+ uint32 value;
+ if (_EvaluateMethod(ASUS_WMI_METHODID_INIT, 0, 0, &value) == B_OK) {
+ TRACE("_INIT: %x\n", value);
+ }
+ if (_EvaluateMethod(ASUS_WMI_METHODID_SPEC, 0, 9, &value) == B_OK) {
+ TRACE("_SPEC: %x\n", value);
+ }
+ if (_EvaluateMethod(ASUS_WMI_METHODID_SFUN, 0, 0, &value) == B_OK) {
+ TRACE("_SFUN: %x\n", value);
+ }
+
+ // install event handler
+ if (wmi->install_event_handler(wmi_cookie, ACPI_ASUS_WMI_EVENT_GUID,
+ _NotifyHandler, this) == B_OK) {
+ fEventGuidString = ACPI_ASUS_WMI_EVENT_GUID;
+ }
+}
+
+
+WMIAsus::~WMIAsus()
+{
+ if (fEventGuidString != NULL)
+ wmi->remove_event_handler(wmi_cookie, fEventGuidString);
+}
+
+
+status_t
+WMIAsus::_EvaluateMethod(uint32 methodId, uint32 arg0, uint32 arg1,
+ uint32 *returnValue)
+{
+ CALLED();
+ uint32 params[] = { arg0, arg1 };
+ acpi_data inBuffer = { sizeof(params), params };
+ acpi_data outBuffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ status_t status = wmi->evaluate_method(wmi_cookie, 0, methodId,
&inBuffer,
+ &outBuffer);
+ if (status != B_OK)
+ return status;
+
+ acpi_object_type* object = (acpi_object_type*)outBuffer.pointer;
+ uint32 result = 0;
+ if (object != NULL) {
+ if (object->object_type == ACPI_TYPE_INTEGER)
+ result = object->integer.integer;
+ free(object);
+ }
+ if (returnValue != NULL)
+ *returnValue = result;
+
+ return B_OK;
+}
+
+
+status_t
+WMIAsus::_GetDevState(uint32 devId, uint32 *value)
+{
+ return _EvaluateMethod(fDstsID, devId, 0, value);
+}
+
+
+status_t
+WMIAsus::_SetDevState(uint32 devId, uint32 arg, uint32 *value)
+{
+ return _EvaluateMethod(ASUS_WMI_METHODID_DEVS, devId, arg, value);
+}
+
+
+void
+WMIAsus::_NotifyHandler(acpi_handle handle, uint32 notify, void *context)
+{
+ WMIAsus* device = (WMIAsus*)context;
+ device->_Notify(handle, notify);
+}
+
+
+void
+WMIAsus::_Notify(acpi_handle handle, uint32 notify)
+{
+ CALLED();
+
+ acpi_data response = { ACPI_ALLOCATE_BUFFER, NULL };
+ wmi->get_event_data(wmi_cookie, notify, &response);
+
+ acpi_object_type* object = (acpi_object_type*)response.pointer;
+ uint32 result = 0;
+ if (object != NULL) {
+ if (object->object_type == ACPI_TYPE_INTEGER)
+ result = object->integer.integer;
+ free(object);
+ }
+ if (result != 0) {
+ if (result == 0xc4 || result == 0xc5) {
+ TRACE("WMIAsus::_Notify() keyboard backlight key\n");
+ uint32 value;
+ if (_GetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT, &value)
== B_OK) {
+ TRACE("WMIAsus::_Notify() getkeyboard backlight
key %"
+ B_PRIx32 "\n", value);
+ value &= 0x7;
+ if (result == 0xc4) {
+ if (value < 3)
+ value++;
+ } else if (value > 0)
+ value--;
+ TRACE("WMIAsus::_Notify() set keyboard
backlight key %"
+ B_PRIx32 "\n", value);
+ _SetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT,
value | 0x80, NULL);
+ }
+ } else if (result == 0x6b) {
+ TRACE("WMIAsus::_Notify() touchpad control\n");
+ } else {
+ TRACE("WMIAsus::_Notify() key 0x%" B_PRIx32 "\n",
result);
+ }
+ }
+}
+
+
+// #pragma mark - driver module API
+
+
+static float
+wmi_asus_support(device_node *parent)
+{
+ // make sure parent is really a wmi device
+ const char *bus;
+ if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
+ return -1;
+
+ if (strcmp(bus, "wmi"))
+ return 0.0;
+
+ // check whether it's an asus wmi device
+ const char *guid;
+ if (gDeviceManager->get_attr_string(parent, WMI_GUID_STRING_ITEM, &guid,
+ false) != B_OK || strcmp(guid, ACPI_ASUS_WMI_MGMT_GUID) != 0) {
+ return 0.0;
+ }
+
+ TRACE("found an asus wmi device\n");
+
+ return 0.6;
+}
+
+
+static status_t
+wmi_asus_register_device(device_node *node)
+{
+ CALLED();
+ device_attr attrs[] = {
+ { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "WMI ASUS" }},
+ { NULL }
+ };
+
+ return gDeviceManager->register_node(node, WMI_ASUS_DRIVER_NAME, attrs,
+ NULL, NULL);
+}
+
+
+static status_t
+wmi_asus_init_driver(device_node *node, void **driverCookie)
+{
+ CALLED();
+
+ WMIAsus* device = new(std::nothrow) WMIAsus(node);
+ if (device == NULL)
+ return B_NO_MEMORY;
+ *driverCookie = device;
+
+ return B_OK;
+}
+
+
+static void
+wmi_asus_uninit_driver(void *driverCookie)
+{
+ CALLED();
+ WMIAsus* device = (WMIAsus*)driverCookie;
+ delete device;
+}
+
+
+static status_t
+wmi_asus_register_child_devices(void *cookie)
+{
+ CALLED();
+ return B_OK;
+}
+
+
+driver_module_info gWMIAsusDriverModule = {
+ {
+ WMI_ASUS_DRIVER_NAME,
+ 0,
+ NULL
+ },
+
+ wmi_asus_support,
+ wmi_asus_register_device,
+ wmi_asus_init_driver,
+ wmi_asus_uninit_driver,
+ wmi_asus_register_child_devices,
+ NULL, // rescan
+ NULL, // removed
+};
+
diff --git a/src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
b/src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
new file mode 100644
index 0000000..582070f
--- /dev/null
+++ b/src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2020, Jérôme Duval, jerome.duval@xxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "WMIPrivate.h"
+
+
+WMIDevice::WMIDevice(device_node *node)
+ :
+ fNode(node),
+ fBus(NULL),
+ fBusCookie(UINT32_MAX),
+ fInitStatus(B_OK)
+{
+ CALLED();
+
+ {
+ device_node *parent = gDeviceManager->get_parent_node(node);
+ gDeviceManager->get_driver(parent, NULL, (void **)&fBus);
+ gDeviceManager->put_node(parent);
+ }
+
+ fInitStatus = gDeviceManager->get_attr_uint32(node, WMI_BUS_COOKIE,
+ &fBusCookie, false);
+}
+
+
+WMIDevice::~WMIDevice()
+{
+}
+
+
+status_t
+WMIDevice::InitCheck()
+{
+ return fInitStatus;
+}
+
+
+status_t
+WMIDevice::EvaluateMethod(uint8 instance, uint32 methodId, const acpi_data* in,
+ acpi_data* out)
+{
+ CALLED();
+ return fBus->EvaluateMethod(fBusCookie, instance, methodId, in, out);
+}
+
+
+status_t
+WMIDevice::InstallEventHandler(const char* guidString,
+ acpi_notify_handler handler, void* context)
+{
+ CALLED();
+ if (guidString == NULL || handler == NULL)
+ return B_BAD_VALUE;
+
+ return fBus->InstallEventHandler(guidString, handler, context);
+}
+
+
+status_t
+WMIDevice::RemoveEventHandler(const char* guidString)
+{
+ CALLED();
+ if (guidString == NULL)
+ return B_BAD_VALUE;
+
+ return fBus->RemoveEventHandler(guidString);
+}
+
+
+status_t
+WMIDevice::GetEventData(uint32 notify, acpi_data* out)
+{
+ CALLED();
+ return fBus->GetEventData(notify, out);
+}
+
+
+const char*
+WMIDevice::GetUid()
+{
+ CALLED();
+ return fBus->GetUid(fBusCookie);
+}
+
+
+// #pragma mark - driver module API
+
+
+static status_t
+wmi_init_device(device_node *node, void **_device)
+{
+ CALLED();
+ WMIDevice *device = new(std::nothrow) WMIDevice(node);
+ if (device == NULL)
+ return B_NO_MEMORY;
+
+ status_t result = device->InitCheck();
+ if (result != B_OK) {
+ ERROR("failed to set up wmi device object\n");
+ return result;
+ }
+
+ *_device = device;
+
+ return B_OK;
+}
+
+
+static void
+wmi_uninit_device(void *_device)
+{
+ CALLED();
+ WMIDevice *device = (WMIDevice *)_device;
+ delete device;
+}
+
+
+static status_t
+wmi_evaluate_method(wmi_device _device, uint8 instance, uint32 methodId,
+ const acpi_data* in, acpi_data* out)
+{
+ WMIDevice *device = (WMIDevice *)_device;
+ return device->EvaluateMethod(instance, methodId, in, out);
+}
+
+
+static status_t
+wmi_install_event_handler(wmi_device _device, const char* guidString,
+ acpi_notify_handler handler, void* context)
+{
+ WMIDevice *device = (WMIDevice *)_device;
+ return device->InstallEventHandler(guidString, handler, context);
+}
+
+
+static status_t
+wmi_remove_event_handler(wmi_device _device, const char* guidString)
+{
+ WMIDevice *device = (WMIDevice *)_device;
+ return device->RemoveEventHandler(guidString);
+}
+
+
+static status_t
+wmi_get_event_data(wmi_device _device, uint32 notify, acpi_data* out)
+{
+ WMIDevice *device = (WMIDevice *)_device;
+ return device->GetEventData(notify, out);
+}
+
+
+static const char*
+wmi_get_uid(wmi_device _device)
+{
+ WMIDevice *device = (WMIDevice *)_device;
+ return device->GetUid();
+}
+
+
+static status_t
+std_ops(int32 op, ...)
+{
+ switch (op) {
+ case B_MODULE_INIT:
+ case B_MODULE_UNINIT:
+ return B_OK;
+
+ default:
+ return B_ERROR;
+ }
+}
+
+
+wmi_device_interface gWMIDeviceModule = {
+ {
+ {
+ WMI_DEVICE_MODULE_NAME,
+ 0,
+ std_ops
+ },
+
+ NULL, // supported devices
+ NULL, // register node
+ wmi_init_device,
+ wmi_uninit_device,
+ NULL, // register child devices
+ NULL, // rescan
+ NULL, // device_removed
+ },
+
+ wmi_evaluate_method,
+ wmi_install_event_handler,
+ wmi_remove_event_handler,
+ wmi_get_event_data,
+ wmi_get_uid,
+};
diff --git a/src/add-ons/kernel/drivers/wmi/WMIPrivate.h
b/src/add-ons/kernel/drivers/wmi/WMIPrivate.h
new file mode 100644
index 0000000..ec8be7f
--- /dev/null
+++ b/src/add-ons/kernel/drivers/wmi/WMIPrivate.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2020, Jérôme Duval, jerome.duval@xxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef WMI_PRIVATE_H
+#define WMI_PRIVATE_H
+
+
+#include <ACPI.h>
+#include <new>
+#include <stdio.h>
+#include <string.h>
+
+#include <lock.h>
+#include <util/AutoLock.h>
+#include <wmi.h>
+
+
+//#define WMI_TRACE
+#ifndef DRIVER_NAME
+# define DRIVER_NAME "wmi"
+#endif
+#ifdef WMI_TRACE
+# define TRACE(x...) dprintf("\33[33m" DRIVER_NAME ":\33[0m
" x)
+#else
+# define TRACE(x...)
+#endif
+#define TRACE_ALWAYS(x...) dprintf("\33[33m" DRIVER_NAME ":\33[0m " x)
+#define ERROR(x...) TRACE_ALWAYS(x)
+#define CALLED() TRACE("CALLED %s\n",
__PRETTY_FUNCTION__)
+
+
+#define WMI_ACPI_DRIVER_NAME "drivers/wmi/acpi/driver_v1"
+#define WMI_DEVICE_MODULE_NAME "drivers/wmi/device/driver_v1"
+
+#define WMI_ASUS_DRIVER_NAME "drivers/wmi/asus/driver_v1"
+
+#define WMI_BUS_COOKIE "wmi/bus/index"
+
+
+class WMIACPI;
+class WMIDevice;
+
+
+extern device_manager_info *gDeviceManager;
+extern wmi_device_interface gWMIDeviceModule;
+extern driver_module_info gWMIAsusDriverModule;
+
+
+class WMIDevice {
+public:
+
WMIDevice(device_node* node);
+ ~WMIDevice();
+
+ status_t InitCheck();
+ status_t EvaluateMethod(uint8
instance, uint32 methodId,
+ const
acpi_data* in, acpi_data* out);
+ status_t
InstallEventHandler(const char* guidString,
+
acpi_notify_handler handler, void* context);
+ status_t
RemoveEventHandler(const char* guidString);
+ status_t GetEventData(uint32
notify, acpi_data* out);
+ const char* GetUid();
+private:
+
+private:
+ device_node* fNode;
+ WMIACPI* fBus;
+ uint32 fBusCookie;
+ status_t fInitStatus;
+};
+
+
+typedef struct {
+ uint8 guid[16];
+ union {
+ char oid[2];
+ struct {
+ uint8 notify_id;
+ };
+ };
+ uint8 max_instance;
+ uint8 flags;
+} guid_info;
+
+
+struct wmi_info;
+typedef struct wmi_info : DoublyLinkedListLinkImpl<wmi_info> {
+ guid_info guid;
+ acpi_notify_handler handler;
+ void* handler_context;
+} wmi_info;
+typedef DoublyLinkedList<wmi_info> WMIInfoList;
+
+
+
+class WMIACPI {
+public:
+
WMIACPI(device_node *node);
+ ~WMIACPI();
+
+ status_t InitCheck();
+
+ status_t Scan();
+
+ status_t GetBlock(uint32
busCookie,
+ uint8
instance, uint32 methodId,
+
acpi_data* out);
+ status_t SetBlock(uint32
busCookie,
+ uint8
instance, uint32 methodId,
+ const
acpi_data* in);
+ status_t EvaluateMethod(uint32
busCookie,
+ uint8
instance, uint32 methodId,
+ const
acpi_data* in, acpi_data* out);
+ status_t
InstallEventHandler(const char* guidString,
+
acpi_notify_handler handler, void* context);
+ status_t
RemoveEventHandler(const char* guidString);
+ status_t GetEventData(uint32
notify, acpi_data* out);
+ const char* GetUid(uint32
busCookie);
+private:
+ status_t
_SetEventGeneration(wmi_info* info,
+ bool
enabled);
+ status_t
_EvaluateMethodSimple(const char* method,
+ uint64
integer);
+ void _Notify(acpi_handle
device, uint32 value);
+ static void _NotifyHandler(acpi_handle
device,
+ uint32
value, void *context);
+
+ void _GuidToGuidString(uint8
guid[16],
+ char*
guidString);
+private:
+ device_node* fNode;
+ acpi_device_module_info* acpi;
+ acpi_device acpi_cookie;
+ status_t fStatus;
+ WMIInfoList fList;
+ wmi_info* fWMIInfos;
+ uint32 fWMIInfoCount;
+ const char* fUid;
+};
+
+
+#endif // WMI_PRIVATE_H
--
To view, visit https://review.haiku-os.org/c/haiku/+/2485
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ib86f70b4a407178b0a1f532269387a55915cc460
Gerrit-Change-Number: 2485
Gerrit-PatchSet: 1
Gerrit-Owner: Jérôme Duval <jerome.duval@xxxxxxxxx>
Gerrit-MessageType: newchange