diff options
author | Mark Brown <broonie@kernel.org> | 2016-05-27 08:45:36 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-05-27 08:45:36 -0400 |
commit | 4c1c16d9a90a7dc3e2a950f7a8629e85a7e114e6 (patch) | |
tree | 5134a37f1bd8e2e2514d0148d6ee625804f97dc7 | |
parent | 463f7e504a8400f0cc9b814662739050540c1a9d (diff) | |
parent | 8ea416748bb04b7a778cb8d2fd5ec7fa51b9d521 (diff) |
Merge remote-tracking branch 'asoc/topic/topology' into asoc-next
-rw-r--r-- | include/uapi/sound/asoc.h | 44 | ||||
-rw-r--r-- | sound/soc/soc-topology.c | 48 |
2 files changed, 87 insertions, 5 deletions
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index c4cc1e40b35c..e4701a3c6331 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h | |||
@@ -116,6 +116,14 @@ | |||
116 | #define SND_SOC_TPLG_STREAM_PLAYBACK 0 | 116 | #define SND_SOC_TPLG_STREAM_PLAYBACK 0 |
117 | #define SND_SOC_TPLG_STREAM_CAPTURE 1 | 117 | #define SND_SOC_TPLG_STREAM_CAPTURE 1 |
118 | 118 | ||
119 | /* vendor tuple types */ | ||
120 | #define SND_SOC_TPLG_TUPLE_TYPE_UUID 0 | ||
121 | #define SND_SOC_TPLG_TUPLE_TYPE_STRING 1 | ||
122 | #define SND_SOC_TPLG_TUPLE_TYPE_BOOL 2 | ||
123 | #define SND_SOC_TPLG_TUPLE_TYPE_BYTE 3 | ||
124 | #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 | ||
125 | #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5 | ||
126 | |||
119 | /* | 127 | /* |
120 | * Block Header. | 128 | * Block Header. |
121 | * This header precedes all object and object arrays below. | 129 | * This header precedes all object and object arrays below. |
@@ -132,6 +140,35 @@ struct snd_soc_tplg_hdr { | |||
132 | __le32 count; /* number of elements in block */ | 140 | __le32 count; /* number of elements in block */ |
133 | } __attribute__((packed)); | 141 | } __attribute__((packed)); |
134 | 142 | ||
143 | /* vendor tuple for uuid */ | ||
144 | struct snd_soc_tplg_vendor_uuid_elem { | ||
145 | __le32 token; | ||
146 | char uuid[16]; | ||
147 | } __attribute__((packed)); | ||
148 | |||
149 | /* vendor tuple for a bool/byte/short/word value */ | ||
150 | struct snd_soc_tplg_vendor_value_elem { | ||
151 | __le32 token; | ||
152 | __le32 value; | ||
153 | } __attribute__((packed)); | ||
154 | |||
155 | /* vendor tuple for string */ | ||
156 | struct snd_soc_tplg_vendor_string_elem { | ||
157 | __le32 token; | ||
158 | char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | ||
159 | } __attribute__((packed)); | ||
160 | |||
161 | struct snd_soc_tplg_vendor_array { | ||
162 | __le32 size; /* size in bytes of the array, including all elements */ | ||
163 | __le32 type; /* SND_SOC_TPLG_TUPLE_TYPE_ */ | ||
164 | __le32 num_elems; /* number of elements in array */ | ||
165 | union { | ||
166 | struct snd_soc_tplg_vendor_uuid_elem uuid[0]; | ||
167 | struct snd_soc_tplg_vendor_value_elem value[0]; | ||
168 | struct snd_soc_tplg_vendor_string_elem string[0]; | ||
169 | }; | ||
170 | } __attribute__((packed)); | ||
171 | |||
135 | /* | 172 | /* |
136 | * Private data. | 173 | * Private data. |
137 | * All topology objects may have private data that can be used by the driver or | 174 | * All topology objects may have private data that can be used by the driver or |
@@ -139,7 +176,10 @@ struct snd_soc_tplg_hdr { | |||
139 | */ | 176 | */ |
140 | struct snd_soc_tplg_private { | 177 | struct snd_soc_tplg_private { |
141 | __le32 size; /* in bytes of private data */ | 178 | __le32 size; /* in bytes of private data */ |
142 | char data[0]; | 179 | union { |
180 | char data[0]; | ||
181 | struct snd_soc_tplg_vendor_array array[0]; | ||
182 | }; | ||
143 | } __attribute__((packed)); | 183 | } __attribute__((packed)); |
144 | 184 | ||
145 | /* | 185 | /* |
@@ -383,7 +423,7 @@ struct snd_soc_tplg_pcm { | |||
383 | __le32 size; /* in bytes of this structure */ | 423 | __le32 size; /* in bytes of this structure */ |
384 | char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | 424 | char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
385 | char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | 425 | char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
386 | __le32 pcm_id; /* unique ID - used to match */ | 426 | __le32 pcm_id; /* unique ID - used to match with DAI link */ |
387 | __le32 dai_id; /* unique ID - used to match */ | 427 | __le32 dai_id; /* unique ID - used to match */ |
388 | __le32 playback; /* supports playback mode */ | 428 | __le32 playback; /* supports playback mode */ |
389 | __le32 capture; /* supports capture mode */ | 429 | __le32 capture; /* supports capture mode */ |
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1cf94d7fb9f4..ee7f15aa46fc 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c | |||
@@ -1023,6 +1023,11 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, | |||
1023 | 1023 | ||
1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; | 1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; |
1025 | 1025 | ||
1026 | if (control_hdr->size != sizeof(*control_hdr)) { | ||
1027 | dev_err(tplg->dev, "ASoC: invalid control size\n"); | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1026 | switch (control_hdr->ops.info) { | 1031 | switch (control_hdr->ops.info) { |
1027 | case SND_SOC_TPLG_CTL_VOLSW: | 1032 | case SND_SOC_TPLG_CTL_VOLSW: |
1028 | case SND_SOC_TPLG_CTL_STROBE: | 1033 | case SND_SOC_TPLG_CTL_STROBE: |
@@ -1476,6 +1481,8 @@ widget: | |||
1476 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; | 1481 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; |
1477 | widget->dobj.ops = tplg->ops; | 1482 | widget->dobj.ops = tplg->ops; |
1478 | widget->dobj.index = tplg->index; | 1483 | widget->dobj.index = tplg->index; |
1484 | kfree(template.sname); | ||
1485 | kfree(template.name); | ||
1479 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); | 1486 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); |
1480 | return 0; | 1487 | return 0; |
1481 | 1488 | ||
@@ -1499,10 +1506,17 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, | |||
1499 | 1506 | ||
1500 | for (i = 0; i < count; i++) { | 1507 | for (i = 0; i < count; i++) { |
1501 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; | 1508 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; |
1509 | if (widget->size != sizeof(*widget)) { | ||
1510 | dev_err(tplg->dev, "ASoC: invalid widget size\n"); | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1502 | ret = soc_tplg_dapm_widget_create(tplg, widget); | 1514 | ret = soc_tplg_dapm_widget_create(tplg, widget); |
1503 | if (ret < 0) | 1515 | if (ret < 0) { |
1504 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", | 1516 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", |
1505 | widget->name); | 1517 | widget->name); |
1518 | return ret; | ||
1519 | } | ||
1506 | } | 1520 | } |
1507 | 1521 | ||
1508 | return 0; | 1522 | return 0; |
@@ -1586,6 +1600,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, | |||
1586 | return snd_soc_register_dai(tplg->comp, dai_drv); | 1600 | return snd_soc_register_dai(tplg->comp, dai_drv); |
1587 | } | 1601 | } |
1588 | 1602 | ||
1603 | /* create the FE DAI link */ | ||
1589 | static int soc_tplg_link_create(struct soc_tplg *tplg, | 1604 | static int soc_tplg_link_create(struct soc_tplg *tplg, |
1590 | struct snd_soc_tplg_pcm *pcm) | 1605 | struct snd_soc_tplg_pcm *pcm) |
1591 | { | 1606 | { |
@@ -1598,6 +1613,16 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, | |||
1598 | 1613 | ||
1599 | link->name = pcm->pcm_name; | 1614 | link->name = pcm->pcm_name; |
1600 | link->stream_name = pcm->pcm_name; | 1615 | link->stream_name = pcm->pcm_name; |
1616 | link->id = pcm->pcm_id; | ||
1617 | |||
1618 | link->cpu_dai_name = pcm->dai_name; | ||
1619 | link->codec_name = "snd-soc-dummy"; | ||
1620 | link->codec_dai_name = "snd-soc-dummy-dai"; | ||
1621 | |||
1622 | /* enable DPCM */ | ||
1623 | link->dynamic = 1; | ||
1624 | link->dpcm_playback = pcm->playback; | ||
1625 | link->dpcm_capture = pcm->capture; | ||
1601 | 1626 | ||
1602 | /* pass control to component driver for optional further init */ | 1627 | /* pass control to component driver for optional further init */ |
1603 | ret = soc_tplg_dai_link_load(tplg, link); | 1628 | ret = soc_tplg_dai_link_load(tplg, link); |
@@ -1639,8 +1664,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1639 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) | 1664 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) |
1640 | return 0; | 1665 | return 0; |
1641 | 1666 | ||
1642 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1643 | |||
1644 | if (soc_tplg_check_elem_count(tplg, | 1667 | if (soc_tplg_check_elem_count(tplg, |
1645 | sizeof(struct snd_soc_tplg_pcm), count, | 1668 | sizeof(struct snd_soc_tplg_pcm), count, |
1646 | hdr->payload_size, "PCM DAI")) { | 1669 | hdr->payload_size, "PCM DAI")) { |
@@ -1650,7 +1673,13 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1650 | } | 1673 | } |
1651 | 1674 | ||
1652 | /* create the FE DAIs and DAI links */ | 1675 | /* create the FE DAIs and DAI links */ |
1676 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1653 | for (i = 0; i < count; i++) { | 1677 | for (i = 0; i < count; i++) { |
1678 | if (pcm->size != sizeof(*pcm)) { | ||
1679 | dev_err(tplg->dev, "ASoC: invalid pcm size\n"); | ||
1680 | return -EINVAL; | ||
1681 | } | ||
1682 | |||
1654 | soc_tplg_pcm_create(tplg, pcm); | 1683 | soc_tplg_pcm_create(tplg, pcm); |
1655 | pcm++; | 1684 | pcm++; |
1656 | } | 1685 | } |
@@ -1670,6 +1699,11 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, | |||
1670 | return 0; | 1699 | return 0; |
1671 | 1700 | ||
1672 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; | 1701 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; |
1702 | if (manifest->size != sizeof(*manifest)) { | ||
1703 | dev_err(tplg->dev, "ASoC: invalid manifest size\n"); | ||
1704 | return -EINVAL; | ||
1705 | } | ||
1706 | |||
1673 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); | 1707 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); |
1674 | 1708 | ||
1675 | if (tplg->comp && tplg->ops && tplg->ops->manifest) | 1709 | if (tplg->comp && tplg->ops && tplg->ops->manifest) |
@@ -1686,6 +1720,14 @@ static int soc_valid_header(struct soc_tplg *tplg, | |||
1686 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) | 1720 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) |
1687 | return 0; | 1721 | return 0; |
1688 | 1722 | ||
1723 | if (hdr->size != sizeof(*hdr)) { | ||
1724 | dev_err(tplg->dev, | ||
1725 | "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", | ||
1726 | hdr->type, soc_tplg_get_hdr_offset(tplg), | ||
1727 | tplg->fw->size); | ||
1728 | return -EINVAL; | ||
1729 | } | ||
1730 | |||
1689 | /* big endian firmware objects not supported atm */ | 1731 | /* big endian firmware objects not supported atm */ |
1690 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { | 1732 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { |
1691 | dev_err(tplg->dev, | 1733 | dev_err(tplg->dev, |