apple.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * apple.c - Apple ACPI quirks
  4. * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
  5. */
  6. #include <linux/acpi.h>
  7. #include <linux/bitmap.h>
  8. #include <linux/platform_data/x86/apple.h>
  9. #include <linux/uuid.h>
  10. #include "../internal.h"
  11. /* Apple _DSM device properties GUID */
  12. static const guid_t apple_prp_guid =
  13. GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
  14. 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
  15. /**
  16. * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
  17. * @adev: ACPI device for which to retrieve the properties
  18. *
  19. * Invoke Apple's custom _DSM once to check the protocol version and once more
  20. * to retrieve the properties. They are marshalled up in a single package as
  21. * alternating key/value elements, unlike _DSD which stores them as a package
  22. * of 2-element packages. Convert to _DSD format and make them available under
  23. * the primary fwnode.
  24. */
  25. void acpi_extract_apple_properties(struct acpi_device *adev)
  26. {
  27. unsigned int i, j = 0, newsize = 0, numprops, numvalid;
  28. union acpi_object *props, *newprops;
  29. unsigned long *valid = NULL;
  30. void *free_space;
  31. if (!x86_apple_machine)
  32. return;
  33. props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
  34. NULL, ACPI_TYPE_BUFFER);
  35. if (!props)
  36. return;
  37. if (!props->buffer.length)
  38. goto out_free;
  39. if (props->buffer.pointer[0] != 3) {
  40. acpi_handle_info(adev->handle, FW_INFO
  41. "unsupported properties version %*ph\n",
  42. props->buffer.length, props->buffer.pointer);
  43. goto out_free;
  44. }
  45. ACPI_FREE(props);
  46. props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
  47. NULL, ACPI_TYPE_PACKAGE);
  48. if (!props)
  49. return;
  50. numprops = props->package.count / 2;
  51. if (!numprops)
  52. goto out_free;
  53. valid = bitmap_zalloc(numprops, GFP_KERNEL);
  54. if (!valid)
  55. goto out_free;
  56. /* newsize = key length + value length of each tuple */
  57. for (i = 0; i < numprops; i++) {
  58. union acpi_object *key = &props->package.elements[i * 2];
  59. union acpi_object *val = &props->package.elements[i * 2 + 1];
  60. if ( key->type != ACPI_TYPE_STRING ||
  61. (val->type != ACPI_TYPE_INTEGER &&
  62. val->type != ACPI_TYPE_BUFFER &&
  63. val->type != ACPI_TYPE_STRING))
  64. continue; /* skip invalid properties */
  65. __set_bit(i, valid);
  66. newsize += key->string.length + 1;
  67. if ( val->type == ACPI_TYPE_BUFFER)
  68. newsize += val->buffer.length;
  69. else if (val->type == ACPI_TYPE_STRING)
  70. newsize += val->string.length + 1;
  71. }
  72. numvalid = bitmap_weight(valid, numprops);
  73. if (numprops > numvalid)
  74. acpi_handle_info(adev->handle, FW_INFO
  75. "skipped %u properties: wrong type\n",
  76. numprops - numvalid);
  77. if (numvalid == 0)
  78. goto out_free;
  79. /* newsize += top-level package + 3 objects for each key/value tuple */
  80. newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
  81. newprops = ACPI_ALLOCATE_ZEROED(newsize);
  82. if (!newprops)
  83. goto out_free;
  84. /* layout: top-level package | packages | key/value tuples | strings */
  85. newprops->type = ACPI_TYPE_PACKAGE;
  86. newprops->package.count = numvalid;
  87. newprops->package.elements = &newprops[1];
  88. free_space = &newprops[1 + 3 * numvalid];
  89. for_each_set_bit(i, valid, numprops) {
  90. union acpi_object *key = &props->package.elements[i * 2];
  91. union acpi_object *val = &props->package.elements[i * 2 + 1];
  92. unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
  93. unsigned int v = k + 1;
  94. newprops[1 + j].type = ACPI_TYPE_PACKAGE;
  95. newprops[1 + j].package.count = 2;
  96. newprops[1 + j].package.elements = &newprops[k];
  97. newprops[k].type = ACPI_TYPE_STRING;
  98. newprops[k].string.length = key->string.length;
  99. newprops[k].string.pointer = free_space;
  100. memcpy(free_space, key->string.pointer, key->string.length);
  101. free_space += key->string.length + 1;
  102. newprops[v].type = val->type;
  103. if (val->type == ACPI_TYPE_INTEGER) {
  104. newprops[v].integer.value = val->integer.value;
  105. } else if (val->type == ACPI_TYPE_STRING) {
  106. newprops[v].string.length = val->string.length;
  107. newprops[v].string.pointer = free_space;
  108. memcpy(free_space, val->string.pointer,
  109. val->string.length);
  110. free_space += val->string.length + 1;
  111. } else {
  112. newprops[v].buffer.length = val->buffer.length;
  113. newprops[v].buffer.pointer = free_space;
  114. memcpy(free_space, val->buffer.pointer,
  115. val->buffer.length);
  116. free_space += val->buffer.length;
  117. }
  118. j++; /* count valid properties */
  119. }
  120. WARN_ON(free_space != (void *)newprops + newsize);
  121. adev->data.pointer = newprops;
  122. acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
  123. out_free:
  124. ACPI_FREE(props);
  125. bitmap_free(valid);
  126. }