- Backport upstream fixes: surround41/50 chmap fix, UCM documents, config string fix, PCM timestamp query API, replacement of list.h with LGPL: 0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch 0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch 0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch 0026-docs-Add-UCM-link-to-main-doxygen-page.patch 0027-Replace-unsafe-characters-with-_-in-card-name.patch 0028-pcm-add-helper-functions-to-query-timestamping-capab.patch 0029-pcm-add-support-for-get-set_audio_htstamp_config.patch 0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch 0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch 0032-test-audio_time-show-report-validity-and-accuracy.patch 0033-pcm-restore-hw-params-on-set-latency-failed.patch 0034-Replace-list.h-with-its-own-version.patch - Backport topology API addition patches: 0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch 0036-topology-Add-topology-core-parser.patch 0037-topology-Add-text-section-parser.patch 0038-topology-Add-PCM-parser.patch 0039-topology-Add-operations-parser.patch 0040-topology-Add-private-data-parser.patch 0041-topology-Add-DAPM-object-parser.patch 0042-topology-Add-CTL-parser.patch 0043-topology-Add-Channel-map-parser.patch 0044-topology-Add-binary-file-builder.patch 0045-topology-autotools-Add-build-support-for-topology-co.patch 0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch 0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch 0048-topology-Fix-missing-inclusion-of-ctype.h.patch OBS-URL: https://build.opensuse.org/request/show/320429 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=186
1327 lines
34 KiB
Diff
1327 lines
34 KiB
Diff
From 37692bb985bdaa95fbb23e4a12eb61f6a2c63ac0 Mon Sep 17 00:00:00 2001
|
|
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
Date: Wed, 29 Jul 2015 17:45:14 +0100
|
|
Subject: [PATCH 36/49] topology: Add topology core parser.
|
|
|
|
The topology core parses the high level topology file and calls the
|
|
individual object parsers when any new object element is detected at
|
|
the high level.
|
|
|
|
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
include/topology.h | 497 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
src/topology/elem.c | 187 +++++++++++++++++
|
|
src/topology/parser.c | 359 +++++++++++++++++++++++++++++++++
|
|
src/topology/tplg_local.h | 234 ++++++++++++++++++++++
|
|
4 files changed, 1277 insertions(+)
|
|
create mode 100644 include/topology.h
|
|
create mode 100644 src/topology/elem.c
|
|
create mode 100644 src/topology/parser.c
|
|
create mode 100644 src/topology/tplg_local.h
|
|
|
|
diff --git a/include/topology.h b/include/topology.h
|
|
new file mode 100644
|
|
index 000000000000..f604ed1450d3
|
|
--- /dev/null
|
|
+++ b/include/topology.h
|
|
@@ -0,0 +1,497 @@
|
|
+/*
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU Lesser General Public License as
|
|
+ * published by the Free Software Foundation; either version 2.1 of
|
|
+ * the License, or (at your option) any later version.
|
|
+ *
|
|
+ * 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 Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+ *
|
|
+ * Copyright (C) 2015 Intel Corporation
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __ALSA_TOPOLOGY_H
|
|
+#define __ALSA_TOPOLOGY_H
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * \defgroup topology Topology Interface
|
|
+ * \{
|
|
+ */
|
|
+
|
|
+/*! \page topology ALSA Topology Interface
|
|
+ *
|
|
+ * The topology interface allows developers to define DSP topologies in a text
|
|
+ * file format and to convert the text topology to a binary topology
|
|
+ * representation that can be understood by the kernel. The topology core
|
|
+ * currently recognises the following object types :-
|
|
+ *
|
|
+ * * Controls (mixer, enumerated and byte) including TLV data.
|
|
+ * * PCMs (FE and BE configurations and capabilities)
|
|
+ * * DAPM widgets
|
|
+ * * DAPM graph elements.
|
|
+ * * Private data for each object type.
|
|
+ * * Manifest (containing count of each object type)
|
|
+ *
|
|
+ * <h3>Topology File Format</h3>
|
|
+ *
|
|
+ * The topology text format uses the standard ALSA configuration file format to
|
|
+ * describe each topology object type. This allows topology objects to include
|
|
+ * other topology objects as part of thier definition. i.e. a TLV data object
|
|
+ * can be shared amongst many control objects that use the same TLV data.
|
|
+ *
|
|
+ *
|
|
+ * <h4>Controls</h4>
|
|
+ * Topology audio controls can belong to three different types :-
|
|
+ * * Mixer control
|
|
+ * * Enumerated control
|
|
+ * * Byte control
|
|
+ *
|
|
+ * Each control type can contain TLV data, private data, operations and also
|
|
+ * belong to widget objects.<br>
|
|
+ *
|
|
+ * <h5>Control Operations</h5>
|
|
+ * Driver Kcontrol callback info(), get() and put() operations are mapped with
|
|
+ * the CTL ops section in topology configuration files. The ctl ops section can
|
|
+ * assign operations using the standard names (listed below) for the standard
|
|
+ * kcontrol types or use ID numbers (>256) to map to bespoke driver controls.<br>
|
|
+ *
|
|
+ * <pre>
|
|
+ *
|
|
+ * ops."ctl" {
|
|
+ * info "volsw"
|
|
+ * get "257"
|
|
+ * put "257"
|
|
+ * }
|
|
+ *
|
|
+ * </pre>
|
|
+ *
|
|
+ * This mapping shows info() using the standard "volsw" info callback whilst
|
|
+ * the get() and put() are mapped to bespoke driver callbacks. <br>
|
|
+ *
|
|
+ * The Standard operations names for control get(), put() and info calls
|
|
+ * are :-
|
|
+ * * volsw
|
|
+ * * volsw_sx
|
|
+ * * volsw_xr_sx
|
|
+ * * enum
|
|
+ * * bytes
|
|
+ * * enum_value
|
|
+ * * range
|
|
+ * * strobe
|
|
+ *
|
|
+ * <h5>Control TLV Data</h5>
|
|
+ * Controls can also use TLV data to represent dB information. This can be done
|
|
+ * by defining a TLV section and using the TLV section within the control.
|
|
+ * The TLV data for DBScale types are defined as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * scale {
|
|
+ * min "-9000"
|
|
+ * step "300"
|
|
+ * mute "1"
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * Where the meanings and values for min, step and mute are exactly the same
|
|
+ * as defined in driver code.
|
|
+ *
|
|
+ * <h5>Control Channel Mapping</h5>
|
|
+ * Controls can also specify which channels they are mapped with. This is useful
|
|
+ * for userspace as it allows applications to determine the correct control
|
|
+ * channel for Left and Right etc. Channel maps are defined as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * channel."name" {
|
|
+ * reg "0"
|
|
+ * shift "0"
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The channel map reg is the register offset for the control, shift is the
|
|
+ * bit shift within the register for the channel and the section name is the
|
|
+ * channel name and can be one of the following :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * * mono # mono stream
|
|
+ * * fl # front left
|
|
+ * * fr # front right
|
|
+ * * rl # rear left
|
|
+ * * rr # rear right
|
|
+ * * fc # front center
|
|
+ * * lfe # LFE
|
|
+ * * sl # side left
|
|
+ * * sr # side right
|
|
+ * * rc # rear center
|
|
+ * * flc # front left center
|
|
+ * * frc # front right center
|
|
+ * * rlc # rear left center
|
|
+ * * rrc # rear right center
|
|
+ * * flw # front left wide
|
|
+ * * frw # front right wide
|
|
+ * * flh # front left high
|
|
+ * * fch # front center high
|
|
+ * * frh # front right high
|
|
+ * * tc # top center
|
|
+ * * tfl # top front left
|
|
+ * * tfr # top front right
|
|
+ * * tfc # top front center
|
|
+ * * trl # top rear left
|
|
+ * * trr # top rear right
|
|
+ * * trc # top rear center
|
|
+ * * tflc # top front left center
|
|
+ * * tfrc # top front right center
|
|
+ * * tsl # top side left
|
|
+ * * tsr # top side right
|
|
+ * * llfe # left LFE
|
|
+ * * rlfe # right LFE
|
|
+ * * bc # bottom center
|
|
+ * * blc # bottom left center
|
|
+ * * brc # bottom right center
|
|
+ * </pre>
|
|
+ *
|
|
+ * <h5>Control Private Data</h5>
|
|
+ * Controls can also have private data. This can be done by defining a private
|
|
+ * data section and including the section within the control. The private data
|
|
+ * section is defined as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionData."pdata for EQU1" {
|
|
+ * file "/path/to/file"
|
|
+ * bytes "0x12,0x34,0x56,0x78"
|
|
+ * shorts "0x1122,0x3344,0x5566,0x7788"
|
|
+ * words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
|
|
+ * };
|
|
+ * </pre>
|
|
+ * The file, bytes, shorts and words keywords are all mutulally exclusive as
|
|
+ * the private data should only be taken from one source. The private data can
|
|
+ * either be read from a separate file or defined in the topology file using
|
|
+ * the bytes, shorts or words keywords.
|
|
+ *
|
|
+ * <h5>Mixer Controls</h5>
|
|
+ * A mixer control is defined as a new section that can include channel mapping,
|
|
+ * TLV data, callback operations and private data. The mixer section also
|
|
+ * includes a few other config options that are shown here :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionControlMixer."mixer name" {
|
|
+ * comment "optional comments"
|
|
+ *
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * channel."name" { # Channel maps
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * ops."ctl" { # Ops callback functions
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * max "32" # Max control value
|
|
+ * invert "0" # Whether control values are inverted
|
|
+ *
|
|
+ * tlv "tld_data" # optional TLV data
|
|
+ *
|
|
+ * data "pdata for mixer1" # optional private data
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The section name is used to define the mixer name. The index number can be
|
|
+ * used to identify topology objects groups. This allows driver operations on
|
|
+ * objects with index number N and can be used to add/remove pipelines of
|
|
+ * objects whilst other objects are unaffected.
|
|
+ *
|
|
+ * <h5>Byte Controls</h5>
|
|
+ * A byte control is defined as a new section that can include channel mapping,
|
|
+ * TLV data, callback operations and private data. The bytes section also
|
|
+ * includes a few other config options that are shown here :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionControlBytes."name" {
|
|
+ * comment "optional comments"
|
|
+ *
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * channel."name" { # Channel maps
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * ops."ctl" { # Ops callback functions
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * base "0" # Register base
|
|
+ * num_regs "16" # Number of registers
|
|
+ * mask "0xff" # Mask
|
|
+ * max "255" # Maximum value
|
|
+ *
|
|
+ * tlv "tld_data" # optional TLV data
|
|
+ *
|
|
+ * data "pdata for mixer1" # optional private data
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * <h5>Enumerated Controls</h5>
|
|
+ * A enumerated control is defined as a new section (like mixer and byte) that
|
|
+ * can include channel mapping, callback operations, private data and
|
|
+ * text strings to represent the enumerated control options.<br>
|
|
+ *
|
|
+ * The text strings for the enumerated controls are defined in a seperate
|
|
+ * section as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionText."name" {
|
|
+ *
|
|
+ * Values [
|
|
+ * "value1"
|
|
+ * "value2"
|
|
+ "value3"
|
|
+ * ]
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * All the enumerated text values are listed in the values list.<br>
|
|
+ * The enumerated control is similar to the other controls and defined as
|
|
+ * follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionControlMixer."name" {
|
|
+ * comment "optional comments"
|
|
+ *
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * texts "EQU1" # Enumerated text items
|
|
+ *
|
|
+ * channel."name" { # Channel maps
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * ops."ctl" { # Ops callback functions
|
|
+ * ....
|
|
+ * }
|
|
+ *
|
|
+ * data "pdata for mixer1" # optional private data
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * <h4>DAPM Graph</h4>
|
|
+ * DAPM graphs can easily be defined using the topology file. The format is
|
|
+ * very similar to the DAPM graph kernel format. :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionGraph."dsp" {
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * lines [
|
|
+ * "sink1, control, source1"
|
|
+ * "sink2, , source2"
|
|
+ * ]
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The lines in the graph are defined as a variable size list of sinks,
|
|
+ * controls and sources. The control name is optional as some graph lines have
|
|
+ * no associated controls. The section name can be used to differentiate the
|
|
+ * graph with other graphs, it's not used by the kernel atm.
|
|
+ *
|
|
+ * <h4>DAPM Widgets</h4>
|
|
+ * DAPM wigets are similar to controls in that they can include many other
|
|
+ * objects. Widgets can contain private data, mixer controls and enum controls.
|
|
+ *
|
|
+ * The following widget types are supported and match the driver types :-
|
|
+ *
|
|
+ * * input
|
|
+ * * output
|
|
+ * * mux
|
|
+ * * mixer
|
|
+ * * pga
|
|
+ * * out_drv
|
|
+ * * adc
|
|
+ * * dac
|
|
+ * * switch
|
|
+ * * pre
|
|
+ * * post
|
|
+ * * aif_in
|
|
+ * * aif_out
|
|
+ * * dai_in
|
|
+ * * dai_out
|
|
+ * * dai_link
|
|
+ *
|
|
+ * Widgets are defined as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionWidget."name" {
|
|
+ *
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * type "aif_in" # Widget type - detailed above
|
|
+ *
|
|
+ * no_pm "true" # No PM control bit.
|
|
+ * reg "20" # PM bit register offset
|
|
+ * shift "0" # PM bit register shift
|
|
+ * invert "1 # PM bit is inverted
|
|
+ * subseq "8" # subsequence number
|
|
+ *
|
|
+ * event_type "1" # DAPM widget event type
|
|
+ * event_flags "1" # DAPM widget event flags
|
|
+ *
|
|
+ * mixer "name" # Optional Mixer Control
|
|
+ * enum "name" # Optional Enum Control
|
|
+ *
|
|
+ * data "name" # optional private data
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The section name is the widget name. The mixer and enum fields are mutually
|
|
+ * exclusive and used to include controls into the widget. The index and data
|
|
+ * fields are the same for widgets as they are for controls whilst the other
|
|
+ * fields map on very closely to the driver widget fields.
|
|
+ *
|
|
+ * <h4>PCM Capabilities</h4>
|
|
+ * Topology can also define the capabilities of FE and BE PCMs. Capabilities
|
|
+ * can be defined with the following section :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionPCMCapabilities."name" {
|
|
+ *
|
|
+ * formats "S24_LE,S16_LE" # Supported formats
|
|
+ * rate_min "48000" # Max supported sample rate
|
|
+ * rate_max "48000" # Min suppoprted sample rate
|
|
+ * channels_min "2" # Min number of channels
|
|
+ * channels_max "2" # max number of channels
|
|
+ * }
|
|
+ * </pre>
|
|
+ * The supported formats use the same naming convention as the driver macros.
|
|
+ * The PCM capabilities name can be reffered to and included by BE, PCM and
|
|
+ * Codec <-> codec topology sections.
|
|
+ *
|
|
+ * <h4>PCM Configurations</h4>
|
|
+ * PCM runtime configurations can be defined for playback and capture stream
|
|
+ * directions with the following section :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionPCMConfig."name" {
|
|
+ *
|
|
+ * config."playback" { # playback config
|
|
+ * format "S16_LE" # playback format
|
|
+ * rate "48000" # playback sample rate
|
|
+ * channels "2" # playback channels
|
|
+ * tdm_slot "0xf" # playback TDM slot
|
|
+ * }
|
|
+ *
|
|
+ * config."capture" { # capture config
|
|
+ * format "S16_LE" # capture format
|
|
+ * rate "48000" # capture sample rate
|
|
+ * channels "2" # capture channels
|
|
+ * tdm_slot "0xf" # capture TDM slot
|
|
+ * }
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The supported formats use the same naming convention as the driver macros.
|
|
+ * The PCM configuration name can be reffered to and included by BE, PCM and
|
|
+ * Codec <-> codec topology sections.
|
|
+ *
|
|
+ * <h4>PCM Configurations</h4>
|
|
+ * PCM, BE and Codec to Codec link sections define the supported capabilities
|
|
+ * and configurations for supported playback and capture streams. The
|
|
+ * definitions and content for PCMs, BE and Codec links are the same with the
|
|
+ * exception of the section type :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionPCM."name" {
|
|
+ * ....
|
|
+ * }
|
|
+ * SectionBE."name" {
|
|
+ * ....
|
|
+ * }
|
|
+ * SectionCC."name" {
|
|
+ * ....
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ * The section types above should be used for PCMs, Back Ends and Codec to Codec
|
|
+ * links respectively.<br>
|
|
+ *
|
|
+ * The data for each section is defined as follows :-
|
|
+ *
|
|
+ * <pre>
|
|
+ * SectionPCM."name" {
|
|
+ *
|
|
+ * index "1" # Index number
|
|
+ *
|
|
+ * id "0" # used for binding to the PCM
|
|
+ *
|
|
+ * pcm."playback" {
|
|
+ * capabilities "capabilities1" # capbilities for playback
|
|
+ *
|
|
+ * configs [ # supported configs for playback
|
|
+ * "config1"
|
|
+ * "config2"
|
|
+ * ]
|
|
+ * }
|
|
+ *
|
|
+ * pcm."capture" {
|
|
+ * capabilities "capabilities2" # capabilities for capture
|
|
+ *
|
|
+ * configs [ # supported configs for capture
|
|
+ * "config1"
|
|
+ * "config2"
|
|
+ * "config3"
|
|
+ * ]
|
|
+ * }
|
|
+ * }
|
|
+ * </pre>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/** Topology context */
|
|
+typedef struct snd_tplg snd_tplg_t;
|
|
+
|
|
+/**
|
|
+ * \brief Create a new topology parser instance.
|
|
+ * \return New topology parser instance
|
|
+ */
|
|
+snd_tplg_t *snd_tplg_new(void);
|
|
+
|
|
+/**
|
|
+ * \brief Free a topology parser instance.
|
|
+ * \param tplg Topology parser instance
|
|
+ */
|
|
+void snd_tplg_free(snd_tplg_t *tplg);
|
|
+
|
|
+/**
|
|
+ * \brief Parse and build topology text file into binary file.
|
|
+ * \param tplg Topology instance.
|
|
+ * \param infile Topology text input file to be parsed
|
|
+ * \param outfile Binary topology output file.
|
|
+ * \return Zero on sucess, otherwise a negative error code
|
|
+ */
|
|
+int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile,
|
|
+ const char *outfile);
|
|
+
|
|
+/**
|
|
+ * \brief Enable verbose reporting of binary file output
|
|
+ * \param tplg Topology Instance
|
|
+ * \param verbose Enable verbose output level if non zero
|
|
+ */
|
|
+void snd_tplg_verbose(snd_tplg_t *tplg, int verbose);
|
|
+
|
|
+/* \} */
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* __ALSA_TOPOLOGY_H */
|
|
diff --git a/src/topology/elem.c b/src/topology/elem.c
|
|
new file mode 100644
|
|
index 000000000000..32ba2c12375b
|
|
--- /dev/null
|
|
+++ b/src/topology/elem.c
|
|
@@ -0,0 +1,187 @@
|
|
+/*
|
|
+ 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 <mengdong.lin@intel.com>
|
|
+ Yao Jin <yao.jin@intel.com>
|
|
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
+*/
|
|
+
|
|
+#include "list.h"
|
|
+#include "tplg_local.h"
|
|
+
|
|
+int tplg_ref_add(struct tplg_elem *elem, int type, const char* id)
|
|
+{
|
|
+ struct tplg_ref *ref;
|
|
+
|
|
+ ref = calloc(1, sizeof(*ref));
|
|
+ if (!ref)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ strncpy(ref->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
+ ref->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
|
|
+ ref->type = type;
|
|
+
|
|
+ list_add_tail(&ref->list, &elem->ref_list);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void tplg_ref_free_list(struct list_head *base)
|
|
+{
|
|
+ struct list_head *pos, *npos;
|
|
+ struct tplg_ref *ref;
|
|
+
|
|
+ list_for_each_safe(pos, npos, base) {
|
|
+ ref = list_entry(pos, struct tplg_ref, list);
|
|
+ list_del(&ref->list);
|
|
+ free(ref);
|
|
+ }
|
|
+}
|
|
+
|
|
+struct tplg_elem *tplg_elem_new(void)
|
|
+{
|
|
+ struct tplg_elem *elem;
|
|
+
|
|
+ elem = calloc(1, sizeof(*elem));
|
|
+ if (!elem)
|
|
+ return NULL;
|
|
+
|
|
+ INIT_LIST_HEAD(&elem->ref_list);
|
|
+ return elem;
|
|
+}
|
|
+
|
|
+void tplg_elem_free(struct tplg_elem *elem)
|
|
+{
|
|
+ tplg_ref_free_list(&elem->ref_list);
|
|
+
|
|
+ /* free struct snd_tplg_ object,
|
|
+ * the union pointers share the same address
|
|
+ */
|
|
+ if (elem->mixer_ctrl)
|
|
+ free(elem->mixer_ctrl);
|
|
+
|
|
+ free(elem);
|
|
+}
|
|
+
|
|
+void tplg_elem_free_list(struct list_head *base)
|
|
+{
|
|
+ struct list_head *pos, *npos;
|
|
+ struct tplg_elem *elem;
|
|
+
|
|
+ list_for_each_safe(pos, npos, base) {
|
|
+ elem = list_entry(pos, struct tplg_elem, list);
|
|
+ list_del(&elem->list);
|
|
+ tplg_elem_free(elem);
|
|
+ }
|
|
+}
|
|
+
|
|
+struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id,
|
|
+ unsigned int type)
|
|
+{
|
|
+ struct list_head *pos;
|
|
+ struct tplg_elem *elem;
|
|
+
|
|
+ list_for_each(pos, base) {
|
|
+
|
|
+ elem = list_entry(pos, struct tplg_elem, list);
|
|
+
|
|
+ if (!strcmp(elem->id, id) && elem->type == type)
|
|
+ return elem;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* create a new common element and object */
|
|
+struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, enum object_type type)
|
|
+{
|
|
+ struct tplg_elem *elem;
|
|
+ const char *id;
|
|
+ int obj_size = 0;
|
|
+ void *obj;
|
|
+
|
|
+ elem = tplg_elem_new();
|
|
+ if (!elem)
|
|
+ return NULL;
|
|
+
|
|
+ snd_config_get_id(cfg, &id);
|
|
+ strncpy(elem->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
+ elem->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
|
|
+
|
|
+ switch (type) {
|
|
+ case OBJECT_TYPE_DATA:
|
|
+ list_add_tail(&elem->list, &tplg->pdata_list);
|
|
+ break;
|
|
+ case OBJECT_TYPE_TEXT:
|
|
+ list_add_tail(&elem->list, &tplg->text_list);
|
|
+ break;
|
|
+ case OBJECT_TYPE_TLV:
|
|
+ list_add_tail(&elem->list, &tplg->tlv_list);
|
|
+ elem->size = sizeof(struct snd_soc_tplg_ctl_tlv);
|
|
+ break;
|
|
+ case OBJECT_TYPE_BYTES:
|
|
+ list_add_tail(&elem->list, &tplg->bytes_ext_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_bytes_control);
|
|
+ break;
|
|
+ case OBJECT_TYPE_ENUM:
|
|
+ list_add_tail(&elem->list, &tplg->enum_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_enum_control);
|
|
+ break;
|
|
+ case SND_SOC_TPLG_TYPE_MIXER:
|
|
+ list_add_tail(&elem->list, &tplg->mixer_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_mixer_control);
|
|
+ break;
|
|
+ case OBJECT_TYPE_DAPM_WIDGET:
|
|
+ list_add_tail(&elem->list, &tplg->widget_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_dapm_widget);
|
|
+ break;
|
|
+ case OBJECT_TYPE_STREAM_CONFIG:
|
|
+ list_add_tail(&elem->list, &tplg->pcm_config_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_stream_config);
|
|
+ break;
|
|
+ case OBJECT_TYPE_STREAM_CAPS:
|
|
+ list_add_tail(&elem->list, &tplg->pcm_caps_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_stream_caps);
|
|
+ break;
|
|
+ case OBJECT_TYPE_PCM:
|
|
+ list_add_tail(&elem->list, &tplg->pcm_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_pcm_dai);
|
|
+ break;
|
|
+ case OBJECT_TYPE_BE:
|
|
+ list_add_tail(&elem->list, &tplg->be_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_pcm_dai);
|
|
+ break;
|
|
+ case OBJECT_TYPE_CC:
|
|
+ list_add_tail(&elem->list, &tplg->cc_list);
|
|
+ obj_size = sizeof(struct snd_soc_tplg_pcm_dai);
|
|
+ break;
|
|
+ default:
|
|
+ free(elem);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* create new object too if required */
|
|
+ if (obj_size > 0) {
|
|
+ obj = calloc(1, obj_size);
|
|
+ if (obj == NULL) {
|
|
+ free(elem);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ elem->obj = obj;
|
|
+ elem->size = obj_size;
|
|
+ }
|
|
+
|
|
+ elem->type = type;
|
|
+ return elem;
|
|
+}
|
|
diff --git a/src/topology/parser.c b/src/topology/parser.c
|
|
new file mode 100644
|
|
index 000000000000..ed25bb88d446
|
|
--- /dev/null
|
|
+++ b/src/topology/parser.c
|
|
@@ -0,0 +1,359 @@
|
|
+/*
|
|
+ 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 <mengdong.lin@intel.com>
|
|
+ Yao Jin <yao.jin@intel.com>
|
|
+ Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
+*/
|
|
+
|
|
+#include "list.h"
|
|
+#include "tplg_local.h"
|
|
+
|
|
+/*
|
|
+ * Parse compound
|
|
+ */
|
|
+int tplg_parse_compound(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ int (*fcn)(snd_tplg_t *, snd_config_t *, void *),
|
|
+ void *private)
|
|
+{
|
|
+ const char *id;
|
|
+ snd_config_iterator_t i, next;
|
|
+ snd_config_t *n;
|
|
+ int err = -EINVAL;
|
|
+
|
|
+ if (snd_config_get_id(cfg, &id) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
|
+ SNDERR("error: compound type expected for %s", id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* parse compound */
|
|
+ snd_config_for_each(i, next, cfg) {
|
|
+ n = snd_config_iterator_entry(i);
|
|
+
|
|
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
|
+ SNDERR("error: compound type expected for %s, is %d",
|
|
+ id, snd_config_get_type(cfg));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ err = fcn(tplg, n, private);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
|
|
+{
|
|
+ snd_config_iterator_t i, next;
|
|
+ snd_config_t *n;
|
|
+ const char *id;
|
|
+ int err;
|
|
+
|
|
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
|
+ SNDERR("error: compound type expected at top level");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* parse topology config sections */
|
|
+ snd_config_for_each(i, next, cfg) {
|
|
+
|
|
+ n = snd_config_iterator_entry(i);
|
|
+ if (snd_config_get_id(n, &id) < 0)
|
|
+ continue;
|
|
+
|
|
+ if (strcmp(id, "SectionTLV") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n, tplg_parse_tlv,
|
|
+ NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionControlMixer") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_control_mixer, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionControlEnum") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_control_enum, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionControlBytes") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_control_bytes, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionWidget") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_dapm_widget, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionPCMConfig") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_pcm_config, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionPCMCapabilities") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_pcm_caps, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionPCM") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_pcm, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionBE") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n, tplg_parse_be,
|
|
+ NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionCC") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n, tplg_parse_cc,
|
|
+ NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionGraph") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n,
|
|
+ tplg_parse_dapm_graph, NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionText") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n, tplg_parse_text,
|
|
+ NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(id, "SectionData") == 0) {
|
|
+ err = tplg_parse_compound(tplg, n, tplg_parse_data,
|
|
+ NULL);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ SNDERR("error: unknown section %s\n", id);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int tplg_load_config(const char *file, snd_config_t **cfg)
|
|
+{
|
|
+ FILE *fp;
|
|
+ snd_input_t *in;
|
|
+ snd_config_t *top;
|
|
+ int ret;
|
|
+
|
|
+ fp = fopen(file, "r");
|
|
+ if (fp == NULL) {
|
|
+ SNDERR("error: could not open configuration file %s",
|
|
+ file);
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ ret = snd_input_stdio_attach(&in, fp, 1);
|
|
+ if (ret < 0) {
|
|
+ SNDERR("error: could not attach stdio %s", file);
|
|
+ goto err;
|
|
+ }
|
|
+ ret = snd_config_top(&top);
|
|
+ if (ret < 0)
|
|
+ goto err;
|
|
+
|
|
+ ret = snd_config_load(top, in);
|
|
+ if (ret < 0) {
|
|
+ SNDERR("error: could not load configuration file %s",
|
|
+ file);
|
|
+ goto err_load;
|
|
+ }
|
|
+
|
|
+ ret = snd_input_close(in);
|
|
+ if (ret < 0)
|
|
+ goto err_load;
|
|
+
|
|
+ *cfg = top;
|
|
+ return 0;
|
|
+
|
|
+err_load:
|
|
+ snd_config_delete(top);
|
|
+err:
|
|
+ fclose(fp);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tplg_build_integ(snd_tplg_t *tplg)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = tplg_build_controls(tplg);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ err = tplg_build_widgets(tplg);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_PCM);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_BE);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_CC);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ err = tplg_build_routes(tplg);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile,
|
|
+ const char *outfile)
|
|
+{
|
|
+ snd_config_t *cfg = NULL;
|
|
+ int err = 0;
|
|
+
|
|
+ /* delete any old output files */
|
|
+ unlink(outfile);
|
|
+
|
|
+ tplg->out_fd =
|
|
+ open(outfile, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
+ if (tplg->out_fd < 0) {
|
|
+ SNDERR("error: failed to open %s err %d\n",
|
|
+ outfile, -errno);
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ err = tplg_load_config(infile, &cfg);
|
|
+ if (err < 0) {
|
|
+ SNDERR("error: failed to load topology file %s\n",
|
|
+ infile);
|
|
+ goto out_close;
|
|
+ }
|
|
+
|
|
+ err = tplg_parse_config(tplg, cfg);
|
|
+ if (err < 0) {
|
|
+ SNDERR("error: failed to parse topology\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ err = tplg_build_integ(tplg);
|
|
+ if (err < 0) {
|
|
+ SNDERR("error: failed to check topology integrity\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ err = tplg_write_data(tplg);
|
|
+ if (err < 0) {
|
|
+ SNDERR("error: failed to write data %d\n", err);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ snd_config_delete(cfg);
|
|
+out_close:
|
|
+ close(tplg->out_fd);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+void snd_tplg_verbose(snd_tplg_t *tplg, int verbose)
|
|
+{
|
|
+ tplg->verbose = verbose;
|
|
+}
|
|
+
|
|
+snd_tplg_t *snd_tplg_new(void)
|
|
+{
|
|
+ snd_tplg_t *tplg;
|
|
+
|
|
+ tplg = calloc(1, sizeof(snd_tplg_t));
|
|
+ if (!tplg)
|
|
+ return NULL;
|
|
+
|
|
+ INIT_LIST_HEAD(&tplg->tlv_list);
|
|
+ INIT_LIST_HEAD(&tplg->widget_list);
|
|
+ INIT_LIST_HEAD(&tplg->pcm_list);
|
|
+ INIT_LIST_HEAD(&tplg->be_list);
|
|
+ INIT_LIST_HEAD(&tplg->cc_list);
|
|
+ INIT_LIST_HEAD(&tplg->route_list);
|
|
+ INIT_LIST_HEAD(&tplg->pdata_list);
|
|
+ INIT_LIST_HEAD(&tplg->text_list);
|
|
+ INIT_LIST_HEAD(&tplg->pcm_config_list);
|
|
+ INIT_LIST_HEAD(&tplg->pcm_caps_list);
|
|
+ INIT_LIST_HEAD(&tplg->mixer_list);
|
|
+ INIT_LIST_HEAD(&tplg->enum_list);
|
|
+ INIT_LIST_HEAD(&tplg->bytes_ext_list);
|
|
+
|
|
+ return tplg;
|
|
+}
|
|
+
|
|
+void snd_tplg_free(snd_tplg_t *tplg)
|
|
+{
|
|
+ tplg_elem_free_list(&tplg->tlv_list);
|
|
+ tplg_elem_free_list(&tplg->widget_list);
|
|
+ tplg_elem_free_list(&tplg->pcm_list);
|
|
+ tplg_elem_free_list(&tplg->be_list);
|
|
+ tplg_elem_free_list(&tplg->cc_list);
|
|
+ tplg_elem_free_list(&tplg->route_list);
|
|
+ tplg_elem_free_list(&tplg->pdata_list);
|
|
+ tplg_elem_free_list(&tplg->text_list);
|
|
+ tplg_elem_free_list(&tplg->pcm_config_list);
|
|
+ tplg_elem_free_list(&tplg->pcm_caps_list);
|
|
+ tplg_elem_free_list(&tplg->mixer_list);
|
|
+ tplg_elem_free_list(&tplg->enum_list);
|
|
+ tplg_elem_free_list(&tplg->bytes_ext_list);
|
|
+
|
|
+ free(tplg);
|
|
+}
|
|
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
|
|
new file mode 100644
|
|
index 000000000000..688c78f3a6a4
|
|
--- /dev/null
|
|
+++ b/src/topology/tplg_local.h
|
|
@@ -0,0 +1,234 @@
|
|
+/*
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library 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
|
|
+ * Lesser General Public License for more details.
|
|
+ */
|
|
+
|
|
+#include <limits.h>
|
|
+#include <stdint.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#include "local.h"
|
|
+#include "list.h"
|
|
+#include "topology.h"
|
|
+
|
|
+#include <sound/asound.h>
|
|
+#include <sound/asoc.h>
|
|
+#include <sound/tlv.h>
|
|
+
|
|
+#define TPLG_DEBUG
|
|
+#ifdef TPLG_DEBUG
|
|
+#define tplg_dbg SNDERR
|
|
+#else
|
|
+#define tplg_dbg(fmt, arg...) do { } while (0)
|
|
+#endif
|
|
+
|
|
+#define MAX_FILE 256
|
|
+#define TPLG_MAX_PRIV_SIZE (1024 * 128)
|
|
+#define ALSA_TPLG_DIR ALSA_CONFIG_DIR "/topology"
|
|
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
|
+
|
|
+/** The name of the environment variable containing the tplg directory */
|
|
+#define ALSA_CONFIG_TPLG_VAR "ALSA_CONFIG_TPLG"
|
|
+
|
|
+struct tplg_ref;
|
|
+struct tplg_elem;
|
|
+
|
|
+/* internal topology object type not used by kernel */
|
|
+enum object_type {
|
|
+ OBJECT_TYPE_TLV = 0,
|
|
+ OBJECT_TYPE_MIXER,
|
|
+ OBJECT_TYPE_ENUM,
|
|
+ OBJECT_TYPE_TEXT,
|
|
+ OBJECT_TYPE_DATA,
|
|
+ OBJECT_TYPE_BYTES,
|
|
+ OBJECT_TYPE_STREAM_CONFIG,
|
|
+ OBJECT_TYPE_STREAM_CAPS,
|
|
+ OBJECT_TYPE_PCM,
|
|
+ OBJECT_TYPE_DAPM_WIDGET,
|
|
+ OBJECT_TYPE_DAPM_GRAPH,
|
|
+ OBJECT_TYPE_BE,
|
|
+ OBJECT_TYPE_CC,
|
|
+ OBJECT_TYPE_MANIFEST,
|
|
+};
|
|
+
|
|
+struct snd_tplg {
|
|
+
|
|
+ /* opaque vendor data */
|
|
+ int vendor_fd;
|
|
+ char *vendor_name;
|
|
+
|
|
+ /* out file */
|
|
+ int out_fd;
|
|
+
|
|
+ int verbose;
|
|
+ unsigned int version;
|
|
+
|
|
+ /* runtime state */
|
|
+ unsigned int next_hdr_pos;
|
|
+ int index;
|
|
+ int channel_idx;
|
|
+
|
|
+ /* manifest */
|
|
+ struct snd_soc_tplg_manifest manifest;
|
|
+
|
|
+ /* list of each element type */
|
|
+ struct list_head tlv_list;
|
|
+ struct list_head widget_list;
|
|
+ struct list_head pcm_list;
|
|
+ struct list_head be_list;
|
|
+ struct list_head cc_list;
|
|
+ struct list_head route_list;
|
|
+ struct list_head text_list;
|
|
+ struct list_head pdata_list;
|
|
+ struct list_head pcm_config_list;
|
|
+ struct list_head pcm_caps_list;
|
|
+
|
|
+ /* type-specific control lists */
|
|
+ struct list_head mixer_list;
|
|
+ struct list_head enum_list;
|
|
+ struct list_head bytes_ext_list;
|
|
+};
|
|
+
|
|
+/* object text references */
|
|
+struct tplg_ref {
|
|
+ unsigned int type;
|
|
+ struct tplg_elem *elem;
|
|
+ char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
|
+ struct list_head list;
|
|
+};
|
|
+
|
|
+/* topology element */
|
|
+struct tplg_elem {
|
|
+
|
|
+ char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
|
+
|
|
+ /* storage for texts and data if this is text or data elem*/
|
|
+ char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
|
+
|
|
+ int index;
|
|
+ enum object_type type;
|
|
+
|
|
+ int size; /* total size of this object inc pdata and ref objects */
|
|
+ int compound_elem; /* dont write this element as individual elem */
|
|
+ int vendor_type; /* vendor type for private data */
|
|
+
|
|
+ /* UAPI object for this elem */
|
|
+ union {
|
|
+ void *obj;
|
|
+ struct snd_soc_tplg_mixer_control *mixer_ctrl;
|
|
+ struct snd_soc_tplg_enum_control *enum_ctrl;
|
|
+ struct snd_soc_tplg_bytes_control *bytes_ext;
|
|
+ struct snd_soc_tplg_dapm_widget *widget;
|
|
+ struct snd_soc_tplg_pcm_dai *pcm;
|
|
+ struct snd_soc_tplg_pcm_dai *be;
|
|
+ struct snd_soc_tplg_pcm_dai *cc;
|
|
+ struct snd_soc_tplg_dapm_graph_elem *route;
|
|
+ struct snd_soc_tplg_stream_config *stream_cfg;
|
|
+ struct snd_soc_tplg_stream_caps *stream_caps;
|
|
+
|
|
+ /* these do not map to UAPI structs but are internal only */
|
|
+ struct snd_soc_tplg_ctl_tlv *tlv;
|
|
+ struct snd_soc_tplg_private *data;
|
|
+ };
|
|
+
|
|
+ /* an element may refer to other elements:
|
|
+ * a mixer control may refer to a tlv,
|
|
+ * a widget may refer to a mixer control array,
|
|
+ * a graph may refer to some widgets.
|
|
+ */
|
|
+ struct list_head ref_list;
|
|
+ struct list_head list; /* list of all elements with same type */
|
|
+};
|
|
+
|
|
+struct map_elem {
|
|
+ const char *name;
|
|
+ int id;
|
|
+};
|
|
+
|
|
+int tplg_parse_compound(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ int (*fcn)(snd_tplg_t *, snd_config_t *, void *),
|
|
+ void *private);
|
|
+
|
|
+int tplg_write_data(snd_tplg_t *tplg);
|
|
+
|
|
+int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_control_bytes(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_control_mixer(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_dapm_widget(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_pcm_config(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_pcm_caps(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
|
|
+ void *private);
|
|
+
|
|
+int tplg_parse_pcm(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_be(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_parse_cc(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
|
|
+
|
|
+int tplg_build_controls(snd_tplg_t *tplg);
|
|
+int tplg_build_widgets(snd_tplg_t *tplg);
|
|
+int tplg_build_routes(snd_tplg_t *tplg);
|
|
+int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type);
|
|
+
|
|
+int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref);
|
|
+
|
|
+int tplg_ref_add(struct tplg_elem *elem, int type, const char* id);
|
|
+
|
|
+struct tplg_elem *tplg_elem_new(void);
|
|
+void tplg_elem_free(struct tplg_elem *elem);
|
|
+void tplg_elem_free_list(struct list_head *base);
|
|
+struct tplg_elem *tplg_elem_lookup(struct list_head *base,
|
|
+ const char* id,
|
|
+ unsigned int type);
|
|
+struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
|
|
+ snd_config_t *cfg, enum object_type type);
|
|
+
|
|
+static inline void elem_copy_text(char *dest, const char *src, int len)
|
|
+{
|
|
+ strncpy(dest, src, len);
|
|
+ dest[len - 1] = 0;
|
|
+}
|
|
+
|
|
+int tplg_parse_channel(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
+ snd_config_t *cfg, void *private);
|
|
+
|
|
+int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
+ snd_config_t *cfg, void *private);
|
|
+
|
|
+struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base,
|
|
+ const char* id);
|
|
--
|
|
2.5.0
|
|
|