xref: /haiku/src/add-ons/kernel/drivers/wmi/WMIAsus.cpp (revision dc0bc42494264bb8d17b6b081647377b5601570a)
1 /*
2  * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT license.
4  */
5 
6 
7 #define DRIVER_NAME "wmi_asus"
8 #include "WMIPrivate.h"
9 
10 
11 #define ACPI_ASUS_WMI_MGMT_GUID		"97845ED0-4E6D-11DE-8A39-0800200C9A66"
12 #define ACPI_ASUS_WMI_EVENT_GUID	"0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
13 #define ACPI_ASUS_UID_ASUSWMI		"ASUSWMI"
14 
15 #define ASUS_WMI_METHODID_INIT		0x54494E49
16 #define ASUS_WMI_METHODID_SPEC		0x43455053
17 #define ASUS_WMI_METHODID_SFUN		0x4E554653
18 #define ASUS_WMI_METHODID_DCTS		0x53544344
19 #define ASUS_WMI_METHODID_DSTS		0x53545344
20 #define ASUS_WMI_METHODID_DEVS		0x53564544
21 
22 #define ASUS_WMI_DEVID_BRIGHTNESS		0x00050012
23 #define ASUS_WMI_DEVID_KBD_BACKLIGHT	0x00050021
24 
25 
26 class WMIAsus {
27 public:
28 								WMIAsus(device_node *node);
29 								~WMIAsus();
30 
31 private:
32 			status_t 			_EvaluateMethod(uint32 methodId, uint32 arg0,
33 									uint32 arg1, uint32 *returnValue);
34 			status_t			_GetDevState(uint32 devId, uint32* value);
35 			status_t			_SetDevState(uint32 devId, uint32 arg,
36 									uint32* value);
37 	static	void				_NotifyHandler(acpi_handle handle,
38 									uint32 notify, void *context);
39 			void				_Notify(acpi_handle handle, uint32 notify);
40 private:
41 			device_node*		fNode;
42 			wmi_device_interface* wmi;
43 			wmi_device			wmi_cookie;
44 			uint32				fDstsID;
45 			const char*			fEventGuidString;
46 };
47 
48 
49 
50 WMIAsus::WMIAsus(device_node *node)
51 	:
52 	fNode(node),
53 	fDstsID(ASUS_WMI_METHODID_DSTS),
54 	fEventGuidString(NULL)
55 {
56 	CALLED();
57 
58 	device_node *parent;
59 	parent = gDeviceManager->get_parent_node(node);
60 	gDeviceManager->get_driver(parent, (driver_module_info **)&wmi,
61 		(void **)&wmi_cookie);
62 
63 	gDeviceManager->put_node(parent);
64 
65 	const char* uid = wmi->get_uid(wmi_cookie);
66 	if (uid != NULL && strcmp(uid, ACPI_ASUS_UID_ASUSWMI) == 0)
67 		fDstsID = ASUS_WMI_METHODID_DCTS;
68 	TRACE("WMIAsus using _UID %s\n", uid);
69 	uint32 value;
70 	if (_EvaluateMethod(ASUS_WMI_METHODID_INIT, 0, 0, &value) == B_OK) {
71 		TRACE("_INIT: %x\n", value);
72 	}
73 	if (_EvaluateMethod(ASUS_WMI_METHODID_SPEC, 0, 9, &value) == B_OK) {
74 		TRACE("_SPEC: %x\n", value);
75 	}
76 	if (_EvaluateMethod(ASUS_WMI_METHODID_SFUN, 0, 0, &value) == B_OK) {
77 		TRACE("_SFUN: %x\n", value);
78 	}
79 
80 	// install event handler
81 	if (wmi->install_event_handler(wmi_cookie, ACPI_ASUS_WMI_EVENT_GUID,
82 		_NotifyHandler, this) == B_OK) {
83 		fEventGuidString = ACPI_ASUS_WMI_EVENT_GUID;
84 	}
85 }
86 
87 
88 WMIAsus::~WMIAsus()
89 {
90 	if (fEventGuidString != NULL)
91 		wmi->remove_event_handler(wmi_cookie, fEventGuidString);
92 }
93 
94 
95 status_t
96 WMIAsus::_EvaluateMethod(uint32 methodId, uint32 arg0, uint32 arg1,
97 	uint32 *returnValue)
98 {
99 	CALLED();
100 	uint32 params[] = { arg0, arg1 };
101 	acpi_data inBuffer = { sizeof(params), params };
102 	acpi_data outBuffer = { ACPI_ALLOCATE_BUFFER, NULL };
103 	status_t status = wmi->evaluate_method(wmi_cookie, 0, methodId, &inBuffer,
104 		&outBuffer);
105 	if (status != B_OK)
106 		return status;
107 
108 	acpi_object_type* object = (acpi_object_type*)outBuffer.pointer;
109 	uint32 result = 0;
110 	if (object != NULL) {
111 		if (object->object_type == ACPI_TYPE_INTEGER)
112 			result = object->integer.integer;
113 		free(object);
114 	}
115 	if (returnValue != NULL)
116 		*returnValue = result;
117 
118 	return B_OK;
119 }
120 
121 
122 status_t
123 WMIAsus::_GetDevState(uint32 devId, uint32 *value)
124 {
125 	return _EvaluateMethod(fDstsID, devId, 0, value);
126 }
127 
128 
129 status_t
130 WMIAsus::_SetDevState(uint32 devId, uint32 arg, uint32 *value)
131 {
132 	return _EvaluateMethod(ASUS_WMI_METHODID_DEVS, devId, arg, value);
133 }
134 
135 
136 void
137 WMIAsus::_NotifyHandler(acpi_handle handle, uint32 notify, void *context)
138 {
139 	WMIAsus* device = (WMIAsus*)context;
140 	device->_Notify(handle, notify);
141 }
142 
143 
144 void
145 WMIAsus::_Notify(acpi_handle handle, uint32 notify)
146 {
147 	CALLED();
148 
149 	acpi_data response = { ACPI_ALLOCATE_BUFFER, NULL };
150 	wmi->get_event_data(wmi_cookie, notify, &response);
151 
152 	acpi_object_type* object = (acpi_object_type*)response.pointer;
153 	uint32 result = 0;
154 	if (object != NULL) {
155 		if (object->object_type == ACPI_TYPE_INTEGER)
156 			result = object->integer.integer;
157 		free(object);
158 	}
159 	if (result != 0) {
160 		if (result == 0xc4 || result == 0xc5) {
161 			TRACE("WMIAsus::_Notify() keyboard backlight key\n");
162 			uint32 value;
163 			if (_GetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT, &value) == B_OK) {
164 				TRACE("WMIAsus::_Notify() getkeyboard backlight key %"
165 					B_PRIx32 "\n", value);
166 				value &= 0x7;
167 				if (result == 0xc4) {
168 					if (value < 3)
169 						value++;
170 				} else if (value > 0)
171 					value--;
172 				TRACE("WMIAsus::_Notify() set keyboard backlight key %"
173 					B_PRIx32 "\n", value);
174 				_SetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT, value | 0x80, NULL);
175 			}
176 		} else if (result == 0x6b) {
177 			TRACE("WMIAsus::_Notify() touchpad control\n");
178 		} else {
179 			TRACE("WMIAsus::_Notify() key 0x%" B_PRIx32 "\n", result);
180 		}
181 	}
182 }
183 
184 
185 //	#pragma mark - driver module API
186 
187 
188 static float
189 wmi_asus_support(device_node *parent)
190 {
191 	// make sure parent is really a wmi device
192 	const char *bus;
193 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
194 		return -1;
195 
196 	if (strcmp(bus, "wmi"))
197 		return 0.0;
198 
199 	// check whether it's an asus wmi device
200 	const char *guid;
201 	if (gDeviceManager->get_attr_string(parent, WMI_GUID_STRING_ITEM, &guid,
202 		false) != B_OK || strcmp(guid, ACPI_ASUS_WMI_MGMT_GUID) != 0) {
203 		return 0.0;
204 	}
205 
206 	TRACE("found an asus wmi device\n");
207 
208 	return 0.6;
209 }
210 
211 
212 static status_t
213 wmi_asus_register_device(device_node *node)
214 {
215 	CALLED();
216 	device_attr attrs[] = {
217 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "WMI ASUS" }},
218 		{ NULL }
219 	};
220 
221 	return gDeviceManager->register_node(node, WMI_ASUS_DRIVER_NAME, attrs,
222 		NULL, NULL);
223 }
224 
225 
226 static status_t
227 wmi_asus_init_driver(device_node *node, void **driverCookie)
228 {
229 	CALLED();
230 
231 	WMIAsus* device = new(std::nothrow) WMIAsus(node);
232 	if (device == NULL)
233 		return B_NO_MEMORY;
234 	*driverCookie = device;
235 
236 	return B_OK;
237 }
238 
239 
240 static void
241 wmi_asus_uninit_driver(void *driverCookie)
242 {
243 	CALLED();
244 	WMIAsus* device = (WMIAsus*)driverCookie;
245 	delete device;
246 }
247 
248 
249 static status_t
250 wmi_asus_register_child_devices(void *cookie)
251 {
252 	CALLED();
253 	return B_OK;
254 }
255 
256 
257 driver_module_info gWMIAsusDriverModule = {
258 	{
259 		WMI_ASUS_DRIVER_NAME,
260 		0,
261 		NULL
262 	},
263 
264 	wmi_asus_support,
265 	wmi_asus_register_device,
266 	wmi_asus_init_driver,
267 	wmi_asus_uninit_driver,
268 	wmi_asus_register_child_devices,
269 	NULL,	// rescan
270 	NULL,	// removed
271 };
272 
273