blob: 0f1c8ebf8cda40b84141a34e28a3cac45640e286 [file] [log] [blame]
Liam Girdwood8a978232015-05-29 19:06:14 +01001/*
2 * soc-topology.c -- ALSA SoC Topology
3 *
4 * Copyright (C) 2012 Texas Instruments Inc.
5 * Copyright (C) 2015 Intel Corporation.
6 *
7 * Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
8 * K, Mythri P <mythri.p.k@intel.com>
9 * Prusty, Subhransu S <subhransu.s.prusty@intel.com>
10 * B, Jayachandran <jayachandran.b@intel.com>
11 * Abdullah, Omair M <omair.m.abdullah@intel.com>
12 * Jin, Yao <yao.jin@intel.com>
13 * Lin, Mengdong <mengdong.lin@intel.com>
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version.
19 *
20 * Add support to read audio firmware topology alongside firmware text. The
21 * topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
22 * equalizers, firmware, coefficients etc.
23 *
24 * This file only manages the core ALSA and ASoC components, all other bespoke
25 * firmware topology data is passed to component drivers for bespoke handling.
26 */
27
28#include <linux/kernel.h>
29#include <linux/export.h>
30#include <linux/list.h>
31#include <linux/firmware.h>
32#include <linux/slab.h>
33#include <sound/soc.h>
34#include <sound/soc-dapm.h>
35#include <sound/soc-topology.h>
Mengdong Lin28a87ee2015-08-05 14:41:13 +010036#include <sound/tlv.h>
Liam Girdwood8a978232015-05-29 19:06:14 +010037
38/*
39 * We make several passes over the data (since it wont necessarily be ordered)
40 * and process objects in the following order. This guarantees the component
41 * drivers will be ready with any vendor data before the mixers and DAPM objects
42 * are loaded (that may make use of the vendor data).
43 */
44#define SOC_TPLG_PASS_MANIFEST 0
45#define SOC_TPLG_PASS_VENDOR 1
46#define SOC_TPLG_PASS_MIXER 2
47#define SOC_TPLG_PASS_WIDGET 3
Mengdong Lin1a8e7fa2015-08-10 22:48:30 +080048#define SOC_TPLG_PASS_PCM_DAI 4
49#define SOC_TPLG_PASS_GRAPH 5
50#define SOC_TPLG_PASS_PINS 6
Mengdong Lin0038be92016-07-26 14:32:37 +080051#define SOC_TPLG_PASS_BE_DAI 7
Liam Girdwood8a978232015-05-29 19:06:14 +010052
53#define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST
Mengdong Lin0038be92016-07-26 14:32:37 +080054#define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI
Liam Girdwood8a978232015-05-29 19:06:14 +010055
Mengdong Lin583958f2016-10-11 14:36:42 +080056/*
57 * Old version of ABI structs, supported for backward compatibility.
58 */
59
60/* Manifest v4 */
61struct snd_soc_tplg_manifest_v4 {
62 __le32 size; /* in bytes of this structure */
63 __le32 control_elems; /* number of control elements */
64 __le32 widget_elems; /* number of widget elements */
65 __le32 graph_elems; /* number of graph elements */
66 __le32 pcm_elems; /* number of PCM elements */
67 __le32 dai_link_elems; /* number of DAI link elements */
68 struct snd_soc_tplg_private priv;
69} __packed;
70
Mengdong Lin55726dc2016-11-03 01:00:16 +080071/* Stream Capabilities v4 */
72struct snd_soc_tplg_stream_caps_v4 {
73 __le32 size; /* in bytes of this structure */
74 char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
75 __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */
76 __le32 rates; /* supported rates SNDRV_PCM_RATE_* */
77 __le32 rate_min; /* min rate */
78 __le32 rate_max; /* max rate */
79 __le32 channels_min; /* min channels */
80 __le32 channels_max; /* max channels */
81 __le32 periods_min; /* min number of periods */
82 __le32 periods_max; /* max number of periods */
83 __le32 period_size_min; /* min period size bytes */
84 __le32 period_size_max; /* max period size bytes */
85 __le32 buffer_size_min; /* min buffer size bytes */
86 __le32 buffer_size_max; /* max buffer size bytes */
87} __packed;
88
89/* PCM v4 */
90struct snd_soc_tplg_pcm_v4 {
91 __le32 size; /* in bytes of this structure */
92 char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
93 char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
94 __le32 pcm_id; /* unique ID - used to match with DAI link */
95 __le32 dai_id; /* unique ID - used to match */
96 __le32 playback; /* supports playback mode */
97 __le32 capture; /* supports capture mode */
98 __le32 compress; /* 1 = compressed; 0 = PCM */
99 struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */
100 __le32 num_streams; /* number of streams */
101 struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */
102} __packed;
103
Mengdong Lin583958f2016-10-11 14:36:42 +0800104/* topology context */
Liam Girdwood8a978232015-05-29 19:06:14 +0100105struct soc_tplg {
106 const struct firmware *fw;
107
108 /* runtime FW parsing */
109 const u8 *pos; /* read postion */
110 const u8 *hdr_pos; /* header position */
111 unsigned int pass; /* pass number */
112
113 /* component caller */
114 struct device *dev;
115 struct snd_soc_component *comp;
116 u32 index; /* current block index */
117 u32 req_index; /* required index, only loaded/free matching blocks */
118
Mengdong Lin88a17d82015-08-18 18:11:51 +0800119 /* vendor specific kcontrol operations */
Liam Girdwood8a978232015-05-29 19:06:14 +0100120 const struct snd_soc_tplg_kcontrol_ops *io_ops;
121 int io_ops_count;
122
Mengdong Lin1a3232d2015-08-18 18:12:20 +0800123 /* vendor specific bytes ext handlers, for TLV bytes controls */
124 const struct snd_soc_tplg_bytes_ext_ops *bytes_ext_ops;
125 int bytes_ext_ops_count;
126
Liam Girdwood8a978232015-05-29 19:06:14 +0100127 /* optional fw loading callbacks to component drivers */
128 struct snd_soc_tplg_ops *ops;
129};
130
131static int soc_tplg_process_headers(struct soc_tplg *tplg);
132static void soc_tplg_complete(struct soc_tplg *tplg);
133struct snd_soc_dapm_widget *
134snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
135 const struct snd_soc_dapm_widget *widget);
136struct snd_soc_dapm_widget *
137snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
138 const struct snd_soc_dapm_widget *widget);
139
140/* check we dont overflow the data for this control chunk */
141static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
142 unsigned int count, size_t bytes, const char *elem_type)
143{
144 const u8 *end = tplg->pos + elem_size * count;
145
146 if (end > tplg->fw->data + tplg->fw->size) {
147 dev_err(tplg->dev, "ASoC: %s overflow end of data\n",
148 elem_type);
149 return -EINVAL;
150 }
151
152 /* check there is enough room in chunk for control.
153 extra bytes at the end of control are for vendor data here */
154 if (elem_size * count > bytes) {
155 dev_err(tplg->dev,
156 "ASoC: %s count %d of size %zu is bigger than chunk %zu\n",
157 elem_type, count, elem_size, bytes);
158 return -EINVAL;
159 }
160
161 return 0;
162}
163
164static inline int soc_tplg_is_eof(struct soc_tplg *tplg)
165{
166 const u8 *end = tplg->hdr_pos;
167
168 if (end >= tplg->fw->data + tplg->fw->size)
169 return 1;
170 return 0;
171}
172
173static inline unsigned long soc_tplg_get_hdr_offset(struct soc_tplg *tplg)
174{
175 return (unsigned long)(tplg->hdr_pos - tplg->fw->data);
176}
177
178static inline unsigned long soc_tplg_get_offset(struct soc_tplg *tplg)
179{
180 return (unsigned long)(tplg->pos - tplg->fw->data);
181}
182
183/* mapping of Kcontrol types and associated operations. */
184static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
185 {SND_SOC_TPLG_CTL_VOLSW, snd_soc_get_volsw,
186 snd_soc_put_volsw, snd_soc_info_volsw},
187 {SND_SOC_TPLG_CTL_VOLSW_SX, snd_soc_get_volsw_sx,
188 snd_soc_put_volsw_sx, NULL},
189 {SND_SOC_TPLG_CTL_ENUM, snd_soc_get_enum_double,
190 snd_soc_put_enum_double, snd_soc_info_enum_double},
191 {SND_SOC_TPLG_CTL_ENUM_VALUE, snd_soc_get_enum_double,
192 snd_soc_put_enum_double, NULL},
193 {SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get,
194 snd_soc_bytes_put, snd_soc_bytes_info},
195 {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range,
196 snd_soc_put_volsw_range, snd_soc_info_volsw_range},
197 {SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx,
198 snd_soc_put_xr_sx, snd_soc_info_xr_sx},
199 {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
200 snd_soc_put_strobe, NULL},
201 {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw,
Jeeja KP2c57d4782015-07-14 13:10:47 +0530202 snd_soc_dapm_put_volsw, snd_soc_info_volsw},
Liam Girdwood8a978232015-05-29 19:06:14 +0100203 {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double,
204 snd_soc_dapm_put_enum_double, snd_soc_info_enum_double},
205 {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double,
206 snd_soc_dapm_put_enum_double, NULL},
207 {SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE, snd_soc_dapm_get_enum_double,
208 snd_soc_dapm_put_enum_double, NULL},
209 {SND_SOC_TPLG_DAPM_CTL_PIN, snd_soc_dapm_get_pin_switch,
210 snd_soc_dapm_put_pin_switch, snd_soc_dapm_info_pin_switch},
211};
212
213struct soc_tplg_map {
214 int uid;
215 int kid;
216};
217
218/* mapping of widget types from UAPI IDs to kernel IDs */
219static const struct soc_tplg_map dapm_map[] = {
220 {SND_SOC_TPLG_DAPM_INPUT, snd_soc_dapm_input},
221 {SND_SOC_TPLG_DAPM_OUTPUT, snd_soc_dapm_output},
222 {SND_SOC_TPLG_DAPM_MUX, snd_soc_dapm_mux},
223 {SND_SOC_TPLG_DAPM_MIXER, snd_soc_dapm_mixer},
224 {SND_SOC_TPLG_DAPM_PGA, snd_soc_dapm_pga},
225 {SND_SOC_TPLG_DAPM_OUT_DRV, snd_soc_dapm_out_drv},
226 {SND_SOC_TPLG_DAPM_ADC, snd_soc_dapm_adc},
227 {SND_SOC_TPLG_DAPM_DAC, snd_soc_dapm_dac},
228 {SND_SOC_TPLG_DAPM_SWITCH, snd_soc_dapm_switch},
229 {SND_SOC_TPLG_DAPM_PRE, snd_soc_dapm_pre},
230 {SND_SOC_TPLG_DAPM_POST, snd_soc_dapm_post},
231 {SND_SOC_TPLG_DAPM_AIF_IN, snd_soc_dapm_aif_in},
232 {SND_SOC_TPLG_DAPM_AIF_OUT, snd_soc_dapm_aif_out},
233 {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in},
234 {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out},
235 {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link},
236};
237
238static int tplc_chan_get_reg(struct soc_tplg *tplg,
239 struct snd_soc_tplg_channel *chan, int map)
240{
241 int i;
242
243 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
244 if (chan[i].id == map)
245 return chan[i].reg;
246 }
247
248 return -EINVAL;
249}
250
251static int tplc_chan_get_shift(struct soc_tplg *tplg,
252 struct snd_soc_tplg_channel *chan, int map)
253{
254 int i;
255
256 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
257 if (chan[i].id == map)
258 return chan[i].shift;
259 }
260
261 return -EINVAL;
262}
263
264static int get_widget_id(int tplg_type)
265{
266 int i;
267
268 for (i = 0; i < ARRAY_SIZE(dapm_map); i++) {
269 if (tplg_type == dapm_map[i].uid)
270 return dapm_map[i].kid;
271 }
272
273 return -EINVAL;
274}
275
Liam Girdwood8a978232015-05-29 19:06:14 +0100276static inline void soc_bind_err(struct soc_tplg *tplg,
277 struct snd_soc_tplg_ctl_hdr *hdr, int index)
278{
279 dev_err(tplg->dev,
280 "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n",
281 hdr->ops.get, hdr->ops.put, hdr->ops.info, index,
282 soc_tplg_get_offset(tplg));
283}
284
285static inline void soc_control_err(struct soc_tplg *tplg,
286 struct snd_soc_tplg_ctl_hdr *hdr, const char *name)
287{
288 dev_err(tplg->dev,
289 "ASoC: no complete mixer IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n",
290 name, hdr->ops.get, hdr->ops.put, hdr->ops.info,
291 soc_tplg_get_offset(tplg));
292}
293
294/* pass vendor data to component driver for processing */
295static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
296 struct snd_soc_tplg_hdr *hdr)
297{
298 int ret = 0;
299
300 if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
301 ret = tplg->ops->vendor_load(tplg->comp, hdr);
302 else {
303 dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
304 hdr->vendor_type);
305 return -EINVAL;
306 }
307
308 if (ret < 0)
309 dev_err(tplg->dev,
310 "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %d:%d\n",
311 soc_tplg_get_hdr_offset(tplg),
312 soc_tplg_get_hdr_offset(tplg),
313 hdr->type, hdr->vendor_type);
314 return ret;
315}
316
317/* pass vendor data to component driver for processing */
318static int soc_tplg_vendor_load(struct soc_tplg *tplg,
319 struct snd_soc_tplg_hdr *hdr)
320{
321 if (tplg->pass != SOC_TPLG_PASS_VENDOR)
322 return 0;
323
324 return soc_tplg_vendor_load_(tplg, hdr);
325}
326
327/* optionally pass new dynamic widget to component driver. This is mainly for
328 * external widgets where we can assign private data/ops */
329static int soc_tplg_widget_load(struct soc_tplg *tplg,
330 struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
331{
332 if (tplg->comp && tplg->ops && tplg->ops->widget_load)
333 return tplg->ops->widget_load(tplg->comp, w, tplg_w);
334
335 return 0;
336}
337
Mengdong Lin64527e82016-01-15 16:13:28 +0800338/* pass DAI configurations to component driver for extra intialization */
339static int soc_tplg_dai_load(struct soc_tplg *tplg,
340 struct snd_soc_dai_driver *dai_drv)
Liam Girdwood8a978232015-05-29 19:06:14 +0100341{
Mengdong Lin64527e82016-01-15 16:13:28 +0800342 if (tplg->comp && tplg->ops && tplg->ops->dai_load)
343 return tplg->ops->dai_load(tplg->comp, dai_drv);
Liam Girdwood8a978232015-05-29 19:06:14 +0100344
345 return 0;
346}
347
Mengdong Linacfc7d42016-01-15 16:13:37 +0800348/* pass link configurations to component driver for extra intialization */
349static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
350 struct snd_soc_dai_link *link)
351{
352 if (tplg->comp && tplg->ops && tplg->ops->link_load)
353 return tplg->ops->link_load(tplg->comp, link);
354
355 return 0;
356}
357
Liam Girdwood8a978232015-05-29 19:06:14 +0100358/* tell the component driver that all firmware has been loaded in this request */
359static void soc_tplg_complete(struct soc_tplg *tplg)
360{
361 if (tplg->comp && tplg->ops && tplg->ops->complete)
362 tplg->ops->complete(tplg->comp);
363}
364
365/* add a dynamic kcontrol */
366static int soc_tplg_add_dcontrol(struct snd_card *card, struct device *dev,
367 const struct snd_kcontrol_new *control_new, const char *prefix,
368 void *data, struct snd_kcontrol **kcontrol)
369{
370 int err;
371
372 *kcontrol = snd_soc_cnew(control_new, data, control_new->name, prefix);
373 if (*kcontrol == NULL) {
374 dev_err(dev, "ASoC: Failed to create new kcontrol %s\n",
375 control_new->name);
376 return -ENOMEM;
377 }
378
379 err = snd_ctl_add(card, *kcontrol);
380 if (err < 0) {
381 dev_err(dev, "ASoC: Failed to add %s: %d\n",
382 control_new->name, err);
383 return err;
384 }
385
386 return 0;
387}
388
389/* add a dynamic kcontrol for component driver */
390static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
391 struct snd_kcontrol_new *k, struct snd_kcontrol **kcontrol)
392{
393 struct snd_soc_component *comp = tplg->comp;
394
395 return soc_tplg_add_dcontrol(comp->card->snd_card,
396 comp->dev, k, NULL, comp, kcontrol);
397}
398
399/* remove a mixer kcontrol */
400static void remove_mixer(struct snd_soc_component *comp,
401 struct snd_soc_dobj *dobj, int pass)
402{
403 struct snd_card *card = comp->card->snd_card;
404 struct soc_mixer_control *sm =
405 container_of(dobj, struct soc_mixer_control, dobj);
406 const unsigned int *p = NULL;
407
408 if (pass != SOC_TPLG_PASS_MIXER)
409 return;
410
411 if (dobj->ops && dobj->ops->control_unload)
412 dobj->ops->control_unload(comp, dobj);
413
414 if (sm->dobj.control.kcontrol->tlv.p)
415 p = sm->dobj.control.kcontrol->tlv.p;
416 snd_ctl_remove(card, sm->dobj.control.kcontrol);
417 list_del(&sm->dobj.list);
418 kfree(sm);
419 kfree(p);
420}
421
422/* remove an enum kcontrol */
423static void remove_enum(struct snd_soc_component *comp,
424 struct snd_soc_dobj *dobj, int pass)
425{
426 struct snd_card *card = comp->card->snd_card;
427 struct soc_enum *se = container_of(dobj, struct soc_enum, dobj);
428 int i;
429
430 if (pass != SOC_TPLG_PASS_MIXER)
431 return;
432
433 if (dobj->ops && dobj->ops->control_unload)
434 dobj->ops->control_unload(comp, dobj);
435
436 snd_ctl_remove(card, se->dobj.control.kcontrol);
437 list_del(&se->dobj.list);
438
439 kfree(se->dobj.control.dvalues);
440 for (i = 0; i < se->items; i++)
441 kfree(se->dobj.control.dtexts[i]);
442 kfree(se);
443}
444
445/* remove a byte kcontrol */
446static void remove_bytes(struct snd_soc_component *comp,
447 struct snd_soc_dobj *dobj, int pass)
448{
449 struct snd_card *card = comp->card->snd_card;
450 struct soc_bytes_ext *sb =
451 container_of(dobj, struct soc_bytes_ext, dobj);
452
453 if (pass != SOC_TPLG_PASS_MIXER)
454 return;
455
456 if (dobj->ops && dobj->ops->control_unload)
457 dobj->ops->control_unload(comp, dobj);
458
459 snd_ctl_remove(card, sb->dobj.control.kcontrol);
460 list_del(&sb->dobj.list);
461 kfree(sb);
462}
463
464/* remove a widget and it's kcontrols - routes must be removed first */
465static void remove_widget(struct snd_soc_component *comp,
466 struct snd_soc_dobj *dobj, int pass)
467{
468 struct snd_card *card = comp->card->snd_card;
469 struct snd_soc_dapm_widget *w =
470 container_of(dobj, struct snd_soc_dapm_widget, dobj);
471 int i;
472
473 if (pass != SOC_TPLG_PASS_WIDGET)
474 return;
475
476 if (dobj->ops && dobj->ops->widget_unload)
477 dobj->ops->widget_unload(comp, dobj);
478
479 /*
480 * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers.
481 * The enum may either have an array of values or strings.
482 */
483 if (dobj->widget.kcontrol_enum) {
484 /* enumerated widget mixer */
485 struct soc_enum *se =
486 (struct soc_enum *)w->kcontrols[0]->private_value;
487
488 snd_ctl_remove(card, w->kcontrols[0]);
489
490 kfree(se->dobj.control.dvalues);
491 for (i = 0; i < se->items; i++)
492 kfree(se->dobj.control.dtexts[i]);
493
494 kfree(se);
495 kfree(w->kcontrol_news);
496 } else {
497 /* non enumerated widget mixer */
498 for (i = 0; i < w->num_kcontrols; i++) {
499 struct snd_kcontrol *kcontrol = w->kcontrols[i];
500 struct soc_mixer_control *sm =
501 (struct soc_mixer_control *) kcontrol->private_value;
502
503 kfree(w->kcontrols[i]->tlv.p);
504
505 snd_ctl_remove(card, w->kcontrols[i]);
506 kfree(sm);
507 }
508 kfree(w->kcontrol_news);
509 }
510 /* widget w is freed by soc-dapm.c */
511}
512
Mengdong Lin64527e82016-01-15 16:13:28 +0800513/* remove DAI configurations */
514static void remove_dai(struct snd_soc_component *comp,
Liam Girdwood8a978232015-05-29 19:06:14 +0100515 struct snd_soc_dobj *dobj, int pass)
516{
Mengdong Lin64527e82016-01-15 16:13:28 +0800517 struct snd_soc_dai_driver *dai_drv =
518 container_of(dobj, struct snd_soc_dai_driver, dobj);
519
Liam Girdwood8a978232015-05-29 19:06:14 +0100520 if (pass != SOC_TPLG_PASS_PCM_DAI)
521 return;
522
Mengdong Lin64527e82016-01-15 16:13:28 +0800523 if (dobj->ops && dobj->ops->dai_unload)
524 dobj->ops->dai_unload(comp, dobj);
Liam Girdwood8a978232015-05-29 19:06:14 +0100525
Mengdong Lin8f27c4a2016-11-03 01:02:59 +0800526 kfree(dai_drv->name);
Liam Girdwood8a978232015-05-29 19:06:14 +0100527 list_del(&dobj->list);
Mengdong Lin64527e82016-01-15 16:13:28 +0800528 kfree(dai_drv);
Liam Girdwood8a978232015-05-29 19:06:14 +0100529}
530
Mengdong Linacfc7d42016-01-15 16:13:37 +0800531/* remove link configurations */
532static void remove_link(struct snd_soc_component *comp,
533 struct snd_soc_dobj *dobj, int pass)
534{
535 struct snd_soc_dai_link *link =
536 container_of(dobj, struct snd_soc_dai_link, dobj);
537
538 if (pass != SOC_TPLG_PASS_PCM_DAI)
539 return;
540
541 if (dobj->ops && dobj->ops->link_unload)
542 dobj->ops->link_unload(comp, dobj);
543
Mengdong Lin8f27c4a2016-11-03 01:02:59 +0800544 kfree(link->name);
545 kfree(link->stream_name);
546 kfree(link->cpu_dai_name);
547
Mengdong Linacfc7d42016-01-15 16:13:37 +0800548 list_del(&dobj->list);
549 snd_soc_remove_dai_link(comp->card, link);
550 kfree(link);
551}
552
Liam Girdwood8a978232015-05-29 19:06:14 +0100553/* bind a kcontrol to it's IO handlers */
554static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
555 struct snd_kcontrol_new *k,
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800556 const struct soc_tplg *tplg)
Liam Girdwood8a978232015-05-29 19:06:14 +0100557{
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800558 const struct snd_soc_tplg_kcontrol_ops *ops;
Mengdong Lin1a3232d2015-08-18 18:12:20 +0800559 const struct snd_soc_tplg_bytes_ext_ops *ext_ops;
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800560 int num_ops, i;
Liam Girdwood8a978232015-05-29 19:06:14 +0100561
Mengdong Lin1a3232d2015-08-18 18:12:20 +0800562 if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES
563 && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER
564 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
565 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
566 struct soc_bytes_ext *sbe;
567 struct snd_soc_tplg_bytes_control *be;
568
569 sbe = (struct soc_bytes_ext *)k->private_value;
570 be = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr);
571
572 /* TLV bytes controls need standard kcontrol info handler,
573 * TLV callback and extended put/get handlers.
574 */
Omair M Abdullahf4be9782015-11-09 23:20:01 +0530575 k->info = snd_soc_bytes_info_ext;
Mengdong Lin1a3232d2015-08-18 18:12:20 +0800576 k->tlv.c = snd_soc_bytes_tlv_callback;
577
578 ext_ops = tplg->bytes_ext_ops;
579 num_ops = tplg->bytes_ext_ops_count;
580 for (i = 0; i < num_ops; i++) {
581 if (!sbe->put && ext_ops[i].id == be->ext_ops.put)
582 sbe->put = ext_ops[i].put;
583 if (!sbe->get && ext_ops[i].id == be->ext_ops.get)
584 sbe->get = ext_ops[i].get;
585 }
586
587 if (sbe->put && sbe->get)
588 return 0;
589 else
590 return -EINVAL;
591 }
592
Mengdong Lin88a17d82015-08-18 18:11:51 +0800593 /* try and map vendor specific kcontrol handlers first */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800594 ops = tplg->io_ops;
595 num_ops = tplg->io_ops_count;
Liam Girdwood8a978232015-05-29 19:06:14 +0100596 for (i = 0; i < num_ops; i++) {
597
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800598 if (k->put == NULL && ops[i].id == hdr->ops.put)
Liam Girdwood8a978232015-05-29 19:06:14 +0100599 k->put = ops[i].put;
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800600 if (k->get == NULL && ops[i].id == hdr->ops.get)
Liam Girdwood8a978232015-05-29 19:06:14 +0100601 k->get = ops[i].get;
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800602 if (k->info == NULL && ops[i].id == hdr->ops.info)
603 k->info = ops[i].info;
Liam Girdwood8a978232015-05-29 19:06:14 +0100604 }
605
Mengdong Lin88a17d82015-08-18 18:11:51 +0800606 /* vendor specific handlers found ? */
607 if (k->put && k->get && k->info)
608 return 0;
609
610 /* none found so try standard kcontrol handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800611 ops = io_ops;
612 num_ops = ARRAY_SIZE(io_ops);
Mengdong Lin88a17d82015-08-18 18:11:51 +0800613 for (i = 0; i < num_ops; i++) {
614
615 if (k->put == NULL && ops[i].id == hdr->ops.put)
616 k->put = ops[i].put;
617 if (k->get == NULL && ops[i].id == hdr->ops.get)
618 k->get = ops[i].get;
619 if (k->info == NULL && ops[i].id == hdr->ops.info)
Liam Girdwood8a978232015-05-29 19:06:14 +0100620 k->info = ops[i].info;
621 }
622
623 /* standard handlers found ? */
624 if (k->put && k->get && k->info)
625 return 0;
626
Liam Girdwood8a978232015-05-29 19:06:14 +0100627 /* nothing to bind */
628 return -EINVAL;
629}
630
631/* bind a widgets to it's evnt handlers */
632int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
633 const struct snd_soc_tplg_widget_events *events,
634 int num_events, u16 event_type)
635{
636 int i;
637
638 w->event = NULL;
639
640 for (i = 0; i < num_events; i++) {
641 if (event_type == events[i].type) {
642
643 /* found - so assign event */
644 w->event = events[i].event_handler;
645 return 0;
646 }
647 }
648
649 /* not found */
650 return -EINVAL;
651}
652EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event);
653
654/* optionally pass new dynamic kcontrol to component driver. */
655static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
656 struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
657{
658 if (tplg->comp && tplg->ops && tplg->ops->control_load)
659 return tplg->ops->control_load(tplg->comp, k, hdr);
660
661 return 0;
662}
663
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100664
665static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
666 struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
Liam Girdwood8a978232015-05-29 19:06:14 +0100667{
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100668 unsigned int item_len = 2 * sizeof(unsigned int);
669 unsigned int *p;
Liam Girdwood8a978232015-05-29 19:06:14 +0100670
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100671 p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
672 if (!p)
Liam Girdwood8a978232015-05-29 19:06:14 +0100673 return -ENOMEM;
674
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100675 p[0] = SNDRV_CTL_TLVT_DB_SCALE;
676 p[1] = item_len;
677 p[2] = scale->min;
678 p[3] = (scale->step & TLV_DB_SCALE_MASK)
679 | (scale->mute ? TLV_DB_SCALE_MUTE : 0);
Liam Girdwood8a978232015-05-29 19:06:14 +0100680
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100681 kc->tlv.p = (void *)p;
682 return 0;
683}
684
685static int soc_tplg_create_tlv(struct soc_tplg *tplg,
686 struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
687{
688 struct snd_soc_tplg_ctl_tlv *tplg_tlv;
689
690 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
691 return 0;
692
Mengdong Lin1a3232d2015-08-18 18:12:20 +0800693 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100694 tplg_tlv = &tc->tlv;
695 switch (tplg_tlv->type) {
696 case SNDRV_CTL_TLVT_DB_SCALE:
697 return soc_tplg_create_tlv_db_scale(tplg, kc,
698 &tplg_tlv->scale);
699
700 /* TODO: add support for other TLV types */
701 default:
702 dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
703 tplg_tlv->type);
704 return -EINVAL;
705 }
706 }
Liam Girdwood8a978232015-05-29 19:06:14 +0100707
708 return 0;
709}
710
711static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
712 struct snd_kcontrol_new *kc)
713{
714 kfree(kc->tlv.p);
715}
716
717static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
718 size_t size)
719{
720 struct snd_soc_tplg_bytes_control *be;
721 struct soc_bytes_ext *sbe;
722 struct snd_kcontrol_new kc;
723 int i, err;
724
725 if (soc_tplg_check_elem_count(tplg,
726 sizeof(struct snd_soc_tplg_bytes_control), count,
727 size, "mixer bytes")) {
728 dev_err(tplg->dev, "ASoC: Invalid count %d for byte control\n",
729 count);
730 return -EINVAL;
731 }
732
733 for (i = 0; i < count; i++) {
734 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
735
736 /* validate kcontrol */
737 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
738 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
739 return -EINVAL;
740
741 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
742 if (sbe == NULL)
743 return -ENOMEM;
744
745 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
746 be->priv.size);
747
748 dev_dbg(tplg->dev,
749 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
750 be->hdr.name, be->hdr.access);
751
752 memset(&kc, 0, sizeof(kc));
753 kc.name = be->hdr.name;
754 kc.private_value = (long)sbe;
755 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
756 kc.access = be->hdr.access;
757
758 sbe->max = be->max;
759 sbe->dobj.type = SND_SOC_DOBJ_BYTES;
760 sbe->dobj.ops = tplg->ops;
761 INIT_LIST_HEAD(&sbe->dobj.list);
762
763 /* map io handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800764 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +0100765 if (err) {
766 soc_control_err(tplg, &be->hdr, be->hdr.name);
767 kfree(sbe);
768 continue;
769 }
770
771 /* pass control to driver for optional further init */
772 err = soc_tplg_init_kcontrol(tplg, &kc,
773 (struct snd_soc_tplg_ctl_hdr *)be);
774 if (err < 0) {
775 dev_err(tplg->dev, "ASoC: failed to init %s\n",
776 be->hdr.name);
777 kfree(sbe);
778 continue;
779 }
780
781 /* register control here */
782 err = soc_tplg_add_kcontrol(tplg, &kc,
783 &sbe->dobj.control.kcontrol);
784 if (err < 0) {
785 dev_err(tplg->dev, "ASoC: failed to add %s\n",
786 be->hdr.name);
787 kfree(sbe);
788 continue;
789 }
790
791 list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
792 }
793 return 0;
794
795}
796
797static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
798 size_t size)
799{
800 struct snd_soc_tplg_mixer_control *mc;
801 struct soc_mixer_control *sm;
802 struct snd_kcontrol_new kc;
803 int i, err;
804
805 if (soc_tplg_check_elem_count(tplg,
806 sizeof(struct snd_soc_tplg_mixer_control),
807 count, size, "mixers")) {
808
809 dev_err(tplg->dev, "ASoC: invalid count %d for controls\n",
810 count);
811 return -EINVAL;
812 }
813
814 for (i = 0; i < count; i++) {
815 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
816
817 /* validate kcontrol */
818 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
819 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
820 return -EINVAL;
821
822 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
823 if (sm == NULL)
824 return -ENOMEM;
825 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
826 mc->priv.size);
827
828 dev_dbg(tplg->dev,
829 "ASoC: adding mixer kcontrol %s with access 0x%x\n",
830 mc->hdr.name, mc->hdr.access);
831
832 memset(&kc, 0, sizeof(kc));
833 kc.name = mc->hdr.name;
834 kc.private_value = (long)sm;
835 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
836 kc.access = mc->hdr.access;
837
838 /* we only support FL/FR channel mapping atm */
839 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
840 SNDRV_CHMAP_FL);
841 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
842 SNDRV_CHMAP_FR);
843 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
844 SNDRV_CHMAP_FL);
845 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
846 SNDRV_CHMAP_FR);
847
848 sm->max = mc->max;
849 sm->min = mc->min;
850 sm->invert = mc->invert;
851 sm->platform_max = mc->platform_max;
852 sm->dobj.index = tplg->index;
853 sm->dobj.ops = tplg->ops;
854 sm->dobj.type = SND_SOC_DOBJ_MIXER;
855 INIT_LIST_HEAD(&sm->dobj.list);
856
857 /* map io handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +0800858 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +0100859 if (err) {
860 soc_control_err(tplg, &mc->hdr, mc->hdr.name);
861 kfree(sm);
862 continue;
863 }
864
865 /* pass control to driver for optional further init */
866 err = soc_tplg_init_kcontrol(tplg, &kc,
867 (struct snd_soc_tplg_ctl_hdr *) mc);
868 if (err < 0) {
869 dev_err(tplg->dev, "ASoC: failed to init %s\n",
870 mc->hdr.name);
871 kfree(sm);
872 continue;
873 }
874
875 /* create any TLV data */
Mengdong Lin28a87ee2015-08-05 14:41:13 +0100876 soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
Liam Girdwood8a978232015-05-29 19:06:14 +0100877
878 /* register control here */
879 err = soc_tplg_add_kcontrol(tplg, &kc,
880 &sm->dobj.control.kcontrol);
881 if (err < 0) {
882 dev_err(tplg->dev, "ASoC: failed to add %s\n",
883 mc->hdr.name);
884 soc_tplg_free_tlv(tplg, &kc);
885 kfree(sm);
886 continue;
887 }
888
889 list_add(&sm->dobj.list, &tplg->comp->dobj_list);
890 }
891
892 return 0;
893}
894
895static int soc_tplg_denum_create_texts(struct soc_enum *se,
896 struct snd_soc_tplg_enum_control *ec)
897{
898 int i, ret;
899
900 se->dobj.control.dtexts =
901 kzalloc(sizeof(char *) * ec->items, GFP_KERNEL);
902 if (se->dobj.control.dtexts == NULL)
903 return -ENOMEM;
904
905 for (i = 0; i < ec->items; i++) {
906
907 if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
908 SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
909 ret = -EINVAL;
910 goto err;
911 }
912
913 se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
914 if (!se->dobj.control.dtexts[i]) {
915 ret = -ENOMEM;
916 goto err;
917 }
918 }
919
920 return 0;
921
922err:
923 for (--i; i >= 0; i--)
924 kfree(se->dobj.control.dtexts[i]);
925 kfree(se->dobj.control.dtexts);
926 return ret;
927}
928
929static int soc_tplg_denum_create_values(struct soc_enum *se,
930 struct snd_soc_tplg_enum_control *ec)
931{
932 if (ec->items > sizeof(*ec->values))
933 return -EINVAL;
934
Andrzej Hajda376c0af2015-08-07 09:59:37 +0200935 se->dobj.control.dvalues = kmemdup(ec->values,
936 ec->items * sizeof(u32),
937 GFP_KERNEL);
Liam Girdwood8a978232015-05-29 19:06:14 +0100938 if (!se->dobj.control.dvalues)
939 return -ENOMEM;
940
Liam Girdwood8a978232015-05-29 19:06:14 +0100941 return 0;
942}
943
944static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
945 size_t size)
946{
947 struct snd_soc_tplg_enum_control *ec;
948 struct soc_enum *se;
949 struct snd_kcontrol_new kc;
950 int i, ret, err;
951
952 if (soc_tplg_check_elem_count(tplg,
953 sizeof(struct snd_soc_tplg_enum_control),
954 count, size, "enums")) {
955
956 dev_err(tplg->dev, "ASoC: invalid count %d for enum controls\n",
957 count);
958 return -EINVAL;
959 }
960
961 for (i = 0; i < count; i++) {
962 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
963 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
964 ec->priv.size);
965
966 /* validate kcontrol */
967 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
968 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
969 return -EINVAL;
970
971 se = kzalloc((sizeof(*se)), GFP_KERNEL);
972 if (se == NULL)
973 return -ENOMEM;
974
975 dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
976 ec->hdr.name, ec->items);
977
978 memset(&kc, 0, sizeof(kc));
979 kc.name = ec->hdr.name;
980 kc.private_value = (long)se;
981 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
982 kc.access = ec->hdr.access;
983
984 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
985 se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
986 SNDRV_CHMAP_FL);
987 se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
988 SNDRV_CHMAP_FL);
989
990 se->items = ec->items;
991 se->mask = ec->mask;
992 se->dobj.index = tplg->index;
993 se->dobj.type = SND_SOC_DOBJ_ENUM;
994 se->dobj.ops = tplg->ops;
995 INIT_LIST_HEAD(&se->dobj.list);
996
997 switch (ec->hdr.ops.info) {
998 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
999 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1000 err = soc_tplg_denum_create_values(se, ec);
1001 if (err < 0) {
1002 dev_err(tplg->dev,
1003 "ASoC: could not create values for %s\n",
1004 ec->hdr.name);
1005 kfree(se);
1006 continue;
1007 }
1008 /* fall through and create texts */
1009 case SND_SOC_TPLG_CTL_ENUM:
1010 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1011 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1012 err = soc_tplg_denum_create_texts(se, ec);
1013 if (err < 0) {
1014 dev_err(tplg->dev,
1015 "ASoC: could not create texts for %s\n",
1016 ec->hdr.name);
1017 kfree(se);
1018 continue;
1019 }
1020 break;
1021 default:
1022 dev_err(tplg->dev,
1023 "ASoC: invalid enum control type %d for %s\n",
1024 ec->hdr.ops.info, ec->hdr.name);
1025 kfree(se);
1026 continue;
1027 }
1028
1029 /* map io handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +08001030 err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +01001031 if (err) {
1032 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1033 kfree(se);
1034 continue;
1035 }
1036
1037 /* pass control to driver for optional further init */
1038 err = soc_tplg_init_kcontrol(tplg, &kc,
1039 (struct snd_soc_tplg_ctl_hdr *) ec);
1040 if (err < 0) {
1041 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1042 ec->hdr.name);
1043 kfree(se);
1044 continue;
1045 }
1046
1047 /* register control here */
1048 ret = soc_tplg_add_kcontrol(tplg,
1049 &kc, &se->dobj.control.kcontrol);
1050 if (ret < 0) {
1051 dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n",
1052 ec->hdr.name);
1053 kfree(se);
1054 continue;
1055 }
1056
1057 list_add(&se->dobj.list, &tplg->comp->dobj_list);
1058 }
1059
1060 return 0;
1061}
1062
1063static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
1064 struct snd_soc_tplg_hdr *hdr)
1065{
1066 struct snd_soc_tplg_ctl_hdr *control_hdr;
1067 int i;
1068
1069 if (tplg->pass != SOC_TPLG_PASS_MIXER) {
1070 tplg->pos += hdr->size + hdr->payload_size;
1071 return 0;
1072 }
1073
1074 dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
1075 soc_tplg_get_offset(tplg));
1076
1077 for (i = 0; i < hdr->count; i++) {
1078
1079 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1080
Mengdong Lin06eb49f2016-04-27 14:52:56 +08001081 if (control_hdr->size != sizeof(*control_hdr)) {
1082 dev_err(tplg->dev, "ASoC: invalid control size\n");
1083 return -EINVAL;
1084 }
1085
Liam Girdwood8a978232015-05-29 19:06:14 +01001086 switch (control_hdr->ops.info) {
1087 case SND_SOC_TPLG_CTL_VOLSW:
1088 case SND_SOC_TPLG_CTL_STROBE:
1089 case SND_SOC_TPLG_CTL_VOLSW_SX:
1090 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1091 case SND_SOC_TPLG_CTL_RANGE:
1092 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1093 case SND_SOC_TPLG_DAPM_CTL_PIN:
1094 soc_tplg_dmixer_create(tplg, 1, hdr->payload_size);
1095 break;
1096 case SND_SOC_TPLG_CTL_ENUM:
1097 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1098 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1099 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1100 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1101 soc_tplg_denum_create(tplg, 1, hdr->payload_size);
1102 break;
1103 case SND_SOC_TPLG_CTL_BYTES:
1104 soc_tplg_dbytes_create(tplg, 1, hdr->payload_size);
1105 break;
1106 default:
1107 soc_bind_err(tplg, control_hdr, i);
1108 return -EINVAL;
1109 }
1110 }
1111
1112 return 0;
1113}
1114
1115static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
1116 struct snd_soc_tplg_hdr *hdr)
1117{
1118 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1119 struct snd_soc_dapm_route route;
1120 struct snd_soc_tplg_dapm_graph_elem *elem;
1121 int count = hdr->count, i;
1122
1123 if (tplg->pass != SOC_TPLG_PASS_GRAPH) {
1124 tplg->pos += hdr->size + hdr->payload_size;
1125 return 0;
1126 }
1127
1128 if (soc_tplg_check_elem_count(tplg,
1129 sizeof(struct snd_soc_tplg_dapm_graph_elem),
1130 count, hdr->payload_size, "graph")) {
1131
1132 dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n",
1133 count);
1134 return -EINVAL;
1135 }
1136
1137 dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count);
1138
1139 for (i = 0; i < count; i++) {
1140 elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
1141 tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
1142
1143 /* validate routes */
1144 if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1145 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1146 return -EINVAL;
1147 if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1148 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1149 return -EINVAL;
1150 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1151 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1152 return -EINVAL;
1153
1154 route.source = elem->source;
1155 route.sink = elem->sink;
1156 route.connected = NULL; /* set to NULL atm for tplg users */
1157 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
1158 route.control = NULL;
1159 else
1160 route.control = elem->control;
1161
1162 /* add route, but keep going if some fail */
1163 snd_soc_dapm_add_routes(dapm, &route, 1);
1164 }
1165
1166 return 0;
1167}
1168
1169static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1170 struct soc_tplg *tplg, int num_kcontrols)
1171{
1172 struct snd_kcontrol_new *kc;
1173 struct soc_mixer_control *sm;
1174 struct snd_soc_tplg_mixer_control *mc;
1175 int i, err;
1176
Axel Lin4ca7deb2015-08-05 22:34:22 +08001177 kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
Liam Girdwood8a978232015-05-29 19:06:14 +01001178 if (kc == NULL)
1179 return NULL;
1180
1181 for (i = 0; i < num_kcontrols; i++) {
1182 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
1183 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
1184 if (sm == NULL)
1185 goto err;
1186
1187 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
1188 mc->priv.size);
1189
1190 /* validate kcontrol */
1191 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1192 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1193 goto err_str;
1194
1195 dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n",
1196 mc->hdr.name, i);
1197
1198 kc[i].name = mc->hdr.name;
1199 kc[i].private_value = (long)sm;
1200 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1201 kc[i].access = mc->hdr.access;
1202
1203 /* we only support FL/FR channel mapping atm */
1204 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
1205 SNDRV_CHMAP_FL);
1206 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
1207 SNDRV_CHMAP_FR);
1208 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
1209 SNDRV_CHMAP_FL);
1210 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
1211 SNDRV_CHMAP_FR);
1212
1213 sm->max = mc->max;
1214 sm->min = mc->min;
1215 sm->invert = mc->invert;
1216 sm->platform_max = mc->platform_max;
1217 sm->dobj.index = tplg->index;
1218 INIT_LIST_HEAD(&sm->dobj.list);
1219
1220 /* map io handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +08001221 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +01001222 if (err) {
1223 soc_control_err(tplg, &mc->hdr, mc->hdr.name);
1224 kfree(sm);
1225 continue;
1226 }
1227
1228 /* pass control to driver for optional further init */
1229 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1230 (struct snd_soc_tplg_ctl_hdr *)mc);
1231 if (err < 0) {
1232 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1233 mc->hdr.name);
1234 kfree(sm);
1235 continue;
1236 }
1237 }
1238 return kc;
1239
1240err_str:
1241 kfree(sm);
1242err:
1243 for (--i; i >= 0; i--)
1244 kfree((void *)kc[i].private_value);
1245 kfree(kc);
1246 return NULL;
1247}
1248
1249static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1250 struct soc_tplg *tplg)
1251{
1252 struct snd_kcontrol_new *kc;
1253 struct snd_soc_tplg_enum_control *ec;
1254 struct soc_enum *se;
1255 int i, err;
1256
1257 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1258 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1259 ec->priv.size);
1260
1261 /* validate kcontrol */
1262 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1263 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1264 return NULL;
1265
1266 kc = kzalloc(sizeof(*kc), GFP_KERNEL);
1267 if (kc == NULL)
1268 return NULL;
1269
1270 se = kzalloc(sizeof(*se), GFP_KERNEL);
1271 if (se == NULL)
1272 goto err;
1273
1274 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1275 ec->hdr.name);
1276
1277 kc->name = ec->hdr.name;
1278 kc->private_value = (long)se;
1279 kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1280 kc->access = ec->hdr.access;
1281
1282 /* we only support FL/FR channel mapping atm */
1283 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1284 se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
1285 se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
1286
1287 se->items = ec->items;
1288 se->mask = ec->mask;
1289 se->dobj.index = tplg->index;
1290
1291 switch (ec->hdr.ops.info) {
1292 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1293 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1294 err = soc_tplg_denum_create_values(se, ec);
1295 if (err < 0) {
1296 dev_err(tplg->dev, "ASoC: could not create values for %s\n",
1297 ec->hdr.name);
1298 goto err_se;
1299 }
1300 /* fall through to create texts */
1301 case SND_SOC_TPLG_CTL_ENUM:
1302 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1303 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1304 err = soc_tplg_denum_create_texts(se, ec);
1305 if (err < 0) {
1306 dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
1307 ec->hdr.name);
1308 goto err_se;
1309 }
1310 break;
1311 default:
1312 dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1313 ec->hdr.ops.info, ec->hdr.name);
1314 goto err_se;
1315 }
1316
1317 /* map io handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +08001318 err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +01001319 if (err) {
1320 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1321 goto err_se;
1322 }
1323
1324 /* pass control to driver for optional further init */
1325 err = soc_tplg_init_kcontrol(tplg, kc,
1326 (struct snd_soc_tplg_ctl_hdr *)ec);
1327 if (err < 0) {
1328 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1329 ec->hdr.name);
1330 goto err_se;
1331 }
1332
1333 return kc;
1334
1335err_se:
1336 /* free values and texts */
1337 kfree(se->dobj.control.dvalues);
1338 for (i = 0; i < ec->items; i++)
1339 kfree(se->dobj.control.dtexts[i]);
1340
1341 kfree(se);
1342err:
1343 kfree(kc);
1344
1345 return NULL;
1346}
1347
1348static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
1349 struct soc_tplg *tplg, int count)
1350{
1351 struct snd_soc_tplg_bytes_control *be;
1352 struct soc_bytes_ext *sbe;
1353 struct snd_kcontrol_new *kc;
1354 int i, err;
1355
Axel Lin4ca7deb2015-08-05 22:34:22 +08001356 kc = kcalloc(count, sizeof(*kc), GFP_KERNEL);
Liam Girdwood8a978232015-05-29 19:06:14 +01001357 if (!kc)
1358 return NULL;
1359
1360 for (i = 0; i < count; i++) {
1361 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
1362
1363 /* validate kcontrol */
1364 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1365 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1366 goto err;
1367
1368 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
1369 if (sbe == NULL)
1370 goto err;
1371
1372 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
1373 be->priv.size);
1374
1375 dev_dbg(tplg->dev,
1376 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
1377 be->hdr.name, be->hdr.access);
1378
Liam Girdwood8a978232015-05-29 19:06:14 +01001379 kc[i].name = be->hdr.name;
1380 kc[i].private_value = (long)sbe;
1381 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1382 kc[i].access = be->hdr.access;
1383
1384 sbe->max = be->max;
1385 INIT_LIST_HEAD(&sbe->dobj.list);
1386
1387 /* map standard io handlers and check for external handlers */
Mengdong Lin2b5cdb92015-08-18 18:12:01 +08001388 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg);
Liam Girdwood8a978232015-05-29 19:06:14 +01001389 if (err) {
1390 soc_control_err(tplg, &be->hdr, be->hdr.name);
1391 kfree(sbe);
1392 continue;
1393 }
1394
1395 /* pass control to driver for optional further init */
1396 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1397 (struct snd_soc_tplg_ctl_hdr *)be);
1398 if (err < 0) {
1399 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1400 be->hdr.name);
1401 kfree(sbe);
1402 continue;
1403 }
1404 }
1405
1406 return kc;
1407
1408err:
1409 for (--i; i >= 0; i--)
1410 kfree((void *)kc[i].private_value);
1411
1412 kfree(kc);
1413 return NULL;
1414}
1415
1416static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1417 struct snd_soc_tplg_dapm_widget *w)
1418{
1419 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1420 struct snd_soc_dapm_widget template, *widget;
1421 struct snd_soc_tplg_ctl_hdr *control_hdr;
1422 struct snd_soc_card *card = tplg->comp->card;
1423 int ret = 0;
1424
1425 if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1426 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1427 return -EINVAL;
1428 if (strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1429 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1430 return -EINVAL;
1431
1432 dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n",
1433 w->name, w->id);
1434
1435 memset(&template, 0, sizeof(template));
1436
1437 /* map user to kernel widget ID */
1438 template.id = get_widget_id(w->id);
1439 if (template.id < 0)
1440 return template.id;
1441
1442 template.name = kstrdup(w->name, GFP_KERNEL);
1443 if (!template.name)
1444 return -ENOMEM;
1445 template.sname = kstrdup(w->sname, GFP_KERNEL);
1446 if (!template.sname) {
1447 ret = -ENOMEM;
1448 goto err;
1449 }
1450 template.reg = w->reg;
1451 template.shift = w->shift;
1452 template.mask = w->mask;
Subhransu S. Prusty6dc6db72015-06-29 17:36:44 +01001453 template.subseq = w->subseq;
Liam Girdwood8a978232015-05-29 19:06:14 +01001454 template.on_val = w->invert ? 0 : 1;
1455 template.off_val = w->invert ? 1 : 0;
1456 template.ignore_suspend = w->ignore_suspend;
1457 template.event_flags = w->event_flags;
1458 template.dobj.index = tplg->index;
1459
1460 tplg->pos +=
1461 (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size);
1462 if (w->num_kcontrols == 0) {
1463 template.num_kcontrols = 0;
1464 goto widget;
1465 }
1466
1467 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1468 dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
1469 w->name, w->num_kcontrols, control_hdr->type);
1470
1471 switch (control_hdr->ops.info) {
1472 case SND_SOC_TPLG_CTL_VOLSW:
1473 case SND_SOC_TPLG_CTL_STROBE:
1474 case SND_SOC_TPLG_CTL_VOLSW_SX:
1475 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1476 case SND_SOC_TPLG_CTL_RANGE:
1477 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1478 template.num_kcontrols = w->num_kcontrols;
1479 template.kcontrol_news =
1480 soc_tplg_dapm_widget_dmixer_create(tplg,
1481 template.num_kcontrols);
1482 if (!template.kcontrol_news) {
1483 ret = -ENOMEM;
1484 goto hdr_err;
1485 }
1486 break;
1487 case SND_SOC_TPLG_CTL_ENUM:
1488 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1489 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1490 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1491 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1492 template.dobj.widget.kcontrol_enum = 1;
1493 template.num_kcontrols = 1;
1494 template.kcontrol_news =
1495 soc_tplg_dapm_widget_denum_create(tplg);
1496 if (!template.kcontrol_news) {
1497 ret = -ENOMEM;
1498 goto hdr_err;
1499 }
1500 break;
1501 case SND_SOC_TPLG_CTL_BYTES:
1502 template.num_kcontrols = w->num_kcontrols;
1503 template.kcontrol_news =
1504 soc_tplg_dapm_widget_dbytes_create(tplg,
1505 template.num_kcontrols);
1506 if (!template.kcontrol_news) {
1507 ret = -ENOMEM;
1508 goto hdr_err;
1509 }
1510 break;
1511 default:
1512 dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
1513 control_hdr->ops.get, control_hdr->ops.put,
1514 control_hdr->ops.info);
1515 ret = -EINVAL;
1516 goto hdr_err;
1517 }
1518
1519widget:
1520 ret = soc_tplg_widget_load(tplg, &template, w);
1521 if (ret < 0)
1522 goto hdr_err;
1523
1524 /* card dapm mutex is held by the core if we are loading topology
1525 * data during sound card init. */
1526 if (card->instantiated)
1527 widget = snd_soc_dapm_new_control(dapm, &template);
1528 else
1529 widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
1530 if (widget == NULL) {
1531 dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
1532 w->name);
Wei Yongjun8ae3ea42016-08-10 13:43:12 +00001533 ret = -ENOMEM;
Liam Girdwood8a978232015-05-29 19:06:14 +01001534 goto hdr_err;
1535 }
1536
1537 widget->dobj.type = SND_SOC_DOBJ_WIDGET;
1538 widget->dobj.ops = tplg->ops;
1539 widget->dobj.index = tplg->index;
Jeeja KP8ea41672016-05-05 11:19:18 +05301540 kfree(template.sname);
1541 kfree(template.name);
Liam Girdwood8a978232015-05-29 19:06:14 +01001542 list_add(&widget->dobj.list, &tplg->comp->dobj_list);
1543 return 0;
1544
1545hdr_err:
1546 kfree(template.sname);
1547err:
1548 kfree(template.name);
1549 return ret;
1550}
1551
1552static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
1553 struct snd_soc_tplg_hdr *hdr)
1554{
1555 struct snd_soc_tplg_dapm_widget *widget;
1556 int ret, count = hdr->count, i;
1557
1558 if (tplg->pass != SOC_TPLG_PASS_WIDGET)
1559 return 0;
1560
1561 dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count);
1562
1563 for (i = 0; i < count; i++) {
1564 widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
Mengdong Lin06eb49f2016-04-27 14:52:56 +08001565 if (widget->size != sizeof(*widget)) {
1566 dev_err(tplg->dev, "ASoC: invalid widget size\n");
1567 return -EINVAL;
1568 }
1569
Liam Girdwood8a978232015-05-29 19:06:14 +01001570 ret = soc_tplg_dapm_widget_create(tplg, widget);
Mengdong Lin7de76b62016-04-27 14:52:38 +08001571 if (ret < 0) {
Liam Girdwood8a978232015-05-29 19:06:14 +01001572 dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
1573 widget->name);
Mengdong Lin7de76b62016-04-27 14:52:38 +08001574 return ret;
1575 }
Liam Girdwood8a978232015-05-29 19:06:14 +01001576 }
1577
1578 return 0;
1579}
1580
1581static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
1582{
1583 struct snd_soc_card *card = tplg->comp->card;
1584 int ret;
1585
1586 /* Card might not have been registered at this point.
1587 * If so, just return success.
1588 */
1589 if (!card || !card->instantiated) {
1590 dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
1591 "Do not add new widgets now\n");
1592 return 0;
1593 }
1594
1595 ret = snd_soc_dapm_new_widgets(card);
1596 if (ret < 0)
1597 dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n",
1598 ret);
1599
1600 return 0;
1601}
1602
Mengdong Linb6b6e4d2016-02-22 16:29:19 +08001603static void set_stream_info(struct snd_soc_pcm_stream *stream,
1604 struct snd_soc_tplg_stream_caps *caps)
1605{
1606 stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
1607 stream->channels_min = caps->channels_min;
1608 stream->channels_max = caps->channels_max;
1609 stream->rates = caps->rates;
1610 stream->rate_min = caps->rate_min;
1611 stream->rate_max = caps->rate_max;
1612 stream->formats = caps->formats;
Mengdong Linf918e162016-08-19 18:12:46 +08001613 stream->sig_bits = caps->sig_bits;
Mengdong Linb6b6e4d2016-02-22 16:29:19 +08001614}
1615
Mengdong Lin0038be92016-07-26 14:32:37 +08001616static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
1617 unsigned int flag_mask, unsigned int flags)
1618{
1619 if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES)
1620 dai_drv->symmetric_rates =
1621 flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0;
1622
1623 if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS)
1624 dai_drv->symmetric_channels =
1625 flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ?
1626 1 : 0;
1627
1628 if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS)
1629 dai_drv->symmetric_samplebits =
1630 flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ?
1631 1 : 0;
1632}
1633
Mengdong Lin64527e82016-01-15 16:13:28 +08001634static int soc_tplg_dai_create(struct soc_tplg *tplg,
1635 struct snd_soc_tplg_pcm *pcm)
1636{
1637 struct snd_soc_dai_driver *dai_drv;
1638 struct snd_soc_pcm_stream *stream;
1639 struct snd_soc_tplg_stream_caps *caps;
1640 int ret;
1641
1642 dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
1643 if (dai_drv == NULL)
1644 return -ENOMEM;
1645
Mengdong Lin8f27c4a2016-11-03 01:02:59 +08001646 if (strlen(pcm->dai_name))
1647 dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
Mengdong Lin64527e82016-01-15 16:13:28 +08001648 dai_drv->id = pcm->dai_id;
1649
1650 if (pcm->playback) {
1651 stream = &dai_drv->playback;
1652 caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
Mengdong Linb6b6e4d2016-02-22 16:29:19 +08001653 set_stream_info(stream, caps);
Mengdong Lin64527e82016-01-15 16:13:28 +08001654 }
1655
1656 if (pcm->capture) {
1657 stream = &dai_drv->capture;
1658 caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
Mengdong Linb6b6e4d2016-02-22 16:29:19 +08001659 set_stream_info(stream, caps);
Mengdong Lin64527e82016-01-15 16:13:28 +08001660 }
1661
1662 /* pass control to component driver for optional further init */
1663 ret = soc_tplg_dai_load(tplg, dai_drv);
1664 if (ret < 0) {
1665 dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
1666 kfree(dai_drv);
1667 return ret;
1668 }
1669
1670 dai_drv->dobj.index = tplg->index;
1671 dai_drv->dobj.ops = tplg->ops;
1672 dai_drv->dobj.type = SND_SOC_DOBJ_PCM;
1673 list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
1674
1675 /* register the DAI to the component */
1676 return snd_soc_register_dai(tplg->comp, dai_drv);
1677}
1678
Guneshwor Singh67d1c212016-04-19 13:12:50 +08001679/* create the FE DAI link */
Mengdong Linacfc7d42016-01-15 16:13:37 +08001680static int soc_tplg_link_create(struct soc_tplg *tplg,
1681 struct snd_soc_tplg_pcm *pcm)
1682{
1683 struct snd_soc_dai_link *link;
1684 int ret;
1685
1686 link = kzalloc(sizeof(struct snd_soc_dai_link), GFP_KERNEL);
1687 if (link == NULL)
1688 return -ENOMEM;
1689
Mengdong Lin8f27c4a2016-11-03 01:02:59 +08001690 if (strlen(pcm->pcm_name)) {
1691 link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
1692 link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
1693 }
Mengdong Linb84fff52016-04-19 13:12:43 +08001694 link->id = pcm->pcm_id;
Mengdong Linacfc7d42016-01-15 16:13:37 +08001695
Mengdong Lin8f27c4a2016-11-03 01:02:59 +08001696 if (strlen(pcm->dai_name))
1697 link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
1698
Guneshwor Singh67d1c212016-04-19 13:12:50 +08001699 link->codec_name = "snd-soc-dummy";
1700 link->codec_dai_name = "snd-soc-dummy-dai";
1701
1702 /* enable DPCM */
1703 link->dynamic = 1;
1704 link->dpcm_playback = pcm->playback;
1705 link->dpcm_capture = pcm->capture;
1706
Mengdong Linacfc7d42016-01-15 16:13:37 +08001707 /* pass control to component driver for optional further init */
1708 ret = soc_tplg_dai_link_load(tplg, link);
1709 if (ret < 0) {
1710 dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
1711 kfree(link);
1712 return ret;
1713 }
1714
1715 link->dobj.index = tplg->index;
1716 link->dobj.ops = tplg->ops;
1717 link->dobj.type = SND_SOC_DOBJ_DAI_LINK;
1718 list_add(&link->dobj.list, &tplg->comp->dobj_list);
1719
1720 snd_soc_add_dai_link(tplg->comp->card, link);
1721 return 0;
1722}
1723
1724/* create a FE DAI and DAI link from the PCM object */
Mengdong Lin64527e82016-01-15 16:13:28 +08001725static int soc_tplg_pcm_create(struct soc_tplg *tplg,
1726 struct snd_soc_tplg_pcm *pcm)
1727{
Mengdong Linacfc7d42016-01-15 16:13:37 +08001728 int ret;
1729
1730 ret = soc_tplg_dai_create(tplg, pcm);
1731 if (ret < 0)
1732 return ret;
1733
1734 return soc_tplg_link_create(tplg, pcm);
Mengdong Lin64527e82016-01-15 16:13:28 +08001735}
1736
Mengdong Lin55726dc2016-11-03 01:00:16 +08001737/* copy stream caps from the old version 4 of source */
1738static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest,
1739 struct snd_soc_tplg_stream_caps_v4 *src)
1740{
1741 dest->size = sizeof(*dest);
1742 memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1743 dest->formats = src->formats;
1744 dest->rates = src->rates;
1745 dest->rate_min = src->rate_min;
1746 dest->rate_max = src->rate_max;
1747 dest->channels_min = src->channels_min;
1748 dest->channels_max = src->channels_max;
1749 dest->periods_min = src->periods_min;
1750 dest->periods_max = src->periods_max;
1751 dest->period_size_min = src->period_size_min;
1752 dest->period_size_max = src->period_size_max;
1753 dest->buffer_size_min = src->buffer_size_min;
1754 dest->buffer_size_max = src->buffer_size_max;
1755}
1756
1757/**
1758 * pcm_new_ver - Create the new version of PCM from the old version.
1759 * @tplg: topology context
1760 * @src: older version of pcm as a source
1761 * @pcm: latest version of pcm created from the source
1762 *
1763 * Support from vesion 4. User should free the returned pcm manually.
1764 */
1765static int pcm_new_ver(struct soc_tplg *tplg,
1766 struct snd_soc_tplg_pcm *src,
1767 struct snd_soc_tplg_pcm **pcm)
1768{
1769 struct snd_soc_tplg_pcm *dest;
1770 struct snd_soc_tplg_pcm_v4 *src_v4;
1771 int i;
1772
1773 *pcm = NULL;
1774
1775 if (src->size != sizeof(*src_v4)) {
1776 dev_err(tplg->dev, "ASoC: invalid PCM size\n");
1777 return -EINVAL;
1778 }
1779
1780 dev_warn(tplg->dev, "ASoC: old version of PCM\n");
1781 src_v4 = (struct snd_soc_tplg_pcm_v4 *)src;
1782 dest = kzalloc(sizeof(*dest), GFP_KERNEL);
1783 if (!dest)
1784 return -ENOMEM;
1785
1786 dest->size = sizeof(*dest); /* size of latest abi version */
1787 memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1788 memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1789 dest->pcm_id = src_v4->pcm_id;
1790 dest->dai_id = src_v4->dai_id;
1791 dest->playback = src_v4->playback;
1792 dest->capture = src_v4->capture;
1793 dest->compress = src_v4->compress;
1794 dest->num_streams = src_v4->num_streams;
1795 for (i = 0; i < dest->num_streams; i++)
1796 memcpy(&dest->stream[i], &src_v4->stream[i],
1797 sizeof(struct snd_soc_tplg_stream));
1798
1799 for (i = 0; i < 2; i++)
1800 stream_caps_new_ver(&dest->caps[i], &src_v4->caps[i]);
1801
1802 *pcm = dest;
1803 return 0;
1804}
1805
Mengdong Lin64527e82016-01-15 16:13:28 +08001806static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
Liam Girdwood8a978232015-05-29 19:06:14 +01001807 struct snd_soc_tplg_hdr *hdr)
1808{
Mengdong Lin55726dc2016-11-03 01:00:16 +08001809 struct snd_soc_tplg_pcm *pcm, *_pcm;
Liam Girdwood8a978232015-05-29 19:06:14 +01001810 int count = hdr->count;
Mengdong Lin55726dc2016-11-03 01:00:16 +08001811 int i, err;
1812 bool abi_match;
Liam Girdwood8a978232015-05-29 19:06:14 +01001813
1814 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
1815 return 0;
1816
Mengdong Lin55726dc2016-11-03 01:00:16 +08001817 /* check the element size and count */
1818 pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
1819 if (pcm->size > sizeof(struct snd_soc_tplg_pcm)
1820 || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) {
1821 dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n",
1822 pcm->size);
1823 return -EINVAL;
1824 }
1825
Liam Girdwood8a978232015-05-29 19:06:14 +01001826 if (soc_tplg_check_elem_count(tplg,
Mengdong Lin55726dc2016-11-03 01:00:16 +08001827 pcm->size, count,
Liam Girdwood8a978232015-05-29 19:06:14 +01001828 hdr->payload_size, "PCM DAI")) {
1829 dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
1830 count);
1831 return -EINVAL;
1832 }
1833
Mengdong Lin64527e82016-01-15 16:13:28 +08001834 for (i = 0; i < count; i++) {
Mengdong Lin55726dc2016-11-03 01:00:16 +08001835 pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
1836
1837 /* check ABI version by size, create a new version of pcm
1838 * if abi not match.
1839 */
1840 if (pcm->size == sizeof(*pcm)) {
1841 abi_match = true;
1842 _pcm = pcm;
1843 } else {
1844 abi_match = false;
1845 err = pcm_new_ver(tplg, pcm, &_pcm);
Mengdong Lin06eb49f2016-04-27 14:52:56 +08001846 }
1847
Mengdong Lin55726dc2016-11-03 01:00:16 +08001848 /* create the FE DAIs and DAI links */
1849 soc_tplg_pcm_create(tplg, _pcm);
1850
1851 if (!abi_match)
1852 kfree(_pcm); /* free the duplicated one */
1853
1854 tplg->pos += pcm->size; /* offset by version-specific size */
Mengdong Lin64527e82016-01-15 16:13:28 +08001855 }
1856
Liam Girdwood8a978232015-05-29 19:06:14 +01001857 dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
Liam Girdwood8a978232015-05-29 19:06:14 +01001858
Liam Girdwood8a978232015-05-29 19:06:14 +01001859 return 0;
Liam Girdwood8a978232015-05-29 19:06:14 +01001860}
1861
Mengdong Lin0038be92016-07-26 14:32:37 +08001862/* *
1863 * soc_tplg_be_dai_config - Find and configure an existing BE DAI.
1864 * @tplg: topology context
1865 * @be: topology BE DAI configs.
1866 *
1867 * The BE dai should already be registered by the platform driver. The
1868 * platform driver should specify the BE DAI name and ID for matching.
1869 */
1870static int soc_tplg_be_dai_config(struct soc_tplg *tplg,
1871 struct snd_soc_tplg_be_dai *be)
1872{
1873 struct snd_soc_dai_link_component dai_component = {0};
1874 struct snd_soc_dai *dai;
1875 struct snd_soc_dai_driver *dai_drv;
1876 struct snd_soc_pcm_stream *stream;
1877 struct snd_soc_tplg_stream_caps *caps;
1878 int ret;
1879
1880 dai_component.dai_name = be->dai_name;
1881 dai = snd_soc_find_dai(&dai_component);
1882 if (!dai) {
1883 dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n",
1884 be->dai_name);
1885 return -EINVAL;
1886 }
1887
1888 if (be->dai_id != dai->id) {
1889 dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n",
1890 be->dai_name);
1891 return -EINVAL;
1892 }
1893
1894 dai_drv = dai->driver;
1895 if (!dai_drv)
1896 return -EINVAL;
1897
1898 if (be->playback) {
1899 stream = &dai_drv->playback;
1900 caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
1901 set_stream_info(stream, caps);
1902 }
1903
1904 if (be->capture) {
1905 stream = &dai_drv->capture;
1906 caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE];
1907 set_stream_info(stream, caps);
1908 }
1909
1910 if (be->flag_mask)
1911 set_dai_flags(dai_drv, be->flag_mask, be->flags);
1912
1913 /* pass control to component driver for optional further init */
1914 ret = soc_tplg_dai_load(tplg, dai_drv);
1915 if (ret < 0) {
1916 dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
1917 return ret;
1918 }
1919
1920 return 0;
1921}
1922
1923static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg,
1924 struct snd_soc_tplg_hdr *hdr)
1925{
1926 struct snd_soc_tplg_be_dai *be;
1927 int count = hdr->count;
1928 int i;
1929
1930 if (tplg->pass != SOC_TPLG_PASS_BE_DAI)
1931 return 0;
1932
1933 /* config the existing BE DAIs */
1934 for (i = 0; i < count; i++) {
1935 be = (struct snd_soc_tplg_be_dai *)tplg->pos;
1936 if (be->size != sizeof(*be)) {
1937 dev_err(tplg->dev, "ASoC: invalid BE DAI size\n");
1938 return -EINVAL;
1939 }
1940
1941 soc_tplg_be_dai_config(tplg, be);
1942 tplg->pos += (sizeof(*be) + be->priv.size);
1943 }
1944
1945 dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count);
1946 return 0;
1947}
1948
Mengdong Lin583958f2016-10-11 14:36:42 +08001949/**
1950 * manifest_new_ver - Create a new version of manifest from the old version
1951 * of source.
1952 * @toplogy: topology context
1953 * @src: old version of manifest as a source
1954 * @manifest: latest version of manifest created from the source
1955 *
1956 * Support from vesion 4. Users need free the returned manifest manually.
1957 */
1958static int manifest_new_ver(struct soc_tplg *tplg,
1959 struct snd_soc_tplg_manifest *src,
1960 struct snd_soc_tplg_manifest **manifest)
1961{
1962 struct snd_soc_tplg_manifest *dest;
1963 struct snd_soc_tplg_manifest_v4 *src_v4;
1964
1965 *manifest = NULL;
1966
1967 if (src->size != sizeof(*src_v4)) {
1968 dev_err(tplg->dev, "ASoC: invalid manifest size\n");
1969 return -EINVAL;
1970 }
1971
1972 dev_warn(tplg->dev, "ASoC: old version of manifest\n");
1973
1974 src_v4 = (struct snd_soc_tplg_manifest_v4 *)src;
1975 dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL);
1976 if (!dest)
1977 return -ENOMEM;
1978
1979 dest->size = sizeof(*dest); /* size of latest abi version */
1980 dest->control_elems = src_v4->control_elems;
1981 dest->widget_elems = src_v4->widget_elems;
1982 dest->graph_elems = src_v4->graph_elems;
1983 dest->pcm_elems = src_v4->pcm_elems;
1984 dest->dai_link_elems = src_v4->dai_link_elems;
1985 dest->priv.size = src_v4->priv.size;
1986 if (dest->priv.size)
1987 memcpy(dest->priv.data, src_v4->priv.data,
1988 src_v4->priv.size);
1989
1990 *manifest = dest;
1991 return 0;
1992}
Mengdong Lin0038be92016-07-26 14:32:37 +08001993
Liam Girdwood8a978232015-05-29 19:06:14 +01001994static int soc_tplg_manifest_load(struct soc_tplg *tplg,
Mengdong Lin0038be92016-07-26 14:32:37 +08001995 struct snd_soc_tplg_hdr *hdr)
Liam Girdwood8a978232015-05-29 19:06:14 +01001996{
Mengdong Lin583958f2016-10-11 14:36:42 +08001997 struct snd_soc_tplg_manifest *manifest, *_manifest;
1998 bool abi_match;
1999 int err;
Liam Girdwood8a978232015-05-29 19:06:14 +01002000
2001 if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
2002 return 0;
2003
2004 manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
Mengdong Lin583958f2016-10-11 14:36:42 +08002005
2006 /* check ABI version by size, create a new manifest if abi not match */
2007 if (manifest->size == sizeof(*manifest)) {
2008 abi_match = true;
2009 _manifest = manifest;
2010 } else {
2011 abi_match = false;
2012 err = manifest_new_ver(tplg, manifest, &_manifest);
2013 if (err < 0)
2014 return err;
Mengdong Lin06eb49f2016-04-27 14:52:56 +08002015 }
2016
Mengdong Lin583958f2016-10-11 14:36:42 +08002017 /* pass control to component driver for optional further init */
Liam Girdwood8a978232015-05-29 19:06:14 +01002018 if (tplg->comp && tplg->ops && tplg->ops->manifest)
Mengdong Lin583958f2016-10-11 14:36:42 +08002019 return tplg->ops->manifest(tplg->comp, _manifest);
Liam Girdwood8a978232015-05-29 19:06:14 +01002020
Mengdong Lin583958f2016-10-11 14:36:42 +08002021 if (!abi_match) /* free the duplicated one */
2022 kfree(_manifest);
2023
Liam Girdwood8a978232015-05-29 19:06:14 +01002024 return 0;
2025}
2026
2027/* validate header magic, size and type */
2028static int soc_valid_header(struct soc_tplg *tplg,
2029 struct snd_soc_tplg_hdr *hdr)
2030{
2031 if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
2032 return 0;
2033
Mengdong Lin06eb49f2016-04-27 14:52:56 +08002034 if (hdr->size != sizeof(*hdr)) {
2035 dev_err(tplg->dev,
2036 "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
2037 hdr->type, soc_tplg_get_hdr_offset(tplg),
2038 tplg->fw->size);
2039 return -EINVAL;
2040 }
2041
Liam Girdwood8a978232015-05-29 19:06:14 +01002042 /* big endian firmware objects not supported atm */
2043 if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
2044 dev_err(tplg->dev,
2045 "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
2046 tplg->pass, hdr->magic,
2047 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
2048 return -EINVAL;
2049 }
2050
2051 if (hdr->magic != SND_SOC_TPLG_MAGIC) {
2052 dev_err(tplg->dev,
2053 "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
2054 tplg->pass, hdr->magic,
2055 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
2056 return -EINVAL;
2057 }
2058
2059 if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
2060 dev_err(tplg->dev,
2061 "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
2062 tplg->pass, hdr->abi,
2063 SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg),
2064 tplg->fw->size);
2065 return -EINVAL;
2066 }
2067
2068 if (hdr->payload_size == 0) {
2069 dev_err(tplg->dev, "ASoC: header has 0 size at offset 0x%lx.\n",
2070 soc_tplg_get_hdr_offset(tplg));
2071 return -EINVAL;
2072 }
2073
2074 if (tplg->pass == hdr->type)
2075 dev_dbg(tplg->dev,
2076 "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
2077 hdr->payload_size, hdr->type, hdr->version,
2078 hdr->vendor_type, tplg->pass);
2079
2080 return 1;
2081}
2082
2083/* check header type and call appropriate handler */
2084static int soc_tplg_load_header(struct soc_tplg *tplg,
2085 struct snd_soc_tplg_hdr *hdr)
2086{
2087 tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
2088
2089 /* check for matching ID */
2090 if (hdr->index != tplg->req_index &&
2091 hdr->index != SND_SOC_TPLG_INDEX_ALL)
2092 return 0;
2093
2094 tplg->index = hdr->index;
2095
2096 switch (hdr->type) {
2097 case SND_SOC_TPLG_TYPE_MIXER:
2098 case SND_SOC_TPLG_TYPE_ENUM:
2099 case SND_SOC_TPLG_TYPE_BYTES:
2100 return soc_tplg_kcontrol_elems_load(tplg, hdr);
2101 case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
2102 return soc_tplg_dapm_graph_elems_load(tplg, hdr);
2103 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
2104 return soc_tplg_dapm_widget_elems_load(tplg, hdr);
2105 case SND_SOC_TPLG_TYPE_PCM:
Mengdong Lin64527e82016-01-15 16:13:28 +08002106 return soc_tplg_pcm_elems_load(tplg, hdr);
Mengdong Lin0038be92016-07-26 14:32:37 +08002107 case SND_SOC_TPLG_TYPE_BE_DAI:
2108 return soc_tplg_be_dai_elems_load(tplg, hdr);
Liam Girdwood8a978232015-05-29 19:06:14 +01002109 case SND_SOC_TPLG_TYPE_MANIFEST:
2110 return soc_tplg_manifest_load(tplg, hdr);
2111 default:
2112 /* bespoke vendor data object */
2113 return soc_tplg_vendor_load(tplg, hdr);
2114 }
2115
2116 return 0;
2117}
2118
2119/* process the topology file headers */
2120static int soc_tplg_process_headers(struct soc_tplg *tplg)
2121{
2122 struct snd_soc_tplg_hdr *hdr;
2123 int ret;
2124
2125 tplg->pass = SOC_TPLG_PASS_START;
2126
2127 /* process the header types from start to end */
2128 while (tplg->pass <= SOC_TPLG_PASS_END) {
2129
2130 tplg->hdr_pos = tplg->fw->data;
2131 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
2132
2133 while (!soc_tplg_is_eof(tplg)) {
2134
2135 /* make sure header is valid before loading */
2136 ret = soc_valid_header(tplg, hdr);
2137 if (ret < 0)
2138 return ret;
2139 else if (ret == 0)
2140 break;
2141
2142 /* load the header object */
2143 ret = soc_tplg_load_header(tplg, hdr);
2144 if (ret < 0)
2145 return ret;
2146
2147 /* goto next header */
2148 tplg->hdr_pos += hdr->payload_size +
2149 sizeof(struct snd_soc_tplg_hdr);
2150 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
2151 }
2152
2153 /* next data type pass */
2154 tplg->pass++;
2155 }
2156
2157 /* signal DAPM we are complete */
2158 ret = soc_tplg_dapm_complete(tplg);
2159 if (ret < 0)
2160 dev_err(tplg->dev,
2161 "ASoC: failed to initialise DAPM from Firmware\n");
2162
2163 return ret;
2164}
2165
2166static int soc_tplg_load(struct soc_tplg *tplg)
2167{
2168 int ret;
2169
2170 ret = soc_tplg_process_headers(tplg);
2171 if (ret == 0)
2172 soc_tplg_complete(tplg);
2173
2174 return ret;
2175}
2176
2177/* load audio component topology from "firmware" file */
2178int snd_soc_tplg_component_load(struct snd_soc_component *comp,
2179 struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
2180{
2181 struct soc_tplg tplg;
2182
2183 /* setup parsing context */
2184 memset(&tplg, 0, sizeof(tplg));
2185 tplg.fw = fw;
2186 tplg.dev = comp->dev;
2187 tplg.comp = comp;
2188 tplg.ops = ops;
2189 tplg.req_index = id;
2190 tplg.io_ops = ops->io_ops;
2191 tplg.io_ops_count = ops->io_ops_count;
Mengdong Lin1a3232d2015-08-18 18:12:20 +08002192 tplg.bytes_ext_ops = ops->bytes_ext_ops;
2193 tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count;
Liam Girdwood8a978232015-05-29 19:06:14 +01002194
2195 return soc_tplg_load(&tplg);
2196}
2197EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
2198
2199/* remove this dynamic widget */
2200void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
2201{
2202 /* make sure we are a widget */
2203 if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
2204 return;
2205
2206 remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
2207}
2208EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
2209
2210/* remove all dynamic widgets from this DAPM context */
2211void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
2212 u32 index)
2213{
2214 struct snd_soc_dapm_widget *w, *next_w;
Liam Girdwood8a978232015-05-29 19:06:14 +01002215
2216 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2217
2218 /* make sure we are a widget with correct context */
2219 if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
2220 continue;
2221
2222 /* match ID */
2223 if (w->dobj.index != index &&
2224 w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
2225 continue;
Liam Girdwood8a978232015-05-29 19:06:14 +01002226 /* check and free and dynamic widget kcontrols */
2227 snd_soc_tplg_widget_remove(w);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002228 snd_soc_dapm_free_widget(w);
Liam Girdwood8a978232015-05-29 19:06:14 +01002229 }
Jyri Sarhafd589a12015-11-10 18:12:42 +02002230 snd_soc_dapm_reset_cache(dapm);
Liam Girdwood8a978232015-05-29 19:06:14 +01002231}
2232EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
2233
2234/* remove dynamic controls from the component driver */
2235int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
2236{
2237 struct snd_soc_dobj *dobj, *next_dobj;
2238 int pass = SOC_TPLG_PASS_END;
2239
2240 /* process the header types from end to start */
2241 while (pass >= SOC_TPLG_PASS_START) {
2242
2243 /* remove mixer controls */
2244 list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
2245 list) {
2246
2247 /* match index */
2248 if (dobj->index != index &&
2249 dobj->index != SND_SOC_TPLG_INDEX_ALL)
2250 continue;
2251
2252 switch (dobj->type) {
2253 case SND_SOC_DOBJ_MIXER:
2254 remove_mixer(comp, dobj, pass);
2255 break;
2256 case SND_SOC_DOBJ_ENUM:
2257 remove_enum(comp, dobj, pass);
2258 break;
2259 case SND_SOC_DOBJ_BYTES:
2260 remove_bytes(comp, dobj, pass);
2261 break;
2262 case SND_SOC_DOBJ_WIDGET:
2263 remove_widget(comp, dobj, pass);
2264 break;
2265 case SND_SOC_DOBJ_PCM:
Mengdong Lin64527e82016-01-15 16:13:28 +08002266 remove_dai(comp, dobj, pass);
Liam Girdwood8a978232015-05-29 19:06:14 +01002267 break;
Mengdong Linacfc7d42016-01-15 16:13:37 +08002268 case SND_SOC_DOBJ_DAI_LINK:
2269 remove_link(comp, dobj, pass);
2270 break;
Liam Girdwood8a978232015-05-29 19:06:14 +01002271 default:
2272 dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",
2273 dobj->type);
2274 break;
2275 }
2276 }
2277 pass--;
2278 }
2279
2280 /* let caller know if FW can be freed when no objects are left */
2281 return !list_empty(&comp->dobj_list);
2282}
2283EXPORT_SYMBOL_GPL(snd_soc_tplg_component_remove);