1 /* 2 * soc-apci.c - support 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 <sound/soc-acpi.h> 18 19 static acpi_status snd_soc_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 37 const char *snd_soc_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, snd_soc_acpi_find_name, NULL, 43 (void **)&name); 44 45 if (ACPI_FAILURE(status) || name[0] == '\0') 46 return NULL; 47 48 return name; 49 } 50 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_name_from_hid); 51 52 static acpi_status snd_soc_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 66 bool snd_soc_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, snd_soc_acpi_mach_match, &found, NULL); 72 73 if (ACPI_FAILURE(status)) 74 return false; 75 76 return found; 77 } 78 EXPORT_SYMBOL_GPL(snd_soc_acpi_check_hid); 79 80 struct snd_soc_acpi_mach * 81 snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) 82 { 83 struct snd_soc_acpi_mach *mach; 84 85 for (mach = machines; mach->id[0]; mach++) { 86 if (snd_soc_acpi_check_hid(mach->id) == true) { 87 if (mach->machine_quirk == NULL) 88 return mach; 89 90 if (mach->machine_quirk(mach) != NULL) 91 return mach; 92 } 93 } 94 return NULL; 95 } 96 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine); 97 98 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level, 99 void *context, void **ret) 100 { 101 struct acpi_device *adev; 102 acpi_status status = AE_OK; 103 struct snd_soc_acpi_package_context *pkg_ctx = context; 104 105 pkg_ctx->data_valid = false; 106 107 if (acpi_bus_get_device(handle, &adev)) 108 return AE_OK; 109 110 if (adev->status.present && adev->status.functional) { 111 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 112 union acpi_object *myobj = NULL; 113 114 status = acpi_evaluate_object_typed(handle, pkg_ctx->name, 115 NULL, &buffer, 116 ACPI_TYPE_PACKAGE); 117 if (ACPI_FAILURE(status)) 118 return AE_OK; 119 120 myobj = buffer.pointer; 121 if (!myobj || myobj->package.count != pkg_ctx->length) { 122 kfree(buffer.pointer); 123 return AE_OK; 124 } 125 126 status = acpi_extract_package(myobj, 127 pkg_ctx->format, pkg_ctx->state); 128 if (ACPI_FAILURE(status)) { 129 kfree(buffer.pointer); 130 return AE_OK; 131 } 132 133 kfree(buffer.pointer); 134 pkg_ctx->data_valid = true; 135 return AE_CTRL_TERMINATE; 136 } 137 138 return AE_OK; 139 } 140 141 bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], 142 struct snd_soc_acpi_package_context *ctx) 143 { 144 acpi_status status; 145 146 status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL); 147 148 if (ACPI_FAILURE(status) || !ctx->data_valid) 149 return false; 150 151 return true; 152 } 153 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid); 154 155 struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) 156 { 157 struct snd_soc_acpi_mach *mach = arg; 158 struct snd_soc_acpi_codecs *codec_list = 159 (struct snd_soc_acpi_codecs *) mach->quirk_data; 160 int i; 161 162 if (mach->quirk_data == NULL) 163 return mach; 164 165 for (i = 0; i < codec_list->num_codecs; i++) { 166 if (snd_soc_acpi_check_hid(codec_list->codecs[i]) != true) 167 return NULL; 168 } 169 170 return mach; 171 } 172 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); 173 174 MODULE_LICENSE("GPL v2"); 175 MODULE_DESCRIPTION("ALSA SoC ACPI module"); 176