1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file control/hcontrol.c 3d5ac70f0Sopenharmony_ci * \brief HCTL Interface - High Level CTL 4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000 7d5ac70f0Sopenharmony_ci * 8d5ac70f0Sopenharmony_ci * HCTL interface is designed to access preloaded and sorted primitive controls. 9d5ac70f0Sopenharmony_ci * Callbacks may be used for event handling. 10d5ac70f0Sopenharmony_ci * See \ref hcontrol page for more details. 11d5ac70f0Sopenharmony_ci */ 12d5ac70f0Sopenharmony_ci/* 13d5ac70f0Sopenharmony_ci * Control Interface - high level API 14d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz> 15d5ac70f0Sopenharmony_ci * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 16d5ac70f0Sopenharmony_ci * 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 19d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 20d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 21d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 24d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 25d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 27d5ac70f0Sopenharmony_ci * 28d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 29d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 30d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 31d5ac70f0Sopenharmony_ci * 32d5ac70f0Sopenharmony_ci */ 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci/*! \page hcontrol High level control interface 35d5ac70f0Sopenharmony_ci 36d5ac70f0Sopenharmony_ci<P> High level control interface is designed to access preloaded and sorted primitive controls. 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci\section hcontrol_general_overview General overview 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci<P> High level control interface caches the accesses to primitive controls 41d5ac70f0Sopenharmony_cito reduce overhead accessing the real controls in kernel drivers. 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ci*/ 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_ci#include "control_local.h" 46d5ac70f0Sopenharmony_ci#include <stdio.h> 47d5ac70f0Sopenharmony_ci#include <stdlib.h> 48d5ac70f0Sopenharmony_ci#include <unistd.h> 49d5ac70f0Sopenharmony_ci#include <string.h> 50d5ac70f0Sopenharmony_ci#include <fcntl.h> 51d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 52d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 53d5ac70f0Sopenharmony_ci#include <pthread.h> 54d5ac70f0Sopenharmony_ci#endif 55d5ac70f0Sopenharmony_ci 56d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 57d5ac70f0Sopenharmony_ci#define NOT_FOUND 1000000000 58d5ac70f0Sopenharmony_ci#endif 59d5ac70f0Sopenharmony_ci 60d5ac70f0Sopenharmony_cistatic int snd_hctl_compare_default(const snd_hctl_elem_t *c1, 61d5ac70f0Sopenharmony_ci const snd_hctl_elem_t *c2); 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci/** 64d5ac70f0Sopenharmony_ci * \brief Opens an HCTL 65d5ac70f0Sopenharmony_ci * \param hctlp Returned HCTL handle 66d5ac70f0Sopenharmony_ci * \param name ASCII identifier of the underlying CTL handle 67d5ac70f0Sopenharmony_ci * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) 68d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 69d5ac70f0Sopenharmony_ci */ 70d5ac70f0Sopenharmony_ciint snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode) 71d5ac70f0Sopenharmony_ci{ 72d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 73d5ac70f0Sopenharmony_ci int err; 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_ci if ((err = snd_ctl_open(&ctl, name, mode)) < 0) 76d5ac70f0Sopenharmony_ci return err; 77d5ac70f0Sopenharmony_ci err = snd_hctl_open_ctl(hctlp, ctl); 78d5ac70f0Sopenharmony_ci if (err < 0) 79d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 80d5ac70f0Sopenharmony_ci return err; 81d5ac70f0Sopenharmony_ci} 82d5ac70f0Sopenharmony_ci 83d5ac70f0Sopenharmony_ci/** 84d5ac70f0Sopenharmony_ci * \brief Opens an HCTL 85d5ac70f0Sopenharmony_ci * \param hctlp Returned HCTL handle 86d5ac70f0Sopenharmony_ci * \param ctl underlying CTL handle 87d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 88d5ac70f0Sopenharmony_ci */ 89d5ac70f0Sopenharmony_ciint snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) 90d5ac70f0Sopenharmony_ci{ 91d5ac70f0Sopenharmony_ci snd_hctl_t *hctl; 92d5ac70f0Sopenharmony_ci 93d5ac70f0Sopenharmony_ci assert(hctlp); 94d5ac70f0Sopenharmony_ci *hctlp = NULL; 95d5ac70f0Sopenharmony_ci if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL) 96d5ac70f0Sopenharmony_ci return -ENOMEM; 97d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&hctl->elems); 98d5ac70f0Sopenharmony_ci hctl->ctl = ctl; 99d5ac70f0Sopenharmony_ci *hctlp = hctl; 100d5ac70f0Sopenharmony_ci return 0; 101d5ac70f0Sopenharmony_ci} 102d5ac70f0Sopenharmony_ci 103d5ac70f0Sopenharmony_ci/** 104d5ac70f0Sopenharmony_ci * \brief close HCTL handle 105d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 106d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 107d5ac70f0Sopenharmony_ci * 108d5ac70f0Sopenharmony_ci * Closes the specified HCTL handle and frees all associated 109d5ac70f0Sopenharmony_ci * resources. 110d5ac70f0Sopenharmony_ci */ 111d5ac70f0Sopenharmony_ciint snd_hctl_close(snd_hctl_t *hctl) 112d5ac70f0Sopenharmony_ci{ 113d5ac70f0Sopenharmony_ci int err; 114d5ac70f0Sopenharmony_ci 115d5ac70f0Sopenharmony_ci assert(hctl); 116d5ac70f0Sopenharmony_ci err = snd_ctl_close(hctl->ctl); 117d5ac70f0Sopenharmony_ci snd_hctl_free(hctl); 118d5ac70f0Sopenharmony_ci free(hctl); 119d5ac70f0Sopenharmony_ci return err; 120d5ac70f0Sopenharmony_ci} 121d5ac70f0Sopenharmony_ci 122d5ac70f0Sopenharmony_ci/** 123d5ac70f0Sopenharmony_ci * \brief get identifier of HCTL handle 124d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 125d5ac70f0Sopenharmony_ci * \return ascii identifier of HCTL handle 126d5ac70f0Sopenharmony_ci * 127d5ac70f0Sopenharmony_ci * Returns the ASCII identifier of given HCTL handle. It's the same 128d5ac70f0Sopenharmony_ci * identifier specified in snd_hctl_open(). 129d5ac70f0Sopenharmony_ci */ 130d5ac70f0Sopenharmony_ciconst char *snd_hctl_name(snd_hctl_t *hctl) 131d5ac70f0Sopenharmony_ci{ 132d5ac70f0Sopenharmony_ci assert(hctl); 133d5ac70f0Sopenharmony_ci return snd_ctl_name(hctl->ctl); 134d5ac70f0Sopenharmony_ci} 135d5ac70f0Sopenharmony_ci 136d5ac70f0Sopenharmony_ci/** 137d5ac70f0Sopenharmony_ci * \brief set nonblock mode 138d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 139d5ac70f0Sopenharmony_ci * \param nonblock 0 = block, 1 = nonblock mode 140d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 141d5ac70f0Sopenharmony_ci */ 142d5ac70f0Sopenharmony_ciint snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock) 143d5ac70f0Sopenharmony_ci{ 144d5ac70f0Sopenharmony_ci assert(hctl); 145d5ac70f0Sopenharmony_ci return snd_ctl_nonblock(hctl->ctl, nonblock); 146d5ac70f0Sopenharmony_ci} 147d5ac70f0Sopenharmony_ci 148d5ac70f0Sopenharmony_ci/** 149d5ac70f0Sopenharmony_ci * \brief set async mode 150d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 151d5ac70f0Sopenharmony_ci * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) 152d5ac70f0Sopenharmony_ci * \param pid Process ID to signal: 0 current 153d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 154d5ac70f0Sopenharmony_ci * 155d5ac70f0Sopenharmony_ci * A signal is raised when a change happens. 156d5ac70f0Sopenharmony_ci */ 157d5ac70f0Sopenharmony_ciint snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid) 158d5ac70f0Sopenharmony_ci{ 159d5ac70f0Sopenharmony_ci assert(hctl); 160d5ac70f0Sopenharmony_ci return snd_ctl_async(hctl->ctl, sig, pid); 161d5ac70f0Sopenharmony_ci} 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_ci/** 164d5ac70f0Sopenharmony_ci * \brief get count of poll descriptors for HCTL handle 165d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 166d5ac70f0Sopenharmony_ci * \return count of poll descriptors 167d5ac70f0Sopenharmony_ci */ 168d5ac70f0Sopenharmony_ciint snd_hctl_poll_descriptors_count(snd_hctl_t *hctl) 169d5ac70f0Sopenharmony_ci{ 170d5ac70f0Sopenharmony_ci assert(hctl); 171d5ac70f0Sopenharmony_ci return snd_ctl_poll_descriptors_count(hctl->ctl); 172d5ac70f0Sopenharmony_ci} 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ci/** 175d5ac70f0Sopenharmony_ci * \brief get poll descriptors 176d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 177d5ac70f0Sopenharmony_ci * \param pfds array of poll descriptors 178d5ac70f0Sopenharmony_ci * \param space space in the poll descriptor array 179d5ac70f0Sopenharmony_ci * \return count of filled descriptors 180d5ac70f0Sopenharmony_ci */ 181d5ac70f0Sopenharmony_ciint snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space) 182d5ac70f0Sopenharmony_ci{ 183d5ac70f0Sopenharmony_ci assert(hctl); 184d5ac70f0Sopenharmony_ci return snd_ctl_poll_descriptors(hctl->ctl, pfds, space); 185d5ac70f0Sopenharmony_ci} 186d5ac70f0Sopenharmony_ci 187d5ac70f0Sopenharmony_ci/** 188d5ac70f0Sopenharmony_ci * \brief get returned events from poll descriptors 189d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 190d5ac70f0Sopenharmony_ci * \param pfds array of poll descriptors 191d5ac70f0Sopenharmony_ci * \param nfds count of poll descriptors 192d5ac70f0Sopenharmony_ci * \param revents returned events 193d5ac70f0Sopenharmony_ci * \return zero if success, otherwise a negative error code 194d5ac70f0Sopenharmony_ci */ 195d5ac70f0Sopenharmony_ciint snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 196d5ac70f0Sopenharmony_ci{ 197d5ac70f0Sopenharmony_ci assert(hctl); 198d5ac70f0Sopenharmony_ci return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents); 199d5ac70f0Sopenharmony_ci} 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_cistatic int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask, 202d5ac70f0Sopenharmony_ci snd_hctl_elem_t *elem) 203d5ac70f0Sopenharmony_ci{ 204d5ac70f0Sopenharmony_ci if (hctl->callback) 205d5ac70f0Sopenharmony_ci return hctl->callback(hctl, mask, elem); 206d5ac70f0Sopenharmony_ci return 0; 207d5ac70f0Sopenharmony_ci} 208d5ac70f0Sopenharmony_ci 209d5ac70f0Sopenharmony_cistatic int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem, 210d5ac70f0Sopenharmony_ci unsigned int mask) 211d5ac70f0Sopenharmony_ci{ 212d5ac70f0Sopenharmony_ci if (elem->callback) 213d5ac70f0Sopenharmony_ci return elem->callback(elem, mask); 214d5ac70f0Sopenharmony_ci return 0; 215d5ac70f0Sopenharmony_ci} 216d5ac70f0Sopenharmony_ci 217d5ac70f0Sopenharmony_cistatic int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) 218d5ac70f0Sopenharmony_ci{ 219d5ac70f0Sopenharmony_ci int res; 220d5ac70f0Sopenharmony_ci 221d5ac70f0Sopenharmony_ci for (res = 0; *names; names++, res += coef) { 222d5ac70f0Sopenharmony_ci if (!strncmp(*name, *names, strlen(*names))) { 223d5ac70f0Sopenharmony_ci *name += strlen(*names); 224d5ac70f0Sopenharmony_ci if (**name == ' ') 225d5ac70f0Sopenharmony_ci (*name)++; 226d5ac70f0Sopenharmony_ci return res+1; 227d5ac70f0Sopenharmony_ci } 228d5ac70f0Sopenharmony_ci } 229d5ac70f0Sopenharmony_ci return NOT_FOUND; 230d5ac70f0Sopenharmony_ci} 231d5ac70f0Sopenharmony_ci 232d5ac70f0Sopenharmony_cistatic int get_compare_weight(const snd_ctl_elem_id_t *id) 233d5ac70f0Sopenharmony_ci{ 234d5ac70f0Sopenharmony_ci static const char *const names[] = { 235d5ac70f0Sopenharmony_ci "Master", 236d5ac70f0Sopenharmony_ci "Hardware Master", 237d5ac70f0Sopenharmony_ci "Headphone", 238d5ac70f0Sopenharmony_ci "Tone Control", 239d5ac70f0Sopenharmony_ci "3D Control", 240d5ac70f0Sopenharmony_ci "PCM", 241d5ac70f0Sopenharmony_ci "Front", 242d5ac70f0Sopenharmony_ci "Surround", 243d5ac70f0Sopenharmony_ci "Center", 244d5ac70f0Sopenharmony_ci "LFE", 245d5ac70f0Sopenharmony_ci "Synth", 246d5ac70f0Sopenharmony_ci "FM", 247d5ac70f0Sopenharmony_ci "Wave", 248d5ac70f0Sopenharmony_ci "Music", 249d5ac70f0Sopenharmony_ci "DSP", 250d5ac70f0Sopenharmony_ci "Line", 251d5ac70f0Sopenharmony_ci "CD", 252d5ac70f0Sopenharmony_ci "Mic", 253d5ac70f0Sopenharmony_ci "Phone", 254d5ac70f0Sopenharmony_ci "Video", 255d5ac70f0Sopenharmony_ci "Zoom Video", 256d5ac70f0Sopenharmony_ci "PC Speaker", 257d5ac70f0Sopenharmony_ci "Aux", 258d5ac70f0Sopenharmony_ci "Mono", 259d5ac70f0Sopenharmony_ci "ADC", 260d5ac70f0Sopenharmony_ci "Capture Source", 261d5ac70f0Sopenharmony_ci "Capture", 262d5ac70f0Sopenharmony_ci "Playback", 263d5ac70f0Sopenharmony_ci "Loopback", 264d5ac70f0Sopenharmony_ci "Analog Loopback", 265d5ac70f0Sopenharmony_ci "Digital Loopback", 266d5ac70f0Sopenharmony_ci "I2S", 267d5ac70f0Sopenharmony_ci "IEC958", 268d5ac70f0Sopenharmony_ci NULL 269d5ac70f0Sopenharmony_ci }; 270d5ac70f0Sopenharmony_ci static const char *const names1[] = { 271d5ac70f0Sopenharmony_ci "Switch", 272d5ac70f0Sopenharmony_ci "Volume", 273d5ac70f0Sopenharmony_ci "Playback", 274d5ac70f0Sopenharmony_ci "Capture", 275d5ac70f0Sopenharmony_ci "Bypass", 276d5ac70f0Sopenharmony_ci "Mono", 277d5ac70f0Sopenharmony_ci "Front", 278d5ac70f0Sopenharmony_ci "Rear", 279d5ac70f0Sopenharmony_ci "Pan", 280d5ac70f0Sopenharmony_ci "Output", 281d5ac70f0Sopenharmony_ci "-", 282d5ac70f0Sopenharmony_ci NULL 283d5ac70f0Sopenharmony_ci }; 284d5ac70f0Sopenharmony_ci static const char *const names2[] = { 285d5ac70f0Sopenharmony_ci "Switch", 286d5ac70f0Sopenharmony_ci "Volume", 287d5ac70f0Sopenharmony_ci "Bypass", 288d5ac70f0Sopenharmony_ci "Depth", 289d5ac70f0Sopenharmony_ci "Wide", 290d5ac70f0Sopenharmony_ci "Space", 291d5ac70f0Sopenharmony_ci "Level", 292d5ac70f0Sopenharmony_ci "Center", 293d5ac70f0Sopenharmony_ci NULL 294d5ac70f0Sopenharmony_ci }; 295d5ac70f0Sopenharmony_ci const char *name = (char *)id->name, *name1; 296d5ac70f0Sopenharmony_ci int res, res1; 297d5ac70f0Sopenharmony_ci 298d5ac70f0Sopenharmony_ci if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND) 299d5ac70f0Sopenharmony_ci return NOT_FOUND; 300d5ac70f0Sopenharmony_ci if (*name == '\0') 301d5ac70f0Sopenharmony_ci return res; 302d5ac70f0Sopenharmony_ci for (name1 = name; *name1 != '\0'; name1++); 303d5ac70f0Sopenharmony_ci for (name1--; name1 != name && *name1 != ' '; name1--); 304d5ac70f0Sopenharmony_ci while (name1 != name && *name1 == ' ') 305d5ac70f0Sopenharmony_ci name1--; 306d5ac70f0Sopenharmony_ci if (name1 != name) { 307d5ac70f0Sopenharmony_ci for (; name1 != name && *name1 != ' '; name1--); 308d5ac70f0Sopenharmony_ci name = name1; 309d5ac70f0Sopenharmony_ci if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND) 310d5ac70f0Sopenharmony_ci return res; 311d5ac70f0Sopenharmony_ci res += res1; 312d5ac70f0Sopenharmony_ci } else { 313d5ac70f0Sopenharmony_ci name = name1; 314d5ac70f0Sopenharmony_ci } 315d5ac70f0Sopenharmony_ci if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND) 316d5ac70f0Sopenharmony_ci return res; 317d5ac70f0Sopenharmony_ci return res + res1; 318d5ac70f0Sopenharmony_ci} 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_cistatic int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir) 321d5ac70f0Sopenharmony_ci{ 322d5ac70f0Sopenharmony_ci unsigned int l, u; 323d5ac70f0Sopenharmony_ci snd_hctl_elem_t el; 324d5ac70f0Sopenharmony_ci int c = 0; 325d5ac70f0Sopenharmony_ci int idx = -1; 326d5ac70f0Sopenharmony_ci assert(hctl && id); 327d5ac70f0Sopenharmony_ci assert(hctl->compare); 328d5ac70f0Sopenharmony_ci el.id = *id; 329d5ac70f0Sopenharmony_ci el.compare_weight = get_compare_weight(id); 330d5ac70f0Sopenharmony_ci l = 0; 331d5ac70f0Sopenharmony_ci u = hctl->count; 332d5ac70f0Sopenharmony_ci while (l < u) { 333d5ac70f0Sopenharmony_ci idx = (l + u) / 2; 334d5ac70f0Sopenharmony_ci c = hctl->compare(&el, hctl->pelems[idx]); 335d5ac70f0Sopenharmony_ci if (c < 0) 336d5ac70f0Sopenharmony_ci u = idx; 337d5ac70f0Sopenharmony_ci else if (c > 0) 338d5ac70f0Sopenharmony_ci l = idx + 1; 339d5ac70f0Sopenharmony_ci else 340d5ac70f0Sopenharmony_ci break; 341d5ac70f0Sopenharmony_ci } 342d5ac70f0Sopenharmony_ci *dir = c; 343d5ac70f0Sopenharmony_ci return idx; 344d5ac70f0Sopenharmony_ci} 345d5ac70f0Sopenharmony_ci 346d5ac70f0Sopenharmony_cistatic int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem) 347d5ac70f0Sopenharmony_ci{ 348d5ac70f0Sopenharmony_ci int dir; 349d5ac70f0Sopenharmony_ci int idx; 350d5ac70f0Sopenharmony_ci elem->compare_weight = get_compare_weight(&elem->id); 351d5ac70f0Sopenharmony_ci if (hctl->count == hctl->alloc) { 352d5ac70f0Sopenharmony_ci snd_hctl_elem_t **h; 353d5ac70f0Sopenharmony_ci hctl->alloc += 32; 354d5ac70f0Sopenharmony_ci h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc); 355d5ac70f0Sopenharmony_ci if (!h) { 356d5ac70f0Sopenharmony_ci hctl->alloc -= 32; 357d5ac70f0Sopenharmony_ci return -ENOMEM; 358d5ac70f0Sopenharmony_ci } 359d5ac70f0Sopenharmony_ci hctl->pelems = h; 360d5ac70f0Sopenharmony_ci } 361d5ac70f0Sopenharmony_ci if (hctl->count == 0) { 362d5ac70f0Sopenharmony_ci list_add_tail(&elem->list, &hctl->elems); 363d5ac70f0Sopenharmony_ci hctl->pelems[0] = elem; 364d5ac70f0Sopenharmony_ci } else { 365d5ac70f0Sopenharmony_ci idx = _snd_hctl_find_elem(hctl, &elem->id, &dir); 366d5ac70f0Sopenharmony_ci assert(dir != 0); 367d5ac70f0Sopenharmony_ci if (dir > 0) { 368d5ac70f0Sopenharmony_ci list_add(&elem->list, &hctl->pelems[idx]->list); 369d5ac70f0Sopenharmony_ci idx++; 370d5ac70f0Sopenharmony_ci } else { 371d5ac70f0Sopenharmony_ci list_add_tail(&elem->list, &hctl->pelems[idx]->list); 372d5ac70f0Sopenharmony_ci } 373d5ac70f0Sopenharmony_ci memmove(hctl->pelems + idx + 1, 374d5ac70f0Sopenharmony_ci hctl->pelems + idx, 375d5ac70f0Sopenharmony_ci (hctl->count - idx) * sizeof(snd_hctl_elem_t *)); 376d5ac70f0Sopenharmony_ci hctl->pelems[idx] = elem; 377d5ac70f0Sopenharmony_ci } 378d5ac70f0Sopenharmony_ci hctl->count++; 379d5ac70f0Sopenharmony_ci return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem); 380d5ac70f0Sopenharmony_ci} 381d5ac70f0Sopenharmony_ci 382d5ac70f0Sopenharmony_cistatic void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx) 383d5ac70f0Sopenharmony_ci{ 384d5ac70f0Sopenharmony_ci snd_hctl_elem_t *elem = hctl->pelems[idx]; 385d5ac70f0Sopenharmony_ci unsigned int m; 386d5ac70f0Sopenharmony_ci snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE); 387d5ac70f0Sopenharmony_ci list_del(&elem->list); 388d5ac70f0Sopenharmony_ci free(elem); 389d5ac70f0Sopenharmony_ci hctl->count--; 390d5ac70f0Sopenharmony_ci m = hctl->count - idx; 391d5ac70f0Sopenharmony_ci if (m > 0) 392d5ac70f0Sopenharmony_ci memmove(hctl->pelems + idx, 393d5ac70f0Sopenharmony_ci hctl->pelems + idx + 1, 394d5ac70f0Sopenharmony_ci m * sizeof(snd_hctl_elem_t *)); 395d5ac70f0Sopenharmony_ci} 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ci/** 398d5ac70f0Sopenharmony_ci * \brief free HCTL loaded elements 399d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 400d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 401d5ac70f0Sopenharmony_ci */ 402d5ac70f0Sopenharmony_ciint snd_hctl_free(snd_hctl_t *hctl) 403d5ac70f0Sopenharmony_ci{ 404d5ac70f0Sopenharmony_ci while (hctl->count > 0) 405d5ac70f0Sopenharmony_ci snd_hctl_elem_remove(hctl, hctl->count - 1); 406d5ac70f0Sopenharmony_ci free(hctl->pelems); 407d5ac70f0Sopenharmony_ci hctl->pelems = 0; 408d5ac70f0Sopenharmony_ci hctl->alloc = 0; 409d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&hctl->elems); 410d5ac70f0Sopenharmony_ci return 0; 411d5ac70f0Sopenharmony_ci} 412d5ac70f0Sopenharmony_ci 413d5ac70f0Sopenharmony_cistatic snd_hctl_t *compare_hctl; 414d5ac70f0Sopenharmony_cistatic int hctl_compare(const void *a, const void *b) { 415d5ac70f0Sopenharmony_ci return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a, 416d5ac70f0Sopenharmony_ci *(const snd_hctl_elem_t * const *) b); 417d5ac70f0Sopenharmony_ci} 418d5ac70f0Sopenharmony_ci 419d5ac70f0Sopenharmony_cistatic void snd_hctl_sort(snd_hctl_t *hctl) 420d5ac70f0Sopenharmony_ci{ 421d5ac70f0Sopenharmony_ci unsigned int k; 422d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 423d5ac70f0Sopenharmony_ci static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER; 424d5ac70f0Sopenharmony_ci#endif 425d5ac70f0Sopenharmony_ci 426d5ac70f0Sopenharmony_ci assert(hctl); 427d5ac70f0Sopenharmony_ci assert(hctl->compare); 428d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&hctl->elems); 429d5ac70f0Sopenharmony_ci 430d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 431d5ac70f0Sopenharmony_ci pthread_mutex_lock(&sync_lock); 432d5ac70f0Sopenharmony_ci#endif 433d5ac70f0Sopenharmony_ci compare_hctl = hctl; 434d5ac70f0Sopenharmony_ci qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare); 435d5ac70f0Sopenharmony_ci#ifdef HAVE_LIBPTHREAD 436d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&sync_lock); 437d5ac70f0Sopenharmony_ci#endif 438d5ac70f0Sopenharmony_ci for (k = 0; k < hctl->count; k++) 439d5ac70f0Sopenharmony_ci list_add_tail(&hctl->pelems[k]->list, &hctl->elems); 440d5ac70f0Sopenharmony_ci} 441d5ac70f0Sopenharmony_ci 442d5ac70f0Sopenharmony_ci/** 443d5ac70f0Sopenharmony_ci * \brief Change HCTL compare function and reorder elements 444d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 445d5ac70f0Sopenharmony_ci * \param compare Element compare function 446d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 447d5ac70f0Sopenharmony_ci */ 448d5ac70f0Sopenharmony_ciint snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare) 449d5ac70f0Sopenharmony_ci{ 450d5ac70f0Sopenharmony_ci assert(hctl); 451d5ac70f0Sopenharmony_ci hctl->compare = compare == NULL ? snd_hctl_compare_default : compare; 452d5ac70f0Sopenharmony_ci snd_hctl_sort(hctl); 453d5ac70f0Sopenharmony_ci return 0; 454d5ac70f0Sopenharmony_ci} 455d5ac70f0Sopenharmony_ci 456d5ac70f0Sopenharmony_ci/** 457d5ac70f0Sopenharmony_ci * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare 458d5ac70f0Sopenharmony_ci * \param c1 First HCTL element 459d5ac70f0Sopenharmony_ci * \param c2 Second HCTL element 460d5ac70f0Sopenharmony_ci * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2 461d5ac70f0Sopenharmony_ci */ 462d5ac70f0Sopenharmony_ciint snd_hctl_compare_fast(const snd_hctl_elem_t *c1, 463d5ac70f0Sopenharmony_ci const snd_hctl_elem_t *c2) 464d5ac70f0Sopenharmony_ci{ 465d5ac70f0Sopenharmony_ci return c1->id.numid - c2->id.numid; 466d5ac70f0Sopenharmony_ci} 467d5ac70f0Sopenharmony_ci 468d5ac70f0Sopenharmony_cistatic int snd_hctl_compare_default(const snd_hctl_elem_t *c1, 469d5ac70f0Sopenharmony_ci const snd_hctl_elem_t *c2) 470d5ac70f0Sopenharmony_ci{ 471d5ac70f0Sopenharmony_ci int res, d; 472d5ac70f0Sopenharmony_ci 473d5ac70f0Sopenharmony_ci d = c1->id.iface - c2->id.iface; 474d5ac70f0Sopenharmony_ci if (d != 0) 475d5ac70f0Sopenharmony_ci return d; 476d5ac70f0Sopenharmony_ci if (c1->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER) { 477d5ac70f0Sopenharmony_ci d = c1->compare_weight - c2->compare_weight; 478d5ac70f0Sopenharmony_ci if (d != 0) 479d5ac70f0Sopenharmony_ci return d; 480d5ac70f0Sopenharmony_ci } 481d5ac70f0Sopenharmony_ci d = c1->id.device - c2->id.device; 482d5ac70f0Sopenharmony_ci if (d != 0) 483d5ac70f0Sopenharmony_ci return d; 484d5ac70f0Sopenharmony_ci d = c1->id.subdevice - c2->id.subdevice; 485d5ac70f0Sopenharmony_ci if (d != 0) 486d5ac70f0Sopenharmony_ci return d; 487d5ac70f0Sopenharmony_ci res = strcmp((const char *)c1->id.name, (const char *)c2->id.name); 488d5ac70f0Sopenharmony_ci if (res != 0) 489d5ac70f0Sopenharmony_ci return res; 490d5ac70f0Sopenharmony_ci return c1->id.index - c2->id.index; 491d5ac70f0Sopenharmony_ci} 492d5ac70f0Sopenharmony_ci 493d5ac70f0Sopenharmony_ci/** 494d5ac70f0Sopenharmony_ci * \brief get first element for an HCTL 495d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 496d5ac70f0Sopenharmony_ci * \return pointer to first element 497d5ac70f0Sopenharmony_ci */ 498d5ac70f0Sopenharmony_cisnd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl) 499d5ac70f0Sopenharmony_ci{ 500d5ac70f0Sopenharmony_ci assert(hctl); 501d5ac70f0Sopenharmony_ci if (list_empty(&hctl->elems)) 502d5ac70f0Sopenharmony_ci return NULL; 503d5ac70f0Sopenharmony_ci return list_entry(hctl->elems.next, snd_hctl_elem_t, list); 504d5ac70f0Sopenharmony_ci} 505d5ac70f0Sopenharmony_ci 506d5ac70f0Sopenharmony_ci/** 507d5ac70f0Sopenharmony_ci * \brief get last element for an HCTL 508d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 509d5ac70f0Sopenharmony_ci * \return pointer to last element 510d5ac70f0Sopenharmony_ci */ 511d5ac70f0Sopenharmony_cisnd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl) 512d5ac70f0Sopenharmony_ci{ 513d5ac70f0Sopenharmony_ci assert(hctl); 514d5ac70f0Sopenharmony_ci if (list_empty(&hctl->elems)) 515d5ac70f0Sopenharmony_ci return NULL; 516d5ac70f0Sopenharmony_ci return list_entry(hctl->elems.prev, snd_hctl_elem_t, list); 517d5ac70f0Sopenharmony_ci} 518d5ac70f0Sopenharmony_ci 519d5ac70f0Sopenharmony_ci/** 520d5ac70f0Sopenharmony_ci * \brief get next HCTL element 521d5ac70f0Sopenharmony_ci * \param elem HCTL element 522d5ac70f0Sopenharmony_ci * \return pointer to next element 523d5ac70f0Sopenharmony_ci */ 524d5ac70f0Sopenharmony_cisnd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem) 525d5ac70f0Sopenharmony_ci{ 526d5ac70f0Sopenharmony_ci assert(elem); 527d5ac70f0Sopenharmony_ci if (elem->list.next == &elem->hctl->elems) 528d5ac70f0Sopenharmony_ci return NULL; 529d5ac70f0Sopenharmony_ci return list_entry(elem->list.next, snd_hctl_elem_t, list); 530d5ac70f0Sopenharmony_ci} 531d5ac70f0Sopenharmony_ci 532d5ac70f0Sopenharmony_ci/** 533d5ac70f0Sopenharmony_ci * \brief get previous HCTL element 534d5ac70f0Sopenharmony_ci * \param elem HCTL element 535d5ac70f0Sopenharmony_ci * \return pointer to previous element 536d5ac70f0Sopenharmony_ci */ 537d5ac70f0Sopenharmony_cisnd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem) 538d5ac70f0Sopenharmony_ci{ 539d5ac70f0Sopenharmony_ci assert(elem); 540d5ac70f0Sopenharmony_ci if (elem->list.prev == &elem->hctl->elems) 541d5ac70f0Sopenharmony_ci return NULL; 542d5ac70f0Sopenharmony_ci return list_entry(elem->list.prev, snd_hctl_elem_t, list); 543d5ac70f0Sopenharmony_ci} 544d5ac70f0Sopenharmony_ci 545d5ac70f0Sopenharmony_ci/** 546d5ac70f0Sopenharmony_ci * \brief Search an HCTL element 547d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 548d5ac70f0Sopenharmony_ci * \param id Element identifier 549d5ac70f0Sopenharmony_ci * \return pointer to found HCTL element or NULL if it does not exists 550d5ac70f0Sopenharmony_ci */ 551d5ac70f0Sopenharmony_cisnd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id) 552d5ac70f0Sopenharmony_ci{ 553d5ac70f0Sopenharmony_ci int dir; 554d5ac70f0Sopenharmony_ci int res = _snd_hctl_find_elem(hctl, id, &dir); 555d5ac70f0Sopenharmony_ci if (res < 0 || dir != 0) 556d5ac70f0Sopenharmony_ci return NULL; 557d5ac70f0Sopenharmony_ci return hctl->pelems[res]; 558d5ac70f0Sopenharmony_ci} 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_ci/** 561d5ac70f0Sopenharmony_ci * \brief Load an HCTL with all elements and sort them 562d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 563d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 564d5ac70f0Sopenharmony_ci */ 565d5ac70f0Sopenharmony_ciint snd_hctl_load(snd_hctl_t *hctl) 566d5ac70f0Sopenharmony_ci{ 567d5ac70f0Sopenharmony_ci snd_ctl_elem_list_t list; 568d5ac70f0Sopenharmony_ci int err = 0; 569d5ac70f0Sopenharmony_ci unsigned int idx; 570d5ac70f0Sopenharmony_ci 571d5ac70f0Sopenharmony_ci assert(hctl); 572d5ac70f0Sopenharmony_ci assert(hctl->ctl); 573d5ac70f0Sopenharmony_ci assert(hctl->count == 0); 574d5ac70f0Sopenharmony_ci assert(list_empty(&hctl->elems)); 575d5ac70f0Sopenharmony_ci memset(&list, 0, sizeof(list)); 576d5ac70f0Sopenharmony_ci if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) 577d5ac70f0Sopenharmony_ci goto _end; 578d5ac70f0Sopenharmony_ci while (list.count != list.used) { 579d5ac70f0Sopenharmony_ci err = snd_ctl_elem_list_alloc_space(&list, list.count); 580d5ac70f0Sopenharmony_ci if (err < 0) 581d5ac70f0Sopenharmony_ci goto _end; 582d5ac70f0Sopenharmony_ci if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) 583d5ac70f0Sopenharmony_ci goto _end; 584d5ac70f0Sopenharmony_ci } 585d5ac70f0Sopenharmony_ci if (hctl->alloc < list.count) { 586d5ac70f0Sopenharmony_ci hctl->alloc = list.count; 587d5ac70f0Sopenharmony_ci free(hctl->pelems); 588d5ac70f0Sopenharmony_ci hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems)); 589d5ac70f0Sopenharmony_ci if (!hctl->pelems) { 590d5ac70f0Sopenharmony_ci err = -ENOMEM; 591d5ac70f0Sopenharmony_ci goto _end; 592d5ac70f0Sopenharmony_ci } 593d5ac70f0Sopenharmony_ci } 594d5ac70f0Sopenharmony_ci for (idx = 0; idx < list.count; idx++) { 595d5ac70f0Sopenharmony_ci snd_hctl_elem_t *elem; 596d5ac70f0Sopenharmony_ci elem = calloc(1, sizeof(snd_hctl_elem_t)); 597d5ac70f0Sopenharmony_ci if (elem == NULL) { 598d5ac70f0Sopenharmony_ci snd_hctl_free(hctl); 599d5ac70f0Sopenharmony_ci err = -ENOMEM; 600d5ac70f0Sopenharmony_ci goto _end; 601d5ac70f0Sopenharmony_ci } 602d5ac70f0Sopenharmony_ci elem->id = list.pids[idx]; 603d5ac70f0Sopenharmony_ci elem->hctl = hctl; 604d5ac70f0Sopenharmony_ci elem->compare_weight = get_compare_weight(&elem->id); 605d5ac70f0Sopenharmony_ci hctl->pelems[idx] = elem; 606d5ac70f0Sopenharmony_ci list_add_tail(&elem->list, &hctl->elems); 607d5ac70f0Sopenharmony_ci hctl->count++; 608d5ac70f0Sopenharmony_ci } 609d5ac70f0Sopenharmony_ci if (!hctl->compare) 610d5ac70f0Sopenharmony_ci hctl->compare = snd_hctl_compare_default; 611d5ac70f0Sopenharmony_ci snd_hctl_sort(hctl); 612d5ac70f0Sopenharmony_ci for (idx = 0; idx < hctl->count; idx++) { 613d5ac70f0Sopenharmony_ci int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, 614d5ac70f0Sopenharmony_ci hctl->pelems[idx]); 615d5ac70f0Sopenharmony_ci if (res < 0) 616d5ac70f0Sopenharmony_ci return res; 617d5ac70f0Sopenharmony_ci } 618d5ac70f0Sopenharmony_ci err = snd_ctl_subscribe_events(hctl->ctl, 1); 619d5ac70f0Sopenharmony_ci _end: 620d5ac70f0Sopenharmony_ci free(list.pids); 621d5ac70f0Sopenharmony_ci return err; 622d5ac70f0Sopenharmony_ci} 623d5ac70f0Sopenharmony_ci 624d5ac70f0Sopenharmony_ci/** 625d5ac70f0Sopenharmony_ci * \brief Set callback function for an HCTL 626d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 627d5ac70f0Sopenharmony_ci * \param callback callback function 628d5ac70f0Sopenharmony_ci */ 629d5ac70f0Sopenharmony_civoid snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback) 630d5ac70f0Sopenharmony_ci{ 631d5ac70f0Sopenharmony_ci assert(hctl); 632d5ac70f0Sopenharmony_ci hctl->callback = callback; 633d5ac70f0Sopenharmony_ci} 634d5ac70f0Sopenharmony_ci 635d5ac70f0Sopenharmony_ci/** 636d5ac70f0Sopenharmony_ci * \brief Set callback private value for an HCTL 637d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 638d5ac70f0Sopenharmony_ci * \param callback_private callback private value 639d5ac70f0Sopenharmony_ci */ 640d5ac70f0Sopenharmony_civoid snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private) 641d5ac70f0Sopenharmony_ci{ 642d5ac70f0Sopenharmony_ci assert(hctl); 643d5ac70f0Sopenharmony_ci hctl->callback_private = callback_private; 644d5ac70f0Sopenharmony_ci} 645d5ac70f0Sopenharmony_ci 646d5ac70f0Sopenharmony_ci/** 647d5ac70f0Sopenharmony_ci * \brief Get callback private value for an HCTL 648d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 649d5ac70f0Sopenharmony_ci * \return callback private value 650d5ac70f0Sopenharmony_ci */ 651d5ac70f0Sopenharmony_civoid *snd_hctl_get_callback_private(snd_hctl_t *hctl) 652d5ac70f0Sopenharmony_ci{ 653d5ac70f0Sopenharmony_ci assert(hctl); 654d5ac70f0Sopenharmony_ci return hctl->callback_private; 655d5ac70f0Sopenharmony_ci} 656d5ac70f0Sopenharmony_ci 657d5ac70f0Sopenharmony_ci/** 658d5ac70f0Sopenharmony_ci * \brief Get number of loaded elements for an HCTL 659d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 660d5ac70f0Sopenharmony_ci * \return elements count 661d5ac70f0Sopenharmony_ci */ 662d5ac70f0Sopenharmony_ciunsigned int snd_hctl_get_count(snd_hctl_t *hctl) 663d5ac70f0Sopenharmony_ci{ 664d5ac70f0Sopenharmony_ci return hctl->count; 665d5ac70f0Sopenharmony_ci} 666d5ac70f0Sopenharmony_ci 667d5ac70f0Sopenharmony_ci/** 668d5ac70f0Sopenharmony_ci * \brief Wait for a HCTL to become ready (i.e. at least one event pending) 669d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 670d5ac70f0Sopenharmony_ci * \param timeout maximum time in milliseconds to wait 671d5ac70f0Sopenharmony_ci * \return a positive value on success otherwise a negative error code 672d5ac70f0Sopenharmony_ci * \retval 0 timeout occurred 673d5ac70f0Sopenharmony_ci * \retval 1 an event is pending 674d5ac70f0Sopenharmony_ci */ 675d5ac70f0Sopenharmony_ciint snd_hctl_wait(snd_hctl_t *hctl, int timeout) 676d5ac70f0Sopenharmony_ci{ 677d5ac70f0Sopenharmony_ci struct pollfd *pfd; 678d5ac70f0Sopenharmony_ci unsigned short *revents; 679d5ac70f0Sopenharmony_ci int i, npfds, pollio, err, err_poll; 680d5ac70f0Sopenharmony_ci 681d5ac70f0Sopenharmony_ci npfds = snd_hctl_poll_descriptors_count(hctl); 682d5ac70f0Sopenharmony_ci if (npfds <= 0 || npfds >= 16) { 683d5ac70f0Sopenharmony_ci SNDERR("Invalid poll_fds %d", npfds); 684d5ac70f0Sopenharmony_ci return -EIO; 685d5ac70f0Sopenharmony_ci } 686d5ac70f0Sopenharmony_ci pfd = alloca(sizeof(*pfd) * npfds); 687d5ac70f0Sopenharmony_ci revents = alloca(sizeof(*revents) * npfds); 688d5ac70f0Sopenharmony_ci err = snd_hctl_poll_descriptors(hctl, pfd, npfds); 689d5ac70f0Sopenharmony_ci if (err < 0) 690d5ac70f0Sopenharmony_ci return err; 691d5ac70f0Sopenharmony_ci if (err != npfds) { 692d5ac70f0Sopenharmony_ci SNDMSG("invalid poll descriptors %d", err); 693d5ac70f0Sopenharmony_ci return -EIO; 694d5ac70f0Sopenharmony_ci } 695d5ac70f0Sopenharmony_ci do { 696d5ac70f0Sopenharmony_ci pollio = 0; 697d5ac70f0Sopenharmony_ci err_poll = poll(pfd, npfds, timeout); 698d5ac70f0Sopenharmony_ci if (err_poll < 0) { 699d5ac70f0Sopenharmony_ci if (errno == EINTR && !CTLINABORT(hctl->ctl) && !(hctl->ctl->mode & SND_CTL_EINTR)) 700d5ac70f0Sopenharmony_ci continue; 701d5ac70f0Sopenharmony_ci return -errno; 702d5ac70f0Sopenharmony_ci } 703d5ac70f0Sopenharmony_ci if (! err_poll) 704d5ac70f0Sopenharmony_ci break; 705d5ac70f0Sopenharmony_ci err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents); 706d5ac70f0Sopenharmony_ci if (err < 0) 707d5ac70f0Sopenharmony_ci return err; 708d5ac70f0Sopenharmony_ci for (i = 0; i < npfds; i++) { 709d5ac70f0Sopenharmony_ci if (revents[i] & (POLLERR | POLLNVAL)) 710d5ac70f0Sopenharmony_ci return -EIO; 711d5ac70f0Sopenharmony_ci if ((revents[i] & (POLLIN | POLLOUT)) == 0) 712d5ac70f0Sopenharmony_ci continue; 713d5ac70f0Sopenharmony_ci pollio++; 714d5ac70f0Sopenharmony_ci } 715d5ac70f0Sopenharmony_ci } while (! pollio); 716d5ac70f0Sopenharmony_ci return err_poll > 0 ? 1 : 0; 717d5ac70f0Sopenharmony_ci} 718d5ac70f0Sopenharmony_ci 719d5ac70f0Sopenharmony_ci/** 720d5ac70f0Sopenharmony_ci * \brief Get a ctl handle associated to the given hctl handle 721d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 722d5ac70f0Sopenharmony_ci * \return a ctl handle otherwise NULL 723d5ac70f0Sopenharmony_ci */ 724d5ac70f0Sopenharmony_cisnd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) 725d5ac70f0Sopenharmony_ci{ 726d5ac70f0Sopenharmony_ci return hctl->ctl; 727d5ac70f0Sopenharmony_ci} 728d5ac70f0Sopenharmony_ci 729d5ac70f0Sopenharmony_cistatic int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) 730d5ac70f0Sopenharmony_ci{ 731d5ac70f0Sopenharmony_ci snd_hctl_elem_t *elem; 732d5ac70f0Sopenharmony_ci int res; 733d5ac70f0Sopenharmony_ci 734d5ac70f0Sopenharmony_ci assert(hctl); 735d5ac70f0Sopenharmony_ci assert(hctl->ctl); 736d5ac70f0Sopenharmony_ci switch (event->type) { 737d5ac70f0Sopenharmony_ci case SND_CTL_EVENT_ELEM: 738d5ac70f0Sopenharmony_ci break; 739d5ac70f0Sopenharmony_ci default: 740d5ac70f0Sopenharmony_ci return 0; 741d5ac70f0Sopenharmony_ci } 742d5ac70f0Sopenharmony_ci if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) { 743d5ac70f0Sopenharmony_ci int dir; 744d5ac70f0Sopenharmony_ci res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir); 745d5ac70f0Sopenharmony_ci if (res < 0 || dir != 0) 746d5ac70f0Sopenharmony_ci return -ENOENT; 747d5ac70f0Sopenharmony_ci snd_hctl_elem_remove(hctl, (unsigned int) res); 748d5ac70f0Sopenharmony_ci return 0; 749d5ac70f0Sopenharmony_ci } 750d5ac70f0Sopenharmony_ci if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) { 751d5ac70f0Sopenharmony_ci elem = calloc(1, sizeof(snd_hctl_elem_t)); 752d5ac70f0Sopenharmony_ci if (elem == NULL) 753d5ac70f0Sopenharmony_ci return -ENOMEM; 754d5ac70f0Sopenharmony_ci elem->id = event->data.elem.id; 755d5ac70f0Sopenharmony_ci elem->hctl = hctl; 756d5ac70f0Sopenharmony_ci res = snd_hctl_elem_add(hctl, elem); 757d5ac70f0Sopenharmony_ci if (res < 0) 758d5ac70f0Sopenharmony_ci return res; 759d5ac70f0Sopenharmony_ci } 760d5ac70f0Sopenharmony_ci if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | 761d5ac70f0Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO)) { 762d5ac70f0Sopenharmony_ci elem = snd_hctl_find_elem(hctl, &event->data.elem.id); 763d5ac70f0Sopenharmony_ci if (!elem) 764d5ac70f0Sopenharmony_ci return -ENOENT; 765d5ac70f0Sopenharmony_ci res = snd_hctl_elem_throw_event(elem, event->data.elem.mask & 766d5ac70f0Sopenharmony_ci (SNDRV_CTL_EVENT_MASK_VALUE | 767d5ac70f0Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO)); 768d5ac70f0Sopenharmony_ci if (res < 0) 769d5ac70f0Sopenharmony_ci return res; 770d5ac70f0Sopenharmony_ci } 771d5ac70f0Sopenharmony_ci return 0; 772d5ac70f0Sopenharmony_ci} 773d5ac70f0Sopenharmony_ci 774d5ac70f0Sopenharmony_ci/** 775d5ac70f0Sopenharmony_ci * \brief Handle pending HCTL events invoking callbacks 776d5ac70f0Sopenharmony_ci * \param hctl HCTL handle 777d5ac70f0Sopenharmony_ci * \return 0 otherwise a negative error code on failure 778d5ac70f0Sopenharmony_ci */ 779d5ac70f0Sopenharmony_ciint snd_hctl_handle_events(snd_hctl_t *hctl) 780d5ac70f0Sopenharmony_ci{ 781d5ac70f0Sopenharmony_ci snd_ctl_event_t event; 782d5ac70f0Sopenharmony_ci int res; 783d5ac70f0Sopenharmony_ci unsigned int count = 0; 784d5ac70f0Sopenharmony_ci 785d5ac70f0Sopenharmony_ci assert(hctl); 786d5ac70f0Sopenharmony_ci assert(hctl->ctl); 787d5ac70f0Sopenharmony_ci while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 && 788d5ac70f0Sopenharmony_ci res != -EAGAIN) { 789d5ac70f0Sopenharmony_ci if (res < 0) 790d5ac70f0Sopenharmony_ci return res; 791d5ac70f0Sopenharmony_ci res = snd_hctl_handle_event(hctl, &event); 792d5ac70f0Sopenharmony_ci if (res < 0) 793d5ac70f0Sopenharmony_ci return res; 794d5ac70f0Sopenharmony_ci count++; 795d5ac70f0Sopenharmony_ci } 796d5ac70f0Sopenharmony_ci return count; 797d5ac70f0Sopenharmony_ci} 798d5ac70f0Sopenharmony_ci 799d5ac70f0Sopenharmony_ci/** 800d5ac70f0Sopenharmony_ci * \brief Get information for an HCTL element 801d5ac70f0Sopenharmony_ci * \param elem HCTL element 802d5ac70f0Sopenharmony_ci * \param info HCTL element information 803d5ac70f0Sopenharmony_ci * \return 0 otherwise a negative error code on failure 804d5ac70f0Sopenharmony_ci */ 805d5ac70f0Sopenharmony_ciint snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info) 806d5ac70f0Sopenharmony_ci{ 807d5ac70f0Sopenharmony_ci assert(elem); 808d5ac70f0Sopenharmony_ci assert(elem->hctl); 809d5ac70f0Sopenharmony_ci assert(info); 810d5ac70f0Sopenharmony_ci info->id = elem->id; 811d5ac70f0Sopenharmony_ci return snd_ctl_elem_info(elem->hctl->ctl, info); 812d5ac70f0Sopenharmony_ci} 813d5ac70f0Sopenharmony_ci 814d5ac70f0Sopenharmony_ci/** 815d5ac70f0Sopenharmony_ci * \brief Get value for an HCTL element 816d5ac70f0Sopenharmony_ci * \param elem HCTL element 817d5ac70f0Sopenharmony_ci * \param value HCTL element value 818d5ac70f0Sopenharmony_ci * \return 0 otherwise a negative error code on failure 819d5ac70f0Sopenharmony_ci */ 820d5ac70f0Sopenharmony_ciint snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) 821d5ac70f0Sopenharmony_ci{ 822d5ac70f0Sopenharmony_ci assert(elem); 823d5ac70f0Sopenharmony_ci assert(elem->hctl); 824d5ac70f0Sopenharmony_ci assert(value); 825d5ac70f0Sopenharmony_ci value->id = elem->id; 826d5ac70f0Sopenharmony_ci return snd_ctl_elem_read(elem->hctl->ctl, value); 827d5ac70f0Sopenharmony_ci} 828d5ac70f0Sopenharmony_ci 829d5ac70f0Sopenharmony_ci/** 830d5ac70f0Sopenharmony_ci * \brief Set value for an HCTL element 831d5ac70f0Sopenharmony_ci * \param elem HCTL element 832d5ac70f0Sopenharmony_ci * \param value HCTL element value 833d5ac70f0Sopenharmony_ci * \retval 0 on success 834d5ac70f0Sopenharmony_ci * \retval >1 on success when value was changed 835d5ac70f0Sopenharmony_ci * \retval <0 a negative error code on failure 836d5ac70f0Sopenharmony_ci */ 837d5ac70f0Sopenharmony_ciint snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) 838d5ac70f0Sopenharmony_ci{ 839d5ac70f0Sopenharmony_ci assert(elem); 840d5ac70f0Sopenharmony_ci assert(elem->hctl); 841d5ac70f0Sopenharmony_ci assert(value); 842d5ac70f0Sopenharmony_ci value->id = elem->id; 843d5ac70f0Sopenharmony_ci return snd_ctl_elem_write(elem->hctl->ctl, value); 844d5ac70f0Sopenharmony_ci} 845d5ac70f0Sopenharmony_ci 846d5ac70f0Sopenharmony_ci/** 847d5ac70f0Sopenharmony_ci * \brief Get TLV value for an HCTL element 848d5ac70f0Sopenharmony_ci * \param elem HCTL element 849d5ac70f0Sopenharmony_ci * \param tlv TLV array for value 850d5ac70f0Sopenharmony_ci * \param tlv_size size of TLV array in bytes 851d5ac70f0Sopenharmony_ci * \return 0 otherwise a negative error code on failure 852d5ac70f0Sopenharmony_ci */ 853d5ac70f0Sopenharmony_ciint snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) 854d5ac70f0Sopenharmony_ci{ 855d5ac70f0Sopenharmony_ci assert(elem); 856d5ac70f0Sopenharmony_ci assert(tlv); 857d5ac70f0Sopenharmony_ci assert(tlv_size >= 12); 858d5ac70f0Sopenharmony_ci return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size); 859d5ac70f0Sopenharmony_ci} 860d5ac70f0Sopenharmony_ci 861d5ac70f0Sopenharmony_ci/** 862d5ac70f0Sopenharmony_ci * \brief Set TLV value for an HCTL element 863d5ac70f0Sopenharmony_ci * \param elem HCTL element 864d5ac70f0Sopenharmony_ci * \param tlv TLV array for value 865d5ac70f0Sopenharmony_ci * \retval 0 on success 866d5ac70f0Sopenharmony_ci * \retval >1 on success when value was changed 867d5ac70f0Sopenharmony_ci * \retval <0 a negative error code on failure 868d5ac70f0Sopenharmony_ci */ 869d5ac70f0Sopenharmony_ciint snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv) 870d5ac70f0Sopenharmony_ci{ 871d5ac70f0Sopenharmony_ci assert(elem); 872d5ac70f0Sopenharmony_ci assert(tlv); 873d5ac70f0Sopenharmony_ci assert(tlv[SNDRV_CTL_TLVO_LEN] >= 4); 874d5ac70f0Sopenharmony_ci return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv); 875d5ac70f0Sopenharmony_ci} 876d5ac70f0Sopenharmony_ci 877d5ac70f0Sopenharmony_ci/** 878d5ac70f0Sopenharmony_ci * \brief Set TLV value for an HCTL element 879d5ac70f0Sopenharmony_ci * \param elem HCTL element 880d5ac70f0Sopenharmony_ci * \param tlv TLV array for value 881d5ac70f0Sopenharmony_ci * \retval 0 on success 882d5ac70f0Sopenharmony_ci * \retval >1 on success when value was changed 883d5ac70f0Sopenharmony_ci * \retval <0 a negative error code on failure 884d5ac70f0Sopenharmony_ci */ 885d5ac70f0Sopenharmony_ciint snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv) 886d5ac70f0Sopenharmony_ci{ 887d5ac70f0Sopenharmony_ci assert(elem); 888d5ac70f0Sopenharmony_ci assert(tlv); 889d5ac70f0Sopenharmony_ci assert(tlv[SNDRV_CTL_TLVO_LEN] >= 4); 890d5ac70f0Sopenharmony_ci return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv); 891d5ac70f0Sopenharmony_ci} 892d5ac70f0Sopenharmony_ci 893d5ac70f0Sopenharmony_ci/** 894d5ac70f0Sopenharmony_ci * \brief Get HCTL handle for an HCTL element 895d5ac70f0Sopenharmony_ci * \param elem HCTL element 896d5ac70f0Sopenharmony_ci * \return HCTL handle 897d5ac70f0Sopenharmony_ci */ 898d5ac70f0Sopenharmony_cisnd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) 899d5ac70f0Sopenharmony_ci{ 900d5ac70f0Sopenharmony_ci assert(elem); 901d5ac70f0Sopenharmony_ci return elem->hctl; 902d5ac70f0Sopenharmony_ci} 903d5ac70f0Sopenharmony_ci 904d5ac70f0Sopenharmony_ci/** 905d5ac70f0Sopenharmony_ci * \brief Get CTL element identifier of a CTL element id/value 906d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 907d5ac70f0Sopenharmony_ci * \param ptr Pointer to returned CTL element identifier 908d5ac70f0Sopenharmony_ci */ 909d5ac70f0Sopenharmony_civoid snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) 910d5ac70f0Sopenharmony_ci{ 911d5ac70f0Sopenharmony_ci assert(obj && ptr); 912d5ac70f0Sopenharmony_ci *ptr = obj->id; 913d5ac70f0Sopenharmony_ci} 914d5ac70f0Sopenharmony_ci 915d5ac70f0Sopenharmony_ci/** 916d5ac70f0Sopenharmony_ci * \brief Get element numeric identifier of a CTL element id/value 917d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 918d5ac70f0Sopenharmony_ci * \return element numeric identifier 919d5ac70f0Sopenharmony_ci */ 920d5ac70f0Sopenharmony_ciunsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) 921d5ac70f0Sopenharmony_ci{ 922d5ac70f0Sopenharmony_ci assert(obj); 923d5ac70f0Sopenharmony_ci return obj->id.numid; 924d5ac70f0Sopenharmony_ci} 925d5ac70f0Sopenharmony_ci 926d5ac70f0Sopenharmony_ci/** 927d5ac70f0Sopenharmony_ci * \brief Get interface part of CTL element identifier of a CTL element id/value 928d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 929d5ac70f0Sopenharmony_ci * \return interface part of element identifier 930d5ac70f0Sopenharmony_ci */ 931d5ac70f0Sopenharmony_cisnd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) 932d5ac70f0Sopenharmony_ci{ 933d5ac70f0Sopenharmony_ci assert(obj); 934d5ac70f0Sopenharmony_ci return obj->id.iface; 935d5ac70f0Sopenharmony_ci} 936d5ac70f0Sopenharmony_ci 937d5ac70f0Sopenharmony_ci/** 938d5ac70f0Sopenharmony_ci * \brief Get device part of CTL element identifier of a CTL element id/value 939d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 940d5ac70f0Sopenharmony_ci * \return device part of element identifier 941d5ac70f0Sopenharmony_ci */ 942d5ac70f0Sopenharmony_ciunsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) 943d5ac70f0Sopenharmony_ci{ 944d5ac70f0Sopenharmony_ci assert(obj); 945d5ac70f0Sopenharmony_ci return obj->id.device; 946d5ac70f0Sopenharmony_ci} 947d5ac70f0Sopenharmony_ci 948d5ac70f0Sopenharmony_ci/** 949d5ac70f0Sopenharmony_ci * \brief Get subdevice part of CTL element identifier of a CTL element id/value 950d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 951d5ac70f0Sopenharmony_ci * \return subdevice part of element identifier 952d5ac70f0Sopenharmony_ci */ 953d5ac70f0Sopenharmony_ciunsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) 954d5ac70f0Sopenharmony_ci{ 955d5ac70f0Sopenharmony_ci assert(obj); 956d5ac70f0Sopenharmony_ci return obj->id.subdevice; 957d5ac70f0Sopenharmony_ci} 958d5ac70f0Sopenharmony_ci 959d5ac70f0Sopenharmony_ci/** 960d5ac70f0Sopenharmony_ci * \brief Get name part of CTL element identifier of a CTL element id/value 961d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 962d5ac70f0Sopenharmony_ci * \return name part of element identifier 963d5ac70f0Sopenharmony_ci */ 964d5ac70f0Sopenharmony_ciconst char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) 965d5ac70f0Sopenharmony_ci{ 966d5ac70f0Sopenharmony_ci assert(obj); 967d5ac70f0Sopenharmony_ci return (const char *)obj->id.name; 968d5ac70f0Sopenharmony_ci} 969d5ac70f0Sopenharmony_ci 970d5ac70f0Sopenharmony_ci/** 971d5ac70f0Sopenharmony_ci * \brief Get index part of CTL element identifier of a CTL element id/value 972d5ac70f0Sopenharmony_ci * \param obj CTL element id/value 973d5ac70f0Sopenharmony_ci * \return index part of element identifier 974d5ac70f0Sopenharmony_ci */ 975d5ac70f0Sopenharmony_ciunsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj) 976d5ac70f0Sopenharmony_ci{ 977d5ac70f0Sopenharmony_ci assert(obj); 978d5ac70f0Sopenharmony_ci return obj->id.index; 979d5ac70f0Sopenharmony_ci} 980d5ac70f0Sopenharmony_ci 981d5ac70f0Sopenharmony_ci/** 982d5ac70f0Sopenharmony_ci * \brief Set callback function for an HCTL element 983d5ac70f0Sopenharmony_ci * \param obj HCTL element 984d5ac70f0Sopenharmony_ci * \param val callback function 985d5ac70f0Sopenharmony_ci */ 986d5ac70f0Sopenharmony_civoid snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val) 987d5ac70f0Sopenharmony_ci{ 988d5ac70f0Sopenharmony_ci assert(obj); 989d5ac70f0Sopenharmony_ci obj->callback = val; 990d5ac70f0Sopenharmony_ci} 991d5ac70f0Sopenharmony_ci 992d5ac70f0Sopenharmony_ci/** 993d5ac70f0Sopenharmony_ci * \brief Set callback private value for an HCTL element 994d5ac70f0Sopenharmony_ci * \param obj HCTL element 995d5ac70f0Sopenharmony_ci * \param val callback private value 996d5ac70f0Sopenharmony_ci */ 997d5ac70f0Sopenharmony_civoid snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val) 998d5ac70f0Sopenharmony_ci{ 999d5ac70f0Sopenharmony_ci assert(obj); 1000d5ac70f0Sopenharmony_ci obj->callback_private = val; 1001d5ac70f0Sopenharmony_ci} 1002d5ac70f0Sopenharmony_ci 1003d5ac70f0Sopenharmony_ci/** 1004d5ac70f0Sopenharmony_ci * \brief Get callback private value for an HCTL element 1005d5ac70f0Sopenharmony_ci * \param obj HCTL element 1006d5ac70f0Sopenharmony_ci * \return callback private value 1007d5ac70f0Sopenharmony_ci */ 1008d5ac70f0Sopenharmony_civoid * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj) 1009d5ac70f0Sopenharmony_ci{ 1010d5ac70f0Sopenharmony_ci assert(obj); 1011d5ac70f0Sopenharmony_ci return obj->callback_private; 1012d5ac70f0Sopenharmony_ci} 1013d5ac70f0Sopenharmony_ci 1014