123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * apple.c - Apple ACPI quirks
- * Copyright (C) 2017 Lukas Wunner <[email protected]>
- */
- #include <linux/acpi.h>
- #include <linux/bitmap.h>
- #include <linux/platform_data/x86/apple.h>
- #include <linux/uuid.h>
- #include "../internal.h"
- /* Apple _DSM device properties GUID */
- static const guid_t apple_prp_guid =
- GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
- 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
- /**
- * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
- * @adev: ACPI device for which to retrieve the properties
- *
- * Invoke Apple's custom _DSM once to check the protocol version and once more
- * to retrieve the properties. They are marshalled up in a single package as
- * alternating key/value elements, unlike _DSD which stores them as a package
- * of 2-element packages. Convert to _DSD format and make them available under
- * the primary fwnode.
- */
- void acpi_extract_apple_properties(struct acpi_device *adev)
- {
- unsigned int i, j = 0, newsize = 0, numprops, numvalid;
- union acpi_object *props, *newprops;
- unsigned long *valid = NULL;
- void *free_space;
- if (!x86_apple_machine)
- return;
- props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
- NULL, ACPI_TYPE_BUFFER);
- if (!props)
- return;
- if (!props->buffer.length)
- goto out_free;
- if (props->buffer.pointer[0] != 3) {
- acpi_handle_info(adev->handle, FW_INFO
- "unsupported properties version %*ph\n",
- props->buffer.length, props->buffer.pointer);
- goto out_free;
- }
- ACPI_FREE(props);
- props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
- NULL, ACPI_TYPE_PACKAGE);
- if (!props)
- return;
- numprops = props->package.count / 2;
- if (!numprops)
- goto out_free;
- valid = bitmap_zalloc(numprops, GFP_KERNEL);
- if (!valid)
- goto out_free;
- /* newsize = key length + value length of each tuple */
- for (i = 0; i < numprops; i++) {
- union acpi_object *key = &props->package.elements[i * 2];
- union acpi_object *val = &props->package.elements[i * 2 + 1];
- if ( key->type != ACPI_TYPE_STRING ||
- (val->type != ACPI_TYPE_INTEGER &&
- val->type != ACPI_TYPE_BUFFER))
- continue; /* skip invalid properties */
- __set_bit(i, valid);
- newsize += key->string.length + 1;
- if ( val->type == ACPI_TYPE_BUFFER)
- newsize += val->buffer.length;
- }
- numvalid = bitmap_weight(valid, numprops);
- if (numprops > numvalid)
- acpi_handle_info(adev->handle, FW_INFO
- "skipped %u properties: wrong type\n",
- numprops - numvalid);
- if (numvalid == 0)
- goto out_free;
- /* newsize += top-level package + 3 objects for each key/value tuple */
- newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
- newprops = ACPI_ALLOCATE_ZEROED(newsize);
- if (!newprops)
- goto out_free;
- /* layout: top-level package | packages | key/value tuples | strings */
- newprops->type = ACPI_TYPE_PACKAGE;
- newprops->package.count = numvalid;
- newprops->package.elements = &newprops[1];
- free_space = &newprops[1 + 3 * numvalid];
- for_each_set_bit(i, valid, numprops) {
- union acpi_object *key = &props->package.elements[i * 2];
- union acpi_object *val = &props->package.elements[i * 2 + 1];
- unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
- unsigned int v = k + 1;
- newprops[1 + j].type = ACPI_TYPE_PACKAGE;
- newprops[1 + j].package.count = 2;
- newprops[1 + j].package.elements = &newprops[k];
- newprops[k].type = ACPI_TYPE_STRING;
- newprops[k].string.length = key->string.length;
- newprops[k].string.pointer = free_space;
- memcpy(free_space, key->string.pointer, key->string.length);
- free_space += key->string.length + 1;
- newprops[v].type = val->type;
- if (val->type == ACPI_TYPE_INTEGER) {
- newprops[v].integer.value = val->integer.value;
- } else {
- newprops[v].buffer.length = val->buffer.length;
- newprops[v].buffer.pointer = free_space;
- memcpy(free_space, val->buffer.pointer,
- val->buffer.length);
- free_space += val->buffer.length;
- }
- j++; /* count valid properties */
- }
- WARN_ON(free_space != (void *)newprops + newsize);
- adev->data.pointer = newprops;
- acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
- out_free:
- ACPI_FREE(props);
- bitmap_free(valid);
- }
|