1 // SPDX-License-Identifier: GPL-2.0-only
3 * apple.c - Apple ACPI quirks
4 * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
7 #include <linux/acpi.h>
8 #include <linux/bitmap.h>
9 #include <linux/platform_data/x86/apple.h>
10 #include <linux/uuid.h>
11 #include "../internal.h"
13 /* Apple _DSM device properties GUID */
14 static const guid_t apple_prp_guid
=
15 GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
16 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
19 * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
20 * @adev: ACPI device for which to retrieve the properties
22 * Invoke Apple's custom _DSM once to check the protocol version and once more
23 * to retrieve the properties. They are marshalled up in a single package as
24 * alternating key/value elements, unlike _DSD which stores them as a package
25 * of 2-element packages. Convert to _DSD format and make them available under
28 void acpi_extract_apple_properties(struct acpi_device
*adev
)
30 unsigned int i
, j
= 0, newsize
= 0, numprops
, numvalid
;
31 union acpi_object
*props
, *newprops
;
32 unsigned long *valid
= NULL
;
35 if (!x86_apple_machine
)
38 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 0,
39 NULL
, ACPI_TYPE_BUFFER
);
43 if (!props
->buffer
.length
)
46 if (props
->buffer
.pointer
[0] != 3) {
47 acpi_handle_info(adev
->handle
, FW_INFO
48 "unsupported properties version %*ph\n",
49 props
->buffer
.length
, props
->buffer
.pointer
);
54 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 1,
55 NULL
, ACPI_TYPE_PACKAGE
);
59 numprops
= props
->package
.count
/ 2;
63 valid
= bitmap_zalloc(numprops
, GFP_KERNEL
);
67 /* newsize = key length + value length of each tuple */
68 for (i
= 0; i
< numprops
; i
++) {
69 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
70 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
72 if ( key
->type
!= ACPI_TYPE_STRING
||
73 (val
->type
!= ACPI_TYPE_INTEGER
&&
74 val
->type
!= ACPI_TYPE_BUFFER
&&
75 val
->type
!= ACPI_TYPE_STRING
))
76 continue; /* skip invalid properties */
79 newsize
+= key
->string
.length
+ 1;
80 if ( val
->type
== ACPI_TYPE_BUFFER
)
81 newsize
+= val
->buffer
.length
;
82 else if (val
->type
== ACPI_TYPE_STRING
)
83 newsize
+= val
->string
.length
+ 1;
86 numvalid
= bitmap_weight(valid
, numprops
);
87 if (numprops
> numvalid
)
88 acpi_handle_info(adev
->handle
, FW_INFO
89 "skipped %u properties: wrong type\n",
94 /* newsize += top-level package + 3 objects for each key/value tuple */
95 newsize
+= (1 + 3 * numvalid
) * sizeof(union acpi_object
);
96 newprops
= ACPI_ALLOCATE_ZEROED(newsize
);
100 /* layout: top-level package | packages | key/value tuples | strings */
101 newprops
->type
= ACPI_TYPE_PACKAGE
;
102 newprops
->package
.count
= numvalid
;
103 newprops
->package
.elements
= &newprops
[1];
104 free_space
= &newprops
[1 + 3 * numvalid
];
106 for_each_set_bit(i
, valid
, numprops
) {
107 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
108 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
109 unsigned int k
= 1 + numvalid
+ j
* 2; /* index into newprops */
110 unsigned int v
= k
+ 1;
112 newprops
[1 + j
].type
= ACPI_TYPE_PACKAGE
;
113 newprops
[1 + j
].package
.count
= 2;
114 newprops
[1 + j
].package
.elements
= &newprops
[k
];
116 newprops
[k
].type
= ACPI_TYPE_STRING
;
117 newprops
[k
].string
.length
= key
->string
.length
;
118 newprops
[k
].string
.pointer
= free_space
;
119 memcpy(free_space
, key
->string
.pointer
, key
->string
.length
);
120 free_space
+= key
->string
.length
+ 1;
122 newprops
[v
].type
= val
->type
;
123 if (val
->type
== ACPI_TYPE_INTEGER
) {
124 newprops
[v
].integer
.value
= val
->integer
.value
;
125 } else if (val
->type
== ACPI_TYPE_STRING
) {
126 newprops
[v
].string
.length
= val
->string
.length
;
127 newprops
[v
].string
.pointer
= free_space
;
128 memcpy(free_space
, val
->string
.pointer
,
130 free_space
+= val
->string
.length
+ 1;
132 newprops
[v
].buffer
.length
= val
->buffer
.length
;
133 newprops
[v
].buffer
.pointer
= free_space
;
134 memcpy(free_space
, val
->buffer
.pointer
,
136 free_space
+= val
->buffer
.length
;
138 j
++; /* count valid properties */
140 WARN_ON(free_space
!= (void *)newprops
+ newsize
);
142 adev
->data
.pointer
= newprops
;
143 acpi_data_add_props(&adev
->data
, &apple_prp_guid
, newprops
);