1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <stdio.h>
33 #include <stdint.h>
34 #include <string.h>
35 #include <stdarg.h>
36 #include <sound/snd_core.h>
37 
ksnd_ctl_num(const char * name)38 int ksnd_ctl_num(const char *name)
39 {
40     struct snd_card *card = NULL;
41     struct snd_kcontrol *k;
42     int num = 0;
43 
44     card = snd_card_find_by_name(name);
45     if (!card) {
46         snd_err("no card %s\n", name);
47         return -1;
48     }
49     if (!card->ctl) {
50         snd_err("card %s has no ctl\n", name);
51         return -1;
52     }
53     snd_mutex_lock(card->ctl->ctl_mutex);
54     list_for_each_entry(k, &card->ctl->controls, list) {
55         if (!k->name)
56             break;
57         num++;
58         snd_print("card:%s,kcontrol[%u] \"%s\"\n", name, k->id, k->name);
59     }
60     snd_mutex_unlock(card->ctl->ctl_mutex);
61     return num;
62 }
63 
ksnd_ctl_get(const char * name,const char * elem,void * info)64 int ksnd_ctl_get(const char *name, const char *elem, void *info)
65 {
66     struct snd_card *card = NULL;
67     struct snd_kcontrol *k;
68     struct snd_ctl_info *i = info;
69     int ret = -1;
70 
71     if (!i)
72         return -1;
73     card = snd_card_find_by_name(name);
74     if (!card) {
75         snd_err("no card %s\n", name);
76         return -1;
77     }
78     if (!card->ctl) {
79         snd_err("card %s has no ctl\n", name);
80         return -1;
81     }
82     snd_mutex_lock(card->ctl->ctl_mutex);
83     list_for_each_entry(k, &card->ctl->controls, list) {
84         if (!strncmp((const char *)k->name, elem, strlen((char *)k->name))) {
85             snd_print("card:%s,kcontrol[%u] \"%s\" found...\n", name, k->id, k->name);
86             ret = k->get(k, i);
87             break;
88         }
89     }
90     snd_mutex_unlock(card->ctl->ctl_mutex);
91     if (ret < 0) {
92         snd_info("card %s ctl doesn't have this elem\n", name);
93     }
94     return ret;
95 }
96 
ksnd_ctl_get_bynum(const char * name,const unsigned int elem_num,void * info)97 int ksnd_ctl_get_bynum(const char *name, const unsigned int elem_num, void *info)
98 {
99     struct snd_card *card = NULL;
100     struct snd_kcontrol *k;
101     struct snd_ctl_info *i = info;
102     int ret = -1;
103 
104     if (!i)
105         return -1;
106     card = snd_card_find_by_name(name);
107     if (!card) {
108         snd_err("no card %s\n", name);
109         return -1;
110     }
111     if (!card->ctl) {
112         snd_err("card %s has no ctl\n", name);
113         return -1;
114     }
115 
116     snd_mutex_lock(card->ctl->ctl_mutex);
117     list_for_each_entry(k, &card->ctl->controls, list) {
118         if (k->id == elem_num) {
119             snd_print("card:%s,kcontrol[%u] \"%s\" found...\n", name, k->id, k->name);
120             ret = k->get(k, i);
121             break;
122         }
123     }
124     snd_mutex_unlock(card->ctl->ctl_mutex);
125     if (ret < 0) {
126         snd_info("card %s ctl doesn't have this elem\n", name);
127     }
128     return ret;
129 }
130 
ksnd_ctl_set(const char * name,const char * elem,unsigned int val)131 int ksnd_ctl_set(const char *name, const char *elem, unsigned int val)
132 {
133     struct snd_card *card = NULL;
134     struct snd_kcontrol *k;
135     int ret = -1;
136 
137     card = snd_card_find_by_name(name);
138     if (!card) {
139         snd_err("no card %s\n", name);
140         return -1;
141     }
142     if (!card->ctl) {
143         snd_err("card %s has no ctl\n", name);
144         return -1;
145     }
146 
147     snd_mutex_lock(card->ctl->ctl_mutex);
148     list_for_each_entry(k, &card->ctl->controls, list) {
149         if (!strncmp((const char *)k->name, elem, strlen((char *)k->name))) {
150             snd_print("card:%s,kcontrol[%u] \"%s\" found...\n", name, k->id, k->name);
151             ret = k->set(k, val);
152             break;
153         }
154     }
155     snd_mutex_unlock(card->ctl->ctl_mutex);
156     if (ret < 0)
157         snd_err("card %s ctl doesn't have this elem\n", name);
158     return ret;
159 }
160 
ksnd_ctl_set_bynum(const char * name,const unsigned int elem_num,unsigned int val)161 int ksnd_ctl_set_bynum(const char *name, const unsigned int elem_num, unsigned int val)
162 {
163     struct snd_card *card = NULL;
164     struct snd_kcontrol *k;
165     int ret = -1;
166 
167     card = snd_card_find_by_name(name);
168     if (!card) {
169         snd_err("no card %s\n", name);
170         return -1;
171     }
172     if (!card->ctl) {
173         snd_err("card %s has no ctl\n", name);
174         return -1;
175     }
176     snd_mutex_lock(card->ctl->ctl_mutex);
177     list_for_each_entry(k, &card->ctl->controls, list) {
178         if (k->id == elem_num) {
179             snd_print("card:%s,kcontrol[%u] \"%s\" found...\n", name, k->id, k->name);
180             ret = k->set(k, val);
181             break;
182         }
183     }
184     snd_mutex_unlock(card->ctl->ctl_mutex);
185     if (ret < 0)
186         snd_err("card %s ctl doesn't have this elem\n", name);
187     return ret;
188 }
189 
ksnd_ctl_set_multi_args(const char * name,const char * elem,int num,...)190 int ksnd_ctl_set_multi_args(const char *name, const char *elem, int num, ...)
191 {
192     struct snd_card *card = NULL;
193     struct snd_kcontrol *k, *kcontrol = NULL;
194     int j, ret = -1;
195     va_list ap;
196     unsigned long *value;
197 
198     card = snd_card_find_by_name(name);
199     if (!card) {
200         snd_err("no card %s\n", name);
201         return -1;
202     }
203     if (!card->ctl) {
204         snd_err("card %s has no ctl\n", name);
205         return -1;
206     }
207 
208     snd_mutex_lock(card->ctl->ctl_mutex);
209     list_for_each_entry(k, &card->ctl->controls, list) {
210         if (!strncmp((const char *)k->name, elem, strlen((char *)k->name))) {
211             kcontrol = k;
212             break;
213         }
214     }
215     if (!kcontrol) {
216         snd_err("card %s ctl doesn't have this elem\n", name);
217         goto err;
218     }
219     if (kcontrol->count != num) {
220         snd_err("actual kcontrol count=%d, but arg num is %d\n",
221                     kcontrol->count, num);
222         goto err;
223     }
224     value = snd_malloc(sizeof(unsigned long) * kcontrol->count);
225 
226     va_start(ap, num);
227     for (j = 0; j < num; j++) {
228         value[j] = va_arg(ap, unsigned long);
229         snd_print("arg%d is :%d\n", j, value[j]);
230     }
231     va_end(ap);
232 
233     ret = kcontrol->set(kcontrol, (unsigned long)value);
234 err:
235     snd_mutex_unlock(card->ctl->ctl_mutex);
236     return ret;
237 }
238 
ksnd_ctl_add_elem(const char * name,void * info)239 int ksnd_ctl_add_elem(const char *name, void *info)
240 {
241     struct snd_card *card = NULL;
242     struct snd_ctl_info *i = info;
243     int ret;
244 
245     if (!i)
246         return -1;
247     card = snd_card_find_by_name(name);
248     if (!card) {
249         snd_err("no card %s\n", name);
250         return -1;
251     }
252     if (!card->ctl) {
253         snd_err("card %s has no ctl\n", name);
254         return -1;
255     }
256 
257     snd_mutex_lock(card->ctl->ctl_mutex);
258     ret = snd_ctl_add_elem(card->ctl, i);
259     snd_mutex_unlock(card->ctl->ctl_mutex);
260     return ret;
261 }
262 
ksnd_ctl_remove_elem(const char * name,const unsigned int elem_num)263 int ksnd_ctl_remove_elem(const char *name, const unsigned int elem_num)
264 {
265     struct snd_card *card = NULL;
266     struct snd_kcontrol *k = NULL;
267     int ret = -1;
268 
269     card = snd_card_find_by_name(name);
270     if (!card) {
271         snd_err("no card %s\n", name);
272         return -1;
273     }
274     if (!card->ctl) {
275         snd_err("card %s has no ctl\n", name);
276         return -1;
277     }
278 
279     snd_mutex_lock(card->ctl->ctl_mutex);
280     list_for_each_entry(k, &card->ctl->controls, list) {
281         if (k->id == elem_num) {
282             ret = snd_ctl_remove_elem(card->ctl, k);
283             break;
284         }
285     }
286     snd_mutex_unlock(card->ctl->ctl_mutex);
287     return ret;
288 }
289