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