libs/alsa-lib-1.0.13/src/mixer/simple_abst.c

Go to the documentation of this file.
00001 
00009 /*
00010  *  Mixer Interface - simple controls - abstraction module
00011  *  Copyright (c) 2005 by Jaroslav Kysela <perex@suse.cz>
00012  *
00013  *
00014  *   This library is free software; you can redistribute it and/or modify
00015  *   it under the terms of the GNU Lesser General Public License as
00016  *   published by the Free Software Foundation; either version 2.1 of
00017  *   the License, or (at your option) any later version.
00018  *
00019  *   This program is distributed in the hope that it will be useful,
00020  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  *   GNU Lesser General Public License for more details.
00023  *
00024  *   You should have received a copy of the GNU Lesser General Public
00025  *   License along with this library; if not, write to the Free Software
00026  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00027  *
00028  */
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include <string.h>
00034 #include <fcntl.h>
00035 #include <sys/ioctl.h>
00036 #include <math.h>
00037 #include <dlfcn.h>
00038 #include "config.h"
00039 #include "asoundlib.h"
00040 #include "mixer_simple.h"
00041 
00042 #ifndef DOC_HIDDEN
00043 
00044 #define SO_PATH PKGLIBDIR "/smixer"
00045 
00046 typedef struct _class_priv {
00047         char *device;
00048         snd_ctl_t *ctl;
00049         snd_hctl_t *hctl;
00050         int attach_flag;
00051         snd_ctl_card_info_t *info;
00052         void *dlhandle;
00053         void *private_data;
00054         void (*private_free)(snd_mixer_class_t *class);
00055 } class_priv_t;
00056 
00057 typedef int (*snd_mixer_sbasic_init_t)(snd_mixer_class_t *class);
00058 
00059 #endif /* !DOC_HIDDEN */
00060 
00061 static int try_open(snd_mixer_class_t *class, const char *lib)
00062 {
00063         class_priv_t *priv = snd_mixer_class_get_private(class);
00064         snd_mixer_event_t event_func;
00065         snd_mixer_sbasic_init_t init_func;
00066         char *xlib, *path;
00067         void *h;
00068         int err;
00069 
00070         path = getenv("ALSA_MIXER_SIMPLE_MODULES");
00071         if (!path)
00072                 path = SO_PATH;
00073         xlib = malloc(strlen(lib) + strlen(path) + 1 + 1);
00074         if (xlib == NULL)
00075                 return -ENOMEM;
00076         strcpy(xlib, path);
00077         strcat(xlib, "/");
00078         strcat(xlib, lib);
00079         h = snd_dlopen(xlib, RTLD_NOW);
00080         if (h == NULL) {
00081                 SNDERR("Unable to open library '%s'", xlib);
00082                 free(xlib);
00083                 return -ENXIO;
00084         }
00085         event_func = dlsym(h, "alsa_mixer_simple_event");
00086         if (event_func == NULL) {
00087                 SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib);
00088                 snd_dlclose(h);
00089                 free(xlib);
00090                 return -ENXIO;
00091         }
00092         init_func = dlsym(h, "alsa_mixer_simple_init");
00093         if (init_func == NULL) {
00094                 SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib);
00095                 snd_dlclose(h);
00096                 free(xlib);
00097                 return -ENXIO;
00098         }
00099         free(xlib);
00100         err = init_func(class);
00101         if (err < 0) {
00102                 snd_dlclose(h);
00103                 return err;
00104         }
00105         snd_mixer_class_set_event(class, event_func);
00106         priv->dlhandle = h;
00107         return 1;
00108 }
00109 
00110 static int match(snd_mixer_class_t *class, const char *lib, const char *searchl)
00111 {
00112         class_priv_t *priv = snd_mixer_class_get_private(class);
00113         const char *components;
00114 
00115         if (searchl == NULL)
00116                 return try_open(class, lib);
00117         components = snd_ctl_card_info_get_components(priv->info);
00118         while (*components != '\0') {
00119                 if (!strncmp(components, searchl, strlen(searchl)))
00120                         return try_open(class, lib);
00121                 while (*components != ' ' && *components != '\0')
00122                         components++;
00123                 while (*components == ' ' && *components != '\0')
00124                         components++;
00125         }
00126         return 0;
00127 }
00128 
00129 static int find_module(snd_mixer_class_t *class, snd_config_t *top)
00130 {
00131         snd_config_iterator_t i, next;
00132         snd_config_iterator_t j, jnext;
00133         char *lib, *searchl;
00134         const char *id;
00135         int err;
00136 
00137         snd_config_for_each(i, next, top) {
00138                 snd_config_t *n = snd_config_iterator_entry(i);
00139                 if (snd_config_get_id(n, &id) < 0)
00140                         continue;
00141                 searchl = NULL;
00142                 lib = NULL;
00143                 snd_config_for_each(j, jnext, n) {
00144                         snd_config_t *m = snd_config_iterator_entry(j);
00145                         if (snd_config_get_id(m, &id) < 0)
00146                                 continue;
00147                         if (!strcmp(id, "searchl")) {
00148                                 err = snd_config_get_string(m, (const char **)&searchl);
00149                                 if (err < 0)
00150                                         return err;
00151                                 continue;
00152                         }
00153                         if (!strcmp(id, "lib")) {
00154                                 err = snd_config_get_string(m, (const char **)&lib);
00155                                 if (err < 0)
00156                                         return err;
00157                                 continue;
00158                         }
00159                 }
00160                 err = match(class, lib, searchl);
00161                 if (err == 1)
00162                         return 0;
00163                 if (err < 0)
00164                         return err;
00165         }
00166         return -ENOENT;
00167 }
00168 
00169 static void private_free(snd_mixer_class_t *class)
00170 {
00171         class_priv_t *priv = snd_mixer_class_get_private(class);
00172         
00173         if (priv->private_free)
00174                 priv->private_free(class);
00175         if (priv->dlhandle)
00176                 snd_dlclose(priv->dlhandle);
00177         if (priv->info)
00178                 snd_ctl_card_info_free(priv->info);
00179         if (priv->hctl) {
00180                 if (priv->attach_flag)
00181                         snd_mixer_detach_hctl(snd_mixer_class_get_mixer(class), priv->hctl);
00182                 snd_hctl_close(priv->hctl);
00183         } else if (priv->ctl)
00184                 snd_ctl_close(priv->ctl);
00185         free(priv->device);
00186         free(priv);
00187 }
00188 
00196 int snd_mixer_simple_basic_register(snd_mixer_t *mixer,
00197                                     struct snd_mixer_selem_regopt *options,
00198                                     snd_mixer_class_t **classp)
00199 {
00200         snd_mixer_class_t *class;
00201         class_priv_t *priv = calloc(1, sizeof(*priv));
00202         const char *file;
00203         snd_input_t *input;
00204         snd_config_t *top = NULL;
00205         int err;
00206 
00207         if (priv == NULL)
00208                 return -ENOMEM;
00209         if (options->device == NULL) {
00210                 free(priv);
00211                 return -EINVAL;
00212         }
00213         if (snd_mixer_class_malloc(&class)) {
00214                 free(priv);
00215                 return -ENOMEM;
00216         }
00217         priv->device = strdup(options->device);
00218         if (priv->device == NULL) {
00219                 free(priv);
00220                 snd_mixer_class_free(class);
00221                 return -ENOMEM;
00222         }
00223         snd_mixer_class_set_compare(class, snd_mixer_selem_compare);
00224         snd_mixer_class_set_private(class, priv);
00225         snd_mixer_class_set_private_free(class, private_free);
00226         err = snd_ctl_open(&priv->ctl, priv->device, 0);
00227         if (err < 0) {
00228                 SNDERR("unable to open control device '%s': %s", priv->device, snd_strerror(err));
00229                 goto __error;
00230         }
00231         err = snd_hctl_open_ctl(&priv->hctl, priv->ctl);
00232         if (err < 0)
00233                 goto __error;
00234         err = snd_ctl_card_info_malloc(&priv->info);
00235         if (err < 0)
00236                 goto __error;
00237         err = snd_ctl_card_info(priv->ctl, priv->info);
00238         if (err < 0)
00239                 goto __error;
00240         file = getenv("ALSA_MIXER_SIMPLE");
00241         if (!file)
00242                 file = "/share" "/alsa/smixer.conf";
00243         err = snd_config_top(&top);
00244         if (err >= 0) {
00245                 err = snd_input_stdio_open(&input, file, "r");
00246                 if (err < 0) {
00247                         SNDERR("unable to open simple mixer configuration file '%s'", file);
00248                         goto __error;
00249                 }
00250                 err = snd_config_load(top, input);
00251                 snd_input_close(input);
00252                 if (err < 0) {
00253                         SNDERR("%s may be old or corrupted: consider to remove or fix it", file);
00254                         goto __error;
00255                 }
00256                 err = find_module(class, top);
00257                 snd_config_delete(top);
00258                 top = NULL;
00259         }
00260         if (err >= 0)
00261                 err = snd_mixer_attach_hctl(mixer, priv->hctl);
00262         if (err >= 0) {
00263                 priv->attach_flag = 1;
00264                 err = snd_mixer_class_register(class, mixer);
00265         }
00266         if (err < 0) {
00267               __error:
00268                 if (top)
00269                         snd_config_delete(top);
00270                 if (class)
00271                         snd_mixer_class_free(class);
00272                 return err;
00273         }
00274         if (top)
00275                 snd_config_delete(top);
00276         if (classp)
00277                 *classp = class;
00278         return 0;
00279 }
00280 
00287 int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info)
00288 {
00289         class_priv_t *priv = snd_mixer_class_get_private(class);
00290 
00291         if (class == NULL || info == NULL)
00292                 return -EINVAL;
00293         info->device = priv->device;
00294         info->ctl = priv->ctl;
00295         info->hctl = priv->hctl;
00296         info->info = priv->info;
00297         return 0;
00298 }
00299 
00305 void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class)
00306 {
00307         class_priv_t *priv = snd_mixer_class_get_private(class);
00308 
00309         if (class == NULL)
00310                 return NULL;
00311         return priv->private_data;
00312 }
00313 
00319 void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data)
00320 {
00321         class_priv_t *priv;
00322 
00323         if (class == NULL)
00324                 return;
00325         priv = snd_mixer_class_get_private(class);
00326         priv->private_data = private_data;
00327 }
00328 
00334 void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class))
00335 {
00336         class_priv_t *priv;
00337 
00338         if (class == NULL)
00339                 return;
00340         priv = snd_mixer_class_get_private(class);
00341         priv->private_free = private_free;
00342 }

Generated on Fri Nov 28 00:06:23 2008 for elphel by  doxygen 1.5.1