1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // soc-apci.c - support for ACPI enumeration. 4 // 5 // Copyright (c) 2013-15, Intel Corporation. 6 7 #include <linux/export.h> 8 #include <linux/module.h> 9 #include <sound/soc-acpi.h> 10 11 static bool snd_soc_acpi_id_present(struct snd_soc_acpi_mach *machine) 12 { 13 const struct snd_soc_acpi_codecs *comp_ids = machine->comp_ids; 14 int i; 15 16 if (machine->id[0]) { 17 if (acpi_dev_present(machine->id, NULL, -1)) 18 return true; 19 } 20 21 if (comp_ids) { 22 for (i = 0; i < comp_ids->num_codecs; i++) { 23 if (acpi_dev_present(comp_ids->codecs[i], NULL, -1)) { 24 strscpy(machine->id, comp_ids->codecs[i], ACPI_ID_LEN); 25 return true; 26 } 27 } 28 } 29 30 return false; 31 } 32 33 struct snd_soc_acpi_mach * 34 snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) 35 { 36 struct snd_soc_acpi_mach *mach; 37 struct snd_soc_acpi_mach *mach_alt; 38 39 for (mach = machines; mach->id[0] || mach->comp_ids; mach++) { 40 if (snd_soc_acpi_id_present(mach)) { 41 if (mach->machine_quirk) { 42 mach_alt = mach->machine_quirk(mach); 43 if (!mach_alt) 44 continue; /* not full match, ignore */ 45 mach = mach_alt; 46 } 47 48 return mach; 49 } 50 } 51 return NULL; 52 } 53 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine); 54 55 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level, 56 void *context, void **ret) 57 { 58 struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 59 acpi_status status; 60 struct snd_soc_acpi_package_context *pkg_ctx = context; 61 62 pkg_ctx->data_valid = false; 63 64 if (adev && adev->status.present && adev->status.functional) { 65 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 66 union acpi_object *myobj = NULL; 67 68 status = acpi_evaluate_object_typed(handle, pkg_ctx->name, 69 NULL, &buffer, 70 ACPI_TYPE_PACKAGE); 71 if (ACPI_FAILURE(status)) 72 return AE_OK; 73 74 myobj = buffer.pointer; 75 if (!myobj || myobj->package.count != pkg_ctx->length) { 76 kfree(buffer.pointer); 77 return AE_OK; 78 } 79 80 status = acpi_extract_package(myobj, 81 pkg_ctx->format, pkg_ctx->state); 82 if (ACPI_FAILURE(status)) { 83 kfree(buffer.pointer); 84 return AE_OK; 85 } 86 87 kfree(buffer.pointer); 88 pkg_ctx->data_valid = true; 89 return AE_CTRL_TERMINATE; 90 } 91 92 return AE_OK; 93 } 94 95 bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], 96 struct snd_soc_acpi_package_context *ctx) 97 { 98 acpi_status status; 99 100 status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL); 101 102 if (ACPI_FAILURE(status) || !ctx->data_valid) 103 return false; 104 105 return true; 106 } 107 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid); 108 109 struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) 110 { 111 struct snd_soc_acpi_mach *mach = arg; 112 struct snd_soc_acpi_codecs *codec_list = 113 (struct snd_soc_acpi_codecs *) mach->quirk_data; 114 int i; 115 116 if (mach->quirk_data == NULL) 117 return mach; 118 119 for (i = 0; i < codec_list->num_codecs; i++) { 120 if (!acpi_dev_present(codec_list->codecs[i], NULL, -1)) 121 return NULL; 122 } 123 124 return mach; 125 } 126 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); 127 128 MODULE_LICENSE("GPL v2"); 129 MODULE_DESCRIPTION("ALSA SoC ACPI module"); 130