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; 59 acpi_status status; 60 struct snd_soc_acpi_package_context *pkg_ctx = context; 61 62 pkg_ctx->data_valid = false; 63 64 if (acpi_bus_get_device(handle, &adev)) 65 return AE_OK; 66 67 if (adev->status.present && adev->status.functional) { 68 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 69 union acpi_object *myobj = NULL; 70 71 status = acpi_evaluate_object_typed(handle, pkg_ctx->name, 72 NULL, &buffer, 73 ACPI_TYPE_PACKAGE); 74 if (ACPI_FAILURE(status)) 75 return AE_OK; 76 77 myobj = buffer.pointer; 78 if (!myobj || myobj->package.count != pkg_ctx->length) { 79 kfree(buffer.pointer); 80 return AE_OK; 81 } 82 83 status = acpi_extract_package(myobj, 84 pkg_ctx->format, pkg_ctx->state); 85 if (ACPI_FAILURE(status)) { 86 kfree(buffer.pointer); 87 return AE_OK; 88 } 89 90 kfree(buffer.pointer); 91 pkg_ctx->data_valid = true; 92 return AE_CTRL_TERMINATE; 93 } 94 95 return AE_OK; 96 } 97 98 bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], 99 struct snd_soc_acpi_package_context *ctx) 100 { 101 acpi_status status; 102 103 status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL); 104 105 if (ACPI_FAILURE(status) || !ctx->data_valid) 106 return false; 107 108 return true; 109 } 110 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid); 111 112 struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) 113 { 114 struct snd_soc_acpi_mach *mach = arg; 115 struct snd_soc_acpi_codecs *codec_list = 116 (struct snd_soc_acpi_codecs *) mach->quirk_data; 117 int i; 118 119 if (mach->quirk_data == NULL) 120 return mach; 121 122 for (i = 0; i < codec_list->num_codecs; i++) { 123 if (!acpi_dev_present(codec_list->codecs[i], NULL, -1)) 124 return NULL; 125 } 126 127 return mach; 128 } 129 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); 130 131 MODULE_LICENSE("GPL v2"); 132 MODULE_DESCRIPTION("ALSA SoC ACPI module"); 133