2 * apple.c - Apple ACPI quirks
3 * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License (version 2) as
7 * published by the Free Software Foundation.
10 #include <linux/acpi.h>
11 #include <linux/bitmap.h>
12 #include <linux/platform_data/x86/apple.h>
13 #include <linux/uuid.h>
15 /* Apple _DSM device properties GUID */
16 static const guid_t apple_prp_guid
=
17 GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
18 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
21 * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
22 * @adev: ACPI device for which to retrieve the properties
24 * Invoke Apple's custom _DSM once to check the protocol version and once more
25 * to retrieve the properties. They are marshalled up in a single package as
26 * alternating key/value elements, unlike _DSD which stores them as a package
27 * of 2-element packages. Convert to _DSD format and make them available under
30 void acpi_extract_apple_properties(struct acpi_device
*adev
)
32 unsigned int i
, j
= 0, newsize
= 0, numprops
, numvalid
;
33 union acpi_object
*props
, *newprops
;
34 unsigned long *valid
= NULL
;
37 if (!x86_apple_machine
)
40 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 0,
41 NULL
, ACPI_TYPE_BUFFER
);
45 if (!props
->buffer
.length
)
48 if (props
->buffer
.pointer
[0] != 3) {
49 acpi_handle_info(adev
->handle
, FW_INFO
50 "unsupported properties version %*ph\n",
51 props
->buffer
.length
, props
->buffer
.pointer
);
56 props
= acpi_evaluate_dsm_typed(adev
->handle
, &apple_prp_guid
, 1, 1,
57 NULL
, ACPI_TYPE_PACKAGE
);
61 numprops
= props
->package
.count
/ 2;
65 valid
= kcalloc(BITS_TO_LONGS(numprops
), sizeof(long), GFP_KERNEL
);
69 /* newsize = key length + value length of each tuple */
70 for (i
= 0; i
< numprops
; i
++) {
71 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
72 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
74 if ( key
->type
!= ACPI_TYPE_STRING
||
75 (val
->type
!= ACPI_TYPE_INTEGER
&&
76 val
->type
!= ACPI_TYPE_BUFFER
))
77 continue; /* skip invalid properties */
80 newsize
+= key
->string
.length
+ 1;
81 if ( val
->type
== ACPI_TYPE_BUFFER
)
82 newsize
+= val
->buffer
.length
;
85 numvalid
= bitmap_weight(valid
, numprops
);
86 if (numprops
> numvalid
)
87 acpi_handle_info(adev
->handle
, FW_INFO
88 "skipped %u properties: wrong type\n",
93 /* newsize += top-level package + 3 objects for each key/value tuple */
94 newsize
+= (1 + 3 * numvalid
) * sizeof(union acpi_object
);
95 newprops
= ACPI_ALLOCATE_ZEROED(newsize
);
99 /* layout: top-level package | packages | key/value tuples | strings */
100 newprops
->type
= ACPI_TYPE_PACKAGE
;
101 newprops
->package
.count
= numvalid
;
102 newprops
->package
.elements
= &newprops
[1];
103 free_space
= &newprops
[1 + 3 * numvalid
];
105 for_each_set_bit(i
, valid
, numprops
) {
106 union acpi_object
*key
= &props
->package
.elements
[i
* 2];
107 union acpi_object
*val
= &props
->package
.elements
[i
* 2 + 1];
108 unsigned int k
= 1 + numvalid
+ j
* 2; /* index into newprops */
109 unsigned int v
= k
+ 1;
111 newprops
[1 + j
].type
= ACPI_TYPE_PACKAGE
;
112 newprops
[1 + j
].package
.count
= 2;
113 newprops
[1 + j
].package
.elements
= &newprops
[k
];
115 newprops
[k
].type
= ACPI_TYPE_STRING
;
116 newprops
[k
].string
.length
= key
->string
.length
;
117 newprops
[k
].string
.pointer
= free_space
;
118 memcpy(free_space
, key
->string
.pointer
, key
->string
.length
);
119 free_space
+= key
->string
.length
+ 1;
121 newprops
[v
].type
= val
->type
;
122 if (val
->type
== ACPI_TYPE_INTEGER
) {
123 newprops
[v
].integer
.value
= val
->integer
.value
;
125 newprops
[v
].buffer
.length
= val
->buffer
.length
;
126 newprops
[v
].buffer
.pointer
= free_space
;
127 memcpy(free_space
, val
->buffer
.pointer
,
129 free_space
+= val
->buffer
.length
;
131 j
++; /* count valid properties */
133 WARN_ON(free_space
!= (void *)newprops
+ newsize
);
135 adev
->data
.properties
= newprops
;
136 adev
->data
.pointer
= newprops
;