[haiku-commits] Change in haiku[master]: wmi: add ACPI WMI implementation

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 16 Apr 2020 16:02:49 +0000

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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: wmi: add ACPI WMI implementation - Gerrit