+---
+ 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)
++ *
++ * Topology File Format
++ *
++ * 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.
++ *
++ *
++ * Controls
++ * 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.
++ *
++ * Control Operations
++ * 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.
++ *
++ *
++ *
++ * ops."ctl" {
++ * info "volsw"
++ * get "257"
++ * put "257"
++ * }
++ *
++ *
++ *
++ * This mapping shows info() using the standard "volsw" info callback whilst
++ * the get() and put() are mapped to bespoke driver callbacks.
++ *
++ * The Standard operations names for control get(), put() and info calls
++ * are :-
++ * * volsw
++ * * volsw_sx
++ * * volsw_xr_sx
++ * * enum
++ * * bytes
++ * * enum_value
++ * * range
++ * * strobe
++ *
++ * Control TLV Data
++ * 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 :-
++ *
++ *
++ * scale {
++ * min "-9000"
++ * step "300"
++ * mute "1"
++ * }
++ *
++ *
++ * Where the meanings and values for min, step and mute are exactly the same
++ * as defined in driver code.
++ *
++ * Control Channel Mapping
++ * 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 :-
++ *
++ *
++ * channel."name" {
++ * reg "0"
++ * shift "0"
++ * }
++ *
++ *
++ * 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 :-
++ *
++ *
++ * * 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
++ *
++ *
++ * Control Private Data
++ * 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 :-
++ *
++ *
++ * SectionData."pdata for EQU1" {
++ * file "/path/to/file"
++ * bytes "0x12,0x34,0x56,0x78"
++ * shorts "0x1122,0x3344,0x5566,0x7788"
++ * words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
++ * };
++ *
++ * 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.
++ *
++ * Mixer Controls
++ * 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 :-
++ *
++ *
++ * 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
++ * }
++ *
++ *
++ * 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.
++ *
++ * Byte Controls
++ * 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 :-
++ *
++ *
++ * 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
++ * }
++ *
++ *
++ * Enumerated Controls
++ * 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.
++ *
++ * The text strings for the enumerated controls are defined in a seperate
++ * section as follows :-
++ *
++ *
++ * SectionText."name" {
++ *
++ * Values [
++ * "value1"
++ * "value2"
++ "value3"
++ * ]
++ * }
++ *
++ *
++ * All the enumerated text values are listed in the values list.
++ * The enumerated control is similar to the other controls and defined as
++ * follows :-
++ *
++ *
++ * 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
++ * }
++ *
++ *
++ * DAPM Graph
++ * DAPM graphs can easily be defined using the topology file. The format is
++ * very similar to the DAPM graph kernel format. :-
++ *
++ *
++ * SectionGraph."dsp" {
++ * index "1" # Index number
++ *
++ * lines [
++ * "sink1, control, source1"
++ * "sink2, , source2"
++ * ]
++ * }
++ *
++ *
++ * 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.
++ *
++ * DAPM Widgets
++ * 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 :-
++ *
++ *
++ * 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
++ * }
++ *
++ *
++ * 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.
++ *
++ * PCM Capabilities
++ * Topology can also define the capabilities of FE and BE PCMs. Capabilities
++ * can be defined with the following section :-
++ *
++ *
++ * 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
++ * }
++ *
++ * 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.
++ *
++ * PCM Configurations
++ * PCM runtime configurations can be defined for playback and capture stream
++ * directions with the following section :-
++ *
++ *
++ * 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
++ * }
++ * }
++ *
++ *
++ * 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.
++ *
++ * PCM Configurations
++ * 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 :-
++ *
++ *
++ * SectionPCM."name" {
++ * ....
++ * }
++ * SectionBE."name" {
++ * ....
++ * }
++ * SectionCC."name" {
++ * ....
++ * }
++ *
++ *
++ * The section types above should be used for PCMs, Back Ends and Codec to Codec
++ * links respectively.
++ *
++ * The data for each section is defined as follows :-
++ *
++ *
++ * 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"
++ * ]
++ * }
++ * }
++ *
++ *
++ */
++
++/** 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
++ Yao Jin
++ Liam Girdwood
++*/
++
++#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
++ Yao Jin
++ Liam Girdwood
++*/
++
++#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
++#include
++#include
++
++#include "local.h"
++#include "list.h"
++#include "topology.h"
++
++#include
++#include
++#include
++
++#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
+
diff --git a/0037-topology-Add-text-section-parser.patch b/0037-topology-Add-text-section-parser.patch
new file mode 100644
index 0000000..5b4a39f
--- /dev/null
+++ b/0037-topology-Add-text-section-parser.patch
@@ -0,0 +1,112 @@
+From 408396a8ca092846c840baa79c04b5f7dbe5da69 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:15 +0100
+Subject: [PATCH 37/49] topology: Add text section parser.
+
+Parse text lists (like enum values) and store for later attachment
+to other objects.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/text.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 88 insertions(+)
+ create mode 100644 src/topology/text.c
+
+diff --git a/src/topology/text.c b/src/topology/text.c
+new file mode 100644
+index 000000000000..ebb6e3840d62
+--- /dev/null
++++ b/src/topology/text.c
+@@ -0,0 +1,88 @@
++/*
++ 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"
++
++#define TEXT_SIZE_MAX \
++ (SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
++
++static int parse_text_values(snd_config_t *cfg, struct tplg_elem *elem)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *value = NULL;
++ int j = 0;
++
++ tplg_dbg(" Text Values: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++
++ if (j == SND_SOC_TPLG_NUM_TEXTS) {
++ tplg_dbg("error: text string number exceeds %d\n", j);
++ return -ENOMEM;
++ }
++
++ /* get value */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ elem_copy_text(&elem->texts[j][0], value,
++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++ tplg_dbg("\t%s\n", &elem->texts[j][0]);
++
++ j++;
++ }
++
++ return 0;
++}
++
++/* Parse Text data */
++int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private ATTRIBUTE_UNUSED)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id;
++ int err = 0;
++ struct tplg_elem *elem;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_TEXT);
++ if (!elem)
++ return -ENOMEM;
++
++ 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, "values") == 0) {
++ err = parse_text_values(n, elem);
++ if (err < 0) {
++ SNDERR("error: failed to parse text values");
++ return err;
++ }
++ continue;
++ }
++ }
++
++ return err;
++}
+--
+2.5.0
+
diff --git a/0038-topology-Add-PCM-parser.patch b/0038-topology-Add-PCM-parser.patch
new file mode 100644
index 0000000..1a3c518
--- /dev/null
+++ b/0038-topology-Add-PCM-parser.patch
@@ -0,0 +1,664 @@
+From 4db19506c3e7a68a0d0be40422172f22605c58d8 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:16 +0100
+Subject: [PATCH 38/49] topology: Add PCM parser.
+
+Parse PCM configurations and capabilities. These can then be used to define
+the capabilities and config for FE DAI links, PCM devices and
+codec <-> codec style links.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/pcm.c | 639 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 639 insertions(+)
+ create mode 100644 src/topology/pcm.c
+
+diff --git a/src/topology/pcm.c b/src/topology/pcm.c
+new file mode 100644
+index 000000000000..8f23a6f12ec4
+--- /dev/null
++++ b/src/topology/pcm.c
+@@ -0,0 +1,639 @@
++/*
++ 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"
++
++struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
++{
++ struct list_head *pos;
++ struct tplg_elem *elem;
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ if (elem->type != OBJECT_TYPE_PCM)
++ return NULL;
++
++ pcm_dai = elem->pcm;
++
++ if (pcm_dai && (!strcmp(pcm_dai->capconf[0].caps.name, id)
++ || !strcmp(pcm_dai->capconf[1].caps.name, id)))
++ return elem;
++ }
++
++ return NULL;
++}
++
++/* copy referenced caps to the pcm */
++static void copy_pcm_caps(const char *id, struct snd_soc_tplg_stream_caps *caps,
++ struct tplg_elem *ref_elem)
++{
++ struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
++
++ tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s' \n",
++ sizeof(*caps), ref_elem->id, id);
++
++ *caps = *ref_caps;
++}
++
++/* copy referenced config to the pcm */
++static void copy_pcm_config(const char *id,
++ struct snd_soc_tplg_stream_config *cfg, struct tplg_elem *ref_elem)
++{
++ struct snd_soc_tplg_stream_config *ref_cfg = ref_elem->stream_cfg;
++
++ tplg_dbg("Copy pcm config (%ld bytes) from '%s' to '%s' \n",
++ sizeof(*cfg), ref_elem->id, id);
++
++ *cfg = *ref_cfg;
++}
++
++/* check referenced config and caps for a pcm */
++static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem)
++{
++ struct tplg_elem *ref_elem = NULL;
++ struct snd_soc_tplg_pcm_cfg_caps *capconf;
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++ unsigned int i, j;
++
++ switch (elem->type) {
++ case OBJECT_TYPE_PCM:
++ pcm_dai = elem->pcm;
++ break;
++ case OBJECT_TYPE_BE:
++ pcm_dai = elem->be;
++ break;
++ case OBJECT_TYPE_CC:
++ pcm_dai = elem->cc;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ for (i = 0; i < 2; i++) {
++ capconf = &pcm_dai->capconf[i];
++
++ ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
++ capconf->caps.name, OBJECT_TYPE_STREAM_CAPS);
++
++ if (ref_elem != NULL)
++ copy_pcm_caps(elem->id, &capconf->caps, ref_elem);
++
++ for (j = 0; j < capconf->num_configs; j++) {
++ ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
++ capconf->configs[j].name,
++ OBJECT_TYPE_STREAM_CONFIG);
++
++ if (ref_elem != NULL)
++ copy_pcm_config(elem->id,
++ &capconf->configs[j],
++ ref_elem);
++ }
++ }
++
++ return 0;
++}
++
++int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type)
++{
++ struct list_head *base, *pos;
++ struct tplg_elem *elem;
++ int err = 0;
++
++ switch (type) {
++ case OBJECT_TYPE_PCM:
++ base = &tplg->pcm_list;
++ break;
++ case OBJECT_TYPE_BE:
++ base = &tplg->be_list;
++ break;
++ case OBJECT_TYPE_CC:
++ base = &tplg->cc_list;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ if (elem->type != type) {
++ SNDERR("error: invalid elem '%s'\n", elem->id);
++ return -EINVAL;
++ }
++
++ err = tplg_build_pcm_cfg_caps(tplg, elem);
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
++/* PCM stream configuration */
++static int tplg_parse_stream_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
++ snd_config_t *cfg, void *private)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct snd_soc_tplg_stream_config *sc = private;
++ struct snd_soc_tplg_stream *stream;
++ const char *id, *val;
++ snd_pcm_format_t format;
++ int ret;
++
++ snd_config_get_id(cfg, &id);
++
++ if (strcmp(id, "playback") == 0)
++ stream = &sc->playback;
++ else if (strcmp(id, "capture") == 0)
++ stream = &sc->capture;
++ else
++ return -EINVAL;
++
++ tplg_dbg("\t%s:\n", id);
++
++ stream->size = sizeof(*stream);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++
++ if (snd_config_get_id(n, &id) < 0)
++ return -EINVAL;
++
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ if (strcmp(id, "format") == 0) {
++ format = snd_pcm_format_value(val);
++ if (format == SND_PCM_FORMAT_UNKNOWN) {
++ SNDERR("error: unsupported stream format %s\n",
++ val);
++ return -EINVAL;
++ }
++
++ stream->format = format;
++ tplg_dbg("\t\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "rate") == 0) {
++ stream->rate = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, stream->rate);
++ continue;
++ }
++
++ if (strcmp(id, "channels") == 0) {
++ stream->channels = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, stream->channels);
++ continue;
++ }
++
++ if (strcmp(id, "tdm_slot") == 0) {
++ stream->tdm_slot = strtol(val, NULL, 16);
++ tplg_dbg("\t\t%s: 0x%x\n", id, stream->tdm_slot);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse pcm configuration */
++int tplg_parse_pcm_config(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_stream_config *sc;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_STREAM_CONFIG);
++ if (!elem)
++ return -ENOMEM;
++
++ sc = elem->stream_cfg;
++ sc->size = elem->size;
++
++ tplg_dbg(" PCM Config: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "config") == 0) {
++ err = tplg_parse_compound(tplg, n,
++ tplg_parse_stream_cfg, sc);
++ if (err < 0)
++ return err;
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
++{
++ char *s = NULL;
++ snd_pcm_format_t format;
++ int i = 0, ret;
++
++ s = strtok(str, ",");
++ while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) {
++ format = snd_pcm_format_value(s);
++ if (format == SND_PCM_FORMAT_UNKNOWN) {
++ SNDERR("error: unsupported stream format %s\n", s);
++ return -EINVAL;
++ }
++
++ caps->formats[i] = format;
++ s = strtok(NULL, ", ");
++ i++;
++ }
++
++ return 0;
++}
++
++/* Parse pcm Capabilities */
++int tplg_parse_pcm_caps(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_stream_caps *sc;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val;
++ char *s;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_STREAM_CAPS);
++ if (!elem)
++ return -ENOMEM;
++
++ sc = elem->stream_caps;
++ sc->size = elem->size;
++ elem_copy_text(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++
++ tplg_dbg(" PCM Capabilities: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ if (strcmp(id, "formats") == 0) {
++ s = strdup(val);
++ if (s == NULL)
++ return -ENOMEM;
++
++ err = split_format(sc, s);
++ free(s);
++
++ if (err < 0)
++ return err;
++
++ tplg_dbg("\t\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "rate_min") == 0) {
++ sc->rate_min = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, sc->rate_min);
++ continue;
++ }
++
++ if (strcmp(id, "rate_max") == 0) {
++ sc->rate_max = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, sc->rate_max);
++ continue;
++ }
++
++ if (strcmp(id, "channels_min") == 0) {
++ sc->channels_min = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, sc->channels_min);
++ continue;
++ }
++
++ if (strcmp(id, "channels_max") == 0) {
++ sc->channels_max = atoi(val);
++ tplg_dbg("\t\t%s: %d\n", id, sc->channels_max);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++static int tplg_parse_pcm_cfg(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
++ snd_config_t *cfg, void *private)
++{
++ struct snd_soc_tplg_pcm_cfg_caps *capconf = private;
++ struct snd_soc_tplg_stream_config *configs = capconf->configs;
++ unsigned int *num_configs = &capconf->num_configs;
++ const char *value;
++
++ if (*num_configs == SND_SOC_TPLG_STREAM_CONFIG_MAX)
++ return -EINVAL;
++
++ if (snd_config_get_string(cfg, &value) < 0)
++ return EINVAL;
++
++ elem_copy_text(configs[*num_configs].name, value,
++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++
++ *num_configs += 1;
++
++ tplg_dbg("\t\t\t%s\n", value);
++
++ return 0;
++}
++
++/* Parse the cap and config of a pcm */
++int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct tplg_elem *elem = private;
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++ const char *id, *value;
++ int err, stream;
++
++ if (elem->type == OBJECT_TYPE_PCM)
++ pcm_dai = elem->pcm;
++ else if (elem->type == OBJECT_TYPE_BE)
++ pcm_dai = elem->be;
++ else if (elem->type == OBJECT_TYPE_CC)
++ pcm_dai = elem->cc;
++ else
++ return -EINVAL;
++
++ snd_config_get_id(cfg, &id);
++
++ tplg_dbg("\t%s:\n", id);
++
++ if (strcmp(id, "playback") == 0) {
++ stream = SND_SOC_TPLG_STREAM_PLAYBACK;
++ pcm_dai->playback = 1;
++ } else if (strcmp(id, "capture") == 0) {
++ stream = SND_SOC_TPLG_STREAM_CAPTURE;
++ pcm_dai->capture = 1;
++ } else
++ return -EINVAL;
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++
++ /* get id */
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ if (strcmp(id, "capabilities") == 0) {
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ elem_copy_text(pcm_dai->capconf[stream].caps.name, value,
++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++
++ tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value);
++ continue;
++ }
++
++ if (strcmp(id, "configs") == 0) {
++ tplg_dbg("\t\tconfigs:\n");
++ err = tplg_parse_compound(tplg, n, tplg_parse_pcm_cfg,
++ &pcm_dai->capconf[stream]);
++ if (err < 0)
++ return err;
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse pcm */
++int tplg_parse_pcm(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_PCM);
++ if (!elem)
++ return -ENOMEM;
++
++ pcm_dai = elem->pcm;
++ pcm_dai->size = elem->size;
++ elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++
++ tplg_dbg(" PCM: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "id") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ pcm_dai->id = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
++ continue;
++ }
++
++ if (strcmp(id, "pcm") == 0) {
++ err = tplg_parse_compound(tplg, n,
++ tplg_parse_pcm_cap_cfg, elem);
++ if (err < 0)
++ return err;
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse be */
++int tplg_parse_be(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_BE);
++ if (!elem)
++ return -ENOMEM;
++
++ pcm_dai = elem->be;
++ pcm_dai->size = elem->size;
++ elem_copy_text(pcm_dai->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++
++ tplg_dbg(" BE: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "id") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ pcm_dai->id = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
++ continue;
++ }
++
++ if (strcmp(id, "be") == 0) {
++ err = tplg_parse_compound(tplg, n,
++ tplg_parse_pcm_cap_cfg, elem);
++ if (err < 0)
++ return err;
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse cc */
++int tplg_parse_cc(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_pcm_dai *pcm_dai;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_CC);
++ if (!elem)
++ return -ENOMEM;
++
++ pcm_dai = elem->cc;
++ pcm_dai->size = elem->size;
++
++ tplg_dbg(" CC: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "id") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ pcm_dai->id = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, pcm_dai->id);
++ continue;
++ }
++
++ if (strcmp(id, "cc") == 0) {
++ err = tplg_parse_compound(tplg, n,
++ tplg_parse_pcm_cap_cfg, elem);
++ if (err < 0)
++ return err;
++ continue;
++ }
++ }
++
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0039-topology-Add-operations-parser.patch b/0039-topology-Add-operations-parser.patch
new file mode 100644
index 0000000..4eb238b
--- /dev/null
+++ b/0039-topology-Add-operations-parser.patch
@@ -0,0 +1,107 @@
+From 353f1eddb608a837157342155fc061f85bf0a5f8 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:17 +0100
+Subject: [PATCH 39/49] topology: Add operations parser
+
+Parse operations so we can bind them to kcontrols in the kernel.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/ops.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 84 insertions(+)
+ create mode 100644 src/topology/ops.c
+
+diff --git a/src/topology/ops.c b/src/topology/ops.c
+new file mode 100644
+index 000000000000..243d8c5e2bbc
+--- /dev/null
++++ b/src/topology/ops.c
+@@ -0,0 +1,84 @@
++/*
++ 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"
++
++/* mapping of kcontrol text names to types */
++static const struct map_elem control_map[] = {
++ {"volsw", SND_SOC_TPLG_CTL_VOLSW},
++ {"volsw_sx", SND_SOC_TPLG_CTL_VOLSW_SX},
++ {"volsw_xr_sx", SND_SOC_TPLG_CTL_VOLSW_XR_SX},
++ {"enum", SND_SOC_TPLG_CTL_ENUM},
++ {"bytes", SND_SOC_TPLG_CTL_BYTES},
++ {"enum_value", SND_SOC_TPLG_CTL_ENUM_VALUE},
++ {"range", SND_SOC_TPLG_CTL_RANGE},
++ {"strobe", SND_SOC_TPLG_CTL_STROBE},
++};
++
++static int lookup_ops(const char *c)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(control_map); i++) {
++ if (strcmp(control_map[i].name, c) == 0)
++ return control_map[i].id;
++ }
++
++ /* cant find string name in our table so we use its ID number */
++ return atoi(c);
++}
++
++/* Parse Control operations. Ops can come from standard names above or
++ * bespoke driver controls with numbers >= 256
++ */
++int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
++ snd_config_t *cfg, void *private)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct snd_soc_tplg_ctl_hdr *hdr = private;
++ const char *id, *value;
++
++ tplg_dbg("\tOps\n");
++ hdr->size = sizeof(*hdr);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++
++ /* get id */
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* get value - try strings then ints */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ if (strcmp(id, "info") == 0)
++ hdr->ops.info = lookup_ops(value);
++ else if (strcmp(id, "put") == 0)
++ hdr->ops.put = lookup_ops(value);
++ else if (strcmp(id, "get") == 0)
++ hdr->ops.get = lookup_ops(value);
++
++ tplg_dbg("\t\t%s = %s\n", id, value);
++ }
++
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0040-topology-Add-private-data-parser.patch b/0040-topology-Add-private-data-parser.patch
new file mode 100644
index 0000000..a4098c5
--- /dev/null
+++ b/0040-topology-Add-private-data-parser.patch
@@ -0,0 +1,420 @@
+From 5b379da2a0a1084349e918a52f471c03e37af703 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:18 +0100
+Subject: [PATCH 40/49] topology: Add private data parser
+
+Parse private data and store for attachment to other objects. Data can come
+file or be locally defined as bytes, shorts or words.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/data.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 396 insertions(+)
+ create mode 100644 src/topology/data.c
+
+diff --git a/src/topology/data.c b/src/topology/data.c
+new file mode 100644
+index 000000000000..ae664721935d
+--- /dev/null
++++ b/src/topology/data.c
+@@ -0,0 +1,396 @@
++/*
++ 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"
++
++/* Get Private data from a file. */
++static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
++{
++ struct snd_soc_tplg_private *priv = NULL;
++ const char *value = NULL;
++ char filename[MAX_FILE];
++ char *env = getenv(ALSA_CONFIG_TPLG_VAR);
++ FILE *fp;
++ size_t size, bytes_read;
++ int ret = 0;
++
++ tplg_dbg("data DataFile: %s\n", elem->id);
++
++ if (snd_config_get_string(cfg, &value) < 0)
++ return -EINVAL;
++
++ /* prepend alsa config directory to path */
++ snprintf(filename, sizeof(filename), "%s/%s",
++ env ? env : ALSA_TPLG_DIR, value);
++
++ fp = fopen(filename, "r");
++ if (fp == NULL) {
++ SNDERR("error: invalid data file path '%s'\n",
++ filename);
++ ret = -errno;
++ goto err;
++ }
++
++ fseek(fp, 0L, SEEK_END);
++ size = ftell(fp);
++ fseek(fp, 0L, SEEK_SET);
++ if (size <= 0) {
++ SNDERR("error: invalid data file size %zu\n", size);
++ ret = -EINVAL;
++ goto err;
++ }
++ if (size > TPLG_MAX_PRIV_SIZE) {
++ SNDERR("error: data file too big %zu\n", size);
++ ret = -EINVAL;
++ goto err;
++ }
++
++ priv = calloc(1, sizeof(*priv) + size);
++ if (!priv) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ bytes_read = fread(&priv->data, 1, size, fp);
++ if (bytes_read != size) {
++ ret = -errno;
++ goto err;
++ }
++
++ elem->data = priv;
++ priv->size = size;
++ elem->size = sizeof(*priv) + size;
++ return 0;
++
++err:
++ if (priv)
++ free(priv);
++ return ret;
++}
++
++static void dump_priv_data(struct tplg_elem *elem)
++{
++ struct snd_soc_tplg_private *priv = elem->data;
++ unsigned char *p = (unsigned char *)priv->data;
++ unsigned int i, j = 0;
++
++ tplg_dbg(" elem size = %d, priv data size = %d\n",
++ elem->size, priv->size);
++
++ for (i = 0; i < priv->size; i++) {
++ if (j++ % 8 == 0)
++ tplg_dbg("\n");
++
++ tplg_dbg(" 0x%x", *p++);
++ }
++
++ tplg_dbg("\n\n");
++}
++
++/* get number of hex value elements in CSV list */
++static int get_hex_num(const char *str)
++{
++ int commas = 0, values = 0, len = strlen(str);
++ const char *end = str + len;
++
++ /* we expect "0x0, 0x0, 0x0" */
++ while (str < end) {
++
++ /* skip white space */
++ if (isspace(*str)) {
++ str++;
++ continue;
++ }
++
++ /* find delimeters */
++ if (*str == ',') {
++ commas++;
++ str++;
++ continue;
++ }
++
++ /* find 0x[0-9] values */
++ if (*str == '0' && str + 2 <= end) {
++ if (str[1] == 'x' && str[2] >= '0' && str[2] <= 'f') {
++ values++;
++ str += 3;
++ } else {
++ str++;
++ }
++ }
++
++ str++;
++ }
++
++ /* there should always be one less comma than value */
++ if (values -1 != commas)
++ return -EINVAL;
++
++ return values;
++}
++
++static int write_hex(char *buf, char *str, int width)
++{
++ long val;
++ void *p = &val;
++
++ errno = 0;
++ val = strtol(str, NULL, 16);
++
++ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
++ || (errno != 0 && val == 0)) {
++ return -EINVAL;
++ }
++
++ switch (width) {
++ case 1:
++ *(unsigned char *)buf = *(unsigned char *)p;
++ break;
++ case 2:
++ *(unsigned short *)buf = *(unsigned short *)p;
++ break;
++ case 4:
++ *(unsigned int *)buf = *(unsigned int *)p;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int copy_data_hex(char *data, int off, const char *str, int width)
++{
++ char *tmp, *s = NULL, *p = data;
++ int ret;
++
++ tmp = strdup(str);
++ if (tmp == NULL)
++ return -ENOMEM;
++
++ p += off;
++ s = strtok(tmp, ",");
++
++ while (s != NULL) {
++ ret = write_hex(p, s, width);
++ if (ret < 0) {
++ free(tmp);
++ return ret;
++ }
++
++ s = strtok(NULL, ",");
++ p += width;
++ }
++
++ free(tmp);
++ return 0;
++}
++
++static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
++ int width)
++{
++ struct snd_soc_tplg_private *priv;
++ const char *value = NULL;
++ int size, esize, off, num;
++ int ret;
++
++ tplg_dbg(" data: %s\n", elem->id);
++
++ if (snd_config_get_string(cfg, &value) < 0)
++ return -EINVAL;
++
++ num = get_hex_num(value);
++ if (num <= 0) {
++ SNDERR("error: malformed hex variable list %s\n", value);
++ return -EINVAL;
++ }
++
++ size = num * width;
++ priv = elem->data;
++
++ if (esize > TPLG_MAX_PRIV_SIZE) {
++ SNDERR("error: data too big %d\n", esize);
++ return -EINVAL;
++ }
++
++ if (priv != NULL) {
++ off = priv->size;
++ esize = elem->size + size;
++ priv = realloc(priv, esize);
++ } else {
++ off = 0;
++ esize = sizeof(*priv) + size;
++ priv = calloc(1, esize);
++ }
++
++ if (!priv)
++ return -ENOMEM;
++
++ elem->data = priv;
++ priv->size += size;
++ elem->size = esize;
++
++ ret = copy_data_hex(priv->data, off, value, width);
++
++ dump_priv_data(elem);
++ return ret;
++}
++
++
++/* Parse Private data.
++ *
++ * Object private data can either be from file or defined as bytes, shorts,
++ * words.
++ */
++int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private ATTRIBUTE_UNUSED)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err = 0;
++ struct tplg_elem *elem;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DATA);
++ if (!elem)
++ return -ENOMEM;
++
++ 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, "file") == 0) {
++ err = tplg_parse_data_file(n, elem);
++ if (err < 0) {
++ SNDERR("error: failed to parse data file\n");
++ return err;
++ }
++ continue;
++ }
++
++ if (strcmp(id, "bytes") == 0) {
++ err = tplg_parse_data_hex(n, elem, 1);
++ if (err < 0) {
++ SNDERR("error: failed to parse data bytes\n");
++ return err;
++ }
++ continue;
++ }
++
++ if (strcmp(id, "shorts") == 0) {
++ err = tplg_parse_data_hex(n, elem, 2);
++ if (err < 0) {
++ SNDERR("error: failed to parse data shorts\n");
++ return err;
++ }
++ continue;
++ }
++
++ if (strcmp(id, "words") == 0) {
++ err = tplg_parse_data_hex(n, elem, 4);
++ if (err < 0) {
++ SNDERR("error: failed to parse data words\n");
++ return err;
++ }
++ continue;
++ }
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "type") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->vendor_type = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++ }
++
++ return err;
++}
++
++/* copy private data into the bytes extended control */
++int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
++{
++ struct snd_soc_tplg_private *priv;
++ int priv_data_size;
++
++ if (!ref)
++ return -EINVAL;
++
++ tplg_dbg("Data '%s' used by '%s'\n", ref->id, elem->id);
++ priv_data_size = ref->data->size;
++
++ switch (elem->type) {
++ case OBJECT_TYPE_MIXER:
++ elem->mixer_ctrl = realloc(elem->mixer_ctrl,
++ elem->size + priv_data_size);
++ if (!elem->mixer_ctrl)
++ return -ENOMEM;
++ priv = &elem->mixer_ctrl->priv;
++ break;
++
++ case OBJECT_TYPE_ENUM:
++ elem->enum_ctrl = realloc(elem->enum_ctrl,
++ elem->size + priv_data_size);
++ if (!elem->enum_ctrl)
++ return -ENOMEM;
++ priv = &elem->enum_ctrl->priv;
++ break;
++
++ case OBJECT_TYPE_BYTES:
++ elem->bytes_ext = realloc(elem->bytes_ext,
++ elem->size + priv_data_size);
++ if (!elem->bytes_ext)
++ return -ENOMEM;
++ priv = &elem->bytes_ext->priv;
++ break;
++
++
++ case OBJECT_TYPE_DAPM_WIDGET:
++ elem->widget = realloc(elem->widget,
++ elem->size + priv_data_size);
++ if (!elem->widget)
++ return -ENOMEM;
++ priv = &elem->widget->priv;
++ break;
++
++ default:
++ SNDERR("elem '%s': type %d private data not supported \n",
++ elem->id, elem->type);
++ return -EINVAL;
++ }
++
++ elem->size += priv_data_size;
++ priv->size = priv_data_size;
++ ref->compound_elem = 1;
++ memcpy(priv->data, ref->data->data, priv_data_size);
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0041-topology-Add-DAPM-object-parser.patch b/0041-topology-Add-DAPM-object-parser.patch
new file mode 100644
index 0000000..da57cb7
--- /dev/null
+++ b/0041-topology-Add-DAPM-object-parser.patch
@@ -0,0 +1,585 @@
+From 01a0e1a1c2196967d2522092ca993098a7c66613 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:19 +0100
+Subject: [PATCH 41/49] topology: Add DAPM object parser
+
+Parse DAPM objects including widgets and graph elements.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/dapm.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 562 insertions(+)
+ create mode 100644 src/topology/dapm.c
+
+diff --git a/src/topology/dapm.c b/src/topology/dapm.c
+new file mode 100644
+index 000000000000..1da82adea470
+--- /dev/null
++++ b/src/topology/dapm.c
+@@ -0,0 +1,562 @@
++/*
++ 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"
++
++/* mapping of widget text names to types */
++static const struct map_elem widget_map[] = {
++ {"input", SND_SOC_TPLG_DAPM_INPUT},
++ {"output", SND_SOC_TPLG_DAPM_OUTPUT},
++ {"mux", SND_SOC_TPLG_DAPM_MUX},
++ {"mixer", SND_SOC_TPLG_DAPM_MIXER},
++ {"pga", SND_SOC_TPLG_DAPM_PGA},
++ {"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV},
++ {"adc", SND_SOC_TPLG_DAPM_ADC},
++ {"dac", SND_SOC_TPLG_DAPM_DAC},
++ {"switch", SND_SOC_TPLG_DAPM_SWITCH},
++ {"pre", SND_SOC_TPLG_DAPM_PRE},
++ {"post", SND_SOC_TPLG_DAPM_POST},
++ {"aif_in", SND_SOC_TPLG_DAPM_AIF_IN},
++ {"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT},
++ {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN},
++ {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT},
++ {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK},
++};
++
++/* mapping of widget kcontrol text names to types */
++static const struct map_elem widget_control_map[] = {
++ {"volsw", SND_SOC_TPLG_DAPM_CTL_VOLSW},
++ {"enum_double", SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE},
++ {"enum_virt", SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT},
++ {"enum_value", SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE},
++};
++
++static int lookup_widget(const char *w)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
++ if (strcmp(widget_map[i].name, w) == 0)
++ return widget_map[i].id;
++ }
++
++ return -EINVAL;
++}
++
++static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *value = NULL;
++
++ tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++
++ /* get value */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ tplg_ref_add(elem, OBJECT_TYPE_MIXER, value);
++ tplg_dbg("\t\t %s\n", value);
++ }
++
++ return 0;
++}
++
++static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *value = NULL;
++
++ tplg_dbg(" DAPM Enum Controls: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++
++ /* get value */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ tplg_ref_add(elem, OBJECT_TYPE_ENUM, value);
++ tplg_dbg("\t\t %s\n", value);
++ }
++
++ return 0;
++}
++
++/* move referenced controls to the widget */
++static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref)
++{
++ struct snd_soc_tplg_dapm_widget *widget = elem->widget;
++ struct snd_soc_tplg_mixer_control *mixer_ctrl = ref->mixer_ctrl;
++ struct snd_soc_tplg_enum_control *enum_ctrl = ref->enum_ctrl;
++
++ tplg_dbg("Control '%s' used by '%s'\n", ref->id, elem->id);
++ tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d\n",
++ elem->size, ref->size, elem->size + ref->size,
++ widget->priv.size);
++
++ widget = realloc(widget, elem->size + ref->size);
++ if (!widget)
++ return -ENOMEM;
++
++ elem->widget = widget;
++
++ /* copy new widget at the end */
++ if (ref->type == OBJECT_TYPE_MIXER)
++ memcpy((void*)widget + elem->size, mixer_ctrl, ref->size);
++ else if (ref->type == OBJECT_TYPE_ENUM)
++ memcpy((void*)widget + elem->size, enum_ctrl, ref->size);
++
++ elem->size += ref->size;
++ widget->num_kcontrols++;
++ ref->compound_elem = 1;
++ return 0;
++}
++
++/* check referenced controls for a widget */
++static int tplg_build_widget(snd_tplg_t *tplg,
++ struct tplg_elem *elem)
++{
++ struct tplg_ref *ref;
++ struct list_head *base, *pos;
++ int err = 0;
++
++ base = &elem->ref_list;
++
++ /* for each ref in this control elem */
++ list_for_each(pos, base) {
++
++ ref = list_entry(pos, struct tplg_ref, list);
++ if (ref->id == NULL || ref->elem)
++ continue;
++
++ switch (ref->type) {
++ case OBJECT_TYPE_MIXER:
++ ref->elem = tplg_elem_lookup(&tplg->mixer_list,
++ ref->id, OBJECT_TYPE_MIXER);
++ if (ref->elem)
++ err = copy_dapm_control(elem, ref->elem);
++ break;
++
++ case OBJECT_TYPE_ENUM:
++ ref->elem = tplg_elem_lookup(&tplg->enum_list,
++ ref->id, OBJECT_TYPE_ENUM);
++ if (ref->elem)
++ err = copy_dapm_control(elem, ref->elem);
++ break;
++
++ case OBJECT_TYPE_DATA:
++ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
++ ref->id, OBJECT_TYPE_DATA);
++ if (ref->elem)
++ err = tplg_copy_data(elem, ref->elem);
++ break;
++ default:
++ break;
++ }
++
++ if (!ref->elem) {
++ SNDERR("error: cannot find control '%s'"
++ " referenced by widget '%s'\n",
++ ref->id, elem->id);
++ return -EINVAL;
++ }
++
++ if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
++int tplg_build_widgets(snd_tplg_t *tplg)
++{
++
++ struct list_head *base, *pos;
++ struct tplg_elem *elem;
++ int err;
++
++ base = &tplg->widget_list;
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ if (!elem->widget || elem->type != OBJECT_TYPE_DAPM_WIDGET) {
++ SNDERR("error: invalid widget '%s'\n",
++ elem->id);
++ return -EINVAL;
++ }
++
++ err = tplg_build_widget(tplg, elem);
++ if (err < 0)
++ return err;
++
++ /* add widget to manifest */
++ tplg->manifest.widget_elems++;
++ }
++
++ return 0;
++}
++
++int tplg_build_routes(snd_tplg_t *tplg)
++{
++ struct list_head *base, *pos;
++ struct tplg_elem *elem;
++ struct snd_soc_tplg_dapm_graph_elem *route;
++
++ base = &tplg->route_list;
++
++ list_for_each(pos, base) {
++ elem = list_entry(pos, struct tplg_elem, list);
++
++ if (!elem->route || elem->type != OBJECT_TYPE_DAPM_GRAPH) {
++ SNDERR("error: invalid route '%s'\n",
++ elem->id);
++ return -EINVAL;
++ }
++
++ route = elem->route;
++ tplg_dbg("\nCheck route: sink '%s', control '%s', source '%s'\n",
++ route->sink, route->control, route->source);
++
++ /* validate sink */
++ if (strlen(route->sink) <= 0) {
++ SNDERR("error: no sink\n");
++ return -EINVAL;
++
++ }
++ if (!tplg_elem_lookup(&tplg->widget_list, route->sink,
++ OBJECT_TYPE_DAPM_WIDGET)) {
++ SNDERR("warning: undefined sink widget/stream '%s'\n",
++ route->sink);
++ }
++
++ /* validate control name */
++ if (strlen(route->control)) {
++ if (!tplg_elem_lookup(&tplg->mixer_list,
++ route->control, OBJECT_TYPE_MIXER) &&
++ !tplg_elem_lookup(&tplg->enum_list,
++ route->control, OBJECT_TYPE_ENUM)) {
++ SNDERR("warning: Undefined mixer/enum control '%s'\n",
++ route->control);
++ }
++ }
++
++ /* validate source */
++ if (strlen(route->source) <= 0) {
++ SNDERR("error: no source\n");
++ return -EINVAL;
++
++ }
++ if (!tplg_elem_lookup(&tplg->widget_list, route->source,
++ OBJECT_TYPE_DAPM_WIDGET)) {
++ SNDERR("warning: Undefined source widget/stream '%s'\n",
++ route->source);
++ }
++
++ /* add graph to manifest */
++ tplg->manifest.graph_elems++;
++ }
++
++ return 0;
++}
++
++#define LINE_SIZE 1024
++
++/* line is defined as '"source, control, sink"' */
++static int tplg_parse_line(const char *text,
++ struct snd_soc_tplg_dapm_graph_elem *line)
++{
++ char buf[LINE_SIZE];
++ unsigned int len, i;
++ const char *source = NULL, *sink = NULL, *control = NULL;
++
++ elem_copy_text(buf, text, LINE_SIZE);
++
++ len = strlen(buf);
++ if (len <= 2) {
++ SNDERR("error: invalid route \"%s\"\n", buf);
++ return -EINVAL;
++ }
++
++ /* find first , */
++ for (i = 1; i < len; i++) {
++ if (buf[i] == ',')
++ goto second;
++ }
++ SNDERR("error: invalid route \"%s\"\n", buf);
++ return -EINVAL;
++
++second:
++ /* find second , */
++ sink = buf;
++ control = &buf[i + 2];
++ buf[i] = 0;
++
++ for (; i < len; i++) {
++ if (buf[i] == ',')
++ goto done;
++ }
++
++ SNDERR("error: invalid route \"%s\"\n", buf);
++ return -EINVAL;
++
++done:
++ buf[i] = 0;
++ source = &buf[i + 2];
++
++ strcpy(line->source, source);
++ strcpy(line->control, control);
++ strcpy(line->sink, sink);
++ return 0;
++}
++
++
++static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct tplg_elem *elem;
++ struct snd_soc_tplg_dapm_graph_elem *line = NULL;
++ int err;
++
++ snd_config_for_each(i, next, cfg) {
++ const char *val;
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_string(n, &val) < 0)
++ continue;
++
++ elem = tplg_elem_new();
++ if (!elem)
++ return -ENOMEM;
++
++ list_add_tail(&elem->list, &tplg->route_list);
++ strcpy(elem->id, "line");
++ elem->type = OBJECT_TYPE_DAPM_GRAPH;
++ elem->size = sizeof(*line);
++
++ line = calloc(1, sizeof(*line));
++ if (!line)
++ return -ENOMEM;
++
++ elem->route = line;
++
++ err = tplg_parse_line(val, line);
++ if (err < 0)
++ return err;
++
++ tplg_dbg("route: sink '%s', control '%s', source '%s'\n",
++ line->sink, line->control, line->source);
++ }
++
++ return 0;
++}
++
++int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private ATTRIBUTE_UNUSED)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ int err;
++ const char *graph_id;
++
++ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
++ SNDERR("error: compound is expected for dapm graph definition\n");
++ return -EINVAL;
++ }
++
++ snd_config_get_id(cfg, &graph_id);
++
++ snd_config_for_each(i, next, cfg) {
++ const char *id;
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0) {
++ continue;
++ }
++
++ if (strcmp(id, "lines") == 0) {
++ err = tplg_parse_routes(tplg, n);
++ if (err < 0) {
++ SNDERR("error: failed to parse dapm graph %s\n",
++ graph_id);
++ return err;
++ }
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* DAPM Widget */
++int tplg_parse_dapm_widget(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_dapm_widget *widget;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int widget_type, err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DAPM_WIDGET);
++ if (!elem)
++ return -ENOMEM;
++
++ tplg_dbg(" Widget: %s\n", elem->id);
++
++ widget = elem->widget;
++ elem_copy_text(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++ widget->size = elem->size;
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "type") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget_type = lookup_widget(val);
++ if (widget_type < 0){
++ SNDERR("Widget '%s': Unsupported widget type %s\n",
++ elem->id, val);
++ return -EINVAL;
++ }
++
++ widget->id = widget_type;
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "no_pm") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ if (strcmp(val, "true") == 0)
++ widget->reg = -1;
++
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "shift") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->shift = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->shift);
++ continue;
++ }
++
++ if (strcmp(id, "reg") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->reg = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->reg);
++ continue;
++ }
++
++ if (strcmp(id, "invert") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->invert = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->invert);
++ continue;
++ }
++
++ if (strcmp(id, "subseq") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->subseq= atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->subseq);
++ continue;
++ }
++
++ if (strcmp(id, "event_type") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->event_type = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->event_type);
++ continue;
++ }
++
++ if (strcmp(id, "event_flags") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ widget->event_flags = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, widget->event_flags);
++ continue;
++ }
++
++ if (strcmp(id, "enum") == 0) {
++ err = tplg_parse_dapm_enums(n, elem);
++ if (err < 0)
++ return err;
++
++ continue;
++ }
++
++ if (strcmp(id, "mixer") == 0) {
++ err = tplg_parse_dapm_mixers(n, elem);
++ if (err < 0)
++ return err;
++
++ continue;
++ }
++
++ if (strcmp(id, "data") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++ }
++
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0042-topology-Add-CTL-parser.patch b/0042-topology-Add-CTL-parser.patch
new file mode 100644
index 0000000..03c75a4
--- /dev/null
+++ b/0042-topology-Add-CTL-parser.patch
@@ -0,0 +1,636 @@
+From 694b857ce7b44a333c4f5e8b12f1b6cdf1c12388 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:20 +0100
+Subject: [PATCH 42/49] topology: Add CTL parser
+
+Add support to parse mixers, enums and byte controls.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/ctl.c | 613 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 613 insertions(+)
+ create mode 100644 src/topology/ctl.c
+
+diff --git a/src/topology/ctl.c b/src/topology/ctl.c
+new file mode 100644
+index 000000000000..9c1333c1fc88
+--- /dev/null
++++ b/src/topology/ctl.c
+@@ -0,0 +1,613 @@
++/*
++ 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"
++
++/* copy referenced TLV to the mixer control */
++static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
++{
++ struct snd_soc_tplg_mixer_control *mixer_ctrl = elem->mixer_ctrl;
++ struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
++
++ tplg_dbg("TLV '%s' used by '%s\n", ref->id, elem->id);
++
++ /* TLV has a fixed size */
++ mixer_ctrl->tlv = *tlv;
++
++ /* set size of TLV data */
++ mixer_ctrl->hdr.tlv_size = tlv->count * sizeof(uint32_t);
++ return 0;
++}
++
++/* check referenced TLV for a mixer control */
++static int tplg_build_mixer_control(snd_tplg_t *tplg,
++ struct tplg_elem *elem)
++{
++ struct tplg_ref *ref;
++ struct list_head *base, *pos;
++ int err = 0;
++
++ base = &elem->ref_list;
++
++ /* for each ref in this control elem */
++ list_for_each(pos, base) {
++
++ ref = list_entry(pos, struct tplg_ref, list);
++ if (ref->id == NULL || ref->elem)
++ continue;
++
++ if (ref->type == OBJECT_TYPE_TLV) {
++ ref->elem = tplg_elem_lookup(&tplg->tlv_list,
++ ref->id, OBJECT_TYPE_TLV);
++ if (ref->elem)
++ err = copy_tlv(elem, ref->elem);
++
++ } else if (ref->type == OBJECT_TYPE_DATA) {
++ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
++ ref->id, OBJECT_TYPE_DATA);
++ err = tplg_copy_data(elem, ref->elem);
++ }
++
++ if (!ref->elem) {
++ SNDERR("error: cannot find '%s' referenced by"
++ " control '%s'\n", ref->id, elem->id);
++ return -EINVAL;
++ } else if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
++static void copy_enum_texts(struct tplg_elem *enum_elem,
++ struct tplg_elem *ref_elem)
++{
++ struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
++
++ memcpy(ec->texts, ref_elem->texts,
++ SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++}
++
++/* check referenced text for a enum control */
++static int tplg_build_enum_control(snd_tplg_t *tplg,
++ struct tplg_elem *elem)
++{
++ struct tplg_ref *ref;
++ struct list_head *base, *pos;
++ int err = 0;
++
++ base = &elem->ref_list;
++
++ list_for_each(pos, base) {
++
++ ref = list_entry(pos, struct tplg_ref, list);
++ if (ref->id == NULL || ref->elem)
++ continue;
++
++ if (ref->type == OBJECT_TYPE_TEXT) {
++ ref->elem = tplg_elem_lookup(&tplg->text_list,
++ ref->id, OBJECT_TYPE_TEXT);
++ if (ref->elem)
++ copy_enum_texts(elem, ref->elem);
++
++ } else if (ref->type == OBJECT_TYPE_DATA) {
++ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
++ ref->id, OBJECT_TYPE_DATA);
++ err = tplg_copy_data(elem, ref->elem);
++ }
++ if (!ref->elem) {
++ SNDERR("error: cannot find '%s' referenced by"
++ " control '%s'\n", ref->id, elem->id);
++ return -EINVAL;
++ } else if (err < 0)
++ return err;
++ }
++
++ return 0;
++}
++
++/* check referenced private data for a byte control */
++static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
++{
++ struct tplg_ref *ref;
++ struct list_head *base, *pos;
++
++ base = &elem->ref_list;
++
++ list_for_each(pos, base) {
++
++ ref = list_entry(pos, struct tplg_ref, list);
++ if (ref->id == NULL || ref->elem)
++ continue;
++
++ /* bytes control only reference one private data section */
++ ref->elem = tplg_elem_lookup(&tplg->pdata_list,
++ ref->id, OBJECT_TYPE_DATA);
++ if (!ref->elem) {
++ SNDERR("error: cannot find data '%s'"
++ " referenced by control '%s'\n",
++ ref->id, elem->id);
++ return -EINVAL;
++ }
++
++ /* copy texts to enum elem */
++ return tplg_copy_data(elem, ref->elem);
++ }
++
++ return 0;
++}
++
++int tplg_build_controls(snd_tplg_t *tplg)
++{
++ struct list_head *base, *pos;
++ struct tplg_elem *elem;
++ int err = 0;
++
++ base = &tplg->mixer_list;
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ err = tplg_build_mixer_control(tplg, elem);
++ if (err < 0)
++ return err;
++
++ /* add control to manifest */
++ tplg->manifest.control_elems++;
++ }
++
++ base = &tplg->enum_list;
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ err = tplg_build_enum_control(tplg, elem);
++ if (err < 0)
++ return err;
++
++ /* add control to manifest */
++ tplg->manifest.control_elems++;
++ }
++
++ base = &tplg->bytes_ext_list;
++ list_for_each(pos, base) {
++
++ elem = list_entry(pos, struct tplg_elem, list);
++ err = tplg_build_bytes_control(tplg, elem);
++ if (err < 0)
++ return err;
++
++ /* add control to manifest */
++ tplg->manifest.control_elems++;
++ }
++
++ return 0;
++}
++
++
++/*
++ * Parse TLV of DBScale type.
++ *
++ * Parse DBScale describing min, step, mute in DB.
++ */
++static int tplg_parse_tlv_dbscale(snd_config_t *cfg, struct tplg_elem *elem)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct snd_soc_tplg_ctl_tlv *tplg_tlv;
++ const char *id = NULL, *value = NULL;
++ int *data;
++
++ tplg_dbg(" scale: %s\n", elem->id);
++
++ tplg_tlv = calloc(1, sizeof(*tplg_tlv));
++ if (!tplg_tlv)
++ return -ENOMEM;
++ data = (int*)(tplg_tlv->data);
++
++ elem->tlv = tplg_tlv;
++ tplg_tlv->numid = SNDRV_CTL_TLVT_DB_SCALE;
++ tplg_tlv->count = 8;
++ tplg_tlv->size = sizeof(*tplg_tlv);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++
++ /* get ID */
++ if (snd_config_get_id(n, &id) < 0) {
++ SNDERR("error: cant get ID\n");
++ return -EINVAL;
++ }
++
++ /* get value */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ tplg_dbg("\t%s = %s\n", id, value);
++
++ /* get TLV data */
++ if (strcmp(id, "min") == 0)
++ data[0] = atoi(value);
++ else if (strcmp(id, "step") == 0)
++ data[1] = atoi(value);
++ else if (strcmp(id, "mute") == 0)
++ data[2] = atoi(value);
++ else
++ SNDERR("error: unknown key %s\n", id);
++ }
++
++ return 0;
++}
++
++/* Parse TLV */
++int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private ATTRIBUTE_UNUSED)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id;
++ int err = 0;
++ struct tplg_elem *elem;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_TLV);
++ if (!elem)
++ return -ENOMEM;
++
++ 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, "scale") == 0) {
++ err = tplg_parse_tlv_dbscale(n, elem);
++ if (err < 0) {
++ SNDERR("error: failed to DBScale");
++ return err;
++ }
++ continue;
++ }
++ }
++
++ return err;
++}
++
++/* Parse Control Bytes */
++int tplg_parse_control_bytes(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_bytes_control *be;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_BYTES);
++ if (!elem)
++ return -ENOMEM;
++
++ be = elem->bytes_ext;
++ be->size = elem->size;
++ elem_copy_text(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++ be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
++
++ tplg_dbg(" Control Bytes: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "base") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ be->base = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, be->base);
++ continue;
++ }
++
++ if (strcmp(id, "num_regs") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ be->num_regs = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, be->num_regs);
++ continue;
++ }
++
++ if (strcmp(id, "max") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ be->max = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, be->num_regs);
++ continue;
++ }
++
++ if (strcmp(id, "mask") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ be->mask = strtol(val, NULL, 16);
++ tplg_dbg("\t%s: %d\n", id, be->mask);
++ continue;
++ }
++
++ if (strcmp(id, "data") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "tlv") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val);
++ if (err < 0)
++ return err;
++
++ be->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
++ SNDRV_CTL_ELEM_ACCESS_READWRITE;
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse Control Enums. */
++int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
++ void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_enum_control *ec;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err, j;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_ENUM);
++ if (!elem)
++ return -ENOMEM;
++
++ /* init new mixer */
++ ec = elem->enum_ctrl;
++ elem_copy_text(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++ ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
++ ec->size = elem->size;
++ tplg->channel_idx = 0;
++
++ /* set channel reg to default state */
++ for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
++ ec->channel[j].reg = -1;
++
++ tplg_dbg(" Control Enum: %s\n", elem->id);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "texts") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ tplg_ref_add(elem, OBJECT_TYPE_TEXT, val);
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "channel") == 0) {
++ if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
++ SNDERR("error: too many channels %s\n",
++ elem->id);
++ return -EINVAL;
++ }
++
++ err = tplg_parse_compound(tplg, n, tplg_parse_channel,
++ ec->channel);
++ if (err < 0)
++ return err;
++
++ ec->num_channels = tplg->channel_idx;
++ continue;
++ }
++
++ if (strcmp(id, "ops") == 0) {
++ err = tplg_parse_compound(tplg, n, tplg_parse_ops,
++ &ec->hdr);
++ if (err < 0)
++ return err;
++ continue;
++ }
++
++ if (strcmp(id, "data") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++ }
++
++ return 0;
++}
++
++/* Parse Controls.
++ *
++ * Mixer control. Supports multiple channels.
++ */
++int tplg_parse_control_mixer(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
++{
++ struct snd_soc_tplg_mixer_control *mc;
++ struct tplg_elem *elem;
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ const char *id, *val = NULL;
++ int err, j;
++
++ elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_MIXER);
++ if (!elem)
++ return -ENOMEM;
++
++ /* init new mixer */
++ mc = elem->mixer_ctrl;
++ elem_copy_text(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
++ mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
++ mc->size = elem->size;
++ tplg->channel_idx = 0;
++
++ /* set channel reg to default state */
++ for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
++ mc->channel[j].reg = -1;
++
++ tplg_dbg(" Control Mixer: %s\n", elem->id);
++
++ /* giterate trough each mixer elment */
++ snd_config_for_each(i, next, cfg) {
++ n = snd_config_iterator_entry(i);
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* skip comments */
++ if (strcmp(id, "comment") == 0)
++ continue;
++ if (id[0] == '#')
++ continue;
++
++ if (strcmp(id, "index") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ elem->index = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, elem->index);
++ continue;
++ }
++
++ if (strcmp(id, "channel") == 0) {
++ if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
++ SNDERR("error: too many channels %s\n",
++ elem->id);
++ return -EINVAL;
++ }
++
++ err = tplg_parse_compound(tplg, n, tplg_parse_channel,
++ mc->channel);
++ if (err < 0)
++ return err;
++
++ mc->num_channels = tplg->channel_idx;
++ continue;
++ }
++
++ if (strcmp(id, "max") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ mc->max = atoi(val);
++ tplg_dbg("\t%s: %d\n", id, mc->max);
++ continue;
++ }
++
++ if (strcmp(id, "invert") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ if (strcmp(val, "true") == 0)
++ mc->invert = 1;
++ else if (strcmp(val, "false") == 0)
++ mc->invert = 0;
++
++ tplg_dbg("\t%s: %d\n", id, mc->invert);
++ continue;
++ }
++
++ if (strcmp(id, "ops") == 0) {
++ err = tplg_parse_compound(tplg, n, tplg_parse_ops,
++ &mc->hdr);
++ if (err < 0)
++ return err;
++ continue;
++ }
++
++ if (strcmp(id, "tlv") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val);
++ if (err < 0)
++ return err;
++
++ mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
++ SNDRV_CTL_ELEM_ACCESS_READWRITE;
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++
++ if (strcmp(id, "data") == 0) {
++ if (snd_config_get_string(n, &val) < 0)
++ return -EINVAL;
++
++ tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
++ tplg_dbg("\t%s: %s\n", id, val);
++ continue;
++ }
++ }
++
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0043-topology-Add-Channel-map-parser.patch b/0043-topology-Add-Channel-map-parser.patch
new file mode 100644
index 0000000..ac04d59
--- /dev/null
+++ b/0043-topology-Add-Channel-map-parser.patch
@@ -0,0 +1,145 @@
+From 9764a4b891737e6b4363c09b5e5ce8384acecc11 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:21 +0100
+Subject: [PATCH 43/49] topology: Add Channel map parser.
+
+Add support for parsing channel map to control registers.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ src/topology/channel.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 122 insertions(+)
+ create mode 100644 src/topology/channel.c
+
+diff --git a/src/topology/channel.c b/src/topology/channel.c
+new file mode 100644
+index 000000000000..9bc5d5a77c57
+--- /dev/null
++++ b/src/topology/channel.c
+@@ -0,0 +1,122 @@
++/*
++ 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"
++
++/* mapping of channel text names to types */
++static const struct map_elem channel_map[] = {
++ {"mono", SNDRV_CHMAP_MONO}, /* mono stream */
++ {"fl", SNDRV_CHMAP_FL}, /* front left */
++ {"fr", SNDRV_CHMAP_FR}, /* front right */
++ {"rl", SNDRV_CHMAP_RL}, /* rear left */
++ {"rr", SNDRV_CHMAP_RR}, /* rear right */
++ {"fc", SNDRV_CHMAP_FC}, /* front center */
++ {"lfe", SNDRV_CHMAP_LFE}, /* LFE */
++ {"sl", SNDRV_CHMAP_SL}, /* side left */
++ {"sr", SNDRV_CHMAP_SR}, /* side right */
++ {"rc", SNDRV_CHMAP_RC}, /* rear center */
++ {"flc", SNDRV_CHMAP_FLC}, /* front left center */
++ {"frc", SNDRV_CHMAP_FRC}, /* front right center */
++ {"rlc", SNDRV_CHMAP_RLC}, /* rear left center */
++ {"rrc", SNDRV_CHMAP_RRC}, /* rear right center */
++ {"flw", SNDRV_CHMAP_FLW}, /* front left wide */
++ {"frw", SNDRV_CHMAP_FRW}, /* front right wide */
++ {"flh", SNDRV_CHMAP_FLH}, /* front left high */
++ {"fch", SNDRV_CHMAP_FCH}, /* front center high */
++ {"frh", SNDRV_CHMAP_FRH}, /* front right high */
++ {"tc", SNDRV_CHMAP_TC}, /* top center */
++ {"tfl", SNDRV_CHMAP_TFL}, /* top front left */
++ {"tfr", SNDRV_CHMAP_TFR}, /* top front right */
++ {"tfc", SNDRV_CHMAP_TFC}, /* top front center */
++ {"trl", SNDRV_CHMAP_TRL}, /* top rear left */
++ {"trr", SNDRV_CHMAP_TRR}, /* top rear right */
++ {"trc", SNDRV_CHMAP_TRC}, /* top rear center */
++ {"tflc", SNDRV_CHMAP_TFLC}, /* top front left center */
++ {"tfrc", SNDRV_CHMAP_TFRC}, /* top front right center */
++ {"tsl", SNDRV_CHMAP_TSL}, /* top side left */
++ {"tsr", SNDRV_CHMAP_TSR}, /* top side right */
++ {"llfe", SNDRV_CHMAP_LLFE}, /* left LFE */
++ {"rlfe", SNDRV_CHMAP_RLFE}, /* right LFE */
++ {"bc", SNDRV_CHMAP_BC}, /* bottom center */
++ {"blc", SNDRV_CHMAP_BLC}, /* bottom left center */
++ {"brc", SNDRV_CHMAP_BRC}, /* bottom right center */
++};
++
++
++static int lookup_channel(const char *c)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
++ if (strcasecmp(channel_map[i].name, c) == 0) {
++ return channel_map[i].id;
++ }
++ }
++
++ return -EINVAL;
++}
++
++/* Parse a channel mapping. */
++int tplg_parse_channel(snd_tplg_t *tplg,
++ snd_config_t *cfg, void *private)
++{
++ snd_config_iterator_t i, next;
++ snd_config_t *n;
++ struct snd_soc_tplg_channel *channel = private;
++ const char *id, *value;
++
++ if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN)
++ return -EINVAL;
++
++ channel += tplg->channel_idx;
++ snd_config_get_id(cfg, &id);
++ tplg_dbg("\tChannel %s at index %d\n", id, tplg->channel_idx);
++
++ channel->id = lookup_channel(id);
++ if (channel->id < 0) {
++ SNDERR("error: invalid channel %s\n", id);
++ return -EINVAL;
++ }
++
++ channel->size = sizeof(*channel);
++ tplg_dbg("\tChan %s = %d\n", id, channel->id);
++
++ snd_config_for_each(i, next, cfg) {
++
++ n = snd_config_iterator_entry(i);
++
++ /* get id */
++ if (snd_config_get_id(n, &id) < 0)
++ continue;
++
++ /* get value */
++ if (snd_config_get_string(n, &value) < 0)
++ continue;
++
++ if (strcmp(id, "reg") == 0)
++ channel->reg = atoi(value);
++ else if (strcmp(id, "shift") == 0)
++ channel->shift = atoi(value);
++
++ tplg_dbg("\t\t%s = %s\n", id, value);
++ }
++
++ tplg->channel_idx++;
++ return 0;
++}
+--
+2.5.0
+
diff --git a/0044-topology-Add-binary-file-builder.patch b/0044-topology-Add-binary-file-builder.patch
new file mode 100644
index 0000000..6df02f0
--- /dev/null
+++ b/0044-topology-Add-binary-file-builder.patch
@@ -0,0 +1,350 @@
+From 1d1dff56767842a99d2e06a6997079c0516dec68 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:22 +0100
+Subject: [PATCH 44/49] topology: Add binary file builder.
+
+Build the binary output file from all the locally parsed objects and elements.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ 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 000000000000..0066b220353c
+--- /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;
++}
+--
+2.5.0
+
diff --git a/0045-topology-autotools-Add-build-support-for-topology-co.patch b/0045-topology-autotools-Add-build-support-for-topology-co.patch
new file mode 100644
index 0000000..6291ac3
--- /dev/null
+++ b/0045-topology-autotools-Add-build-support-for-topology-co.patch
@@ -0,0 +1,125 @@
+From fec1e8f25374ec8eb4d57ee43e94e9689a748678 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:23 +0100
+Subject: [PATCH 45/49] topology: autotools: Add build support for topology
+ core
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ configure.ac | 9 ++++++++-
+ include/Makefile.am | 4 ++++
+ src/Makefile.am | 7 +++++++
+ src/topology/Makefile.am | 19 +++++++++++++++++++
+ 4 files changed, 38 insertions(+), 1 deletion(-)
+ create mode 100644 src/topology/Makefile.am
+
+diff --git a/configure.ac b/configure.ac
+index 9621d4e9ec2b..b6bea2dca434 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -380,6 +380,9 @@ AC_ARG_ENABLE(seq,
+ AC_ARG_ENABLE(ucm,
+ AS_HELP_STRING([--disable-ucm], [disable the use-case-manager component]),
+ [build_ucm="$enableval"], [build_ucm="yes"])
++AC_ARG_ENABLE(topology,
++ AS_HELP_STRING([--disable-topology], [disable the DSP topology component]),
++ [build_topology="$enableval"], [build_topology="yes"])
+ AC_ARG_ENABLE(alisp,
+ AS_HELP_STRING([--disable-alisp], [disable the alisp component]),
+ [build_alisp="$enableval"], [build_alisp="yes"])
+@@ -422,6 +425,7 @@ AM_CONDITIONAL([BUILD_RAWMIDI], [test x$build_rawmidi = xyes])
+ AM_CONDITIONAL([BUILD_HWDEP], [test x$build_hwdep = xyes])
+ AM_CONDITIONAL([BUILD_SEQ], [test x$build_seq = xyes])
+ AM_CONDITIONAL([BUILD_UCM], [test x$build_ucm = xyes])
++AM_CONDITIONAL([BUILD_TOPOLOGY], [test x$build_topology = xyes])
+ AM_CONDITIONAL([BUILD_ALISP], [test x$build_alisp = xyes])
+ AM_CONDITIONAL([BUILD_PYTHON], [test x$build_python = xyes])
+
+@@ -443,6 +447,9 @@ fi
+ if test "$build_ucm" = "yes"; then
+ AC_DEFINE([BUILD_UCM], "1", [Build UCM component])
+ fi
++if test "$build_topology" = "yes"; then
++ AC_DEFINE([BUILD_TOPOLOGY], "1", [Build DSP Topology component])
++fi
+
+ dnl PCM Plugins
+
+@@ -643,7 +650,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
+ src/pcm/Makefile src/pcm/scopes/Makefile \
+ src/rawmidi/Makefile src/timer/Makefile \
+ src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
+- src/alisp/Makefile \
++ src/alisp/Makefile src/topology/Makefile \
+ src/conf/Makefile src/conf/alsa.conf.d/Makefile \
+ src/conf/cards/Makefile \
+ src/conf/pcm/Makefile \
+diff --git a/include/Makefile.am b/include/Makefile.am
+index 4baa03af69e1..ff931fda24d5 100644
+--- a/include/Makefile.am
++++ b/include/Makefile.am
+@@ -50,6 +50,10 @@ if BUILD_UCM
+ alsainclude_HEADERS += use-case.h
+ endif
+
++if BUILD_TOPOLOGY
++alsainclude_HEADERS += topology.h
++endif
++
+ if BUILD_ALISP
+ alsainclude_HEADERS += alisp.h
+ endif
+diff --git a/src/Makefile.am b/src/Makefile.am
+index fa255ff43ee0..57686a612fd8 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -42,6 +42,10 @@ if BUILD_UCM
+ SUBDIRS += ucm
+ libasound_la_LIBADD += ucm/libucm.la
+ endif
++if BUILD_TOPOLOGY
++SUBDIRS += topology
++libasound_la_LIBADD += topology/libtopology.la
++endif
+ if BUILD_ALISP
+ SUBDIRS += alisp
+ libasound_la_LIBADD += alisp/libalisp.la
+@@ -81,6 +85,9 @@ seq/libseq.la:
+ ucm/libucm.la:
+ $(MAKE) -C ucm libucm.la
+
++topology/libtopology.la:
++ $(MAKE) -C topology libtopology.la
++
+ instr/libinstr.la:
+ $(MAKE) -C instr libinstr.la
+
+diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
+new file mode 100644
+index 000000000000..3fb8bf7a9290
+--- /dev/null
++++ b/src/topology/Makefile.am
+@@ -0,0 +1,19 @@
++EXTRA_LTLIBRARIES = libtopology.la
++
++libtopology_la_SOURCES =\
++ parser.c \
++ builder.c \
++ ctl.c \
++ dapm.c \
++ pcm.c \
++ data.c \
++ text.c \
++ channel.c \
++ ops.c \
++ elem.c
++
++noinst_HEADERS = tplg_local.h
++
++all: libtopology.la
++
++AM_CPPFLAGS=-I$(top_srcdir)/include
+--
+2.5.0
+
diff --git a/0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch b/0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
new file mode 100644
index 0000000..3b7830f
--- /dev/null
+++ b/0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
@@ -0,0 +1,60 @@
+From 22603237b09ed50744030f550248ade135d4f73b Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:24 +0100
+Subject: [PATCH 46/49] topology: doxygen: Add doxygen support for topology
+ core.
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ doc/doxygen.cfg.in | 7 +++++--
+ doc/index.doxygen | 1 +
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
+index 043e75b2d7eb..92bd52ba67a2 100644
+--- a/doc/doxygen.cfg.in
++++ b/doc/doxygen.cfg.in
+@@ -29,6 +29,7 @@ INPUT = @top_srcdir@/doc/index.doxygen \
+ @top_srcdir@/include/control_external.h \
+ @top_srcdir@/include/mixer.h \
+ @top_srcdir@/include/use-case.h \
++ @top_srcdir@/include/topology.h \
+ @top_srcdir@/src/error.c \
+ @top_srcdir@/src/dlmisc.c \
+ @top_srcdir@/src/async.c \
+@@ -78,7 +79,8 @@ INPUT = @top_srcdir@/doc/index.doxygen \
+ @top_srcdir@/src/timer \
+ @top_srcdir@/src/hwdep \
+ @top_srcdir@/src/seq \
+- @top_srcdir@/src/ucm
++ @top_srcdir@/src/ucm \
++ @top_srcdir@/src/topology
+ EXCLUDE = @top_srcdir@/src/control/control_local.h \
+ @top_srcdir@/src/pcm/atomic.h \
+ @top_srcdir@/src/pcm/interval.h \
+@@ -94,7 +96,8 @@ EXCLUDE = @top_srcdir@/src/control/control_local.h \
+ @top_srcdir@/src/mixer/mixer_local.h \
+ @top_srcdir@/src/rawmidi/rawmidi_local.h \
+ @top_srcdir@/src/seq/seq_local.h \
+- @top_srcdir@/src/ucm/ucm_local.h
++ @top_srcdir@/src/ucm/ucm_local.h \
++ @top_srcdir@/src/topology/tplg_local.h
+ RECURSIVE = YES
+ FILE_PATTERNS = *.c *.h
+ EXAMPLE_PATH = @top_srcdir@/test
+diff --git a/doc/index.doxygen b/doc/index.doxygen
+index 7d049fe5c32a..b40c75a5239b 100644
+--- a/doc/index.doxygen
++++ b/doc/index.doxygen
+@@ -41,6 +41,7 @@ may be placed in the library code instead of the kernel driver.
+ Page \ref timer explains the design of the Timer API.
+ Page \ref seq explains the design of the Sequencer API.
+ Page \ref ucm explains the use case API.
++ Page \ref topology explains the DSP topology API.
+
+
+ Configuration
+--
+2.5.0
+
diff --git a/0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch b/0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
new file mode 100644
index 0000000..42758e3
--- /dev/null
+++ b/0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
@@ -0,0 +1,443 @@
+From 00a51b5bacb0f966d0e323bd9d3057c0eb0e6f23 Mon Sep 17 00:00:00 2001
+From: Liam Girdwood
+Date: Wed, 29 Jul 2015 17:45:25 +0100
+Subject: [PATCH 47/49] conf: topology: Add topology file for broadwell audio
+ DSP
+
+Signed-off-by: Liam Girdwood
+Signed-off-by: Takashi Iwai
+---
+ configure.ac | 2 +
+ src/conf/Makefile.am | 2 +-
+ src/conf/topology/Makefile.am | 1 +
+ src/conf/topology/broadwell/Makefile.am | 4 +
+ src/conf/topology/broadwell/broadwell.conf | 375 +++++++++++++++++++++++++++++
+ 5 files changed, 383 insertions(+), 1 deletion(-)
+ create mode 100644 src/conf/topology/Makefile.am
+ create mode 100644 src/conf/topology/broadwell/Makefile.am
+ create mode 100644 src/conf/topology/broadwell/broadwell.conf
+
+diff --git a/configure.ac b/configure.ac
+index b6bea2dca434..a482b3e7f6ca 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -663,6 +663,8 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
+ src/conf/ucm/PAZ00/Makefile \
+ src/conf/ucm/GoogleNyan/Makefile \
+ src/conf/ucm/broadwell-rt286/Makefile \
++ src/conf/topology/Makefile \
++ src/conf/topology/broadwell/Makefile \
+ modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
+ alsalisp/Makefile aserver/Makefile \
+ test/Makefile test/lsb/Makefile \
+diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
+index 948d5a1c822e..a04f73fddc65 100644
+--- a/src/conf/Makefile.am
++++ b/src/conf/Makefile.am
+@@ -1,4 +1,4 @@
+-SUBDIRS=cards pcm alsa.conf.d ucm
++SUBDIRS=cards pcm alsa.conf.d ucm topology
+
+ cfg_files = alsa.conf
+ if BUILD_ALISP
+diff --git a/src/conf/topology/Makefile.am b/src/conf/topology/Makefile.am
+new file mode 100644
+index 000000000000..f56a96c651e5
+--- /dev/null
++++ b/src/conf/topology/Makefile.am
+@@ -0,0 +1 @@
++SUBDIRS=broadwell
+diff --git a/src/conf/topology/broadwell/Makefile.am b/src/conf/topology/broadwell/Makefile.am
+new file mode 100644
+index 000000000000..35d1e83cb645
+--- /dev/null
++++ b/src/conf/topology/broadwell/Makefile.am
+@@ -0,0 +1,4 @@
++alsaconfigdir = @ALSA_CONFIG_DIR@
++topologydir = $(alsaconfigdir)/topology/broadwell
++topology_DATA = broadwell.conf
++EXTRA_DIST = $(topology_DATA)
+diff --git a/src/conf/topology/broadwell/broadwell.conf b/src/conf/topology/broadwell/broadwell.conf
+new file mode 100644
+index 000000000000..05b3889bec58
+--- /dev/null
++++ b/src/conf/topology/broadwell/broadwell.conf
+@@ -0,0 +1,375 @@
++# Dynamic Firmware Configuration for Broadwell
++
++# TLV
++SectionTLV."hsw_vol_tlv" {
++ Comment "TLV used by both global and stream volumes"
++
++ scale {
++ min "-9000"
++ step "300"
++ mute "1"
++ }
++}
++
++# Controls
++SectionControlMixer."Master Playback Volume" {
++ Comment "Global DSP volume"
++
++ # control belongs to this index group
++ index "1"
++
++ # Channel register and shift for Front Left/Right
++ channel."FL" {
++ reg "0"
++ shift "0"
++ }
++ channel."FR" {
++ reg "0"
++ shift "8"
++ }
++
++ # max control value and whether value is inverted
++ max "31"
++ invert "false"
++
++ # control uses bespoke driver get/put/info ID 0
++ ops."ctl" {
++ info "volsw"
++ get "256"
++ put "256"
++ }
++
++ # uses TLV data above
++ tlv "hsw_vol_tlv"
++}
++
++SectionControlMixer."Media0 Playback Volume" {
++ Comment "Offload 0 volume"
++
++ # control belongs to this index group
++ index "1"
++
++ # Channel register and shift for Front Left/Right
++ channel."FL" {
++ reg "1"
++ shift "0"
++ }
++ channel."FR" {
++ reg "1"
++ shift "8"
++ }
++
++ # max control value and whether value is inverted
++ max "31"
++ invert "false"
++
++ # control uses bespoke driver get/put/info ID 0
++ ops."ctl" {
++ info "volsw"
++ get "257"
++ put "257"
++ }
++
++ # uses TLV data above
++ tlv "hsw_vol_tlv"
++}
++
++SectionControlMixer."Media1 Playback Volume" {
++ Comment "Offload 1 volume"
++
++ # control belongs to this index group
++ index "1"
++
++ # Channel register and shift for Front Left/Right
++ channel."FL" {
++ reg "2"
++ shift "0"
++ }
++ channel."FR" {
++ reg "2"
++ shift "8"
++ }
++
++ # max control value and whether value is inverted
++ max "31"
++ invert "false"
++
++ # control uses bespoke driver get/put/info ID 0
++ ops."ctl" {
++ info "volsw"
++ get "257"
++ put "257"
++ }
++
++ # uses TLV data above
++ tlv "hsw_vol_tlv"
++}
++
++SectionControlMixer."Mic Capture Volume" {
++ Comment "Mic Capture volume"
++
++ # control belongs to this index group
++ index "1"
++
++ # Channel register and shift for Front Left/Right
++ channel."FL" {
++ reg "0"
++ shift "0"
++ }
++ channel."FR" {
++ reg "0"
++ shift "8"
++ }
++
++ # max control value and whether value is inverted
++ max "31"
++ invert "false"
++
++ # control uses bespoke driver get/put/info ID 0
++ ops."ctl" {
++ info "volsw"
++ get "257"
++ put "257"
++ }
++
++ # uses TLV data above
++ tlv "hsw_vol_tlv"
++}
++
++SectionWidget."SSP0 CODEC IN" {
++
++ index "1"
++ type "aif_in"
++ no_pm "true"
++ shift "0"
++ invert "0"
++}
++
++SectionWidget."SSP0 CODEC OUT" {
++
++ index "1"
++ type "aif_out"
++ no_pm "true"
++ shift "0"
++ invert "0"
++}
++
++SectionWidget."SSP1 BT IN" {
++
++ index "1"
++ type "aif_in"
++ no_pm "true"
++ shift "0"
++ invert "0"
++}
++
++SectionWidget."SSP1 BT OUT" {
++
++ index "1"
++ type "aif_out"
++ no_pm "true"
++ shift "0"
++ invert "0"
++}
++
++SectionWidget."Playback VMixer" {
++
++ index "1"
++ type "mixer"
++ no_pm "true"
++ shift "0"
++ invert "0"
++}
++
++# PCM Configurations supported by FW
++SectionPCMConfig."PCM 48k Stereo 24bit" {
++
++ config."playback" {
++ format "S24_LE"
++ rate "48000"
++ channels "2"
++ tdm_slot "0xf"
++ }
++
++ config."capture" {
++ format "S24_LE"
++ rate "48000"
++ channels "2"
++ tdm_slot "0xf"
++ }
++}
++
++SectionPCMConfig."PCM 48k Stereo 16bit" {
++
++ config."playback" {
++ format "S16_LE"
++ rate "48000"
++ channels "2"
++ tdm_slot "0xf"
++ }
++
++ config."capture" {
++ format "S16_LE"
++ rate "48000"
++ channels "2"
++ tdm_slot "0xf"
++ }
++}
++
++SectionPCMConfig."PCM 48k 2P/4C 16bit" {
++
++ config."playback" {
++ format "S16_LE"
++ rate "48000"
++ channels "2"
++ tdm_slot "0xf"
++ }
++
++ config."capture" {
++ format "S16_LE"
++ rate "48000"
++ channels "4"
++ tdm_slot "0xf"
++ }
++}
++
++# PCM capabilities supported by FW
++SectionPCMCapabilities."System Playback" {
++
++ formats "S24_LE,S16_LE"
++ rate_min "48000"
++ rate_max "48000"
++ channels_min "2"
++ channels_max "2"
++}
++
++SectionPCMCapabilities."Analog Capture" {
++
++ formats "S24_LE,S16_LE"
++ rate_min "48000"
++ rate_max "48000"
++ channels_min "2"
++ channels_max "4"
++}
++
++SectionPCMCapabilities."Loopback Capture" {
++
++ formats "S24_LE,S16_LE"
++ rate_min "48000"
++ rate_max "48000"
++ channels_min "2"
++ channels_max "2"
++}
++
++SectionPCMCapabilities."Offload0 Playback" {
++ formats "S24_LE,S16_LE"
++ rate_min "8000"
++ rate_max "192000"
++ channels_min "2"
++ channels_max "2"
++}
++
++SectionPCMCapabilities."Offload1 Playback" {
++ formats "S24_LE,S16_LE"
++ rate_min "8000"
++ rate_max "48000"
++ channels_min "2"
++ channels_max "2"
++}
++
++# PCM devices exported by Firmware
++SectionPCM."System Pin" {
++
++ index "1"
++
++ # used for binding to the PCM
++ ID "0"
++
++ pcm."playback" {
++
++ capabilities "System Playback"
++
++ configs [
++ "PCM 48k Stereo 24bit"
++ "PCM 48k Stereo 16bit"
++ ]
++ }
++
++ pcm."capture" {
++
++ capabilities "Analog Capture"
++
++ configs [
++ "PCM 48k Stereo 24bit"
++ "PCM 48k Stereo 16bit"
++ "PCM 48k 2P/4C 16bit"
++ ]
++ }
++}
++
++SectionPCM."Offload0 Pin" {
++
++ index "1"
++
++ # used for binding to the PCM
++ ID "1"
++
++ pcm."playback" {
++
++ capabilities "Offload0 Playback"
++
++ configs [
++ "PCM 48k Stereo 24bit"
++ "PCM 48k Stereo 16bit"
++ ]
++ }
++}
++
++SectionPCM."Offload1 Pin" {
++
++ index "1"
++
++ # used for binding to the PCM
++ ID "2"
++
++ pcm."playback" {
++
++ capabilities "Offload1 Playback"
++
++ configs [
++ "PCM 48k Stereo 24bit"
++ "PCM 48k Stereo 16bit"
++ ]
++ }
++}
++
++SectionPCM."Loopback Pin" {
++
++ index "1"
++
++ # used for binding to the PCM
++ ID "3"
++
++ pcm."capture" {
++
++ capabilities "Loopback Capture"
++
++ configs [
++ "PCM 48k Stereo 24bit"
++ "PCM 48k Stereo 16bit"
++ ]
++ }
++}
++
++SectionGraph."dsp" {
++ index "1"
++
++ lines [
++ "Playback VMixer, , System Playback"
++ "Playback VMixer, , Offload0 Playback"
++ "Playback VMixer, , Offload1 Playback"
++ "SSP0 CODEC OUT, , Playback VMixer"
++ "Loopback Capture, , Playback VMixer"
++ "Analog Capture, , SSP0 CODEC IN"
++ ]
++}
+--
+2.5.0
+
diff --git a/0048-topology-Fix-missing-inclusion-of-ctype.h.patch b/0048-topology-Fix-missing-inclusion-of-ctype.h.patch
new file mode 100644
index 0000000..cd5f832
--- /dev/null
+++ b/0048-topology-Fix-missing-inclusion-of-ctype.h.patch
@@ -0,0 +1,28 @@
+From 907e464593a2acf51c2e2be4c3d4e098efdd95ff Mon Sep 17 00:00:00 2001
+From: Takashi Iwai
+Date: Thu, 30 Jul 2015 16:34:50 +0200
+Subject: [PATCH 48/49] topology: Fix missing inclusion of ctype.h
+
+Fix a compile warning:
+ data.c:116:7: warning: implicit declaration of function 'isspace' [-Wimplicit-function-declaration]
+
+Signed-off-by: Takashi Iwai
+---
+ src/topology/data.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/topology/data.c b/src/topology/data.c
+index ae664721935d..13e1e2bb60fb 100644
+--- a/src/topology/data.c
++++ b/src/topology/data.c
+@@ -18,6 +18,7 @@
+
+ #include "list.h"
+ #include "tplg_local.h"
++#include
+
+ /* Get Private data from a file. */
+ static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
+--
+2.5.0
+
diff --git a/0049-topology-Fix-typos.patch b/0049-topology-Fix-typos.patch
new file mode 100644
index 0000000..2744878
--- /dev/null
+++ b/0049-topology-Fix-typos.patch
@@ -0,0 +1,96 @@
+From 66ce9f9a1177de3b8e8304323b4d3a16d78ead32 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai
+Date: Thu, 30 Jul 2015 16:43:19 +0200
+Subject: [PATCH 49/49] topology: Fix typos
+
+Signed-off-by: Takashi Iwai
+---
+ include/topology.h | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/include/topology.h b/include/topology.h
+index f604ed1450d3..0cb2d79e5574 100644
+--- a/include/topology.h
++++ b/include/topology.h
+@@ -48,7 +48,7 @@ extern "C" {
+ *
+ * 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
++ * other topology objects as part of their definition. i.e. a TLV data object
+ * can be shared amongst many control objects that use the same TLV data.
+ *
+ *
+@@ -174,7 +174,7 @@ extern "C" {
+ * words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
+ * };
+ *
+- * The file, bytes, shorts and words keywords are all mutulally exclusive as
++ * The file, bytes, shorts and words keywords are all mutually 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.
+@@ -247,7 +247,7 @@ extern "C" {
+ * can include channel mapping, callback operations, private data and
+ * text strings to represent the enumerated control options.
+ *
+- * The text strings for the enumerated controls are defined in a seperate
++ * The text strings for the enumerated controls are defined in a separate
+ * section as follows :-
+ *
+ *
+@@ -306,7 +306,7 @@ extern "C" {
+ * graph with other graphs, it's not used by the kernel atm.
+ *
+ * DAPM Widgets
+- * DAPM wigets are similar to controls in that they can include many other
++ * DAPM widgets 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 :-
+@@ -367,13 +367,13 @@ extern "C" {
+ *
+ * formats "S24_LE,S16_LE" # Supported formats
+ * rate_min "48000" # Max supported sample rate
+- * rate_max "48000" # Min suppoprted sample rate
++ * rate_max "48000" # Min supported sample rate
+ * channels_min "2" # Min number of channels
+ * channels_max "2" # max number of channels
+ * }
+ *
+ * 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
++ * The PCM capabilities name can be referred to and included by BE, PCM and
+ * Codec <-> codec topology sections.
+ *
+ * PCM Configurations
+@@ -400,7 +400,7 @@ extern "C" {
+ *
+ *
+ * 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
++ * The PCM configuration name can be referred to and included by BE, PCM and
+ * Codec <-> codec topology sections.
+ *
+ * PCM Configurations
+@@ -434,7 +434,7 @@ extern "C" {
+ * id "0" # used for binding to the PCM
+ *
+ * pcm."playback" {
+- * capabilities "capabilities1" # capbilities for playback
++ * capabilities "capabilities1" # capabilities for playback
+ *
+ * configs [ # supported configs for playback
+ * "config1"
+@@ -476,7 +476,7 @@ void snd_tplg_free(snd_tplg_t *tplg);
+ * \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
++ * \return Zero on success, otherwise a negative error code
+ */
+ int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile,
+ const char *outfile);
+--
+2.5.0
+
diff --git a/alsa.changes b/alsa.changes
index 6857d72..44d5968 100644
--- a/alsa.changes
+++ b/alsa.changes
@@ -1,3 +1,39 @@
+-------------------------------------------------------------------
+Tue Aug 4 17:41:39 CEST 2015 - tiwai@suse.de
+
+- 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
+ 0049-topology-Fix-typos.patch
+- Enable autoreconf call to regenerate after patching
+
-------------------------------------------------------------------
Fri Jul 31 07:35:12 UTC 2015 - dimstar@opensuse.org
diff --git a/alsa.spec b/alsa.spec
index fffddc0..d838164 100644
--- a/alsa.spec
+++ b/alsa.spec
@@ -71,6 +71,33 @@ Patch19: 0019-pcm-Don-t-assert-in-_snd_pcm_hw_params_internal.patch
Patch20: 0020-pcm-Fix-snd_pcm_status-for-dmix-co.patch
Patch21: 0021-control-Allow-cset-ing-specific-values-in-the-multi-.patch
Patch22: 0022-PCM-snd_pcm_xxxx_drain-maybe-blocked-after-suspend-a.patch
+Patch23: 0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
+Patch24: 0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
+Patch25: 0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
+Patch26: 0026-docs-Add-UCM-link-to-main-doxygen-page.patch
+Patch27: 0027-Replace-unsafe-characters-with-_-in-card-name.patch
+Patch28: 0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
+Patch29: 0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
+Patch30: 0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
+Patch31: 0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
+Patch32: 0032-test-audio_time-show-report-validity-and-accuracy.patch
+Patch33: 0033-pcm-restore-hw-params-on-set-latency-failed.patch
+Patch34: 0034-Replace-list.h-with-its-own-version.patch
+Patch35: 0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
+Patch36: 0036-topology-Add-topology-core-parser.patch
+Patch37: 0037-topology-Add-text-section-parser.patch
+Patch38: 0038-topology-Add-PCM-parser.patch
+Patch39: 0039-topology-Add-operations-parser.patch
+Patch40: 0040-topology-Add-private-data-parser.patch
+Patch41: 0041-topology-Add-DAPM-object-parser.patch
+Patch42: 0042-topology-Add-CTL-parser.patch
+Patch43: 0043-topology-Add-Channel-map-parser.patch
+Patch44: 0044-topology-Add-binary-file-builder.patch
+Patch45: 0045-topology-autotools-Add-build-support-for-topology-co.patch
+Patch46: 0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
+Patch47: 0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
+Patch48: 0048-topology-Fix-missing-inclusion-of-ctype.h.patch
+Patch49: 0049-topology-Fix-typos.patch
# rest suse patches
Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff
# suppress timestamp in documents
@@ -163,6 +190,33 @@ Architecture.
%patch20 -p1
%patch21 -p1
%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+%patch27 -p1
+%patch28 -p1
+%patch29 -p1
+%patch30 -p1
+%patch31 -p1
+%patch32 -p1
+%patch33 -p1
+%patch34 -p1
+%patch35 -p1
+%patch36 -p1
+%patch37 -p1
+%patch38 -p1
+%patch39 -p1
+%patch40 -p1
+%patch41 -p1
+%patch42 -p1
+%patch43 -p1
+%patch44 -p1
+%patch45 -p1
+%patch46 -p1
+%patch47 -p1
+%patch48 -p1
+%patch49 -p1
%if 0%{?suse_version} == 1130
%patch99 -p1
%endif
@@ -178,7 +232,7 @@ sed -i -e'/recommends.*alsa-oss/d' $RPM_SOURCE_DIR/baselibs.conf
%build
export AUTOMAKE_JOBS="%{?_smp_mflags}"
# build alsa-lib
-# autoreconf -fi
+autoreconf -fi
%configure \
--disable-static \
--enable-symbolic-functions \