0002-buttons.patch 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. From 5e6d16a8fb200eb0325061c7a0f10126d69c2466 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 02/10] buttons
  5. ---
  6. drivers/input/misc/Kconfig | 6 +-
  7. drivers/input/misc/soc_button_array.c | 112 +++++++++++++++++++---
  8. drivers/platform/x86/surfacepro3_button.c | 47 +++++++++
  9. 3 files changed, 150 insertions(+), 15 deletions(-)
  10. diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
  11. index d07c1eb15aa6..7d9ae394e597 100644
  12. --- a/drivers/input/misc/Kconfig
  13. +++ b/drivers/input/misc/Kconfig
  14. @@ -813,10 +813,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 5e59f8e57f8e..ef89698c7d43 100644
  28. --- a/drivers/input/misc/soc_button_array.c
  29. +++ b/drivers/input/misc/soc_button_array.c
  30. @@ -25,6 +25,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. @@ -87,8 +92,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,7 +377,7 @@ 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. + if (!device_data || !device_data->button_info)
  98. devm_kfree(dev, button_info);
  99. return 0;
  100. @@ -368,7 +388,7 @@ static int soc_button_probe(struct platform_device *pdev)
  101. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  102. * Platforms"
  103. */
  104. -static struct soc_button_info soc_button_PNP0C40[] = {
  105. +static const struct soc_button_info soc_button_PNP0C40[] = {
  106. { "power", 0, EV_KEY, KEY_POWER, false, true },
  107. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
  108. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  109. @@ -377,9 +397,77 @@ static struct soc_button_info soc_button_PNP0C40[] = {
  110. { }
  111. };
  112. +static const struct soc_device_data soc_device_PNP0C40 = {
  113. + .button_info = soc_button_PNP0C40,
  114. +};
  115. +
  116. +/*
  117. + * Special device check for Surface Book 2 and Surface Pro (2017).
  118. + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  119. + * devices use MSHW0040 for power and volume buttons, however the way they
  120. + * have to be addressed differs. Make sure that we only load this drivers
  121. + * for the correct devices by checking the OEM Platform Revision provided by
  122. + * the _DSM method.
  123. + */
  124. +#define MSHW0040_DSM_REVISION 0x01
  125. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  126. +static const guid_t MSHW0040_DSM_UUID =
  127. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  128. + 0x49, 0x80, 0x35);
  129. +
  130. +static int soc_device_check_MSHW0040(struct device *dev)
  131. +{
  132. + acpi_handle handle = ACPI_HANDLE(dev);
  133. + union acpi_object *result;
  134. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  135. +
  136. + // get OEM platform revision
  137. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  138. + MSHW0040_DSM_REVISION,
  139. + MSHW0040_DSM_GET_OMPR, NULL,
  140. + ACPI_TYPE_INTEGER);
  141. +
  142. + if (result) {
  143. + oem_platform_rev = result->integer.value;
  144. + ACPI_FREE(result);
  145. + }
  146. +
  147. + /*
  148. + * If the revision is zero here, the _DSM evaluation has failed. This
  149. + * indicates that we have a Pro 4 or Book 1 and this driver should not
  150. + * be used.
  151. + */
  152. + if (oem_platform_rev == 0)
  153. + return -ENODEV;
  154. +
  155. + dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  156. +
  157. + return 0;
  158. +}
  159. +
  160. +/*
  161. + * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  162. + * Obtained from DSDT/testing.
  163. + */
  164. +static const struct soc_button_info soc_button_MSHW0040[] = {
  165. + { "power", 0, EV_KEY, KEY_POWER, false, true },
  166. + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  167. + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
  168. + { }
  169. +};
  170. +
  171. +static const struct soc_device_data soc_device_MSHW0040 = {
  172. + .button_info = soc_button_MSHW0040,
  173. + .check = soc_device_check_MSHW0040,
  174. +};
  175. +
  176. static const struct acpi_device_id soc_button_acpi_match[] = {
  177. - { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
  178. + { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  179. { "ACPI0011", 0 },
  180. +
  181. + /* Microsoft Surface Devices (5th and 6th generation) */
  182. + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  183. +
  184. { }
  185. };
  186. diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
  187. index 47c6d000465a..ec515223f654 100644
  188. --- a/drivers/platform/x86/surfacepro3_button.c
  189. +++ b/drivers/platform/x86/surfacepro3_button.c
  190. @@ -20,6 +20,12 @@
  191. #define SURFACE_BUTTON_OBJ_NAME "VGBI"
  192. #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
  193. +#define MSHW0040_DSM_REVISION 0x01
  194. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  195. +static const guid_t MSHW0040_DSM_UUID =
  196. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  197. + 0x49, 0x80, 0x35);
  198. +
  199. #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
  200. #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
  201. @@ -142,6 +148,44 @@ static int surface_button_resume(struct device *dev)
  202. }
  203. #endif
  204. +/*
  205. + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
  206. + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
  207. + * device by checking for the _DSM method and OEM Platform Revision.
  208. + *
  209. + * Returns true if the driver should bind to this device, i.e. the device is
  210. + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
  211. + */
  212. +static bool surface_button_check_MSHW0040(struct acpi_device *dev)
  213. +{
  214. + acpi_handle handle = dev->handle;
  215. + union acpi_object *result;
  216. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  217. +
  218. + // get OEM platform revision
  219. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  220. + MSHW0040_DSM_REVISION,
  221. + MSHW0040_DSM_GET_OMPR,
  222. + NULL, ACPI_TYPE_INTEGER);
  223. +
  224. + /*
  225. + * If evaluating the _DSM fails, the method is not present. This means
  226. + * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
  227. + * should use this driver. We use revision 0 indicating it is
  228. + * unavailable.
  229. + */
  230. +
  231. + if (result) {
  232. + oem_platform_rev = result->integer.value;
  233. + ACPI_FREE(result);
  234. + }
  235. +
  236. + dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  237. +
  238. + return oem_platform_rev == 0;
  239. +}
  240. +
  241. +
  242. static int surface_button_add(struct acpi_device *device)
  243. {
  244. struct surface_button *button;
  245. @@ -154,6 +198,9 @@ static int surface_button_add(struct acpi_device *device)
  246. strlen(SURFACE_BUTTON_OBJ_NAME)))
  247. return -ENODEV;
  248. + if (!surface_button_check_MSHW0040(device))
  249. + return -ENODEV;
  250. +
  251. button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
  252. if (!button)
  253. return -ENOMEM;
  254. --
  255. 2.24.1