1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file control/control_ext.c 3d5ac70f0Sopenharmony_ci * \ingroup CtlPlugin_SDK 4d5ac70f0Sopenharmony_ci * \brief External Control Plugin SDK 5d5ac70f0Sopenharmony_ci * \author Takashi Iwai <tiwai@suse.de> 6d5ac70f0Sopenharmony_ci * \date 2005 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * Control Interface - External Control Plugin SDK 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * 14d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 15d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 16d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 17d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 20d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 21d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 25d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 26d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27d5ac70f0Sopenharmony_ci * 28d5ac70f0Sopenharmony_ci */ 29d5ac70f0Sopenharmony_ci 30d5ac70f0Sopenharmony_ci#include "control_local.h" 31d5ac70f0Sopenharmony_ci#include "control_external.h" 32d5ac70f0Sopenharmony_ci#include <stdio.h> 33d5ac70f0Sopenharmony_ci#include <stdlib.h> 34d5ac70f0Sopenharmony_ci#include <unistd.h> 35d5ac70f0Sopenharmony_ci#include <string.h> 36d5ac70f0Sopenharmony_ci 37d5ac70f0Sopenharmony_ci#ifndef PIC 38d5ac70f0Sopenharmony_ci/* entry for static linking */ 39d5ac70f0Sopenharmony_ciconst char *_snd_module_control_ext = ""; 40d5ac70f0Sopenharmony_ci#endif 41d5ac70f0Sopenharmony_ci 42d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_close(snd_ctl_t *handle) 43d5ac70f0Sopenharmony_ci{ 44d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 45d5ac70f0Sopenharmony_ci 46d5ac70f0Sopenharmony_ci if (ext->callback->close) 47d5ac70f0Sopenharmony_ci ext->callback->close(ext); 48d5ac70f0Sopenharmony_ci return 0; 49d5ac70f0Sopenharmony_ci} 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_nonblock(snd_ctl_t *handle, int nonblock) 52d5ac70f0Sopenharmony_ci{ 53d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_ci ext->nonblock = nonblock; 56d5ac70f0Sopenharmony_ci return 0; 57d5ac70f0Sopenharmony_ci} 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_async(snd_ctl_t *ctl ATTRIBUTE_UNUSED, 60d5ac70f0Sopenharmony_ci int sig ATTRIBUTE_UNUSED, 61d5ac70f0Sopenharmony_ci pid_t pid ATTRIBUTE_UNUSED) 62d5ac70f0Sopenharmony_ci{ 63d5ac70f0Sopenharmony_ci return -ENOSYS; 64d5ac70f0Sopenharmony_ci} 65d5ac70f0Sopenharmony_ci 66d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_subscribe_events(snd_ctl_t *handle, int subscribe) 67d5ac70f0Sopenharmony_ci{ 68d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 69d5ac70f0Sopenharmony_ci 70d5ac70f0Sopenharmony_ci if (subscribe < 0) 71d5ac70f0Sopenharmony_ci return ext->subscribed; 72d5ac70f0Sopenharmony_ci ext->subscribed = !!subscribe; 73d5ac70f0Sopenharmony_ci if (ext->callback->subscribe_events) 74d5ac70f0Sopenharmony_ci ext->callback->subscribe_events(ext, subscribe); 75d5ac70f0Sopenharmony_ci return 0; 76d5ac70f0Sopenharmony_ci} 77d5ac70f0Sopenharmony_ci 78d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info) 79d5ac70f0Sopenharmony_ci{ 80d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 81d5ac70f0Sopenharmony_ci 82d5ac70f0Sopenharmony_ci memset(info, 0, sizeof(*info)); 83d5ac70f0Sopenharmony_ci info->card = ext->card_idx; 84d5ac70f0Sopenharmony_ci memcpy(info->id, ext->id, sizeof(info->id)); 85d5ac70f0Sopenharmony_ci memcpy(info->driver, ext->driver, sizeof(info->driver)); 86d5ac70f0Sopenharmony_ci memcpy(info->name, ext->name, sizeof(info->name)); 87d5ac70f0Sopenharmony_ci memcpy(info->longname, ext->longname, sizeof(info->longname)); 88d5ac70f0Sopenharmony_ci memcpy(info->mixername, ext->mixername, sizeof(info->mixername)); 89d5ac70f0Sopenharmony_ci return 0; 90d5ac70f0Sopenharmony_ci} 91d5ac70f0Sopenharmony_ci 92d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) 93d5ac70f0Sopenharmony_ci{ 94d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 95d5ac70f0Sopenharmony_ci int ret; 96d5ac70f0Sopenharmony_ci unsigned int i, offset; 97d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t *ids; 98d5ac70f0Sopenharmony_ci 99d5ac70f0Sopenharmony_ci list->count = ext->callback->elem_count(ext); 100d5ac70f0Sopenharmony_ci list->used = 0; 101d5ac70f0Sopenharmony_ci ids = list->pids; 102d5ac70f0Sopenharmony_ci offset = list->offset; 103d5ac70f0Sopenharmony_ci for (i = 0; i < list->space; i++) { 104d5ac70f0Sopenharmony_ci if (offset >= list->count) 105d5ac70f0Sopenharmony_ci break; 106d5ac70f0Sopenharmony_ci snd_ctl_elem_id_clear(ids); 107d5ac70f0Sopenharmony_ci ret = ext->callback->elem_list(ext, offset, ids); 108d5ac70f0Sopenharmony_ci if (ret < 0) 109d5ac70f0Sopenharmony_ci return ret; 110d5ac70f0Sopenharmony_ci ids->numid = offset + 1; /* fake number */ 111d5ac70f0Sopenharmony_ci list->used++; 112d5ac70f0Sopenharmony_ci offset++; 113d5ac70f0Sopenharmony_ci ids++; 114d5ac70f0Sopenharmony_ci } 115d5ac70f0Sopenharmony_ci return 0; 116d5ac70f0Sopenharmony_ci} 117d5ac70f0Sopenharmony_ci 118d5ac70f0Sopenharmony_cistatic snd_ctl_ext_key_t get_elem(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id) 119d5ac70f0Sopenharmony_ci{ 120d5ac70f0Sopenharmony_ci int numid = id->numid; 121d5ac70f0Sopenharmony_ci if (numid > 0) { 122d5ac70f0Sopenharmony_ci ext->callback->elem_list(ext, numid - 1, id); 123d5ac70f0Sopenharmony_ci id->numid = numid; 124d5ac70f0Sopenharmony_ci } else 125d5ac70f0Sopenharmony_ci id->numid = 0; 126d5ac70f0Sopenharmony_ci return ext->callback->find_elem(ext, id); 127d5ac70f0Sopenharmony_ci} 128d5ac70f0Sopenharmony_ci 129d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info) 130d5ac70f0Sopenharmony_ci{ 131d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 132d5ac70f0Sopenharmony_ci snd_ctl_ext_key_t key; 133d5ac70f0Sopenharmony_ci int type, ret; 134d5ac70f0Sopenharmony_ci 135d5ac70f0Sopenharmony_ci key = get_elem(ext, &info->id); 136d5ac70f0Sopenharmony_ci if (key == SND_CTL_EXT_KEY_NOT_FOUND) 137d5ac70f0Sopenharmony_ci return -ENOENT; 138d5ac70f0Sopenharmony_ci ret = ext->callback->get_attribute(ext, key, &type, &info->access, &info->count); 139d5ac70f0Sopenharmony_ci if (ret < 0) 140d5ac70f0Sopenharmony_ci goto err; 141d5ac70f0Sopenharmony_ci info->type = type; 142d5ac70f0Sopenharmony_ci ret = -EINVAL; 143d5ac70f0Sopenharmony_ci switch (info->type) { 144d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 145d5ac70f0Sopenharmony_ci info->value.integer.min = 0; 146d5ac70f0Sopenharmony_ci info->value.integer.max = 1; 147d5ac70f0Sopenharmony_ci ret = 0; 148d5ac70f0Sopenharmony_ci break; 149d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 150d5ac70f0Sopenharmony_ci if (! ext->callback->get_integer_info) 151d5ac70f0Sopenharmony_ci goto err; 152d5ac70f0Sopenharmony_ci ret = ext->callback->get_integer_info(ext, key, &info->value.integer.min, 153d5ac70f0Sopenharmony_ci &info->value.integer.max, 154d5ac70f0Sopenharmony_ci &info->value.integer.step); 155d5ac70f0Sopenharmony_ci break; 156d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 157d5ac70f0Sopenharmony_ci if (! ext->callback->get_integer64_info) 158d5ac70f0Sopenharmony_ci goto err; 159d5ac70f0Sopenharmony_ci { 160d5ac70f0Sopenharmony_ci int64_t xmin, xmax, xstep; 161d5ac70f0Sopenharmony_ci ret = ext->callback->get_integer64_info(ext, key, 162d5ac70f0Sopenharmony_ci &xmin, 163d5ac70f0Sopenharmony_ci &xmax, 164d5ac70f0Sopenharmony_ci &xstep); 165d5ac70f0Sopenharmony_ci info->value.integer64.min = xmin; 166d5ac70f0Sopenharmony_ci info->value.integer64.max = xmax; 167d5ac70f0Sopenharmony_ci info->value.integer64.step = xstep; 168d5ac70f0Sopenharmony_ci } 169d5ac70f0Sopenharmony_ci break; 170d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 171d5ac70f0Sopenharmony_ci if (! ext->callback->get_enumerated_info) 172d5ac70f0Sopenharmony_ci goto err; 173d5ac70f0Sopenharmony_ci ret = ext->callback->get_enumerated_info(ext, key, &info->value.enumerated.items); 174d5ac70f0Sopenharmony_ci ext->callback->get_enumerated_name(ext, key, info->value.enumerated.item, 175d5ac70f0Sopenharmony_ci info->value.enumerated.name, 176d5ac70f0Sopenharmony_ci sizeof(info->value.enumerated.name)); 177d5ac70f0Sopenharmony_ci break; 178d5ac70f0Sopenharmony_ci default: 179d5ac70f0Sopenharmony_ci ret = 0; 180d5ac70f0Sopenharmony_ci break; 181d5ac70f0Sopenharmony_ci } 182d5ac70f0Sopenharmony_ci 183d5ac70f0Sopenharmony_ci err: 184d5ac70f0Sopenharmony_ci if (ext->callback->free_key) 185d5ac70f0Sopenharmony_ci ext->callback->free_key(ext, key); 186d5ac70f0Sopenharmony_ci 187d5ac70f0Sopenharmony_ci return ret; 188d5ac70f0Sopenharmony_ci} 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_add(snd_ctl_t *handle ATTRIBUTE_UNUSED, 191d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) 192d5ac70f0Sopenharmony_ci{ 193d5ac70f0Sopenharmony_ci return -ENXIO; 194d5ac70f0Sopenharmony_ci} 195d5ac70f0Sopenharmony_ci 196d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_replace(snd_ctl_t *handle ATTRIBUTE_UNUSED, 197d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) 198d5ac70f0Sopenharmony_ci{ 199d5ac70f0Sopenharmony_ci return -ENXIO; 200d5ac70f0Sopenharmony_ci} 201d5ac70f0Sopenharmony_ci 202d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_remove(snd_ctl_t *handle ATTRIBUTE_UNUSED, 203d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) 204d5ac70f0Sopenharmony_ci{ 205d5ac70f0Sopenharmony_ci return -ENXIO; 206d5ac70f0Sopenharmony_ci} 207d5ac70f0Sopenharmony_ci 208d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control) 209d5ac70f0Sopenharmony_ci{ 210d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 211d5ac70f0Sopenharmony_ci snd_ctl_ext_key_t key; 212d5ac70f0Sopenharmony_ci int type, ret; 213d5ac70f0Sopenharmony_ci unsigned int access, count; 214d5ac70f0Sopenharmony_ci 215d5ac70f0Sopenharmony_ci key = get_elem(ext, &control->id); 216d5ac70f0Sopenharmony_ci if (key == SND_CTL_EXT_KEY_NOT_FOUND) 217d5ac70f0Sopenharmony_ci return -ENOENT; 218d5ac70f0Sopenharmony_ci ret = ext->callback->get_attribute(ext, key, &type, &access, &count); 219d5ac70f0Sopenharmony_ci if (ret < 0) 220d5ac70f0Sopenharmony_ci goto err; 221d5ac70f0Sopenharmony_ci ret = -EINVAL; 222d5ac70f0Sopenharmony_ci switch (type) { 223d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 224d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 225d5ac70f0Sopenharmony_ci if (! ext->callback->read_integer) 226d5ac70f0Sopenharmony_ci goto err; 227d5ac70f0Sopenharmony_ci ret = ext->callback->read_integer(ext, key, control->value.integer.value); 228d5ac70f0Sopenharmony_ci break; 229d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 230d5ac70f0Sopenharmony_ci if (! ext->callback->read_integer64) 231d5ac70f0Sopenharmony_ci goto err; 232d5ac70f0Sopenharmony_ci ret = ext->callback->read_integer64(ext, key, 233d5ac70f0Sopenharmony_ci (int64_t*)control->value.integer64.value); 234d5ac70f0Sopenharmony_ci break; 235d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 236d5ac70f0Sopenharmony_ci if (! ext->callback->read_enumerated) 237d5ac70f0Sopenharmony_ci goto err; 238d5ac70f0Sopenharmony_ci ret = ext->callback->read_enumerated(ext, key, control->value.enumerated.item); 239d5ac70f0Sopenharmony_ci break; 240d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 241d5ac70f0Sopenharmony_ci if (! ext->callback->read_bytes) 242d5ac70f0Sopenharmony_ci goto err; 243d5ac70f0Sopenharmony_ci ret = ext->callback->read_bytes(ext, key, control->value.bytes.data, 244d5ac70f0Sopenharmony_ci sizeof(control->value.bytes.data)); 245d5ac70f0Sopenharmony_ci break; 246d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_IEC958: 247d5ac70f0Sopenharmony_ci if (! ext->callback->read_iec958) 248d5ac70f0Sopenharmony_ci goto err; 249d5ac70f0Sopenharmony_ci ret = ext->callback->read_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); 250d5ac70f0Sopenharmony_ci break; 251d5ac70f0Sopenharmony_ci default: 252d5ac70f0Sopenharmony_ci break; 253d5ac70f0Sopenharmony_ci } 254d5ac70f0Sopenharmony_ci 255d5ac70f0Sopenharmony_ci err: 256d5ac70f0Sopenharmony_ci if (ext->callback->free_key) 257d5ac70f0Sopenharmony_ci ext->callback->free_key(ext, key); 258d5ac70f0Sopenharmony_ci 259d5ac70f0Sopenharmony_ci return ret; 260d5ac70f0Sopenharmony_ci} 261d5ac70f0Sopenharmony_ci 262d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control) 263d5ac70f0Sopenharmony_ci{ 264d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 265d5ac70f0Sopenharmony_ci snd_ctl_ext_key_t key; 266d5ac70f0Sopenharmony_ci int type, ret; 267d5ac70f0Sopenharmony_ci unsigned int access, count; 268d5ac70f0Sopenharmony_ci 269d5ac70f0Sopenharmony_ci key = get_elem(ext, &control->id); 270d5ac70f0Sopenharmony_ci if (key == SND_CTL_EXT_KEY_NOT_FOUND) 271d5ac70f0Sopenharmony_ci return -ENOENT; 272d5ac70f0Sopenharmony_ci ret = ext->callback->get_attribute(ext, key, &type, &access, &count); 273d5ac70f0Sopenharmony_ci if (ret < 0) 274d5ac70f0Sopenharmony_ci goto err; 275d5ac70f0Sopenharmony_ci ret = -EINVAL; 276d5ac70f0Sopenharmony_ci switch (type) { 277d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 278d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 279d5ac70f0Sopenharmony_ci if (! ext->callback->write_integer) 280d5ac70f0Sopenharmony_ci goto err; 281d5ac70f0Sopenharmony_ci ret = ext->callback->write_integer(ext, key, control->value.integer.value); 282d5ac70f0Sopenharmony_ci break; 283d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 284d5ac70f0Sopenharmony_ci if (! ext->callback->write_integer64) 285d5ac70f0Sopenharmony_ci goto err; 286d5ac70f0Sopenharmony_ci ret = ext->callback->write_integer64(ext, key, (int64_t *)control->value.integer64.value); 287d5ac70f0Sopenharmony_ci break; 288d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 289d5ac70f0Sopenharmony_ci if (! ext->callback->write_enumerated) 290d5ac70f0Sopenharmony_ci goto err; 291d5ac70f0Sopenharmony_ci ret = ext->callback->write_enumerated(ext, key, control->value.enumerated.item); 292d5ac70f0Sopenharmony_ci break; 293d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 294d5ac70f0Sopenharmony_ci if (! ext->callback->write_bytes) 295d5ac70f0Sopenharmony_ci goto err; 296d5ac70f0Sopenharmony_ci ret = ext->callback->write_bytes(ext, key, control->value.bytes.data, 297d5ac70f0Sopenharmony_ci sizeof(control->value.bytes.data)); 298d5ac70f0Sopenharmony_ci break; 299d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_IEC958: 300d5ac70f0Sopenharmony_ci if (! ext->callback->write_iec958) 301d5ac70f0Sopenharmony_ci goto err; 302d5ac70f0Sopenharmony_ci ret = ext->callback->write_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); 303d5ac70f0Sopenharmony_ci break; 304d5ac70f0Sopenharmony_ci default: 305d5ac70f0Sopenharmony_ci break; 306d5ac70f0Sopenharmony_ci } 307d5ac70f0Sopenharmony_ci 308d5ac70f0Sopenharmony_ci err: 309d5ac70f0Sopenharmony_ci if (ext->callback->free_key) 310d5ac70f0Sopenharmony_ci ext->callback->free_key(ext, key); 311d5ac70f0Sopenharmony_ci 312d5ac70f0Sopenharmony_ci return ret; 313d5ac70f0Sopenharmony_ci} 314d5ac70f0Sopenharmony_ci 315d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_lock(snd_ctl_t *handle ATTRIBUTE_UNUSED, 316d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) 317d5ac70f0Sopenharmony_ci{ 318d5ac70f0Sopenharmony_ci return -ENXIO; 319d5ac70f0Sopenharmony_ci} 320d5ac70f0Sopenharmony_ci 321d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED, 322d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) 323d5ac70f0Sopenharmony_ci{ 324d5ac70f0Sopenharmony_ci return -ENXIO; 325d5ac70f0Sopenharmony_ci} 326d5ac70f0Sopenharmony_ci 327d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_tlv(snd_ctl_t *handle, int op_flag, 328d5ac70f0Sopenharmony_ci unsigned int numid, 329d5ac70f0Sopenharmony_ci unsigned int *tlv, unsigned int tlv_size) 330d5ac70f0Sopenharmony_ci{ 331d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 332d5ac70f0Sopenharmony_ci snd_ctl_ext_key_t key; 333d5ac70f0Sopenharmony_ci int type, ret; 334d5ac70f0Sopenharmony_ci unsigned int access, count, len; 335d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t id; 336d5ac70f0Sopenharmony_ci 337d5ac70f0Sopenharmony_ci /* we don't support TLV on protocol ver 1.0.0 or earlier */ 338d5ac70f0Sopenharmony_ci if (ext->version <= SNDRV_PROTOCOL_VERSION(1, 0, 0)) 339d5ac70f0Sopenharmony_ci return -ENXIO; 340d5ac70f0Sopenharmony_ci 341d5ac70f0Sopenharmony_ci snd_ctl_elem_id_clear(&id); 342d5ac70f0Sopenharmony_ci if (numid > 0) { 343d5ac70f0Sopenharmony_ci ext->callback->elem_list(ext, numid - 1, &id); 344d5ac70f0Sopenharmony_ci id.numid = numid; 345d5ac70f0Sopenharmony_ci } else 346d5ac70f0Sopenharmony_ci id.numid = 0; 347d5ac70f0Sopenharmony_ci key = ext->callback->find_elem(ext, &id); 348d5ac70f0Sopenharmony_ci 349d5ac70f0Sopenharmony_ci if (key == SND_CTL_EXT_KEY_NOT_FOUND) 350d5ac70f0Sopenharmony_ci return -ENOENT; 351d5ac70f0Sopenharmony_ci ret = ext->callback->get_attribute(ext, key, &type, &access, &count); 352d5ac70f0Sopenharmony_ci if (ret < 0) 353d5ac70f0Sopenharmony_ci return ret; 354d5ac70f0Sopenharmony_ci 355d5ac70f0Sopenharmony_ci if ((op_flag == 0 && (access & SND_CTL_EXT_ACCESS_TLV_READ) == 0) || 356d5ac70f0Sopenharmony_ci (op_flag > 0 && (access & SND_CTL_EXT_ACCESS_TLV_WRITE) == 0) || 357d5ac70f0Sopenharmony_ci (op_flag < 0 && (access & SND_CTL_EXT_ACCESS_TLV_COMMAND) == 0)) 358d5ac70f0Sopenharmony_ci return -ENXIO; 359d5ac70f0Sopenharmony_ci if (access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 360d5ac70f0Sopenharmony_ci return ext->tlv.c(ext, key, op_flag, numid, tlv, tlv_size); 361d5ac70f0Sopenharmony_ci } else { 362d5ac70f0Sopenharmony_ci if (op_flag) 363d5ac70f0Sopenharmony_ci return -ENXIO; 364d5ac70f0Sopenharmony_ci len = ext->tlv.p[1] + 2 * sizeof(unsigned int); 365d5ac70f0Sopenharmony_ci if (tlv_size < len) 366d5ac70f0Sopenharmony_ci return -ENOMEM; 367d5ac70f0Sopenharmony_ci memcpy(tlv, ext->tlv.p, len); 368d5ac70f0Sopenharmony_ci return 0; 369d5ac70f0Sopenharmony_ci } 370d5ac70f0Sopenharmony_ci} 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED, 373d5ac70f0Sopenharmony_ci int *device ATTRIBUTE_UNUSED) 374d5ac70f0Sopenharmony_ci{ 375d5ac70f0Sopenharmony_ci return -ENXIO; 376d5ac70f0Sopenharmony_ci} 377d5ac70f0Sopenharmony_ci 378d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_prefer_subdevice(snd_ctl_t *handle ATTRIBUTE_UNUSED, 379d5ac70f0Sopenharmony_ci int subdev ATTRIBUTE_UNUSED) 380d5ac70f0Sopenharmony_ci{ 381d5ac70f0Sopenharmony_ci return -ENXIO; 382d5ac70f0Sopenharmony_ci} 383d5ac70f0Sopenharmony_ci 384d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_hwdep_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, 385d5ac70f0Sopenharmony_ci snd_hwdep_info_t *info ATTRIBUTE_UNUSED) 386d5ac70f0Sopenharmony_ci{ 387d5ac70f0Sopenharmony_ci return -ENXIO; 388d5ac70f0Sopenharmony_ci} 389d5ac70f0Sopenharmony_ci 390d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_pcm_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, 391d5ac70f0Sopenharmony_ci snd_pcm_info_t *info ATTRIBUTE_UNUSED) 392d5ac70f0Sopenharmony_ci{ 393d5ac70f0Sopenharmony_ci return -ENXIO; 394d5ac70f0Sopenharmony_ci} 395d5ac70f0Sopenharmony_ci 396d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_rawmidi_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, 397d5ac70f0Sopenharmony_ci snd_rawmidi_info_t *info ATTRIBUTE_UNUSED) 398d5ac70f0Sopenharmony_ci{ 399d5ac70f0Sopenharmony_ci return -ENXIO; 400d5ac70f0Sopenharmony_ci} 401d5ac70f0Sopenharmony_ci 402d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_set_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, 403d5ac70f0Sopenharmony_ci unsigned int state ATTRIBUTE_UNUSED) 404d5ac70f0Sopenharmony_ci{ 405d5ac70f0Sopenharmony_ci return 0; 406d5ac70f0Sopenharmony_ci} 407d5ac70f0Sopenharmony_ci 408d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_get_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, 409d5ac70f0Sopenharmony_ci unsigned int *state ATTRIBUTE_UNUSED) 410d5ac70f0Sopenharmony_ci{ 411d5ac70f0Sopenharmony_ci return 0; 412d5ac70f0Sopenharmony_ci} 413d5ac70f0Sopenharmony_ci 414d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event) 415d5ac70f0Sopenharmony_ci{ 416d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 417d5ac70f0Sopenharmony_ci 418d5ac70f0Sopenharmony_ci if (ext->callback->read_event) { 419d5ac70f0Sopenharmony_ci memset(event, 0, sizeof(*event)); 420d5ac70f0Sopenharmony_ci return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); 421d5ac70f0Sopenharmony_ci } 422d5ac70f0Sopenharmony_ci 423d5ac70f0Sopenharmony_ci return -EINVAL; 424d5ac70f0Sopenharmony_ci} 425d5ac70f0Sopenharmony_ci 426d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle) 427d5ac70f0Sopenharmony_ci{ 428d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 429d5ac70f0Sopenharmony_ci 430d5ac70f0Sopenharmony_ci if (ext->callback->poll_descriptors_count) 431d5ac70f0Sopenharmony_ci return ext->callback->poll_descriptors_count(ext); 432d5ac70f0Sopenharmony_ci if (ext->poll_fd >= 0) 433d5ac70f0Sopenharmony_ci return 1; 434d5ac70f0Sopenharmony_ci return 0; 435d5ac70f0Sopenharmony_ci} 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_descriptors(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space) 438d5ac70f0Sopenharmony_ci{ 439d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 440d5ac70f0Sopenharmony_ci 441d5ac70f0Sopenharmony_ci if (ext->callback->poll_descriptors) 442d5ac70f0Sopenharmony_ci return ext->callback->poll_descriptors(ext, pfds, space); 443d5ac70f0Sopenharmony_ci if (ext->poll_fd < 0) 444d5ac70f0Sopenharmony_ci return 0; 445d5ac70f0Sopenharmony_ci if (space > 0) { 446d5ac70f0Sopenharmony_ci pfds->fd = ext->poll_fd; 447d5ac70f0Sopenharmony_ci pfds->events = POLLIN|POLLERR|POLLNVAL; 448d5ac70f0Sopenharmony_ci return 1; 449d5ac70f0Sopenharmony_ci } 450d5ac70f0Sopenharmony_ci return 0; 451d5ac70f0Sopenharmony_ci} 452d5ac70f0Sopenharmony_ci 453d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_revents(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 454d5ac70f0Sopenharmony_ci{ 455d5ac70f0Sopenharmony_ci snd_ctl_ext_t *ext = handle->private_data; 456d5ac70f0Sopenharmony_ci 457d5ac70f0Sopenharmony_ci if (ext->callback->poll_revents) 458d5ac70f0Sopenharmony_ci return ext->callback->poll_revents(ext, pfds, nfds, revents); 459d5ac70f0Sopenharmony_ci if (nfds == 1) { 460d5ac70f0Sopenharmony_ci *revents = pfds->revents; 461d5ac70f0Sopenharmony_ci return 0; 462d5ac70f0Sopenharmony_ci } 463d5ac70f0Sopenharmony_ci return -EINVAL; 464d5ac70f0Sopenharmony_ci} 465d5ac70f0Sopenharmony_ci 466d5ac70f0Sopenharmony_cistatic const snd_ctl_ops_t snd_ctl_ext_ops = { 467d5ac70f0Sopenharmony_ci .close = snd_ctl_ext_close, 468d5ac70f0Sopenharmony_ci .nonblock = snd_ctl_ext_nonblock, 469d5ac70f0Sopenharmony_ci .async = snd_ctl_ext_async, 470d5ac70f0Sopenharmony_ci .subscribe_events = snd_ctl_ext_subscribe_events, 471d5ac70f0Sopenharmony_ci .card_info = snd_ctl_ext_card_info, 472d5ac70f0Sopenharmony_ci .element_list = snd_ctl_ext_elem_list, 473d5ac70f0Sopenharmony_ci .element_info = snd_ctl_ext_elem_info, 474d5ac70f0Sopenharmony_ci .element_add = snd_ctl_ext_elem_add, 475d5ac70f0Sopenharmony_ci .element_replace = snd_ctl_ext_elem_replace, 476d5ac70f0Sopenharmony_ci .element_remove = snd_ctl_ext_elem_remove, 477d5ac70f0Sopenharmony_ci .element_read = snd_ctl_ext_elem_read, 478d5ac70f0Sopenharmony_ci .element_write = snd_ctl_ext_elem_write, 479d5ac70f0Sopenharmony_ci .element_lock = snd_ctl_ext_elem_lock, 480d5ac70f0Sopenharmony_ci .element_unlock = snd_ctl_ext_elem_unlock, 481d5ac70f0Sopenharmony_ci .element_tlv = snd_ctl_ext_elem_tlv, 482d5ac70f0Sopenharmony_ci .hwdep_next_device = snd_ctl_ext_next_device, 483d5ac70f0Sopenharmony_ci .hwdep_info = snd_ctl_ext_hwdep_info, 484d5ac70f0Sopenharmony_ci .pcm_next_device = snd_ctl_ext_next_device, 485d5ac70f0Sopenharmony_ci .pcm_info = snd_ctl_ext_pcm_info, 486d5ac70f0Sopenharmony_ci .pcm_prefer_subdevice = snd_ctl_ext_prefer_subdevice, 487d5ac70f0Sopenharmony_ci .rawmidi_next_device = snd_ctl_ext_next_device, 488d5ac70f0Sopenharmony_ci .rawmidi_info = snd_ctl_ext_rawmidi_info, 489d5ac70f0Sopenharmony_ci .rawmidi_prefer_subdevice = snd_ctl_ext_prefer_subdevice, 490d5ac70f0Sopenharmony_ci .set_power_state = snd_ctl_ext_set_power_state, 491d5ac70f0Sopenharmony_ci .get_power_state = snd_ctl_ext_get_power_state, 492d5ac70f0Sopenharmony_ci .read = snd_ctl_ext_read, 493d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_ctl_ext_poll_descriptors_count, 494d5ac70f0Sopenharmony_ci .poll_descriptors = snd_ctl_ext_poll_descriptors, 495d5ac70f0Sopenharmony_ci .poll_revents = snd_ctl_ext_poll_revents, 496d5ac70f0Sopenharmony_ci}; 497d5ac70f0Sopenharmony_ci 498d5ac70f0Sopenharmony_ci/* 499d5ac70f0Sopenharmony_ci * Exported functions 500d5ac70f0Sopenharmony_ci */ 501d5ac70f0Sopenharmony_ci 502d5ac70f0Sopenharmony_ci/*! \page ctl_external_plugins External Control Plugin SDK 503d5ac70f0Sopenharmony_ci 504d5ac70f0Sopenharmony_ci\section ctl_externals External Control Plugins 505d5ac70f0Sopenharmony_ci 506d5ac70f0Sopenharmony_ciThe external plugins are implemented in a shared object file located 507d5ac70f0Sopenharmony_ciat /usr/lib/alsa-lib (the exact location depends on the build option 508d5ac70f0Sopenharmony_ciand asoundrc configuration). It has to be the file like 509d5ac70f0Sopenharmony_cilibasound_module_ctl_MYPLUGIN.so, where MYPLUGIN corresponds to your 510d5ac70f0Sopenharmony_ciown plugin name. 511d5ac70f0Sopenharmony_ci 512d5ac70f0Sopenharmony_ciThe entry point of the plugin is defined via 513d5ac70f0Sopenharmony_ci#SND_CTL_PLUGIN_DEFINE_FUNC() macro. This macro defines the function 514d5ac70f0Sopenharmony_ciwith a proper name to be referred from alsa-lib. The function takes 515d5ac70f0Sopenharmony_cithe following 5 arguments: 516d5ac70f0Sopenharmony_ci\code 517d5ac70f0Sopenharmony_ciint (snd_ctl_t **phandle, const char *name, snd_config_t *root, 518d5ac70f0Sopenharmony_ci snd_config_t *conf, int mode) 519d5ac70f0Sopenharmony_ci\endcode 520d5ac70f0Sopenharmony_ciThe first argument, phandle, is the pointer to store the resultant control 521d5ac70f0Sopenharmony_cihandle. The arguments name, root and mode are the parameters 522d5ac70f0Sopenharmony_cito be passed to the plugin constructor. The conf is the configuration 523d5ac70f0Sopenharmony_citree for the plugin. The arguments above are defined in the macro 524d5ac70f0Sopenharmony_ciitself, so don't use variables with the same names to shadow 525d5ac70f0Sopenharmony_ciparameters. 526d5ac70f0Sopenharmony_ci 527d5ac70f0Sopenharmony_ciAfter parsing the configuration parameters in the given conf tree, 528d5ac70f0Sopenharmony_ciusually you will call the external plugin API function 529d5ac70f0Sopenharmony_ci#snd_ctl_ext_create(). 530d5ac70f0Sopenharmony_ciThe control handle must be filled *phandle in return. 531d5ac70f0Sopenharmony_ciThen this function must return either a value 0 when succeeded, or a 532d5ac70f0Sopenharmony_cinegative value as the error code. 533d5ac70f0Sopenharmony_ci 534d5ac70f0Sopenharmony_ciFinally, add #SND_CTL_PLUGIN_SYMBOL() with the name of your 535d5ac70f0Sopenharmony_ciplugin as the argument at the end. This defines the proper versioned 536d5ac70f0Sopenharmony_cisymbol as the reference. 537d5ac70f0Sopenharmony_ci 538d5ac70f0Sopenharmony_ciThe typical code would look like below: 539d5ac70f0Sopenharmony_ci\code 540d5ac70f0Sopenharmony_cistruct myctl_info { 541d5ac70f0Sopenharmony_ci snd_ctl_ext_t ext; 542d5ac70f0Sopenharmony_ci int my_own_data; 543d5ac70f0Sopenharmony_ci ... 544d5ac70f0Sopenharmony_ci}; 545d5ac70f0Sopenharmony_ci 546d5ac70f0Sopenharmony_ciSND_CTL_PLUGIN_DEFINE_FUNC(myctl) 547d5ac70f0Sopenharmony_ci{ 548d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 549d5ac70f0Sopenharmony_ci struct myctl_info *myctl; 550d5ac70f0Sopenharmony_ci int err; 551d5ac70f0Sopenharmony_ci 552d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 553d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 554d5ac70f0Sopenharmony_ci const char *id; 555d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 556d5ac70f0Sopenharmony_ci continue; 557d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) 558d5ac70f0Sopenharmony_ci continue; 559d5ac70f0Sopenharmony_ci if (strcmp(id, "my_own_parameter") == 0) { 560d5ac70f0Sopenharmony_ci .... 561d5ac70f0Sopenharmony_ci continue; 562d5ac70f0Sopenharmony_ci } 563d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 564d5ac70f0Sopenharmony_ci return -EINVAL; 565d5ac70f0Sopenharmony_ci } 566d5ac70f0Sopenharmony_ci 567d5ac70f0Sopenharmony_ci myctl = calloc(1, sizeof(*myctl)); 568d5ac70f0Sopenharmony_ci if (myctl == NULL) 569d5ac70f0Sopenharmony_ci return -ENOMEM; 570d5ac70f0Sopenharmony_ci 571d5ac70f0Sopenharmony_ci myctl->ext.version = SND_CTL_EXT_VERSION; 572d5ac70f0Sopenharmony_ci myctl->ext.card_idx = 0; 573d5ac70f0Sopenharmony_ci strcpy(myctl->ext.id, "Myctl"); 574d5ac70f0Sopenharmony_ci strcpy(myctl->ext.name, "My Control"); 575d5ac70f0Sopenharmony_ci strcpy(myctl->ext.longname, "My External Control for Foobar"); 576d5ac70f0Sopenharmony_ci strcpy(myctl->ext.mixername, "My Control"); 577d5ac70f0Sopenharmony_ci myctl->ext.callback = &my_own_callback; 578d5ac70f0Sopenharmony_ci myctl->ext.private_data = myctl; 579d5ac70f0Sopenharmony_ci .... 580d5ac70f0Sopenharmony_ci 581d5ac70f0Sopenharmony_ci err = snd_pcm_extplug_create(&myctl->ext, name, mode); 582d5ac70f0Sopenharmony_ci if (err < 0) { 583d5ac70f0Sopenharmony_ci myctl_free(myctl); 584d5ac70f0Sopenharmony_ci return err; 585d5ac70f0Sopenharmony_ci } 586d5ac70f0Sopenharmony_ci 587d5ac70f0Sopenharmony_ci *phandle = myctl->ext.handle; 588d5ac70f0Sopenharmony_ci return 0; 589d5ac70f0Sopenharmony_ci} 590d5ac70f0Sopenharmony_ci 591d5ac70f0Sopenharmony_ciSND_CTL_PLUGIN_SYMBOL(myctl); 592d5ac70f0Sopenharmony_ci\endcode 593d5ac70f0Sopenharmony_ci 594d5ac70f0Sopenharmony_ciRead the codes in alsa-plugins package for the real examples. 595d5ac70f0Sopenharmony_ci 596d5ac70f0Sopenharmony_ci 597d5ac70f0Sopenharmony_ci\section ctl_ext_impl Implementation of External Control Plugins 598d5ac70f0Sopenharmony_ci 599d5ac70f0Sopenharmony_ciThe following fields have to be filled in external control record before calling 600d5ac70f0Sopenharmony_ci#snd_ctl_ext_create() : version, card_idx, id, name, longname, mixername, poll_fd and callback. 601d5ac70f0Sopenharmony_ciOtherfields are optional and should be initialized with zero. 602d5ac70f0Sopenharmony_ci 603d5ac70f0Sopenharmony_ciThe constant #SND_CTL_EXT_VERSION must be passed to the version 604d5ac70f0Sopenharmony_cifield for the version check in alsa-lib. The card_idx field specifies the card 605d5ac70f0Sopenharmony_ciindex of this control. [FIXME: solve confliction of card index in alsa-lib?] 606d5ac70f0Sopenharmony_ci 607d5ac70f0Sopenharmony_ciThe id, name, longname and mixername fields are the strings shown in the card_info 608d5ac70f0Sopenharmony_ciinqurirys. They are the char arrays, so you have to <i>copy</i> strings to these 609d5ac70f0Sopenharmony_cifields. 610d5ac70f0Sopenharmony_ci 611d5ac70f0Sopenharmony_ciThe callback field contains the table of callback functions for this plugin (defined as 612d5ac70f0Sopenharmony_ci#snd_ctl_ext_callback_t). 613d5ac70f0Sopenharmony_ciThe poll_fd can be used to specify the poll file descriptor for this control. 614d5ac70f0Sopenharmony_ciSet -1 if not available. Alternatively, you can define poll_descriptors_count and 615d5ac70f0Sopenharmony_cipoll_descriptors callbacks in the callback table for handling the poll descriptor(s) 616d5ac70f0Sopenharmony_cidynamically after the creation of plugin instance. 617d5ac70f0Sopenharmony_ci 618d5ac70f0Sopenharmony_ciThe driver can set an arbitrary value (pointer) to private_data 619d5ac70f0Sopenharmony_cifield to refer its own data in the callbacks. 620d5ac70f0Sopenharmony_ci 621d5ac70f0Sopenharmony_ciThe rest fields are filled by #snd_ctl_ext_create(). The handle field 622d5ac70f0Sopenharmony_ciis the resultant PCM handle. The others are the current status of the 623d5ac70f0Sopenharmony_ciPCM. 624d5ac70f0Sopenharmony_ci 625d5ac70f0Sopenharmony_ci\section ctl_ext_impl_cb Callback Functions of External Control Plugins 626d5ac70f0Sopenharmony_ci 627d5ac70f0Sopenharmony_ciThe callback functions in #snd_ctl_ext_callback_t define the real 628d5ac70f0Sopenharmony_cibehavior of the driver. There are many callbacks but many of them are optional. 629d5ac70f0Sopenharmony_ci 630d5ac70f0Sopenharmony_ciThe close callback is called when the PCM is closed. If the plugin 631d5ac70f0Sopenharmony_ciallocates private resources, this is the place to release them 632d5ac70f0Sopenharmony_ciagain. This callback is optional. 633d5ac70f0Sopenharmony_ci 634d5ac70f0Sopenharmony_ciThe elem_count and elem_list callbacks are mandatory. The elem_count returns the 635d5ac70f0Sopenharmony_citotal number of control elements. The elem_list returns the control element ID 636d5ac70f0Sopenharmony_ciof the corresponding element offset (the offset is from 0 to elem_count - 1). 637d5ac70f0Sopenharmony_ciThe id field is initialized to all zero in prior to elem_list callback. The callback 638d5ac70f0Sopenharmony_cihas to fill the necessary field (typically iface, name and index) in return via the 639d5ac70f0Sopenharmony_cistandard control API functions like #snd_ctl_elem_id_set_interface, 640d5ac70f0Sopenharmony_ci#snd_ctl_elem_id_set_name and #snd_ctl_elem_id_set_index, etc. The callbacks should 641d5ac70f0Sopenharmony_cireturn 0 if successful, or a negative error code. 642d5ac70f0Sopenharmony_ci 643d5ac70f0Sopenharmony_ciThe find_elem callback is used to convert the given control element ID to the 644d5ac70f0Sopenharmony_cicertain key value for the faster access to get, read and write callbacks. 645d5ac70f0Sopenharmony_ciThe key type is alias of unsigned long, so you can assign some static number 646d5ac70f0Sopenharmony_ci(e.g. index of the array) to this value of the corresponding element, or 647d5ac70f0Sopenharmony_ciassign the pointer (cast to #snd_ctl_ext_key_t). When no key is defined or found, 648d5ac70f0Sopenharmony_cireturn #SND_CTL_EXT_KEY_NOT_FOUND. This callback is (very likely) required 649d5ac70f0Sopenharmony_ciif you use get, read and write callbacks as follows. 650d5ac70f0Sopenharmony_ciIf you need to create a record dynamically (e.g. via malloc) at each find_elem call, 651d5ac70f0Sopenharmony_cithe allocated record can be released with the optional free_key callback. 652d5ac70f0Sopenharmony_ci 653d5ac70f0Sopenharmony_ciThe get_attribute is a mandatory callback, which returns the attribute of the 654d5ac70f0Sopenharmony_cicontrol element given via a key value (converted with find_elem callback). 655d5ac70f0Sopenharmony_ciIt must fill the control element type (#snd_ctl_elem_type_t), the access type 656d5ac70f0Sopenharmony_ci(#snd_ctl_ext_access_t), and the count (element array size). The callback returns 657d5ac70f0Sopenharmony_ci0 if successful, or a negative error code, as usual. 658d5ac70f0Sopenharmony_ci 659d5ac70f0Sopenharmony_ciThe get_integer_info, get_integetr64_info and get_enumerated_info callbacks are called 660d5ac70f0Sopenharmony_cito return the information of the given control element for each element type. 661d5ac70f0Sopenharmony_ciFor integer and integer64 types, the callbacks need to fill the minimal (imin), 662d5ac70f0Sopenharmony_cimaximal (imax) and the step (istep) values of the control. For the enumerated type, 663d5ac70f0Sopenharmony_cithe number of enum items must be filled. Additionally, the enum control has to define 664d5ac70f0Sopenharmony_ciget_enumerated_name callback to store the name of the enumerated item of the given control 665d5ac70f0Sopenharmony_cielement. All functions return 0 if successful, or a negative error code. 666d5ac70f0Sopenharmony_ci 667d5ac70f0Sopenharmony_ciFor reading the current values of a control element, read_integer, read_integer64, 668d5ac70f0Sopenharmony_ciread_enumerated, read_bytes and read_iec958 callbacks are called depending on the 669d5ac70f0Sopenharmony_cielement type. These callbacks have to fill the current values of the element in return. 670d5ac70f0Sopenharmony_ciNote that a control element can be an array. If it contains more than one values 671d5ac70f0Sopenharmony_ci(i.e. the count value in get_attribute callback is more than 1), <i>all</i> values 672d5ac70f0Sopenharmony_cimust be filled on the given value pointer as an array. Also, note that the boolean type 673d5ac70f0Sopenharmony_ciis handled as integer here (although boolean type doesn't need to define the corresponding 674d5ac70f0Sopenharmony_ciinfo callback since it's obvious). These callbacks return 0 if successful, or 675d5ac70f0Sopenharmony_cia negative error code. 676d5ac70f0Sopenharmony_ci 677d5ac70f0Sopenharmony_ciFor writing the current values, write_integer, write_integer64, write_bytes, and 678d5ac70f0Sopenharmony_ciwrite_iec958 callbacks are called as well as for read. The callbacks should check the 679d5ac70f0Sopenharmony_cicurrent values and compare with the given values. If they are identical, the callbacks 680d5ac70f0Sopenharmony_cishould do nothing and return 0. If they differ, update the current values and return 1, 681d5ac70f0Sopenharmony_ciinstead. For any errors, return a negative error code. 682d5ac70f0Sopenharmony_ci 683d5ac70f0Sopenharmony_ciThe subscribe_events callback is called when the application subscribes or cancels 684d5ac70f0Sopenharmony_cithe event notifications (e.g. through mixer API). The current value of event 685d5ac70f0Sopenharmony_cisubscription is kept in the subscribed field. 686d5ac70f0Sopenharmony_ciThe read_event callback is called for reading a pending notification event. 687d5ac70f0Sopenharmony_ciThe callback needs to fill the event_mask value, a bit-field defined as SND_CTL_EVENT_MASK_XXX. 688d5ac70f0Sopenharmony_ciIf no event is pending, return -EAGAIN. These two callbacks are optional. 689d5ac70f0Sopenharmony_ci 690d5ac70f0Sopenharmony_ciThe poll_descriptors_count and poll_descriptors callbacks are used to return 691d5ac70f0Sopenharmony_cithe poll descriptor(s) via callbacks. As already mentioned, if the callback cannot 692d5ac70f0Sopenharmony_ciset the static poll_fd, you can define these callbacks to return dynamically. 693d5ac70f0Sopenharmony_ciAlso, when multiple poll descriptors are required, use these callbacks. 694d5ac70f0Sopenharmony_ciThe poll_revents callback is used for handle poll revents. 695d5ac70f0Sopenharmony_ci 696d5ac70f0Sopenharmony_ci*/ 697d5ac70f0Sopenharmony_ci 698d5ac70f0Sopenharmony_ci/** 699d5ac70f0Sopenharmony_ci * \brief Create an external control plugin instance 700d5ac70f0Sopenharmony_ci * \param ext the plugin handle 701d5ac70f0Sopenharmony_ci * \param name name of control 702d5ac70f0Sopenharmony_ci * \param mode control open mode 703d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 704d5ac70f0Sopenharmony_ci * 705d5ac70f0Sopenharmony_ci * Creates the external control instance. 706d5ac70f0Sopenharmony_ci * 707d5ac70f0Sopenharmony_ci */ 708d5ac70f0Sopenharmony_ciint snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode) 709d5ac70f0Sopenharmony_ci{ 710d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 711d5ac70f0Sopenharmony_ci int err; 712d5ac70f0Sopenharmony_ci 713d5ac70f0Sopenharmony_ci if (ext->version < SNDRV_PROTOCOL_VERSION(1, 0, 0) || 714d5ac70f0Sopenharmony_ci ext->version > SND_CTL_EXT_VERSION) { 715d5ac70f0Sopenharmony_ci SNDERR("ctl_ext: Plugin version mismatch"); 716d5ac70f0Sopenharmony_ci return -ENXIO; 717d5ac70f0Sopenharmony_ci } 718d5ac70f0Sopenharmony_ci 719d5ac70f0Sopenharmony_ci err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name, mode); 720d5ac70f0Sopenharmony_ci if (err < 0) 721d5ac70f0Sopenharmony_ci return err; 722d5ac70f0Sopenharmony_ci 723d5ac70f0Sopenharmony_ci ext->handle = ctl; 724d5ac70f0Sopenharmony_ci 725d5ac70f0Sopenharmony_ci ctl->ops = &snd_ctl_ext_ops; 726d5ac70f0Sopenharmony_ci ctl->private_data = ext; 727d5ac70f0Sopenharmony_ci ctl->poll_fd = ext->poll_fd; 728d5ac70f0Sopenharmony_ci if (mode & SND_CTL_NONBLOCK) 729d5ac70f0Sopenharmony_ci ext->nonblock = 1; 730d5ac70f0Sopenharmony_ci 731d5ac70f0Sopenharmony_ci return 0; 732d5ac70f0Sopenharmony_ci} 733d5ac70f0Sopenharmony_ci 734d5ac70f0Sopenharmony_ci/** 735d5ac70f0Sopenharmony_ci * \brief Delete the external control plugin 736d5ac70f0Sopenharmony_ci * \param ext the plugin handle 737d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 738d5ac70f0Sopenharmony_ci */ 739d5ac70f0Sopenharmony_ciint snd_ctl_ext_delete(snd_ctl_ext_t *ext) 740d5ac70f0Sopenharmony_ci{ 741d5ac70f0Sopenharmony_ci return snd_ctl_close(ext->handle); 742d5ac70f0Sopenharmony_ci} 743