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