Blame src/topology/decoder.c

Packit Service db8eaa
/*
Packit Service db8eaa
  Copyright (c) 2019 Red Hat Inc.
Packit Service db8eaa
  All rights reserved.
Packit Service db8eaa
Packit Service db8eaa
  This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
  it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
  published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
  the License, or (at your option) any later version.
Packit Service db8eaa
Packit Service db8eaa
  This program is distributed in the hope that it will be useful,
Packit Service db8eaa
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
  GNU Lesser General Public License for more details.
Packit Service db8eaa
Packit Service db8eaa
  Authors: Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
#include "list.h"
Packit Service db8eaa
#include "tplg_local.h"
Packit Service db8eaa
Packit Service db8eaa
int tplg_decode_template(snd_tplg_t *tplg,
Packit Service db8eaa
			 size_t pos,
Packit Service db8eaa
			 struct snd_soc_tplg_hdr *hdr,
Packit Service db8eaa
			 snd_tplg_obj_template_t *t)
Packit Service db8eaa
{
Packit Service db8eaa
	int type;
Packit Service db8eaa
Packit Service db8eaa
	type = tplg_get_type(hdr->type);
Packit Service db8eaa
	tplg_log(tplg, 'D', pos, "template: asoc type %d library type %d",
Packit Service db8eaa
		 hdr->type, type);
Packit Service db8eaa
	if (type < 0)
Packit Service db8eaa
		return type;
Packit Service db8eaa
Packit Service db8eaa
	memset(t, 0, sizeof(*t));
Packit Service db8eaa
	t->type = type;
Packit Service db8eaa
	t->index = hdr->index;
Packit Service db8eaa
	t->version = hdr->version;
Packit Service db8eaa
	t->vendor_type = hdr->vendor_type;
Packit Service db8eaa
	tplg_log(tplg, 'D', pos, "template: index %d version %d vendor_type %d",
Packit Service db8eaa
		 hdr->index, hdr->version, hdr->vendor_type);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_hdr *hdr;
Packit Service db8eaa
	struct tplg_table *tptr;
Packit Service db8eaa
	size_t pos;
Packit Service db8eaa
	void *b = bin;
Packit Service db8eaa
	unsigned int index;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (dflags != 0)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	if (tplg == NULL || bin == NULL)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	while (1) {
Packit Service db8eaa
		pos = b - bin;
Packit Service db8eaa
		if (size == pos) {
Packit Service db8eaa
			tplg_log(tplg, 'D', pos, "block: success (total %zd)", size);
Packit Service db8eaa
			return 0;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (size - pos < sizeof(*hdr)) {
Packit Service db8eaa
			tplg_log(tplg, 'D', pos, "block: small size");
Packit Service db8eaa
			SNDERR("incomplete header data to decode");
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		hdr = b;
Packit Service db8eaa
		if (hdr->magic != SND_SOC_TPLG_MAGIC) {
Packit Service db8eaa
			SNDERR("bad block magic %08x", hdr->magic);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		tplg_log(tplg, 'D', pos, "block: abi %d size %d payload size %d",
Packit Service db8eaa
			 hdr->abi, hdr->size, hdr->payload_size);
Packit Service db8eaa
		if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
Packit Service db8eaa
			SNDERR("unsupported ABI version %d", hdr->abi);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (hdr->size != sizeof(*hdr)) {
Packit Service db8eaa
			SNDERR("header size mismatch");
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (size - pos < hdr->size + hdr->payload_size) {
Packit Service db8eaa
			SNDERR("incomplete payload data to decode");
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (hdr->payload_size < 8) {
Packit Service db8eaa
			SNDERR("wrong payload size %d", hdr->payload_size);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* first block must be manifest */
Packit Service db8eaa
		if (b == bin) {
Packit Service db8eaa
			if (hdr->type != SND_SOC_TPLG_TYPE_MANIFEST) {
Packit Service db8eaa
				SNDERR("first block must be manifest (value %d)", hdr->type);
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = snd_tplg_set_version(tplg, hdr->version);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		pos += hdr->size;
Packit Service db8eaa
		for (index = 0; index < tplg_table_items; index++) {
Packit Service db8eaa
			tptr = &tplg_table[index];
Packit Service db8eaa
			if (tptr->tsoc == (int)hdr->type)
Packit Service db8eaa
				break;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (index >= tplg_table_items || tptr->decod == NULL) {
Packit Service db8eaa
			SNDERR("unknown block type %d", hdr->type);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		tplg_log(tplg, 'D', pos, "block: type %d - %s", hdr->type, tptr->name);
Packit Service db8eaa
		err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		b += hdr->size + hdr->payload_size;
Packit Service db8eaa
	}
Packit Service db8eaa
}