surfaceacpi.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
  2. index 51ebc5a..244fa92 100644
  3. --- a/drivers/platform/x86/Kconfig
  4. +++ b/drivers/platform/x86/Kconfig
  5. @@ -1155,6 +1155,15 @@ config SURFACE_3_BUTTON
  6. ---help---
  7. This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
  8. +config ACPI_SURFACE
  9. + tristate "Microsoft Surface Extras"
  10. + depends on ACPI
  11. + depends on ACPI_WMI
  12. + depends on INPUT
  13. + ---help---
  14. + This driver adds support for access to certain system events
  15. + on Microsoft Surface devices.
  16. +
  17. config INTEL_PUNIT_IPC
  18. tristate "Intel P-Unit IPC Driver"
  19. ---help---
  20. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
  21. index 2ba6cb7..bcb0dd9 100644
  22. --- a/drivers/platform/x86/Makefile
  23. +++ b/drivers/platform/x86/Makefile
  24. @@ -81,6 +81,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
  25. obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o
  26. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  27. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  28. +obj-$(CONFIG_ACPI_SURFACE) += surface_acpi.o
  29. obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
  30. obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o
  31. obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
  32. diff --git a/drivers/platform/x86/surface_acpi.c b/drivers/platform/x86/surface_acpi.c
  33. new file mode 100644
  34. index 0000000..bee15e7
  35. --- /dev/null
  36. +++ b/drivers/platform/x86/surface_acpi.c
  37. @@ -0,0 +1,472 @@
  38. +/*
  39. + * surface_acpi.c - Microsoft Surface ACPI Notify
  40. + *
  41. + * This program is free software; you can redistribute it and/or modify
  42. + * it under the terms of the GNU General Public License as published by
  43. + * the Free Software Foundation; either version 2 of the License, or
  44. + * (at your option) any later version.
  45. + *
  46. + * This program is distributed in the hope that it will be useful,
  47. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  48. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  49. + * GNU General Public License for more details.
  50. + *
  51. + * The full GNU General Public License is included in this distribution in
  52. + * the file called "COPYING".
  53. + */
  54. +
  55. +#define SURFACE_ACPI_VERSION "0.1"
  56. +#define SURFACE_GEN_VERSION 0x08
  57. +#define PROC_SURFACE "surface"
  58. +
  59. +#include <linux/kernel.h>
  60. +#include <linux/module.h>
  61. +#include <linux/init.h>
  62. +#include <linux/types.h>
  63. +#include <linux/acpi.h>
  64. +#include <linux/power_supply.h>
  65. +#include <linux/thermal.h>
  66. +#include <linux/dmi.h>
  67. +#include <linux/seq_file.h>
  68. +#include <acpi/acpi_bus.h>
  69. +#include <acpi/acpi_drivers.h>
  70. +
  71. +MODULE_AUTHOR("Jake Day");
  72. +MODULE_DESCRIPTION("Microsoft Surface ACPI Notify Driver");
  73. +MODULE_LICENSE("GPL");
  74. +
  75. +#define SUR_METHOD_DSM "_DSM"
  76. +#define SUR_METHOD_REG "_REG"
  77. +#define SUR_METHOD_STA "_STA"
  78. +#define SUR_METHOD_INI "_INI"
  79. +#define SUR_METHOD_CRS "_CRS"
  80. +
  81. +#define SUR_QUERY_DEVICE 0x00
  82. +#define SUR_SET_DVER 0x01
  83. +#define SUR_GET_BOARD_REVID 0x02
  84. +#define SUR_BAT1_STATE_CHANGE 0x03
  85. +#define SUR_BAT1_INFO_CHANGE 0x04
  86. +#define SUR_PSU_STATE_CHANGE 0x05
  87. +#define SUR_PSU_INFO_CHANGE 0x06
  88. +#define SUR_BAT2_STATE_CHANGE 0x07
  89. +#define SUR_BAT2_INFO_CHANGE 0x08
  90. +#define SUR_SENSOR_TRIP_POINT 0x09
  91. +
  92. +#define REG_AVAILABLE 0x01
  93. +#define REG_INIT 0x09
  94. +
  95. +static char SURFACE_EVENT_GUID[] = "93b666c5-70c6-469f-a215-3d487c91ab3c";
  96. +static char SUR_SAN_RQST[] = "\\_SB._SAN.RQST";
  97. +static char SUR_SAN_RQSX[] = "\\_SB._SAN.RQSX";
  98. +
  99. +struct surface_acpi_dev {
  100. + acpi_handle handle;
  101. + acpi_handle rqst_handle;
  102. + acpi_handle rqsx_handle;
  103. +
  104. + struct acpi_device *san_dev;
  105. + struct acpi_device *ssh_dev;
  106. + struct acpi_device *bat1_dev;
  107. + struct acpi_device *bat2_dev;
  108. + struct acpi_device *psu_dev;
  109. +
  110. + unsigned int bat1_attached:1;
  111. + unsigned int bat2_attached:1;
  112. + unsigned int psu_registered:1;
  113. +};
  114. +
  115. +static struct surface_acpi_dev *surface_acpi;
  116. +
  117. +static struct proc_dir_entry *surface_proc_dir;
  118. +
  119. +static acpi_status surface_acpi_check_status(struct acpi_device *dev)
  120. +{
  121. + unsigned long long value;
  122. + acpi_status status;
  123. +
  124. + if (acpi_has_method(dev->handle, SUR_METHOD_STA)) {
  125. + status = acpi_evaluate_integer(dev->handle,
  126. + SUR_METHOD_STA, NULL, &value);
  127. +
  128. + if (ACPI_FAILURE(status)) {
  129. + pr_err("surface_acpi: ACPI event failure status %s\n",
  130. + acpi_format_exception(status));
  131. + return AE_ERROR;
  132. + }
  133. + }
  134. + else
  135. + return AE_NOT_FOUND;
  136. +
  137. + return AE_OK;
  138. +}
  139. +
  140. +static acpi_status surface_acpi_san_reg(void)
  141. +{
  142. + union acpi_object in_objs[2], out_objs[1];
  143. + struct acpi_object_list params;
  144. + struct acpi_buffer results;
  145. + acpi_status status;
  146. +
  147. + params.count = ARRAY_SIZE(in_objs);
  148. + params.pointer = in_objs;
  149. + in_objs[0].type = ACPI_TYPE_INTEGER;
  150. + in_objs[0].integer.value = REG_INIT;
  151. + in_objs[1].type = ACPI_TYPE_INTEGER;
  152. + in_objs[1].integer.value = REG_AVAILABLE;
  153. + results.length = sizeof(out_objs);
  154. + results.pointer = out_objs;
  155. +
  156. + if (acpi_has_method(surface_acpi->handle, SUR_METHOD_REG)) {
  157. + status = acpi_evaluate_object(surface_acpi->handle,
  158. + SUR_METHOD_REG, &params, &results);
  159. +
  160. + if (ACPI_FAILURE(status)) {
  161. + pr_err("surface_acpi: ACPI event failure status %s\n",
  162. + acpi_format_exception(status));
  163. + return AE_ERROR;
  164. + }
  165. + }
  166. + else
  167. + return AE_NOT_FOUND;
  168. +
  169. + return AE_OK;
  170. +}
  171. +
  172. +static acpi_status surface_acpi_event_handler(u32 event)
  173. +{
  174. + union acpi_object in_objs[4], out_objs[5];
  175. + struct acpi_object_list params;
  176. + struct acpi_buffer results;
  177. + acpi_status status;
  178. +
  179. + params.count = ARRAY_SIZE(in_objs);
  180. + params.pointer = in_objs;
  181. + in_objs[0].type = ACPI_TYPE_BUFFER;
  182. + in_objs[0].buffer.length = sizeof(SURFACE_EVENT_GUID);
  183. + in_objs[0].buffer.pointer = SURFACE_EVENT_GUID;
  184. + in_objs[1].type = ACPI_TYPE_INTEGER;
  185. + in_objs[1].integer.value = SUR_QUERY_DEVICE;
  186. + in_objs[2].type = ACPI_TYPE_INTEGER;
  187. + in_objs[2].integer.value = event;
  188. + in_objs[3].type = ACPI_TYPE_PACKAGE;
  189. + in_objs[3].package.count = 0;
  190. + in_objs[3].package.elements = SURFACE_GEN_VERSION;
  191. + results.length = sizeof(out_objs);
  192. + results.pointer = out_objs;
  193. +
  194. + if (acpi_has_method(surface_acpi->handle, SUR_METHOD_DSM)) {
  195. + status = acpi_evaluate_object(surface_acpi->handle,
  196. + SUR_METHOD_DSM, &params, &results);
  197. +
  198. + if (ACPI_FAILURE(status)) {
  199. + pr_err("surface_acpi: ACPI event failure status %s\n",
  200. + acpi_format_exception(status));
  201. + return AE_ERROR;
  202. + }
  203. + }
  204. + else
  205. + return AE_NOT_FOUND;
  206. +
  207. + return AE_OK;
  208. +}
  209. +
  210. +static void surface_acpi_san_load(void)
  211. +{
  212. + acpi_status ret;
  213. +
  214. + ret = surface_acpi_event_handler(SUR_SET_DVER);
  215. + if (ACPI_FAILURE(ret))
  216. + pr_err("surface_acpi: Error setting Driver Version\n");
  217. +
  218. + ret = surface_acpi_event_handler(SUR_SENSOR_TRIP_POINT);
  219. + if (ACPI_FAILURE(ret))
  220. + pr_err("surface_acpi: Error setting Sensor Trip Point\n");
  221. +
  222. + ret = surface_acpi_event_handler(SUR_BAT1_INFO_CHANGE);
  223. + if (ACPI_FAILURE(ret))
  224. + pr_err("surface_acpi: Error attaching BAT1\n");
  225. + else
  226. + surface_acpi->bat1_attached = 1;
  227. +
  228. + ret = surface_acpi_event_handler(SUR_BAT2_INFO_CHANGE);
  229. + if (ACPI_FAILURE(ret))
  230. + pr_err("surface_acpi: Error attaching BAT2\n");
  231. + else
  232. + surface_acpi->bat2_attached = 1;
  233. +
  234. + ret = surface_acpi_event_handler(SUR_PSU_INFO_CHANGE);
  235. + if (ACPI_FAILURE(ret))
  236. + pr_err("surface_acpi: Error registering PSU\n");
  237. + else
  238. + surface_acpi->psu_registered = 1;
  239. +}
  240. +
  241. +static acpi_status surface_acpi_ssh_initialize(void)
  242. +{
  243. + acpi_status status;
  244. +
  245. + if (acpi_has_method(surface_acpi->ssh_dev->handle, SUR_METHOD_INI)) {
  246. + status = acpi_evaluate_object(surface_acpi->ssh_dev->handle,
  247. + SUR_METHOD_INI, NULL, NULL);
  248. +
  249. + if (ACPI_FAILURE(status)) {
  250. + pr_err("surface_acpi: ACPI event failure status %s\n",
  251. + acpi_format_exception(status));
  252. + return AE_ERROR;
  253. + }
  254. + }
  255. + else
  256. + return AE_NOT_FOUND;
  257. +
  258. + return AE_OK;
  259. +}
  260. +
  261. +static int bat1_proc_show(struct seq_file *m, void *v)
  262. +{
  263. + seq_printf(m, "attached: %d\n", surface_acpi->bat1_attached);
  264. + return 0;
  265. +}
  266. +
  267. +static int bat1_proc_open(struct inode *inode, struct file *file)
  268. +{
  269. + return single_open(file, bat1_proc_show, PDE_DATA(inode));
  270. +}
  271. +
  272. +static const struct file_operations bat1_proc_fops = {
  273. + .owner = THIS_MODULE,
  274. + .open = bat1_proc_open,
  275. + .read = seq_read,
  276. + .llseek = seq_lseek,
  277. + .release = single_release,
  278. +};
  279. +
  280. +static int bat2_proc_show(struct seq_file *m, void *v)
  281. +{
  282. + seq_printf(m, "attached: %d\n", surface_acpi->bat2_attached);
  283. + return 0;
  284. +}
  285. +
  286. +static int bat2_proc_open(struct inode *inode, struct file *file)
  287. +{
  288. + return single_open(file, bat2_proc_show, PDE_DATA(inode));
  289. +}
  290. +
  291. +static const struct file_operations bat2_proc_fops = {
  292. + .owner = THIS_MODULE,
  293. + .open = bat2_proc_open,
  294. + .read = seq_read,
  295. + .llseek = seq_lseek,
  296. + .release = single_release,
  297. +};
  298. +
  299. +static int psu_proc_show(struct seq_file *m, void *v)
  300. +{
  301. + seq_printf(m, "registered: %d\n", surface_acpi->psu_registered);
  302. + return 0;
  303. +}
  304. +
  305. +static int psu_proc_open(struct inode *inode, struct file *file)
  306. +{
  307. + return single_open(file, psu_proc_show, PDE_DATA(inode));
  308. +}
  309. +
  310. +static const struct file_operations psu_proc_fops = {
  311. + .owner = THIS_MODULE,
  312. + .open = psu_proc_open,
  313. + .read = seq_read,
  314. + .llseek = seq_lseek,
  315. + .release = single_release,
  316. +};
  317. +
  318. +static int version_proc_show(struct seq_file *m, void *v)
  319. +{
  320. + seq_printf(m, "driver: %s\n", SURFACE_ACPI_VERSION);
  321. + return 0;
  322. +}
  323. +
  324. +static int version_proc_open(struct inode *inode, struct file *file)
  325. +{
  326. + return single_open(file, version_proc_show, PDE_DATA(inode));
  327. +}
  328. +
  329. +static const struct file_operations version_proc_fops = {
  330. + .owner = THIS_MODULE,
  331. + .open = version_proc_open,
  332. + .read = seq_read,
  333. + .llseek = seq_lseek,
  334. + .release = single_release,
  335. +};
  336. +
  337. +static void create_surface_proc_entries(void)
  338. +{
  339. + proc_create_data("BAT1", 0, surface_proc_dir,
  340. + &bat1_proc_fops, surface_acpi->bat1_attached);
  341. + proc_create_data("BAT2", 0, surface_proc_dir,
  342. + &bat2_proc_fops, surface_acpi->bat2_attached);
  343. + proc_create_data("ADP1", 0, surface_proc_dir,
  344. + &psu_proc_fops, surface_acpi->psu_registered);
  345. + proc_create_data("version", 0, surface_proc_dir,
  346. + &version_proc_fops, SURFACE_ACPI_VERSION);
  347. +}
  348. +
  349. +static void remove_surface_proc_entries(void)
  350. +{
  351. + remove_proc_entry("BAT1", surface_proc_dir);
  352. + remove_proc_entry("BAT2", surface_proc_dir);
  353. + remove_proc_entry("ADP1", surface_proc_dir);
  354. + remove_proc_entry("version", surface_proc_dir);
  355. +}
  356. +
  357. +static void surface_acpi_notify(struct acpi_device *dev, u32 event)
  358. +{
  359. + pr_info("surface_acpi: Event received %x\n", event);
  360. +}
  361. +
  362. +static void surface_acpi_register_rqst_handler(void)
  363. +{
  364. + acpi_status status;
  365. +
  366. + status = acpi_get_handle(NULL, SUR_SAN_RQST, &surface_acpi->rqst_handle);
  367. + if (ACPI_FAILURE(status)) {
  368. + pr_err("surface_acpi: ACPI event failure status %s\n",
  369. + acpi_format_exception(status));
  370. + }
  371. +}
  372. +
  373. +static void surface_acpi_register_rqsx_handler(void)
  374. +{
  375. + acpi_status status;
  376. +
  377. + status = acpi_get_handle(NULL, SUR_SAN_RQSX, &surface_acpi->rqsx_handle);
  378. + if (ACPI_FAILURE(status)) {
  379. + pr_err("surface_acpi: ACPI event failure status %s\n",
  380. + acpi_format_exception(status));
  381. + }
  382. +}
  383. +
  384. +static acpi_status surface_acpi_walk_callback(acpi_handle handle, u32 level,
  385. + void *context, void **return_value)
  386. +{
  387. + struct acpi_device_info *info;
  388. +
  389. + if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
  390. + pr_warn("method: name: %4.4s, args %X\n",
  391. + (char *)&info->name, info->param_count);
  392. +
  393. + kfree(info);
  394. + }
  395. +
  396. + return AE_OK;
  397. +}
  398. +
  399. +static void surface_acpi_walk_namespace(struct acpi_device *dev)
  400. +{
  401. + acpi_status status;
  402. +
  403. + status = acpi_walk_namespace(ACPI_TYPE_METHOD,
  404. + dev->handle, 1, surface_acpi_walk_callback,
  405. + NULL, NULL, NULL);
  406. + if (ACPI_FAILURE(status))
  407. + pr_warn("surface_acpi: Unable to walk acpi resources\n");
  408. +}
  409. +
  410. +static int surface_acpi_add(struct acpi_device *dev)
  411. +{
  412. + if (!surface_acpi)
  413. + {
  414. + surface_acpi = kzalloc(sizeof(*surface_acpi), GFP_KERNEL);
  415. + if (!surface_acpi)
  416. + return AE_NO_MEMORY;
  417. + }
  418. +
  419. + if (acpi_has_method(dev->handle, SUR_METHOD_DSM))
  420. + {
  421. + pr_info("surface_acpi: Attaching device MSHW0091\n");
  422. +
  423. + surface_acpi->san_dev = dev;
  424. + surface_acpi->handle = dev->handle;
  425. +
  426. + surface_acpi_walk_namespace(surface_acpi->san_dev);
  427. + surface_acpi_check_status(surface_acpi->san_dev);
  428. +
  429. + surface_acpi_register_rqst_handler();
  430. + surface_acpi_register_rqsx_handler();
  431. +
  432. + surface_acpi_san_reg();
  433. + surface_acpi_san_load();
  434. +
  435. + create_surface_proc_entries();
  436. + }
  437. + else
  438. + {
  439. + pr_info("surface_acpi: Attaching device MSHW0084\n");
  440. +
  441. + surface_acpi->ssh_dev = dev;
  442. +
  443. + surface_acpi_walk_namespace(surface_acpi->ssh_dev);
  444. + surface_acpi_check_status(surface_acpi->ssh_dev);
  445. +
  446. + surface_acpi_ssh_initialize();
  447. + //surface_acpi_ssh_load();
  448. + }
  449. +
  450. + return AE_OK;
  451. +}
  452. +
  453. +static int surface_acpi_remove(struct acpi_device *dev)
  454. +{
  455. + remove_surface_proc_entries();
  456. +
  457. + return AE_OK;
  458. +}
  459. +
  460. +static const struct acpi_device_id surface_device_ids[] = {
  461. + {"MSHW0091", 0},
  462. + {"MSHW0084", 0},
  463. + {"", 0},
  464. +};
  465. +MODULE_DEVICE_TABLE(acpi, surface_device_ids);
  466. +
  467. +static struct acpi_driver surface_acpi_driver = {
  468. + .name = "surface_acpi",
  469. + .owner = THIS_MODULE,
  470. + .ids = surface_device_ids,
  471. + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
  472. + .ops = {
  473. + .add = surface_acpi_add,
  474. + .remove = surface_acpi_remove,
  475. + .notify = surface_acpi_notify,
  476. + },
  477. +};
  478. +
  479. +static int __init surface_acpi_init(void)
  480. +{
  481. + int ret;
  482. +
  483. + pr_info("surface_acpi: Microsoft Surface ACPI Notify version %s\n",
  484. + SURFACE_ACPI_VERSION);
  485. +
  486. + surface_proc_dir = proc_mkdir(PROC_SURFACE, acpi_root_dir);
  487. + if (!surface_proc_dir) {
  488. + pr_err("surface_acpi: Unable to create proc dir " PROC_SURFACE "\n");
  489. + return -ENODEV;
  490. + }
  491. +
  492. + ret = acpi_bus_register_driver(&surface_acpi_driver);
  493. + if (ret) {
  494. + pr_err("surface_acpi: Failed to register ACPI driver: %d\n", ret);
  495. + remove_proc_entry(PROC_SURFACE, acpi_root_dir);
  496. + }
  497. +
  498. + return ret;
  499. +}
  500. +
  501. +static void __exit surface_acpi_exit(void)
  502. +{
  503. + acpi_bus_unregister_driver(&surface_acpi_driver);
  504. + if (surface_proc_dir)
  505. + remove_proc_entry(PROC_SURFACE, acpi_root_dir);
  506. +}
  507. +
  508. +module_init(surface_acpi_init);
  509. +module_exit(surface_acpi_exit);