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