ASoC: topology: Bind vendor specific kcontrol handlers before standard ones
[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,
511 const struct snd_soc_tplg_kcontrol_ops *ops, int num_ops,
512 const struct snd_soc_tplg_kcontrol_ops *bops, int num_bops)
513{
514 int i;
515
88a17d8f 516 /* try and map vendor specific kcontrol handlers first */
8a978234
LG
517 for (i = 0; i < num_bops; i++) {
518
519 if (k->put == NULL && bops[i].id == hdr->ops.put)
520 k->put = bops[i].put;
521 if (k->get == NULL && bops[i].id == hdr->ops.get)
522 k->get = bops[i].get;
54068983 523 if (k->info == NULL && bops[i].id == hdr->ops.info)
8a978234
LG
524 k->info = bops[i].info;
525 }
526
88a17d8f
ML
527 /* vendor specific handlers found ? */
528 if (k->put && k->get && k->info)
529 return 0;
530
531 /* none found so try standard kcontrol handlers */
532 for (i = 0; i < num_ops; i++) {
533
534 if (k->put == NULL && ops[i].id == hdr->ops.put)
535 k->put = ops[i].put;
536 if (k->get == NULL && ops[i].id == hdr->ops.get)
537 k->get = ops[i].get;
538 if (k->info == NULL && ops[i].id == hdr->ops.info)
539 k->info = ops[i].info;
540 }
541
542 /* standard handlers found ? */
8a978234
LG
543 if (k->put && k->get && k->info)
544 return 0;
545
546 /* nothing to bind */
547 return -EINVAL;
548}
549
550/* bind a widgets to it's evnt handlers */
551int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
552 const struct snd_soc_tplg_widget_events *events,
553 int num_events, u16 event_type)
554{
555 int i;
556
557 w->event = NULL;
558
559 for (i = 0; i < num_events; i++) {
560 if (event_type == events[i].type) {
561
562 /* found - so assign event */
563 w->event = events[i].event_handler;
564 return 0;
565 }
566 }
567
568 /* not found */
569 return -EINVAL;
570}
571EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_bind_event);
572
573/* optionally pass new dynamic kcontrol to component driver. */
574static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
575 struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
576{
577 if (tplg->comp && tplg->ops && tplg->ops->control_load)
578 return tplg->ops->control_load(tplg->comp, k, hdr);
579
580 return 0;
581}
582
8a978234 583
28a87eeb
ML
584static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
585 struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
586{
587 unsigned int item_len = 2 * sizeof(unsigned int);
588 unsigned int *p;
8a978234 589
28a87eeb
ML
590 p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
591 if (!p)
8a978234
LG
592 return -ENOMEM;
593
28a87eeb
ML
594 p[0] = SNDRV_CTL_TLVT_DB_SCALE;
595 p[1] = item_len;
596 p[2] = scale->min;
597 p[3] = (scale->step & TLV_DB_SCALE_MASK)
598 | (scale->mute ? TLV_DB_SCALE_MUTE : 0);
599
600 kc->tlv.p = (void *)p;
601 return 0;
602}
603
8a978234 604static int soc_tplg_create_tlv(struct soc_tplg *tplg,
28a87eeb 605 struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
8a978234
LG
606{
607 struct snd_soc_tplg_ctl_tlv *tplg_tlv;
8a978234 608
28a87eeb 609 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
8a978234
LG
610 return 0;
611
28a87eeb
ML
612 if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
613 kc->tlv.c = snd_soc_bytes_tlv_callback;
614 } else {
615 tplg_tlv = &tc->tlv;
616 switch (tplg_tlv->type) {
617 case SNDRV_CTL_TLVT_DB_SCALE:
618 return soc_tplg_create_tlv_db_scale(tplg, kc,
619 &tplg_tlv->scale);
8a978234 620
28a87eeb
ML
621 /* TODO: add support for other TLV types */
622 default:
623 dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
624 tplg_tlv->type);
625 return -EINVAL;
626 }
627 }
8a978234
LG
628
629 return 0;
630}
631
632static inline void soc_tplg_free_tlv(struct soc_tplg *tplg,
633 struct snd_kcontrol_new *kc)
634{
635 kfree(kc->tlv.p);
636}
637
638static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
639 size_t size)
640{
641 struct snd_soc_tplg_bytes_control *be;
642 struct soc_bytes_ext *sbe;
643 struct snd_kcontrol_new kc;
644 int i, err;
645
646 if (soc_tplg_check_elem_count(tplg,
647 sizeof(struct snd_soc_tplg_bytes_control), count,
648 size, "mixer bytes")) {
649 dev_err(tplg->dev, "ASoC: Invalid count %d for byte control\n",
650 count);
651 return -EINVAL;
652 }
653
654 for (i = 0; i < count; i++) {
655 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
656
657 /* validate kcontrol */
658 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
659 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
660 return -EINVAL;
661
662 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
663 if (sbe == NULL)
664 return -ENOMEM;
665
666 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
667 be->priv.size);
668
669 dev_dbg(tplg->dev,
670 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
671 be->hdr.name, be->hdr.access);
672
673 memset(&kc, 0, sizeof(kc));
674 kc.name = be->hdr.name;
675 kc.private_value = (long)sbe;
676 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
677 kc.access = be->hdr.access;
678
679 sbe->max = be->max;
680 sbe->dobj.type = SND_SOC_DOBJ_BYTES;
681 sbe->dobj.ops = tplg->ops;
682 INIT_LIST_HEAD(&sbe->dobj.list);
683
684 /* map io handlers */
685 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc, io_ops,
686 ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
687 if (err) {
688 soc_control_err(tplg, &be->hdr, be->hdr.name);
689 kfree(sbe);
690 continue;
691 }
692
693 /* pass control to driver for optional further init */
694 err = soc_tplg_init_kcontrol(tplg, &kc,
695 (struct snd_soc_tplg_ctl_hdr *)be);
696 if (err < 0) {
697 dev_err(tplg->dev, "ASoC: failed to init %s\n",
698 be->hdr.name);
699 kfree(sbe);
700 continue;
701 }
702
703 /* register control here */
704 err = soc_tplg_add_kcontrol(tplg, &kc,
705 &sbe->dobj.control.kcontrol);
706 if (err < 0) {
707 dev_err(tplg->dev, "ASoC: failed to add %s\n",
708 be->hdr.name);
709 kfree(sbe);
710 continue;
711 }
712
713 list_add(&sbe->dobj.list, &tplg->comp->dobj_list);
714 }
715 return 0;
716
717}
718
719static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
720 size_t size)
721{
722 struct snd_soc_tplg_mixer_control *mc;
723 struct soc_mixer_control *sm;
724 struct snd_kcontrol_new kc;
725 int i, err;
726
727 if (soc_tplg_check_elem_count(tplg,
728 sizeof(struct snd_soc_tplg_mixer_control),
729 count, size, "mixers")) {
730
731 dev_err(tplg->dev, "ASoC: invalid count %d for controls\n",
732 count);
733 return -EINVAL;
734 }
735
736 for (i = 0; i < count; i++) {
737 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
738
739 /* validate kcontrol */
740 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
741 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
742 return -EINVAL;
743
744 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
745 if (sm == NULL)
746 return -ENOMEM;
747 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
748 mc->priv.size);
749
750 dev_dbg(tplg->dev,
751 "ASoC: adding mixer kcontrol %s with access 0x%x\n",
752 mc->hdr.name, mc->hdr.access);
753
754 memset(&kc, 0, sizeof(kc));
755 kc.name = mc->hdr.name;
756 kc.private_value = (long)sm;
757 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
758 kc.access = mc->hdr.access;
759
760 /* we only support FL/FR channel mapping atm */
761 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
762 SNDRV_CHMAP_FL);
763 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
764 SNDRV_CHMAP_FR);
765 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
766 SNDRV_CHMAP_FL);
767 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
768 SNDRV_CHMAP_FR);
769
770 sm->max = mc->max;
771 sm->min = mc->min;
772 sm->invert = mc->invert;
773 sm->platform_max = mc->platform_max;
774 sm->dobj.index = tplg->index;
775 sm->dobj.ops = tplg->ops;
776 sm->dobj.type = SND_SOC_DOBJ_MIXER;
777 INIT_LIST_HEAD(&sm->dobj.list);
778
779 /* map io handlers */
780 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc, io_ops,
781 ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
782 if (err) {
783 soc_control_err(tplg, &mc->hdr, mc->hdr.name);
784 kfree(sm);
785 continue;
786 }
787
788 /* pass control to driver for optional further init */
789 err = soc_tplg_init_kcontrol(tplg, &kc,
790 (struct snd_soc_tplg_ctl_hdr *) mc);
791 if (err < 0) {
792 dev_err(tplg->dev, "ASoC: failed to init %s\n",
793 mc->hdr.name);
794 kfree(sm);
795 continue;
796 }
797
798 /* create any TLV data */
28a87eeb 799 soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
8a978234
LG
800
801 /* register control here */
802 err = soc_tplg_add_kcontrol(tplg, &kc,
803 &sm->dobj.control.kcontrol);
804 if (err < 0) {
805 dev_err(tplg->dev, "ASoC: failed to add %s\n",
806 mc->hdr.name);
807 soc_tplg_free_tlv(tplg, &kc);
808 kfree(sm);
809 continue;
810 }
811
812 list_add(&sm->dobj.list, &tplg->comp->dobj_list);
813 }
814
815 return 0;
816}
817
818static int soc_tplg_denum_create_texts(struct soc_enum *se,
819 struct snd_soc_tplg_enum_control *ec)
820{
821 int i, ret;
822
823 se->dobj.control.dtexts =
824 kzalloc(sizeof(char *) * ec->items, GFP_KERNEL);
825 if (se->dobj.control.dtexts == NULL)
826 return -ENOMEM;
827
828 for (i = 0; i < ec->items; i++) {
829
830 if (strnlen(ec->texts[i], SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
831 SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
832 ret = -EINVAL;
833 goto err;
834 }
835
836 se->dobj.control.dtexts[i] = kstrdup(ec->texts[i], GFP_KERNEL);
837 if (!se->dobj.control.dtexts[i]) {
838 ret = -ENOMEM;
839 goto err;
840 }
841 }
842
843 return 0;
844
845err:
846 for (--i; i >= 0; i--)
847 kfree(se->dobj.control.dtexts[i]);
848 kfree(se->dobj.control.dtexts);
849 return ret;
850}
851
852static int soc_tplg_denum_create_values(struct soc_enum *se,
853 struct snd_soc_tplg_enum_control *ec)
854{
855 if (ec->items > sizeof(*ec->values))
856 return -EINVAL;
857
376c0afe
AH
858 se->dobj.control.dvalues = kmemdup(ec->values,
859 ec->items * sizeof(u32),
860 GFP_KERNEL);
8a978234
LG
861 if (!se->dobj.control.dvalues)
862 return -ENOMEM;
863
8a978234
LG
864 return 0;
865}
866
867static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
868 size_t size)
869{
870 struct snd_soc_tplg_enum_control *ec;
871 struct soc_enum *se;
872 struct snd_kcontrol_new kc;
873 int i, ret, err;
874
875 if (soc_tplg_check_elem_count(tplg,
876 sizeof(struct snd_soc_tplg_enum_control),
877 count, size, "enums")) {
878
879 dev_err(tplg->dev, "ASoC: invalid count %d for enum controls\n",
880 count);
881 return -EINVAL;
882 }
883
884 for (i = 0; i < count; i++) {
885 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
886 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
887 ec->priv.size);
888
889 /* validate kcontrol */
890 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
891 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
892 return -EINVAL;
893
894 se = kzalloc((sizeof(*se)), GFP_KERNEL);
895 if (se == NULL)
896 return -ENOMEM;
897
898 dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
899 ec->hdr.name, ec->items);
900
901 memset(&kc, 0, sizeof(kc));
902 kc.name = ec->hdr.name;
903 kc.private_value = (long)se;
904 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
905 kc.access = ec->hdr.access;
906
907 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
908 se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
909 SNDRV_CHMAP_FL);
910 se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
911 SNDRV_CHMAP_FL);
912
913 se->items = ec->items;
914 se->mask = ec->mask;
915 se->dobj.index = tplg->index;
916 se->dobj.type = SND_SOC_DOBJ_ENUM;
917 se->dobj.ops = tplg->ops;
918 INIT_LIST_HEAD(&se->dobj.list);
919
920 switch (ec->hdr.ops.info) {
921 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
922 case SND_SOC_TPLG_CTL_ENUM_VALUE:
923 err = soc_tplg_denum_create_values(se, ec);
924 if (err < 0) {
925 dev_err(tplg->dev,
926 "ASoC: could not create values for %s\n",
927 ec->hdr.name);
928 kfree(se);
929 continue;
930 }
931 /* fall through and create texts */
932 case SND_SOC_TPLG_CTL_ENUM:
933 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
934 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
935 err = soc_tplg_denum_create_texts(se, ec);
936 if (err < 0) {
937 dev_err(tplg->dev,
938 "ASoC: could not create texts for %s\n",
939 ec->hdr.name);
940 kfree(se);
941 continue;
942 }
943 break;
944 default:
945 dev_err(tplg->dev,
946 "ASoC: invalid enum control type %d for %s\n",
947 ec->hdr.ops.info, ec->hdr.name);
948 kfree(se);
949 continue;
950 }
951
952 /* map io handlers */
953 err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc, io_ops,
954 ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
955 if (err) {
956 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
957 kfree(se);
958 continue;
959 }
960
961 /* pass control to driver for optional further init */
962 err = soc_tplg_init_kcontrol(tplg, &kc,
963 (struct snd_soc_tplg_ctl_hdr *) ec);
964 if (err < 0) {
965 dev_err(tplg->dev, "ASoC: failed to init %s\n",
966 ec->hdr.name);
967 kfree(se);
968 continue;
969 }
970
971 /* register control here */
972 ret = soc_tplg_add_kcontrol(tplg,
973 &kc, &se->dobj.control.kcontrol);
974 if (ret < 0) {
975 dev_err(tplg->dev, "ASoC: could not add kcontrol %s\n",
976 ec->hdr.name);
977 kfree(se);
978 continue;
979 }
980
981 list_add(&se->dobj.list, &tplg->comp->dobj_list);
982 }
983
984 return 0;
985}
986
987static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
988 struct snd_soc_tplg_hdr *hdr)
989{
990 struct snd_soc_tplg_ctl_hdr *control_hdr;
991 int i;
992
993 if (tplg->pass != SOC_TPLG_PASS_MIXER) {
994 tplg->pos += hdr->size + hdr->payload_size;
995 return 0;
996 }
997
998 dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
999 soc_tplg_get_offset(tplg));
1000
1001 for (i = 0; i < hdr->count; i++) {
1002
1003 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1004
1005 switch (control_hdr->ops.info) {
1006 case SND_SOC_TPLG_CTL_VOLSW:
1007 case SND_SOC_TPLG_CTL_STROBE:
1008 case SND_SOC_TPLG_CTL_VOLSW_SX:
1009 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1010 case SND_SOC_TPLG_CTL_RANGE:
1011 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1012 case SND_SOC_TPLG_DAPM_CTL_PIN:
1013 soc_tplg_dmixer_create(tplg, 1, hdr->payload_size);
1014 break;
1015 case SND_SOC_TPLG_CTL_ENUM:
1016 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1017 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1018 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1019 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1020 soc_tplg_denum_create(tplg, 1, hdr->payload_size);
1021 break;
1022 case SND_SOC_TPLG_CTL_BYTES:
1023 soc_tplg_dbytes_create(tplg, 1, hdr->payload_size);
1024 break;
1025 default:
1026 soc_bind_err(tplg, control_hdr, i);
1027 return -EINVAL;
1028 }
1029 }
1030
1031 return 0;
1032}
1033
1034static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
1035 struct snd_soc_tplg_hdr *hdr)
1036{
1037 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1038 struct snd_soc_dapm_route route;
1039 struct snd_soc_tplg_dapm_graph_elem *elem;
1040 int count = hdr->count, i;
1041
1042 if (tplg->pass != SOC_TPLG_PASS_GRAPH) {
1043 tplg->pos += hdr->size + hdr->payload_size;
1044 return 0;
1045 }
1046
1047 if (soc_tplg_check_elem_count(tplg,
1048 sizeof(struct snd_soc_tplg_dapm_graph_elem),
1049 count, hdr->payload_size, "graph")) {
1050
1051 dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n",
1052 count);
1053 return -EINVAL;
1054 }
1055
1056 dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes\n", count);
1057
1058 for (i = 0; i < count; i++) {
1059 elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos;
1060 tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
1061
1062 /* validate routes */
1063 if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1064 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1065 return -EINVAL;
1066 if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1067 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1068 return -EINVAL;
1069 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1070 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1071 return -EINVAL;
1072
1073 route.source = elem->source;
1074 route.sink = elem->sink;
1075 route.connected = NULL; /* set to NULL atm for tplg users */
1076 if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
1077 route.control = NULL;
1078 else
1079 route.control = elem->control;
1080
1081 /* add route, but keep going if some fail */
1082 snd_soc_dapm_add_routes(dapm, &route, 1);
1083 }
1084
1085 return 0;
1086}
1087
1088static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1089 struct soc_tplg *tplg, int num_kcontrols)
1090{
1091 struct snd_kcontrol_new *kc;
1092 struct soc_mixer_control *sm;
1093 struct snd_soc_tplg_mixer_control *mc;
1094 int i, err;
1095
4ca7deb1 1096 kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
8a978234
LG
1097 if (kc == NULL)
1098 return NULL;
1099
1100 for (i = 0; i < num_kcontrols; i++) {
1101 mc = (struct snd_soc_tplg_mixer_control *)tplg->pos;
1102 sm = kzalloc(sizeof(*sm), GFP_KERNEL);
1103 if (sm == NULL)
1104 goto err;
1105
1106 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
1107 mc->priv.size);
1108
1109 /* validate kcontrol */
1110 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1111 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1112 goto err_str;
1113
1114 dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n",
1115 mc->hdr.name, i);
1116
1117 kc[i].name = mc->hdr.name;
1118 kc[i].private_value = (long)sm;
1119 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1120 kc[i].access = mc->hdr.access;
1121
1122 /* we only support FL/FR channel mapping atm */
1123 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
1124 SNDRV_CHMAP_FL);
1125 sm->rreg = tplc_chan_get_reg(tplg, mc->channel,
1126 SNDRV_CHMAP_FR);
1127 sm->shift = tplc_chan_get_shift(tplg, mc->channel,
1128 SNDRV_CHMAP_FL);
1129 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
1130 SNDRV_CHMAP_FR);
1131
1132 sm->max = mc->max;
1133 sm->min = mc->min;
1134 sm->invert = mc->invert;
1135 sm->platform_max = mc->platform_max;
1136 sm->dobj.index = tplg->index;
1137 INIT_LIST_HEAD(&sm->dobj.list);
1138
1139 /* map io handlers */
1140 err = soc_tplg_kcontrol_bind_io(&mc->hdr, &kc[i], io_ops,
1141 ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
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 */
1238 err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, io_ops,
1239 ARRAY_SIZE(io_ops), tplg->io_ops, tplg->io_ops_count);
1240 if (err) {
1241 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1242 goto err_se;
1243 }
1244
1245 /* pass control to driver for optional further init */
1246 err = soc_tplg_init_kcontrol(tplg, kc,
1247 (struct snd_soc_tplg_ctl_hdr *)ec);
1248 if (err < 0) {
1249 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1250 ec->hdr.name);
1251 goto err_se;
1252 }
1253
1254 return kc;
1255
1256err_se:
1257 /* free values and texts */
1258 kfree(se->dobj.control.dvalues);
1259 for (i = 0; i < ec->items; i++)
1260 kfree(se->dobj.control.dtexts[i]);
1261
1262 kfree(se);
1263err:
1264 kfree(kc);
1265
1266 return NULL;
1267}
1268
1269static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
1270 struct soc_tplg *tplg, int count)
1271{
1272 struct snd_soc_tplg_bytes_control *be;
1273 struct soc_bytes_ext *sbe;
1274 struct snd_kcontrol_new *kc;
1275 int i, err;
1276
4ca7deb1 1277 kc = kcalloc(count, sizeof(*kc), GFP_KERNEL);
8a978234
LG
1278 if (!kc)
1279 return NULL;
1280
1281 for (i = 0; i < count; i++) {
1282 be = (struct snd_soc_tplg_bytes_control *)tplg->pos;
1283
1284 /* validate kcontrol */
1285 if (strnlen(be->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1286 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1287 goto err;
1288
1289 sbe = kzalloc(sizeof(*sbe), GFP_KERNEL);
1290 if (sbe == NULL)
1291 goto err;
1292
1293 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
1294 be->priv.size);
1295
1296 dev_dbg(tplg->dev,
1297 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
1298 be->hdr.name, be->hdr.access);
1299
8a978234
LG
1300 kc[i].name = be->hdr.name;
1301 kc[i].private_value = (long)sbe;
1302 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1303 kc[i].access = be->hdr.access;
1304
1305 sbe->max = be->max;
1306 INIT_LIST_HEAD(&sbe->dobj.list);
1307
1308 /* map standard io handlers and check for external handlers */
1309 err = soc_tplg_kcontrol_bind_io(&be->hdr, &kc[i], io_ops,
1310 ARRAY_SIZE(io_ops), tplg->io_ops,
1311 tplg->io_ops_count);
1312 if (err) {
1313 soc_control_err(tplg, &be->hdr, be->hdr.name);
1314 kfree(sbe);
1315 continue;
1316 }
1317
1318 /* pass control to driver for optional further init */
1319 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1320 (struct snd_soc_tplg_ctl_hdr *)be);
1321 if (err < 0) {
1322 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1323 be->hdr.name);
1324 kfree(sbe);
1325 continue;
1326 }
1327 }
1328
1329 return kc;
1330
1331err:
1332 for (--i; i >= 0; i--)
1333 kfree((void *)kc[i].private_value);
1334
1335 kfree(kc);
1336 return NULL;
1337}
1338
1339static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1340 struct snd_soc_tplg_dapm_widget *w)
1341{
1342 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1343 struct snd_soc_dapm_widget template, *widget;
1344 struct snd_soc_tplg_ctl_hdr *control_hdr;
1345 struct snd_soc_card *card = tplg->comp->card;
1346 int ret = 0;
1347
1348 if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1349 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1350 return -EINVAL;
1351 if (strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1352 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1353 return -EINVAL;
1354
1355 dev_dbg(tplg->dev, "ASoC: creating DAPM widget %s id %d\n",
1356 w->name, w->id);
1357
1358 memset(&template, 0, sizeof(template));
1359
1360 /* map user to kernel widget ID */
1361 template.id = get_widget_id(w->id);
1362 if (template.id < 0)
1363 return template.id;
1364
1365 template.name = kstrdup(w->name, GFP_KERNEL);
1366 if (!template.name)
1367 return -ENOMEM;
1368 template.sname = kstrdup(w->sname, GFP_KERNEL);
1369 if (!template.sname) {
1370 ret = -ENOMEM;
1371 goto err;
1372 }
1373 template.reg = w->reg;
1374 template.shift = w->shift;
1375 template.mask = w->mask;
6dc6db79 1376 template.subseq = w->subseq;
8a978234
LG
1377 template.on_val = w->invert ? 0 : 1;
1378 template.off_val = w->invert ? 1 : 0;
1379 template.ignore_suspend = w->ignore_suspend;
1380 template.event_flags = w->event_flags;
1381 template.dobj.index = tplg->index;
1382
1383 tplg->pos +=
1384 (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size);
1385 if (w->num_kcontrols == 0) {
1386 template.num_kcontrols = 0;
1387 goto widget;
1388 }
1389
1390 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1391 dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
1392 w->name, w->num_kcontrols, control_hdr->type);
1393
1394 switch (control_hdr->ops.info) {
1395 case SND_SOC_TPLG_CTL_VOLSW:
1396 case SND_SOC_TPLG_CTL_STROBE:
1397 case SND_SOC_TPLG_CTL_VOLSW_SX:
1398 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1399 case SND_SOC_TPLG_CTL_RANGE:
1400 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1401 template.num_kcontrols = w->num_kcontrols;
1402 template.kcontrol_news =
1403 soc_tplg_dapm_widget_dmixer_create(tplg,
1404 template.num_kcontrols);
1405 if (!template.kcontrol_news) {
1406 ret = -ENOMEM;
1407 goto hdr_err;
1408 }
1409 break;
1410 case SND_SOC_TPLG_CTL_ENUM:
1411 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1412 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1413 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1414 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1415 template.dobj.widget.kcontrol_enum = 1;
1416 template.num_kcontrols = 1;
1417 template.kcontrol_news =
1418 soc_tplg_dapm_widget_denum_create(tplg);
1419 if (!template.kcontrol_news) {
1420 ret = -ENOMEM;
1421 goto hdr_err;
1422 }
1423 break;
1424 case SND_SOC_TPLG_CTL_BYTES:
1425 template.num_kcontrols = w->num_kcontrols;
1426 template.kcontrol_news =
1427 soc_tplg_dapm_widget_dbytes_create(tplg,
1428 template.num_kcontrols);
1429 if (!template.kcontrol_news) {
1430 ret = -ENOMEM;
1431 goto hdr_err;
1432 }
1433 break;
1434 default:
1435 dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
1436 control_hdr->ops.get, control_hdr->ops.put,
1437 control_hdr->ops.info);
1438 ret = -EINVAL;
1439 goto hdr_err;
1440 }
1441
1442widget:
1443 ret = soc_tplg_widget_load(tplg, &template, w);
1444 if (ret < 0)
1445 goto hdr_err;
1446
1447 /* card dapm mutex is held by the core if we are loading topology
1448 * data during sound card init. */
1449 if (card->instantiated)
1450 widget = snd_soc_dapm_new_control(dapm, &template);
1451 else
1452 widget = snd_soc_dapm_new_control_unlocked(dapm, &template);
1453 if (widget == NULL) {
1454 dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
1455 w->name);
1456 goto hdr_err;
1457 }
1458
1459 widget->dobj.type = SND_SOC_DOBJ_WIDGET;
1460 widget->dobj.ops = tplg->ops;
1461 widget->dobj.index = tplg->index;
1462 list_add(&widget->dobj.list, &tplg->comp->dobj_list);
1463 return 0;
1464
1465hdr_err:
1466 kfree(template.sname);
1467err:
1468 kfree(template.name);
1469 return ret;
1470}
1471
1472static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
1473 struct snd_soc_tplg_hdr *hdr)
1474{
1475 struct snd_soc_tplg_dapm_widget *widget;
1476 int ret, count = hdr->count, i;
1477
1478 if (tplg->pass != SOC_TPLG_PASS_WIDGET)
1479 return 0;
1480
1481 dev_dbg(tplg->dev, "ASoC: adding %d DAPM widgets\n", count);
1482
1483 for (i = 0; i < count; i++) {
1484 widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
1485 ret = soc_tplg_dapm_widget_create(tplg, widget);
1486 if (ret < 0)
1487 dev_err(tplg->dev, "ASoC: failed to load widget %s\n",
1488 widget->name);
1489 }
1490
1491 return 0;
1492}
1493
1494static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
1495{
1496 struct snd_soc_card *card = tplg->comp->card;
1497 int ret;
1498
1499 /* Card might not have been registered at this point.
1500 * If so, just return success.
1501 */
1502 if (!card || !card->instantiated) {
1503 dev_warn(tplg->dev, "ASoC: Parent card not yet available,"
1504 "Do not add new widgets now\n");
1505 return 0;
1506 }
1507
1508 ret = snd_soc_dapm_new_widgets(card);
1509 if (ret < 0)
1510 dev_err(tplg->dev, "ASoC: failed to create new widgets %d\n",
1511 ret);
1512
1513 return 0;
1514}
1515
1516static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
1517 struct snd_soc_tplg_hdr *hdr)
1518{
1519 struct snd_soc_tplg_pcm_dai *pcm_dai;
1520 struct snd_soc_dobj *dobj;
1521 int count = hdr->count;
1522 int ret;
1523
1524 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
1525 return 0;
1526
1527 pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos;
1528
1529 if (soc_tplg_check_elem_count(tplg,
1530 sizeof(struct snd_soc_tplg_pcm_dai), count,
1531 hdr->payload_size, "PCM DAI")) {
1532 dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
1533 count);
1534 return -EINVAL;
1535 }
1536
1537 dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
1538 tplg->pos += sizeof(struct snd_soc_tplg_pcm_dai) * count;
1539
1540 dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL);
1541 if (dobj == NULL)
1542 return -ENOMEM;
1543
1544 /* Call the platform driver call back to register the dais */
1545 ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count);
1546 if (ret < 0) {
1547 dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n");
1548 goto err;
1549 }
1550
1551 dobj->type = get_dobj_type(hdr, NULL);
1552 dobj->pcm_dai.count = count;
1553 dobj->pcm_dai.pd = pcm_dai;
1554 dobj->ops = tplg->ops;
1555 dobj->index = tplg->index;
1556 list_add(&dobj->list, &tplg->comp->dobj_list);
1557 return 0;
1558
1559err:
1560 kfree(dobj);
1561 return ret;
1562}
1563
1564static int soc_tplg_manifest_load(struct soc_tplg *tplg,
1565 struct snd_soc_tplg_hdr *hdr)
1566{
1567 struct snd_soc_tplg_manifest *manifest;
1568
1569 if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
1570 return 0;
1571
1572 manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
1573 tplg->pos += sizeof(struct snd_soc_tplg_manifest);
1574
1575 if (tplg->comp && tplg->ops && tplg->ops->manifest)
1576 return tplg->ops->manifest(tplg->comp, manifest);
1577
1578 dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n");
1579 return 0;
1580}
1581
1582/* validate header magic, size and type */
1583static int soc_valid_header(struct soc_tplg *tplg,
1584 struct snd_soc_tplg_hdr *hdr)
1585{
1586 if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
1587 return 0;
1588
1589 /* big endian firmware objects not supported atm */
1590 if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) {
1591 dev_err(tplg->dev,
1592 "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
1593 tplg->pass, hdr->magic,
1594 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
1595 return -EINVAL;
1596 }
1597
1598 if (hdr->magic != SND_SOC_TPLG_MAGIC) {
1599 dev_err(tplg->dev,
1600 "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
1601 tplg->pass, hdr->magic,
1602 soc_tplg_get_hdr_offset(tplg), tplg->fw->size);
1603 return -EINVAL;
1604 }
1605
1606 if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
1607 dev_err(tplg->dev,
1608 "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
1609 tplg->pass, hdr->abi,
1610 SND_SOC_TPLG_ABI_VERSION, soc_tplg_get_hdr_offset(tplg),
1611 tplg->fw->size);
1612 return -EINVAL;
1613 }
1614
1615 if (hdr->payload_size == 0) {
1616 dev_err(tplg->dev, "ASoC: header has 0 size at offset 0x%lx.\n",
1617 soc_tplg_get_hdr_offset(tplg));
1618 return -EINVAL;
1619 }
1620
1621 if (tplg->pass == hdr->type)
1622 dev_dbg(tplg->dev,
1623 "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
1624 hdr->payload_size, hdr->type, hdr->version,
1625 hdr->vendor_type, tplg->pass);
1626
1627 return 1;
1628}
1629
1630/* check header type and call appropriate handler */
1631static int soc_tplg_load_header(struct soc_tplg *tplg,
1632 struct snd_soc_tplg_hdr *hdr)
1633{
1634 tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
1635
1636 /* check for matching ID */
1637 if (hdr->index != tplg->req_index &&
1638 hdr->index != SND_SOC_TPLG_INDEX_ALL)
1639 return 0;
1640
1641 tplg->index = hdr->index;
1642
1643 switch (hdr->type) {
1644 case SND_SOC_TPLG_TYPE_MIXER:
1645 case SND_SOC_TPLG_TYPE_ENUM:
1646 case SND_SOC_TPLG_TYPE_BYTES:
1647 return soc_tplg_kcontrol_elems_load(tplg, hdr);
1648 case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
1649 return soc_tplg_dapm_graph_elems_load(tplg, hdr);
1650 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
1651 return soc_tplg_dapm_widget_elems_load(tplg, hdr);
1652 case SND_SOC_TPLG_TYPE_PCM:
1653 case SND_SOC_TPLG_TYPE_DAI_LINK:
1654 case SND_SOC_TPLG_TYPE_CODEC_LINK:
1655 return soc_tplg_pcm_dai_elems_load(tplg, hdr);
1656 case SND_SOC_TPLG_TYPE_MANIFEST:
1657 return soc_tplg_manifest_load(tplg, hdr);
1658 default:
1659 /* bespoke vendor data object */
1660 return soc_tplg_vendor_load(tplg, hdr);
1661 }
1662
1663 return 0;
1664}
1665
1666/* process the topology file headers */
1667static int soc_tplg_process_headers(struct soc_tplg *tplg)
1668{
1669 struct snd_soc_tplg_hdr *hdr;
1670 int ret;
1671
1672 tplg->pass = SOC_TPLG_PASS_START;
1673
1674 /* process the header types from start to end */
1675 while (tplg->pass <= SOC_TPLG_PASS_END) {
1676
1677 tplg->hdr_pos = tplg->fw->data;
1678 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
1679
1680 while (!soc_tplg_is_eof(tplg)) {
1681
1682 /* make sure header is valid before loading */
1683 ret = soc_valid_header(tplg, hdr);
1684 if (ret < 0)
1685 return ret;
1686 else if (ret == 0)
1687 break;
1688
1689 /* load the header object */
1690 ret = soc_tplg_load_header(tplg, hdr);
1691 if (ret < 0)
1692 return ret;
1693
1694 /* goto next header */
1695 tplg->hdr_pos += hdr->payload_size +
1696 sizeof(struct snd_soc_tplg_hdr);
1697 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
1698 }
1699
1700 /* next data type pass */
1701 tplg->pass++;
1702 }
1703
1704 /* signal DAPM we are complete */
1705 ret = soc_tplg_dapm_complete(tplg);
1706 if (ret < 0)
1707 dev_err(tplg->dev,
1708 "ASoC: failed to initialise DAPM from Firmware\n");
1709
1710 return ret;
1711}
1712
1713static int soc_tplg_load(struct soc_tplg *tplg)
1714{
1715 int ret;
1716
1717 ret = soc_tplg_process_headers(tplg);
1718 if (ret == 0)
1719 soc_tplg_complete(tplg);
1720
1721 return ret;
1722}
1723
1724/* load audio component topology from "firmware" file */
1725int snd_soc_tplg_component_load(struct snd_soc_component *comp,
1726 struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id)
1727{
1728 struct soc_tplg tplg;
1729
1730 /* setup parsing context */
1731 memset(&tplg, 0, sizeof(tplg));
1732 tplg.fw = fw;
1733 tplg.dev = comp->dev;
1734 tplg.comp = comp;
1735 tplg.ops = ops;
1736 tplg.req_index = id;
1737 tplg.io_ops = ops->io_ops;
1738 tplg.io_ops_count = ops->io_ops_count;
1739
1740 return soc_tplg_load(&tplg);
1741}
1742EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
1743
1744/* remove this dynamic widget */
1745void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w)
1746{
1747 /* make sure we are a widget */
1748 if (w->dobj.type != SND_SOC_DOBJ_WIDGET)
1749 return;
1750
1751 remove_widget(w->dapm->component, &w->dobj, SOC_TPLG_PASS_WIDGET);
1752}
1753EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove);
1754
1755/* remove all dynamic widgets from this DAPM context */
1756void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
1757 u32 index)
1758{
1759 struct snd_soc_dapm_widget *w, *next_w;
1760 struct snd_soc_dapm_path *p, *next_p;
1761
1762 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
1763
1764 /* make sure we are a widget with correct context */
1765 if (w->dobj.type != SND_SOC_DOBJ_WIDGET || w->dapm != dapm)
1766 continue;
1767
1768 /* match ID */
1769 if (w->dobj.index != index &&
1770 w->dobj.index != SND_SOC_TPLG_INDEX_ALL)
1771 continue;
1772
1773 list_del(&w->list);
1774
1775 /*
1776 * remove source and sink paths associated to this widget.
1777 * While removing the path, remove reference to it from both
1778 * source and sink widgets so that path is removed only once.
1779 */
1780 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
1781 list_del(&p->list_sink);
1782 list_del(&p->list_source);
1783 list_del(&p->list);
1784 kfree(p);
1785 }
1786 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
1787 list_del(&p->list_sink);
1788 list_del(&p->list_source);
1789 list_del(&p->list);
1790 kfree(p);
1791 }
1792 /* check and free and dynamic widget kcontrols */
1793 snd_soc_tplg_widget_remove(w);
1794 kfree(w->kcontrols);
1795 kfree(w->name);
1796 kfree(w);
1797 }
1798}
1799EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
1800
1801/* remove dynamic controls from the component driver */
1802int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
1803{
1804 struct snd_soc_dobj *dobj, *next_dobj;
1805 int pass = SOC_TPLG_PASS_END;
1806
1807 /* process the header types from end to start */
1808 while (pass >= SOC_TPLG_PASS_START) {
1809
1810 /* remove mixer controls */
1811 list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
1812 list) {
1813
1814 /* match index */
1815 if (dobj->index != index &&
1816 dobj->index != SND_SOC_TPLG_INDEX_ALL)
1817 continue;
1818
1819 switch (dobj->type) {
1820 case SND_SOC_DOBJ_MIXER:
1821 remove_mixer(comp, dobj, pass);
1822 break;
1823 case SND_SOC_DOBJ_ENUM:
1824 remove_enum(comp, dobj, pass);
1825 break;
1826 case SND_SOC_DOBJ_BYTES:
1827 remove_bytes(comp, dobj, pass);
1828 break;
1829 case SND_SOC_DOBJ_WIDGET:
1830 remove_widget(comp, dobj, pass);
1831 break;
1832 case SND_SOC_DOBJ_PCM:
1833 case SND_SOC_DOBJ_DAI_LINK:
1834 case SND_SOC_DOBJ_CODEC_LINK:
1835 remove_pcm_dai(comp, dobj, pass);
1836 break;
1837 default:
1838 dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",
1839 dobj->type);
1840 break;
1841 }
1842 }
1843 pass--;
1844 }
1845
1846 /* let caller know if FW can be freed when no objects are left */
1847 return !list_empty(&comp->dobj_list);
1848}
1849EXPORT_SYMBOL_GPL(snd_soc_tplg_component_remove);
This page took 0.097973 seconds and 5 git commands to generate.