0004-surface-buttons.patch 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. From 25c1108f70fde7cca28e5f851427108737443088 Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Sat, 27 Jul 2019 17:51:37 +0200
  4. Subject: [PATCH 04/10] surface-buttons
  5. ---
  6. drivers/input/misc/Kconfig | 6 +-
  7. drivers/input/misc/soc_button_array.c | 114 +++++++++++++++++++---
  8. drivers/platform/x86/surfacepro3_button.c | 47 +++++++++
  9. 3 files changed, 151 insertions(+), 16 deletions(-)
  10. diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
  11. index ca59a2be9bc5..ea69610370e8 100644
  12. --- a/drivers/input/misc/Kconfig
  13. +++ b/drivers/input/misc/Kconfig
  14. @@ -781,10 +781,10 @@ config INPUT_IDEAPAD_SLIDEBAR
  15. config INPUT_SOC_BUTTON_ARRAY
  16. tristate "Windows-compatible SoC Button Array"
  17. - depends on KEYBOARD_GPIO
  18. + depends on KEYBOARD_GPIO && ACPI
  19. help
  20. - Say Y here if you have a SoC-based tablet that originally
  21. - runs Windows 8.
  22. + Say Y here if you have a SoC-based tablet that originally runs
  23. + Windows 8 or a Microsoft Surface Book 2, Pro 5, Laptop 1 or later.
  24. To compile this driver as a module, choose M here: the
  25. module will be called soc_button_array.
  26. diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
  27. index 55cd6e0b409c..c564ea99f47d 100644
  28. --- a/drivers/input/misc/soc_button_array.c
  29. +++ b/drivers/input/misc/soc_button_array.c
  30. @@ -29,6 +29,11 @@ struct soc_button_info {
  31. bool wakeup;
  32. };
  33. +struct soc_device_data {
  34. + const struct soc_button_info *button_info;
  35. + int (*check)(struct device *dev);
  36. +};
  37. +
  38. /*
  39. * Some of the buttons like volume up/down are auto repeat, while others
  40. * are not. To support both, we register two platform devices, and put
  41. @@ -91,8 +96,20 @@ soc_button_device_create(struct platform_device *pdev,
  42. continue;
  43. gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
  44. - if (!gpio_is_valid(gpio))
  45. + if (!gpio_is_valid(gpio)) {
  46. + /*
  47. + * Skip GPIO if not present. Note we deliberately
  48. + * ignore -EPROBE_DEFER errors here. On some devices
  49. + * Intel is using so called virtual GPIOs which are not
  50. + * GPIOs at all but some way for AML code to check some
  51. + * random status bits without need a custom opregion.
  52. + * In some cases the resources table we parse points to
  53. + * such a virtual GPIO, since these are not real GPIOs
  54. + * we do not have a driver for these so they will never
  55. + * show up, therefor we ignore -EPROBE_DEFER.
  56. + */
  57. continue;
  58. + }
  59. gpio_keys[n_buttons].type = info->event_type;
  60. gpio_keys[n_buttons].code = info->event_code;
  61. @@ -309,23 +326,26 @@ static int soc_button_remove(struct platform_device *pdev)
  62. static int soc_button_probe(struct platform_device *pdev)
  63. {
  64. struct device *dev = &pdev->dev;
  65. - const struct acpi_device_id *id;
  66. - struct soc_button_info *button_info;
  67. + const struct soc_device_data *device_data;
  68. + const struct soc_button_info *button_info;
  69. struct soc_button_data *priv;
  70. struct platform_device *pd;
  71. int i;
  72. int error;
  73. - id = acpi_match_device(dev->driver->acpi_match_table, dev);
  74. - if (!id)
  75. - return -ENODEV;
  76. + device_data = acpi_device_get_match_data(dev);
  77. + if (device_data && device_data->check) {
  78. + error = device_data->check(dev);
  79. + if (error)
  80. + return error;
  81. + }
  82. - if (!id->driver_data) {
  83. + if (device_data && device_data->button_info) {
  84. + button_info = device_data->button_info;
  85. + } else {
  86. button_info = soc_button_get_button_info(dev);
  87. if (IS_ERR(button_info))
  88. return PTR_ERR(button_info);
  89. - } else {
  90. - button_info = (struct soc_button_info *)id->driver_data;
  91. }
  92. error = gpiod_count(dev, NULL);
  93. @@ -357,8 +377,8 @@ static int soc_button_probe(struct platform_device *pdev)
  94. if (!priv->children[0] && !priv->children[1])
  95. return -ENODEV;
  96. - if (!id->driver_data)
  97. - devm_kfree(dev, button_info);
  98. + if (!device_data || !device_data->button_info)
  99. + devm_kfree(dev, (void *)button_info);
  100. return 0;
  101. }
  102. @@ -368,7 +388,7 @@ static int soc_button_probe(struct platform_device *pdev)
  103. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  104. * Platforms"
  105. */
  106. -static struct soc_button_info soc_button_PNP0C40[] = {
  107. +static const struct soc_button_info soc_button_PNP0C40[] = {
  108. { "power", 0, EV_KEY, KEY_POWER, false, true },
  109. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
  110. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  111. @@ -377,9 +397,77 @@ static struct soc_button_info soc_button_PNP0C40[] = {
  112. { }
  113. };
  114. +static const struct soc_device_data soc_device_PNP0C40 = {
  115. + .button_info = soc_button_PNP0C40,
  116. +};
  117. +
  118. +/*
  119. + * Special device check for Surface Book 2 and Surface Pro (2017).
  120. + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  121. + * devices use MSHW0040 for power and volume buttons, however the way they
  122. + * have to be addressed differs. Make sure that we only load this drivers
  123. + * for the correct devices by checking the OEM Platform Revision provided by
  124. + * the _DSM method.
  125. + */
  126. +#define MSHW0040_DSM_REVISION 0x01
  127. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  128. +static const guid_t MSHW0040_DSM_UUID =
  129. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  130. + 0x49, 0x80, 0x35);
  131. +
  132. +static int soc_device_check_MSHW0040(struct device *dev)
  133. +{
  134. + acpi_handle handle = ACPI_HANDLE(dev);
  135. + union acpi_object *result;
  136. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  137. +
  138. + // get OEM platform revision
  139. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  140. + MSHW0040_DSM_REVISION,
  141. + MSHW0040_DSM_GET_OMPR, NULL,
  142. + ACPI_TYPE_INTEGER);
  143. +
  144. + if (result) {
  145. + oem_platform_rev = result->integer.value;
  146. + ACPI_FREE(result);
  147. + }
  148. +
  149. + /*
  150. + * If the revision is zero here, the _DSM evaluation has failed. This
  151. + * indicates that we have a Pro 4 or Book 1 and this driver should not
  152. + * be used.
  153. + */
  154. + if (oem_platform_rev == 0)
  155. + return -ENODEV;
  156. +
  157. + dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  158. +
  159. + return 0;
  160. +}
  161. +
  162. +/*
  163. + * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  164. + * Obtained from DSDT/testing.
  165. + */
  166. +static const struct soc_button_info soc_button_MSHW0040[] = {
  167. + { "power", 0, EV_KEY, KEY_POWER, false, true },
  168. + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  169. + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
  170. + { }
  171. +};
  172. +
  173. +static const struct soc_device_data soc_device_MSHW0040 = {
  174. + .button_info = soc_button_MSHW0040,
  175. + .check = soc_device_check_MSHW0040,
  176. +};
  177. +
  178. static const struct acpi_device_id soc_button_acpi_match[] = {
  179. - { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
  180. + { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  181. { "ACPI0011", 0 },
  182. +
  183. + /* Microsoft Surface Devices (5th and 6th generation) */
  184. + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  185. +
  186. { }
  187. };
  188. diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
  189. index 1b491690ce07..96627627060e 100644
  190. --- a/drivers/platform/x86/surfacepro3_button.c
  191. +++ b/drivers/platform/x86/surfacepro3_button.c
  192. @@ -24,6 +24,12 @@
  193. #define SURFACE_BUTTON_OBJ_NAME "VGBI"
  194. #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
  195. +#define MSHW0040_DSM_REVISION 0x01
  196. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  197. +static const guid_t MSHW0040_DSM_UUID =
  198. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  199. + 0x49, 0x80, 0x35);
  200. +
  201. #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
  202. #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
  203. @@ -146,6 +152,44 @@ static int surface_button_resume(struct device *dev)
  204. }
  205. #endif
  206. +/*
  207. + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
  208. + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
  209. + * device by checking for the _DSM method and OEM Platform Revision.
  210. + *
  211. + * Returns true if the driver should bind to this device, i.e. the device is
  212. + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
  213. + */
  214. +static bool surface_button_check_MSHW0040(struct acpi_device *dev)
  215. +{
  216. + acpi_handle handle = dev->handle;
  217. + union acpi_object *result;
  218. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  219. +
  220. + // get OEM platform revision
  221. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  222. + MSHW0040_DSM_REVISION,
  223. + MSHW0040_DSM_GET_OMPR,
  224. + NULL, ACPI_TYPE_INTEGER);
  225. +
  226. + /*
  227. + * If evaluating the _DSM fails, the method is not present. This means
  228. + * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
  229. + * should use this driver. We use revision 0 indicating it is
  230. + * unavailable.
  231. + */
  232. +
  233. + if (result) {
  234. + oem_platform_rev = result->integer.value;
  235. + ACPI_FREE(result);
  236. + }
  237. +
  238. + dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  239. +
  240. + return oem_platform_rev == 0;
  241. +}
  242. +
  243. +
  244. static int surface_button_add(struct acpi_device *device)
  245. {
  246. struct surface_button *button;
  247. @@ -158,6 +202,9 @@ static int surface_button_add(struct acpi_device *device)
  248. strlen(SURFACE_BUTTON_OBJ_NAME)))
  249. return -ENODEV;
  250. + if (!surface_button_check_MSHW0040(device))
  251. + return -ENODEV;
  252. +
  253. button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
  254. if (!button)
  255. return -ENOMEM;
  256. --
  257. 2.26.2