1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <ulog/ulog.h>
7 #include <errno.h>
8 #include <string.h>
9 #include "control.h"
10 
11 #define LOG_TAG  "[control]"
12 #define MAX_CONTROL_COUNT	1028
13 
audio_ctl_new(struct audio_kcontrol ** kctl,unsigned int count,unsigned int access)14 static int audio_ctl_new(struct audio_kcontrol **kctl, unsigned int count, unsigned int access)
15 {
16 	unsigned int size;
17 	unsigned int idx;
18 
19 	if (count == 0 || count > MAX_CONTROL_COUNT) {
20 		return -EINVAL;
21 	}
22 
23 	size  = sizeof(struct audio_kcontrol) + sizeof(struct audio_kcontrol_volatile) * count;
24 	*kctl = malloc(size);
25 	if (!*kctl) {
26 		return -ENOMEM;
27 	}
28 	(*kctl)->count = count;
29 
30 	for (idx = 0; idx < count; idx++) {
31 		(*kctl)->vd[idx].access = access;
32 	}
33 	return 0;
34 }
35 
audio_ctl_new1(const struct audio_kcontrol_new * ncontrol,void * private_data)36 static struct audio_kcontrol *audio_ctl_new1(const struct audio_kcontrol_new *ncontrol, void *private_data)
37 {
38 	struct audio_kcontrol *kctl;
39 	unsigned int count;
40 	unsigned int access;
41 	int err;
42 
43 	if (!ncontrol) {
44         LOGE(LOG_TAG, "%s:%d, ncontrol is null", __func__, __LINE__);
45         return NULL;
46 	}
47 	if (!ncontrol->info) {
48         LOGE(LOG_TAG, "%s:%d, control info is null", __func__, __LINE__);
49         return NULL;
50 	}
51 	count = ncontrol->count;
52 	if (count == 0)
53 		count = 1;
54 
55 	access = ncontrol->access;
56 	if (access == 0)
57 		access = AOS_CTL_ELEM_ACCESS_READWRITE;
58 	access &= AOS_CTL_ELEM_ACCESS_READWRITE;
59 
60 	err = audio_ctl_new(&kctl, count, access);
61 	if (err < 0) {
62 		return NULL;
63 	}
64 
65 	/* The 'numid' member is decided when calling audio_ctl_add(). */
66 	kctl->id.iface = ncontrol->iface;
67 	kctl->id.deviceId = ncontrol->deviceId;
68 	kctl->id.subdeviceId = ncontrol->subdeviceId;
69 	if (ncontrol->name) {
70 		strlcpy((char*)kctl->id.name, (const char*)ncontrol->name, sizeof(kctl->id.name));
71 	}
72 	kctl->id.index = ncontrol->index;
73 	kctl->info = ncontrol->info;
74 	kctl->get = ncontrol->get;
75 	kctl->put = ncontrol->put;
76 	kctl->tlv.p = ncontrol->tlv.p;
77 	kctl->private_value = ncontrol->private_value;
78 	kctl->private_data = private_data;
79 
80 	return kctl;
81 }
82 
audio_soc_cnew(const struct audio_kcontrol_new * _template,void * data,const char * long_name)83 static struct audio_kcontrol *audio_soc_cnew(const struct audio_kcontrol_new *_template, void *data, const char *long_name)
84 {
85 	struct audio_kcontrol_new template;
86 	struct audio_kcontrol *kcontrol;
87 
88 	memcpy(&template, _template, sizeof(template));
89 	template.index = 0;
90 
91 	if (long_name) {
92 		template.name = long_name;
93 	}
94 
95 	kcontrol = audio_ctl_new1(&template, data);
96 	return kcontrol;
97 }
98 
audio_ctl_add(ctrl_device_t * dev,struct audio_kcontrol * kcontrol)99 static int audio_ctl_add(ctrl_device_t *dev, struct audio_kcontrol *kcontrol)
100 {
101 	struct audio_mixer_control *private_value = NULL;
102 	if (! kcontrol) {
103 		return -EINVAL;
104 	}
105 	if (!dev || !kcontrol->info) {
106         LOGE(LOG_TAG, "%s:%d, card or kcontrol is null", __func__, __LINE__);
107         goto __error__;
108     }
109 
110 	dlist_add_tail(&kcontrol->list, &dev->kcontrol_list);
111 	dev->kcontrols_count += kcontrol->count;
112 	kcontrol->id.id = dev->last_numid + 1;
113 	dev->last_numid += kcontrol->count;
114 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->count: %d", __func__, __LINE__, kcontrol->count);
115 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->id.id: %d", __func__, __LINE__, kcontrol->id.id);
116 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->id.index: %d", __func__, __LINE__, kcontrol->id.index);
117 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->id.iface: %d", __func__, __LINE__, kcontrol->id.iface);
118 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->id.name: %s", __func__, __LINE__, kcontrol->id.name);
119 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->id.device/subdevice: %d/%d", __func__, __LINE__, kcontrol->id.deviceId, kcontrol->id.subdeviceId);
120 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->vd[0].access: %d", __func__, __LINE__, kcontrol->vd[0].access);
121 	LOGD(LOG_TAG, "%s:%d, ----kcontrol->tlv.p: 0x%x", __func__, __LINE__, kcontrol->tlv.p);
122 	private_value = (struct audio_mixer_control *)kcontrol->private_value;
123 	if(private_value) {
124 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->min: 0x%x", __func__, __LINE__, private_value->min);
125 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->max: 0x%x", __func__, __LINE__, private_value->max);
126 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->platform_max: 0x%x", __func__, __LINE__, private_value->platform_max);
127 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->reg: 0x%x", __func__, __LINE__, private_value->reg);
128 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->rreg: 0x%x", __func__, __LINE__, private_value->rreg);
129 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->shift: 0x%x", __func__, __LINE__, private_value->shift);
130 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->rshift: 0x%x", __func__, __LINE__, private_value->rshift);
131 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->sign_bit: 0x%x", __func__, __LINE__, private_value->sign_bit);
132 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->invert: 0x%x", __func__, __LINE__, private_value->invert);
133 		LOGD(LOG_TAG, "%s:%d, ----kcontrol->private_value->autodisable: 0x%x", __func__, __LINE__, private_value->autodisable);
134 	}
135 
136 	return 0;
137 
138  __error__:
139 	if(kcontrol->private_free) {
140 		kcontrol->private_free(kcontrol);
141 	}
142 	free(kcontrol);
143 	return -EINVAL;
144 }
145 
146 /**************************************************************************
147  ** audio driver interface
148 **************************************************************************/
audio_add_controls(ctrl_device_t * dev,const struct audio_kcontrol_new * controls,int num_controls,void * data)149 int audio_add_controls(ctrl_device_t *dev, const struct audio_kcontrol_new *controls, int num_controls, void *data)
150 {
151 	int err, i;
152 	for (i = 0; i < num_controls; i++) {
153 		const struct audio_kcontrol_new *control = &controls[i];
154 		err = audio_ctl_add(dev, audio_soc_cnew(control, data, control->name));
155 		if (err < 0) {
156             LOGE(LOG_TAG, "%s:%d, Failed to add %s: %d", __func__, __LINE__, control->name, err);
157 			return err;
158 		}
159 	}
160 	return 0;
161 }
162 
163 /**************************************************************************
164  ** audio service interface
165 **************************************************************************/
audio_ctl_find_numid(ctrl_device_t * dev,unsigned int numid)166 static struct audio_kcontrol *audio_ctl_find_numid(ctrl_device_t *dev, unsigned int numid)
167 {
168 	struct audio_kcontrol *kctl = NULL;
169 
170 	if (!dev) {
171         LOGE(LOG_TAG, "%s:%d, dev is null", __func__, __LINE__);
172         return NULL;
173     }
174     dlist_for_each_entry(&dev->kcontrol_list, kctl, struct audio_kcontrol, list) {
175 		if (kctl->id.id <= numid && kctl->id.id + kctl->count > numid) {
176             return kctl;
177         }
178     }
179 	return NULL;
180 }
181 
audio_ctl_find_id(ctrl_device_t * dev,struct audio_ctl_elem_id * id)182 static struct audio_kcontrol *audio_ctl_find_id(ctrl_device_t *dev, struct audio_ctl_elem_id *id)
183 {
184 	struct audio_kcontrol *kctl = NULL;
185 
186 	if (!dev || !id) {
187         LOGE(LOG_TAG, "%s:%d, dev or id is null", __func__, __LINE__);
188         return NULL;
189     }
190 	if (id->id != 0) {
191         return audio_ctl_find_numid(dev, id->id);
192     }
193 	dlist_for_each_entry(&dev->kcontrol_list, kctl, struct audio_kcontrol, list) {
194 		if (kctl->id.iface != id->iface)
195 			continue;
196 		if (kctl->id.deviceId != id->deviceId)
197 			continue;
198 		if (kctl->id.subdeviceId != id->subdeviceId)
199 			continue;
200 		if (strncmp((const char*)kctl->id.name, (const char*)id->name, sizeof(kctl->id.name)))
201 			continue;
202 		if (kctl->id.index > id->index)
203 			continue;
204 		if (kctl->id.index + kctl->count <= id->index)
205 			continue;
206 		return kctl;
207 	}
208 	return NULL;
209 }
210 
audio_ctl_card_info(ctrl_device_t * dev,struct audio_ctl_card_info * info)211 int audio_ctl_card_info(ctrl_device_t *dev, struct audio_ctl_card_info *info)
212 {
213 	if (!dev || !info) {
214         LOGE(LOG_TAG, "%s:%d, dev or info is null", __func__, __LINE__);
215         return -EINVAL;
216     }
217 	info->card = dev->id;
218 	strlcpy((char*)info->shortName, (const char*)dev->name, sizeof(info->shortName));
219 	LOGD(LOG_TAG, "%s:%d, ----audio_ctl_card_info->card: %d", __func__, __LINE__, info->card);
220 	LOGD(LOG_TAG, "%s:%d, ----audio_ctl_card_info->shortName: %s", __func__, __LINE__, info->shortName);
221 	return 0;
222 }
223 
224 
audio_ctl_elem_list(ctrl_device_t * dev,struct audio_ctl_elem_list * list)225 int audio_ctl_elem_list(ctrl_device_t *dev, struct audio_ctl_elem_list *list)
226 {
227     struct audio_kcontrol *kctl;
228     struct audio_ctl_elem_id *dst, *id;
229     unsigned int offset, space, jidx;
230     struct dlist_s *node;
231 
232     if(!dev || !list) {
233         LOGE(LOG_TAG, "%s:%d, dev or list is null", __func__, __LINE__);
234         return -EINVAL;
235     }
236 
237     offset = list->offset;
238     space = list->space;
239 	LOGD(LOG_TAG, "%s:%d, ----offset: %d, space: %d", __func__, __LINE__, offset, space);
240     if(space > 16384) {
241         LOGE(LOG_TAG, "%s:%d, unexpected space size", __func__, __LINE__);
242         return -ENOMEM;
243     }
244 
245     list->count = dev->kcontrols_count;
246     list->used = 0;
247 
248     if(space > 0) {
249         dst = malloc(space * sizeof(struct audio_ctl_elem_id));
250         if(!dst) {
251             LOGE(LOG_TAG, "%s:%d, dst is null", __func__, __LINE__);
252             return -ENOMEM;
253         }
254 
255         /* 1. find the node by count offset */
256         node = dev->kcontrol_list.next;
257         while(node != &dev->kcontrol_list) {
258             if(0 == offset) {
259                 break;
260             }
261             kctl = aos_container_of(node, struct audio_kcontrol, list);
262             if(offset < kctl->count) {
263                 break;
264             }
265             offset -= kctl->count;
266             node = node->next;
267         }
268 
269         /* 2. copy all kctl->id to dst[] */
270         id = dst;
271         while(space > 0 && node != &dev->kcontrol_list) {
272             kctl = aos_container_of(node, struct audio_kcontrol, list);
273             for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
274                 /* copy kctl->id to dst[xx] */
275 				*id = kctl->id;
276                 id->index += jidx;
277                 id->id += jidx;
278 				LOGD(LOG_TAG, "%s:%d, ----id->numid: %d", __func__, __LINE__, id->id);
279 				LOGD(LOG_TAG, "%s:%d, ----id->index: %d", __func__, __LINE__, id->index);
280 				LOGD(LOG_TAG, "%s:%d, ----id->iface: %d", __func__, __LINE__, id->iface);
281 				LOGD(LOG_TAG, "%s:%d, ----id->name: %s", __func__, __LINE__, id->name);
282 				LOGD(LOG_TAG, "%s:%d, ----id->device/subdevice: %d/%d", __func__, __LINE__, id->deviceId, id->subdeviceId);
283 				id++;
284 				space--;
285 				list->used++;
286 			}
287 			node = node->next;
288 			offset = 0;
289         }
290 
291         /* 3. copy dst[] to list */
292         memcpy(list->pids, dst, list->used * sizeof(struct audio_ctl_elem_id));
293     }
294     return 0;
295 }
296 
audio_ctl_elem_info(ctrl_device_t * dev,struct audio_ctl_elem_info * info)297 int audio_ctl_elem_info(ctrl_device_t *dev, struct audio_ctl_elem_info *info)
298 {
299     int ret = -1;
300     struct audio_kcontrol *kctl = NULL;
301 
302     if(!dev || !info) {
303         LOGE(LOG_TAG, "%s:%d, dev or info is null", __func__, __LINE__);
304         return -EINVAL;
305     }
306     kctl = audio_ctl_find_id(dev, &info->id);
307     if(!kctl) {
308         LOGE(LOG_TAG, "%s:%d, no matched kctl", __func__, __LINE__);
309         return -ENOENT;
310     }
311 
312     if(kctl->info) {
313         ret = kctl->info(kctl, info);
314     }
315 	LOGD(LOG_TAG, "%s:%d, ----id->numid: %d", __func__, __LINE__, info->id.id);
316 	LOGD(LOG_TAG, "%s:%d, ----id->index: %d", __func__, __LINE__, info->id.index);
317 	LOGD(LOG_TAG, "%s:%d, ----id->iface: %d", __func__, __LINE__, info->id.iface);
318 	LOGD(LOG_TAG, "%s:%d, ----id->name: %s", __func__, __LINE__, info->id.name);
319     return ret;
320 }
321 
audio_ctl_elem_read(ctrl_device_t * dev,struct audio_ctl_elem_value * value)322 int audio_ctl_elem_read(ctrl_device_t *dev, struct audio_ctl_elem_value *value)
323 {
324     int ret = -1;
325     struct audio_kcontrol *kctl;
326     struct audio_kcontrol_volatile *vd;
327 
328 	if(!dev || !value) {
329         LOGE(LOG_TAG, "%s:%d, dev or info is null", __func__, __LINE__);
330         return -EINVAL;
331     }
332 
333     kctl = audio_ctl_find_id(dev, &value->id);
334     if(!kctl) {
335         LOGE(LOG_TAG, "%s:%d, no matched kctl", __func__, __LINE__);
336         return -ENOENT;
337     }
338     vd = &kctl->vd[0];
339     if ((vd->access & AOS_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
340 		//audio_ctl_build_ioff(&value->id, kctl, index_offset);
341         value->id = kctl->id;
342 		ret = kctl->get(kctl, value);
343 	}
344     return ret;
345 }
346 
audio_ctl_elem_write(ctrl_device_t * dev,struct audio_ctl_elem_value * value)347 int audio_ctl_elem_write(ctrl_device_t *dev, struct audio_ctl_elem_value *value)
348 {
349     int ret = -1;
350     struct audio_kcontrol *kctl;
351     struct audio_kcontrol_volatile *vd;
352 
353 	if(!dev || !value) {
354         LOGE(LOG_TAG, "%s:%d, dev or value is null", __func__, __LINE__);
355         return -EINVAL;
356     }
357 
358     kctl = audio_ctl_find_id(dev, &value->id);
359     if(!kctl) {
360         LOGE(LOG_TAG, "%s:%d, no matched kctl", __func__, __LINE__);
361         return -ENOENT;
362     }
363     vd = &kctl->vd[0];
364     if ((vd->access & AOS_CTL_ELEM_ACCESS_WRITE) && kctl->put != NULL) {
365 		//audio_ctl_build_ioff(&value->id, kctl, index_offset);
366         value->id = kctl->id;
367 		ret = kctl->put(kctl, value);
368 	}
369     return ret;
370 }
371 
audio_ctl_tlv_ioctl(ctrl_device_t * dev,struct audio_ctl_tlv * tlv,int op_flag)372 int audio_ctl_tlv_ioctl(ctrl_device_t *dev, struct audio_ctl_tlv *tlv, int op_flag)
373 {
374     int ret = -1;
375 	struct audio_kcontrol *kctl;
376 
377 	if(!dev || !tlv) {
378         LOGE(LOG_TAG, "%s:%d, dev or tlv is null", __func__, __LINE__);
379         return -EINVAL;
380     }
381 
382     kctl = audio_ctl_find_numid(dev, tlv->numid);
383     if(!kctl) {
384         LOGE(LOG_TAG, "%s:%d, no matched kctl", __func__, __LINE__);
385         return -ENOENT;
386     }
387 
388     if(!kctl->tlv.c) {
389         LOGE(LOG_TAG, "%s:%d, kctl->tlv.c is null", __func__, __LINE__);
390         return -EPERM;
391     }
392     ret = kctl->tlv.c(kctl, op_flag, tlv->len, tlv->tlv);
393     return ret;
394 }
395 
get_integer_info(struct audio_kcontrol * kcontrol,struct audio_ctl_elem_info * uinfo)396 int get_integer_info(struct audio_kcontrol * kcontrol, struct audio_ctl_elem_info * uinfo)
397 {
398 	struct audio_mixer_control *mc = (struct audio_mixer_control *)kcontrol->private_value;
399 	int platform_max;
400 
401 	if (!mc->platform_max)
402 		mc->platform_max = mc->max;
403 	platform_max = mc->platform_max;
404 
405 	if (platform_max == 1 && !strstr((const char*)kcontrol->id.name, " Volume"))
406 		uinfo->type = AOS_CTL_ELEM_TYPE_BOOLEAN;
407 	else
408 		uinfo->type = AOS_CTL_ELEM_TYPE_INTEGER;
409 
410 	uinfo->id = kcontrol->id;
411 	uinfo->count = 1;
412 	uinfo->value.integer.min = 0;
413 	uinfo->value.integer.max = platform_max - mc->min;
414 	return 0;
415 }
416 
417