Merge remote-tracking branch 'asoc/topic/topology' into asoc-next
authorMark Brown <broonie@kernel.org>
Fri, 27 May 2016 12:45:36 +0000 (13:45 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 27 May 2016 12:45:36 +0000 (13:45 +0100)
include/uapi/sound/asoc.h
sound/soc/soc-topology.c

index c4cc1e40b35c1343595d716b6b5b5e7d894226ce..e4701a3c633187c25a832580eb0af5fe70f2ade4 100644 (file)
 #define SND_SOC_TPLG_STREAM_PLAYBACK   0
 #define SND_SOC_TPLG_STREAM_CAPTURE    1
 
+/* vendor tuple types */
+#define SND_SOC_TPLG_TUPLE_TYPE_UUID   0
+#define SND_SOC_TPLG_TUPLE_TYPE_STRING 1
+#define SND_SOC_TPLG_TUPLE_TYPE_BOOL   2
+#define SND_SOC_TPLG_TUPLE_TYPE_BYTE   3
+#define SND_SOC_TPLG_TUPLE_TYPE_WORD   4
+#define SND_SOC_TPLG_TUPLE_TYPE_SHORT  5
+
 /*
  * Block Header.
  * This header precedes all object and object arrays below.
@@ -132,6 +140,35 @@ struct snd_soc_tplg_hdr {
        __le32 count;           /* number of elements in block */
 } __attribute__((packed));
 
+/* vendor tuple for uuid */
+struct snd_soc_tplg_vendor_uuid_elem {
+       __le32 token;
+       char uuid[16];
+} __attribute__((packed));
+
+/* vendor tuple for a bool/byte/short/word value */
+struct snd_soc_tplg_vendor_value_elem {
+       __le32 token;
+       __le32 value;
+} __attribute__((packed));
+
+/* vendor tuple for string */
+struct snd_soc_tplg_vendor_string_elem {
+       __le32 token;
+       char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+} __attribute__((packed));
+
+struct snd_soc_tplg_vendor_array {
+       __le32 size;    /* size in bytes of the array, including all elements */
+       __le32 type;    /* SND_SOC_TPLG_TUPLE_TYPE_ */
+       __le32 num_elems;       /* number of elements in array */
+       union {
+               struct snd_soc_tplg_vendor_uuid_elem uuid[0];
+               struct snd_soc_tplg_vendor_value_elem value[0];
+               struct snd_soc_tplg_vendor_string_elem string[0];
+       };
+} __attribute__((packed));
+
 /*
  * Private data.
  * All topology objects may have private data that can be used by the driver or
@@ -139,7 +176,10 @@ struct snd_soc_tplg_hdr {
  */
 struct snd_soc_tplg_private {
        __le32 size;    /* in bytes of private data */
-       char data[0];
+       union {
+               char data[0];
+               struct snd_soc_tplg_vendor_array array[0];
+       };
 } __attribute__((packed));
 
 /*
@@ -383,7 +423,7 @@ struct snd_soc_tplg_pcm {
        __le32 size;            /* in bytes of this structure */
        char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       __le32 pcm_id;          /* unique ID - used to match */
+       __le32 pcm_id;          /* unique ID - used to match with DAI link */
        __le32 dai_id;          /* unique ID - used to match */
        __le32 playback;        /* supports playback mode */
        __le32 capture;         /* supports capture mode */
index 1cf94d7fb9f4534801b83565227408b594f2ee59..ee7f15aa46fca30400a07d8b8cf4f44717f0a89f 100644 (file)
@@ -1023,6 +1023,11 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
 
                control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
 
+               if (control_hdr->size != sizeof(*control_hdr)) {
+                       dev_err(tplg->dev, "ASoC: invalid control size\n");
+                       return -EINVAL;
+               }
+
                switch (control_hdr->ops.info) {
                case SND_SOC_TPLG_CTL_VOLSW:
                case SND_SOC_TPLG_CTL_STROBE:
@@ -1476,6 +1481,8 @@ widget:
        widget->dobj.type = SND_SOC_DOBJ_WIDGET;
        widget->dobj.ops = tplg->ops;
        widget->dobj.index = tplg->index;
+       kfree(template.sname);
+       kfree(template.name);
        list_add(&widget->dobj.list, &tplg->comp->dobj_list);
        return 0;
 
@@ -1499,10 +1506,17 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
 
        for (i = 0; i < count; i++) {
                widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
+               if (widget->size != sizeof(*widget)) {
+                       dev_err(tplg->dev, "ASoC: invalid widget size\n");
+                       return -EINVAL;
+               }
+
                ret = soc_tplg_dapm_widget_create(tplg, widget);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
                                widget->name);
+                       return ret;
+               }
        }
 
        return 0;
@@ -1586,6 +1600,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        return snd_soc_register_dai(tplg->comp, dai_drv);
 }
 
+/* create the FE DAI link */
 static int soc_tplg_link_create(struct soc_tplg *tplg,
        struct snd_soc_tplg_pcm *pcm)
 {
@@ -1598,6 +1613,16 @@ static int soc_tplg_link_create(struct soc_tplg *tplg,
 
        link->name = pcm->pcm_name;
        link->stream_name = pcm->pcm_name;
+       link->id = pcm->pcm_id;
+
+       link->cpu_dai_name = pcm->dai_name;
+       link->codec_name = "snd-soc-dummy";
+       link->codec_dai_name = "snd-soc-dummy-dai";
+
+       /* enable DPCM */
+       link->dynamic = 1;
+       link->dpcm_playback = pcm->playback;
+       link->dpcm_capture = pcm->capture;
 
        /* pass control to component driver for optional further init */
        ret = soc_tplg_dai_link_load(tplg, link);
@@ -1639,8 +1664,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
        if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
                return 0;
 
-       pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
-
        if (soc_tplg_check_elem_count(tplg,
                sizeof(struct snd_soc_tplg_pcm), count,
                hdr->payload_size, "PCM DAI")) {
@@ -1650,7 +1673,13 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
        }
 
        /* create the FE DAIs and DAI links */
+       pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
        for (i = 0; i < count; i++) {
+               if (pcm->size != sizeof(*pcm)) {
+                       dev_err(tplg->dev, "ASoC: invalid pcm size\n");
+                       return -EINVAL;
+               }
+
                soc_tplg_pcm_create(tplg, pcm);
                pcm++;
        }
@@ -1670,6 +1699,11 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
                return 0;
 
        manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
+       if (manifest->size != sizeof(*manifest)) {
+               dev_err(tplg->dev, "ASoC: invalid manifest size\n");
+               return -EINVAL;
+       }
+
        tplg->pos += sizeof(struct snd_soc_tplg_manifest);
 
        if (tplg->comp && tplg->ops && tplg->ops->manifest)
@@ -1686,6 +1720,14 @@ static int soc_valid_header(struct soc_tplg *tplg,
        if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
                return 0;
 
+       if (hdr->size != sizeof(*hdr)) {
+               dev_err(tplg->dev,
+                       "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
+                       hdr->type, soc_tplg_get_hdr_offset(tplg),
+                       tplg->fw->size);
+               return -EINVAL;
+       }
+
        /* big endian firmware objects not supported atm */
        if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
                dev_err(tplg->dev,