1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file mixer/simple_abst.c 3d5ac70f0Sopenharmony_ci * \brief Mixer Simple Element Class Interface - Module Abstraction 4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 5d5ac70f0Sopenharmony_ci * \date 2005 6d5ac70f0Sopenharmony_ci * 7d5ac70f0Sopenharmony_ci * Mixer simple element class interface. 8d5ac70f0Sopenharmony_ci */ 9d5ac70f0Sopenharmony_ci/* 10d5ac70f0Sopenharmony_ci * Mixer Interface - simple controls - abstraction module 11d5ac70f0Sopenharmony_ci * Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz> 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 "mixer_local.h" 31d5ac70f0Sopenharmony_ci#include "mixer_simple.h" 32d5ac70f0Sopenharmony_ci#include <stdio.h> 33d5ac70f0Sopenharmony_ci#include <stdlib.h> 34d5ac70f0Sopenharmony_ci#include <unistd.h> 35d5ac70f0Sopenharmony_ci#include <string.h> 36d5ac70f0Sopenharmony_ci#include <fcntl.h> 37d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 38d5ac70f0Sopenharmony_ci#include <math.h> 39d5ac70f0Sopenharmony_ci#include <dlfcn.h> 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ci#define SO_PATH "smixer" 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_citypedef struct _class_priv { 46d5ac70f0Sopenharmony_ci char *device; 47d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 48d5ac70f0Sopenharmony_ci snd_hctl_t *hctl; 49d5ac70f0Sopenharmony_ci int attach_flag; 50d5ac70f0Sopenharmony_ci snd_ctl_card_info_t *info; 51d5ac70f0Sopenharmony_ci void *dlhandle; 52d5ac70f0Sopenharmony_ci void *private_data; 53d5ac70f0Sopenharmony_ci void (*private_free)(snd_mixer_class_t *class); 54d5ac70f0Sopenharmony_ci} class_priv_t; 55d5ac70f0Sopenharmony_ci 56d5ac70f0Sopenharmony_citypedef int (*snd_mixer_sbasic_init_t)(snd_mixer_class_t *class); 57d5ac70f0Sopenharmony_citypedef int (*snd_mixer_sfbasic_init_t)(snd_mixer_class_t *class, 58d5ac70f0Sopenharmony_ci snd_mixer_t *mixer, 59d5ac70f0Sopenharmony_ci const char *device); 60d5ac70f0Sopenharmony_ci 61d5ac70f0Sopenharmony_ci#endif /* !DOC_HIDDEN */ 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_cistatic int try_open(snd_mixer_class_t *class, const char *lib) 64d5ac70f0Sopenharmony_ci{ 65d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 66d5ac70f0Sopenharmony_ci snd_mixer_event_t event_func; 67d5ac70f0Sopenharmony_ci snd_mixer_sbasic_init_t init_func = NULL; 68d5ac70f0Sopenharmony_ci char *xlib, *path, errbuf[256]; 69d5ac70f0Sopenharmony_ci void *h; 70d5ac70f0Sopenharmony_ci int err = 0; 71d5ac70f0Sopenharmony_ci 72d5ac70f0Sopenharmony_ci if (!lib) 73d5ac70f0Sopenharmony_ci return -ENXIO; 74d5ac70f0Sopenharmony_ci path = getenv("ALSA_MIXER_SIMPLE_MODULES"); 75d5ac70f0Sopenharmony_ci if (!path) 76d5ac70f0Sopenharmony_ci path = SO_PATH; 77d5ac70f0Sopenharmony_ci xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); 78d5ac70f0Sopenharmony_ci if (xlib == NULL) 79d5ac70f0Sopenharmony_ci return -ENOMEM; 80d5ac70f0Sopenharmony_ci strcpy(xlib, path); 81d5ac70f0Sopenharmony_ci strcat(xlib, "/"); 82d5ac70f0Sopenharmony_ci strcat(xlib, lib); 83d5ac70f0Sopenharmony_ci h = INTERNAL(snd_dlopen)(xlib, RTLD_NOW, errbuf, sizeof(errbuf)); 84d5ac70f0Sopenharmony_ci if (h == NULL) { 85d5ac70f0Sopenharmony_ci SNDERR("Unable to open library '%s' (%s)", xlib, errbuf); 86d5ac70f0Sopenharmony_ci free(xlib); 87d5ac70f0Sopenharmony_ci return -ENXIO; 88d5ac70f0Sopenharmony_ci } 89d5ac70f0Sopenharmony_ci priv->dlhandle = h; 90d5ac70f0Sopenharmony_ci event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); 91d5ac70f0Sopenharmony_ci if (event_func == NULL) { 92d5ac70f0Sopenharmony_ci SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); 93d5ac70f0Sopenharmony_ci err = -ENXIO; 94d5ac70f0Sopenharmony_ci } 95d5ac70f0Sopenharmony_ci if (err == 0) { 96d5ac70f0Sopenharmony_ci init_func = snd_dlsym(h, "alsa_mixer_simple_init", NULL); 97d5ac70f0Sopenharmony_ci if (init_func == NULL) { 98d5ac70f0Sopenharmony_ci SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib); 99d5ac70f0Sopenharmony_ci err = -ENXIO; 100d5ac70f0Sopenharmony_ci } 101d5ac70f0Sopenharmony_ci } 102d5ac70f0Sopenharmony_ci free(xlib); 103d5ac70f0Sopenharmony_ci err = err == 0 ? init_func(class) : err; 104d5ac70f0Sopenharmony_ci if (err < 0) 105d5ac70f0Sopenharmony_ci return err; 106d5ac70f0Sopenharmony_ci snd_mixer_class_set_event(class, event_func); 107d5ac70f0Sopenharmony_ci return 1; 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_cistatic int try_open_full(snd_mixer_class_t *class, snd_mixer_t *mixer, 111d5ac70f0Sopenharmony_ci const char *lib, const char *device) 112d5ac70f0Sopenharmony_ci{ 113d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 114d5ac70f0Sopenharmony_ci snd_mixer_event_t event_func; 115d5ac70f0Sopenharmony_ci snd_mixer_sfbasic_init_t init_func = NULL; 116d5ac70f0Sopenharmony_ci char *xlib, *path, errbuf[256]; 117d5ac70f0Sopenharmony_ci void *h; 118d5ac70f0Sopenharmony_ci int err = 0; 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ci path = getenv("ALSA_MIXER_SIMPLE_MODULES"); 121d5ac70f0Sopenharmony_ci if (!path) 122d5ac70f0Sopenharmony_ci path = SO_PATH; 123d5ac70f0Sopenharmony_ci xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); 124d5ac70f0Sopenharmony_ci if (xlib == NULL) 125d5ac70f0Sopenharmony_ci return -ENOMEM; 126d5ac70f0Sopenharmony_ci strcpy(xlib, path); 127d5ac70f0Sopenharmony_ci strcat(xlib, "/"); 128d5ac70f0Sopenharmony_ci strcat(xlib, lib); 129d5ac70f0Sopenharmony_ci /* note python modules requires RTLD_GLOBAL */ 130d5ac70f0Sopenharmony_ci h = INTERNAL(snd_dlopen)(xlib, RTLD_NOW|RTLD_GLOBAL, errbuf, sizeof(errbuf)); 131d5ac70f0Sopenharmony_ci if (h == NULL) { 132d5ac70f0Sopenharmony_ci SNDERR("Unable to open library '%s'", xlib); 133d5ac70f0Sopenharmony_ci free(xlib); 134d5ac70f0Sopenharmony_ci return -ENXIO; 135d5ac70f0Sopenharmony_ci } 136d5ac70f0Sopenharmony_ci priv->dlhandle = h; 137d5ac70f0Sopenharmony_ci event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); 138d5ac70f0Sopenharmony_ci if (event_func == NULL) { 139d5ac70f0Sopenharmony_ci SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); 140d5ac70f0Sopenharmony_ci err = -ENXIO; 141d5ac70f0Sopenharmony_ci } 142d5ac70f0Sopenharmony_ci if (err == 0) { 143d5ac70f0Sopenharmony_ci init_func = snd_dlsym(h, "alsa_mixer_simple_finit", NULL); 144d5ac70f0Sopenharmony_ci if (init_func == NULL) { 145d5ac70f0Sopenharmony_ci SNDERR("Symbol 'alsa_mixer_simple_finit' was not found in '%s'", xlib); 146d5ac70f0Sopenharmony_ci err = -ENXIO; 147d5ac70f0Sopenharmony_ci } 148d5ac70f0Sopenharmony_ci } 149d5ac70f0Sopenharmony_ci free(xlib); 150d5ac70f0Sopenharmony_ci err = err == 0 ? init_func(class, mixer, device) : err; 151d5ac70f0Sopenharmony_ci if (err < 0) 152d5ac70f0Sopenharmony_ci return err; 153d5ac70f0Sopenharmony_ci snd_mixer_class_set_event(class, event_func); 154d5ac70f0Sopenharmony_ci return 1; 155d5ac70f0Sopenharmony_ci} 156d5ac70f0Sopenharmony_ci 157d5ac70f0Sopenharmony_cistatic int match(snd_mixer_class_t *class, const char *lib, const char *searchl) 158d5ac70f0Sopenharmony_ci{ 159d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 160d5ac70f0Sopenharmony_ci const char *components; 161d5ac70f0Sopenharmony_ci 162d5ac70f0Sopenharmony_ci if (searchl == NULL) 163d5ac70f0Sopenharmony_ci return try_open(class, lib); 164d5ac70f0Sopenharmony_ci components = snd_ctl_card_info_get_components(priv->info); 165d5ac70f0Sopenharmony_ci while (*components != '\0') { 166d5ac70f0Sopenharmony_ci if (!strncmp(components, searchl, strlen(searchl))) 167d5ac70f0Sopenharmony_ci return try_open(class, lib); 168d5ac70f0Sopenharmony_ci while (*components != ' ' && *components != '\0') 169d5ac70f0Sopenharmony_ci components++; 170d5ac70f0Sopenharmony_ci while (*components == ' ' && *components != '\0') 171d5ac70f0Sopenharmony_ci components++; 172d5ac70f0Sopenharmony_ci } 173d5ac70f0Sopenharmony_ci return 0; 174d5ac70f0Sopenharmony_ci} 175d5ac70f0Sopenharmony_ci 176d5ac70f0Sopenharmony_cistatic int find_full(snd_mixer_class_t *class, snd_mixer_t *mixer, 177d5ac70f0Sopenharmony_ci snd_config_t *top, const char *device) 178d5ac70f0Sopenharmony_ci{ 179d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 180d5ac70f0Sopenharmony_ci char *lib; 181d5ac70f0Sopenharmony_ci const char *id; 182d5ac70f0Sopenharmony_ci int err; 183d5ac70f0Sopenharmony_ci 184d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, top) { 185d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 186d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 187d5ac70f0Sopenharmony_ci continue; 188d5ac70f0Sopenharmony_ci if (strcmp(id, "_full")) 189d5ac70f0Sopenharmony_ci continue; 190d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, (const char **)&lib); 191d5ac70f0Sopenharmony_ci if (err < 0) 192d5ac70f0Sopenharmony_ci return err; 193d5ac70f0Sopenharmony_ci err = try_open_full(class, mixer, lib, device); 194d5ac70f0Sopenharmony_ci if (err < 0) 195d5ac70f0Sopenharmony_ci return err; 196d5ac70f0Sopenharmony_ci return 0; 197d5ac70f0Sopenharmony_ci } 198d5ac70f0Sopenharmony_ci return -ENOENT; 199d5ac70f0Sopenharmony_ci} 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_cistatic int find_module(snd_mixer_class_t *class, snd_config_t *top) 202d5ac70f0Sopenharmony_ci{ 203d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 204d5ac70f0Sopenharmony_ci snd_config_iterator_t j, jnext; 205d5ac70f0Sopenharmony_ci char *lib, *searchl; 206d5ac70f0Sopenharmony_ci const char *id; 207d5ac70f0Sopenharmony_ci int err; 208d5ac70f0Sopenharmony_ci 209d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, top) { 210d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 211d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 212d5ac70f0Sopenharmony_ci continue; 213d5ac70f0Sopenharmony_ci if (*id == '_') 214d5ac70f0Sopenharmony_ci continue; 215d5ac70f0Sopenharmony_ci searchl = NULL; 216d5ac70f0Sopenharmony_ci lib = NULL; 217d5ac70f0Sopenharmony_ci snd_config_for_each(j, jnext, n) { 218d5ac70f0Sopenharmony_ci snd_config_t *m = snd_config_iterator_entry(j); 219d5ac70f0Sopenharmony_ci if (snd_config_get_id(m, &id) < 0) 220d5ac70f0Sopenharmony_ci continue; 221d5ac70f0Sopenharmony_ci if (!strcmp(id, "searchl")) { 222d5ac70f0Sopenharmony_ci err = snd_config_get_string(m, (const char **)&searchl); 223d5ac70f0Sopenharmony_ci if (err < 0) 224d5ac70f0Sopenharmony_ci return err; 225d5ac70f0Sopenharmony_ci continue; 226d5ac70f0Sopenharmony_ci } 227d5ac70f0Sopenharmony_ci if (!strcmp(id, "lib")) { 228d5ac70f0Sopenharmony_ci err = snd_config_get_string(m, (const char **)&lib); 229d5ac70f0Sopenharmony_ci if (err < 0) 230d5ac70f0Sopenharmony_ci return err; 231d5ac70f0Sopenharmony_ci continue; 232d5ac70f0Sopenharmony_ci } 233d5ac70f0Sopenharmony_ci } 234d5ac70f0Sopenharmony_ci err = match(class, lib, searchl); 235d5ac70f0Sopenharmony_ci if (err == 1) 236d5ac70f0Sopenharmony_ci return 0; 237d5ac70f0Sopenharmony_ci if (err < 0) 238d5ac70f0Sopenharmony_ci return err; 239d5ac70f0Sopenharmony_ci } 240d5ac70f0Sopenharmony_ci return -ENOENT; 241d5ac70f0Sopenharmony_ci} 242d5ac70f0Sopenharmony_ci 243d5ac70f0Sopenharmony_cistatic void private_free(snd_mixer_class_t *class) 244d5ac70f0Sopenharmony_ci{ 245d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 246d5ac70f0Sopenharmony_ci 247d5ac70f0Sopenharmony_ci if (priv->private_free) 248d5ac70f0Sopenharmony_ci priv->private_free(class); 249d5ac70f0Sopenharmony_ci if (priv->dlhandle) 250d5ac70f0Sopenharmony_ci snd_dlclose(priv->dlhandle); 251d5ac70f0Sopenharmony_ci if (priv->info) 252d5ac70f0Sopenharmony_ci snd_ctl_card_info_free(priv->info); 253d5ac70f0Sopenharmony_ci if (priv->hctl) { 254d5ac70f0Sopenharmony_ci if (priv->attach_flag) 255d5ac70f0Sopenharmony_ci snd_mixer_detach_hctl(snd_mixer_class_get_mixer(class), priv->hctl); 256d5ac70f0Sopenharmony_ci snd_hctl_close(priv->hctl); 257d5ac70f0Sopenharmony_ci } else if (priv->ctl) 258d5ac70f0Sopenharmony_ci snd_ctl_close(priv->ctl); 259d5ac70f0Sopenharmony_ci free(priv->device); 260d5ac70f0Sopenharmony_ci free(priv); 261d5ac70f0Sopenharmony_ci} 262d5ac70f0Sopenharmony_ci 263d5ac70f0Sopenharmony_ci/** 264d5ac70f0Sopenharmony_ci * \brief Register mixer simple element class - basic abstraction 265d5ac70f0Sopenharmony_ci * \param mixer Mixer handle 266d5ac70f0Sopenharmony_ci * \param options Options container 267d5ac70f0Sopenharmony_ci * \param classp Pointer to returned mixer simple element class handle (or NULL 268d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 269d5ac70f0Sopenharmony_ci */ 270d5ac70f0Sopenharmony_ciint snd_mixer_simple_basic_register(snd_mixer_t *mixer, 271d5ac70f0Sopenharmony_ci struct snd_mixer_selem_regopt *options, 272d5ac70f0Sopenharmony_ci snd_mixer_class_t **classp) 273d5ac70f0Sopenharmony_ci{ 274d5ac70f0Sopenharmony_ci snd_mixer_class_t *class; 275d5ac70f0Sopenharmony_ci class_priv_t *priv = calloc(1, sizeof(*priv)); 276d5ac70f0Sopenharmony_ci const char *file; 277d5ac70f0Sopenharmony_ci snd_input_t *input; 278d5ac70f0Sopenharmony_ci snd_config_t *top = NULL; 279d5ac70f0Sopenharmony_ci int err; 280d5ac70f0Sopenharmony_ci 281d5ac70f0Sopenharmony_ci if (priv == NULL) 282d5ac70f0Sopenharmony_ci return -ENOMEM; 283d5ac70f0Sopenharmony_ci if (options->device == NULL) { 284d5ac70f0Sopenharmony_ci free(priv); 285d5ac70f0Sopenharmony_ci return -EINVAL; 286d5ac70f0Sopenharmony_ci } 287d5ac70f0Sopenharmony_ci if (snd_mixer_class_malloc(&class)) { 288d5ac70f0Sopenharmony_ci free(priv); 289d5ac70f0Sopenharmony_ci return -ENOMEM; 290d5ac70f0Sopenharmony_ci } 291d5ac70f0Sopenharmony_ci priv->device = strdup(options->device); 292d5ac70f0Sopenharmony_ci if (priv->device == NULL) { 293d5ac70f0Sopenharmony_ci free(priv); 294d5ac70f0Sopenharmony_ci snd_mixer_class_free(class); 295d5ac70f0Sopenharmony_ci return -ENOMEM; 296d5ac70f0Sopenharmony_ci } 297d5ac70f0Sopenharmony_ci snd_mixer_class_set_compare(class, snd_mixer_selem_compare); 298d5ac70f0Sopenharmony_ci snd_mixer_class_set_private(class, priv); 299d5ac70f0Sopenharmony_ci snd_mixer_class_set_private_free(class, private_free); 300d5ac70f0Sopenharmony_ci file = getenv("ALSA_MIXER_SIMPLE"); 301d5ac70f0Sopenharmony_ci if (!file) { 302d5ac70f0Sopenharmony_ci const char *topdir = snd_config_topdir(); 303d5ac70f0Sopenharmony_ci char *s = alloca(strlen(topdir) + strlen("smixer.conf") + 2); 304d5ac70f0Sopenharmony_ci sprintf(s, "%s/smixer.conf", topdir); 305d5ac70f0Sopenharmony_ci file = s; 306d5ac70f0Sopenharmony_ci } 307d5ac70f0Sopenharmony_ci err = snd_config_top(&top); 308d5ac70f0Sopenharmony_ci if (err >= 0) { 309d5ac70f0Sopenharmony_ci err = snd_input_stdio_open(&input, file, "r"); 310d5ac70f0Sopenharmony_ci if (err < 0) { 311d5ac70f0Sopenharmony_ci SNDERR("unable to open simple mixer configuration file '%s'", file); 312d5ac70f0Sopenharmony_ci goto __error; 313d5ac70f0Sopenharmony_ci } 314d5ac70f0Sopenharmony_ci err = snd_config_load(top, input); 315d5ac70f0Sopenharmony_ci snd_input_close(input); 316d5ac70f0Sopenharmony_ci if (err < 0) { 317d5ac70f0Sopenharmony_ci SNDERR("%s may be old or corrupted: consider to remove or fix it", file); 318d5ac70f0Sopenharmony_ci goto __error; 319d5ac70f0Sopenharmony_ci } 320d5ac70f0Sopenharmony_ci err = find_full(class, mixer, top, priv->device); 321d5ac70f0Sopenharmony_ci if (err >= 0) 322d5ac70f0Sopenharmony_ci goto __full; 323d5ac70f0Sopenharmony_ci } 324d5ac70f0Sopenharmony_ci if (err >= 0) { 325d5ac70f0Sopenharmony_ci err = snd_ctl_open(&priv->ctl, priv->device, 0); 326d5ac70f0Sopenharmony_ci if (err < 0) { 327d5ac70f0Sopenharmony_ci SNDERR("unable to open control device '%s': %s", priv->device, snd_strerror(err)); 328d5ac70f0Sopenharmony_ci goto __error; 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci err = snd_hctl_open_ctl(&priv->hctl, priv->ctl); 331d5ac70f0Sopenharmony_ci if (err < 0) 332d5ac70f0Sopenharmony_ci goto __error; 333d5ac70f0Sopenharmony_ci err = snd_ctl_card_info_malloc(&priv->info); 334d5ac70f0Sopenharmony_ci if (err < 0) 335d5ac70f0Sopenharmony_ci goto __error; 336d5ac70f0Sopenharmony_ci err = snd_ctl_card_info(priv->ctl, priv->info); 337d5ac70f0Sopenharmony_ci if (err < 0) 338d5ac70f0Sopenharmony_ci goto __error; 339d5ac70f0Sopenharmony_ci } 340d5ac70f0Sopenharmony_ci if (err >= 0) 341d5ac70f0Sopenharmony_ci err = find_module(class, top); 342d5ac70f0Sopenharmony_ci if (err >= 0) 343d5ac70f0Sopenharmony_ci err = snd_mixer_attach_hctl(mixer, priv->hctl); 344d5ac70f0Sopenharmony_ci if (err >= 0) { 345d5ac70f0Sopenharmony_ci priv->attach_flag = 1; 346d5ac70f0Sopenharmony_ci err = snd_mixer_class_register(class, mixer); 347d5ac70f0Sopenharmony_ci } 348d5ac70f0Sopenharmony_ci __full: 349d5ac70f0Sopenharmony_ci if (err < 0) { 350d5ac70f0Sopenharmony_ci __error: 351d5ac70f0Sopenharmony_ci if (top) 352d5ac70f0Sopenharmony_ci snd_config_delete(top); 353d5ac70f0Sopenharmony_ci if (class) 354d5ac70f0Sopenharmony_ci snd_mixer_class_free(class); 355d5ac70f0Sopenharmony_ci return err; 356d5ac70f0Sopenharmony_ci } 357d5ac70f0Sopenharmony_ci if (top) 358d5ac70f0Sopenharmony_ci snd_config_delete(top); 359d5ac70f0Sopenharmony_ci if (classp) 360d5ac70f0Sopenharmony_ci *classp = class; 361d5ac70f0Sopenharmony_ci return 0; 362d5ac70f0Sopenharmony_ci} 363d5ac70f0Sopenharmony_ci 364d5ac70f0Sopenharmony_ci/** 365d5ac70f0Sopenharmony_ci * \brief Basic Mixer Abstraction - Get information about device 366d5ac70f0Sopenharmony_ci * \param class Mixer class 367d5ac70f0Sopenharmony_ci * \param info Info structure 368d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 369d5ac70f0Sopenharmony_ci */ 370d5ac70f0Sopenharmony_ciint snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info) 371d5ac70f0Sopenharmony_ci{ 372d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 373d5ac70f0Sopenharmony_ci 374d5ac70f0Sopenharmony_ci if (class == NULL || info == NULL) 375d5ac70f0Sopenharmony_ci return -EINVAL; 376d5ac70f0Sopenharmony_ci info->device = priv->device; 377d5ac70f0Sopenharmony_ci info->ctl = priv->ctl; 378d5ac70f0Sopenharmony_ci info->hctl = priv->hctl; 379d5ac70f0Sopenharmony_ci info->info = priv->info; 380d5ac70f0Sopenharmony_ci return 0; 381d5ac70f0Sopenharmony_ci} 382d5ac70f0Sopenharmony_ci 383d5ac70f0Sopenharmony_ci/** 384d5ac70f0Sopenharmony_ci * \brief Get private data for basic abstraction 385d5ac70f0Sopenharmony_ci * \param class Mixer class 386d5ac70f0Sopenharmony_ci * \return private data 387d5ac70f0Sopenharmony_ci */ 388d5ac70f0Sopenharmony_civoid *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class) 389d5ac70f0Sopenharmony_ci{ 390d5ac70f0Sopenharmony_ci class_priv_t *priv = snd_mixer_class_get_private(class); 391d5ac70f0Sopenharmony_ci 392d5ac70f0Sopenharmony_ci if (class == NULL) 393d5ac70f0Sopenharmony_ci return NULL; 394d5ac70f0Sopenharmony_ci return priv->private_data; 395d5ac70f0Sopenharmony_ci} 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ci/** 398d5ac70f0Sopenharmony_ci * \brief Set private data for basic abstraction 399d5ac70f0Sopenharmony_ci * \param class Mixer class 400d5ac70f0Sopenharmony_ci * \param private_data Private data 401d5ac70f0Sopenharmony_ci */ 402d5ac70f0Sopenharmony_civoid snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data) 403d5ac70f0Sopenharmony_ci{ 404d5ac70f0Sopenharmony_ci class_priv_t *priv; 405d5ac70f0Sopenharmony_ci 406d5ac70f0Sopenharmony_ci if (class == NULL) 407d5ac70f0Sopenharmony_ci return; 408d5ac70f0Sopenharmony_ci priv = snd_mixer_class_get_private(class); 409d5ac70f0Sopenharmony_ci priv->private_data = private_data; 410d5ac70f0Sopenharmony_ci} 411d5ac70f0Sopenharmony_ci 412d5ac70f0Sopenharmony_ci/** 413d5ac70f0Sopenharmony_ci * \brief Set private data free callback for basic abstraction 414d5ac70f0Sopenharmony_ci * \param class Mixer class 415d5ac70f0Sopenharmony_ci * \param private_free free callback for private data 416d5ac70f0Sopenharmony_ci */ 417d5ac70f0Sopenharmony_civoid snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)) 418d5ac70f0Sopenharmony_ci{ 419d5ac70f0Sopenharmony_ci class_priv_t *priv; 420d5ac70f0Sopenharmony_ci 421d5ac70f0Sopenharmony_ci if (class == NULL) 422d5ac70f0Sopenharmony_ci return; 423d5ac70f0Sopenharmony_ci priv = snd_mixer_class_get_private(class); 424d5ac70f0Sopenharmony_ci priv->private_free = private_free; 425d5ac70f0Sopenharmony_ci} 426