From patchwork Wed Jul 29 16:45:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liam Girdwood X-Patchwork-Id: 6895451 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 62E69C05AC for ; Wed, 29 Jul 2015 16:51:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D9E802062F for ; Wed, 29 Jul 2015 16:51:45 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 81C062022D for ; Wed, 29 Jul 2015 16:51:43 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id A5BAE265993; Wed, 29 Jul 2015 18:51:42 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 86CC4265CBD; Wed, 29 Jul 2015 18:47:11 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id C9E99265CBA; Wed, 29 Jul 2015 18:47:09 +0200 (CEST) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by alsa0.perex.cz (Postfix) with ESMTP id DAB9B26599E for ; Wed, 29 Jul 2015 18:45:58 +0200 (CEST) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP; 29 Jul 2015 09:45:58 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,572,1432623600"; d="scan'208";a="615321059" Received: from iikavana-mobl1.ger.corp.intel.com (HELO loki.ger.corp.intel.com) ([10.252.21.221]) by orsmga003.jf.intel.com with ESMTP; 29 Jul 2015 09:45:57 -0700 From: Liam Girdwood To: Date: Wed, 29 Jul 2015 17:45:22 +0100 Message-Id: <1438188325-11553-11-git-send-email-liam.r.girdwood@linux.intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1438188325-11553-1-git-send-email-liam.r.girdwood@linux.intel.com> References: <1438188325-11553-1-git-send-email-liam.r.girdwood@linux.intel.com> Cc: Takashi Iwai , Liam Girdwood , Mark Brown Subject: [alsa-devel] [PATCH v3 10/13] topology: Add binary file builder. X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Build the binary output file from all the locally parsed objects and elements. Signed-off-by: Liam Girdwood --- src/topology/builder.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 src/topology/builder.c diff --git a/src/topology/builder.c b/src/topology/builder.c new file mode 100644 index 0000000..0066b22 --- /dev/null +++ b/src/topology/builder.c @@ -0,0 +1,327 @@ +/* + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + Authors: Mengdong Lin + Yao Jin + Liam Girdwood +*/ + +#include "list.h" +#include "tplg_local.h" + +/* verbose output detailing each object size and file position */ +static void verbose(snd_tplg_t *tplg, const char *fmt, ...) +{ + int offset; + va_list va; + + if (!tplg->verbose) + return; + + offset = lseek(tplg->out_fd, 0, SEEK_CUR); + + va_start(va, fmt); + fprintf(stdout, "0x%6.6x/%6.6d -", offset, offset); + vfprintf(stdout, fmt, va); + va_end(va); +} + +/* write out block header to output file */ +static int write_block_header(snd_tplg_t *tplg, unsigned int type, + unsigned int vendor_type, unsigned int version, unsigned int index, + size_t payload_size, int count) +{ + struct snd_soc_tplg_hdr hdr; + size_t bytes; + int offset = lseek(tplg->out_fd, 0, SEEK_CUR); + + memset(&hdr, 0, sizeof(hdr)); + hdr.magic = SND_SOC_TPLG_MAGIC; + hdr.abi = SND_SOC_TPLG_ABI_VERSION; + hdr.type = type; + hdr.vendor_type = vendor_type; + hdr.version = version; + hdr.payload_size = payload_size; + hdr.index = index; + hdr.size = sizeof(hdr); + hdr.count = count; + + /* make sure file offset is aligned with the calculated HDR offset */ + if ((unsigned int)offset != tplg->next_hdr_pos) { + SNDERR("error: New header is at offset 0x%x but file" + " offset 0x%x is %s by %d bytes\n", + tplg->next_hdr_pos, offset, + (unsigned int)offset > tplg->next_hdr_pos ? "ahead" : "behind", + abs(offset - tplg->next_hdr_pos)); + exit(-EINVAL); + } + + verbose(tplg, " header type %d size 0x%lx/%ld vendor %d " + "version %d\n", type, (long unsigned int)payload_size, + (long int)payload_size, vendor_type, version); + + tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr); + + bytes = write(tplg->out_fd, &hdr, sizeof(hdr)); + if (bytes != sizeof(hdr)) { + SNDERR("error: can't write section header %lu\n", + (long unsigned int)bytes); + return bytes; + } + + return bytes; +} + +static int write_data_block(snd_tplg_t *tplg, int size, int tplg_type, + const char *obj_name, void *data) +{ + int ret; + + /* write the header for this block */ + ret = write_block_header(tplg, tplg_type, 0, + SND_SOC_TPLG_ABI_VERSION, 0, size, 1); + if (ret < 0) { + SNDERR("error: failed to write %s block %d\n", obj_name, ret); + return ret; + } + + verbose(tplg, " %s : write %d bytes\n", obj_name, size); + + ret = write(tplg->out_fd, data, size); + if (ret < 0) { + SNDERR("error: failed to write %s %d\n", obj_name, ret); + return ret; + } + + return 0; +} + +static int write_elem_block(snd_tplg_t *tplg, + struct list_head *base, int size, int tplg_type, const char *obj_name) +{ + struct list_head *pos; + struct tplg_elem *elem; + int ret, wsize = 0, count = 0, vendor_type; + + /* count number of elements */ + list_for_each(pos, base) + count++; + + /* write the header for this block */ + list_for_each(pos, base) { + elem = list_entry(pos, struct tplg_elem, list); + vendor_type = elem->vendor_type; + break; + } + + ret = write_block_header(tplg, tplg_type, vendor_type, + SND_SOC_TPLG_ABI_VERSION, 0, size, count); + if (ret < 0) { + SNDERR("error: failed to write %s block %d\n", + obj_name, ret); + return ret; + } + + /* write each elem to block */ + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + + /* compound elems have already been copied to other elems */ + if (elem->compound_elem) + continue; + + if (elem->type != OBJECT_TYPE_DAPM_GRAPH) + verbose(tplg, " %s '%s': write %d bytes\n", + obj_name, elem->id, elem->size); + else + verbose(tplg, " %s '%s': write %d bytes\n", + obj_name, elem->route->source, elem->size); + + count = write(tplg->out_fd, elem->obj, elem->size); + if (count < 0) { + SNDERR("error: failed to write %s %d\n", + obj_name, ret); + return ret; + } + + wsize += count; + } + + /* make sure we have written the correct size */ + if (wsize != size) { + SNDERR("error: size mismatch. Expected %d wrote %d\n", + size, wsize); + return -EIO; + } + + return 0; +} + +static int calc_block_size(struct list_head *base) +{ + struct list_head *pos; + struct tplg_elem *elem; + int size = 0; + + list_for_each(pos, base) { + + elem = list_entry(pos, struct tplg_elem, list); + + /* compound elems have already been copied to other elems */ + if (elem->compound_elem) + continue; + + size += elem->size; + } + + return size; +} + +static int write_block(snd_tplg_t *tplg, struct list_head *base, + int type) +{ + int size; + + /* calculate the block size in bytes for all elems in this list */ + size = calc_block_size(base); + if (size <= 0) + return size; + + verbose(tplg, " block size for type %d is %d\n", type, size); + + /* write each elem for this block */ + switch (type) { + case OBJECT_TYPE_MIXER: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_MIXER, "mixer"); + case OBJECT_TYPE_BYTES: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_BYTES, "bytes"); + case OBJECT_TYPE_ENUM: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_ENUM, "enum"); + case OBJECT_TYPE_DAPM_GRAPH: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAPM_GRAPH, "route"); + case OBJECT_TYPE_DAPM_WIDGET: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAPM_WIDGET, "widget"); + case OBJECT_TYPE_PCM: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_PCM, "pcm"); + case OBJECT_TYPE_BE: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAI_LINK, "be"); + case OBJECT_TYPE_CC: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_DAI_LINK, "cc"); + case OBJECT_TYPE_MANIFEST: + return write_data_block(tplg, size, SND_SOC_TPLG_TYPE_MANIFEST, + "manifest", &tplg->manifest); + case OBJECT_TYPE_DATA: + return write_elem_block(tplg, base, size, + SND_SOC_TPLG_TYPE_PDATA, "data"); + default: + return -EINVAL; + } + + return 0; +} + +int tplg_write_data(snd_tplg_t *tplg) +{ + int ret; + + /* write manifest */ + ret = write_data_block(tplg, sizeof(tplg->manifest), + OBJECT_TYPE_MANIFEST, "manifest", &tplg->manifest); + if (ret < 0) { + SNDERR("failed to write manifest %d\n", ret); + return ret; + } + + /* write mixer elems. */ + ret = write_block(tplg, &tplg->mixer_list, + OBJECT_TYPE_MIXER); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write enum control elems. */ + ret = write_block(tplg, &tplg->enum_list, + OBJECT_TYPE_ENUM); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write bytes extended control elems. */ + ret = write_block(tplg, &tplg->bytes_ext_list, + OBJECT_TYPE_BYTES); + if (ret < 0) { + SNDERR("failed to write control elems %d\n", ret); + return ret; + } + + /* write widget elems */ + ret = write_block(tplg, &tplg->widget_list, + OBJECT_TYPE_DAPM_WIDGET); + if (ret < 0) { + SNDERR("failed to write widget elems %d\n", ret); + return ret; + } + + /* write pcm elems */ + ret = write_block(tplg, &tplg->pcm_list, + OBJECT_TYPE_PCM); + if (ret < 0) { + SNDERR("failed to write pcm elems %d\n", ret); + return ret; + } + + /* write be elems */ + ret = write_block(tplg, &tplg->be_list, + OBJECT_TYPE_BE); + if (ret < 0) { + SNDERR("failed to write be elems %d\n", ret); + return ret; + } + + /* write cc elems */ + ret = write_block(tplg, &tplg->cc_list, + OBJECT_TYPE_CC); + if (ret < 0) { + SNDERR("failed to write cc elems %d\n", ret); + return ret; + } + + /* write route elems */ + ret = write_block(tplg, &tplg->route_list, + OBJECT_TYPE_DAPM_GRAPH); + if (ret < 0) { + SNDERR("failed to write graph elems %d\n", ret); + return ret; + } + + /* write private data */ + ret = write_block(tplg, &tplg->pdata_list, + OBJECT_TYPE_DATA); + if (ret < 0) { + SNDERR("failed to write private data %d\n", ret); + return ret; + } + + return 0; +}