0003-buttons.patch 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. From e0465b614d5191e2fc3ecae7bfa6f1e44ed94a84 Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Fri, 26 Jul 2019 04:45:10 +0200
  4. Subject: [PATCH 03/12] buttons
  5. ---
  6. drivers/input/misc/Kconfig | 6 +-
  7. drivers/input/misc/soc_button_array.c | 105 +++++++++++++++++++---
  8. drivers/platform/x86/surfacepro3_button.c | 47 ++++++++++
  9. 3 files changed, 143 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..6f0133fe1546 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,13 @@ 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 < 0 && gpio != -ENOENT) {
  46. + error = gpio;
  47. + goto err_free_mem;
  48. + } else if (!gpio_is_valid(gpio)) {
  49. + /* Skip GPIO if not present */
  50. continue;
  51. + }
  52. gpio_keys[n_buttons].type = info->event_type;
  53. gpio_keys[n_buttons].code = info->event_code;
  54. @@ -309,23 +319,26 @@ static int soc_button_remove(struct platform_device *pdev)
  55. static int soc_button_probe(struct platform_device *pdev)
  56. {
  57. struct device *dev = &pdev->dev;
  58. - const struct acpi_device_id *id;
  59. - struct soc_button_info *button_info;
  60. + const struct soc_device_data *device_data;
  61. + const struct soc_button_info *button_info;
  62. struct soc_button_data *priv;
  63. struct platform_device *pd;
  64. int i;
  65. int error;
  66. - id = acpi_match_device(dev->driver->acpi_match_table, dev);
  67. - if (!id)
  68. - return -ENODEV;
  69. + device_data = acpi_device_get_match_data(dev);
  70. + if (device_data && device_data->check) {
  71. + error = device_data->check(dev);
  72. + if (error)
  73. + return error;
  74. + }
  75. - if (!id->driver_data) {
  76. + if (device_data && device_data->button_info) {
  77. + button_info = device_data->button_info;
  78. + } else {
  79. button_info = soc_button_get_button_info(dev);
  80. if (IS_ERR(button_info))
  81. return PTR_ERR(button_info);
  82. - } else {
  83. - button_info = (struct soc_button_info *)id->driver_data;
  84. }
  85. error = gpiod_count(dev, NULL);
  86. @@ -357,7 +370,7 @@ static int soc_button_probe(struct platform_device *pdev)
  87. if (!priv->children[0] && !priv->children[1])
  88. return -ENODEV;
  89. - if (!id->driver_data)
  90. + if (!device_data || !device_data->button_info)
  91. devm_kfree(dev, button_info);
  92. return 0;
  93. @@ -368,7 +381,7 @@ static int soc_button_probe(struct platform_device *pdev)
  94. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  95. * Platforms"
  96. */
  97. -static struct soc_button_info soc_button_PNP0C40[] = {
  98. +static const struct soc_button_info soc_button_PNP0C40[] = {
  99. { "power", 0, EV_KEY, KEY_POWER, false, true },
  100. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
  101. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  102. @@ -377,9 +390,77 @@ static struct soc_button_info soc_button_PNP0C40[] = {
  103. { }
  104. };
  105. +static const struct soc_device_data soc_device_PNP0C40 = {
  106. + .button_info = soc_button_PNP0C40,
  107. +};
  108. +
  109. +/*
  110. + * Special device check for Surface Book 2 and Surface Pro (2017).
  111. + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  112. + * devices use MSHW0040 for power and volume buttons, however the way they
  113. + * have to be addressed differs. Make sure that we only load this drivers
  114. + * for the correct devices by checking the OEM Platform Revision provided by
  115. + * the _DSM method.
  116. + */
  117. +#define MSHW0040_DSM_REVISION 0x01
  118. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  119. +static const guid_t MSHW0040_DSM_UUID =
  120. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  121. + 0x49, 0x80, 0x35);
  122. +
  123. +static int soc_device_check_MSHW0040(struct device *dev)
  124. +{
  125. + acpi_handle handle = ACPI_HANDLE(dev);
  126. + union acpi_object *result;
  127. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  128. +
  129. + // get OEM platform revision
  130. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  131. + MSHW0040_DSM_REVISION,
  132. + MSHW0040_DSM_GET_OMPR, NULL,
  133. + ACPI_TYPE_INTEGER);
  134. +
  135. + if (result) {
  136. + oem_platform_rev = result->integer.value;
  137. + ACPI_FREE(result);
  138. + }
  139. +
  140. + /*
  141. + * If the revision is zero here, the _DSM evaluation has failed. This
  142. + * indicates that we have a Pro 4 or Book 1 and this driver should not
  143. + * be used.
  144. + */
  145. + if (oem_platform_rev == 0)
  146. + return -ENODEV;
  147. +
  148. + dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  149. +
  150. + return 0;
  151. +}
  152. +
  153. +/*
  154. + * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  155. + * Obtained from DSDT/testing.
  156. + */
  157. +static const struct soc_button_info soc_button_MSHW0040[] = {
  158. + { "power", 0, EV_KEY, KEY_POWER, false, true },
  159. + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  160. + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
  161. + { }
  162. +};
  163. +
  164. +static const struct soc_device_data soc_device_MSHW0040 = {
  165. + .button_info = soc_button_MSHW0040,
  166. + .check = soc_device_check_MSHW0040,
  167. +};
  168. +
  169. static const struct acpi_device_id soc_button_acpi_match[] = {
  170. - { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
  171. + { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  172. { "ACPI0011", 0 },
  173. +
  174. + /* Microsoft Surface Devices (5th and 6th generation) */
  175. + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  176. +
  177. { }
  178. };
  179. diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
  180. index 47c6d000465a..ec515223f654 100644
  181. --- a/drivers/platform/x86/surfacepro3_button.c
  182. +++ b/drivers/platform/x86/surfacepro3_button.c
  183. @@ -20,6 +20,12 @@
  184. #define SURFACE_BUTTON_OBJ_NAME "VGBI"
  185. #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
  186. +#define MSHW0040_DSM_REVISION 0x01
  187. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  188. +static const guid_t MSHW0040_DSM_UUID =
  189. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  190. + 0x49, 0x80, 0x35);
  191. +
  192. #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
  193. #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
  194. @@ -142,6 +148,44 @@ static int surface_button_resume(struct device *dev)
  195. }
  196. #endif
  197. +/*
  198. + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
  199. + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
  200. + * device by checking for the _DSM method and OEM Platform Revision.
  201. + *
  202. + * Returns true if the driver should bind to this device, i.e. the device is
  203. + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
  204. + */
  205. +static bool surface_button_check_MSHW0040(struct acpi_device *dev)
  206. +{
  207. + acpi_handle handle = dev->handle;
  208. + union acpi_object *result;
  209. + u64 oem_platform_rev = 0; // valid revisions are nonzero
  210. +
  211. + // get OEM platform revision
  212. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  213. + MSHW0040_DSM_REVISION,
  214. + MSHW0040_DSM_GET_OMPR,
  215. + NULL, ACPI_TYPE_INTEGER);
  216. +
  217. + /*
  218. + * If evaluating the _DSM fails, the method is not present. This means
  219. + * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
  220. + * should use this driver. We use revision 0 indicating it is
  221. + * unavailable.
  222. + */
  223. +
  224. + if (result) {
  225. + oem_platform_rev = result->integer.value;
  226. + ACPI_FREE(result);
  227. + }
  228. +
  229. + dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  230. +
  231. + return oem_platform_rev == 0;
  232. +}
  233. +
  234. +
  235. static int surface_button_add(struct acpi_device *device)
  236. {
  237. struct surface_button *button;
  238. @@ -154,6 +198,9 @@ static int surface_button_add(struct acpi_device *device)
  239. strlen(SURFACE_BUTTON_OBJ_NAME)))
  240. return -ENODEV;
  241. + if (!surface_button_check_MSHW0040(device))
  242. + return -ENODEV;
  243. +
  244. button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
  245. if (!button)
  246. return -ENOMEM;
  247. --
  248. 2.23.0