xref: /haiku/src/add-ons/kernel/drivers/wmi/WMIAsus.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
23 #define ASUS_WMI_DEVID_ALS_ENABLE		0x00050001
24 #define ASUS_WMI_DEVID_BRIGHTNESS		0x00050012
25 #define ASUS_WMI_DEVID_KBD_BACKLIGHT	0x00050021
26 
27 
28 class WMIAsus {
29 public:
30 								WMIAsus(device_node *node);
31 								~WMIAsus();
32 
33 private:
34 			status_t 			_EvaluateMethod(uint32 methodId, uint32 arg0,
35 									uint32 arg1, uint32 *returnValue);
36 			status_t			_GetDevState(uint32 devId, uint32* value);
37 			status_t			_SetDevState(uint32 devId, uint32 arg,
38 									uint32* value);
39 	static	void				_NotifyHandler(acpi_handle handle,
40 									uint32 notify, void *context);
41 			void				_Notify(acpi_handle handle, uint32 notify);
42 			status_t			_EnableAls(uint32 enable);
43 private:
44 			device_node*		fNode;
45 			wmi_device_interface* wmi;
46 			wmi_device			wmi_cookie;
47 			uint32				fDstsID;
48 			const char*			fEventGuidString;
49 			bool				fEnableALS;
50 };
51 
52 
53 
54 WMIAsus::WMIAsus(device_node *node)
55 	:
56 	fNode(node),
57 	fDstsID(ASUS_WMI_METHODID_DSTS),
58 	fEventGuidString(NULL),
59 	fEnableALS(false)
60 {
61 	CALLED();
62 
63 	device_node *parent;
64 	parent = gDeviceManager->get_parent_node(node);
65 	gDeviceManager->get_driver(parent, (driver_module_info **)&wmi,
66 		(void **)&wmi_cookie);
67 
68 	gDeviceManager->put_node(parent);
69 
70 	const char* uid = wmi->get_uid(wmi_cookie);
71 	if (uid != NULL && strcmp(uid, ACPI_ASUS_UID_ASUSWMI) == 0)
72 		fDstsID = ASUS_WMI_METHODID_DCTS;
73 	TRACE("WMIAsus using _UID %s\n", uid);
74 	uint32 value;
75 	if (_EvaluateMethod(ASUS_WMI_METHODID_INIT, 0, 0, &value) == B_OK) {
76 		TRACE("_INIT: %x\n", value);
77 	}
78 	if (_EvaluateMethod(ASUS_WMI_METHODID_SPEC, 0, 9, &value) == B_OK) {
79 		TRACE("_SPEC: %x\n", value);
80 	}
81 	if (_EvaluateMethod(ASUS_WMI_METHODID_SFUN, 0, 0, &value) == B_OK) {
82 		TRACE("_SFUN: %x\n", value);
83 	}
84 
85 	// some ASUS laptops need to be ALS forced
86 	fEnableALS =
87 		gSMBios->match_vendor_product("ASUSTeK COMPUTER INC.", "UX430UAR");
88 	if (fEnableALS && _EnableAls(1) == B_OK) {
89 		TRACE("ALSC enabled\n");
90 	}
91 
92 	// install event handler
93 	if (wmi->install_event_handler(wmi_cookie, ACPI_ASUS_WMI_EVENT_GUID,
94 		_NotifyHandler, this) == B_OK) {
95 		fEventGuidString = ACPI_ASUS_WMI_EVENT_GUID;
96 	}
97 }
98 
99 
100 WMIAsus::~WMIAsus()
101 {
102 	// for ALS
103 	if (fEnableALS && _EnableAls(0) == B_OK) {
104 		TRACE("ALSC disabled\n");
105 	}
106 
107 	if (fEventGuidString != NULL)
108 		wmi->remove_event_handler(wmi_cookie, fEventGuidString);
109 }
110 
111 
112 status_t
113 WMIAsus::_EvaluateMethod(uint32 methodId, uint32 arg0, uint32 arg1,
114 	uint32 *returnValue)
115 {
116 	CALLED();
117 	uint32 params[] = { arg0, arg1 };
118 	acpi_data inBuffer = { sizeof(params), params };
119 	acpi_data outBuffer = { ACPI_ALLOCATE_BUFFER, NULL };
120 	status_t status = wmi->evaluate_method(wmi_cookie, 0, methodId, &inBuffer,
121 		&outBuffer);
122 	if (status != B_OK)
123 		return status;
124 
125 	acpi_object_type* object = (acpi_object_type*)outBuffer.pointer;
126 	uint32 result = 0;
127 	if (object != NULL) {
128 		if (object->object_type == ACPI_TYPE_INTEGER)
129 			result = object->integer.integer;
130 		free(object);
131 	}
132 	if (returnValue != NULL)
133 		*returnValue = result;
134 
135 	return B_OK;
136 }
137 
138 
139 status_t
140 WMIAsus::_EnableAls(uint32 enable)
141 {
142 	CALLED();
143 	return _SetDevState(ASUS_WMI_DEVID_ALS_ENABLE, enable, NULL);
144 }
145 
146 
147 status_t
148 WMIAsus::_GetDevState(uint32 devId, uint32 *value)
149 {
150 	return _EvaluateMethod(fDstsID, devId, 0, value);
151 }
152 
153 
154 status_t
155 WMIAsus::_SetDevState(uint32 devId, uint32 arg, uint32 *value)
156 {
157 	return _EvaluateMethod(ASUS_WMI_METHODID_DEVS, devId, arg, value);
158 }
159 
160 
161 void
162 WMIAsus::_NotifyHandler(acpi_handle handle, uint32 notify, void *context)
163 {
164 	WMIAsus* device = (WMIAsus*)context;
165 	device->_Notify(handle, notify);
166 }
167 
168 
169 void
170 WMIAsus::_Notify(acpi_handle handle, uint32 notify)
171 {
172 	CALLED();
173 
174 	acpi_data response = { ACPI_ALLOCATE_BUFFER, NULL };
175 	wmi->get_event_data(wmi_cookie, notify, &response);
176 
177 	acpi_object_type* object = (acpi_object_type*)response.pointer;
178 	uint32 result = 0;
179 	if (object != NULL) {
180 		if (object->object_type == ACPI_TYPE_INTEGER)
181 			result = object->integer.integer;
182 		free(object);
183 	}
184 	if (result != 0) {
185 		if (result == 0xc4 || result == 0xc5) {
186 			TRACE("WMIAsus::_Notify() keyboard backlight key\n");
187 			uint32 value;
188 			if (_GetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT, &value) == B_OK) {
189 				TRACE("WMIAsus::_Notify() getkeyboard backlight key %"
190 					B_PRIx32 "\n", value);
191 				value &= 0x7;
192 				if (result == 0xc4) {
193 					if (value < 3)
194 						value++;
195 				} else if (value > 0)
196 					value--;
197 				TRACE("WMIAsus::_Notify() set keyboard backlight key %"
198 					B_PRIx32 "\n", value);
199 				_SetDevState(ASUS_WMI_DEVID_KBD_BACKLIGHT, value | 0x80, NULL);
200 			}
201 		} else if (result == 0x6b) {
202 			TRACE("WMIAsus::_Notify() touchpad control\n");
203 		} else {
204 			TRACE("WMIAsus::_Notify() key 0x%" B_PRIx32 "\n", result);
205 		}
206 	}
207 }
208 
209 
210 //	#pragma mark - driver module API
211 
212 
213 static float
214 wmi_asus_support(device_node *parent)
215 {
216 	// make sure parent is really a wmi device
217 	const char *bus;
218 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
219 		return -1;
220 
221 	if (strcmp(bus, "wmi"))
222 		return 0.0;
223 
224 	// check whether it's an asus wmi device
225 	const char *guid;
226 	if (gDeviceManager->get_attr_string(parent, WMI_GUID_STRING_ITEM, &guid,
227 		false) != B_OK || strcmp(guid, ACPI_ASUS_WMI_MGMT_GUID) != 0) {
228 		return 0.0;
229 	}
230 
231 	TRACE("found an asus wmi device\n");
232 
233 	return 0.6;
234 }
235 
236 
237 static status_t
238 wmi_asus_register_device(device_node *node)
239 {
240 	CALLED();
241 	device_attr attrs[] = {
242 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "WMI ASUS" }},
243 		{ NULL }
244 	};
245 
246 	return gDeviceManager->register_node(node, WMI_ASUS_DRIVER_NAME, attrs,
247 		NULL, NULL);
248 }
249 
250 
251 static status_t
252 wmi_asus_init_driver(device_node *node, void **driverCookie)
253 {
254 	CALLED();
255 
256 	WMIAsus* device = new(std::nothrow) WMIAsus(node);
257 	if (device == NULL)
258 		return B_NO_MEMORY;
259 	*driverCookie = device;
260 
261 	return B_OK;
262 }
263 
264 
265 static void
266 wmi_asus_uninit_driver(void *driverCookie)
267 {
268 	CALLED();
269 	WMIAsus* device = (WMIAsus*)driverCookie;
270 	delete device;
271 }
272 
273 
274 static status_t
275 wmi_asus_register_child_devices(void *cookie)
276 {
277 	CALLED();
278 	return B_OK;
279 }
280 
281 
282 driver_module_info gWMIAsusDriverModule = {
283 	{
284 		WMI_ASUS_DRIVER_NAME,
285 		0,
286 		NULL
287 	},
288 
289 	wmi_asus_support,
290 	wmi_asus_register_device,
291 	wmi_asus_init_driver,
292 	wmi_asus_uninit_driver,
293 	wmi_asus_register_child_devices,
294 	NULL,	// rescan
295 	NULL,	// removed
296 };
297 
298