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>
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);
18 * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
19 * @adev: ACPI device for which to retrieve the properties
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
27 void acpi_extract_apple_properties(struct acpi_device
*adev
)
29 unsigned int i
, j
= 0, newsize
= 0, numprops
, numvalid
;
30 union acpi_object
*props
, *newprops
;
31 unsigned long *valid
= NULL
;
34 if (!x86_apple_machine
)
37 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 0,
38 NULL
, ACPI_TYPE_BUFFER
);
42 if (!props
->buffer
.length
)
45 if (props
->buffer
.pointer
[0] != 3) {
46 acpi_handle_info(adev
->handle
, FW_INFO
47 "unsupported properties version %*ph\n",
48 props
->buffer
.length
, props
->buffer
.pointer
);
53 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 1,
54 NULL
, ACPI_TYPE_PACKAGE
);
58 numprops
= props
->package
.count
/ 2;
62 valid
= bitmap_zalloc(numprops
, GFP_KERNEL
);
66 /* newsize = key length + value length of each tuple */
67 for (i
= 0; i
< numprops
; i
++) {
68 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
69 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
71 if ( key
->type
!= ACPI_TYPE_STRING
||
72 (val
->type
!= ACPI_TYPE_INTEGER
&&
73 val
->type
!= ACPI_TYPE_BUFFER
))
74 continue; /* skip invalid properties */
77 newsize
+= key
->string
.length
+ 1;
78 if ( val
->type
== ACPI_TYPE_BUFFER
)
79 newsize
+= val
->buffer
.length
;
82 numvalid
= bitmap_weight(valid
, numprops
);
83 if (numprops
> numvalid
)
84 acpi_handle_info(adev
->handle
, FW_INFO
85 "skipped %u properties: wrong type\n",
90 /* newsize += top-level package + 3 objects for each key/value tuple */
91 newsize
+= (1 + 3 * numvalid
) * sizeof(union acpi_object
);
92 newprops
= ACPI_ALLOCATE_ZEROED(newsize
);
96 /* layout: top-level package | packages | key/value tuples | strings */
97 newprops
->type
= ACPI_TYPE_PACKAGE
;
98 newprops
->package
.count
= numvalid
;
99 newprops
->package
.elements
= &newprops
[1];
100 free_space
= &newprops
[1 + 3 * numvalid
];
102 for_each_set_bit(i
, valid
, numprops
) {
103 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
104 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
105 unsigned int k
= 1 + numvalid
+ j
* 2; /* index into newprops */
106 unsigned int v
= k
+ 1;
108 newprops
[1 + j
].type
= ACPI_TYPE_PACKAGE
;
109 newprops
[1 + j
].package
.count
= 2;
110 newprops
[1 + j
].package
.elements
= &newprops
[k
];
112 newprops
[k
].type
= ACPI_TYPE_STRING
;
113 newprops
[k
].string
.length
= key
->string
.length
;
114 newprops
[k
].string
.pointer
= free_space
;
115 memcpy(free_space
, key
->string
.pointer
, key
->string
.length
);
116 free_space
+= key
->string
.length
+ 1;
118 newprops
[v
].type
= val
->type
;
119 if (val
->type
== ACPI_TYPE_INTEGER
) {
120 newprops
[v
].integer
.value
= val
->integer
.value
;
122 newprops
[v
].buffer
.length
= val
->buffer
.length
;
123 newprops
[v
].buffer
.pointer
= free_space
;
124 memcpy(free_space
, val
->buffer
.pointer
,
126 free_space
+= val
->buffer
.length
;
128 j
++; /* count valid properties */
130 WARN_ON(free_space
!= (void *)newprops
+ newsize
);
132 adev
->data
.pointer
= newprops
;
133 acpi_data_add_props(&adev
->data
, &apple_prp_guid
, newprops
);