wmi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. /*
  2. * ACPI-WMI mapping driver
  3. *
  4. * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
  5. *
  6. * GUID parsing code from ldm.c is:
  7. * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
  8. * Copyright (c) 2001-2007 Anton Altaparmakov
  9. * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
  10. *
  11. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 2 of the License, or (at
  16. * your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful, but
  19. * WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License along
  24. * with this program; if not, write to the Free Software Foundation, Inc.,
  25. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  26. *
  27. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  28. */
  29. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  30. #include <linux/kernel.h>
  31. #include <linux/init.h>
  32. #include <linux/types.h>
  33. #include <linux/device.h>
  34. #include <linux/list.h>
  35. #include <linux/acpi.h>
  36. #include <linux/slab.h>
  37. #include <acpi/acpi_bus.h>
  38. #include <acpi/acpi_drivers.h>
  39. ACPI_MODULE_NAME("wmi");
  40. MODULE_AUTHOR("Carlos Corbacho");
  41. MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
  42. MODULE_LICENSE("GPL");
  43. #define ACPI_WMI_CLASS "wmi"
  44. static DEFINE_MUTEX(wmi_data_lock);
  45. static LIST_HEAD(wmi_block_list);
  46. struct guid_block {
  47. char guid[16];
  48. union {
  49. char object_id[2];
  50. struct {
  51. unsigned char notify_id;
  52. unsigned char reserved;
  53. };
  54. };
  55. u8 instance_count;
  56. u8 flags;
  57. };
  58. struct wmi_block {
  59. struct list_head list;
  60. struct guid_block gblock;
  61. acpi_handle handle;
  62. wmi_notify_handler handler;
  63. void *handler_data;
  64. struct device dev;
  65. };
  66. /*
  67. * If the GUID data block is marked as expensive, we must enable and
  68. * explicitily disable data collection.
  69. */
  70. #define ACPI_WMI_EXPENSIVE 0x1
  71. #define ACPI_WMI_METHOD 0x2 /* GUID is a method */
  72. #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
  73. #define ACPI_WMI_EVENT 0x8 /* GUID is an event */
  74. static int debug_event;
  75. module_param(debug_event, bool, 0444);
  76. MODULE_PARM_DESC(debug_event,
  77. "Log WMI Events [0/1]");
  78. static int debug_dump_wdg;
  79. module_param(debug_dump_wdg, bool, 0444);
  80. MODULE_PARM_DESC(debug_dump_wdg,
  81. "Dump available WMI interfaces [0/1]");
  82. static int acpi_wmi_remove(struct acpi_device *device, int type);
  83. static int acpi_wmi_add(struct acpi_device *device);
  84. static void acpi_wmi_notify(struct acpi_device *device, u32 event);
  85. static const struct acpi_device_id wmi_device_ids[] = {
  86. {"PNP0C14", 0},
  87. {"pnp0c14", 0},
  88. {"", 0},
  89. };
  90. MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
  91. static struct acpi_driver acpi_wmi_driver = {
  92. .name = "wmi",
  93. .class = ACPI_WMI_CLASS,
  94. .ids = wmi_device_ids,
  95. .ops = {
  96. .add = acpi_wmi_add,
  97. .remove = acpi_wmi_remove,
  98. .notify = acpi_wmi_notify,
  99. },
  100. };
  101. /*
  102. * GUID parsing functions
  103. */
  104. /**
  105. * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
  106. * @src: Pointer to at least 2 characters to convert.
  107. *
  108. * Convert a two character ASCII hex string to a number.
  109. *
  110. * Return: 0-255 Success, the byte was parsed correctly
  111. * -1 Error, an invalid character was supplied
  112. */
  113. static int wmi_parse_hexbyte(const u8 *src)
  114. {
  115. int h;
  116. int value;
  117. /* high part */
  118. h = value = hex_to_bin(src[0]);
  119. if (value < 0)
  120. return -1;
  121. /* low part */
  122. value = hex_to_bin(src[1]);
  123. if (value >= 0)
  124. return (h << 4) | value;
  125. return -1;
  126. }
  127. /**
  128. * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
  129. * @src: Memory block holding binary GUID (16 bytes)
  130. * @dest: Memory block to hold byte swapped binary GUID (16 bytes)
  131. *
  132. * Byte swap a binary GUID to match it's real GUID value
  133. */
  134. static void wmi_swap_bytes(u8 *src, u8 *dest)
  135. {
  136. int i;
  137. for (i = 0; i <= 3; i++)
  138. memcpy(dest + i, src + (3 - i), 1);
  139. for (i = 0; i <= 1; i++)
  140. memcpy(dest + 4 + i, src + (5 - i), 1);
  141. for (i = 0; i <= 1; i++)
  142. memcpy(dest + 6 + i, src + (7 - i), 1);
  143. memcpy(dest + 8, src + 8, 8);
  144. }
  145. /**
  146. * wmi_parse_guid - Convert GUID from ASCII to binary
  147. * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
  148. * @dest: Memory block to hold binary GUID (16 bytes)
  149. *
  150. * N.B. The GUID need not be NULL terminated.
  151. *
  152. * Return: 'true' @dest contains binary GUID
  153. * 'false' @dest contents are undefined
  154. */
  155. static bool wmi_parse_guid(const u8 *src, u8 *dest)
  156. {
  157. static const int size[] = { 4, 2, 2, 2, 6 };
  158. int i, j, v;
  159. if (src[8] != '-' || src[13] != '-' ||
  160. src[18] != '-' || src[23] != '-')
  161. return false;
  162. for (j = 0; j < 5; j++, src++) {
  163. for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
  164. v = wmi_parse_hexbyte(src);
  165. if (v < 0)
  166. return false;
  167. }
  168. }
  169. return true;
  170. }
  171. /*
  172. * Convert a raw GUID to the ACII string representation
  173. */
  174. static int wmi_gtoa(const char *in, char *out)
  175. {
  176. int i;
  177. for (i = 3; i >= 0; i--)
  178. out += sprintf(out, "%02X", in[i] & 0xFF);
  179. out += sprintf(out, "-");
  180. out += sprintf(out, "%02X", in[5] & 0xFF);
  181. out += sprintf(out, "%02X", in[4] & 0xFF);
  182. out += sprintf(out, "-");
  183. out += sprintf(out, "%02X", in[7] & 0xFF);
  184. out += sprintf(out, "%02X", in[6] & 0xFF);
  185. out += sprintf(out, "-");
  186. out += sprintf(out, "%02X", in[8] & 0xFF);
  187. out += sprintf(out, "%02X", in[9] & 0xFF);
  188. out += sprintf(out, "-");
  189. for (i = 10; i <= 15; i++)
  190. out += sprintf(out, "%02X", in[i] & 0xFF);
  191. *out = '\0';
  192. return 0;
  193. }
  194. static bool find_guid(const char *guid_string, struct wmi_block **out)
  195. {
  196. char tmp[16], guid_input[16];
  197. struct wmi_block *wblock;
  198. struct guid_block *block;
  199. struct list_head *p;
  200. wmi_parse_guid(guid_string, tmp);
  201. wmi_swap_bytes(tmp, guid_input);
  202. list_for_each(p, &wmi_block_list) {
  203. wblock = list_entry(p, struct wmi_block, list);
  204. block = &wblock->gblock;
  205. if (memcmp(block->guid, guid_input, 16) == 0) {
  206. if (out)
  207. *out = wblock;
  208. return 1;
  209. }
  210. }
  211. return 0;
  212. }
  213. static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
  214. {
  215. struct guid_block *block = NULL;
  216. char method[5];
  217. struct acpi_object_list input;
  218. union acpi_object params[1];
  219. acpi_status status;
  220. acpi_handle handle;
  221. block = &wblock->gblock;
  222. handle = wblock->handle;
  223. if (!block)
  224. return AE_NOT_EXIST;
  225. input.count = 1;
  226. input.pointer = params;
  227. params[0].type = ACPI_TYPE_INTEGER;
  228. params[0].integer.value = enable;
  229. snprintf(method, 5, "WE%02X", block->notify_id);
  230. status = acpi_evaluate_object(handle, method, &input, NULL);
  231. if (status != AE_OK && status != AE_NOT_FOUND)
  232. return status;
  233. else
  234. return AE_OK;
  235. }
  236. /*
  237. * Exported WMI functions
  238. */
  239. /**
  240. * wmi_evaluate_method - Evaluate a WMI method
  241. * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
  242. * @instance: Instance index
  243. * @method_id: Method ID to call
  244. * &in: Buffer containing input for the method call
  245. * &out: Empty buffer to return the method results
  246. *
  247. * Call an ACPI-WMI method
  248. */
  249. acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
  250. u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
  251. {
  252. struct guid_block *block = NULL;
  253. struct wmi_block *wblock = NULL;
  254. acpi_handle handle;
  255. acpi_status status;
  256. struct acpi_object_list input;
  257. union acpi_object params[3];
  258. char method[5] = "WM";
  259. if (!find_guid(guid_string, &wblock))
  260. return AE_ERROR;
  261. block = &wblock->gblock;
  262. handle = wblock->handle;
  263. if (!(block->flags & ACPI_WMI_METHOD))
  264. return AE_BAD_DATA;
  265. if (block->instance_count < instance)
  266. return AE_BAD_PARAMETER;
  267. input.count = 2;
  268. input.pointer = params;
  269. params[0].type = ACPI_TYPE_INTEGER;
  270. params[0].integer.value = instance;
  271. params[1].type = ACPI_TYPE_INTEGER;
  272. params[1].integer.value = method_id;
  273. if (in) {
  274. input.count = 3;
  275. if (block->flags & ACPI_WMI_STRING) {
  276. params[2].type = ACPI_TYPE_STRING;
  277. } else {
  278. params[2].type = ACPI_TYPE_BUFFER;
  279. }
  280. params[2].buffer.length = in->length;
  281. params[2].buffer.pointer = in->pointer;
  282. }
  283. strncat(method, block->object_id, 2);
  284. status = acpi_evaluate_object(handle, method, &input, out);
  285. return status;
  286. }
  287. EXPORT_SYMBOL_GPL(wmi_evaluate_method);
  288. /**
  289. * wmi_query_block - Return contents of a WMI block
  290. * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
  291. * @instance: Instance index
  292. * &out: Empty buffer to return the contents of the data block to
  293. *
  294. * Return the contents of an ACPI-WMI data block to a buffer
  295. */
  296. acpi_status wmi_query_block(const char *guid_string, u8 instance,
  297. struct acpi_buffer *out)
  298. {
  299. struct guid_block *block = NULL;
  300. struct wmi_block *wblock = NULL;
  301. acpi_handle handle, wc_handle;
  302. acpi_status status, wc_status = AE_ERROR;
  303. struct acpi_object_list input, wc_input;
  304. union acpi_object wc_params[1], wq_params[1];
  305. char method[5];
  306. char wc_method[5] = "WC";
  307. if (!guid_string || !out)
  308. return AE_BAD_PARAMETER;
  309. if (!find_guid(guid_string, &wblock))
  310. return AE_ERROR;
  311. block = &wblock->gblock;
  312. handle = wblock->handle;
  313. if (block->instance_count < instance)
  314. return AE_BAD_PARAMETER;
  315. /* Check GUID is a data block */
  316. if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
  317. return AE_ERROR;
  318. input.count = 1;
  319. input.pointer = wq_params;
  320. wq_params[0].type = ACPI_TYPE_INTEGER;
  321. wq_params[0].integer.value = instance;
  322. /*
  323. * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
  324. * enable collection.
  325. */
  326. if (block->flags & ACPI_WMI_EXPENSIVE) {
  327. wc_input.count = 1;
  328. wc_input.pointer = wc_params;
  329. wc_params[0].type = ACPI_TYPE_INTEGER;
  330. wc_params[0].integer.value = 1;
  331. strncat(wc_method, block->object_id, 2);
  332. /*
  333. * Some GUIDs break the specification by declaring themselves
  334. * expensive, but have no corresponding WCxx method. So we
  335. * should not fail if this happens.
  336. */
  337. wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
  338. if (ACPI_SUCCESS(wc_status))
  339. wc_status = acpi_evaluate_object(handle, wc_method,
  340. &wc_input, NULL);
  341. }
  342. strcpy(method, "WQ");
  343. strncat(method, block->object_id, 2);
  344. status = acpi_evaluate_object(handle, method, &input, out);
  345. /*
  346. * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
  347. * the WQxx method failed - we should disable collection anyway.
  348. */
  349. if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
  350. wc_params[0].integer.value = 0;
  351. status = acpi_evaluate_object(handle,
  352. wc_method, &wc_input, NULL);
  353. }
  354. return status;
  355. }
  356. EXPORT_SYMBOL_GPL(wmi_query_block);
  357. /**
  358. * wmi_set_block - Write to a WMI block
  359. * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
  360. * @instance: Instance index
  361. * &in: Buffer containing new values for the data block
  362. *
  363. * Write the contents of the input buffer to an ACPI-WMI data block
  364. */
  365. acpi_status wmi_set_block(const char *guid_string, u8 instance,
  366. const struct acpi_buffer *in)
  367. {
  368. struct guid_block *block = NULL;
  369. struct wmi_block *wblock = NULL;
  370. acpi_handle handle;
  371. struct acpi_object_list input;
  372. union acpi_object params[2];
  373. char method[5] = "WS";
  374. if (!guid_string || !in)
  375. return AE_BAD_DATA;
  376. if (!find_guid(guid_string, &wblock))
  377. return AE_ERROR;
  378. block = &wblock->gblock;
  379. handle = wblock->handle;
  380. if (block->instance_count < instance)
  381. return AE_BAD_PARAMETER;
  382. /* Check GUID is a data block */
  383. if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
  384. return AE_ERROR;
  385. input.count = 2;
  386. input.pointer = params;
  387. params[0].type = ACPI_TYPE_INTEGER;
  388. params[0].integer.value = instance;
  389. if (block->flags & ACPI_WMI_STRING) {
  390. params[1].type = ACPI_TYPE_STRING;
  391. } else {
  392. params[1].type = ACPI_TYPE_BUFFER;
  393. }
  394. params[1].buffer.length = in->length;
  395. params[1].buffer.pointer = in->pointer;
  396. strncat(method, block->object_id, 2);
  397. return acpi_evaluate_object(handle, method, &input, NULL);
  398. }
  399. EXPORT_SYMBOL_GPL(wmi_set_block);
  400. static void wmi_dump_wdg(const struct guid_block *g)
  401. {
  402. char guid_string[37];
  403. wmi_gtoa(g->guid, guid_string);
  404. pr_info("%s:\n", guid_string);
  405. pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]);
  406. pr_info("\tnotify_id: %02X\n", g->notify_id);
  407. pr_info("\treserved: %02X\n", g->reserved);
  408. pr_info("\tinstance_count: %d\n", g->instance_count);
  409. pr_info("\tflags: %#x", g->flags);
  410. if (g->flags) {
  411. if (g->flags & ACPI_WMI_EXPENSIVE)
  412. pr_cont(" ACPI_WMI_EXPENSIVE");
  413. if (g->flags & ACPI_WMI_METHOD)
  414. pr_cont(" ACPI_WMI_METHOD");
  415. if (g->flags & ACPI_WMI_STRING)
  416. pr_cont(" ACPI_WMI_STRING");
  417. if (g->flags & ACPI_WMI_EVENT)
  418. pr_cont(" ACPI_WMI_EVENT");
  419. }
  420. pr_cont("\n");
  421. }
  422. static void wmi_notify_debug(u32 value, void *context)
  423. {
  424. struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
  425. union acpi_object *obj;
  426. acpi_status status;
  427. status = wmi_get_event_data(value, &response);
  428. if (status != AE_OK) {
  429. pr_info("bad event status 0x%x\n", status);
  430. return;
  431. }
  432. obj = (union acpi_object *)response.pointer;
  433. if (!obj)
  434. return;
  435. pr_info("DEBUG Event ");
  436. switch(obj->type) {
  437. case ACPI_TYPE_BUFFER:
  438. pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
  439. break;
  440. case ACPI_TYPE_STRING:
  441. pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
  442. break;
  443. case ACPI_TYPE_INTEGER:
  444. pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
  445. break;
  446. case ACPI_TYPE_PACKAGE:
  447. pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
  448. break;
  449. default:
  450. pr_cont("object type 0x%X\n", obj->type);
  451. }
  452. kfree(obj);
  453. }
  454. /**
  455. * wmi_install_notify_handler - Register handler for WMI events
  456. * @handler: Function to handle notifications
  457. * @data: Data to be returned to handler when event is fired
  458. *
  459. * Register a handler for events sent to the ACPI-WMI mapper device.
  460. */
  461. acpi_status wmi_install_notify_handler(const char *guid,
  462. wmi_notify_handler handler, void *data)
  463. {
  464. struct wmi_block *block;
  465. acpi_status status = AE_NOT_EXIST;
  466. char tmp[16], guid_input[16];
  467. struct list_head *p;
  468. if (!guid || !handler)
  469. return AE_BAD_PARAMETER;
  470. wmi_parse_guid(guid, tmp);
  471. wmi_swap_bytes(tmp, guid_input);
  472. list_for_each(p, &wmi_block_list) {
  473. acpi_status wmi_status;
  474. block = list_entry(p, struct wmi_block, list);
  475. if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
  476. if (block->handler &&
  477. block->handler != wmi_notify_debug)
  478. return AE_ALREADY_ACQUIRED;
  479. block->handler = handler;
  480. block->handler_data = data;
  481. wmi_status = wmi_method_enable(block, 1);
  482. if ((wmi_status != AE_OK) ||
  483. ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
  484. status = wmi_status;
  485. }
  486. }
  487. return status;
  488. }
  489. EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
  490. /**
  491. * wmi_uninstall_notify_handler - Unregister handler for WMI events
  492. *
  493. * Unregister handler for events sent to the ACPI-WMI mapper device.
  494. */
  495. acpi_status wmi_remove_notify_handler(const char *guid)
  496. {
  497. struct wmi_block *block;
  498. acpi_status status = AE_NOT_EXIST;
  499. char tmp[16], guid_input[16];
  500. struct list_head *p;
  501. if (!guid)
  502. return AE_BAD_PARAMETER;
  503. wmi_parse_guid(guid, tmp);
  504. wmi_swap_bytes(tmp, guid_input);
  505. list_for_each(p, &wmi_block_list) {
  506. acpi_status wmi_status;
  507. block = list_entry(p, struct wmi_block, list);
  508. if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
  509. if (!block->handler ||
  510. block->handler == wmi_notify_debug)
  511. return AE_NULL_ENTRY;
  512. if (debug_event) {
  513. block->handler = wmi_notify_debug;
  514. status = AE_OK;
  515. } else {
  516. wmi_status = wmi_method_enable(block, 0);
  517. block->handler = NULL;
  518. block->handler_data = NULL;
  519. if ((wmi_status != AE_OK) ||
  520. ((wmi_status == AE_OK) &&
  521. (status == AE_NOT_EXIST)))
  522. status = wmi_status;
  523. }
  524. }
  525. }
  526. return status;
  527. }
  528. EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
  529. /**
  530. * wmi_get_event_data - Get WMI data associated with an event
  531. *
  532. * @event: Event to find
  533. * @out: Buffer to hold event data. out->pointer should be freed with kfree()
  534. *
  535. * Returns extra data associated with an event in WMI.
  536. */
  537. acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
  538. {
  539. struct acpi_object_list input;
  540. union acpi_object params[1];
  541. struct guid_block *gblock;
  542. struct wmi_block *wblock;
  543. struct list_head *p;
  544. input.count = 1;
  545. input.pointer = params;
  546. params[0].type = ACPI_TYPE_INTEGER;
  547. params[0].integer.value = event;
  548. list_for_each(p, &wmi_block_list) {
  549. wblock = list_entry(p, struct wmi_block, list);
  550. gblock = &wblock->gblock;
  551. if ((gblock->flags & ACPI_WMI_EVENT) &&
  552. (gblock->notify_id == event))
  553. return acpi_evaluate_object(wblock->handle, "_WED",
  554. &input, out);
  555. }
  556. return AE_NOT_FOUND;
  557. }
  558. EXPORT_SYMBOL_GPL(wmi_get_event_data);
  559. /**
  560. * wmi_has_guid - Check if a GUID is available
  561. * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
  562. *
  563. * Check if a given GUID is defined by _WDG
  564. */
  565. bool wmi_has_guid(const char *guid_string)
  566. {
  567. return find_guid(guid_string, NULL);
  568. }
  569. EXPORT_SYMBOL_GPL(wmi_has_guid);
  570. /*
  571. * sysfs interface
  572. */
  573. static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
  574. char *buf)
  575. {
  576. char guid_string[37];
  577. struct wmi_block *wblock;
  578. wblock = dev_get_drvdata(dev);
  579. if (!wblock)
  580. return -ENOMEM;
  581. wmi_gtoa(wblock->gblock.guid, guid_string);
  582. return sprintf(buf, "wmi:%s\n", guid_string);
  583. }
  584. static struct device_attribute wmi_dev_attrs[] = {
  585. __ATTR_RO(modalias),
  586. __ATTR_NULL
  587. };
  588. static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
  589. {
  590. char guid_string[37];
  591. struct wmi_block *wblock;
  592. if (add_uevent_var(env, "MODALIAS="))
  593. return -ENOMEM;
  594. wblock = dev_get_drvdata(dev);
  595. if (!wblock)
  596. return -ENOMEM;
  597. wmi_gtoa(wblock->gblock.guid, guid_string);
  598. strcpy(&env->buf[env->buflen - 1], "wmi:");
  599. memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
  600. env->buflen += 40;
  601. return 0;
  602. }
  603. static void wmi_dev_free(struct device *dev)
  604. {
  605. struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
  606. kfree(wmi_block);
  607. }
  608. static struct class wmi_class = {
  609. .name = "wmi",
  610. .dev_release = wmi_dev_free,
  611. .dev_uevent = wmi_dev_uevent,
  612. .dev_attrs = wmi_dev_attrs,
  613. };
  614. static int wmi_create_device(const struct guid_block *gblock,
  615. struct wmi_block *wblock, acpi_handle handle)
  616. {
  617. char guid_string[37];
  618. wblock->dev.class = &wmi_class;
  619. wmi_gtoa(gblock->guid, guid_string);
  620. dev_set_name(&wblock->dev, guid_string);
  621. dev_set_drvdata(&wblock->dev, wblock);
  622. return device_register(&wblock->dev);
  623. }
  624. static void wmi_free_devices(void)
  625. {
  626. struct wmi_block *wblock, *next;
  627. /* Delete devices for all the GUIDs */
  628. list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
  629. if (wblock->dev.class)
  630. device_unregister(&wblock->dev);
  631. }
  632. static bool guid_already_parsed(const char *guid_string)
  633. {
  634. struct wmi_block *wblock;
  635. list_for_each_entry(wblock, &wmi_block_list, list)
  636. if (memcmp(wblock->gblock.guid, guid_string, 16) == 0)
  637. return true;
  638. return false;
  639. }
  640. /*
  641. * Parse the _WDG method for the GUID data blocks
  642. */
  643. static acpi_status parse_wdg(acpi_handle handle)
  644. {
  645. struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
  646. union acpi_object *obj;
  647. const struct guid_block *gblock;
  648. struct wmi_block *wblock;
  649. acpi_status status;
  650. int retval;
  651. u32 i, total;
  652. status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
  653. if (ACPI_FAILURE(status))
  654. return -ENXIO;
  655. obj = (union acpi_object *) out.pointer;
  656. if (!obj)
  657. return -ENXIO;
  658. if (obj->type != ACPI_TYPE_BUFFER) {
  659. retval = -ENXIO;
  660. goto out_free_pointer;
  661. }
  662. gblock = (const struct guid_block *)obj->buffer.pointer;
  663. total = obj->buffer.length / sizeof(struct guid_block);
  664. for (i = 0; i < total; i++) {
  665. if (debug_dump_wdg)
  666. wmi_dump_wdg(&gblock[i]);
  667. wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
  668. if (!wblock)
  669. return AE_NO_MEMORY;
  670. wblock->handle = handle;
  671. wblock->gblock = gblock[i];
  672. /*
  673. Some WMI devices, like those for nVidia hooks, have a
  674. duplicate GUID. It's not clear what we should do in this
  675. case yet, so for now, we'll just ignore the duplicate
  676. for device creation.
  677. */
  678. if (!guid_already_parsed(gblock[i].guid)) {
  679. retval = wmi_create_device(&gblock[i], wblock, handle);
  680. if (retval) {
  681. wmi_free_devices();
  682. goto out_free_pointer;
  683. }
  684. }
  685. list_add_tail(&wblock->list, &wmi_block_list);
  686. if (debug_event) {
  687. wblock->handler = wmi_notify_debug;
  688. wmi_method_enable(wblock, 1);
  689. }
  690. }
  691. retval = 0;
  692. out_free_pointer:
  693. kfree(out.pointer);
  694. return retval;
  695. }
  696. /*
  697. * WMI can have EmbeddedControl access regions. In which case, we just want to
  698. * hand these off to the EC driver.
  699. */
  700. static acpi_status
  701. acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
  702. u32 bits, u64 *value,
  703. void *handler_context, void *region_context)
  704. {
  705. int result = 0, i = 0;
  706. u8 temp = 0;
  707. if ((address > 0xFF) || !value)
  708. return AE_BAD_PARAMETER;
  709. if (function != ACPI_READ && function != ACPI_WRITE)
  710. return AE_BAD_PARAMETER;
  711. if (bits != 8)
  712. return AE_BAD_PARAMETER;
  713. if (function == ACPI_READ) {
  714. result = ec_read(address, &temp);
  715. (*value) |= ((u64)temp) << i;
  716. } else {
  717. temp = 0xff & ((*value) >> i);
  718. result = ec_write(address, temp);
  719. }
  720. switch (result) {
  721. case -EINVAL:
  722. return AE_BAD_PARAMETER;
  723. break;
  724. case -ENODEV:
  725. return AE_NOT_FOUND;
  726. break;
  727. case -ETIME:
  728. return AE_TIME;
  729. break;
  730. default:
  731. return AE_OK;
  732. }
  733. }
  734. static void acpi_wmi_notify(struct acpi_device *device, u32 event)
  735. {
  736. struct guid_block *block;
  737. struct wmi_block *wblock;
  738. struct list_head *p;
  739. char guid_string[37];
  740. list_for_each(p, &wmi_block_list) {
  741. wblock = list_entry(p, struct wmi_block, list);
  742. block = &wblock->gblock;
  743. if ((block->flags & ACPI_WMI_EVENT) &&
  744. (block->notify_id == event)) {
  745. if (wblock->handler)
  746. wblock->handler(event, wblock->handler_data);
  747. if (debug_event) {
  748. wmi_gtoa(wblock->gblock.guid, guid_string);
  749. pr_info("DEBUG Event GUID: %s\n", guid_string);
  750. }
  751. acpi_bus_generate_netlink_event(
  752. device->pnp.device_class, dev_name(&device->dev),
  753. event, 0);
  754. break;
  755. }
  756. }
  757. }
  758. static int acpi_wmi_remove(struct acpi_device *device, int type)
  759. {
  760. acpi_remove_address_space_handler(device->handle,
  761. ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
  762. wmi_free_devices();
  763. return 0;
  764. }
  765. static int acpi_wmi_add(struct acpi_device *device)
  766. {
  767. acpi_status status;
  768. int error;
  769. status = acpi_install_address_space_handler(device->handle,
  770. ACPI_ADR_SPACE_EC,
  771. &acpi_wmi_ec_space_handler,
  772. NULL, NULL);
  773. if (ACPI_FAILURE(status)) {
  774. pr_err("Error installing EC region handler\n");
  775. return -ENODEV;
  776. }
  777. error = parse_wdg(device->handle);
  778. if (error) {
  779. acpi_remove_address_space_handler(device->handle,
  780. ACPI_ADR_SPACE_EC,
  781. &acpi_wmi_ec_space_handler);
  782. pr_err("Failed to parse WDG method\n");
  783. return error;
  784. }
  785. return 0;
  786. }
  787. static int __init acpi_wmi_init(void)
  788. {
  789. int error;
  790. if (acpi_disabled)
  791. return -ENODEV;
  792. error = class_register(&wmi_class);
  793. if (error)
  794. return error;
  795. error = acpi_bus_register_driver(&acpi_wmi_driver);
  796. if (error) {
  797. pr_err("Error loading mapper\n");
  798. class_unregister(&wmi_class);
  799. return error;
  800. }
  801. pr_info("Mapper loaded\n");
  802. return 0;
  803. }
  804. static void __exit acpi_wmi_exit(void)
  805. {
  806. acpi_bus_unregister_driver(&acpi_wmi_driver);
  807. class_unregister(&wmi_class);
  808. pr_info("Mapper unloaded\n");
  809. }
  810. subsys_initcall(acpi_wmi_init);
  811. module_exit(acpi_wmi_exit);