1 /**
2  * \file control/control_remap.c
3  * \brief CTL Remap Plugin Interface
4  * \author Jaroslav Kysela <perex@perex.cz>
5  * \date 2021
6  */
7 /*
8  *  Control - Remap Controls
9  *  Copyright (c) 2021 by Jaroslav Kysela <perex@perex.cz>
10  *
11  *
12  *   This library is free software; you can redistribute it and/or modify
13  *   it under the terms of the GNU Lesser General Public License as
14  *   published by the Free Software Foundation; either version 2.1 of
15  *   the License, or (at your option) any later version.
16  *
17  *   This program is distributed in the hope that it will be useful,
18  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *   GNU Lesser General Public License for more details.
21  *
22  *   You should have received a copy of the GNU Lesser General Public
23  *   License along with this library; if not, write to the Free Software
24  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  */
27 
28 #include "control_local.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 #include <string.h>
35 
36 #ifndef DOC_HIDDEN
37 #if 0
38 #define REMAP_DEBUG 1
39 #define debug(format, args...) fprintf(stderr, format, ##args)
40 #define debug_id(id, format, args...) do { \
41 	char *s = snd_ctl_ascii_elem_id_get(id); \
42 	fprintf(stderr, "%s: ", s); free(s); \
43 	fprintf(stderr, format, ##args); \
44 } while (0)
45 #else
46 #define REMAP_DEBUG 0
47 #define debug(format, args...) do { } while (0)
48 #define debug_id(id, format, args...) do { } while (0)
49 #endif
50 
51 #define EREMAPNOTFOUND (888899)
52 #endif /* DOC_HIDDEN */
53 
54 #ifndef PIC
55 /* entry for static linking */
56 const char *_snd_module_control_remap = "";
57 #endif
58 
59 #ifndef DOC_HIDDEN
60 typedef struct {
61 	unsigned int numid_child;
62 	unsigned int numid_app;
63 } snd_ctl_numid_t;
64 
65 typedef struct {
66 	snd_ctl_elem_id_t id_child;
67 	snd_ctl_elem_id_t id_app;
68 } snd_ctl_remap_id_t;
69 
70 typedef struct {
71 	snd_ctl_elem_id_t map_id;
72 	snd_ctl_elem_type_t type;
73 	size_t controls_items;
74 	size_t controls_alloc;
75 	struct snd_ctl_map_ctl {
76 		snd_ctl_elem_id_t id_child;
77 		size_t channel_map_items;
78 		size_t channel_map_alloc;
79 		long *channel_map;
80 	} *controls;
81 	unsigned int event_mask;
82 } snd_ctl_map_t;
83 
84 typedef struct {
85 	snd_ctl_t *child;
86 	int numid_remap_active;
87 	unsigned int numid_app_last;
88 	size_t numid_items;
89 	size_t numid_alloc;
90 	snd_ctl_numid_t *numid;
91 	snd_ctl_numid_t numid_temp;
92 	size_t remap_items;
93 	size_t remap_alloc;
94 	snd_ctl_remap_id_t *remap;
95 	size_t map_items;
96 	size_t map_alloc;
97 	snd_ctl_map_t *map;
98 	size_t map_read_queue_head;
99 	size_t map_read_queue_tail;
100 	snd_ctl_map_t **map_read_queue;
101 } snd_ctl_remap_t;
102 #endif
103 
remap_numid_temp(snd_ctl_remap_t *priv, unsigned int numid)104 static snd_ctl_numid_t *remap_numid_temp(snd_ctl_remap_t *priv, unsigned int numid)
105 {
106 	priv->numid_temp.numid_child = numid;
107 	priv->numid_temp.numid_app = numid;
108 	return &priv->numid_temp;
109 }
110 
remap_find_numid_app(snd_ctl_remap_t *priv, unsigned int numid_app)111 static snd_ctl_numid_t *remap_find_numid_app(snd_ctl_remap_t *priv, unsigned int numid_app)
112 {
113 	snd_ctl_numid_t *numid;
114 	size_t count;
115 
116 	if (!priv->numid_remap_active)
117 		return remap_numid_temp(priv, numid_app);
118 	numid = priv->numid;
119 	for (count = priv->numid_items; count > 0; count--, numid++)
120 		if (numid_app == numid->numid_app)
121 			return numid;
122 	return NULL;
123 }
124 
remap_numid_new(snd_ctl_remap_t *priv, unsigned int numid_child, unsigned int numid_app)125 static snd_ctl_numid_t *remap_numid_new(snd_ctl_remap_t *priv, unsigned int numid_child,
126 					unsigned int numid_app)
127 {
128 	snd_ctl_numid_t *numid;
129 
130 	if (priv->numid_alloc == priv->numid_items) {
131 		numid = realloc(priv->numid, (priv->numid_alloc + 16) * sizeof(*numid));
132 		if (numid == NULL)
133 			return NULL;
134 		memset(numid + priv->numid_alloc, 0, sizeof(*numid) * 16);
135 		priv->numid_alloc += 16;
136 		priv->numid = numid;
137 	}
138 	numid = &priv->numid[priv->numid_items++];
139 	numid->numid_child = numid_child;
140 	numid->numid_app = numid_app;
141 	debug("new numid: child %u app %u\n", numid->numid_child, numid->numid_app);
142 	return numid;
143 }
144 
remap_numid_child_new(snd_ctl_remap_t *priv, unsigned int numid_child)145 static snd_ctl_numid_t *remap_numid_child_new(snd_ctl_remap_t *priv, unsigned int numid_child)
146 {
147 	unsigned int numid_app;
148 
149 	if (numid_child == 0)
150 		return NULL;
151 	if (priv->numid_remap_active && remap_find_numid_app(priv, numid_child)) {
152 		while (remap_find_numid_app(priv, priv->numid_app_last))
153 			priv->numid_app_last++;
154 		numid_app = priv->numid_app_last;
155 	} else {
156 		numid_app = numid_child;
157 	}
158 	return remap_numid_new(priv, numid_child, numid_app);
159 }
160 
remap_find_numid_child(snd_ctl_remap_t *priv, unsigned int numid_child)161 static snd_ctl_numid_t *remap_find_numid_child(snd_ctl_remap_t *priv, unsigned int numid_child)
162 {
163 	snd_ctl_numid_t *numid;
164 	size_t count;
165 
166 	if (!priv->numid_remap_active)
167 		return remap_numid_temp(priv, numid_child);
168 	numid = priv->numid;
169 	for (count = priv->numid_items; count > 0; count--, numid++)
170 		if (numid_child == numid->numid_child)
171 			return numid;
172 	return remap_numid_child_new(priv, numid_child);
173 }
174 
remap_find_id_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)175 static snd_ctl_remap_id_t *remap_find_id_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
176 {
177 	size_t count;
178 	snd_ctl_remap_id_t *rid;
179 
180 	if (id->numid > 0) {
181 		rid = priv->remap;
182 		for (count = priv->remap_items; count > 0; count--, rid++)
183 			if (id->numid == rid->id_child.numid)
184 				return rid;
185 	}
186 	rid = priv->remap;
187 	for (count = priv->remap_items; count > 0; count--, rid++)
188 		if (snd_ctl_elem_id_compare_set(id, &rid->id_child) == 0)
189 			return rid;
190 	return NULL;
191 }
192 
remap_find_id_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)193 static snd_ctl_remap_id_t *remap_find_id_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
194 {
195 	size_t count;
196 	snd_ctl_remap_id_t *rid;
197 
198 	if (id->numid > 0) {
199 		rid = priv->remap;
200 		for (count = priv->remap_items; count > 0; count--, rid++)
201 			if (id->numid == rid->id_app.numid)
202 				return rid;
203 	}
204 	rid = priv->remap;
205 	for (count = priv->remap_items; count > 0; count--, rid++)
206 		if (snd_ctl_elem_id_compare_set(id, &rid->id_app) == 0)
207 			return rid;
208 	return NULL;
209 }
210 
remap_find_map_numid(snd_ctl_remap_t *priv, unsigned int numid)211 static snd_ctl_map_t *remap_find_map_numid(snd_ctl_remap_t *priv, unsigned int numid)
212 {
213 	size_t count;
214 	snd_ctl_map_t *map;
215 
216 	if (numid == 0)
217 		return NULL;
218 	map = priv->map;
219 	for (count = priv->map_items; count > 0; count--, map++) {
220 		if (numid == map->map_id.numid)
221 			return map;
222 	}
223 	return NULL;
224 }
225 
remap_find_map_id(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)226 static snd_ctl_map_t *remap_find_map_id(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id)
227 {
228 	size_t count;
229 	snd_ctl_map_t *map;
230 
231 	if (id->numid > 0)
232 		return remap_find_map_numid(priv, id->numid);
233 	map = priv->map;
234 	for (count = priv->map_items; count > 0; count--, map++)
235 		if (snd_ctl_elem_id_compare_set(id, &map->map_id) == 0)
236 			return map;
237 	return NULL;
238 }
239 
remap_id_to_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl_remap_id_t **_rid)240 static int remap_id_to_child(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl_remap_id_t **_rid)
241 {
242 	snd_ctl_remap_id_t *rid;
243 	snd_ctl_numid_t *numid;
244 
245 	debug_id(id, "%s enter\n", __func__);
246 	rid = remap_find_id_app(priv, id);
247 	if (rid) {
248 		if (rid->id_app.numid == 0) {
249 			numid = remap_find_numid_app(priv, id->numid);
250 			if (numid) {
251 				rid->id_child.numid = numid->numid_child;
252 				rid->id_app.numid = numid->numid_app;
253 			}
254 		}
255 		*id = rid->id_child;
256 	} else {
257 		if (remap_find_id_child(priv, id))
258 			return -ENOENT;
259 		numid = remap_find_numid_app(priv, id->numid);
260 		if (numid)
261 			id->numid = numid->numid_child;
262 		else
263 			id->numid = 0;
264 	}
265 	*_rid = rid;
266 	debug_id(id, "%s leave\n", __func__);
267 	return 0;
268 }
269 
remap_id_to_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl_remap_id_t *rid, int err)270 static int remap_id_to_app(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, snd_ctl_remap_id_t *rid, int err)
271 {
272 	snd_ctl_numid_t *numid;
273 
274 	if (rid) {
275 		if (err >= 0 && rid->id_app.numid == 0) {
276 			numid = remap_numid_child_new(priv, id->numid);
277 			if (numid == NULL)
278 				return -EIO;
279 			rid->id_child.numid = numid->numid_child;
280 			rid->id_app.numid = numid->numid_app;
281 		}
282 		*id = rid->id_app;
283 	} else {
284 		if (err >= 0) {
285 			numid = remap_find_numid_child(priv, id->numid);
286 			if (numid == NULL)
287 				return -EIO;
288 			id->numid = numid->numid_app;
289 		}
290 	}
291 	return err;
292 }
293 
remap_free(snd_ctl_remap_t *priv)294 static void remap_free(snd_ctl_remap_t *priv)
295 {
296 	size_t idx1, idx2;
297 	snd_ctl_map_t *map;
298 
299 	for (idx1 = 0; idx1 < priv->map_items; idx1++) {
300 		map = &priv->map[idx1];
301 		for (idx2 = 0; idx2 < map->controls_items; idx2++)
302 			free(map->controls[idx2].channel_map);
303 		free(map->controls);
304 	}
305 	free(priv->map_read_queue);
306 	free(priv->map);
307 	free(priv->remap);
308 	free(priv->numid);
309 	free(priv);
310 }
311 
snd_ctl_remap_close(snd_ctl_t *ctl)312 static int snd_ctl_remap_close(snd_ctl_t *ctl)
313 {
314 	snd_ctl_remap_t *priv = ctl->private_data;
315 	int err = snd_ctl_close(priv->child);
316 	remap_free(priv);
317 	return err;
318 }
319 
snd_ctl_remap_nonblock(snd_ctl_t *ctl, int nonblock)320 static int snd_ctl_remap_nonblock(snd_ctl_t *ctl, int nonblock)
321 {
322 	snd_ctl_remap_t *priv = ctl->private_data;
323 	return snd_ctl_nonblock(priv->child, nonblock);
324 }
325 
snd_ctl_remap_async(snd_ctl_t *ctl, int sig, pid_t pid)326 static int snd_ctl_remap_async(snd_ctl_t *ctl, int sig, pid_t pid)
327 {
328 	snd_ctl_remap_t *priv = ctl->private_data;
329 	return snd_ctl_async(priv->child, sig, pid);
330 }
331 
snd_ctl_remap_subscribe_events(snd_ctl_t *ctl, int subscribe)332 static int snd_ctl_remap_subscribe_events(snd_ctl_t *ctl, int subscribe)
333 {
334 	snd_ctl_remap_t *priv = ctl->private_data;
335 	return snd_ctl_subscribe_events(priv->child, subscribe);
336 }
337 
snd_ctl_remap_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)338 static int snd_ctl_remap_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
339 {
340 	snd_ctl_remap_t *priv = ctl->private_data;
341 	return snd_ctl_card_info(priv->child, info);
342 }
343 
snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)344 static int snd_ctl_remap_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)
345 {
346 	snd_ctl_remap_t *priv = ctl->private_data;
347 	snd_ctl_elem_id_t *id;
348 	snd_ctl_remap_id_t *rid;
349 	snd_ctl_numid_t *numid;
350 	snd_ctl_map_t *map;
351 	unsigned int index;
352 	size_t index2;
353 	int err;
354 
355 	err = snd_ctl_elem_list(priv->child, list);
356 	if (err < 0)
357 		return err;
358 	for (index = 0; index < list->used; index++) {
359 		id = &list->pids[index];
360 		rid = remap_find_id_child(priv, id);
361 		if (rid) {
362 			rid->id_app.numid = id->numid;
363 			*id = rid->id_app;
364 		}
365 		numid = remap_find_numid_child(priv, id->numid);
366 		if (numid == NULL)
367 			return -EIO;
368 		id->numid = numid->numid_app;
369 	}
370 	if (list->offset >= list->count + priv->map_items)
371 		return 0;
372 	index2 = 0;
373 	if (list->offset > list->count)
374 		index2 = list->offset - list->count;
375 	for ( ; index < list->space && index2 < priv->map_items; index2++, index++) {
376 		id = &list->pids[index];
377 		map = &priv->map[index2];
378 		*id = map->map_id;
379 		list->used++;
380 	}
381 	list->count += priv->map_items;
382 	return 0;
383 }
384 
385 #ifndef DOC_HIDDEN
386 #define ACCESS_BITS(bits) \
387 	(bits & (SNDRV_CTL_ELEM_ACCESS_READWRITE|\
388 		 SNDRV_CTL_ELEM_ACCESS_VOLATILE|\
389 		 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
390 #endif /* DOC_HIDDEN */
391 
remap_map_elem_info(snd_ctl_remap_t *priv, snd_ctl_elem_info_t *info)392 static int remap_map_elem_info(snd_ctl_remap_t *priv, snd_ctl_elem_info_t *info)
393 {
394 	snd_ctl_map_t *map;
395 	snd_ctl_elem_info_t info2, info3;
396 	size_t item;
397 	unsigned int access;
398 	size_t count;
399 	int owner, err;
400 
401 	map = remap_find_map_id(priv, &info->id);
402 	if (map == NULL)
403 		return -EREMAPNOTFOUND;
404 	debug_id(&info->id, "%s\n", __func__);
405 	assert(map->controls_items > 0);
406 	snd_ctl_elem_info_clear(&info2);
407 	info2.id = map->controls[0].id_child;
408 	debug_id(&info2.id, "%s controls[0]\n", __func__);
409 	err = snd_ctl_elem_info(priv->child, &info2);
410 	if (err < 0)
411 		return err;
412 	if (info2.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
413 	    info2.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
414 	    info2.type != SNDRV_CTL_ELEM_TYPE_INTEGER64 &&
415 	    info2.type != SNDRV_CTL_ELEM_TYPE_BYTES)
416 		return -EIO;
417 	map->controls[0].id_child.numid = info2.id.numid;
418 	map->type = info2.type;
419 	access = info2.access;
420 	owner = info2.owner;
421 	count = map->controls[0].channel_map_items;
422 	for (item = 1; item < map->controls_items; item++) {
423 		snd_ctl_elem_info_clear(&info3);
424 		info3.id = map->controls[item].id_child;
425 		debug_id(&info3.id, "%s controls[%zd]\n", __func__, item);
426 		err = snd_ctl_elem_info(priv->child, &info3);
427 		if (err < 0)
428 			return err;
429 		if (info2.type != info3.type)
430 			return -EIO;
431 		if (ACCESS_BITS(info2.access) != ACCESS_BITS(info3.access))
432 			return -EIO;
433 		if (info2.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
434 		    info2.type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
435 			if (memcmp(&info2.value.integer, &info3.value.integer, sizeof(info2.value.integer)))
436 				return -EIO;
437 		} else if (info2.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
438 			if (memcmp(&info2.value.integer64, &info3.value.integer64, sizeof(info2.value.integer64)))
439 				return -EIO;
440 		}
441 		access |= info3.access;
442 		if (owner == 0)
443 			owner = info3.owner;
444 		if (count < map->controls[item].channel_map_items)
445 			count = map->controls[item].channel_map_items;
446 	}
447 	snd_ctl_elem_info_clear(info);
448 	info->id = map->map_id;
449 	info->type = info2.type;
450 	info->access = access;
451 	info->count = count;
452 	if (info2.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
453 	    info2.type == SNDRV_CTL_ELEM_TYPE_INTEGER)
454 		info->value.integer = info2.value.integer;
455 	else if (info2.type == SNDRV_CTL_ELEM_TYPE_INTEGER64)
456 		info->value.integer64 = info2.value.integer64;
457 	if (access & SNDRV_CTL_ELEM_ACCESS_LOCK)
458 		info->owner = owner;
459 	return 0;
460 }
461 
snd_ctl_remap_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)462 static int snd_ctl_remap_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
463 {
464 	snd_ctl_remap_t *priv = ctl->private_data;
465 	snd_ctl_remap_id_t *rid;
466 	int err;
467 
468 	debug_id(&info->id, "%s\n", __func__);
469 	err = remap_map_elem_info(priv, info);
470 	if (err != -EREMAPNOTFOUND)
471 		return err;
472 	err = remap_id_to_child(priv, &info->id, &rid);
473 	if (err < 0)
474 		return err;
475 	err = snd_ctl_elem_info(priv->child, info);
476 	return remap_id_to_app(priv, &info->id, rid, err);
477 }
478 
remap_map_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)479 static int remap_map_elem_read(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)
480 {
481 	snd_ctl_map_t *map;
482 	struct snd_ctl_map_ctl *mctl;
483 	snd_ctl_elem_value_t control2;
484 	size_t item, index;
485 	int err;
486 
487 	map = remap_find_map_id(priv, &control->id);
488 	if (map == NULL)
489 		return -EREMAPNOTFOUND;
490 	debug_id(&control->id, "%s\n", __func__);
491 	snd_ctl_elem_value_clear(control);
492 	control->id = map->map_id;
493 	for (item = 0; item < map->controls_items; item++) {
494 		mctl = &map->controls[item];
495 		snd_ctl_elem_value_clear(&control2);
496 		control2.id = mctl->id_child;
497 		debug_id(&control2.id, "%s controls[%zd]\n", __func__, item);
498 		err = snd_ctl_elem_read(priv->child, &control2);
499 		if (err < 0)
500 			return err;
501 		if (map->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
502 		    map->type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
503 			for (index = 0; index < mctl->channel_map_items; index++) {
504 				long src = mctl->channel_map[index];
505 				if ((unsigned long)src < ARRAY_SIZE(control->value.integer.value))
506 					control->value.integer.value[index] = control2.value.integer.value[src];
507 			}
508 		} else if (map->type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
509 			for (index = 0; index < mctl->channel_map_items; index++) {
510 				long src = mctl->channel_map[index];
511 				if ((unsigned long)src < ARRAY_SIZE(control->value.integer64.value))
512 					control->value.integer64.value[index] = control2.value.integer64.value[src];
513 			}
514 		} else if (map->type == SNDRV_CTL_ELEM_TYPE_BYTES) {
515 			for (index = 0; index < mctl->channel_map_items; index++) {
516 				long src = mctl->channel_map[index];
517 				if ((unsigned long)src < ARRAY_SIZE(control->value.bytes.data))
518 					control->value.bytes.data[index] = control2.value.bytes.data[src];
519 			}
520 		}
521 	}
522 	return 0;
523 }
524 
snd_ctl_remap_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)525 static int snd_ctl_remap_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
526 {
527 	snd_ctl_remap_t *priv = ctl->private_data;
528 	snd_ctl_remap_id_t *rid;
529 	int err;
530 
531 	debug_id(&control->id, "%s\n", __func__);
532 	err = remap_map_elem_read(priv, control);
533 	if (err != -EREMAPNOTFOUND)
534 		return err;
535 	err = remap_id_to_child(priv, &control->id, &rid);
536 	if (err < 0)
537 		return err;
538 	err = snd_ctl_elem_read(priv->child, control);
539 	return remap_id_to_app(priv, &control->id, rid, err);
540 }
541 
remap_map_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)542 static int remap_map_elem_write(snd_ctl_remap_t *priv, snd_ctl_elem_value_t *control)
543 {
544 	snd_ctl_map_t *map;
545 	struct snd_ctl_map_ctl *mctl;
546 	snd_ctl_elem_value_t control2;
547 	size_t item, index;
548 	int err, changes;
549 
550 	map = remap_find_map_id(priv, &control->id);
551 	if (map == NULL)
552 		return -EREMAPNOTFOUND;
553 	debug_id(&control->id, "%s\n", __func__);
554 	control->id = map->map_id;
555 	for (item = 0; item < map->controls_items; item++) {
556 		mctl = &map->controls[item];
557 		snd_ctl_elem_value_clear(&control2);
558 		control2.id = mctl->id_child;
559 		debug_id(&control2.id, "%s controls[%zd]\n", __func__, item);
560 		err = snd_ctl_elem_read(priv->child, &control2);
561 		if (err < 0)
562 			return err;
563 		changes = 0;
564 		if (map->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
565 		    map->type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
566 			for (index = 0; index < mctl->channel_map_items; index++) {
567 				long dst = mctl->channel_map[index];
568 				if ((unsigned long)dst < ARRAY_SIZE(control->value.integer.value)) {
569 					changes |= control2.value.integer.value[dst] != control->value.integer.value[index];
570 					control2.value.integer.value[dst] = control->value.integer.value[index];
571 				}
572 			}
573 		} else if (map->type == SNDRV_CTL_ELEM_TYPE_INTEGER64) {
574 			for (index = 0; index < mctl->channel_map_items; index++) {
575 				long dst = mctl->channel_map[index];
576 				if ((unsigned long)dst < ARRAY_SIZE(control->value.integer64.value)) {
577 					changes |= control2.value.integer64.value[dst] != control->value.integer64.value[index];
578 					control2.value.integer64.value[dst] = control->value.integer64.value[index];
579 				}
580 			}
581 		} else if (map->type == SNDRV_CTL_ELEM_TYPE_BYTES) {
582 			for (index = 0; index < mctl->channel_map_items; index++) {
583 				long dst = mctl->channel_map[index];
584 				if ((unsigned long)dst < ARRAY_SIZE(control->value.bytes.data)) {
585 					changes |= control2.value.bytes.data[dst] != control->value.bytes.data[index];
586 					control2.value.bytes.data[dst] = control->value.bytes.data[index];
587 				}
588 			}
589 		}
590 		debug_id(&control2.id, "%s changes %d\n", __func__, changes);
591 		if (changes > 0) {
592 			err = snd_ctl_elem_write(priv->child, &control2);
593 			if (err < 0)
594 				return err;
595 		}
596 	}
597 	return 0;
598 }
599 
snd_ctl_remap_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)600 static int snd_ctl_remap_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
601 {
602 	snd_ctl_remap_t *priv = ctl->private_data;
603 	snd_ctl_remap_id_t *rid;
604 	int err;
605 
606 	debug_id(&control->id, "%s\n", __func__);
607 	err = remap_map_elem_write(priv, control);
608 	if (err != -EREMAPNOTFOUND)
609 		return err;
610 	err = remap_id_to_child(priv, &control->id, &rid);
611 	if (err < 0)
612 		return err;
613 	err = snd_ctl_elem_write(priv->child, control);
614 	return remap_id_to_app(priv, &control->id, rid, err);
615 }
616 
snd_ctl_remap_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)617 static int snd_ctl_remap_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
618 {
619 	snd_ctl_remap_t *priv = ctl->private_data;
620 	snd_ctl_remap_id_t *rid;
621 	int err;
622 
623 	debug_id(id, "%s\n", __func__);
624 	err = remap_id_to_child(priv, id, &rid);
625 	if (err < 0)
626 		return err;
627 	err = snd_ctl_elem_lock(priv->child, id);
628 	return remap_id_to_app(priv, id, rid, err);
629 }
630 
snd_ctl_remap_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)631 static int snd_ctl_remap_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
632 {
633 	snd_ctl_remap_t *priv = ctl->private_data;
634 	snd_ctl_remap_id_t *rid;
635 	int err;
636 
637 	debug_id(id, "%s\n", __func__);
638 	err = remap_id_to_child(priv, id, &rid);
639 	if (err < 0)
640 		return err;
641 	err = snd_ctl_elem_unlock(priv->child, id);
642 	return remap_id_to_app(priv, id, rid, err);
643 }
644 
remap_get_map_numid(snd_ctl_remap_t *priv, struct snd_ctl_map_ctl *mctl)645 static int remap_get_map_numid(snd_ctl_remap_t *priv, struct snd_ctl_map_ctl *mctl)
646 {
647 	snd_ctl_elem_info_t info;
648 	snd_ctl_numid_t *numid;
649 	int err;
650 
651 	if (mctl->id_child.numid > 0)
652 		return 0;
653 	debug_id(&mctl->id_child, "%s get numid\n", __func__);
654 	snd_ctl_elem_info_clear(&info);
655 	info.id = mctl->id_child;
656 	err = snd_ctl_elem_info(priv->child, &info);
657 	if (err < 0)
658 		return err;
659 	numid = remap_find_numid_child(priv, info.id.numid);
660 	if (numid == NULL)
661 		return -EIO;
662 	mctl->id_child.numid = info.id.numid;
663 	return 0;
664 }
665 
remap_map_elem_tlv(snd_ctl_remap_t *priv, int op_flag, unsigned int numid, unsigned int *tlv, unsigned int tlv_size)666 static int remap_map_elem_tlv(snd_ctl_remap_t *priv, int op_flag, unsigned int numid,
667 			      unsigned int *tlv, unsigned int tlv_size)
668 {
669 	snd_ctl_map_t *map;
670 	struct snd_ctl_map_ctl *mctl;
671 	size_t item;
672 	unsigned int *tlv2;
673 	int err;
674 
675 	map = remap_find_map_numid(priv, numid);
676 	if (map == NULL)
677 		return -EREMAPNOTFOUND;
678 	if (op_flag != 0)	/* read only */
679 		return -ENXIO;
680 	debug("%s numid %d\n", __func__, numid);
681 	mctl = &map->controls[0];
682 	err = remap_get_map_numid(priv, mctl);
683 	if (err < 0)
684 		return err;
685 	memset(tlv, 0, tlv_size);
686 	err = priv->child->ops->element_tlv(priv->child, op_flag, mctl->id_child.numid, tlv, tlv_size);
687 	if (err < 0)
688 		return err;
689 	tlv2 = malloc(tlv_size);
690 	if (tlv2 == NULL)
691 		return -ENOMEM;
692 	for (item = 1; item < map->controls_items; item++) {
693 		mctl = &map->controls[item];
694 		err = remap_get_map_numid(priv, mctl);
695 		if (err < 0) {
696 			free(tlv2);
697 			return err;
698 		}
699 		memset(tlv2, 0, tlv_size);
700 		err = priv->child->ops->element_tlv(priv->child, op_flag, mctl->id_child.numid, tlv2, tlv_size);
701 		if (err < 0) {
702 			free(tlv2);
703 			return err;
704 		}
705 		if (memcmp(tlv, tlv2, tlv_size) != 0) {
706 			free(tlv2);
707 			return -EIO;
708 		}
709 	}
710 	free(tlv2);
711 	return 0;
712 }
713 
snd_ctl_remap_elem_tlv(snd_ctl_t *ctl, int op_flag, unsigned int numid, unsigned int *tlv, unsigned int tlv_size)714 static int snd_ctl_remap_elem_tlv(snd_ctl_t *ctl, int op_flag,
715 				  unsigned int numid,
716 				  unsigned int *tlv, unsigned int tlv_size)
717 {
718 	snd_ctl_remap_t *priv = ctl->private_data;
719 	snd_ctl_numid_t *map_numid;
720 	int err;
721 
722 	debug("%s: numid = %d, op_flag = %d\n", __func__, numid, op_flag);
723 	err = remap_map_elem_tlv(priv, op_flag, numid, tlv, tlv_size);
724 	if (err != -EREMAPNOTFOUND)
725 		return err;
726 	map_numid = remap_find_numid_app(priv, numid);
727 	if (map_numid == NULL)
728 		return -ENOENT;
729 	return priv->child->ops->element_tlv(priv->child, op_flag, map_numid->numid_child, tlv, tlv_size);
730 }
731 
snd_ctl_remap_hwdep_next_device(snd_ctl_t *ctl, int * device)732 static int snd_ctl_remap_hwdep_next_device(snd_ctl_t *ctl, int * device)
733 {
734 	snd_ctl_remap_t *priv = ctl->private_data;
735 	return snd_ctl_hwdep_next_device(priv->child, device);
736 }
737 
snd_ctl_remap_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)738 static int snd_ctl_remap_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
739 {
740 	snd_ctl_remap_t *priv = ctl->private_data;
741 	return snd_ctl_hwdep_info(priv->child, info);
742 }
743 
snd_ctl_remap_pcm_next_device(snd_ctl_t *ctl, int * device)744 static int snd_ctl_remap_pcm_next_device(snd_ctl_t *ctl, int * device)
745 {
746 	snd_ctl_remap_t *priv = ctl->private_data;
747 	return snd_ctl_pcm_next_device(priv->child, device);
748 }
749 
snd_ctl_remap_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)750 static int snd_ctl_remap_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
751 {
752 	snd_ctl_remap_t *priv = ctl->private_data;
753 	return snd_ctl_pcm_info(priv->child, info);
754 }
755 
snd_ctl_remap_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)756 static int snd_ctl_remap_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
757 {
758 	snd_ctl_remap_t *priv = ctl->private_data;
759 	return snd_ctl_pcm_prefer_subdevice(priv->child, subdev);
760 }
761 
snd_ctl_remap_rawmidi_next_device(snd_ctl_t *ctl, int * device)762 static int snd_ctl_remap_rawmidi_next_device(snd_ctl_t *ctl, int * device)
763 {
764 	snd_ctl_remap_t *priv = ctl->private_data;
765 	return snd_ctl_rawmidi_next_device(priv->child, device);
766 }
767 
snd_ctl_remap_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)768 static int snd_ctl_remap_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
769 {
770 	snd_ctl_remap_t *priv = ctl->private_data;
771 	return snd_ctl_rawmidi_info(priv->child, info);
772 }
773 
snd_ctl_remap_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)774 static int snd_ctl_remap_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
775 {
776 	snd_ctl_remap_t *priv = ctl->private_data;
777 	return snd_ctl_rawmidi_prefer_subdevice(priv->child, subdev);
778 }
779 
snd_ctl_remap_set_power_state(snd_ctl_t *ctl, unsigned int state)780 static int snd_ctl_remap_set_power_state(snd_ctl_t *ctl, unsigned int state)
781 {
782 	snd_ctl_remap_t *priv = ctl->private_data;
783 	return snd_ctl_set_power_state(priv->child, state);
784 }
785 
snd_ctl_remap_get_power_state(snd_ctl_t *ctl, unsigned int *state)786 static int snd_ctl_remap_get_power_state(snd_ctl_t *ctl, unsigned int *state)
787 {
788 	snd_ctl_remap_t *priv = ctl->private_data;
789 	return snd_ctl_get_power_state(priv->child, state);
790 }
791 
_next_ptr(size_t *ptr, size_t count)792 static void _next_ptr(size_t *ptr, size_t count)
793 {
794 	*ptr = (*ptr + 1) % count;
795 }
796 
remap_event_for_all_map_controls(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *id, unsigned int event_mask)797 static void remap_event_for_all_map_controls(snd_ctl_remap_t *priv,
798 					     snd_ctl_elem_id_t *id,
799 					     unsigned int event_mask)
800 {
801 	size_t count, index, head;
802 	snd_ctl_map_t *map;
803 	struct snd_ctl_map_ctl *mctl;
804 	int found;
805 
806 	if (event_mask == SNDRV_CTL_EVENT_MASK_REMOVE)
807 		event_mask = SNDRV_CTL_EVENT_MASK_INFO;
808 	map = priv->map;
809 	for (count = priv->map_items; count > 0; count--, map++) {
810 		for (index = 0; index < map->controls_items; index++) {
811 			mctl = &map->controls[index];
812 			if (mctl->id_child.numid == 0) {
813 				if (snd_ctl_elem_id_compare_set(id, &mctl->id_child))
814 					continue;
815 				mctl->id_child.numid = id->numid;
816 			}
817 			if (id->numid != mctl->id_child.numid)
818 				continue;
819 			debug_id(&map->map_id, "%s found (all)\n", __func__);
820 			map->event_mask |= event_mask;
821 			found = 0;
822 			for (head = priv->map_read_queue_head;
823 			     head != priv->map_read_queue_tail;
824 			     _next_ptr(&head, priv->map_items))
825 				if (priv->map_read_queue[head] == map) {
826 					found = 1;
827 					break;
828 				}
829 			if (found)
830 				continue;
831 			debug_id(&map->map_id, "%s marking for read\n", __func__);
832 			priv->map_read_queue[priv->map_read_queue_tail] = map;
833 			_next_ptr(&priv->map_read_queue_tail, priv->map_items);
834 		}
835 	}
836 }
837 
snd_ctl_remap_read(snd_ctl_t *ctl, snd_ctl_event_t *event)838 static int snd_ctl_remap_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
839 {
840 	snd_ctl_remap_t *priv = ctl->private_data;
841 	snd_ctl_remap_id_t *rid;
842 	snd_ctl_numid_t *numid;
843 	snd_ctl_map_t *map;
844 	int err;
845 
846 	if (priv->map_read_queue_head != priv->map_read_queue_tail) {
847 		map = priv->map_read_queue[priv->map_read_queue_head];
848 		_next_ptr(&priv->map_read_queue_head, priv->map_items);
849 		memset(event, 0, sizeof(*event));
850 		event->type = SNDRV_CTL_EVENT_ELEM;
851 		event->data.elem.mask = map->event_mask;
852 		event->data.elem.id = map->map_id;
853 		map->event_mask = 0;
854 		debug_id(&map->map_id, "%s queue read\n", __func__);
855 		return 1;
856 	}
857 	err = snd_ctl_read(priv->child, event);
858 	if (err < 0 || event->type != SNDRV_CTL_EVENT_ELEM)
859 		return err;
860 	if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE ||
861 	    (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO |
862 				      SNDRV_CTL_EVENT_MASK_ADD | SNDRV_CTL_EVENT_MASK_TLV)) != 0) {
863 		debug_id(&event->data.elem.id, "%s event mask 0x%x\n", __func__, event->data.elem.mask);
864 		remap_event_for_all_map_controls(priv, &event->data.elem.id, event->data.elem.mask);
865 		rid = remap_find_id_child(priv, &event->data.elem.id);
866 		if (rid) {
867 			if (rid->id_child.numid == 0) {
868 				numid = remap_find_numid_child(priv, event->data.elem.id.numid);
869 				if (numid == NULL)
870 					return -EIO;
871 				rid->id_child.numid = numid->numid_child;
872 				rid->id_app.numid = numid->numid_app;
873 			}
874 			event->data.elem.id = rid->id_app;
875 		} else {
876 			numid = remap_find_numid_child(priv, event->data.elem.id.numid);
877 			if (numid == NULL)
878 				return -EIO;
879 			event->data.elem.id.numid = numid->numid_app;
880 		}
881 	}
882 	return err;
883 }
884 
885 static const snd_ctl_ops_t snd_ctl_remap_ops = {
886 	.close = snd_ctl_remap_close,
887 	.nonblock = snd_ctl_remap_nonblock,
888 	.async = snd_ctl_remap_async,
889 	.subscribe_events = snd_ctl_remap_subscribe_events,
890 	.card_info = snd_ctl_remap_card_info,
891 	.element_list = snd_ctl_remap_elem_list,
892 	.element_info = snd_ctl_remap_elem_info,
893 	.element_read = snd_ctl_remap_elem_read,
894 	.element_write = snd_ctl_remap_elem_write,
895 	.element_lock = snd_ctl_remap_elem_lock,
896 	.element_unlock = snd_ctl_remap_elem_unlock,
897 	.element_tlv = snd_ctl_remap_elem_tlv,
898 	.hwdep_next_device = snd_ctl_remap_hwdep_next_device,
899 	.hwdep_info = snd_ctl_remap_hwdep_info,
900 	.pcm_next_device = snd_ctl_remap_pcm_next_device,
901 	.pcm_info = snd_ctl_remap_pcm_info,
902 	.pcm_prefer_subdevice = snd_ctl_remap_pcm_prefer_subdevice,
903 	.rawmidi_next_device = snd_ctl_remap_rawmidi_next_device,
904 	.rawmidi_info = snd_ctl_remap_rawmidi_info,
905 	.rawmidi_prefer_subdevice = snd_ctl_remap_rawmidi_prefer_subdevice,
906 	.set_power_state = snd_ctl_remap_set_power_state,
907 	.get_power_state = snd_ctl_remap_get_power_state,
908 	.read = snd_ctl_remap_read,
909 };
910 
add_to_remap(snd_ctl_remap_t *priv, snd_ctl_elem_id_t *child, snd_ctl_elem_id_t *app)911 static int add_to_remap(snd_ctl_remap_t *priv,
912 			snd_ctl_elem_id_t *child,
913 			snd_ctl_elem_id_t *app)
914 {
915 	snd_ctl_remap_id_t *rid;
916 
917 	if (priv->remap_alloc == priv->remap_items) {
918 		rid = realloc(priv->remap, (priv->remap_alloc + 16) * sizeof(*rid));
919 		if (rid == NULL)
920 			return -ENOMEM;
921 		memset(rid + priv->remap_alloc, 0, sizeof(*rid) * 16);
922 		priv->remap_alloc += 16;
923 		priv->remap = rid;
924 	}
925 	rid = &priv->remap[priv->remap_items++];
926 	rid->id_child = *child;
927 	rid->id_app = *app;
928 	debug_id(&rid->id_child, "%s remap child\n", __func__);
929 	debug_id(&rid->id_app, "%s remap app\n", __func__);
930 	return 0;
931 }
932 
parse_remap(snd_ctl_remap_t *priv, snd_config_t *conf)933 static int parse_remap(snd_ctl_remap_t *priv, snd_config_t *conf)
934 {
935 	snd_config_iterator_t i, next;
936 	snd_ctl_elem_id_t child, app;
937 	int err;
938 
939 	if (conf == NULL)
940 		return 0;
941 	snd_config_for_each(i, next, conf) {
942 		snd_config_t *n = snd_config_iterator_entry(i);
943 		const char *id, *str;
944 		if (snd_config_get_id(n, &id) < 0)
945 			continue;
946 		if (snd_config_get_string(n, &str) < 0) {
947 			SNDERR("expected string with the target control id!");
948 			return -EINVAL;
949 		}
950 		snd_ctl_elem_id_clear(&app);
951 		err = snd_ctl_ascii_elem_id_parse(&app, str);
952 		if (err < 0) {
953 			SNDERR("unable to parse target id '%s'!", str);
954 			return -EINVAL;
955 		}
956 		if (remap_find_id_app(priv, &app)) {
957 			SNDERR("duplicate target id '%s'!", id);
958 			return -EINVAL;
959 		}
960 		snd_ctl_elem_id_clear(&child);
961 		err = snd_ctl_ascii_elem_id_parse(&child, id);
962 		if (err < 0) {
963 			SNDERR("unable to parse source id '%s'!", id);
964 			return -EINVAL;
965 		}
966 		if (remap_find_id_child(priv, &app)) {
967 			SNDERR("duplicate source id '%s'!", id);
968 			return -EINVAL;
969 		}
970 		err = add_to_remap(priv, &child, &app);
971 		if (err < 0)
972 			return err;
973 	}
974 
975 	return 0;
976 }
977 
new_map(snd_ctl_remap_t *priv, snd_ctl_map_t **_map, snd_ctl_elem_id_t *id)978 static int new_map(snd_ctl_remap_t *priv, snd_ctl_map_t **_map, snd_ctl_elem_id_t *id)
979 {
980 	snd_ctl_map_t *map;
981 	snd_ctl_numid_t *numid;
982 
983 	if (priv->map_alloc == priv->map_items) {
984 		map = realloc(priv->map, (priv->map_alloc + 16) * sizeof(*map));
985 		if (map == NULL)
986 			return -ENOMEM;
987 		memset(map + priv->map_alloc, 0, sizeof(*map) * 16);
988 		priv->map_alloc += 16;
989 		priv->map = map;
990 	}
991 	map = &priv->map[priv->map_items++];
992 	map->map_id = *id;
993 	numid = remap_numid_new(priv, 0, ++priv->numid_app_last);
994 	if (numid == NULL)
995 		return -ENOMEM;
996 	map->map_id.numid = numid->numid_app;
997 	debug_id(&map->map_id, "%s created\n", __func__);
998 	*_map = map;
999 	return 0;
1000 }
1001 
add_ctl_to_map(snd_ctl_map_t *map, struct snd_ctl_map_ctl **_mctl, snd_ctl_elem_id_t *id)1002 static int add_ctl_to_map(snd_ctl_map_t *map, struct snd_ctl_map_ctl **_mctl, snd_ctl_elem_id_t *id)
1003 {
1004 	struct snd_ctl_map_ctl *mctl;
1005 
1006 	if (map->controls_alloc == map->controls_items) {
1007 		mctl = realloc(map->controls, (map->controls_alloc + 4) * sizeof(*mctl));
1008 		if (mctl == NULL)
1009 			return -ENOMEM;
1010 		memset(mctl + map->controls_alloc, 0, sizeof(*mctl) * 4);
1011 		map->controls_alloc += 4;
1012 		map->controls = mctl;
1013 	}
1014 	mctl = &map->controls[map->controls_items++];
1015 	mctl->id_child = *id;
1016 	*_mctl = mctl;
1017 	return 0;
1018 }
1019 
add_chn_to_map(struct snd_ctl_map_ctl *mctl, long idx, long val)1020 static int add_chn_to_map(struct snd_ctl_map_ctl *mctl, long idx, long val)
1021 {
1022 	size_t off;
1023 	long *map;
1024 
1025 	if (mctl->channel_map_alloc <= (size_t)idx) {
1026 		map = realloc(mctl->channel_map, (idx + 4) * sizeof(*map));
1027 		if (map == NULL)
1028 			return -ENOMEM;
1029 		mctl->channel_map = map;
1030 		off = mctl->channel_map_alloc;
1031 		mctl->channel_map_alloc = idx + 4;
1032 		for ( ; off < mctl->channel_map_alloc; off++)
1033 			map[off] = -1;
1034 	}
1035 	if ((size_t)idx >= mctl->channel_map_items)
1036 		mctl->channel_map_items = idx + 1;
1037 	mctl->channel_map[idx] = val;
1038 	return 0;
1039 }
1040 
parse_map_vindex(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)1041 static int parse_map_vindex(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)
1042 {
1043 	snd_config_iterator_t i, next;
1044 	int err;
1045 
1046 	snd_config_for_each(i, next, conf) {
1047 		snd_config_t *n = snd_config_iterator_entry(i);
1048 		long idx = -1, chn = -1;
1049 		const char *id;
1050 		if (snd_config_get_id(n, &id) < 0)
1051 			continue;
1052 		if (safe_strtol(id, &idx) || snd_config_get_integer(n, &chn)) {
1053 			SNDERR("Wrong channel mapping (%ld -> %ld)", idx, chn);
1054 			return -EINVAL;
1055 		}
1056 		err = add_chn_to_map(mctl, idx, chn);
1057 		if (err < 0)
1058 			return err;
1059 	}
1060 
1061 	return 0;
1062 }
1063 
parse_map_config(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)1064 static int parse_map_config(struct snd_ctl_map_ctl *mctl, snd_config_t *conf)
1065 {
1066 	snd_config_iterator_t i, next;
1067 	int err;
1068 
1069 	snd_config_for_each(i, next, conf) {
1070 		snd_config_t *n = snd_config_iterator_entry(i);
1071 		const char *id;
1072 		if (snd_config_get_id(n, &id) < 0)
1073 			continue;
1074 		if (strcmp(id, "vindex") == 0) {
1075 			err = parse_map_vindex(mctl, n);
1076 			if (err < 0)
1077 				return err;
1078 		}
1079 	}
1080 	return 0;
1081 }
1082 
parse_map1(snd_ctl_map_t *map, snd_config_t *conf)1083 static int parse_map1(snd_ctl_map_t *map, snd_config_t *conf)
1084 {
1085 	snd_config_iterator_t i, next;
1086 	snd_ctl_elem_id_t cid;
1087 	struct snd_ctl_map_ctl *mctl;
1088 	int err;
1089 
1090 	snd_config_for_each(i, next, conf) {
1091 		snd_config_t *n = snd_config_iterator_entry(i);
1092 		const char *id;
1093 		if (snd_config_get_id(n, &id) < 0)
1094 			continue;
1095 		snd_ctl_elem_id_clear(&cid);
1096 		err = snd_ctl_ascii_elem_id_parse(&cid, id);
1097 		if (err < 0) {
1098 			SNDERR("unable to parse control id '%s'!", id);
1099 			return -EINVAL;
1100 		}
1101 		err = add_ctl_to_map(map, &mctl, &cid);
1102 		if (err < 0)
1103 			return err;
1104 		err = parse_map_config(mctl, n);
1105 		if (err < 0)
1106 			return err;
1107 	}
1108 
1109 	return 0;
1110 }
1111 
parse_map(snd_ctl_remap_t *priv, snd_config_t *conf)1112 static int parse_map(snd_ctl_remap_t *priv, snd_config_t *conf)
1113 {
1114 	snd_config_iterator_t i, next;
1115 	snd_ctl_elem_id_t eid;
1116 	snd_ctl_map_t *map;
1117 	int err;
1118 
1119 	if (conf == NULL)
1120 		return 0;
1121 	snd_config_for_each(i, next, conf) {
1122 		snd_config_t *n = snd_config_iterator_entry(i);
1123 		const char *id;
1124 		if (snd_config_get_id(n, &id) < 0)
1125 			continue;
1126 		snd_ctl_elem_id_clear(&eid);
1127 		err = snd_ctl_ascii_elem_id_parse(&eid, id);
1128 		if (err < 0) {
1129 			SNDERR("unable to parse id '%s'!", id);
1130 			return -EINVAL;
1131 		}
1132 		err = new_map(priv, &map, &eid);
1133 		if (err < 0)
1134 			return 0;
1135 		err = parse_map1(map, n);
1136 		if (err < 0)
1137 			return err;
1138 	}
1139 
1140 	return 0;
1141 }
1142 
1143 /**
1144  * \brief Creates a new remap & map control handle
1145  * \param handlep Returns created control handle
1146  * \param name Name of control device
1147  * \param remap Remap configuration
1148  * \param map Map configuration
1149  * \param child child configuration root
1150  * \param mode Control handle mode
1151  * \retval zero on success otherwise a negative error code
1152  * \warning Using of this function might be dangerous in the sense
1153  *          of compatibility reasons. The prototype might be freely
1154  *          changed in future.
1155  */
snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *remap, snd_config_t *map, snd_ctl_t *child, int mode)1156 int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *remap,
1157 		       snd_config_t *map, snd_ctl_t *child, int mode)
1158 {
1159 	snd_ctl_remap_t *priv;
1160 	snd_ctl_t *ctl;
1161 	int result, err;
1162 
1163 	/* no-op, remove the plugin */
1164 	if (!remap && !map)
1165 		goto _noop;
1166 
1167 	priv = calloc(1, sizeof(*priv));
1168 	if (priv == NULL)
1169 		return -ENOMEM;
1170 
1171 	err = parse_remap(priv, remap);
1172 	if (err < 0) {
1173 		result = err;
1174 		goto _err;
1175 	}
1176 
1177 	err = parse_map(priv, map);
1178 	if (err < 0) {
1179 		result = err;
1180 		goto _err;
1181 	}
1182 
1183 	/* no-op check, remove the plugin */
1184 	if (priv->map_items == 0 && priv->remap_items == 0) {
1185 		remap_free(priv);
1186  _noop:
1187 		free(child->name);
1188 		child->name = name ? strdup(name) : NULL;
1189 		if (name && !child->name)
1190 			return -ENOMEM;
1191 		*handlep = child;
1192 		return 0;
1193 	}
1194 
1195 	priv->map_read_queue = calloc(priv->map_items, sizeof(priv->map_read_queue[0]));
1196 	if (priv->map_read_queue == NULL) {
1197 		result = -ENOMEM;
1198 		goto _err;
1199 	}
1200 
1201 	priv->numid_remap_active = priv->map_items > 0;
1202 
1203 	priv->child = child;
1204 	err = snd_ctl_new(&ctl, SND_CTL_TYPE_REMAP, name, mode);
1205 	if (err < 0) {
1206 		result = err;
1207 		goto _err;
1208 	}
1209 	ctl->ops = &snd_ctl_remap_ops;
1210 	ctl->private_data = priv;
1211 	ctl->poll_fd = child->poll_fd;
1212 
1213 	*handlep = ctl;
1214 	return 0;
1215 
1216  _err:
1217 	remap_free(priv);
1218 	return result;
1219 }
1220 
1221 /*! \page control_plugins
1222 
1223 \section control_plugins_remap Plugin: Remap & map
1224 
1225 This plugin can remap (rename) identifiers (except the numid part) for
1226 a child control to another. The plugin can also merge the multiple
1227 child controls to one or split one control to more.
1228 
1229 \code
1230 ctl.name {
1231 	type remap              # Route & Volume conversion PCM
1232 	child STR               # Slave name
1233 	# or
1234 	child {                 # Slave definition
1235 		type STR
1236 		...
1237 	}
1238 	remap {
1239 		# the ID strings are parsed in the amixer style like 'name="Headphone Playback Switch",index=2'
1240 		SRC_ID1_STR DST_ID1_STR
1241 		SRC_ID2_STR DST_ID2_STR
1242 		...
1243 	}
1244 	map {
1245 		# join two stereo controls to one
1246 		CREATE_ID1_STR {
1247 			SRC_ID1_STR {
1248 				vindex.0 0	# source channel 0 to merged channel 0
1249 				vindex.1 1
1250 			}
1251 			SRC_ID2_STR {
1252 				vindex.2 0
1253 				vindex.3 1	# source channel 1 to merged channel 3
1254 			}
1255 		}
1256 		# split stereo to mono
1257 		CREATE_ID2_STR {
1258 			SRC_ID3_STR {
1259 				vindex.0 0	# stereo to mono (first channel)
1260 			}
1261 		}
1262 		CREATE_ID3_STR {
1263 			SRC_ID4_STR {
1264 				vindex.0 1	# stereo to mono (second channel)
1265 			}
1266 		}
1267 	}
1268 }
1269 \endcode
1270 
1271 \subsection control_plugins_route_funcref Function reference
1272 
1273 <UL>
1274   <LI>snd_ctl_remap_open()
1275   <LI>_snd_ctl_remap_open()
1276 </UL>
1277 
1278 */
1279 
1280 /**
1281  * \brief Creates a new remap & map control plugin
1282  * \param handlep Returns created control handle
1283  * \param name Name of control
1284  * \param root Root configuration node
1285  * \param conf Configuration node with Route & Volume PCM description
1286  * \param mode Control handle mode
1287  * \retval zero on success otherwise a negative error code
1288  * \warning Using of this function might be dangerous in the sense
1289  *          of compatibility reasons. The prototype might be freely
1290  *          changed in future.
1291  */
_snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_config_t *conf, int mode)1292 int _snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_config_t *conf, int mode)
1293 {
1294 	snd_config_iterator_t i, next;
1295 	snd_config_t *child = NULL;
1296 	snd_config_t *remap = NULL;
1297 	snd_config_t *map = NULL;
1298 	snd_ctl_t *cctl;
1299 	int err;
1300 
1301 	snd_config_for_each(i, next, conf) {
1302 		snd_config_t *n = snd_config_iterator_entry(i);
1303 		const char *id;
1304 		if (snd_config_get_id(n, &id) < 0)
1305 			continue;
1306 		if (_snd_conf_generic_id(id))
1307 			continue;
1308 		if (strcmp(id, "remap") == 0) {
1309 			remap = n;
1310 			continue;
1311 		}
1312 		if (strcmp(id, "map") == 0) {
1313 			map = n;
1314 			continue;
1315 		}
1316 		if (strcmp(id, "child") == 0) {
1317 			child = n;
1318 			continue;
1319 		}
1320 		SNDERR("Unknown field %s", id);
1321 		return -EINVAL;
1322 	}
1323 	if (!child) {
1324 		SNDERR("child is not defined");
1325 		return -EINVAL;
1326 	}
1327 	err = _snd_ctl_open_child(&cctl, root, child, mode, conf);
1328 	if (err < 0)
1329 		return err;
1330 	err = snd_ctl_remap_open(handlep, name, remap, map, cctl, mode);
1331 	if (err < 0)
1332 		snd_ctl_close(cctl);
1333 	return err;
1334 }
1335 #ifndef DOC_HIDDEN
1336 SND_DLSYM_BUILD_VERSION(_snd_ctl_remap_open, SND_CONTROL_DLSYM_VERSION);
1337 #endif
1338