ASoC: topology: Reduce arguments of soc_tplg_kcontrol_bind_io()
[deliverable/linux.git] / sound / soc / soc-topology.c
CommitLineData
8a978234
LG
1/*
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>
28a87eeb 36#include <sound/tlv.h>
8a978234
LG
37
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
1a8e7fab
ML
48#define SOC_TPLG_PASS_PCM_DAI 4
49#define SOC_TPLG_PASS_GRAPH 5
50#define SOC_TPLG_PASS_PINS 6
8a978234
LG
51
52#define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST
1a8e7fab 53#define SOC_TPLG_PASS_END SOC_TPLG_PASS_PINS
8a978234
LG
54
55struct soc_tplg {
56 const struct firmware *fw;
57
58 /* runtime FW parsing */
59 const u8 *pos; /* read postion */
60 const u8 *hdr_pos; /* header position */
61 unsigned int pass; /* pass number */
62
63 /* component caller */
64 struct device *dev;
65 struct snd_soc_component *comp;
66 u32 index; /* current block index */
67 u32 req_index; /* required index, only loaded/free matching blocks */
68
88a17d8f 69 /* vendor specific kcontrol operations */
8a978234
LG
70 const struct snd_soc_tplg_kcontrol_ops *io_ops;
71 int io_ops_count;
72
73 /* optional fw loading callbacks to component drivers */
74 struct snd_soc_tplg_ops *ops;
75};
76
77static int soc_tplg_process_headers(struct soc_tplg *tplg);
78static void soc_tplg_complete(struct soc_tplg *tplg);
79struct snd_soc_dapm_widget *
80snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
81 const struct snd_soc_dapm_widget *widget);
82struct snd_soc_dapm_widget *
83snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
84 const struct snd_soc_dapm_widget *widget);
85
86/* check we dont overflow the data for this control chunk */
87static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
88 unsigned int count, size_t bytes, const char *elem_type)
89{
90 const u8 *end = tplg->pos + elem_size * count;
91
92 if (end > tplg->fw->data + tplg->fw->size) {
93 dev_err(tplg->dev, "ASoC: %s overflow end of data\n",
94 elem_type);
95 return -EINVAL;
96 }
97
98 /* check there is enough room in chunk for control.
99 extra bytes at the end of control are for vendor data here */
100 if (elem_size * count > bytes) {
101 dev_err(tplg->dev,
102 "ASoC: %s count %d of size %zu is bigger than chunk %zu\n",
103 elem_type, count, elem_size, bytes);
104 return -EINVAL;
105 }
106
107 return 0;
108}
109
110static inline int soc_tplg_is_eof(struct soc_tplg *tplg)
111{
112 const u8 *end = tplg->hdr_pos;
113
114 if (end >= tplg->fw->data + tplg->fw->size)
115 return 1;
116 return 0;
117}
118
119static inline unsigned long soc_tplg_get_hdr_offset(struct soc_tplg *tplg)
120{
121 return (unsigned long)(tplg->hdr_pos - tplg->fw->data);
122}
123
124static inline unsigned long soc_tplg_get_offset(struct soc_tplg *tplg)
125{
126 return (unsigned long)(tplg->pos - tplg->fw->data);
127}
128
129/* mapping of Kcontrol types and associated operations. */
130static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
131 {SND_SOC_TPLG_CTL_VOLSW, snd_soc_get_volsw,
132 snd_soc_put_volsw, snd_soc_info_volsw},
133 {SND_SOC_TPLG_CTL_VOLSW_SX, snd_soc_get_volsw_sx,
134 snd_soc_put_volsw_sx, NULL},
135 {SND_SOC_TPLG_CTL_ENUM, snd_soc_get_enum_double,
136 snd_soc_put_enum_double, snd_soc_info_enum_double},
137 {SND_SOC_TPLG_CTL_ENUM_VALUE, snd_soc_get_enum_double,
138 snd_soc_put_enum_double, NULL},
139 {SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get,
140 snd_soc_bytes_put, snd_soc_bytes_info},
141 {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range,
142 snd_soc_put_volsw_range, snd_soc_info_volsw_range},
143 {SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx,
144 snd_soc_put_xr_sx, snd_soc_info_xr_sx},
145 {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
146 snd_soc_put_strobe, NULL},
147 {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw,
2c57d478 148 snd_soc_dapm_put_volsw, snd_soc_info_volsw},
8a978234
LG
149 {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double,
150 snd_soc_dapm_put_enum_double, snd_soc_info_enum_double},
151 {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double,
152 snd_soc_dapm_put_enum_double, NULL},
153 {SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE, snd_soc_dapm_get_enum_double,
154 snd_soc_dapm_put_enum_double, NULL},
155 {SND_SOC_TPLG_DAPM_CTL_PIN, snd_soc_dapm_get_pin_switch,
156 snd_soc_dapm_put_pin_switch, snd_soc_dapm_info_pin_switch},
157};
158
159struct soc_tplg_map {
160 int uid;
161 int kid;
162};
163
164/* mapping of widget types from UAPI IDs to kernel IDs */
165static const struct soc_tplg_map dapm_map[] = {
166 {SND_SOC_TPLG_DAPM_INPUT, snd_soc_dapm_input},
167 {SND_SOC_TPLG_DAPM_OUTPUT, snd_soc_dapm_output},
168 {SND_SOC_TPLG_DAPM_MUX, snd_soc_dapm_mux},
169 {SND_SOC_TPLG_DAPM_MIXER, snd_soc_dapm_mixer},
170 {SND_SOC_TPLG_DAPM_PGA, snd_soc_dapm_pga},
171 {SND_SOC_TPLG_DAPM_OUT_DRV, snd_soc_dapm_out_drv},
172 {SND_SOC_TPLG_DAPM_ADC, snd_soc_dapm_adc},
173 {SND_SOC_TPLG_DAPM_DAC, snd_soc_dapm_dac},
174 {SND_SOC_TPLG_DAPM_SWITCH, snd_soc_dapm_switch},
175 {SND_SOC_TPLG_DAPM_PRE, snd_soc_dapm_pre},
176 {SND_SOC_TPLG_DAPM_POST, snd_soc_dapm_post},
177 {SND_SOC_TPLG_DAPM_AIF_IN, snd_soc_dapm_aif_in},
178 {SND_SOC_TPLG_DAPM_AIF_OUT, snd_soc_dapm_aif_out},
179 {SND_SOC_TPLG_DAPM_DAI_IN, snd_soc_dapm_dai_in},
180 {SND_SOC_TPLG_DAPM_DAI_OUT, snd_soc_dapm_dai_out},
181 {SND_SOC_TPLG_DAPM_DAI_LINK, snd_soc_dapm_dai_link},
182};
183
184static int tplc_chan_get_reg(struct soc_tplg *tplg,
185 struct snd_soc_tplg_channel *chan, int map)
186{
187 int i;
188
189 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
190 if (chan[i].id == map)
191 return chan[i].reg;
192 }
193
194 return -EINVAL;
195}
196
197static int tplc_chan_get_shift(struct soc_tplg *tplg,
198 struct snd_soc_tplg_channel *chan, int map)
199{
200 int i;
201
202 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
203 if (chan[i].id == map)
204 return chan[i].shift;
205 }
206
207 return -EINVAL;
208}
209
210static int get_widget_id(int tplg_type)
211{
212 int i;
213
214 for (i = 0; i < ARRAY_SIZE(dapm_map); i++) {
215 if (tplg_type == dapm_map[i].uid)
216 return dapm_map[i].kid;
217 }
218
219 return -EINVAL;
220}
221
222static enum snd_soc_dobj_type get_dobj_mixer_type(
223 struct snd_soc_tplg_ctl_hdr *control_hdr)
224{
225 if (control_hdr == NULL)
226 return SND_SOC_DOBJ_NONE;
227
228 switch (control_hdr->ops.info) {
229 case SND_SOC_TPLG_CTL_VOLSW:
230 case SND_SOC_TPLG_CTL_VOLSW_SX:
231 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
232 case SND_SOC_TPLG_CTL_RANGE:
233 case SND_SOC_TPLG_CTL_STROBE:
234 return SND_SOC_DOBJ_MIXER;
235 case SND_SOC_TPLG_CTL_ENUM:
236 case SND_SOC_TPLG_CTL_ENUM_VALUE:
237 return SND_SOC_DOBJ_ENUM;
238 case SND_SOC_TPLG_CTL_BYTES:
239 return SND_SOC_DOBJ_BYTES;
240 default:
241 return SND_SOC_DOBJ_NONE;
242 }
243}
244
245static enum snd_soc_dobj_type get_dobj_type(struct snd_soc_tplg_hdr *hdr,
246 struct snd_soc_tplg_ctl_hdr *control_hdr)
247{
248 switch (hdr->type) {
249 case SND_SOC_TPLG_TYPE_MIXER:
250 return get_dobj_mixer_type(control_hdr);
251 case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
252 case SND_SOC_TPLG_TYPE_MANIFEST:
253 return SND_SOC_DOBJ_NONE;
254 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
255 return SND_SOC_DOBJ_WIDGET;
256 case SND_SOC_TPLG_TYPE_DAI_LINK:
257 return SND_SOC_DOBJ_DAI_LINK;
258 case SND_SOC_TPLG_TYPE_PCM:
259 return SND_SOC_DOBJ_PCM;
260 case SND_SOC_TPLG_TYPE_CODEC_LINK:
261 return SND_SOC_DOBJ_CODEC_LINK;
262 default:
263 return SND_SOC_DOBJ_NONE;
264 }
265}
266
267static inline void soc_bind_err(struct soc_tplg *tplg,
268 struct snd_soc_tplg_ctl_hdr *hdr, int index)
269{
270 dev_err(tplg->dev,
271 "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n",
272 hdr->ops.get, hdr->ops.put, hdr->ops.info, index,
273 soc_tplg_get_offset(tplg));
274}
275
276static inline void soc_control_err(struct soc_tplg *tplg,
277 struct snd_soc_tplg_ctl_hdr *hdr, const char *name)
278{
279 dev_err(tplg->dev,
280 "ASoC: no complete mixer IO handler for %s type (g,p,i) %d:%d:%d at 0x%lx\n",
281 name, hdr->ops.get, hdr->ops.put, hdr->ops.info,
282 soc_tplg_get_offset(tplg));
283}
284
285/* pass vendor data to component driver for processing */
286static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
287 struct snd_soc_tplg_hdr *hdr)
288{
289 int ret = 0;
290
291 if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
292 ret = tplg->ops->vendor_load(tplg->comp, hdr);
293 else {
294 dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
295 hdr->vendor_type);
296 return -EINVAL;
297 }
298
299 if (ret < 0)
300 dev_err(tplg->dev,
301 "ASoC: vendor load failed at hdr offset %ld/0x%lx for type %d:%d\n",
302 soc_tplg_get_hdr_offset(tplg),
303 soc_tplg_get_hdr_offset(tplg),
304 hdr->type, hdr->vendor_type);
305 return ret;
306}
307
308/* pass vendor data to component driver for processing */
309static int soc_tplg_vendor_load(struct soc_tplg *tplg,
310 struct snd_soc_tplg_hdr *hdr)
311{
312 if (tplg->pass != SOC_TPLG_PASS_VENDOR)
313 return 0;
314
315 return soc_tplg_vendor_load_(tplg, hdr);
316}
317
318/* optionally pass new dynamic widget to component driver. This is mainly for
319 * external widgets where we can assign private data/ops */
320static int soc_tplg_widget_load(struct soc_tplg *tplg,
321 struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
322{
323 if (tplg->comp && tplg->ops && tplg->ops->widget_load)
324 return tplg->ops->widget_load(tplg->comp, w, tplg_w);
325
326 return 0;
327}
328
329/* pass dynamic FEs configurations to component driver */
330static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg,
331 struct snd_soc_tplg_pcm_dai *pcm_dai, int num_pcm_dai)
332{
333 if (tplg->comp && tplg->ops && tplg->ops->pcm_dai_load)
334 return tplg->ops->pcm_dai_load(tplg->comp, pcm_dai, num_pcm_dai);
335
336 return 0;
337}
338
339/* tell the component driver that all firmware has been loaded in this request */
340static void soc_tplg_complete(struct soc_tplg *tplg)
341{
342 if (tplg->comp && tplg->ops && tplg->ops->complete)
343 tplg->ops->complete(tplg->comp);
344}
345
346/* add a dynamic kcontrol */
347static int soc_tplg_add_dcontrol(struct snd_card *card, struct device *dev,
348 const struct snd_kcontrol_new *control_new, const char *prefix,
349 void *data, struct snd_kcontrol **kcontrol)
350{
351 int err;
352
353 *kcontrol = snd_soc_cnew(control_new, data, control_new->name, prefix);
354 if (*kcontrol == NULL) {
355 dev_err(dev, "ASoC: Failed to create new kcontrol %s\n",
356 control_new->name);
357 return -ENOMEM;
358 }
359
360 err = snd_ctl_add(card, *kcontrol);
361 if (err < 0) {
362 dev_err(dev, "ASoC: Failed to add %s: %d\n",
363 control_new->name, err);
364 return err;
365 }
366
367 return 0;
368}
369
370/* add a dynamic kcontrol for component driver */
371static int soc_tplg_add_kcontrol(struct soc_tplg *tplg,
372 struct snd_kcontrol_new *k, struct snd_kcontrol **kcontrol)
373{
374 struct snd_soc_component *comp = tplg->comp;
375
376 return soc_tplg_add_dcontrol(comp->card->snd_card,
377 comp->dev, k, NULL, comp, kcontrol);
378}
379
380/* remove a mixer kcontrol */
381static void remove_mixer(struct snd_soc_component *comp,
382 struct snd_soc_dobj *dobj, int pass)
383{
384 struct snd_card *card = comp->card->snd_card;
385 struct soc_mixer_control *sm =
386 container_of(dobj, struct soc_mixer_control, dobj);
387 const unsigned int *p = NULL;
388
389 if (pass != SOC_TPLG_PASS_MIXER)
390 return;
391
392 if (dobj->ops && dobj->ops->control_unload)
393 dobj->ops->control_unload(comp, dobj);
394
395 if (sm->dobj.control.kcontrol->tlv.p)
396 p = sm->dobj.control.kcontrol->tlv.p;
397 snd_ctl_remove(card, sm->dobj.control.kcontrol);
398 list_del(&sm->dobj.list);
399 kfree(sm);
400 kfree(p);
401}
402
403/* remove an enum kcontrol */
404static void remove_enum(struct snd_soc_component *comp,
405 struct snd_soc_dobj *dobj, int pass)
406{
407 struct snd_card *card = comp->card->snd_card;
408 struct soc_enum *se = container_of(dobj, struct soc_enum, dobj);
409 int i;
410
411 if (pass != SOC_TPLG_PASS_MIXER)
412 return;
413
414 if (dobj->ops && dobj->ops->control_unload)
415 dobj->ops->control_unload(comp, dobj);
416
417 snd_ctl_remove(card, se->dobj.control.kcontrol);
418 list_del(&se->dobj.list);
419
420 kfree(se->dobj.control.dvalues);
421 for (i = 0; i < se->items; i++)
422 kfree(se->dobj.control.dtexts[i]);
423 kfree(se);
424}
425
426/* remove a byte kcontrol */
427static void remove_bytes(struct snd_soc_component *comp,
428 struct snd_soc_dobj *dobj, int pass)
429{
430 struct snd_card *card = comp->card->snd_card;
431 struct soc_bytes_ext *sb =
432 container_of(dobj, struct soc_bytes_ext, dobj);
433
434 if (pass != SOC_TPLG_PASS_MIXER)
435 return;
436
437 if (dobj->ops && dobj->ops->control_unload)
438 dobj->ops->control_unload(comp, dobj);
439
440 snd_ctl_remove(card, sb->dobj.control.kcontrol);
441 list_del(&sb->dobj.list);
442 kfree(sb);
443}
444
445/* remove a widget and it's kcontrols - routes must be removed first */
446static void remove_widget(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 snd_soc_dapm_widget *w =
451 container_of(dobj, struct snd_soc_dapm_widget, dobj);
452 int i;
453
454 if (pass != SOC_TPLG_PASS_WIDGET)
455 return;
456
457 if (dobj->ops && dobj->ops->widget_unload)
458 dobj->ops->widget_unload(comp, dobj);
459
460 /*
461 * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers.
462 * The enum may either have an array of values or strings.
463 */
464 if (dobj->widget.kcontrol_enum) {
465 /* enumerated widget mixer */
466 struct soc_enum *se =
467 (struct soc_enum *)w->kcontrols[0]->private_value;
468
469 snd_ctl_remove(card, w->kcontrols[0]);
470
471 kfree(se->dobj.control.dvalues);
472 for (i = 0; i < se->items; i++)
473 kfree(se->dobj.control.dtexts[i]);
474
475 kfree(se);
476 kfree(w->kcontrol_news);
477 } else {
478 /* non enumerated widget mixer */
479 for (i = 0; i < w->num_kcontrols; i++) {
480 struct snd_kcontrol *kcontrol = w->kcontrols[i];
481 struct soc_mixer_control *sm =
482 (struct soc_mixer_control *) kcontrol->private_value;
483
484 kfree(w->kcontrols[i]->tlv.p);
485
486 snd_ctl_remove(card, w->kcontrols[i]);
487 kfree(sm);
488 }
489 kfree(w->kcontrol_news);
490 }
491 /* widget w is freed by soc-dapm.c */
492}
493
494/* remove PCM DAI configurations */
495static void remove_pcm_dai(struct snd_soc_component *comp,
496 struct snd_soc_dobj *dobj, int pass)
497{
498 if (pass != SOC_TPLG_PASS_PCM_DAI)
499 return;
500
501 if (dobj->ops && dobj->ops->pcm_dai_unload)
502 dobj->ops->pcm_dai_unload(comp, dobj);
503
504 list_del(&dobj->list);
505 kfree(dobj);
506}
507
508/* bind a kcontrol to it's IO handlers */
509static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
510 struct snd_kcontrol_new *k,
2b5cdb91 511 const struct soc_tplg *tplg)
8a978234 512{
2b5cdb91
ML
513 const struct snd_soc_tplg_kcontrol_ops *ops;
514 int num_ops, i;
8a978234 515
88a17d8f 516 /* try and map vendor specific kcontrol handlers first */
2b5cdb91
ML
517 ops = tplg->io_ops;
518 num_ops = tplg->io_ops_count;
519 for (i = 0; i < num_ops; i++) {
520
521 if (k->put == NULL && ops[i].id == hdr->ops.put)
522 k->put = ops[i].put;
523 if (k->get == NULL && ops[i].id == hdr->ops.get)
524 k->get = ops[i].get;
525 if (k->info == NULL && ops[i].id == hdr->ops.info)
526 k->info = ops[i].info;
8a978234
LG
527 }
528
88a17d8f
ML
529 /* vendor specific handlers found ? */
530 if (k->put && k->get && k->info)
531 return 0;
532
533 /* none found so try standard kcontrol handlers */
2b5cdb91
ML
534 ops = io_ops;
535 num_ops = ARRAY_SIZE(io_ops);
88a17d8f
ML
536 for (i = 0; i < num_ops; i++) {
537
538 if (k->put == NULL && ops[i].id == hdr->ops.put)
539 k->put = ops[i].put;
540 if (k->get == NULL && ops[i].id == hdr->ops.get)
541 k->get = ops[i].get;
542 if (k->info == NULL && ops[i].id == hdr->ops.info)
543 k->info = ops[i].info;
544 }
545
546 /* standard handlers found ? */
8a978234
LG
547 if (k->put && k->get && k->info)
548 return 0;
549
550 /* nothing to bind */
551 return -EINVAL;
552}
553
554/* bind a widgets to it's evnt handlers */
555int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
556 const struct snd_soc_tplg_widget_events *events,
557 int num_events, u16 event_type)
558{
559 int i;
560
561 w->event = NULL;
562
563 for (i = 0; i < num_events; i++) {
564 if (event_type == events[i].type) {
565
566 /* found - so assign event */
567 w->event = events[i].event_handler;
568 return 0;
569 }
570 }
571
572 /* not found */
573 return -EINVAL;
574}
575EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event);
576
577/* optionally pass new dynamic kcontrol to component driver. */
578static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
579 struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
580{
581 if (tplg->comp && tplg->ops && tplg->ops->control_load)
582 return tplg->ops->control_load(tplg->comp, k, hdr);
583
584 return 0;
585}
586
8a978234 587
28a87eeb
ML
588static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
589 struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
590{
591 unsigned int item_len = 2 * sizeof(unsigned int);
592 unsigned int *p;
8a978234 593
28a87eeb
ML
594 p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
595 if (!p)
8a978234
LG
596 return -ENOMEM;
597
28a87eeb
ML
598 p[0] = SNDRV_CTL_TLVT_DB_SCALE;
599 p[1] = item_len;
600 p[2] = scale->min;
601 p[3] = (scale->step & TLV_DB_SCALE_MASK)
602 | (scale->mute ? TLV_DB_SCALE_MUTE : 0);
603
604 kc->tlv.p = (void *)p;
605 return 0;
606}
607
8a978234 608static int soc_tplg_create_tlv(struct soc_tplg *tplg,
28a87eeb 609 struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
8a978234
LG
610{
611 struct snd_soc_tplg_ctl_tlv *tplg_tlv;
8a978234 612
28a87eeb 613 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
8a978234
LG
614 return 0;
615
28a87eeb
ML
616 if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
617 kc->tlv.c = snd_soc_bytes_tlv_callback;
618 } else {
619 tplg_tlv = &tc->tlv;
620 switch (tplg_tlv->type) {
621 case SNDRV_CTL_TLVT_DB_SCALE:
622 return soc_tplg_create_tlv_db_scale(tplg, kc,
623 &tplg_tlv->scale);
8a978234 624
28a87eeb
ML
625 /* TODO: add support for other TLV types */
626 default:
627 dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
628 tplg_tlv->type);
629 return -EINVAL;
630 }
631 }
8a978234
LG
632
633 return 0;
634}
635
636static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
637 struct snd_kcontrol_new *kc)
638{
639 kfree(kc->tlv.p);
640}
641
642static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
643 size_t size)
644{
645 struct snd_soc_tplg_bytes_control *be;
646 struct soc_bytes_ext *sbe;
647 struct snd_kcontrol_new kc;
648 int i, err;
649
650 if (soc_tplg_check_elem_count(tplg,
651 sizeof(struct snd_soc_tplg_bytes_control), count,
652 size, "mixer bytes")) {
653 dev_err(tplg->dev, "ASoC: Invalid count %d for byte control\n",
654 count);
655 return -EINVAL;
656 }
657
658 for (i = 0; i < count; i++) {
659 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
660
661 /* validate kcontrol */
662 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
663 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
664 return -EINVAL;
665
666 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
667 if (sbe == NULL)
668 return -ENOMEM;
669
670 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
671 be->priv.size);
672
673 dev_dbg(tplg->dev,
674 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
675 be->hdr.name, be->hdr.access);
676
677 memset(&kc, 0, sizeof(kc));
678 kc.name = be->hdr.name;
679 kc.private_value = (long)sbe;
680 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
681 kc.access = be->hdr.access;
682
683 sbe->max = be->max;
684 sbe->dobj.type = SND_SOC_DOBJ_BYTES;
685 sbe->dobj.ops = tplg->ops;
686 INIT_LIST_HEAD(&sbe->dobj.list);
687
688 /* map io handlers */
2b5cdb91 689 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, tplg);
8a978234
LG
690 if (err) {
691 soc_control_err(tplg, &be->hdr, be->hdr.name);
692 kfree(sbe);
693 continue;
694 }
695
696 /* pass control to driver for optional further init */
697 err = soc_tplg_init_kcontrol(tplg, &kc,
698 (struct snd_soc_tplg_ctl_hdr *)be);
699 if (err < 0) {
700 dev_err(tplg->dev, "ASoC: failed to init %s\n",
701 be->hdr.name);
702 kfree(sbe);
703 continue;
704 }
705
706 /* register control here */
707 err = soc_tplg_add_kcontrol(tplg, &kc,
708 &sbe->dobj.control.kcontrol);
709 if (err < 0) {
710 dev_err(tplg->dev, "ASoC: failed to add %s\n",
711 be->hdr.name);
712 kfree(sbe);
713 continue;
714 }
715
716 list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
717 }
718 return 0;
719
720}
721
722static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
723 size_t size)
724{
725 struct snd_soc_tplg_mixer_control *mc;
726 struct soc_mixer_control *sm;
727 struct snd_kcontrol_new kc;
728 int i, err;
729
730 if (soc_tplg_check_elem_count(tplg,
731 sizeof(struct snd_soc_tplg_mixer_control),
732 count, size, "mixers")) {
733
734 dev_err(tplg->dev, "ASoC: invalid count %d for controls\n",
735 count);
736 return -EINVAL;
737 }
738
739 for (i = 0; i < count; i++) {
740 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
741
742 /* validate kcontrol */
743 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
744 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
745 return -EINVAL;
746
747 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
748 if (sm == NULL)
749 return -ENOMEM;
750 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
751 mc->priv.size);
752
753 dev_dbg(tplg->dev,
754 "ASoC: adding mixer kcontrol %s with access 0x%x\n",
755 mc->hdr.name, mc->hdr.access);
756
757 memset(&kc, 0, sizeof(kc));
758 kc.name = mc->hdr.name;
759 kc.private_value = (long)sm;
760 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
761 kc.access = mc->hdr.access;
762
763 /* we only support FL/FR channel mapping atm */
764 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
765 SNDRV_CHMAP_FL);
766 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
767 SNDRV_CHMAP_FR);
768 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
769 SNDRV_CHMAP_FL);
770 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
771 SNDRV_CHMAP_FR);
772
773 sm->max = mc->max;
774 sm->min = mc->min;
775 sm->invert = mc->invert;
776 sm->platform_max = mc->platform_max;
777 sm->dobj.index = tplg->index;
778 sm->dobj.ops = tplg->ops;
779 sm->dobj.type = SND_SOC_DOBJ_MIXER;
780 INIT_LIST_HEAD(&sm->dobj.list);
781
782 /* map io handlers */
2b5cdb91 783 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, tplg);
8a978234
LG
784 if (err) {
785 soc_control_err(tplg, &mc->hdr, mc->hdr.name);
786 kfree(sm);
787 continue;
788 }
789
790 /* pass control to driver for optional further init */
791 err = soc_tplg_init_kcontrol(tplg, &kc,
792 (struct snd_soc_tplg_ctl_hdr *) mc);
793 if (err < 0) {
794 dev_err(tplg->dev, "ASoC: failed to init %s\n",
795 mc->hdr.name);
796 kfree(sm);
797 continue;
798 }
799
800 /* create any TLV data */
28a87eeb 801 soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
8a978234
LG
802
803 /* register control here */
804 err = soc_tplg_add_kcontrol(tplg, &kc,
805 &sm->dobj.control.kcontrol);
806 if (err < 0) {
807 dev_err(tplg->dev, "ASoC: failed to add %s\n",
808 mc->hdr.name);
809 soc_tplg_free_tlv(tplg, &kc);
810 kfree(sm);
811 continue;
812 }
813
814 list_add(&sm->dobj.list, &tplg->comp->dobj_list);
815 }
816
817 return 0;
818}
819
820static int soc_tplg_denum_create_texts(struct soc_enum *se,
821 struct snd_soc_tplg_enum_control *ec)
822{
823 int i, ret;
824
825 se->dobj.control.dtexts =
826 kzalloc(sizeof(char *) * ec->items, GFP_KERNEL);
827 if (se->dobj.control.dtexts == NULL)
828 return -ENOMEM;
829
830 for (i = 0; i < ec->items; i++) {
831
832 if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
833 SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
834 ret = -EINVAL;
835 goto err;
836 }
837
838 se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
839 if (!se->dobj.control.dtexts[i]) {
840 ret = -ENOMEM;
841 goto err;
842 }
843 }
844
845 return 0;
846
847err:
848 for (--i; i >= 0; i--)
849 kfree(se->dobj.control.dtexts[i]);
850 kfree(se->dobj.control.dtexts);
851 return ret;
852}
853
854static int soc_tplg_denum_create_values(struct soc_enum *se,
855 struct snd_soc_tplg_enum_control *ec)
856{
857 if (ec->items > sizeof(*ec->values))
858 return -EINVAL;
859
376c0afe
AH
860 se->dobj.control.dvalues = kmemdup(ec->values,
861 ec->items * sizeof(u32),
862 GFP_KERNEL);
8a978234
LG
863 if (!se->dobj.control.dvalues)
864 return -ENOMEM;
865
8a978234
LG
866 return 0;
867}
868
869static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
870 size_t size)
871{
872 struct snd_soc_tplg_enum_control *ec;
873 struct soc_enum *se;
874 struct snd_kcontrol_new kc;
875 int i, ret, err;
876
877 if (soc_tplg_check_elem_count(tplg,
878 sizeof(struct snd_soc_tplg_enum_control),
879 count, size, "enums")) {
880
881 dev_err(tplg->dev, "ASoC: invalid count %d for enum controls\n",
882 count);
883 return -EINVAL;
884 }
885
886 for (i = 0; i < count; i++) {
887 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
888 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
889 ec->priv.size);
890
891 /* validate kcontrol */
892 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
893 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
894 return -EINVAL;
895
896 se = kzalloc((sizeof(*se)), GFP_KERNEL);
897 if (se == NULL)
898 return -ENOMEM;
899
900 dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
901 ec->hdr.name, ec->items);
902
903 memset(&kc, 0, sizeof(kc));
904 kc.name = ec->hdr.name;
905 kc.private_value = (long)se;
906 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
907 kc.access = ec->hdr.access;
908
909 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
910 se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
911 SNDRV_CHMAP_FL);
912 se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
913 SNDRV_CHMAP_FL);
914
915 se->items = ec->items;
916 se->mask = ec->mask;
917 se->dobj.index = tplg->index;
918 se->dobj.type = SND_SOC_DOBJ_ENUM;
919 se->dobj.ops = tplg->ops;
920 INIT_LIST_HEAD(&se->dobj.list);
921
922 switch (ec->hdr.ops.info) {
923 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
924 case SND_SOC_TPLG_CTL_ENUM_VALUE:
925 err = soc_tplg_denum_create_values(se, ec);
926 if (err < 0) {
927 dev_err(tplg->dev,
928 "ASoC: could not create values for %s\n",
929 ec->hdr.name);
930 kfree(se);
931 continue;
932 }
933 /* fall through and create texts */
934 case SND_SOC_TPLG_CTL_ENUM:
935 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
936 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
937 err = soc_tplg_denum_create_texts(se, ec);
938 if (err < 0) {
939 dev_err(tplg->dev,
940 "ASoC: could not create texts for %s\n",
941 ec->hdr.name);
942 kfree(se);
943 continue;
944 }
945 break;
946 default:
947 dev_err(tplg->dev,
948 "ASoC: invalid enum control type %d for %s\n",
949 ec->hdr.ops.info, ec->hdr.name);
950 kfree(se);
951 continue;
952 }
953
954 /* map io handlers */
2b5cdb91 955 err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, tplg);
8a978234
LG
956 if (err) {
957 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
958 kfree(se);
959 continue;
960 }
961
962 /* pass control to driver for optional further init */
963 err = soc_tplg_init_kcontrol(tplg, &kc,
964 (struct snd_soc_tplg_ctl_hdr *) ec);
965 if (err < 0) {
966 dev_err(tplg->dev, "ASoC: failed to init %s\n",
967 ec->hdr.name);
968 kfree(se);
969 continue;
970 }
971
972 /* register control here */
973 ret = soc_tplg_add_kcontrol(tplg,
974 &kc, &se->dobj.control.kcontrol);
975 if (ret < 0) {
976 dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n",
977 ec->hdr.name);
978 kfree(se);
979 continue;
980 }
981
982 list_add(&se->dobj.list, &tplg->comp->dobj_list);
983 }
984
985 return 0;
986}
987
988static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
989 struct snd_soc_tplg_hdr *hdr)
990{
991 struct snd_soc_tplg_ctl_hdr *control_hdr;
992 int i;
993
994 if (tplg->pass != SOC_TPLG_PASS_MIXER) {
995 tplg->pos += hdr->size + hdr->payload_size;
996 return 0;
997 }
998
999 dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
1000 soc_tplg_get_offset(tplg));
1001
1002 for (i = 0; i < hdr->count; i++) {
1003
1004 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1005
1006 switch (control_hdr->ops.info) {
1007 case SND_SOC_TPLG_CTL_VOLSW:
1008 case SND_SOC_TPLG_CTL_STROBE:
1009 case SND_SOC_TPLG_CTL_VOLSW_SX:
1010 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1011 case SND_SOC_TPLG_CTL_RANGE:
1012 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1013 case SND_SOC_TPLG_DAPM_CTL_PIN:
1014 soc_tplg_dmixer_create(tplg, 1, hdr->payload_size);
1015 break;
1016 case SND_SOC_TPLG_CTL_ENUM:
1017 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1018 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1019 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1020 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1021 soc_tplg_denum_create(tplg, 1, hdr->payload_size);
1022 break;
1023 case SND_SOC_TPLG_CTL_BYTES:
1024 soc_tplg_dbytes_create(tplg, 1, hdr->payload_size);
1025 break;
1026 default:
1027 soc_bind_err(tplg, control_hdr, i);
1028 return -EINVAL;
1029 }
1030 }
1031
1032 return 0;
1033}
1034
1035static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
1036 struct snd_soc_tplg_hdr *hdr)
1037{
1038 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1039 struct snd_soc_dapm_route route;
1040 struct snd_soc_tplg_dapm_graph_elem *elem;
1041 int count = hdr->count, i;
1042
1043 if (tplg->pass != SOC_TPLG_PASS_GRAPH) {
1044 tplg->pos += hdr->size + hdr->payload_size;
1045 return 0;
1046 }
1047
1048 if (soc_tplg_check_elem_count(tplg,
1049 sizeof(struct snd_soc_tplg_dapm_graph_elem),
1050 count, hdr->payload_size, "graph")) {
1051
1052 dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n",
1053 count);
1054 return -EINVAL;
1055 }
1056
1057 dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count);
1058
1059 for (i = 0; i < count; i++) {
1060 elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
1061 tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
1062
1063 /* validate routes */
1064 if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1065 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1066 return -EINVAL;
1067 if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1068 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1069 return -EINVAL;
1070 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1071 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1072 return -EINVAL;
1073
1074 route.source = elem->source;
1075 route.sink = elem->sink;
1076 route.connected = NULL; /* set to NULL atm for tplg users */
1077 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
1078 route.control = NULL;
1079 else
1080 route.control = elem->control;
1081
1082 /* add route, but keep going if some fail */
1083 snd_soc_dapm_add_routes(dapm, &route, 1);
1084 }
1085
1086 return 0;
1087}
1088
1089static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1090 struct soc_tplg *tplg, int num_kcontrols)
1091{
1092 struct snd_kcontrol_new *kc;
1093 struct soc_mixer_control *sm;
1094 struct snd_soc_tplg_mixer_control *mc;
1095 int i, err;
1096
4ca7deb1 1097 kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
8a978234
LG
1098 if (kc == NULL)
1099 return NULL;
1100
1101 for (i = 0; i < num_kcontrols; i++) {
1102 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
1103 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
1104 if (sm == NULL)
1105 goto err;
1106
1107 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
1108 mc->priv.size);
1109
1110 /* validate kcontrol */
1111 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1112 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1113 goto err_str;
1114
1115 dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n",
1116 mc->hdr.name, i);
1117
1118 kc[i].name = mc->hdr.name;
1119 kc[i].private_value = (long)sm;
1120 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1121 kc[i].access = mc->hdr.access;
1122
1123 /* we only support FL/FR channel mapping atm */
1124 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
1125 SNDRV_CHMAP_FL);
1126 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
1127 SNDRV_CHMAP_FR);
1128 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
1129 SNDRV_CHMAP_FL);
1130 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
1131 SNDRV_CHMAP_FR);
1132
1133 sm->max = mc->max;
1134 sm->min = mc->min;
1135 sm->invert = mc->invert;
1136 sm->platform_max = mc->platform_max;
1137 sm->dobj.index = tplg->index;
1138 INIT_LIST_HEAD(&sm->dobj.list);
1139
1140 /* map io handlers */
2b5cdb91 1141 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], tplg);
8a978234
LG
1142 if (err) {
1143 soc_control_err(tplg, &mc->hdr, mc->hdr.name);
1144 kfree(sm);
1145 continue;
1146 }
1147
1148 /* pass control to driver for optional further init */
1149 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1150 (struct snd_soc_tplg_ctl_hdr *)mc);
1151 if (err < 0) {
1152 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1153 mc->hdr.name);
1154 kfree(sm);
1155 continue;
1156 }
1157 }
1158 return kc;
1159
1160err_str:
1161 kfree(sm);
1162err:
1163 for (--i; i >= 0; i--)
1164 kfree((void *)kc[i].private_value);
1165 kfree(kc);
1166 return NULL;
1167}
1168
1169static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1170 struct soc_tplg *tplg)
1171{
1172 struct snd_kcontrol_new *kc;
1173 struct snd_soc_tplg_enum_control *ec;
1174 struct soc_enum *se;
1175 int i, err;
1176
1177 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1178 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1179 ec->priv.size);
1180
1181 /* validate kcontrol */
1182 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1183 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1184 return NULL;
1185
1186 kc = kzalloc(sizeof(*kc), GFP_KERNEL);
1187 if (kc == NULL)
1188 return NULL;
1189
1190 se = kzalloc(sizeof(*se), GFP_KERNEL);
1191 if (se == NULL)
1192 goto err;
1193
1194 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1195 ec->hdr.name);
1196
1197 kc->name = ec->hdr.name;
1198 kc->private_value = (long)se;
1199 kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1200 kc->access = ec->hdr.access;
1201
1202 /* we only support FL/FR channel mapping atm */
1203 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1204 se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL);
1205 se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR);
1206
1207 se->items = ec->items;
1208 se->mask = ec->mask;
1209 se->dobj.index = tplg->index;
1210
1211 switch (ec->hdr.ops.info) {
1212 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1213 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1214 err = soc_tplg_denum_create_values(se, ec);
1215 if (err < 0) {
1216 dev_err(tplg->dev, "ASoC: could not create values for %s\n",
1217 ec->hdr.name);
1218 goto err_se;
1219 }
1220 /* fall through to create texts */
1221 case SND_SOC_TPLG_CTL_ENUM:
1222 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1223 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1224 err = soc_tplg_denum_create_texts(se, ec);
1225 if (err < 0) {
1226 dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
1227 ec->hdr.name);
1228 goto err_se;
1229 }
1230 break;
1231 default:
1232 dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1233 ec->hdr.ops.info, ec->hdr.name);
1234 goto err_se;
1235 }
1236
1237 /* map io handlers */
2b5cdb91 1238 err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg);
8a978234
LG
1239 if (err) {
1240 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1241 goto err_se;
1242 }
1243
1244 /* pass control to driver for optional further init */
1245 err = soc_tplg_init_kcontrol(tplg, kc,
1246 (struct snd_soc_tplg_ctl_hdr *)ec);
1247 if (err < 0) {
1248 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1249 ec->hdr.name);
1250 goto err_se;
1251 }
1252
1253 return kc;
1254
1255err_se:
1256 /* free values and texts */
1257 kfree(se->dobj.control.dvalues);
1258 for (i = 0; i < ec->items; i++)
1259 kfree(se->dobj.control.dtexts[i]);
1260
1261 kfree(se);
1262err:
1263 kfree(kc);
1264
1265 return NULL;
1266}
1267
1268static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
1269 struct soc_tplg *tplg, int count)
1270{
1271 struct snd_soc_tplg_bytes_control *be;
1272 struct soc_bytes_ext *sbe;
1273 struct snd_kcontrol_new *kc;
1274 int i, err;
1275
4ca7deb1 1276 kc = kcalloc(count, sizeof(*kc), GFP_KERNEL);
8a978234
LG
1277 if (!kc)
1278 return NULL;
1279
1280 for (i = 0; i < count; i++) {
1281 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
1282
1283 /* validate kcontrol */
1284 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1285 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1286 goto err;
1287
1288 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
1289 if (sbe == NULL)
1290 goto err;
1291
1292 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
1293 be->priv.size);
1294
1295 dev_dbg(tplg->dev,
1296 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
1297 be->hdr.name, be->hdr.access);
1298
8a978234
LG
1299 kc[i].name = be->hdr.name;
1300 kc[i].private_value = (long)sbe;
1301 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1302 kc[i].access = be->hdr.access;
1303
1304 sbe->max = be->max;
1305 INIT_LIST_HEAD(&sbe->dobj.list);
1306
1307 /* map standard io handlers and check for external handlers */
2b5cdb91 1308 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], tplg);
8a978234
LG
1309 if (err) {
1310 soc_control_err(tplg, &be->hdr, be->hdr.name);
1311 kfree(sbe);
1312 continue;
1313 }
1314
1315 /* pass control to driver for optional further init */
1316 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1317 (struct snd_soc_tplg_ctl_hdr *)be);
1318 if (err < 0) {
1319 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1320 be->hdr.name);
1321 kfree(sbe);
1322 continue;
1323 }
1324 }
1325
1326 return kc;
1327
1328err:
1329 for (--i; i >= 0; i--)
1330 kfree((void *)kc[i].private_value);
1331
1332 kfree(kc);
1333 return NULL;
1334}
1335
1336static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1337 struct snd_soc_tplg_dapm_widget *w)
1338{
1339 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1340 struct snd_soc_dapm_widget template, *widget;
1341 struct snd_soc_tplg_ctl_hdr *control_hdr;
1342 struct snd_soc_card *card = tplg->comp->card;
1343 int ret = 0;
1344
1345 if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1346 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1347 return -EINVAL;
1348 if (strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1349 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1350 return -EINVAL;
1351
1352 dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n",
1353 w->name, w->id);
1354
1355 memset(&template, 0, sizeof(template));
1356
1357 /* map user to kernel widget ID */
1358 template.id = get_widget_id(w->id);
1359 if (template.id < 0)
1360 return template.id;
1361
1362 template.name = kstrdup(w->name, GFP_KERNEL);
1363 if (!template.name)
1364 return -ENOMEM;
1365 template.sname = kstrdup(w->sname, GFP_KERNEL);
1366 if (!template.sname) {
1367 ret = -ENOMEM;
1368 goto err;
1369 }
1370 template.reg = w->reg;
1371 template.shift = w->shift;
1372 template.mask = w->mask;
6dc6db79 1373 template.subseq = w->subseq;
8a978234
LG
1374 template.on_val = w->invert ? 0 : 1;
1375 template.off_val = w->invert ? 1 : 0;
1376 template.ignore_suspend = w->ignore_suspend;
1377 template.event_flags = w->event_flags;
1378 template.dobj.index = tplg->index;
1379
1380 tplg->pos +=
1381 (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size);
1382 if (w->num_kcontrols == 0) {
1383 template.num_kcontrols = 0;
1384 goto widget;
1385 }
1386
1387 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1388 dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
1389 w->name, w->num_kcontrols, control_hdr->type);
1390
1391 switch (control_hdr->ops.info) {
1392 case SND_SOC_TPLG_CTL_VOLSW:
1393 case SND_SOC_TPLG_CTL_STROBE:
1394 case SND_SOC_TPLG_CTL_VOLSW_SX:
1395 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1396 case SND_SOC_TPLG_CTL_RANGE:
1397 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1398 template.num_kcontrols = w->num_kcontrols;
1399 template.kcontrol_news =
1400 soc_tplg_dapm_widget_dmixer_create(tplg,
1401 template.num_kcontrols);
1402 if (!template.kcontrol_news) {
1403 ret = -ENOMEM;
1404 goto hdr_err;
1405 }
1406 break;
1407 case SND_SOC_TPLG_CTL_ENUM:
1408 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1409 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1410 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1411 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1412 template.dobj.widget.kcontrol_enum = 1;
1413 template.num_kcontrols = 1;
1414 template.kcontrol_news =
1415 soc_tplg_dapm_widget_denum_create(tplg);
1416 if (!template.kcontrol_news) {
1417 ret = -ENOMEM;
1418 goto hdr_err;
1419 }
1420 break;
1421 case SND_SOC_TPLG_CTL_BYTES:
1422 template.num_kcontrols = w->num_kcontrols;
1423 template.kcontrol_news =
1424 soc_tplg_dapm_widget_dbytes_create(tplg,
1425 template.num_kcontrols);
1426 if (!template.kcontrol_news) {
1427 ret = -ENOMEM;
1428 goto hdr_err;
1429 }
1430 break;
1431 default:
1432 dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
1433 control_hdr->ops.get, control_hdr->ops.put,
1434 control_hdr->ops.info);
1435 ret = -EINVAL;
1436 goto hdr_err;
1437 }
1438
1439widget:
1440 ret = soc_tplg_widget_load(tplg, &template, w);
1441 if (ret < 0)
1442 goto hdr_err;
1443
1444 /* card dapm mutex is held by the core if we are loading topology
1445 * data during sound card init. */
1446 if (card->instantiated)
1447 widget = snd_soc_dapm_new_control(dapm, &template);
1448 else
1449 widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
1450 if (widget == NULL) {
1451 dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
1452 w->name);
1453 goto hdr_err;
1454 }
1455
1456 widget->dobj.type = SND_SOC_DOBJ_WIDGET;
1457 widget->dobj.ops = tplg->ops;
1458 widget->dobj.index = tplg->index;
1459 list_add(&widget->dobj.list, &tplg->comp->dobj_list);
1460 return 0;
1461
1462hdr_err:
1463 kfree(template.sname);
1464err:
1465 kfree(template.name);
1466 return ret;
1467}
1468
1469static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
1470 struct snd_soc_tplg_hdr *hdr)
1471{
1472 struct snd_soc_tplg_dapm_widget *widget;
1473 int ret, count = hdr->count, i;
1474
1475 if (tplg->pass != SOC_TPLG_PASS_WIDGET)
1476 return 0;
1477
1478 dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count);
1479
1480 for (i = 0; i < count; i++) {
1481 widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
1482 ret = soc_tplg_dapm_widget_create(tplg, widget);
1483 if (ret < 0)
1484 dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
1485 widget->name);
1486 }
1487
1488 return 0;
1489}
1490
1491static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
1492{
1493 struct snd_soc_card *card = tplg->comp->card;
1494 int ret;
1495
1496 /* Card might not have been registered at this point.
1497 * If so, just return success.
1498 */
1499 if (!card || !card->instantiated) {
1500 dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
1501 "Do not add new widgets now\n");
1502 return 0;
1503 }
1504
1505 ret = snd_soc_dapm_new_widgets(card);
1506 if (ret < 0)
1507 dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n",
1508 ret);
1509
1510 return 0;
1511}
1512
1513static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
1514 struct snd_soc_tplg_hdr *hdr)
1515{
1516 struct snd_soc_tplg_pcm_dai *pcm_dai;
1517 struct snd_soc_dobj *dobj;
1518 int count = hdr->count;
1519 int ret;
1520
1521 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
1522 return 0;
1523
1524 pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos;
1525
1526 if (soc_tplg_check_elem_count(tplg,
1527 sizeof(struct snd_soc_tplg_pcm_dai), count,
1528 hdr->payload_size, "PCM DAI")) {
1529 dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
1530 count);
1531 return -EINVAL;
1532 }
1533
1534 dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
1535 tplg->pos += sizeof(struct snd_soc_tplg_pcm_dai) * count;
1536
1537 dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL);
1538 if (dobj == NULL)
1539 return -ENOMEM;
1540
1541 /* Call the platform driver call back to register the dais */
1542 ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count);
1543 if (ret < 0) {
1544 dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n");
1545 goto err;
1546 }
1547
1548 dobj->type = get_dobj_type(hdr, NULL);
1549 dobj->pcm_dai.count = count;
1550 dobj->pcm_dai.pd = pcm_dai;
1551 dobj->ops = tplg->ops;
1552 dobj->index = tplg->index;
1553 list_add(&dobj->list, &tplg->comp->dobj_list);
1554 return 0;
1555
1556err:
1557 kfree(dobj);
1558 return ret;
1559}
1560
1561static int soc_tplg_manifest_load(struct soc_tplg *tplg,
1562 struct snd_soc_tplg_hdr *hdr)
1563{
1564 struct snd_soc_tplg_manifest *manifest;
1565
1566 if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
1567 return 0;
1568
1569 manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
1570 tplg->pos += sizeof(struct snd_soc_tplg_manifest);
1571
1572 if (tplg->comp && tplg->ops && tplg->ops->manifest)
1573 return tplg->ops->manifest(tplg->comp, manifest);
1574
1575 dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n");
1576 return 0;
1577}
1578
1579/* validate header magic, size and type */
1580static int soc_valid_header(struct soc_tplg *tplg,
1581 struct snd_soc_tplg_hdr *hdr)
1582{
1583 if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
1584 return 0;
1585
1586 /* big endian firmware objects not supported atm */
1587 if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
1588 dev_err(tplg->dev,
1589 "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
1590 tplg->pass, hdr->magic,
1591 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
1592 return -EINVAL;
1593 }
1594
1595 if (hdr->magic != SND_SOC_TPLG_MAGIC) {
1596 dev_err(tplg->dev,
1597 "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
1598 tplg->pass, hdr->magic,
1599 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
1600 return -EINVAL;
1601 }
1602
1603 if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
1604 dev_err(tplg->dev,
1605 "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
1606 tplg->pass, hdr->abi,
1607 SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg),
1608 tplg->fw->size);
1609 return -EINVAL;
1610 }
1611
1612 if (hdr->payload_size == 0) {
1613 dev_err(tplg->dev, "ASoC: header has 0 size at offset 0x%lx.\n",
1614 soc_tplg_get_hdr_offset(tplg));
1615 return -EINVAL;
1616 }
1617
1618 if (tplg->pass == hdr->type)
1619 dev_dbg(tplg->dev,
1620 "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
1621 hdr->payload_size, hdr->type, hdr->version,
1622 hdr->vendor_type, tplg->pass);
1623
1624 return 1;
1625}
1626
1627/* check header type and call appropriate handler */
1628static int soc_tplg_load_header(struct soc_tplg *tplg,
1629 struct snd_soc_tplg_hdr *hdr)
1630{
1631 tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
1632
1633 /* check for matching ID */
1634 if (hdr->index != tplg->req_index &&
1635 hdr->index != SND_SOC_TPLG_INDEX_ALL)
1636 return 0;
1637
1638 tplg->index = hdr->index;
1639
1640 switch (hdr->type) {
1641 case SND_SOC_TPLG_TYPE_MIXER:
1642 case SND_SOC_TPLG_TYPE_ENUM:
1643 case SND_SOC_TPLG_TYPE_BYTES:
1644 return soc_tplg_kcontrol_elems_load(tplg, hdr);
1645 case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
1646 return soc_tplg_dapm_graph_elems_load(tplg, hdr);
1647 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
1648 return soc_tplg_dapm_widget_elems_load(tplg, hdr);
1649 case SND_SOC_TPLG_TYPE_PCM:
1650 case SND_SOC_TPLG_TYPE_DAI_LINK:
1651 case SND_SOC_TPLG_TYPE_CODEC_LINK:
1652 return soc_tplg_pcm_dai_elems_load(tplg, hdr);
1653 case SND_SOC_TPLG_TYPE_MANIFEST:
1654 return soc_tplg_manifest_load(tplg, hdr);
1655 default:
1656 /* bespoke vendor data object */
1657 return soc_tplg_vendor_load(tplg, hdr);
1658 }
1659
1660 return 0;
1661}
1662
1663/* process the topology file headers */
1664static int soc_tplg_process_headers(struct soc_tplg *tplg)
1665{
1666 struct snd_soc_tplg_hdr *hdr;
1667 int ret;
1668
1669 tplg->pass = SOC_TPLG_PASS_START;
1670
1671 /* process the header types from start to end */
1672 while (tplg->pass <= SOC_TPLG_PASS_END) {
1673
1674 tplg->hdr_pos = tplg->fw->data;
1675 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
1676
1677 while (!soc_tplg_is_eof(tplg)) {
1678
1679 /* make sure header is valid before loading */
1680 ret = soc_valid_header(tplg, hdr);
1681 if (ret < 0)
1682 return ret;
1683 else if (ret == 0)
1684 break;
1685
1686 /* load the header object */
1687 ret = soc_tplg_load_header(tplg, hdr);
1688 if (ret < 0)
1689 return ret;
1690
1691 /* goto next header */
1692 tplg->hdr_pos += hdr->payload_size +
1693 sizeof(struct snd_soc_tplg_hdr);
1694 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
1695 }
1696
1697 /* next data type pass */
1698 tplg->pass++;
1699 }
1700
1701 /* signal DAPM we are complete */
1702 ret = soc_tplg_dapm_complete(tplg);
1703 if (ret < 0)
1704 dev_err(tplg->dev,
1705 "ASoC: failed to initialise DAPM from Firmware\n");
1706
1707 return ret;
1708}
1709
1710static int soc_tplg_load(struct soc_tplg *tplg)
1711{
1712 int ret;
1713
1714 ret = soc_tplg_process_headers(tplg);
1715 if (ret == 0)
1716 soc_tplg_complete(tplg);
1717
1718 return ret;
1719}
1720
1721/* load audio component topology from "firmware" file */
1722int snd_soc_tplg_component_load(struct snd_soc_component *comp,
1723 struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
1724{
1725 struct soc_tplg tplg;
1726
1727 /* setup parsing context */
1728 memset(&tplg, 0, sizeof(tplg));
1729 tplg.fw = fw;
1730 tplg.dev = comp->dev;
1731 tplg.comp = comp;
1732 tplg.ops = ops;
1733 tplg.req_index = id;
1734 tplg.io_ops = ops->io_ops;
1735 tplg.io_ops_count = ops->io_ops_count;
1736
1737 return soc_tplg_load(&tplg);
1738}
1739EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
1740
1741/* remove this dynamic widget */
1742void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
1743{
1744 /* make sure we are a widget */
1745 if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
1746 return;
1747
1748 remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
1749}
1750EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
1751
1752/* remove all dynamic widgets from this DAPM context */
1753void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
1754 u32 index)
1755{
1756 struct snd_soc_dapm_widget *w, *next_w;
1757 struct snd_soc_dapm_path *p, *next_p;
1758
1759 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
1760
1761 /* make sure we are a widget with correct context */
1762 if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
1763 continue;
1764
1765 /* match ID */
1766 if (w->dobj.index != index &&
1767 w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
1768 continue;
1769
1770 list_del(&w->list);
1771
1772 /*
1773 * remove source and sink paths associated to this widget.
1774 * While removing the path, remove reference to it from both
1775 * source and sink widgets so that path is removed only once.
1776 */
1777 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
1778 list_del(&p->list_sink);
1779 list_del(&p->list_source);
1780 list_del(&p->list);
1781 kfree(p);
1782 }
1783 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
1784 list_del(&p->list_sink);
1785 list_del(&p->list_source);
1786 list_del(&p->list);
1787 kfree(p);
1788 }
1789 /* check and free and dynamic widget kcontrols */
1790 snd_soc_tplg_widget_remove(w);
1791 kfree(w->kcontrols);
1792 kfree(w->name);
1793 kfree(w);
1794 }
1795}
1796EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
1797
1798/* remove dynamic controls from the component driver */
1799int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
1800{
1801 struct snd_soc_dobj *dobj, *next_dobj;
1802 int pass = SOC_TPLG_PASS_END;
1803
1804 /* process the header types from end to start */
1805 while (pass >= SOC_TPLG_PASS_START) {
1806
1807 /* remove mixer controls */
1808 list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
1809 list) {
1810
1811 /* match index */
1812 if (dobj->index != index &&
1813 dobj->index != SND_SOC_TPLG_INDEX_ALL)
1814 continue;
1815
1816 switch (dobj->type) {
1817 case SND_SOC_DOBJ_MIXER:
1818 remove_mixer(comp, dobj, pass);
1819 break;
1820 case SND_SOC_DOBJ_ENUM:
1821 remove_enum(comp, dobj, pass);
1822 break;
1823 case SND_SOC_DOBJ_BYTES:
1824 remove_bytes(comp, dobj, pass);
1825 break;
1826 case SND_SOC_DOBJ_WIDGET:
1827 remove_widget(comp, dobj, pass);
1828 break;
1829 case SND_SOC_DOBJ_PCM:
1830 case SND_SOC_DOBJ_DAI_LINK:
1831 case SND_SOC_DOBJ_CODEC_LINK:
1832 remove_pcm_dai(comp, dobj, pass);
1833 break;
1834 default:
1835 dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",
1836 dobj->type);
1837 break;
1838 }
1839 }
1840 pass--;
1841 }
1842
1843 /* let caller know if FW can be freed when no objects are left */
1844 return !list_empty(&comp->dobj_list);
1845}
1846EXPORT_SYMBOL_GPL(snd_soc_tplg_component_remove);
This page took 0.098458 seconds and 5 git commands to generate.