1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * ALSA command line mixer utility 3c72fcc34Sopenharmony_ci * Copyright (c) 1999-2000 by Jaroslav Kysela <perex@perex.cz> 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 6c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 7c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8c72fcc34Sopenharmony_ci * (at your option) any later version. 9c72fcc34Sopenharmony_ci * 10c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 11c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c72fcc34Sopenharmony_ci * GNU General Public License for more details. 14c72fcc34Sopenharmony_ci * 15c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 16c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 17c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18c72fcc34Sopenharmony_ci * 19c72fcc34Sopenharmony_ci */ 20c72fcc34Sopenharmony_ci 21c72fcc34Sopenharmony_ci#include "aconfig.h" 22c72fcc34Sopenharmony_ci#include <stdio.h> 23c72fcc34Sopenharmony_ci#include <stdlib.h> 24c72fcc34Sopenharmony_ci#include <string.h> 25c72fcc34Sopenharmony_ci#include <getopt.h> 26c72fcc34Sopenharmony_ci#include <stdarg.h> 27c72fcc34Sopenharmony_ci#include <ctype.h> 28c72fcc34Sopenharmony_ci#include <math.h> 29c72fcc34Sopenharmony_ci#include <errno.h> 30c72fcc34Sopenharmony_ci#include <assert.h> 31c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h> 32c72fcc34Sopenharmony_ci#include <poll.h> 33c72fcc34Sopenharmony_ci#include <stdint.h> 34c72fcc34Sopenharmony_ci#include "amixer.h" 35c72fcc34Sopenharmony_ci#include "../alsamixer/volume_mapping.h" 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_ci#define LEVEL_BASIC (1<<0) 38c72fcc34Sopenharmony_ci#define LEVEL_INACTIVE (1<<1) 39c72fcc34Sopenharmony_ci#define LEVEL_ID (1<<2) 40c72fcc34Sopenharmony_ci 41c72fcc34Sopenharmony_cistatic int quiet = 0; 42c72fcc34Sopenharmony_cistatic int debugflag = 0; 43c72fcc34Sopenharmony_cistatic int no_check = 0; 44c72fcc34Sopenharmony_cistatic int smixer_level = 0; 45c72fcc34Sopenharmony_cistatic int ignore_error = 0; 46c72fcc34Sopenharmony_cistatic struct snd_mixer_selem_regopt smixer_options; 47c72fcc34Sopenharmony_cistatic char card[64] = "default"; 48c72fcc34Sopenharmony_ci 49c72fcc34Sopenharmony_cistatic void error(const char *fmt,...) 50c72fcc34Sopenharmony_ci{ 51c72fcc34Sopenharmony_ci va_list va; 52c72fcc34Sopenharmony_ci 53c72fcc34Sopenharmony_ci va_start(va, fmt); 54c72fcc34Sopenharmony_ci fprintf(stderr, "amixer: "); 55c72fcc34Sopenharmony_ci vfprintf(stderr, fmt, va); 56c72fcc34Sopenharmony_ci fprintf(stderr, "\n"); 57c72fcc34Sopenharmony_ci va_end(va); 58c72fcc34Sopenharmony_ci} 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_cistatic int help(void) 61c72fcc34Sopenharmony_ci{ 62c72fcc34Sopenharmony_ci printf("Usage: amixer <options> [command]\n"); 63c72fcc34Sopenharmony_ci printf("\nAvailable options:\n"); 64c72fcc34Sopenharmony_ci printf(" -h,--help this help\n"); 65c72fcc34Sopenharmony_ci printf(" -c,--card N select the card\n"); 66c72fcc34Sopenharmony_ci printf(" -D,--device N select the device, default '%s'\n", card); 67c72fcc34Sopenharmony_ci printf(" -d,--debug debug mode\n"); 68c72fcc34Sopenharmony_ci printf(" -n,--nocheck do not perform range checking\n"); 69c72fcc34Sopenharmony_ci printf(" -v,--version print version of this program\n"); 70c72fcc34Sopenharmony_ci printf(" -q,--quiet be quiet\n"); 71c72fcc34Sopenharmony_ci printf(" -i,--inactive show also inactive controls\n"); 72c72fcc34Sopenharmony_ci printf(" -a,--abstract L select abstraction level (none or basic)\n"); 73c72fcc34Sopenharmony_ci printf(" -s,--stdin Read and execute commands from stdin sequentially\n"); 74c72fcc34Sopenharmony_ci printf(" -R,--raw-volume Use the raw value (default)\n"); 75c72fcc34Sopenharmony_ci printf(" -M,--mapped-volume Use the mapped volume\n"); 76c72fcc34Sopenharmony_ci printf("\nAvailable commands:\n"); 77c72fcc34Sopenharmony_ci printf(" scontrols show all mixer simple controls\n"); 78c72fcc34Sopenharmony_ci printf(" scontents show contents of all mixer simple controls (default command)\n"); 79c72fcc34Sopenharmony_ci printf(" sset sID P set contents for one mixer simple control\n"); 80c72fcc34Sopenharmony_ci printf(" sget sID get contents for one mixer simple control\n"); 81c72fcc34Sopenharmony_ci printf(" controls show all controls for given card\n"); 82c72fcc34Sopenharmony_ci printf(" contents show contents of all controls for given card\n"); 83c72fcc34Sopenharmony_ci printf(" cset cID P set control contents for one control\n"); 84c72fcc34Sopenharmony_ci printf(" cget cID get control contents for one control\n"); 85c72fcc34Sopenharmony_ci printf("\nAvailable advanced commands:\n"); 86c72fcc34Sopenharmony_ci printf(" sevents show the mixer events for simple controls\n"); 87c72fcc34Sopenharmony_ci printf(" events show the mixer events for controls\n"); 88c72fcc34Sopenharmony_ci return 0; 89c72fcc34Sopenharmony_ci} 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_cistatic int info(void) 92c72fcc34Sopenharmony_ci{ 93c72fcc34Sopenharmony_ci int err; 94c72fcc34Sopenharmony_ci snd_ctl_t *handle; 95c72fcc34Sopenharmony_ci snd_mixer_t *mhandle; 96c72fcc34Sopenharmony_ci snd_ctl_card_info_t *info; 97c72fcc34Sopenharmony_ci snd_ctl_elem_list_t *clist; 98c72fcc34Sopenharmony_ci snd_ctl_card_info_alloca(&info); 99c72fcc34Sopenharmony_ci snd_ctl_elem_list_alloca(&clist); 100c72fcc34Sopenharmony_ci 101c72fcc34Sopenharmony_ci if ((err = snd_ctl_open(&handle, card, 0)) < 0) { 102c72fcc34Sopenharmony_ci error("Control device %s open error: %s", card, snd_strerror(err)); 103c72fcc34Sopenharmony_ci return err; 104c72fcc34Sopenharmony_ci } 105c72fcc34Sopenharmony_ci 106c72fcc34Sopenharmony_ci if ((err = snd_ctl_card_info(handle, info)) < 0) { 107c72fcc34Sopenharmony_ci error("Control device %s hw info error: %s", card, snd_strerror(err)); 108c72fcc34Sopenharmony_ci return err; 109c72fcc34Sopenharmony_ci } 110c72fcc34Sopenharmony_ci printf("Card %s '%s'/'%s'\n", card, snd_ctl_card_info_get_id(info), 111c72fcc34Sopenharmony_ci snd_ctl_card_info_get_longname(info)); 112c72fcc34Sopenharmony_ci printf(" Mixer name : '%s'\n", snd_ctl_card_info_get_mixername(info)); 113c72fcc34Sopenharmony_ci printf(" Components : '%s'\n", snd_ctl_card_info_get_components(info)); 114c72fcc34Sopenharmony_ci if ((err = snd_ctl_elem_list(handle, clist)) < 0) { 115c72fcc34Sopenharmony_ci error("snd_ctl_elem_list failure: %s", snd_strerror(err)); 116c72fcc34Sopenharmony_ci } else { 117c72fcc34Sopenharmony_ci printf(" Controls : %i\n", snd_ctl_elem_list_get_count(clist)); 118c72fcc34Sopenharmony_ci } 119c72fcc34Sopenharmony_ci snd_ctl_close(handle); 120c72fcc34Sopenharmony_ci if ((err = snd_mixer_open(&mhandle, 0)) < 0) { 121c72fcc34Sopenharmony_ci error("Mixer open error: %s", snd_strerror(err)); 122c72fcc34Sopenharmony_ci return err; 123c72fcc34Sopenharmony_ci } 124c72fcc34Sopenharmony_ci if (smixer_level == 0 && (err = snd_mixer_attach(mhandle, card)) < 0) { 125c72fcc34Sopenharmony_ci error("Mixer attach %s error: %s", card, snd_strerror(err)); 126c72fcc34Sopenharmony_ci snd_mixer_close(mhandle); 127c72fcc34Sopenharmony_ci return err; 128c72fcc34Sopenharmony_ci } 129c72fcc34Sopenharmony_ci if ((err = snd_mixer_selem_register(mhandle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { 130c72fcc34Sopenharmony_ci error("Mixer register error: %s", snd_strerror(err)); 131c72fcc34Sopenharmony_ci snd_mixer_close(mhandle); 132c72fcc34Sopenharmony_ci return err; 133c72fcc34Sopenharmony_ci } 134c72fcc34Sopenharmony_ci err = snd_mixer_load(mhandle); 135c72fcc34Sopenharmony_ci if (err < 0) { 136c72fcc34Sopenharmony_ci error("Mixer load %s error: %s", card, snd_strerror(err)); 137c72fcc34Sopenharmony_ci snd_mixer_close(mhandle); 138c72fcc34Sopenharmony_ci return err; 139c72fcc34Sopenharmony_ci } 140c72fcc34Sopenharmony_ci printf(" Simple ctrls : %i\n", snd_mixer_get_count(mhandle)); 141c72fcc34Sopenharmony_ci snd_mixer_close(mhandle); 142c72fcc34Sopenharmony_ci return 0; 143c72fcc34Sopenharmony_ci} 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_cistatic const char *control_type(snd_ctl_elem_info_t *info) 146c72fcc34Sopenharmony_ci{ 147c72fcc34Sopenharmony_ci return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)); 148c72fcc34Sopenharmony_ci} 149c72fcc34Sopenharmony_ci 150c72fcc34Sopenharmony_cistatic const char *control_access(snd_ctl_elem_info_t *info) 151c72fcc34Sopenharmony_ci{ 152c72fcc34Sopenharmony_ci static char result[10]; 153c72fcc34Sopenharmony_ci char *res = result; 154c72fcc34Sopenharmony_ci 155c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_readable(info) ? 'r' : '-'; 156c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_writable(info) ? 'w' : '-'; 157c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_inactive(info) ? 'i' : '-'; 158c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_volatile(info) ? 'v' : '-'; 159c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_locked(info) ? 'l' : '-'; 160c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_tlv_readable(info) ? 'R' : '-'; 161c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_tlv_writable(info) ? 'W' : '-'; 162c72fcc34Sopenharmony_ci *res++ = snd_ctl_elem_info_is_tlv_commandable(info) ? 'C' : '-'; 163c72fcc34Sopenharmony_ci *res++ = '\0'; 164c72fcc34Sopenharmony_ci return result; 165c72fcc34Sopenharmony_ci} 166c72fcc34Sopenharmony_ci 167c72fcc34Sopenharmony_ci#define check_range(val, min, max) \ 168c72fcc34Sopenharmony_ci (no_check ? (val) : ((val < min) ? (min) : (val > max) ? (max) : (val))) 169c72fcc34Sopenharmony_ci#if 0 170c72fcc34Sopenharmony_cistatic int convert_range(int val, int omin, int omax, int nmin, int nmax) 171c72fcc34Sopenharmony_ci{ 172c72fcc34Sopenharmony_ci int orange = omax - omin, nrange = nmax - nmin; 173c72fcc34Sopenharmony_ci 174c72fcc34Sopenharmony_ci if (orange == 0) 175c72fcc34Sopenharmony_ci return 0; 176c72fcc34Sopenharmony_ci return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / ((double)orange + (double)nmin)); 177c72fcc34Sopenharmony_ci} 178c72fcc34Sopenharmony_ci#endif 179c72fcc34Sopenharmony_ci 180c72fcc34Sopenharmony_ci#if 0 181c72fcc34Sopenharmony_cistatic int convert_db_range(int val, int omin, int omax, int nmin, int nmax) 182c72fcc34Sopenharmony_ci{ 183c72fcc34Sopenharmony_ci int orange = omax - omin, nrange = nmax - nmin; 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci if (orange == 0) 186c72fcc34Sopenharmony_ci return 0; 187c72fcc34Sopenharmony_ci return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / (double)orange + (double)nmin); 188c72fcc34Sopenharmony_ci} 189c72fcc34Sopenharmony_ci#endif 190c72fcc34Sopenharmony_ci 191c72fcc34Sopenharmony_ci/* Fuction to convert from volume to percentage. val = volume */ 192c72fcc34Sopenharmony_ci 193c72fcc34Sopenharmony_cistatic int convert_prange(long val, long min, long max) 194c72fcc34Sopenharmony_ci{ 195c72fcc34Sopenharmony_ci long range = max - min; 196c72fcc34Sopenharmony_ci int tmp; 197c72fcc34Sopenharmony_ci 198c72fcc34Sopenharmony_ci if (range == 0) 199c72fcc34Sopenharmony_ci return min; 200c72fcc34Sopenharmony_ci val -= min; 201c72fcc34Sopenharmony_ci tmp = rint((double)val/(double)range * 100); 202c72fcc34Sopenharmony_ci return tmp; 203c72fcc34Sopenharmony_ci} 204c72fcc34Sopenharmony_ci 205c72fcc34Sopenharmony_ci/* Function to convert from percentage to volume. perc = percentage */ 206c72fcc34Sopenharmony_cistatic long convert_prange1(long perc, long min, long max) 207c72fcc34Sopenharmony_ci{ 208c72fcc34Sopenharmony_ci long tmp; 209c72fcc34Sopenharmony_ci 210c72fcc34Sopenharmony_ci tmp = rint((double)perc * (double)(max - min) * 0.01); 211c72fcc34Sopenharmony_ci if (tmp == 0 && perc > 0) 212c72fcc34Sopenharmony_ci tmp++; 213c72fcc34Sopenharmony_ci return tmp + min; 214c72fcc34Sopenharmony_ci} 215c72fcc34Sopenharmony_ci 216c72fcc34Sopenharmony_cistruct volume_ops { 217c72fcc34Sopenharmony_ci int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max); 218c72fcc34Sopenharmony_ci int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c, 219c72fcc34Sopenharmony_ci long *value); 220c72fcc34Sopenharmony_ci int (*set)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c, 221c72fcc34Sopenharmony_ci long value, int dir); 222c72fcc34Sopenharmony_ci}; 223c72fcc34Sopenharmony_ci 224c72fcc34Sopenharmony_cienum { VOL_RAW, VOL_DB, VOL_MAP }; 225c72fcc34Sopenharmony_ci 226c72fcc34Sopenharmony_cistruct volume_ops_set { 227c72fcc34Sopenharmony_ci int (*has_volume)(snd_mixer_elem_t *elem); 228c72fcc34Sopenharmony_ci struct volume_ops v[3]; 229c72fcc34Sopenharmony_ci}; 230c72fcc34Sopenharmony_ci 231c72fcc34Sopenharmony_cistatic int set_playback_dB(snd_mixer_elem_t *elem, 232c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, long value, int dir) 233c72fcc34Sopenharmony_ci{ 234c72fcc34Sopenharmony_ci return snd_mixer_selem_set_playback_dB(elem, c, value, dir); 235c72fcc34Sopenharmony_ci} 236c72fcc34Sopenharmony_ci 237c72fcc34Sopenharmony_cistatic int set_capture_dB(snd_mixer_elem_t *elem, 238c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, long value, int dir) 239c72fcc34Sopenharmony_ci{ 240c72fcc34Sopenharmony_ci return snd_mixer_selem_set_capture_dB(elem, c, value, dir); 241c72fcc34Sopenharmony_ci} 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_cistatic int set_playback_raw_volume(snd_mixer_elem_t *elem, 244c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 245c72fcc34Sopenharmony_ci long value, int dir ATTRIBUTE_UNUSED) 246c72fcc34Sopenharmony_ci{ 247c72fcc34Sopenharmony_ci return snd_mixer_selem_set_playback_volume(elem, c, value); 248c72fcc34Sopenharmony_ci} 249c72fcc34Sopenharmony_ci 250c72fcc34Sopenharmony_cistatic int set_capture_raw_volume(snd_mixer_elem_t *elem, 251c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 252c72fcc34Sopenharmony_ci long value, int dir ATTRIBUTE_UNUSED) 253c72fcc34Sopenharmony_ci{ 254c72fcc34Sopenharmony_ci return snd_mixer_selem_set_capture_volume(elem, c, value); 255c72fcc34Sopenharmony_ci} 256c72fcc34Sopenharmony_ci 257c72fcc34Sopenharmony_ci/* FIXME: normalize to int32 space to be compatible with other types */ 258c72fcc34Sopenharmony_ci#define MAP_VOL_RES (INT32_MAX / 100) 259c72fcc34Sopenharmony_ci 260c72fcc34Sopenharmony_cistatic int get_mapped_volume_range(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED, 261c72fcc34Sopenharmony_ci long *pmin, long *pmax) 262c72fcc34Sopenharmony_ci{ 263c72fcc34Sopenharmony_ci *pmin = 0; 264c72fcc34Sopenharmony_ci *pmax = MAP_VOL_RES; 265c72fcc34Sopenharmony_ci return 0; 266c72fcc34Sopenharmony_ci} 267c72fcc34Sopenharmony_ci 268c72fcc34Sopenharmony_cistatic int get_playback_mapped_volume(snd_mixer_elem_t *elem, 269c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 270c72fcc34Sopenharmony_ci long *value) 271c72fcc34Sopenharmony_ci{ 272c72fcc34Sopenharmony_ci *value = (rint)(get_normalized_playback_volume(elem, c) * MAP_VOL_RES); 273c72fcc34Sopenharmony_ci return 0; 274c72fcc34Sopenharmony_ci} 275c72fcc34Sopenharmony_ci 276c72fcc34Sopenharmony_cistatic int set_playback_mapped_volume(snd_mixer_elem_t *elem, 277c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 278c72fcc34Sopenharmony_ci long value, int dir) 279c72fcc34Sopenharmony_ci{ 280c72fcc34Sopenharmony_ci return set_normalized_playback_volume(elem, c, 281c72fcc34Sopenharmony_ci (double)value / MAP_VOL_RES, dir); 282c72fcc34Sopenharmony_ci} 283c72fcc34Sopenharmony_ci 284c72fcc34Sopenharmony_cistatic int get_capture_mapped_volume(snd_mixer_elem_t *elem, 285c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 286c72fcc34Sopenharmony_ci long *value) 287c72fcc34Sopenharmony_ci{ 288c72fcc34Sopenharmony_ci *value = (rint)(get_normalized_capture_volume(elem, c) * MAP_VOL_RES); 289c72fcc34Sopenharmony_ci return 0; 290c72fcc34Sopenharmony_ci} 291c72fcc34Sopenharmony_ci 292c72fcc34Sopenharmony_cistatic int set_capture_mapped_volume(snd_mixer_elem_t *elem, 293c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t c, 294c72fcc34Sopenharmony_ci long value, int dir) 295c72fcc34Sopenharmony_ci{ 296c72fcc34Sopenharmony_ci return set_normalized_capture_volume(elem, c, 297c72fcc34Sopenharmony_ci (double)value / MAP_VOL_RES, dir); 298c72fcc34Sopenharmony_ci} 299c72fcc34Sopenharmony_ci 300c72fcc34Sopenharmony_cistatic const struct volume_ops_set vol_ops[2] = { 301c72fcc34Sopenharmony_ci { 302c72fcc34Sopenharmony_ci .has_volume = snd_mixer_selem_has_playback_volume, 303c72fcc34Sopenharmony_ci .v = {{ snd_mixer_selem_get_playback_volume_range, 304c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_volume, 305c72fcc34Sopenharmony_ci set_playback_raw_volume }, 306c72fcc34Sopenharmony_ci { snd_mixer_selem_get_playback_dB_range, 307c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_dB, 308c72fcc34Sopenharmony_ci set_playback_dB }, 309c72fcc34Sopenharmony_ci { get_mapped_volume_range, 310c72fcc34Sopenharmony_ci get_playback_mapped_volume, 311c72fcc34Sopenharmony_ci set_playback_mapped_volume }, 312c72fcc34Sopenharmony_ci }, 313c72fcc34Sopenharmony_ci }, 314c72fcc34Sopenharmony_ci { 315c72fcc34Sopenharmony_ci .has_volume = snd_mixer_selem_has_capture_volume, 316c72fcc34Sopenharmony_ci .v = {{ snd_mixer_selem_get_capture_volume_range, 317c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_volume, 318c72fcc34Sopenharmony_ci set_capture_raw_volume }, 319c72fcc34Sopenharmony_ci { snd_mixer_selem_get_capture_dB_range, 320c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_dB, 321c72fcc34Sopenharmony_ci set_capture_dB }, 322c72fcc34Sopenharmony_ci { get_mapped_volume_range, 323c72fcc34Sopenharmony_ci get_capture_mapped_volume, 324c72fcc34Sopenharmony_ci set_capture_mapped_volume }, 325c72fcc34Sopenharmony_ci }, 326c72fcc34Sopenharmony_ci }, 327c72fcc34Sopenharmony_ci}; 328c72fcc34Sopenharmony_ci 329c72fcc34Sopenharmony_cistatic int std_vol_type = VOL_RAW; 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_cistatic int set_volume_simple(snd_mixer_elem_t *elem, 332c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t chn, 333c72fcc34Sopenharmony_ci char **ptr, int dir) 334c72fcc34Sopenharmony_ci{ 335c72fcc34Sopenharmony_ci long val, orig, pmin, pmax; 336c72fcc34Sopenharmony_ci char *p = *ptr, *s; 337c72fcc34Sopenharmony_ci int invalid = 0, percent = 0, err = 0; 338c72fcc34Sopenharmony_ci int vol_type; 339c72fcc34Sopenharmony_ci double scale = 1.0; 340c72fcc34Sopenharmony_ci int correct = 0; 341c72fcc34Sopenharmony_ci 342c72fcc34Sopenharmony_ci if (! vol_ops[dir].has_volume(elem)) 343c72fcc34Sopenharmony_ci invalid = 1; 344c72fcc34Sopenharmony_ci 345c72fcc34Sopenharmony_ci if (*p == ':') 346c72fcc34Sopenharmony_ci p++; 347c72fcc34Sopenharmony_ci if (*p == '\0' || (!isdigit(*p) && *p != '-')) 348c72fcc34Sopenharmony_ci goto skip; 349c72fcc34Sopenharmony_ci 350c72fcc34Sopenharmony_ci s = p; 351c72fcc34Sopenharmony_ci val = strtol(s, &p, 10); 352c72fcc34Sopenharmony_ci if (*p == '.') { 353c72fcc34Sopenharmony_ci p++; 354c72fcc34Sopenharmony_ci strtol(p, &p, 10); 355c72fcc34Sopenharmony_ci } 356c72fcc34Sopenharmony_ci if (*p == '%') { 357c72fcc34Sopenharmony_ci vol_type = std_vol_type; 358c72fcc34Sopenharmony_ci percent = 1; 359c72fcc34Sopenharmony_ci p++; 360c72fcc34Sopenharmony_ci } else if (toupper(p[0]) == 'D' && toupper(p[1]) == 'B') { 361c72fcc34Sopenharmony_ci vol_type = VOL_DB; 362c72fcc34Sopenharmony_ci p += 2; 363c72fcc34Sopenharmony_ci scale = 100; 364c72fcc34Sopenharmony_ci } else { 365c72fcc34Sopenharmony_ci vol_type = VOL_RAW; 366c72fcc34Sopenharmony_ci } 367c72fcc34Sopenharmony_ci 368c72fcc34Sopenharmony_ci if (*p && !strchr(",:+-", *p)) 369c72fcc34Sopenharmony_ci invalid = 1; 370c72fcc34Sopenharmony_ci 371c72fcc34Sopenharmony_ci val = (long)(strtod(s, NULL) * scale); 372c72fcc34Sopenharmony_ci if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0) 373c72fcc34Sopenharmony_ci invalid = 1; 374c72fcc34Sopenharmony_ci if (percent) 375c72fcc34Sopenharmony_ci val = (long)convert_prange1(val, pmin, pmax); 376c72fcc34Sopenharmony_ci if (*p == '+' || *p == '-') { 377c72fcc34Sopenharmony_ci if (! invalid) { 378c72fcc34Sopenharmony_ci if (vol_ops[dir].v[vol_type].get(elem, chn, &orig) < 0) 379c72fcc34Sopenharmony_ci invalid = 1; 380c72fcc34Sopenharmony_ci if (*p == '+') { 381c72fcc34Sopenharmony_ci val = orig + val; 382c72fcc34Sopenharmony_ci correct = 1; 383c72fcc34Sopenharmony_ci } else { 384c72fcc34Sopenharmony_ci val = orig - val; 385c72fcc34Sopenharmony_ci correct = -1; 386c72fcc34Sopenharmony_ci } 387c72fcc34Sopenharmony_ci } 388c72fcc34Sopenharmony_ci p++; 389c72fcc34Sopenharmony_ci } 390c72fcc34Sopenharmony_ci 391c72fcc34Sopenharmony_ci if (*p && !strchr(",:", *p)) 392c72fcc34Sopenharmony_ci invalid = 1; 393c72fcc34Sopenharmony_ci 394c72fcc34Sopenharmony_ci if (! invalid) { 395c72fcc34Sopenharmony_ci val = check_range(val, pmin, pmax); 396c72fcc34Sopenharmony_ci err = vol_ops[dir].v[vol_type].set(elem, chn, val, correct); 397c72fcc34Sopenharmony_ci } 398c72fcc34Sopenharmony_ci skip: 399c72fcc34Sopenharmony_ci if (*p == ',') 400c72fcc34Sopenharmony_ci p++; 401c72fcc34Sopenharmony_ci *ptr = p; 402c72fcc34Sopenharmony_ci return err ? err : (invalid ? -ENOENT : 0); 403c72fcc34Sopenharmony_ci} 404c72fcc34Sopenharmony_ci 405c72fcc34Sopenharmony_cistatic int get_bool_simple(char **ptr, char *str, int invert, int orig) 406c72fcc34Sopenharmony_ci{ 407c72fcc34Sopenharmony_ci if (**ptr == ':') 408c72fcc34Sopenharmony_ci (*ptr)++; 409c72fcc34Sopenharmony_ci if (!strncasecmp(*ptr, str, strlen(str))) { 410c72fcc34Sopenharmony_ci orig = 1 ^ (invert ? 1 : 0); 411c72fcc34Sopenharmony_ci while (**ptr != '\0' && **ptr != ',' && **ptr != ':') 412c72fcc34Sopenharmony_ci (*ptr)++; 413c72fcc34Sopenharmony_ci } 414c72fcc34Sopenharmony_ci if (**ptr == ',' || **ptr == ':') 415c72fcc34Sopenharmony_ci (*ptr)++; 416c72fcc34Sopenharmony_ci return orig; 417c72fcc34Sopenharmony_ci} 418c72fcc34Sopenharmony_ci 419c72fcc34Sopenharmony_cistatic int simple_skip_word(char **ptr, char *str) 420c72fcc34Sopenharmony_ci{ 421c72fcc34Sopenharmony_ci char *xptr = *ptr; 422c72fcc34Sopenharmony_ci if (*xptr == ':') 423c72fcc34Sopenharmony_ci xptr++; 424c72fcc34Sopenharmony_ci if (!strncasecmp(xptr, str, strlen(str))) { 425c72fcc34Sopenharmony_ci while (*xptr != '\0' && *xptr != ',' && *xptr != ':') 426c72fcc34Sopenharmony_ci xptr++; 427c72fcc34Sopenharmony_ci if (*xptr == ',' || *xptr == ':') 428c72fcc34Sopenharmony_ci xptr++; 429c72fcc34Sopenharmony_ci *ptr = xptr; 430c72fcc34Sopenharmony_ci return 1; 431c72fcc34Sopenharmony_ci } 432c72fcc34Sopenharmony_ci return 0; 433c72fcc34Sopenharmony_ci} 434c72fcc34Sopenharmony_ci 435c72fcc34Sopenharmony_cistatic void show_control_id(snd_ctl_elem_id_t *id) 436c72fcc34Sopenharmony_ci{ 437c72fcc34Sopenharmony_ci char *str; 438c72fcc34Sopenharmony_ci 439c72fcc34Sopenharmony_ci str = snd_ctl_ascii_elem_id_get(id); 440c72fcc34Sopenharmony_ci if (str) 441c72fcc34Sopenharmony_ci printf("%s", str); 442c72fcc34Sopenharmony_ci free(str); 443c72fcc34Sopenharmony_ci} 444c72fcc34Sopenharmony_ci 445c72fcc34Sopenharmony_cistatic void print_spaces(unsigned int spaces) 446c72fcc34Sopenharmony_ci{ 447c72fcc34Sopenharmony_ci while (spaces-- > 0) 448c72fcc34Sopenharmony_ci putc(' ', stdout); 449c72fcc34Sopenharmony_ci} 450c72fcc34Sopenharmony_ci 451c72fcc34Sopenharmony_cistatic void print_dB(long dB) 452c72fcc34Sopenharmony_ci{ 453c72fcc34Sopenharmony_ci if (dB < 0) { 454c72fcc34Sopenharmony_ci printf("-%li.%02lidB", -dB / 100, -dB % 100); 455c72fcc34Sopenharmony_ci } else { 456c72fcc34Sopenharmony_ci printf("%li.%02lidB", dB / 100, dB % 100); 457c72fcc34Sopenharmony_ci } 458c72fcc34Sopenharmony_ci} 459c72fcc34Sopenharmony_ci 460c72fcc34Sopenharmony_cistatic void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size) 461c72fcc34Sopenharmony_ci{ 462c72fcc34Sopenharmony_ci unsigned int type = tlv[0]; 463c72fcc34Sopenharmony_ci unsigned int size; 464c72fcc34Sopenharmony_ci unsigned int idx = 0; 465c72fcc34Sopenharmony_ci const char *chmap_type = NULL; 466c72fcc34Sopenharmony_ci int lf = 1; 467c72fcc34Sopenharmony_ci 468c72fcc34Sopenharmony_ci if (tlv_size < 2 * sizeof(unsigned int)) { 469c72fcc34Sopenharmony_ci printf("TLV size error!\n"); 470c72fcc34Sopenharmony_ci return; 471c72fcc34Sopenharmony_ci } 472c72fcc34Sopenharmony_ci print_spaces(spaces); 473c72fcc34Sopenharmony_ci printf("| "); 474c72fcc34Sopenharmony_ci type = tlv[idx++]; 475c72fcc34Sopenharmony_ci size = tlv[idx++]; 476c72fcc34Sopenharmony_ci tlv_size -= 2 * sizeof(unsigned int); 477c72fcc34Sopenharmony_ci if (size > tlv_size) { 478c72fcc34Sopenharmony_ci printf("TLV size error (%u, %u, %u)!\n", type, size, tlv_size); 479c72fcc34Sopenharmony_ci return; 480c72fcc34Sopenharmony_ci } 481c72fcc34Sopenharmony_ci switch (type) { 482c72fcc34Sopenharmony_ci case SND_CTL_TLVT_CONTAINER: 483c72fcc34Sopenharmony_ci printf("container\n"); 484c72fcc34Sopenharmony_ci size += sizeof(unsigned int) -1; 485c72fcc34Sopenharmony_ci size /= sizeof(unsigned int); 486c72fcc34Sopenharmony_ci while (idx < size) { 487c72fcc34Sopenharmony_ci if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) { 488c72fcc34Sopenharmony_ci printf("TLV size error in compound!\n"); 489c72fcc34Sopenharmony_ci return; 490c72fcc34Sopenharmony_ci } 491c72fcc34Sopenharmony_ci decode_tlv(spaces + 2, tlv + idx, tlv[idx+1] + 8); 492c72fcc34Sopenharmony_ci idx += 2 + (tlv[idx+1] + sizeof(unsigned int) - 1) / sizeof(unsigned int); 493c72fcc34Sopenharmony_ci } 494c72fcc34Sopenharmony_ci lf = 0; 495c72fcc34Sopenharmony_ci break; 496c72fcc34Sopenharmony_ci case SND_CTL_TLVT_DB_SCALE: 497c72fcc34Sopenharmony_ci printf("dBscale-"); 498c72fcc34Sopenharmony_ci if (size != 2 * sizeof(unsigned int)) { 499c72fcc34Sopenharmony_ci while (size > 0) { 500c72fcc34Sopenharmony_ci printf("0x%08x,", tlv[idx++]); 501c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 502c72fcc34Sopenharmony_ci } 503c72fcc34Sopenharmony_ci } else { 504c72fcc34Sopenharmony_ci printf("min="); 505c72fcc34Sopenharmony_ci print_dB((int)tlv[2]); 506c72fcc34Sopenharmony_ci printf(",step="); 507c72fcc34Sopenharmony_ci print_dB(tlv[3] & 0xffff); 508c72fcc34Sopenharmony_ci printf(",mute=%i", (tlv[3] >> 16) & 1); 509c72fcc34Sopenharmony_ci } 510c72fcc34Sopenharmony_ci break; 511c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_LINEAR 512c72fcc34Sopenharmony_ci case SND_CTL_TLVT_DB_LINEAR: 513c72fcc34Sopenharmony_ci printf("dBlinear-"); 514c72fcc34Sopenharmony_ci if (size != 2 * sizeof(unsigned int)) { 515c72fcc34Sopenharmony_ci while (size > 0) { 516c72fcc34Sopenharmony_ci printf("0x%08x,", tlv[idx++]); 517c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 518c72fcc34Sopenharmony_ci } 519c72fcc34Sopenharmony_ci } else { 520c72fcc34Sopenharmony_ci printf("min="); 521c72fcc34Sopenharmony_ci print_dB((int)tlv[2]); 522c72fcc34Sopenharmony_ci printf(",max="); 523c72fcc34Sopenharmony_ci print_dB((int)tlv[3]); 524c72fcc34Sopenharmony_ci } 525c72fcc34Sopenharmony_ci break; 526c72fcc34Sopenharmony_ci#endif 527c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_RANGE 528c72fcc34Sopenharmony_ci case SND_CTL_TLVT_DB_RANGE: 529c72fcc34Sopenharmony_ci printf("dBrange-\n"); 530c72fcc34Sopenharmony_ci if ((size % (6 * sizeof(unsigned int))) != 0) { 531c72fcc34Sopenharmony_ci while (size > 0) { 532c72fcc34Sopenharmony_ci printf("0x%08x,", tlv[idx++]); 533c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 534c72fcc34Sopenharmony_ci } 535c72fcc34Sopenharmony_ci break; 536c72fcc34Sopenharmony_ci } 537c72fcc34Sopenharmony_ci while (size > 0) { 538c72fcc34Sopenharmony_ci print_spaces(spaces + 2); 539c72fcc34Sopenharmony_ci printf("rangemin=%i,", tlv[idx++]); 540c72fcc34Sopenharmony_ci printf(",rangemax=%i\n", tlv[idx++]); 541c72fcc34Sopenharmony_ci decode_tlv(spaces + 4, tlv + idx, 4 * sizeof(unsigned int)); 542c72fcc34Sopenharmony_ci idx += 4; 543c72fcc34Sopenharmony_ci size -= 6 * sizeof(unsigned int); 544c72fcc34Sopenharmony_ci } 545c72fcc34Sopenharmony_ci break; 546c72fcc34Sopenharmony_ci#endif 547c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_MINMAX 548c72fcc34Sopenharmony_ci case SND_CTL_TLVT_DB_MINMAX: 549c72fcc34Sopenharmony_ci case SND_CTL_TLVT_DB_MINMAX_MUTE: 550c72fcc34Sopenharmony_ci if (type == SND_CTL_TLVT_DB_MINMAX_MUTE) 551c72fcc34Sopenharmony_ci printf("dBminmaxmute-"); 552c72fcc34Sopenharmony_ci else 553c72fcc34Sopenharmony_ci printf("dBminmax-"); 554c72fcc34Sopenharmony_ci if (size != 2 * sizeof(unsigned int)) { 555c72fcc34Sopenharmony_ci while (size > 0) { 556c72fcc34Sopenharmony_ci printf("0x%08x,", tlv[idx++]); 557c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 558c72fcc34Sopenharmony_ci } 559c72fcc34Sopenharmony_ci } else { 560c72fcc34Sopenharmony_ci printf("min="); 561c72fcc34Sopenharmony_ci print_dB((int)tlv[2]); 562c72fcc34Sopenharmony_ci printf(",max="); 563c72fcc34Sopenharmony_ci print_dB((int)tlv[3]); 564c72fcc34Sopenharmony_ci } 565c72fcc34Sopenharmony_ci break; 566c72fcc34Sopenharmony_ci#endif 567c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_CHMAP_FIXED 568c72fcc34Sopenharmony_ci case SND_CTL_TLVT_CHMAP_FIXED: 569c72fcc34Sopenharmony_ci chmap_type = "fixed"; 570c72fcc34Sopenharmony_ci /* Fall through */ 571c72fcc34Sopenharmony_ci case SND_CTL_TLVT_CHMAP_VAR: 572c72fcc34Sopenharmony_ci if (!chmap_type) 573c72fcc34Sopenharmony_ci chmap_type = "variable"; 574c72fcc34Sopenharmony_ci /* Fall through */ 575c72fcc34Sopenharmony_ci case SND_CTL_TLVT_CHMAP_PAIRED: 576c72fcc34Sopenharmony_ci if (!chmap_type) 577c72fcc34Sopenharmony_ci chmap_type = "paired"; 578c72fcc34Sopenharmony_ci printf("chmap-%s=", chmap_type); 579c72fcc34Sopenharmony_ci 580c72fcc34Sopenharmony_ci while (size > 0) { 581c72fcc34Sopenharmony_ci printf("%s", snd_pcm_chmap_name(tlv[idx++])); 582c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 583c72fcc34Sopenharmony_ci if (size > 0) 584c72fcc34Sopenharmony_ci printf(","); 585c72fcc34Sopenharmony_ci } 586c72fcc34Sopenharmony_ci break; 587c72fcc34Sopenharmony_ci#endif 588c72fcc34Sopenharmony_ci default: 589c72fcc34Sopenharmony_ci printf("unk-%u-", type); 590c72fcc34Sopenharmony_ci while (size > 0) { 591c72fcc34Sopenharmony_ci printf("0x%08x,", tlv[idx++]); 592c72fcc34Sopenharmony_ci size -= sizeof(unsigned int); 593c72fcc34Sopenharmony_ci } 594c72fcc34Sopenharmony_ci break; 595c72fcc34Sopenharmony_ci } 596c72fcc34Sopenharmony_ci if (lf) 597c72fcc34Sopenharmony_ci putc('\n', stdout); 598c72fcc34Sopenharmony_ci} 599c72fcc34Sopenharmony_ci 600c72fcc34Sopenharmony_cistatic int show_control(const char *space, snd_hctl_elem_t *elem, 601c72fcc34Sopenharmony_ci int level) 602c72fcc34Sopenharmony_ci{ 603c72fcc34Sopenharmony_ci int err; 604c72fcc34Sopenharmony_ci unsigned int item, idx, count, *tlv; 605c72fcc34Sopenharmony_ci snd_ctl_elem_type_t type; 606c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 607c72fcc34Sopenharmony_ci snd_ctl_elem_info_t *info; 608c72fcc34Sopenharmony_ci snd_ctl_elem_value_t *control; 609c72fcc34Sopenharmony_ci snd_aes_iec958_t iec958; 610c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 611c72fcc34Sopenharmony_ci snd_ctl_elem_info_alloca(&info); 612c72fcc34Sopenharmony_ci snd_ctl_elem_value_alloca(&control); 613c72fcc34Sopenharmony_ci if ((err = snd_hctl_elem_info(elem, info)) < 0) { 614c72fcc34Sopenharmony_ci error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err)); 615c72fcc34Sopenharmony_ci return err; 616c72fcc34Sopenharmony_ci } 617c72fcc34Sopenharmony_ci if (level & LEVEL_ID) { 618c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(elem, id); 619c72fcc34Sopenharmony_ci show_control_id(id); 620c72fcc34Sopenharmony_ci printf("\n"); 621c72fcc34Sopenharmony_ci } 622c72fcc34Sopenharmony_ci count = snd_ctl_elem_info_get_count(info); 623c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(info); 624c72fcc34Sopenharmony_ci printf("%s; type=%s,access=%s,values=%u", space, control_type(info), control_access(info), count); 625c72fcc34Sopenharmony_ci switch (type) { 626c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 627c72fcc34Sopenharmony_ci printf(",min=%li,max=%li,step=%li\n", 628c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_min(info), 629c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_max(info), 630c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_step(info)); 631c72fcc34Sopenharmony_ci break; 632c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 633c72fcc34Sopenharmony_ci printf(",min=%lli,max=%lli,step=%lli\n", 634c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_min64(info), 635c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_max64(info), 636c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_step64(info)); 637c72fcc34Sopenharmony_ci break; 638c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 639c72fcc34Sopenharmony_ci { 640c72fcc34Sopenharmony_ci unsigned int items = snd_ctl_elem_info_get_items(info); 641c72fcc34Sopenharmony_ci printf(",items=%u\n", items); 642c72fcc34Sopenharmony_ci for (item = 0; item < items; item++) { 643c72fcc34Sopenharmony_ci snd_ctl_elem_info_set_item(info, item); 644c72fcc34Sopenharmony_ci if ((err = snd_hctl_elem_info(elem, info)) < 0) { 645c72fcc34Sopenharmony_ci error("Control %s element info error: %s\n", card, snd_strerror(err)); 646c72fcc34Sopenharmony_ci return err; 647c72fcc34Sopenharmony_ci } 648c72fcc34Sopenharmony_ci printf("%s; Item #%u '%s'\n", space, item, snd_ctl_elem_info_get_item_name(info)); 649c72fcc34Sopenharmony_ci } 650c72fcc34Sopenharmony_ci break; 651c72fcc34Sopenharmony_ci } 652c72fcc34Sopenharmony_ci default: 653c72fcc34Sopenharmony_ci printf("\n"); 654c72fcc34Sopenharmony_ci break; 655c72fcc34Sopenharmony_ci } 656c72fcc34Sopenharmony_ci if (level & LEVEL_BASIC) { 657c72fcc34Sopenharmony_ci if (!snd_ctl_elem_info_is_readable(info)) 658c72fcc34Sopenharmony_ci goto __skip_read; 659c72fcc34Sopenharmony_ci if ((err = snd_hctl_elem_read(elem, control)) < 0) { 660c72fcc34Sopenharmony_ci error("Control %s element read error: %s\n", card, snd_strerror(err)); 661c72fcc34Sopenharmony_ci return err; 662c72fcc34Sopenharmony_ci } 663c72fcc34Sopenharmony_ci printf("%s: values=", space); 664c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 665c72fcc34Sopenharmony_ci if (idx > 0) 666c72fcc34Sopenharmony_ci printf(","); 667c72fcc34Sopenharmony_ci switch (type) { 668c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 669c72fcc34Sopenharmony_ci printf("%s", snd_ctl_elem_value_get_boolean(control, idx) ? "on" : "off"); 670c72fcc34Sopenharmony_ci break; 671c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 672c72fcc34Sopenharmony_ci printf("%li", snd_ctl_elem_value_get_integer(control, idx)); 673c72fcc34Sopenharmony_ci break; 674c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 675c72fcc34Sopenharmony_ci printf("%lli", snd_ctl_elem_value_get_integer64(control, idx)); 676c72fcc34Sopenharmony_ci break; 677c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 678c72fcc34Sopenharmony_ci printf("%u", snd_ctl_elem_value_get_enumerated(control, idx)); 679c72fcc34Sopenharmony_ci break; 680c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 681c72fcc34Sopenharmony_ci printf("0x%02x", snd_ctl_elem_value_get_byte(control, idx)); 682c72fcc34Sopenharmony_ci break; 683c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_IEC958: 684c72fcc34Sopenharmony_ci snd_ctl_elem_value_get_iec958(control, &iec958); 685c72fcc34Sopenharmony_ci printf("[AES0=0x%02x AES1=0x%02x AES2=0x%02x AES3=0x%02x]", 686c72fcc34Sopenharmony_ci iec958.status[0], iec958.status[1], 687c72fcc34Sopenharmony_ci iec958.status[2], iec958.status[3]); 688c72fcc34Sopenharmony_ci break; 689c72fcc34Sopenharmony_ci default: 690c72fcc34Sopenharmony_ci printf("?"); 691c72fcc34Sopenharmony_ci break; 692c72fcc34Sopenharmony_ci } 693c72fcc34Sopenharmony_ci } 694c72fcc34Sopenharmony_ci printf("\n"); 695c72fcc34Sopenharmony_ci __skip_read: 696c72fcc34Sopenharmony_ci if (!snd_ctl_elem_info_is_tlv_readable(info)) 697c72fcc34Sopenharmony_ci goto __skip_tlv; 698c72fcc34Sopenharmony_ci /* skip ASoC ext bytes controls that may have huge binary TLV data */ 699c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_BYTES && 700c72fcc34Sopenharmony_ci !snd_ctl_elem_info_is_readable(info) && 701c72fcc34Sopenharmony_ci !snd_ctl_elem_info_is_writable(info)) { 702c72fcc34Sopenharmony_ci printf("%s; ASoC TLV Byte control, skipping bytes dump\n", space); 703c72fcc34Sopenharmony_ci goto __skip_tlv; 704c72fcc34Sopenharmony_ci } 705c72fcc34Sopenharmony_ci 706c72fcc34Sopenharmony_ci tlv = malloc(4096); 707c72fcc34Sopenharmony_ci if ((err = snd_hctl_elem_tlv_read(elem, tlv, 4096)) < 0) { 708c72fcc34Sopenharmony_ci error("Control %s element TLV read error: %s\n", card, snd_strerror(err)); 709c72fcc34Sopenharmony_ci free(tlv); 710c72fcc34Sopenharmony_ci return err; 711c72fcc34Sopenharmony_ci } 712c72fcc34Sopenharmony_ci decode_tlv(strlen(space), tlv, 4096); 713c72fcc34Sopenharmony_ci free(tlv); 714c72fcc34Sopenharmony_ci } 715c72fcc34Sopenharmony_ci __skip_tlv: 716c72fcc34Sopenharmony_ci return 0; 717c72fcc34Sopenharmony_ci} 718c72fcc34Sopenharmony_ci 719c72fcc34Sopenharmony_cistatic int controls(int level) 720c72fcc34Sopenharmony_ci{ 721c72fcc34Sopenharmony_ci int err; 722c72fcc34Sopenharmony_ci snd_hctl_t *handle; 723c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 724c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 725c72fcc34Sopenharmony_ci snd_ctl_elem_info_t *info; 726c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 727c72fcc34Sopenharmony_ci snd_ctl_elem_info_alloca(&info); 728c72fcc34Sopenharmony_ci 729c72fcc34Sopenharmony_ci if ((err = snd_hctl_open(&handle, card, 0)) < 0) { 730c72fcc34Sopenharmony_ci error("Control %s open error: %s", card, snd_strerror(err)); 731c72fcc34Sopenharmony_ci return err; 732c72fcc34Sopenharmony_ci } 733c72fcc34Sopenharmony_ci if ((err = snd_hctl_load(handle)) < 0) { 734c72fcc34Sopenharmony_ci error("Control %s local error: %s\n", card, snd_strerror(err)); 735c72fcc34Sopenharmony_ci return err; 736c72fcc34Sopenharmony_ci } 737c72fcc34Sopenharmony_ci for (elem = snd_hctl_first_elem(handle); elem; elem = snd_hctl_elem_next(elem)) { 738c72fcc34Sopenharmony_ci if ((err = snd_hctl_elem_info(elem, info)) < 0) { 739c72fcc34Sopenharmony_ci error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err)); 740c72fcc34Sopenharmony_ci return err; 741c72fcc34Sopenharmony_ci } 742c72fcc34Sopenharmony_ci if (!(level & LEVEL_INACTIVE) && snd_ctl_elem_info_is_inactive(info)) 743c72fcc34Sopenharmony_ci continue; 744c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(elem, id); 745c72fcc34Sopenharmony_ci show_control_id(id); 746c72fcc34Sopenharmony_ci printf("\n"); 747c72fcc34Sopenharmony_ci if (level & LEVEL_BASIC) 748c72fcc34Sopenharmony_ci show_control(" ", elem, 1); 749c72fcc34Sopenharmony_ci } 750c72fcc34Sopenharmony_ci snd_hctl_close(handle); 751c72fcc34Sopenharmony_ci return 0; 752c72fcc34Sopenharmony_ci} 753c72fcc34Sopenharmony_ci 754c72fcc34Sopenharmony_cistatic void show_selem_volume(snd_mixer_elem_t *elem, 755c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t chn, int dir, 756c72fcc34Sopenharmony_ci long min, long max) 757c72fcc34Sopenharmony_ci{ 758c72fcc34Sopenharmony_ci long raw, val; 759c72fcc34Sopenharmony_ci vol_ops[dir].v[VOL_RAW].get(elem, chn, &raw); 760c72fcc34Sopenharmony_ci if (std_vol_type == VOL_RAW) 761c72fcc34Sopenharmony_ci val = convert_prange(raw, min, max); 762c72fcc34Sopenharmony_ci else { 763c72fcc34Sopenharmony_ci vol_ops[dir].v[std_vol_type].get(elem, chn, &val); 764c72fcc34Sopenharmony_ci val = convert_prange(val, 0, MAP_VOL_RES); 765c72fcc34Sopenharmony_ci } 766c72fcc34Sopenharmony_ci printf(" %li [%li%%]", raw, val); 767c72fcc34Sopenharmony_ci if (!vol_ops[dir].v[VOL_DB].get(elem, chn, &val)) { 768c72fcc34Sopenharmony_ci printf(" ["); 769c72fcc34Sopenharmony_ci print_dB(val); 770c72fcc34Sopenharmony_ci printf("]"); 771c72fcc34Sopenharmony_ci } 772c72fcc34Sopenharmony_ci} 773c72fcc34Sopenharmony_ci 774c72fcc34Sopenharmony_cistatic int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level) 775c72fcc34Sopenharmony_ci{ 776c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t chn; 777c72fcc34Sopenharmony_ci long pmin = 0, pmax = 0; 778c72fcc34Sopenharmony_ci long cmin = 0, cmax = 0; 779c72fcc34Sopenharmony_ci int psw, csw; 780c72fcc34Sopenharmony_ci int pmono, cmono, mono_ok = 0; 781c72fcc34Sopenharmony_ci snd_mixer_elem_t *elem; 782c72fcc34Sopenharmony_ci 783c72fcc34Sopenharmony_ci elem = snd_mixer_find_selem(handle, id); 784c72fcc34Sopenharmony_ci if (!elem) { 785c72fcc34Sopenharmony_ci error("Mixer %s simple element not found", card); 786c72fcc34Sopenharmony_ci return -ENOENT; 787c72fcc34Sopenharmony_ci } 788c72fcc34Sopenharmony_ci 789c72fcc34Sopenharmony_ci if (level & LEVEL_BASIC) { 790c72fcc34Sopenharmony_ci printf("%sCapabilities:", space); 791c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_common_volume(elem)) { 792c72fcc34Sopenharmony_ci printf(" volume"); 793c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume_joined(elem)) 794c72fcc34Sopenharmony_ci printf(" volume-joined"); 795c72fcc34Sopenharmony_ci } else { 796c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem)) { 797c72fcc34Sopenharmony_ci printf(" pvolume"); 798c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume_joined(elem)) 799c72fcc34Sopenharmony_ci printf(" pvolume-joined"); 800c72fcc34Sopenharmony_ci } 801c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume(elem)) { 802c72fcc34Sopenharmony_ci printf(" cvolume"); 803c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume_joined(elem)) 804c72fcc34Sopenharmony_ci printf(" cvolume-joined"); 805c72fcc34Sopenharmony_ci } 806c72fcc34Sopenharmony_ci } 807c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_common_switch(elem)) { 808c72fcc34Sopenharmony_ci printf(" switch"); 809c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_switch_joined(elem)) 810c72fcc34Sopenharmony_ci printf(" switch-joined"); 811c72fcc34Sopenharmony_ci } else { 812c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_switch(elem)) { 813c72fcc34Sopenharmony_ci printf(" pswitch"); 814c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_switch_joined(elem)) 815c72fcc34Sopenharmony_ci printf(" pswitch-joined"); 816c72fcc34Sopenharmony_ci } 817c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch(elem)) { 818c72fcc34Sopenharmony_ci printf(" cswitch"); 819c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch_joined(elem)) 820c72fcc34Sopenharmony_ci printf(" cswitch-joined"); 821c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch_exclusive(elem)) 822c72fcc34Sopenharmony_ci printf(" cswitch-exclusive"); 823c72fcc34Sopenharmony_ci } 824c72fcc34Sopenharmony_ci } 825c72fcc34Sopenharmony_ci if (snd_mixer_selem_is_enum_playback(elem)) { 826c72fcc34Sopenharmony_ci printf(" penum"); 827c72fcc34Sopenharmony_ci } else if (snd_mixer_selem_is_enum_capture(elem)) { 828c72fcc34Sopenharmony_ci printf(" cenum"); 829c72fcc34Sopenharmony_ci } else if (snd_mixer_selem_is_enumerated(elem)) { 830c72fcc34Sopenharmony_ci printf(" enum"); 831c72fcc34Sopenharmony_ci } 832c72fcc34Sopenharmony_ci printf("\n"); 833c72fcc34Sopenharmony_ci if (snd_mixer_selem_is_enumerated(elem)) { 834c72fcc34Sopenharmony_ci int i, items; 835c72fcc34Sopenharmony_ci unsigned int idx; 836c72fcc34Sopenharmony_ci /* 837c72fcc34Sopenharmony_ci * See snd_ctl_elem_init_enum_names() in 838c72fcc34Sopenharmony_ci * sound/core/control.c. 839c72fcc34Sopenharmony_ci */ 840c72fcc34Sopenharmony_ci char itemname[64]; 841c72fcc34Sopenharmony_ci items = snd_mixer_selem_get_enum_items(elem); 842c72fcc34Sopenharmony_ci printf(" Items:"); 843c72fcc34Sopenharmony_ci for (i = 0; i < items; i++) { 844c72fcc34Sopenharmony_ci snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname); 845c72fcc34Sopenharmony_ci printf(" '%s'", itemname); 846c72fcc34Sopenharmony_ci } 847c72fcc34Sopenharmony_ci printf("\n"); 848c72fcc34Sopenharmony_ci for (i = 0; !snd_mixer_selem_get_enum_item(elem, i, &idx); i++) { 849c72fcc34Sopenharmony_ci snd_mixer_selem_get_enum_item_name(elem, idx, sizeof(itemname) - 1, itemname); 850c72fcc34Sopenharmony_ci printf(" Item%d: '%s'\n", i, itemname); 851c72fcc34Sopenharmony_ci } 852c72fcc34Sopenharmony_ci return 0; /* no more thing to do */ 853c72fcc34Sopenharmony_ci } 854c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch_exclusive(elem)) 855c72fcc34Sopenharmony_ci printf("%sCapture exclusive group: %i\n", space, 856c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_group(elem)); 857c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem) || 858c72fcc34Sopenharmony_ci snd_mixer_selem_has_playback_switch(elem)) { 859c72fcc34Sopenharmony_ci printf("%sPlayback channels:", space); 860c72fcc34Sopenharmony_ci if (snd_mixer_selem_is_playback_mono(elem)) { 861c72fcc34Sopenharmony_ci printf(" Mono"); 862c72fcc34Sopenharmony_ci } else { 863c72fcc34Sopenharmony_ci int first = 1; 864c72fcc34Sopenharmony_ci for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){ 865c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_playback_channel(elem, chn)) 866c72fcc34Sopenharmony_ci continue; 867c72fcc34Sopenharmony_ci if (!first) 868c72fcc34Sopenharmony_ci printf(" -"); 869c72fcc34Sopenharmony_ci printf(" %s", snd_mixer_selem_channel_name(chn)); 870c72fcc34Sopenharmony_ci first = 0; 871c72fcc34Sopenharmony_ci } 872c72fcc34Sopenharmony_ci } 873c72fcc34Sopenharmony_ci printf("\n"); 874c72fcc34Sopenharmony_ci } 875c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume(elem) || 876c72fcc34Sopenharmony_ci snd_mixer_selem_has_capture_switch(elem)) { 877c72fcc34Sopenharmony_ci printf("%sCapture channels:", space); 878c72fcc34Sopenharmony_ci if (snd_mixer_selem_is_capture_mono(elem)) { 879c72fcc34Sopenharmony_ci printf(" Mono"); 880c72fcc34Sopenharmony_ci } else { 881c72fcc34Sopenharmony_ci int first = 1; 882c72fcc34Sopenharmony_ci for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){ 883c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_capture_channel(elem, chn)) 884c72fcc34Sopenharmony_ci continue; 885c72fcc34Sopenharmony_ci if (!first) 886c72fcc34Sopenharmony_ci printf(" -"); 887c72fcc34Sopenharmony_ci printf(" %s", snd_mixer_selem_channel_name(chn)); 888c72fcc34Sopenharmony_ci first = 0; 889c72fcc34Sopenharmony_ci } 890c72fcc34Sopenharmony_ci } 891c72fcc34Sopenharmony_ci printf("\n"); 892c72fcc34Sopenharmony_ci } 893c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem) || 894c72fcc34Sopenharmony_ci snd_mixer_selem_has_capture_volume(elem)) { 895c72fcc34Sopenharmony_ci printf("%sLimits:", space); 896c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_common_volume(elem)) { 897c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax); 898c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax); 899c72fcc34Sopenharmony_ci printf(" %li - %li", pmin, pmax); 900c72fcc34Sopenharmony_ci } else { 901c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem)) { 902c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax); 903c72fcc34Sopenharmony_ci printf(" Playback %li - %li", pmin, pmax); 904c72fcc34Sopenharmony_ci } 905c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume(elem)) { 906c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax); 907c72fcc34Sopenharmony_ci printf(" Capture %li - %li", cmin, cmax); 908c72fcc34Sopenharmony_ci } 909c72fcc34Sopenharmony_ci } 910c72fcc34Sopenharmony_ci printf("\n"); 911c72fcc34Sopenharmony_ci } 912c72fcc34Sopenharmony_ci pmono = snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO) && 913c72fcc34Sopenharmony_ci (snd_mixer_selem_is_playback_mono(elem) || 914c72fcc34Sopenharmony_ci (!snd_mixer_selem_has_playback_volume(elem) && 915c72fcc34Sopenharmony_ci !snd_mixer_selem_has_playback_switch(elem))); 916c72fcc34Sopenharmony_ci cmono = snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO) && 917c72fcc34Sopenharmony_ci (snd_mixer_selem_is_capture_mono(elem) || 918c72fcc34Sopenharmony_ci (!snd_mixer_selem_has_capture_volume(elem) && 919c72fcc34Sopenharmony_ci !snd_mixer_selem_has_capture_switch(elem))); 920c72fcc34Sopenharmony_ci#if 0 921c72fcc34Sopenharmony_ci printf("pmono = %i, cmono = %i (%i, %i, %i, %i)\n", pmono, cmono, 922c72fcc34Sopenharmony_ci snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO), 923c72fcc34Sopenharmony_ci snd_mixer_selem_is_capture_mono(elem), 924c72fcc34Sopenharmony_ci snd_mixer_selem_has_capture_volume(elem), 925c72fcc34Sopenharmony_ci snd_mixer_selem_has_capture_switch(elem)); 926c72fcc34Sopenharmony_ci#endif 927c72fcc34Sopenharmony_ci if (pmono || cmono) { 928c72fcc34Sopenharmony_ci if (!mono_ok) { 929c72fcc34Sopenharmony_ci printf("%s%s:", space, "Mono"); 930c72fcc34Sopenharmony_ci mono_ok = 1; 931c72fcc34Sopenharmony_ci } 932c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_common_volume(elem)) { 933c72fcc34Sopenharmony_ci show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax); 934c72fcc34Sopenharmony_ci } 935c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_common_switch(elem)) { 936c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw); 937c72fcc34Sopenharmony_ci printf(" [%s]", psw ? "on" : "off"); 938c72fcc34Sopenharmony_ci } 939c72fcc34Sopenharmony_ci } 940c72fcc34Sopenharmony_ci if (pmono && snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO)) { 941c72fcc34Sopenharmony_ci int title = 0; 942c72fcc34Sopenharmony_ci if (!mono_ok) { 943c72fcc34Sopenharmony_ci printf("%s%s:", space, "Mono"); 944c72fcc34Sopenharmony_ci mono_ok = 1; 945c72fcc34Sopenharmony_ci } 946c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_volume(elem)) { 947c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem)) { 948c72fcc34Sopenharmony_ci printf(" Playback"); 949c72fcc34Sopenharmony_ci title = 1; 950c72fcc34Sopenharmony_ci show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax); 951c72fcc34Sopenharmony_ci } 952c72fcc34Sopenharmony_ci } 953c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_switch(elem)) { 954c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_switch(elem)) { 955c72fcc34Sopenharmony_ci if (!title) 956c72fcc34Sopenharmony_ci printf(" Playback"); 957c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw); 958c72fcc34Sopenharmony_ci printf(" [%s]", psw ? "on" : "off"); 959c72fcc34Sopenharmony_ci } 960c72fcc34Sopenharmony_ci } 961c72fcc34Sopenharmony_ci } 962c72fcc34Sopenharmony_ci if (cmono && snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO)) { 963c72fcc34Sopenharmony_ci int title = 0; 964c72fcc34Sopenharmony_ci if (!mono_ok) { 965c72fcc34Sopenharmony_ci printf("%s%s:", space, "Mono"); 966c72fcc34Sopenharmony_ci mono_ok = 1; 967c72fcc34Sopenharmony_ci } 968c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_volume(elem)) { 969c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume(elem)) { 970c72fcc34Sopenharmony_ci printf(" Capture"); 971c72fcc34Sopenharmony_ci title = 1; 972c72fcc34Sopenharmony_ci show_selem_volume(elem, SND_MIXER_SCHN_MONO, 1, cmin, cmax); 973c72fcc34Sopenharmony_ci } 974c72fcc34Sopenharmony_ci } 975c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_switch(elem)) { 976c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch(elem)) { 977c72fcc34Sopenharmony_ci if (!title) 978c72fcc34Sopenharmony_ci printf(" Capture"); 979c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_MONO, &csw); 980c72fcc34Sopenharmony_ci printf(" [%s]", csw ? "on" : "off"); 981c72fcc34Sopenharmony_ci } 982c72fcc34Sopenharmony_ci } 983c72fcc34Sopenharmony_ci } 984c72fcc34Sopenharmony_ci if (pmono || cmono) 985c72fcc34Sopenharmony_ci printf("\n"); 986c72fcc34Sopenharmony_ci if (!pmono || !cmono) { 987c72fcc34Sopenharmony_ci for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) { 988c72fcc34Sopenharmony_ci if ((pmono || !snd_mixer_selem_has_playback_channel(elem, chn)) && 989c72fcc34Sopenharmony_ci (cmono || !snd_mixer_selem_has_capture_channel(elem, chn))) 990c72fcc34Sopenharmony_ci continue; 991c72fcc34Sopenharmony_ci printf("%s%s:", space, snd_mixer_selem_channel_name(chn)); 992c72fcc34Sopenharmony_ci if (!pmono && !cmono && snd_mixer_selem_has_common_volume(elem)) { 993c72fcc34Sopenharmony_ci show_selem_volume(elem, chn, 0, pmin, pmax); 994c72fcc34Sopenharmony_ci } 995c72fcc34Sopenharmony_ci if (!pmono && !cmono && snd_mixer_selem_has_common_switch(elem)) { 996c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &psw); 997c72fcc34Sopenharmony_ci printf(" [%s]", psw ? "on" : "off"); 998c72fcc34Sopenharmony_ci } 999c72fcc34Sopenharmony_ci if (!pmono && snd_mixer_selem_has_playback_channel(elem, chn)) { 1000c72fcc34Sopenharmony_ci int title = 0; 1001c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_volume(elem)) { 1002c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_volume(elem)) { 1003c72fcc34Sopenharmony_ci printf(" Playback"); 1004c72fcc34Sopenharmony_ci title = 1; 1005c72fcc34Sopenharmony_ci show_selem_volume(elem, chn, 0, pmin, pmax); 1006c72fcc34Sopenharmony_ci } 1007c72fcc34Sopenharmony_ci } 1008c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_switch(elem)) { 1009c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_playback_switch(elem)) { 1010c72fcc34Sopenharmony_ci if (!title) 1011c72fcc34Sopenharmony_ci printf(" Playback"); 1012c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &psw); 1013c72fcc34Sopenharmony_ci printf(" [%s]", psw ? "on" : "off"); 1014c72fcc34Sopenharmony_ci } 1015c72fcc34Sopenharmony_ci } 1016c72fcc34Sopenharmony_ci } 1017c72fcc34Sopenharmony_ci if (!cmono && snd_mixer_selem_has_capture_channel(elem, chn)) { 1018c72fcc34Sopenharmony_ci int title = 0; 1019c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_volume(elem)) { 1020c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_volume(elem)) { 1021c72fcc34Sopenharmony_ci printf(" Capture"); 1022c72fcc34Sopenharmony_ci title = 1; 1023c72fcc34Sopenharmony_ci show_selem_volume(elem, chn, 1, cmin, cmax); 1024c72fcc34Sopenharmony_ci } 1025c72fcc34Sopenharmony_ci } 1026c72fcc34Sopenharmony_ci if (!snd_mixer_selem_has_common_switch(elem)) { 1027c72fcc34Sopenharmony_ci if (snd_mixer_selem_has_capture_switch(elem)) { 1028c72fcc34Sopenharmony_ci if (!title) 1029c72fcc34Sopenharmony_ci printf(" Capture"); 1030c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &csw); 1031c72fcc34Sopenharmony_ci printf(" [%s]", csw ? "on" : "off"); 1032c72fcc34Sopenharmony_ci } 1033c72fcc34Sopenharmony_ci } 1034c72fcc34Sopenharmony_ci } 1035c72fcc34Sopenharmony_ci printf("\n"); 1036c72fcc34Sopenharmony_ci } 1037c72fcc34Sopenharmony_ci } 1038c72fcc34Sopenharmony_ci } 1039c72fcc34Sopenharmony_ci return 0; 1040c72fcc34Sopenharmony_ci} 1041c72fcc34Sopenharmony_ci 1042c72fcc34Sopenharmony_cistatic int selems(int level) 1043c72fcc34Sopenharmony_ci{ 1044c72fcc34Sopenharmony_ci int err; 1045c72fcc34Sopenharmony_ci snd_mixer_t *handle; 1046c72fcc34Sopenharmony_ci snd_mixer_selem_id_t *sid; 1047c72fcc34Sopenharmony_ci snd_mixer_elem_t *elem; 1048c72fcc34Sopenharmony_ci snd_mixer_selem_id_alloca(&sid); 1049c72fcc34Sopenharmony_ci 1050c72fcc34Sopenharmony_ci if ((err = snd_mixer_open(&handle, 0)) < 0) { 1051c72fcc34Sopenharmony_ci error("Mixer %s open error: %s", card, snd_strerror(err)); 1052c72fcc34Sopenharmony_ci return err; 1053c72fcc34Sopenharmony_ci } 1054c72fcc34Sopenharmony_ci if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { 1055c72fcc34Sopenharmony_ci error("Mixer attach %s error: %s", card, snd_strerror(err)); 1056c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1057c72fcc34Sopenharmony_ci return err; 1058c72fcc34Sopenharmony_ci } 1059c72fcc34Sopenharmony_ci if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { 1060c72fcc34Sopenharmony_ci error("Mixer register error: %s", snd_strerror(err)); 1061c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1062c72fcc34Sopenharmony_ci return err; 1063c72fcc34Sopenharmony_ci } 1064c72fcc34Sopenharmony_ci err = snd_mixer_load(handle); 1065c72fcc34Sopenharmony_ci if (err < 0) { 1066c72fcc34Sopenharmony_ci error("Mixer %s load error: %s", card, snd_strerror(err)); 1067c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1068c72fcc34Sopenharmony_ci return err; 1069c72fcc34Sopenharmony_ci } 1070c72fcc34Sopenharmony_ci for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) { 1071c72fcc34Sopenharmony_ci snd_mixer_selem_get_id(elem, sid); 1072c72fcc34Sopenharmony_ci if (!(level & LEVEL_INACTIVE) && !snd_mixer_selem_is_active(elem)) 1073c72fcc34Sopenharmony_ci continue; 1074c72fcc34Sopenharmony_ci printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1075c72fcc34Sopenharmony_ci show_selem(handle, sid, " ", level); 1076c72fcc34Sopenharmony_ci } 1077c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1078c72fcc34Sopenharmony_ci return 0; 1079c72fcc34Sopenharmony_ci} 1080c72fcc34Sopenharmony_ci 1081c72fcc34Sopenharmony_cistatic int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid) 1082c72fcc34Sopenharmony_ci{ 1083c72fcc34Sopenharmony_ci int c, size; 1084c72fcc34Sopenharmony_ci char buf[128]; 1085c72fcc34Sopenharmony_ci char *ptr = buf; 1086c72fcc34Sopenharmony_ci 1087c72fcc34Sopenharmony_ci while (*str == ' ' || *str == '\t') 1088c72fcc34Sopenharmony_ci str++; 1089c72fcc34Sopenharmony_ci if (!(*str)) 1090c72fcc34Sopenharmony_ci return -EINVAL; 1091c72fcc34Sopenharmony_ci size = 1; /* for '\0' */ 1092c72fcc34Sopenharmony_ci if (*str != '"' && *str != '\'') { 1093c72fcc34Sopenharmony_ci while (*str && *str != ',') { 1094c72fcc34Sopenharmony_ci if (size < (int)sizeof(buf)) { 1095c72fcc34Sopenharmony_ci *ptr++ = *str; 1096c72fcc34Sopenharmony_ci size++; 1097c72fcc34Sopenharmony_ci } 1098c72fcc34Sopenharmony_ci str++; 1099c72fcc34Sopenharmony_ci } 1100c72fcc34Sopenharmony_ci } else { 1101c72fcc34Sopenharmony_ci c = *str++; 1102c72fcc34Sopenharmony_ci while (*str && *str != c) { 1103c72fcc34Sopenharmony_ci if (size < (int)sizeof(buf)) { 1104c72fcc34Sopenharmony_ci *ptr++ = *str; 1105c72fcc34Sopenharmony_ci size++; 1106c72fcc34Sopenharmony_ci } 1107c72fcc34Sopenharmony_ci str++; 1108c72fcc34Sopenharmony_ci } 1109c72fcc34Sopenharmony_ci if (*str == c) 1110c72fcc34Sopenharmony_ci str++; 1111c72fcc34Sopenharmony_ci } 1112c72fcc34Sopenharmony_ci if (*str == '\0') { 1113c72fcc34Sopenharmony_ci snd_mixer_selem_id_set_index(sid, 0); 1114c72fcc34Sopenharmony_ci *ptr = 0; 1115c72fcc34Sopenharmony_ci goto _set; 1116c72fcc34Sopenharmony_ci } 1117c72fcc34Sopenharmony_ci if (*str != ',') 1118c72fcc34Sopenharmony_ci return -EINVAL; 1119c72fcc34Sopenharmony_ci *ptr = 0; /* terminate the string */ 1120c72fcc34Sopenharmony_ci str++; 1121c72fcc34Sopenharmony_ci if (!isdigit(*str)) 1122c72fcc34Sopenharmony_ci return -EINVAL; 1123c72fcc34Sopenharmony_ci snd_mixer_selem_id_set_index(sid, atoi(str)); 1124c72fcc34Sopenharmony_ci _set: 1125c72fcc34Sopenharmony_ci snd_mixer_selem_id_set_name(sid, buf); 1126c72fcc34Sopenharmony_ci return 0; 1127c72fcc34Sopenharmony_ci} 1128c72fcc34Sopenharmony_ci 1129c72fcc34Sopenharmony_cistatic int cset(int argc, char *argv[], int roflag, int keep_handle) 1130c72fcc34Sopenharmony_ci{ 1131c72fcc34Sopenharmony_ci int err; 1132c72fcc34Sopenharmony_ci static snd_ctl_t *handle = NULL; 1133c72fcc34Sopenharmony_ci snd_ctl_elem_info_t *info; 1134c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 1135c72fcc34Sopenharmony_ci snd_ctl_elem_value_t *control; 1136c72fcc34Sopenharmony_ci snd_ctl_elem_info_alloca(&info); 1137c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 1138c72fcc34Sopenharmony_ci snd_ctl_elem_value_alloca(&control); 1139c72fcc34Sopenharmony_ci 1140c72fcc34Sopenharmony_ci if (argc < 1) { 1141c72fcc34Sopenharmony_ci fprintf(stderr, "Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n"); 1142c72fcc34Sopenharmony_ci return -EINVAL; 1143c72fcc34Sopenharmony_ci } 1144c72fcc34Sopenharmony_ci if (snd_ctl_ascii_elem_id_parse(id, argv[0])) { 1145c72fcc34Sopenharmony_ci fprintf(stderr, "Wrong control identifier: %s\n", argv[0]); 1146c72fcc34Sopenharmony_ci return -EINVAL; 1147c72fcc34Sopenharmony_ci } 1148c72fcc34Sopenharmony_ci if (debugflag) { 1149c72fcc34Sopenharmony_ci printf("VERIFY ID: "); 1150c72fcc34Sopenharmony_ci show_control_id(id); 1151c72fcc34Sopenharmony_ci printf("\n"); 1152c72fcc34Sopenharmony_ci } 1153c72fcc34Sopenharmony_ci if (handle == NULL && 1154c72fcc34Sopenharmony_ci (err = snd_ctl_open(&handle, card, 0)) < 0) { 1155c72fcc34Sopenharmony_ci error("Control %s open error: %s\n", card, snd_strerror(err)); 1156c72fcc34Sopenharmony_ci return err; 1157c72fcc34Sopenharmony_ci } 1158c72fcc34Sopenharmony_ci snd_ctl_elem_info_set_id(info, id); 1159c72fcc34Sopenharmony_ci if ((err = snd_ctl_elem_info(handle, info)) < 0) { 1160c72fcc34Sopenharmony_ci if (ignore_error) 1161c72fcc34Sopenharmony_ci return 0; 1162c72fcc34Sopenharmony_ci error("Cannot find the given element from control %s\n", card); 1163c72fcc34Sopenharmony_ci if (! keep_handle) { 1164c72fcc34Sopenharmony_ci snd_ctl_close(handle); 1165c72fcc34Sopenharmony_ci handle = NULL; 1166c72fcc34Sopenharmony_ci } 1167c72fcc34Sopenharmony_ci return err; 1168c72fcc34Sopenharmony_ci } 1169c72fcc34Sopenharmony_ci snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ 1170c72fcc34Sopenharmony_ci if (!roflag) { 1171c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_id(control, id); 1172c72fcc34Sopenharmony_ci if ((err = snd_ctl_elem_read(handle, control)) < 0) { 1173c72fcc34Sopenharmony_ci if (ignore_error) 1174c72fcc34Sopenharmony_ci return 0; 1175c72fcc34Sopenharmony_ci error("Cannot read the given element from control %s\n", card); 1176c72fcc34Sopenharmony_ci if (! keep_handle) { 1177c72fcc34Sopenharmony_ci snd_ctl_close(handle); 1178c72fcc34Sopenharmony_ci handle = NULL; 1179c72fcc34Sopenharmony_ci } 1180c72fcc34Sopenharmony_ci return err; 1181c72fcc34Sopenharmony_ci } 1182c72fcc34Sopenharmony_ci err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]); 1183c72fcc34Sopenharmony_ci if (err < 0) { 1184c72fcc34Sopenharmony_ci if (!ignore_error) 1185c72fcc34Sopenharmony_ci error("Control %s parse error: %s\n", card, snd_strerror(err)); 1186c72fcc34Sopenharmony_ci if (!keep_handle) { 1187c72fcc34Sopenharmony_ci snd_ctl_close(handle); 1188c72fcc34Sopenharmony_ci handle = NULL; 1189c72fcc34Sopenharmony_ci } 1190c72fcc34Sopenharmony_ci return ignore_error ? 0 : err; 1191c72fcc34Sopenharmony_ci } 1192c72fcc34Sopenharmony_ci if ((err = snd_ctl_elem_write(handle, control)) < 0) { 1193c72fcc34Sopenharmony_ci if (!ignore_error) 1194c72fcc34Sopenharmony_ci error("Control %s element write error: %s\n", card, snd_strerror(err)); 1195c72fcc34Sopenharmony_ci if (!keep_handle) { 1196c72fcc34Sopenharmony_ci snd_ctl_close(handle); 1197c72fcc34Sopenharmony_ci handle = NULL; 1198c72fcc34Sopenharmony_ci } 1199c72fcc34Sopenharmony_ci return ignore_error ? 0 : err; 1200c72fcc34Sopenharmony_ci } 1201c72fcc34Sopenharmony_ci } 1202c72fcc34Sopenharmony_ci if (! keep_handle) { 1203c72fcc34Sopenharmony_ci snd_ctl_close(handle); 1204c72fcc34Sopenharmony_ci handle = NULL; 1205c72fcc34Sopenharmony_ci } 1206c72fcc34Sopenharmony_ci if (!quiet) { 1207c72fcc34Sopenharmony_ci snd_hctl_t *hctl; 1208c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 1209c72fcc34Sopenharmony_ci if ((err = snd_hctl_open(&hctl, card, 0)) < 0) { 1210c72fcc34Sopenharmony_ci error("Control %s open error: %s\n", card, snd_strerror(err)); 1211c72fcc34Sopenharmony_ci return err; 1212c72fcc34Sopenharmony_ci } 1213c72fcc34Sopenharmony_ci if ((err = snd_hctl_load(hctl)) < 0) { 1214c72fcc34Sopenharmony_ci error("Control %s load error: %s\n", card, snd_strerror(err)); 1215c72fcc34Sopenharmony_ci return err; 1216c72fcc34Sopenharmony_ci } 1217c72fcc34Sopenharmony_ci elem = snd_hctl_find_elem(hctl, id); 1218c72fcc34Sopenharmony_ci if (elem) 1219c72fcc34Sopenharmony_ci show_control(" ", elem, LEVEL_BASIC | LEVEL_ID); 1220c72fcc34Sopenharmony_ci else 1221c72fcc34Sopenharmony_ci printf("Could not find the specified element\n"); 1222c72fcc34Sopenharmony_ci snd_hctl_close(hctl); 1223c72fcc34Sopenharmony_ci } 1224c72fcc34Sopenharmony_ci return 0; 1225c72fcc34Sopenharmony_ci} 1226c72fcc34Sopenharmony_ci 1227c72fcc34Sopenharmony_citypedef struct channel_mask { 1228c72fcc34Sopenharmony_ci char *name; 1229c72fcc34Sopenharmony_ci unsigned int mask; 1230c72fcc34Sopenharmony_ci} channel_mask_t; 1231c72fcc34Sopenharmony_cistatic const channel_mask_t chanmask[] = { 1232c72fcc34Sopenharmony_ci {"frontleft", 1 << SND_MIXER_SCHN_FRONT_LEFT}, 1233c72fcc34Sopenharmony_ci {"frontright", 1 << SND_MIXER_SCHN_FRONT_RIGHT}, 1234c72fcc34Sopenharmony_ci {"frontcenter", 1 << SND_MIXER_SCHN_FRONT_CENTER}, 1235c72fcc34Sopenharmony_ci {"front", ((1 << SND_MIXER_SCHN_FRONT_LEFT) | 1236c72fcc34Sopenharmony_ci (1 << SND_MIXER_SCHN_FRONT_RIGHT))}, 1237c72fcc34Sopenharmony_ci {"center", 1 << SND_MIXER_SCHN_FRONT_CENTER}, 1238c72fcc34Sopenharmony_ci {"rearleft", 1 << SND_MIXER_SCHN_REAR_LEFT}, 1239c72fcc34Sopenharmony_ci {"rearright", 1 << SND_MIXER_SCHN_REAR_RIGHT}, 1240c72fcc34Sopenharmony_ci {"rear", ((1 << SND_MIXER_SCHN_REAR_LEFT) | 1241c72fcc34Sopenharmony_ci (1 << SND_MIXER_SCHN_REAR_RIGHT))}, 1242c72fcc34Sopenharmony_ci {"woofer", 1 << SND_MIXER_SCHN_WOOFER}, 1243c72fcc34Sopenharmony_ci {NULL, 0} 1244c72fcc34Sopenharmony_ci}; 1245c72fcc34Sopenharmony_ci 1246c72fcc34Sopenharmony_cistatic unsigned int channels_mask(char **arg, unsigned int def) 1247c72fcc34Sopenharmony_ci{ 1248c72fcc34Sopenharmony_ci const channel_mask_t *c; 1249c72fcc34Sopenharmony_ci 1250c72fcc34Sopenharmony_ci for (c = chanmask; c->name; c++) { 1251c72fcc34Sopenharmony_ci if (strncasecmp(*arg, c->name, strlen(c->name)) == 0) { 1252c72fcc34Sopenharmony_ci while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t') 1253c72fcc34Sopenharmony_ci (*arg)++; 1254c72fcc34Sopenharmony_ci if (**arg == ',' || **arg == ' ' || **arg == '\t') 1255c72fcc34Sopenharmony_ci (*arg)++; 1256c72fcc34Sopenharmony_ci return c->mask; 1257c72fcc34Sopenharmony_ci } 1258c72fcc34Sopenharmony_ci } 1259c72fcc34Sopenharmony_ci return def; 1260c72fcc34Sopenharmony_ci} 1261c72fcc34Sopenharmony_ci 1262c72fcc34Sopenharmony_cistatic unsigned int dir_mask(char **arg, unsigned int def) 1263c72fcc34Sopenharmony_ci{ 1264c72fcc34Sopenharmony_ci int findend = 0; 1265c72fcc34Sopenharmony_ci 1266c72fcc34Sopenharmony_ci if (strncasecmp(*arg, "playback", 8) == 0) 1267c72fcc34Sopenharmony_ci def = findend = 1; 1268c72fcc34Sopenharmony_ci else if (strncasecmp(*arg, "capture", 8) == 0) 1269c72fcc34Sopenharmony_ci def = findend = 2; 1270c72fcc34Sopenharmony_ci if (findend) { 1271c72fcc34Sopenharmony_ci while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t') 1272c72fcc34Sopenharmony_ci (*arg)++; 1273c72fcc34Sopenharmony_ci if (**arg == ',' || **arg == ' ' || **arg == '\t') 1274c72fcc34Sopenharmony_ci (*arg)++; 1275c72fcc34Sopenharmony_ci } 1276c72fcc34Sopenharmony_ci return def; 1277c72fcc34Sopenharmony_ci} 1278c72fcc34Sopenharmony_ci 1279c72fcc34Sopenharmony_cistatic int get_enum_item_index(snd_mixer_elem_t *elem, char **ptrp) 1280c72fcc34Sopenharmony_ci{ 1281c72fcc34Sopenharmony_ci char *ptr = *ptrp; 1282c72fcc34Sopenharmony_ci int items, i, len; 1283c72fcc34Sopenharmony_ci 1284c72fcc34Sopenharmony_ci /* See snd_ctl_elem_init_enum_names() in sound/core/control.c. */ 1285c72fcc34Sopenharmony_ci char name[64]; 1286c72fcc34Sopenharmony_ci 1287c72fcc34Sopenharmony_ci items = snd_mixer_selem_get_enum_items(elem); 1288c72fcc34Sopenharmony_ci if (items <= 0) 1289c72fcc34Sopenharmony_ci return -1; 1290c72fcc34Sopenharmony_ci 1291c72fcc34Sopenharmony_ci for (i = 0; i < items; i++) { 1292c72fcc34Sopenharmony_ci if (snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name) < 0) 1293c72fcc34Sopenharmony_ci continue; 1294c72fcc34Sopenharmony_ci 1295c72fcc34Sopenharmony_ci len = strlen(name); 1296c72fcc34Sopenharmony_ci if (! strncmp(name, ptr, len)) { 1297c72fcc34Sopenharmony_ci if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') { 1298c72fcc34Sopenharmony_ci ptr += len; 1299c72fcc34Sopenharmony_ci *ptrp = ptr; 1300c72fcc34Sopenharmony_ci return i; 1301c72fcc34Sopenharmony_ci } 1302c72fcc34Sopenharmony_ci } 1303c72fcc34Sopenharmony_ci } 1304c72fcc34Sopenharmony_ci return -1; 1305c72fcc34Sopenharmony_ci} 1306c72fcc34Sopenharmony_ci 1307c72fcc34Sopenharmony_cistatic int sset_enum(snd_mixer_elem_t *elem, unsigned int argc, char **argv) 1308c72fcc34Sopenharmony_ci{ 1309c72fcc34Sopenharmony_ci unsigned int idx, item = 0; 1310c72fcc34Sopenharmony_ci int check_flag = ignore_error ? 0 : -1; 1311c72fcc34Sopenharmony_ci 1312c72fcc34Sopenharmony_ci for (idx = 1; idx < argc; idx++) { 1313c72fcc34Sopenharmony_ci char *ptr = argv[idx]; 1314c72fcc34Sopenharmony_ci while (*ptr) { 1315c72fcc34Sopenharmony_ci int ival = get_enum_item_index(elem, &ptr); 1316c72fcc34Sopenharmony_ci if (ival < 0) 1317c72fcc34Sopenharmony_ci return check_flag; 1318c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_enum_item(elem, item++, ival) >= 0) 1319c72fcc34Sopenharmony_ci check_flag = 1; 1320c72fcc34Sopenharmony_ci /* skip separators */ 1321c72fcc34Sopenharmony_ci while (*ptr == ',' || isspace(*ptr)) 1322c72fcc34Sopenharmony_ci ptr++; 1323c72fcc34Sopenharmony_ci } 1324c72fcc34Sopenharmony_ci } 1325c72fcc34Sopenharmony_ci return check_flag; 1326c72fcc34Sopenharmony_ci} 1327c72fcc34Sopenharmony_ci 1328c72fcc34Sopenharmony_cistatic int sset_channels(snd_mixer_elem_t *elem, unsigned int argc, char **argv) 1329c72fcc34Sopenharmony_ci{ 1330c72fcc34Sopenharmony_ci unsigned int channels = ~0U; 1331c72fcc34Sopenharmony_ci unsigned int dir = 3, okflag = 3; 1332c72fcc34Sopenharmony_ci unsigned int idx; 1333c72fcc34Sopenharmony_ci snd_mixer_selem_channel_id_t chn; 1334c72fcc34Sopenharmony_ci int check_flag = ignore_error ? 0 : -1; 1335c72fcc34Sopenharmony_ci 1336c72fcc34Sopenharmony_ci for (idx = 1; idx < argc; idx++) { 1337c72fcc34Sopenharmony_ci char *ptr = argv[idx], *optr; 1338c72fcc34Sopenharmony_ci int multi, firstchn = 1; 1339c72fcc34Sopenharmony_ci channels = channels_mask(&ptr, channels); 1340c72fcc34Sopenharmony_ci if (*ptr == '\0') 1341c72fcc34Sopenharmony_ci continue; 1342c72fcc34Sopenharmony_ci dir = dir_mask(&ptr, dir); 1343c72fcc34Sopenharmony_ci if (*ptr == '\0') 1344c72fcc34Sopenharmony_ci continue; 1345c72fcc34Sopenharmony_ci multi = (strchr(ptr, ',') != NULL); 1346c72fcc34Sopenharmony_ci optr = ptr; 1347c72fcc34Sopenharmony_ci for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) { 1348c72fcc34Sopenharmony_ci char *sptr = NULL; 1349c72fcc34Sopenharmony_ci int ival; 1350c72fcc34Sopenharmony_ci 1351c72fcc34Sopenharmony_ci if (!(channels & (1 << chn))) 1352c72fcc34Sopenharmony_ci continue; 1353c72fcc34Sopenharmony_ci 1354c72fcc34Sopenharmony_ci if ((dir & 1) && snd_mixer_selem_has_playback_channel(elem, chn)) { 1355c72fcc34Sopenharmony_ci sptr = ptr; 1356c72fcc34Sopenharmony_ci if (!strncmp(ptr, "mute", 4) && snd_mixer_selem_has_playback_switch(elem)) { 1357c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &ival); 1358c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "mute", 1, ival)) >= 0) 1359c72fcc34Sopenharmony_ci check_flag = 1; 1360c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "off", 3) && snd_mixer_selem_has_playback_switch(elem)) { 1361c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &ival); 1362c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "off", 1, ival)) >= 0) 1363c72fcc34Sopenharmony_ci check_flag = 1; 1364c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "unmute", 6) && snd_mixer_selem_has_playback_switch(elem)) { 1365c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &ival); 1366c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "unmute", 0, ival)) >= 0) 1367c72fcc34Sopenharmony_ci check_flag = 1; 1368c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "on", 2) && snd_mixer_selem_has_playback_switch(elem)) { 1369c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &ival); 1370c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "on", 0, ival)) >= 0) 1371c72fcc34Sopenharmony_ci check_flag = 1; 1372c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_playback_switch(elem)) { 1373c72fcc34Sopenharmony_ci if (firstchn || !snd_mixer_selem_has_playback_switch_joined(elem)) { 1374c72fcc34Sopenharmony_ci snd_mixer_selem_get_playback_switch(elem, chn, &ival); 1375c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_playback_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0) 1376c72fcc34Sopenharmony_ci check_flag = 1; 1377c72fcc34Sopenharmony_ci } 1378c72fcc34Sopenharmony_ci simple_skip_word(&ptr, "toggle"); 1379c72fcc34Sopenharmony_ci } else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') { 1380c72fcc34Sopenharmony_ci if (set_volume_simple(elem, chn, &ptr, 0) >= 0) 1381c72fcc34Sopenharmony_ci check_flag = 1; 1382c72fcc34Sopenharmony_ci } else if (simple_skip_word(&ptr, "cap") || simple_skip_word(&ptr, "rec") || 1383c72fcc34Sopenharmony_ci simple_skip_word(&ptr, "nocap") || simple_skip_word(&ptr, "norec")) { 1384c72fcc34Sopenharmony_ci /* nothing */ 1385c72fcc34Sopenharmony_ci } else { 1386c72fcc34Sopenharmony_ci okflag &= ~1; 1387c72fcc34Sopenharmony_ci } 1388c72fcc34Sopenharmony_ci } 1389c72fcc34Sopenharmony_ci if ((dir & 2) && snd_mixer_selem_has_capture_channel(elem, chn)) { 1390c72fcc34Sopenharmony_ci if (sptr != NULL) 1391c72fcc34Sopenharmony_ci ptr = sptr; 1392c72fcc34Sopenharmony_ci sptr = ptr; 1393c72fcc34Sopenharmony_ci if (!strncmp(ptr, "cap", 3) && snd_mixer_selem_has_capture_switch(elem)) { 1394c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &ival); 1395c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "cap", 0, ival)) >= 0) 1396c72fcc34Sopenharmony_ci check_flag = 1; 1397c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "rec", 3) && snd_mixer_selem_has_capture_switch(elem)) { 1398c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &ival); 1399c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "rec", 0, ival)) >= 0) 1400c72fcc34Sopenharmony_ci check_flag = 1; 1401c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "nocap", 5) && snd_mixer_selem_has_capture_switch(elem)) { 1402c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &ival); 1403c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "nocap", 1, ival)) >= 0) 1404c72fcc34Sopenharmony_ci check_flag = 1; 1405c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "norec", 5) && snd_mixer_selem_has_capture_switch(elem)) { 1406c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &ival); 1407c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "norec", 1, ival)) >= 0) 1408c72fcc34Sopenharmony_ci check_flag = 1; 1409c72fcc34Sopenharmony_ci } else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_capture_switch(elem)) { 1410c72fcc34Sopenharmony_ci if (firstchn || !snd_mixer_selem_has_capture_switch_joined(elem)) { 1411c72fcc34Sopenharmony_ci snd_mixer_selem_get_capture_switch(elem, chn, &ival); 1412c72fcc34Sopenharmony_ci if (snd_mixer_selem_set_capture_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0) 1413c72fcc34Sopenharmony_ci check_flag = 1; 1414c72fcc34Sopenharmony_ci } 1415c72fcc34Sopenharmony_ci simple_skip_word(&ptr, "toggle"); 1416c72fcc34Sopenharmony_ci } else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') { 1417c72fcc34Sopenharmony_ci if (set_volume_simple(elem, chn, &ptr, 1) >= 0) 1418c72fcc34Sopenharmony_ci check_flag = 1; 1419c72fcc34Sopenharmony_ci } else if (simple_skip_word(&ptr, "mute") || simple_skip_word(&ptr, "off") || 1420c72fcc34Sopenharmony_ci simple_skip_word(&ptr, "unmute") || simple_skip_word(&ptr, "on")) { 1421c72fcc34Sopenharmony_ci /* nothing */ 1422c72fcc34Sopenharmony_ci } else { 1423c72fcc34Sopenharmony_ci okflag &= ~2; 1424c72fcc34Sopenharmony_ci } 1425c72fcc34Sopenharmony_ci } 1426c72fcc34Sopenharmony_ci if (okflag == 0) { 1427c72fcc34Sopenharmony_ci if (debugflag) { 1428c72fcc34Sopenharmony_ci if (dir & 1) 1429c72fcc34Sopenharmony_ci error("Unknown playback setup '%s'..", ptr); 1430c72fcc34Sopenharmony_ci if (dir & 2) 1431c72fcc34Sopenharmony_ci error("Unknown capture setup '%s'..", ptr); 1432c72fcc34Sopenharmony_ci } 1433c72fcc34Sopenharmony_ci return 0; /* just skip it */ 1434c72fcc34Sopenharmony_ci } 1435c72fcc34Sopenharmony_ci if (!multi) 1436c72fcc34Sopenharmony_ci ptr = optr; 1437c72fcc34Sopenharmony_ci firstchn = 0; 1438c72fcc34Sopenharmony_ci } 1439c72fcc34Sopenharmony_ci } 1440c72fcc34Sopenharmony_ci return check_flag; 1441c72fcc34Sopenharmony_ci} 1442c72fcc34Sopenharmony_ci 1443c72fcc34Sopenharmony_cistatic int sset(unsigned int argc, char *argv[], int roflag, int keep_handle) 1444c72fcc34Sopenharmony_ci{ 1445c72fcc34Sopenharmony_ci int err = 0; 1446c72fcc34Sopenharmony_ci static snd_mixer_t *handle = NULL; 1447c72fcc34Sopenharmony_ci snd_mixer_elem_t *elem; 1448c72fcc34Sopenharmony_ci snd_mixer_selem_id_t *sid; 1449c72fcc34Sopenharmony_ci snd_mixer_selem_id_alloca(&sid); 1450c72fcc34Sopenharmony_ci 1451c72fcc34Sopenharmony_ci if (argc < 1) { 1452c72fcc34Sopenharmony_ci fprintf(stderr, "Specify a scontrol identifier: 'name',index\n"); 1453c72fcc34Sopenharmony_ci return 1; 1454c72fcc34Sopenharmony_ci } 1455c72fcc34Sopenharmony_ci if (parse_simple_id(argv[0], sid)) { 1456c72fcc34Sopenharmony_ci fprintf(stderr, "Wrong scontrol identifier: %s\n", argv[0]); 1457c72fcc34Sopenharmony_ci return 1; 1458c72fcc34Sopenharmony_ci } 1459c72fcc34Sopenharmony_ci if (!roflag && argc < 2) { 1460c72fcc34Sopenharmony_ci fprintf(stderr, "Specify what you want to set...\n"); 1461c72fcc34Sopenharmony_ci return 1; 1462c72fcc34Sopenharmony_ci } 1463c72fcc34Sopenharmony_ci if (handle == NULL) { 1464c72fcc34Sopenharmony_ci if ((err = snd_mixer_open(&handle, 0)) < 0) { 1465c72fcc34Sopenharmony_ci error("Mixer %s open error: %s\n", card, snd_strerror(err)); 1466c72fcc34Sopenharmony_ci return err; 1467c72fcc34Sopenharmony_ci } 1468c72fcc34Sopenharmony_ci if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { 1469c72fcc34Sopenharmony_ci error("Mixer attach %s error: %s", card, snd_strerror(err)); 1470c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1471c72fcc34Sopenharmony_ci handle = NULL; 1472c72fcc34Sopenharmony_ci return err; 1473c72fcc34Sopenharmony_ci } 1474c72fcc34Sopenharmony_ci if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { 1475c72fcc34Sopenharmony_ci error("Mixer register error: %s", snd_strerror(err)); 1476c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1477c72fcc34Sopenharmony_ci handle = NULL; 1478c72fcc34Sopenharmony_ci return err; 1479c72fcc34Sopenharmony_ci } 1480c72fcc34Sopenharmony_ci err = snd_mixer_load(handle); 1481c72fcc34Sopenharmony_ci if (err < 0) { 1482c72fcc34Sopenharmony_ci error("Mixer %s load error: %s", card, snd_strerror(err)); 1483c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1484c72fcc34Sopenharmony_ci handle = NULL; 1485c72fcc34Sopenharmony_ci return err; 1486c72fcc34Sopenharmony_ci } 1487c72fcc34Sopenharmony_ci } 1488c72fcc34Sopenharmony_ci elem = snd_mixer_find_selem(handle, sid); 1489c72fcc34Sopenharmony_ci if (!elem) { 1490c72fcc34Sopenharmony_ci if (ignore_error) 1491c72fcc34Sopenharmony_ci return 0; 1492c72fcc34Sopenharmony_ci error("Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1493c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1494c72fcc34Sopenharmony_ci handle = NULL; 1495c72fcc34Sopenharmony_ci return -ENOENT; 1496c72fcc34Sopenharmony_ci } 1497c72fcc34Sopenharmony_ci if (!roflag) { 1498c72fcc34Sopenharmony_ci /* enum control */ 1499c72fcc34Sopenharmony_ci if (snd_mixer_selem_is_enumerated(elem)) 1500c72fcc34Sopenharmony_ci err = sset_enum(elem, argc, argv); 1501c72fcc34Sopenharmony_ci else 1502c72fcc34Sopenharmony_ci err = sset_channels(elem, argc, argv); 1503c72fcc34Sopenharmony_ci 1504c72fcc34Sopenharmony_ci if (!err) 1505c72fcc34Sopenharmony_ci goto done; 1506c72fcc34Sopenharmony_ci if (err < 0) { 1507c72fcc34Sopenharmony_ci error("Invalid command!"); 1508c72fcc34Sopenharmony_ci goto done; 1509c72fcc34Sopenharmony_ci } 1510c72fcc34Sopenharmony_ci } 1511c72fcc34Sopenharmony_ci if (!quiet) { 1512c72fcc34Sopenharmony_ci printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1513c72fcc34Sopenharmony_ci show_selem(handle, sid, " ", 1); 1514c72fcc34Sopenharmony_ci } 1515c72fcc34Sopenharmony_ci done: 1516c72fcc34Sopenharmony_ci if (! keep_handle) { 1517c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1518c72fcc34Sopenharmony_ci handle = NULL; 1519c72fcc34Sopenharmony_ci } 1520c72fcc34Sopenharmony_ci return err < 0 ? 1 : 0; 1521c72fcc34Sopenharmony_ci} 1522c72fcc34Sopenharmony_ci 1523c72fcc34Sopenharmony_cistatic void events_info(snd_hctl_elem_t *helem) 1524c72fcc34Sopenharmony_ci{ 1525c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 1526c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 1527c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(helem, id); 1528c72fcc34Sopenharmony_ci printf("event info: "); 1529c72fcc34Sopenharmony_ci show_control_id(id); 1530c72fcc34Sopenharmony_ci printf("\n"); 1531c72fcc34Sopenharmony_ci} 1532c72fcc34Sopenharmony_ci 1533c72fcc34Sopenharmony_cistatic void events_value(snd_hctl_elem_t *helem) 1534c72fcc34Sopenharmony_ci{ 1535c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 1536c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 1537c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(helem, id); 1538c72fcc34Sopenharmony_ci printf("event value: "); 1539c72fcc34Sopenharmony_ci show_control_id(id); 1540c72fcc34Sopenharmony_ci printf("\n"); 1541c72fcc34Sopenharmony_ci} 1542c72fcc34Sopenharmony_ci 1543c72fcc34Sopenharmony_cistatic void events_remove(snd_hctl_elem_t *helem) 1544c72fcc34Sopenharmony_ci{ 1545c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 1546c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 1547c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(helem, id); 1548c72fcc34Sopenharmony_ci printf("event remove: "); 1549c72fcc34Sopenharmony_ci show_control_id(id); 1550c72fcc34Sopenharmony_ci printf("\n"); 1551c72fcc34Sopenharmony_ci} 1552c72fcc34Sopenharmony_ci 1553c72fcc34Sopenharmony_cistatic int element_callback(snd_hctl_elem_t *elem, unsigned int mask) 1554c72fcc34Sopenharmony_ci{ 1555c72fcc34Sopenharmony_ci if (mask == SND_CTL_EVENT_MASK_REMOVE) { 1556c72fcc34Sopenharmony_ci events_remove(elem); 1557c72fcc34Sopenharmony_ci return 0; 1558c72fcc34Sopenharmony_ci } 1559c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_INFO) 1560c72fcc34Sopenharmony_ci events_info(elem); 1561c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_VALUE) 1562c72fcc34Sopenharmony_ci events_value(elem); 1563c72fcc34Sopenharmony_ci return 0; 1564c72fcc34Sopenharmony_ci} 1565c72fcc34Sopenharmony_ci 1566c72fcc34Sopenharmony_cistatic void events_add(snd_hctl_elem_t *helem) 1567c72fcc34Sopenharmony_ci{ 1568c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 1569c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 1570c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(helem, id); 1571c72fcc34Sopenharmony_ci printf("event add: "); 1572c72fcc34Sopenharmony_ci show_control_id(id); 1573c72fcc34Sopenharmony_ci printf("\n"); 1574c72fcc34Sopenharmony_ci snd_hctl_elem_set_callback(helem, element_callback); 1575c72fcc34Sopenharmony_ci} 1576c72fcc34Sopenharmony_ci 1577c72fcc34Sopenharmony_cistatic int ctl_callback(snd_hctl_t *ctl ATTRIBUTE_UNUSED, unsigned int mask, 1578c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem) 1579c72fcc34Sopenharmony_ci{ 1580c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_ADD) 1581c72fcc34Sopenharmony_ci events_add(elem); 1582c72fcc34Sopenharmony_ci return 0; 1583c72fcc34Sopenharmony_ci} 1584c72fcc34Sopenharmony_ci 1585c72fcc34Sopenharmony_cistatic int events(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) 1586c72fcc34Sopenharmony_ci{ 1587c72fcc34Sopenharmony_ci snd_hctl_t *handle; 1588c72fcc34Sopenharmony_ci snd_hctl_elem_t *helem; 1589c72fcc34Sopenharmony_ci int err; 1590c72fcc34Sopenharmony_ci 1591c72fcc34Sopenharmony_ci if ((err = snd_hctl_open(&handle, card, 0)) < 0) { 1592c72fcc34Sopenharmony_ci error("Control %s open error: %s\n", card, snd_strerror(err)); 1593c72fcc34Sopenharmony_ci return err; 1594c72fcc34Sopenharmony_ci } 1595c72fcc34Sopenharmony_ci snd_hctl_set_callback(handle, ctl_callback); 1596c72fcc34Sopenharmony_ci if ((err = snd_hctl_load(handle)) < 0) { 1597c72fcc34Sopenharmony_ci error("Control %s hbuild error: %s\n", card, snd_strerror(err)); 1598c72fcc34Sopenharmony_ci return err; 1599c72fcc34Sopenharmony_ci } 1600c72fcc34Sopenharmony_ci for (helem = snd_hctl_first_elem(handle); helem; helem = snd_hctl_elem_next(helem)) { 1601c72fcc34Sopenharmony_ci snd_hctl_elem_set_callback(helem, element_callback); 1602c72fcc34Sopenharmony_ci } 1603c72fcc34Sopenharmony_ci printf("Ready to listen...\n"); 1604c72fcc34Sopenharmony_ci while (1) { 1605c72fcc34Sopenharmony_ci int res = snd_hctl_wait(handle, -1); 1606c72fcc34Sopenharmony_ci if (res >= 0) { 1607c72fcc34Sopenharmony_ci printf("Poll ok: %i\n", res); 1608c72fcc34Sopenharmony_ci res = snd_hctl_handle_events(handle); 1609c72fcc34Sopenharmony_ci if (res < 0) 1610c72fcc34Sopenharmony_ci printf("ERR: %s (%d)\n", snd_strerror(res), res); 1611c72fcc34Sopenharmony_ci } 1612c72fcc34Sopenharmony_ci } 1613c72fcc34Sopenharmony_ci snd_hctl_close(handle); 1614c72fcc34Sopenharmony_ci return 0; 1615c72fcc34Sopenharmony_ci} 1616c72fcc34Sopenharmony_ci 1617c72fcc34Sopenharmony_cistatic void sevents_value(snd_mixer_selem_id_t *sid) 1618c72fcc34Sopenharmony_ci{ 1619c72fcc34Sopenharmony_ci printf("event value: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1620c72fcc34Sopenharmony_ci} 1621c72fcc34Sopenharmony_ci 1622c72fcc34Sopenharmony_cistatic void sevents_info(snd_mixer_selem_id_t *sid) 1623c72fcc34Sopenharmony_ci{ 1624c72fcc34Sopenharmony_ci printf("event info: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1625c72fcc34Sopenharmony_ci} 1626c72fcc34Sopenharmony_ci 1627c72fcc34Sopenharmony_cistatic void sevents_remove(snd_mixer_selem_id_t *sid) 1628c72fcc34Sopenharmony_ci{ 1629c72fcc34Sopenharmony_ci printf("event remove: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1630c72fcc34Sopenharmony_ci} 1631c72fcc34Sopenharmony_ci 1632c72fcc34Sopenharmony_cistatic int melem_event(snd_mixer_elem_t *elem, unsigned int mask) 1633c72fcc34Sopenharmony_ci{ 1634c72fcc34Sopenharmony_ci snd_mixer_selem_id_t *sid; 1635c72fcc34Sopenharmony_ci snd_mixer_selem_id_alloca(&sid); 1636c72fcc34Sopenharmony_ci snd_mixer_selem_get_id(elem, sid); 1637c72fcc34Sopenharmony_ci if (mask == SND_CTL_EVENT_MASK_REMOVE) { 1638c72fcc34Sopenharmony_ci sevents_remove(sid); 1639c72fcc34Sopenharmony_ci return 0; 1640c72fcc34Sopenharmony_ci } 1641c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_INFO) 1642c72fcc34Sopenharmony_ci sevents_info(sid); 1643c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_VALUE) 1644c72fcc34Sopenharmony_ci sevents_value(sid); 1645c72fcc34Sopenharmony_ci return 0; 1646c72fcc34Sopenharmony_ci} 1647c72fcc34Sopenharmony_ci 1648c72fcc34Sopenharmony_cistatic void sevents_add(snd_mixer_elem_t *elem) 1649c72fcc34Sopenharmony_ci{ 1650c72fcc34Sopenharmony_ci snd_mixer_selem_id_t *sid; 1651c72fcc34Sopenharmony_ci snd_mixer_selem_id_alloca(&sid); 1652c72fcc34Sopenharmony_ci snd_mixer_selem_get_id(elem, sid); 1653c72fcc34Sopenharmony_ci printf("event add: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); 1654c72fcc34Sopenharmony_ci snd_mixer_elem_set_callback(elem, melem_event); 1655c72fcc34Sopenharmony_ci} 1656c72fcc34Sopenharmony_ci 1657c72fcc34Sopenharmony_cistatic int mixer_event(snd_mixer_t *mixer ATTRIBUTE_UNUSED, unsigned int mask, 1658c72fcc34Sopenharmony_ci snd_mixer_elem_t *elem) 1659c72fcc34Sopenharmony_ci{ 1660c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_ADD) 1661c72fcc34Sopenharmony_ci sevents_add(elem); 1662c72fcc34Sopenharmony_ci return 0; 1663c72fcc34Sopenharmony_ci} 1664c72fcc34Sopenharmony_ci 1665c72fcc34Sopenharmony_cistatic int sevents(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) 1666c72fcc34Sopenharmony_ci{ 1667c72fcc34Sopenharmony_ci snd_mixer_t *handle; 1668c72fcc34Sopenharmony_ci int err; 1669c72fcc34Sopenharmony_ci 1670c72fcc34Sopenharmony_ci if ((err = snd_mixer_open(&handle, 0)) < 0) { 1671c72fcc34Sopenharmony_ci error("Mixer %s open error: %s", card, snd_strerror(err)); 1672c72fcc34Sopenharmony_ci return err; 1673c72fcc34Sopenharmony_ci } 1674c72fcc34Sopenharmony_ci if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { 1675c72fcc34Sopenharmony_ci error("Mixer attach %s error: %s", card, snd_strerror(err)); 1676c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1677c72fcc34Sopenharmony_ci return err; 1678c72fcc34Sopenharmony_ci } 1679c72fcc34Sopenharmony_ci if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { 1680c72fcc34Sopenharmony_ci error("Mixer register error: %s", snd_strerror(err)); 1681c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1682c72fcc34Sopenharmony_ci return err; 1683c72fcc34Sopenharmony_ci } 1684c72fcc34Sopenharmony_ci snd_mixer_set_callback(handle, mixer_event); 1685c72fcc34Sopenharmony_ci err = snd_mixer_load(handle); 1686c72fcc34Sopenharmony_ci if (err < 0) { 1687c72fcc34Sopenharmony_ci error("Mixer %s load error: %s", card, snd_strerror(err)); 1688c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1689c72fcc34Sopenharmony_ci return err; 1690c72fcc34Sopenharmony_ci } 1691c72fcc34Sopenharmony_ci 1692c72fcc34Sopenharmony_ci printf("Ready to listen...\n"); 1693c72fcc34Sopenharmony_ci while (1) { 1694c72fcc34Sopenharmony_ci int res; 1695c72fcc34Sopenharmony_ci res = snd_mixer_wait(handle, -1); 1696c72fcc34Sopenharmony_ci if (res >= 0) { 1697c72fcc34Sopenharmony_ci printf("Poll ok: %i\n", res); 1698c72fcc34Sopenharmony_ci res = snd_mixer_handle_events(handle); 1699c72fcc34Sopenharmony_ci assert(res >= 0); 1700c72fcc34Sopenharmony_ci } 1701c72fcc34Sopenharmony_ci } 1702c72fcc34Sopenharmony_ci snd_mixer_close(handle); 1703c72fcc34Sopenharmony_ci return 0; 1704c72fcc34Sopenharmony_ci} 1705c72fcc34Sopenharmony_ci 1706c72fcc34Sopenharmony_ci/* 1707c72fcc34Sopenharmony_ci * split a line into tokens 1708c72fcc34Sopenharmony_ci * the content in the line buffer is modified 1709c72fcc34Sopenharmony_ci */ 1710c72fcc34Sopenharmony_cistatic int split_line(char *buf, char **token, int max_token) 1711c72fcc34Sopenharmony_ci{ 1712c72fcc34Sopenharmony_ci char *dst; 1713c72fcc34Sopenharmony_ci int n, esc, quote; 1714c72fcc34Sopenharmony_ci 1715c72fcc34Sopenharmony_ci for (n = 0; n < max_token; n++) { 1716c72fcc34Sopenharmony_ci while (isspace(*buf)) 1717c72fcc34Sopenharmony_ci buf++; 1718c72fcc34Sopenharmony_ci if (! *buf || *buf == '\n') 1719c72fcc34Sopenharmony_ci return n; 1720c72fcc34Sopenharmony_ci /* skip comments */ 1721c72fcc34Sopenharmony_ci if (*buf == '#' || *buf == '!') 1722c72fcc34Sopenharmony_ci return n; 1723c72fcc34Sopenharmony_ci esc = 0; 1724c72fcc34Sopenharmony_ci quote = 0; 1725c72fcc34Sopenharmony_ci token[n] = buf; 1726c72fcc34Sopenharmony_ci for (dst = buf; *buf && *buf != '\n'; buf++) { 1727c72fcc34Sopenharmony_ci if (esc) 1728c72fcc34Sopenharmony_ci esc = 0; 1729c72fcc34Sopenharmony_ci else if (isspace(*buf) && !quote) { 1730c72fcc34Sopenharmony_ci buf++; 1731c72fcc34Sopenharmony_ci break; 1732c72fcc34Sopenharmony_ci } else if (*buf == '\\') { 1733c72fcc34Sopenharmony_ci esc = 1; 1734c72fcc34Sopenharmony_ci continue; 1735c72fcc34Sopenharmony_ci } else if (*buf == '\'' || *buf == '"') { 1736c72fcc34Sopenharmony_ci if (! quote) { 1737c72fcc34Sopenharmony_ci quote = *buf; 1738c72fcc34Sopenharmony_ci continue; 1739c72fcc34Sopenharmony_ci } else if (*buf == quote) { 1740c72fcc34Sopenharmony_ci quote = 0; 1741c72fcc34Sopenharmony_ci continue; 1742c72fcc34Sopenharmony_ci } 1743c72fcc34Sopenharmony_ci } 1744c72fcc34Sopenharmony_ci *dst++ = *buf; 1745c72fcc34Sopenharmony_ci } 1746c72fcc34Sopenharmony_ci *dst = 0; 1747c72fcc34Sopenharmony_ci } 1748c72fcc34Sopenharmony_ci return n; 1749c72fcc34Sopenharmony_ci} 1750c72fcc34Sopenharmony_ci 1751c72fcc34Sopenharmony_ci#define MAX_ARGS 32 1752c72fcc34Sopenharmony_ci 1753c72fcc34Sopenharmony_cistatic int exec_stdin(void) 1754c72fcc34Sopenharmony_ci{ 1755c72fcc34Sopenharmony_ci int narg; 1756c72fcc34Sopenharmony_ci char buf[256], *args[MAX_ARGS]; 1757c72fcc34Sopenharmony_ci int err = 0; 1758c72fcc34Sopenharmony_ci 1759c72fcc34Sopenharmony_ci /* quiet = 1; */ 1760c72fcc34Sopenharmony_ci ignore_error = 1; 1761c72fcc34Sopenharmony_ci 1762c72fcc34Sopenharmony_ci while (fgets(buf, sizeof(buf), stdin)) { 1763c72fcc34Sopenharmony_ci narg = split_line(buf, args, MAX_ARGS); 1764c72fcc34Sopenharmony_ci if (narg > 0) { 1765c72fcc34Sopenharmony_ci if (!strcmp(args[0], "sset") || !strcmp(args[0], "set")) 1766c72fcc34Sopenharmony_ci err = sset(narg - 1, args + 1, 0, 1); 1767c72fcc34Sopenharmony_ci else if (!strcmp(args[0], "cset")) 1768c72fcc34Sopenharmony_ci err = cset(narg - 1, args + 1, 0, 1); 1769c72fcc34Sopenharmony_ci if (err < 0) 1770c72fcc34Sopenharmony_ci return 1; 1771c72fcc34Sopenharmony_ci } 1772c72fcc34Sopenharmony_ci } 1773c72fcc34Sopenharmony_ci return 0; 1774c72fcc34Sopenharmony_ci} 1775c72fcc34Sopenharmony_ci 1776c72fcc34Sopenharmony_ci 1777c72fcc34Sopenharmony_ciint main(int argc, char *argv[]) 1778c72fcc34Sopenharmony_ci{ 1779c72fcc34Sopenharmony_ci int badopt, retval, level = 0; 1780c72fcc34Sopenharmony_ci int read_stdin = 0; 1781c72fcc34Sopenharmony_ci static const struct option long_option[] = 1782c72fcc34Sopenharmony_ci { 1783c72fcc34Sopenharmony_ci {"help", 0, NULL, 'h'}, 1784c72fcc34Sopenharmony_ci {"card", 1, NULL, 'c'}, 1785c72fcc34Sopenharmony_ci {"device", 1, NULL, 'D'}, 1786c72fcc34Sopenharmony_ci {"quiet", 0, NULL, 'q'}, 1787c72fcc34Sopenharmony_ci {"inactive", 0, NULL, 'i'}, 1788c72fcc34Sopenharmony_ci {"debug", 0, NULL, 'd'}, 1789c72fcc34Sopenharmony_ci {"nocheck", 0, NULL, 'n'}, 1790c72fcc34Sopenharmony_ci {"version", 0, NULL, 'v'}, 1791c72fcc34Sopenharmony_ci {"abstract", 1, NULL, 'a'}, 1792c72fcc34Sopenharmony_ci {"stdin", 0, NULL, 's'}, 1793c72fcc34Sopenharmony_ci {"raw-volume", 0, NULL, 'R'}, 1794c72fcc34Sopenharmony_ci {"mapped-volume", 0, NULL, 'M'}, 1795c72fcc34Sopenharmony_ci {NULL, 0, NULL, 0}, 1796c72fcc34Sopenharmony_ci }; 1797c72fcc34Sopenharmony_ci 1798c72fcc34Sopenharmony_ci badopt = 0; 1799c72fcc34Sopenharmony_ci while (1) { 1800c72fcc34Sopenharmony_ci int c; 1801c72fcc34Sopenharmony_ci 1802c72fcc34Sopenharmony_ci if ((c = getopt_long(argc, argv, "hc:D:qidnva:sRM", long_option, NULL)) < 0) 1803c72fcc34Sopenharmony_ci break; 1804c72fcc34Sopenharmony_ci switch (c) { 1805c72fcc34Sopenharmony_ci case 'h': 1806c72fcc34Sopenharmony_ci help(); 1807c72fcc34Sopenharmony_ci return 0; 1808c72fcc34Sopenharmony_ci case 'c': 1809c72fcc34Sopenharmony_ci { 1810c72fcc34Sopenharmony_ci int i; 1811c72fcc34Sopenharmony_ci i = snd_card_get_index(optarg); 1812c72fcc34Sopenharmony_ci if (i >= 0 && i < 32) 1813c72fcc34Sopenharmony_ci#if defined(SND_LIB_VER) && SND_LIB_VER(1, 2, 5) <= SND_LIB_VERSION 1814c72fcc34Sopenharmony_ci sprintf(card, "sysdefault:%i", i); 1815c72fcc34Sopenharmony_ci#else 1816c72fcc34Sopenharmony_ci sprintf(card, "hw:%i", i); 1817c72fcc34Sopenharmony_ci#endif 1818c72fcc34Sopenharmony_ci else { 1819c72fcc34Sopenharmony_ci fprintf(stderr, "Invalid card number '%s'.\n", optarg); 1820c72fcc34Sopenharmony_ci badopt++; 1821c72fcc34Sopenharmony_ci } 1822c72fcc34Sopenharmony_ci } 1823c72fcc34Sopenharmony_ci break; 1824c72fcc34Sopenharmony_ci case 'D': 1825c72fcc34Sopenharmony_ci strncpy(card, optarg, sizeof(card)-1); 1826c72fcc34Sopenharmony_ci card[sizeof(card)-1] = '\0'; 1827c72fcc34Sopenharmony_ci break; 1828c72fcc34Sopenharmony_ci case 'q': 1829c72fcc34Sopenharmony_ci quiet = 1; 1830c72fcc34Sopenharmony_ci break; 1831c72fcc34Sopenharmony_ci case 'i': 1832c72fcc34Sopenharmony_ci level |= LEVEL_INACTIVE; 1833c72fcc34Sopenharmony_ci break; 1834c72fcc34Sopenharmony_ci case 'd': 1835c72fcc34Sopenharmony_ci debugflag = 1; 1836c72fcc34Sopenharmony_ci break; 1837c72fcc34Sopenharmony_ci case 'n': 1838c72fcc34Sopenharmony_ci no_check = 1; 1839c72fcc34Sopenharmony_ci break; 1840c72fcc34Sopenharmony_ci case 'v': 1841c72fcc34Sopenharmony_ci printf("amixer version " SND_UTIL_VERSION_STR "\n"); 1842c72fcc34Sopenharmony_ci return 0; 1843c72fcc34Sopenharmony_ci case 'a': 1844c72fcc34Sopenharmony_ci smixer_level = 1; 1845c72fcc34Sopenharmony_ci memset(&smixer_options, 0, sizeof(smixer_options)); 1846c72fcc34Sopenharmony_ci smixer_options.ver = 1; 1847c72fcc34Sopenharmony_ci if (!strcmp(optarg, "none")) 1848c72fcc34Sopenharmony_ci smixer_options.abstract = SND_MIXER_SABSTRACT_NONE; 1849c72fcc34Sopenharmony_ci else if (!strcmp(optarg, "basic")) 1850c72fcc34Sopenharmony_ci smixer_options.abstract = SND_MIXER_SABSTRACT_BASIC; 1851c72fcc34Sopenharmony_ci else { 1852c72fcc34Sopenharmony_ci fprintf(stderr, "Select correct abstraction level (none or basic)...\n"); 1853c72fcc34Sopenharmony_ci badopt++; 1854c72fcc34Sopenharmony_ci } 1855c72fcc34Sopenharmony_ci break; 1856c72fcc34Sopenharmony_ci case 's': 1857c72fcc34Sopenharmony_ci read_stdin = 1; 1858c72fcc34Sopenharmony_ci break; 1859c72fcc34Sopenharmony_ci case 'R': 1860c72fcc34Sopenharmony_ci std_vol_type = VOL_RAW; 1861c72fcc34Sopenharmony_ci break; 1862c72fcc34Sopenharmony_ci case 'M': 1863c72fcc34Sopenharmony_ci std_vol_type = VOL_MAP; 1864c72fcc34Sopenharmony_ci break; 1865c72fcc34Sopenharmony_ci default: 1866c72fcc34Sopenharmony_ci fprintf(stderr, "Invalid switch or option -%c needs an argument.\n", c); 1867c72fcc34Sopenharmony_ci badopt++; 1868c72fcc34Sopenharmony_ci } 1869c72fcc34Sopenharmony_ci } 1870c72fcc34Sopenharmony_ci if (badopt) 1871c72fcc34Sopenharmony_ci return 1; 1872c72fcc34Sopenharmony_ci 1873c72fcc34Sopenharmony_ci smixer_options.device = card; 1874c72fcc34Sopenharmony_ci 1875c72fcc34Sopenharmony_ci if (read_stdin) { 1876c72fcc34Sopenharmony_ci retval = exec_stdin(); 1877c72fcc34Sopenharmony_ci goto finish; 1878c72fcc34Sopenharmony_ci } 1879c72fcc34Sopenharmony_ci 1880c72fcc34Sopenharmony_ci if (argc - optind <= 0) { 1881c72fcc34Sopenharmony_ci retval = selems(LEVEL_BASIC | level) ? 1 : 0; 1882c72fcc34Sopenharmony_ci goto finish; 1883c72fcc34Sopenharmony_ci } 1884c72fcc34Sopenharmony_ci if (!strcmp(argv[optind], "help")) { 1885c72fcc34Sopenharmony_ci retval = help() ? 1 : 0; 1886c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "info")) { 1887c72fcc34Sopenharmony_ci retval = info() ? 1 : 0; 1888c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "controls")) { 1889c72fcc34Sopenharmony_ci retval = controls(level) ? 1 : 0; 1890c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "contents")) { 1891c72fcc34Sopenharmony_ci retval = controls(LEVEL_BASIC | level) ? 1 : 0; 1892c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "scontrols") || !strcmp(argv[optind], "simple")) { 1893c72fcc34Sopenharmony_ci retval = selems(level) ? 1 : 0; 1894c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "scontents")) { 1895c72fcc34Sopenharmony_ci retval = selems(LEVEL_BASIC | level) ? 1 : 0; 1896c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "sset") || !strcmp(argv[optind], "set")) { 1897c72fcc34Sopenharmony_ci retval = sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0; 1898c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "sget") || !strcmp(argv[optind], "get")) { 1899c72fcc34Sopenharmony_ci retval = sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0; 1900c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "cset")) { 1901c72fcc34Sopenharmony_ci retval = cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0; 1902c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "cget")) { 1903c72fcc34Sopenharmony_ci retval = cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0; 1904c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "events")) { 1905c72fcc34Sopenharmony_ci retval = events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL); 1906c72fcc34Sopenharmony_ci } else if (!strcmp(argv[optind], "sevents")) { 1907c72fcc34Sopenharmony_ci retval = sevents(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL); 1908c72fcc34Sopenharmony_ci } else { 1909c72fcc34Sopenharmony_ci fprintf(stderr, "amixer: Unknown command '%s'...\n", argv[optind]); 1910c72fcc34Sopenharmony_ci retval = 0; 1911c72fcc34Sopenharmony_ci } 1912c72fcc34Sopenharmony_ci 1913c72fcc34Sopenharmony_cifinish: 1914c72fcc34Sopenharmony_ci snd_config_update_free_global(); 1915c72fcc34Sopenharmony_ci 1916c72fcc34Sopenharmony_ci return retval; 1917c72fcc34Sopenharmony_ci} 1918