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