mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 07:18:40 +01:00
wmi: add ACPI WMI implementation
add a WMI Asus driver, to control keyboard backlight brightness. Change-Id: Ib86f70b4a407178b0a1f532269387a55915cc460 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2485 Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com> Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
parent
526752bc02
commit
1baf45b64b
43
headers/private/wmi/wmi.h
Normal file
43
headers/private/wmi/wmi.h
Normal file
@ -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_ */
|
@ -18,3 +18,5 @@ SubInclude HAIKU_TOP src add-ons kernel drivers power ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers timer ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers tty ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers video ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers wmi ;
|
||||
|
||||
|
11
src/add-ons/kernel/drivers/wmi/Jamfile
Normal file
11
src/add-ons/kernel/drivers/wmi/Jamfile
Normal file
@ -0,0 +1,11 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers wmi ;
|
||||
|
||||
UsePrivateHeaders wmi ;
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon wmi :
|
||||
WMIACPI.cpp
|
||||
WMIAsus.cpp
|
||||
WMIDevice.cpp
|
||||
;
|
||||
|
485
src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
Normal file
485
src/add-ons/kernel/drivers/wmi/WMIACPI.cpp
Normal file
@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* 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
|
||||
};
|
272
src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
Normal file
272
src/add-ons/kernel/drivers/wmi/WMIAsus.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* 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
|
||||
};
|
||||
|
200
src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
Normal file
200
src/add-ons/kernel/drivers/wmi/WMIDevice.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* 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,
|
||||
};
|
142
src/add-ons/kernel/drivers/wmi/WMIPrivate.h
Normal file
142
src/add-ons/kernel/drivers/wmi/WMIPrivate.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* 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
|
Loading…
Reference in New Issue
Block a user