Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * apple.c - Apple ACPI quirks
0004  * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
0005  */
0006 
0007 #include <linux/acpi.h>
0008 #include <linux/bitmap.h>
0009 #include <linux/platform_data/x86/apple.h>
0010 #include <linux/uuid.h>
0011 
0012 /* Apple _DSM device properties GUID */
0013 static const guid_t apple_prp_guid =
0014     GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
0015           0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
0016 
0017 /**
0018  * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
0019  * @adev: ACPI device for which to retrieve the properties
0020  *
0021  * Invoke Apple's custom _DSM once to check the protocol version and once more
0022  * to retrieve the properties.  They are marshalled up in a single package as
0023  * alternating key/value elements, unlike _DSD which stores them as a package
0024  * of 2-element packages.  Convert to _DSD format and make them available under
0025  * the primary fwnode.
0026  */
0027 void acpi_extract_apple_properties(struct acpi_device *adev)
0028 {
0029     unsigned int i, j = 0, newsize = 0, numprops, numvalid;
0030     union acpi_object *props, *newprops;
0031     unsigned long *valid = NULL;
0032     void *free_space;
0033 
0034     if (!x86_apple_machine)
0035         return;
0036 
0037     props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
0038                     NULL, ACPI_TYPE_BUFFER);
0039     if (!props)
0040         return;
0041 
0042     if (!props->buffer.length)
0043         goto out_free;
0044 
0045     if (props->buffer.pointer[0] != 3) {
0046         acpi_handle_info(adev->handle, FW_INFO
0047                  "unsupported properties version %*ph\n",
0048                  props->buffer.length, props->buffer.pointer);
0049         goto out_free;
0050     }
0051 
0052     ACPI_FREE(props);
0053     props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
0054                     NULL, ACPI_TYPE_PACKAGE);
0055     if (!props)
0056         return;
0057 
0058     numprops = props->package.count / 2;
0059     if (!numprops)
0060         goto out_free;
0061 
0062     valid = bitmap_zalloc(numprops, GFP_KERNEL);
0063     if (!valid)
0064         goto out_free;
0065 
0066     /* newsize = key length + value length of each tuple */
0067     for (i = 0; i < numprops; i++) {
0068         union acpi_object *key = &props->package.elements[i * 2];
0069         union acpi_object *val = &props->package.elements[i * 2 + 1];
0070 
0071         if ( key->type != ACPI_TYPE_STRING ||
0072             (val->type != ACPI_TYPE_INTEGER &&
0073              val->type != ACPI_TYPE_BUFFER))
0074             continue; /* skip invalid properties */
0075 
0076         __set_bit(i, valid);
0077         newsize += key->string.length + 1;
0078         if ( val->type == ACPI_TYPE_BUFFER)
0079             newsize += val->buffer.length;
0080     }
0081 
0082     numvalid = bitmap_weight(valid, numprops);
0083     if (numprops > numvalid)
0084         acpi_handle_info(adev->handle, FW_INFO
0085                  "skipped %u properties: wrong type\n",
0086                  numprops - numvalid);
0087     if (numvalid == 0)
0088         goto out_free;
0089 
0090     /* newsize += top-level package + 3 objects for each key/value tuple */
0091     newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
0092     newprops = ACPI_ALLOCATE_ZEROED(newsize);
0093     if (!newprops)
0094         goto out_free;
0095 
0096     /* layout: top-level package | packages | key/value tuples | strings */
0097     newprops->type = ACPI_TYPE_PACKAGE;
0098     newprops->package.count = numvalid;
0099     newprops->package.elements = &newprops[1];
0100     free_space = &newprops[1 + 3 * numvalid];
0101 
0102     for_each_set_bit(i, valid, numprops) {
0103         union acpi_object *key = &props->package.elements[i * 2];
0104         union acpi_object *val = &props->package.elements[i * 2 + 1];
0105         unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
0106         unsigned int v = k + 1;
0107 
0108         newprops[1 + j].type = ACPI_TYPE_PACKAGE;
0109         newprops[1 + j].package.count = 2;
0110         newprops[1 + j].package.elements = &newprops[k];
0111 
0112         newprops[k].type = ACPI_TYPE_STRING;
0113         newprops[k].string.length = key->string.length;
0114         newprops[k].string.pointer = free_space;
0115         memcpy(free_space, key->string.pointer, key->string.length);
0116         free_space += key->string.length + 1;
0117 
0118         newprops[v].type = val->type;
0119         if (val->type == ACPI_TYPE_INTEGER) {
0120             newprops[v].integer.value = val->integer.value;
0121         } else {
0122             newprops[v].buffer.length = val->buffer.length;
0123             newprops[v].buffer.pointer = free_space;
0124             memcpy(free_space, val->buffer.pointer,
0125                    val->buffer.length);
0126             free_space += val->buffer.length;
0127         }
0128         j++; /* count valid properties */
0129     }
0130     WARN_ON(free_space != (void *)newprops + newsize);
0131 
0132     adev->data.pointer = newprops;
0133     acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
0134 
0135 out_free:
0136     ACPI_FREE(props);
0137     bitmap_free(valid);
0138 }