linux/sound/soc/intel/common/sst-match-acpi.c
<<
>>
Prefs
   1/*
   2 * sst_match_apci.c - SST (LPE) match for ACPI enumeration.
   3 *
   4 * Copyright (c) 2013-15, Intel Corporation.
   5 *
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms and conditions of the GNU General Public License,
   9 * version 2, as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 */
  16
  17#include "sst-acpi.h"
  18
  19static acpi_status sst_acpi_find_name(acpi_handle handle, u32 level,
  20                                      void *context, void **ret)
  21{
  22        struct acpi_device *adev;
  23        const char *name = NULL;
  24
  25        if (acpi_bus_get_device(handle, &adev))
  26                return AE_OK;
  27
  28        if (adev->status.present && adev->status.functional) {
  29                name = acpi_dev_name(adev);
  30                *(const char **)ret = name;
  31                return AE_CTRL_TERMINATE;
  32        }
  33
  34        return AE_OK;
  35}
  36
  37const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
  38{
  39        const char *name = NULL;
  40        acpi_status status;
  41
  42        status = acpi_get_devices(hid, sst_acpi_find_name, NULL,
  43                                  (void **)&name);
  44
  45        if (ACPI_FAILURE(status) || name[0] == '\0')
  46                return NULL;
  47
  48        return name;
  49}
  50EXPORT_SYMBOL_GPL(sst_acpi_find_name_from_hid);
  51
  52static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
  53                                       void *context, void **ret)
  54{
  55        unsigned long long sta;
  56        acpi_status status;
  57
  58        *(bool *)context = true;
  59        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
  60        if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
  61                *(bool *)context = false;
  62
  63        return AE_OK;
  64}
  65
  66bool sst_acpi_check_hid(const u8 hid[ACPI_ID_LEN])
  67{
  68        acpi_status status;
  69        bool found = false;
  70
  71        status = acpi_get_devices(hid, sst_acpi_mach_match, &found, NULL);
  72
  73        if (ACPI_FAILURE(status))
  74                return false;
  75
  76        return found;
  77}
  78EXPORT_SYMBOL_GPL(sst_acpi_check_hid);
  79
  80struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
  81{
  82        struct sst_acpi_mach *mach;
  83
  84        for (mach = machines; mach->id[0]; mach++) {
  85                if (sst_acpi_check_hid(mach->id) == true) {
  86                        if (mach->machine_quirk == NULL)
  87                                return mach;
  88
  89                        if (mach->machine_quirk(mach) != NULL)
  90                                return mach;
  91                }
  92        }
  93        return NULL;
  94}
  95EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
  96
  97static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level,
  98                                        void *context, void **ret)
  99{
 100        struct acpi_device *adev;
 101        acpi_status status = AE_OK;
 102        struct sst_acpi_package_context *pkg_ctx = context;
 103
 104        pkg_ctx->data_valid = false;
 105
 106        if (acpi_bus_get_device(handle, &adev))
 107                return AE_OK;
 108
 109        if (adev->status.present && adev->status.functional) {
 110                struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 111                union acpi_object  *myobj = NULL;
 112
 113                status = acpi_evaluate_object_typed(handle, pkg_ctx->name,
 114                                                NULL, &buffer,
 115                                                ACPI_TYPE_PACKAGE);
 116                if (ACPI_FAILURE(status))
 117                        return AE_OK;
 118
 119                myobj = buffer.pointer;
 120                if (!myobj || myobj->package.count != pkg_ctx->length) {
 121                        kfree(buffer.pointer);
 122                        return AE_OK;
 123                }
 124
 125                status = acpi_extract_package(myobj,
 126                                        pkg_ctx->format, pkg_ctx->state);
 127                if (ACPI_FAILURE(status)) {
 128                        kfree(buffer.pointer);
 129                        return AE_OK;
 130                }
 131
 132                kfree(buffer.pointer);
 133                pkg_ctx->data_valid = true;
 134                return AE_CTRL_TERMINATE;
 135        }
 136
 137        return AE_OK;
 138}
 139
 140bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
 141                                struct sst_acpi_package_context *ctx)
 142{
 143        acpi_status status;
 144
 145        status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL);
 146
 147        if (ACPI_FAILURE(status) || !ctx->data_valid)
 148                return false;
 149
 150        return true;
 151}
 152EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid);
 153
 154struct sst_acpi_mach *sst_acpi_codec_list(void *arg)
 155{
 156        struct sst_acpi_mach *mach = arg;
 157        struct sst_codecs *codec_list = (struct sst_codecs *) mach->quirk_data;
 158        int i;
 159
 160        if (mach->quirk_data == NULL)
 161                return mach;
 162
 163        for (i = 0; i < codec_list->num_codecs; i++) {
 164                if (sst_acpi_check_hid(codec_list->codecs[i]) != true)
 165                        return NULL;
 166        }
 167
 168        return mach;
 169}
 170EXPORT_SYMBOL_GPL(sst_acpi_codec_list);
 171
 172MODULE_LICENSE("GPL v2");
 173MODULE_DESCRIPTION("Intel Common ACPI Match module");
 174