1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci Copyright (c) 2019 Red Hat Inc. 3d5ac70f0Sopenharmony_ci All rights reserved. 4d5ac70f0Sopenharmony_ci 5d5ac70f0Sopenharmony_ci This library is free software; you can redistribute it and/or modify 6d5ac70f0Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 7d5ac70f0Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of 8d5ac70f0Sopenharmony_ci the License, or (at your option) any later version. 9d5ac70f0Sopenharmony_ci 10d5ac70f0Sopenharmony_ci This program is distributed in the hope that it will be useful, 11d5ac70f0Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 12d5ac70f0Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13d5ac70f0Sopenharmony_ci GNU Lesser General Public License for more details. 14d5ac70f0Sopenharmony_ci 15d5ac70f0Sopenharmony_ci Authors: Jaroslav Kysela <perex@perex.cz> 16d5ac70f0Sopenharmony_ci*/ 17d5ac70f0Sopenharmony_ci 18d5ac70f0Sopenharmony_ci#include "tplg_local.h" 19d5ac70f0Sopenharmony_ci 20d5ac70f0Sopenharmony_ciint tplg_decode_template(snd_tplg_t *tplg, 21d5ac70f0Sopenharmony_ci size_t pos, 22d5ac70f0Sopenharmony_ci struct snd_soc_tplg_hdr *hdr, 23d5ac70f0Sopenharmony_ci snd_tplg_obj_template_t *t) 24d5ac70f0Sopenharmony_ci{ 25d5ac70f0Sopenharmony_ci int type; 26d5ac70f0Sopenharmony_ci 27d5ac70f0Sopenharmony_ci type = tplg_get_type(hdr->type); 28d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "template: asoc type %d library type %d", 29d5ac70f0Sopenharmony_ci hdr->type, type); 30d5ac70f0Sopenharmony_ci if (type < 0) 31d5ac70f0Sopenharmony_ci return type; 32d5ac70f0Sopenharmony_ci 33d5ac70f0Sopenharmony_ci memset(t, 0, sizeof(*t)); 34d5ac70f0Sopenharmony_ci t->type = type; 35d5ac70f0Sopenharmony_ci t->index = hdr->index; 36d5ac70f0Sopenharmony_ci t->version = hdr->version; 37d5ac70f0Sopenharmony_ci t->vendor_type = hdr->vendor_type; 38d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "template: index %d version %d vendor_type %d", 39d5ac70f0Sopenharmony_ci hdr->index, hdr->version, hdr->vendor_type); 40d5ac70f0Sopenharmony_ci return 0; 41d5ac70f0Sopenharmony_ci} 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ciint snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags) 44d5ac70f0Sopenharmony_ci{ 45d5ac70f0Sopenharmony_ci struct snd_soc_tplg_hdr *hdr; 46d5ac70f0Sopenharmony_ci struct tplg_table *tptr; 47d5ac70f0Sopenharmony_ci size_t pos; 48d5ac70f0Sopenharmony_ci void *b = bin; 49d5ac70f0Sopenharmony_ci unsigned int index; 50d5ac70f0Sopenharmony_ci int err; 51d5ac70f0Sopenharmony_ci 52d5ac70f0Sopenharmony_ci if (dflags != 0) 53d5ac70f0Sopenharmony_ci return -EINVAL; 54d5ac70f0Sopenharmony_ci if (tplg == NULL || bin == NULL) 55d5ac70f0Sopenharmony_ci return -EINVAL; 56d5ac70f0Sopenharmony_ci while (1) { 57d5ac70f0Sopenharmony_ci pos = b - bin; 58d5ac70f0Sopenharmony_ci if (size == pos) { 59d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "block: success (total %zd)", size); 60d5ac70f0Sopenharmony_ci return 0; 61d5ac70f0Sopenharmony_ci } 62d5ac70f0Sopenharmony_ci if (size - pos < sizeof(*hdr)) { 63d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "block: small size"); 64d5ac70f0Sopenharmony_ci SNDERR("incomplete header data to decode"); 65d5ac70f0Sopenharmony_ci return -EINVAL; 66d5ac70f0Sopenharmony_ci } 67d5ac70f0Sopenharmony_ci hdr = b; 68d5ac70f0Sopenharmony_ci if (hdr->magic != SND_SOC_TPLG_MAGIC) { 69d5ac70f0Sopenharmony_ci SNDERR("bad block magic %08x", hdr->magic); 70d5ac70f0Sopenharmony_ci return -EINVAL; 71d5ac70f0Sopenharmony_ci } 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "block: abi %d size %d payload size %d", 74d5ac70f0Sopenharmony_ci hdr->abi, hdr->size, hdr->payload_size); 75d5ac70f0Sopenharmony_ci if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) { 76d5ac70f0Sopenharmony_ci SNDERR("unsupported ABI version %d", hdr->abi); 77d5ac70f0Sopenharmony_ci return -EINVAL; 78d5ac70f0Sopenharmony_ci } 79d5ac70f0Sopenharmony_ci if (hdr->size != sizeof(*hdr)) { 80d5ac70f0Sopenharmony_ci SNDERR("header size mismatch"); 81d5ac70f0Sopenharmony_ci return -EINVAL; 82d5ac70f0Sopenharmony_ci } 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci if (size - pos < hdr->size + hdr->payload_size) { 85d5ac70f0Sopenharmony_ci SNDERR("incomplete payload data to decode"); 86d5ac70f0Sopenharmony_ci return -EINVAL; 87d5ac70f0Sopenharmony_ci } 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ci if (hdr->payload_size < 8) { 90d5ac70f0Sopenharmony_ci SNDERR("wrong payload size %d", hdr->payload_size); 91d5ac70f0Sopenharmony_ci return -EINVAL; 92d5ac70f0Sopenharmony_ci } 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_ci /* first block must be manifest */ 95d5ac70f0Sopenharmony_ci if (b == bin) { 96d5ac70f0Sopenharmony_ci if (hdr->type != SND_SOC_TPLG_TYPE_MANIFEST) { 97d5ac70f0Sopenharmony_ci SNDERR("first block must be manifest (value %d)", hdr->type); 98d5ac70f0Sopenharmony_ci return -EINVAL; 99d5ac70f0Sopenharmony_ci } 100d5ac70f0Sopenharmony_ci err = snd_tplg_set_version(tplg, hdr->version); 101d5ac70f0Sopenharmony_ci if (err < 0) 102d5ac70f0Sopenharmony_ci return err; 103d5ac70f0Sopenharmony_ci } 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_ci pos += hdr->size; 106d5ac70f0Sopenharmony_ci for (index = 0; index < tplg_table_items; index++) { 107d5ac70f0Sopenharmony_ci tptr = &tplg_table[index]; 108d5ac70f0Sopenharmony_ci if (tptr->tsoc == (int)hdr->type) 109d5ac70f0Sopenharmony_ci break; 110d5ac70f0Sopenharmony_ci } 111d5ac70f0Sopenharmony_ci if (index >= tplg_table_items || tptr->decod == NULL) { 112d5ac70f0Sopenharmony_ci SNDERR("unknown block type %d", hdr->type); 113d5ac70f0Sopenharmony_ci return -EINVAL; 114d5ac70f0Sopenharmony_ci } 115d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "block: type %d - %s", hdr->type, tptr->name); 116d5ac70f0Sopenharmony_ci err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size); 117d5ac70f0Sopenharmony_ci if (err < 0) 118d5ac70f0Sopenharmony_ci return err; 119d5ac70f0Sopenharmony_ci b += hdr->size + hdr->payload_size; 120d5ac70f0Sopenharmony_ci } 121d5ac70f0Sopenharmony_ci} 122