Blame amixer/amixer.c

Packit Service a9274b
/*
Packit Service a9274b
 *   ALSA command line mixer utility
Packit Service a9274b
 *   Copyright (c) 1999-2000 by Jaroslav Kysela <perex@perex.cz>
Packit Service a9274b
 *
Packit Service a9274b
 *   This program is free software; you can redistribute it and/or modify
Packit Service a9274b
 *   it under the terms of the GNU General Public License as published by
Packit Service a9274b
 *   the Free Software Foundation; either version 2 of the License, or
Packit Service a9274b
 *   (at your option) any later version.
Packit Service a9274b
 *
Packit Service a9274b
 *   This program is distributed in the hope that it will be useful,
Packit Service a9274b
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 *   GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 *   You should have received a copy of the GNU General Public License
Packit Service a9274b
 *   along with this program; if not, write to the Free Software
Packit Service a9274b
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service a9274b
 *
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <getopt.h>
Packit Service a9274b
#include <stdarg.h>
Packit Service a9274b
#include <ctype.h>
Packit Service a9274b
#include <math.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <assert.h>
Packit Service a9274b
#include <alsa/asoundlib.h>
Packit Service a9274b
#include <poll.h>
Packit Service a9274b
#include <stdint.h>
Packit Service a9274b
#include "amixer.h"
Packit Service a9274b
#include "../alsamixer/volume_mapping.h"
Packit Service a9274b
Packit Service a9274b
#define LEVEL_BASIC		(1<<0)
Packit Service a9274b
#define LEVEL_INACTIVE		(1<<1)
Packit Service a9274b
#define LEVEL_ID		(1<<2)
Packit Service a9274b
Packit Service a9274b
static int quiet = 0;
Packit Service a9274b
static int debugflag = 0;
Packit Service a9274b
static int no_check = 0;
Packit Service a9274b
static int smixer_level = 0;
Packit Service a9274b
static int ignore_error = 0;
Packit Service a9274b
static struct snd_mixer_selem_regopt smixer_options;
Packit Service a9274b
static char card[64] = "default";
Packit Service a9274b
Packit Service a9274b
static void error(const char *fmt,...)
Packit Service a9274b
{
Packit Service a9274b
	va_list va;
Packit Service a9274b
Packit Service a9274b
	va_start(va, fmt);
Packit Service a9274b
	fprintf(stderr, "amixer: ");
Packit Service a9274b
	vfprintf(stderr, fmt, va);
Packit Service a9274b
	fprintf(stderr, "\n");
Packit Service a9274b
	va_end(va);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int help(void)
Packit Service a9274b
{
Packit Service a9274b
	printf("Usage: amixer <options> [command]\n");
Packit Service a9274b
	printf("\nAvailable options:\n");
Packit Service a9274b
	printf("  -h,--help       this help\n");
Packit Service a9274b
	printf("  -c,--card N     select the card\n");
Packit Service a9274b
	printf("  -D,--device N   select the device, default '%s'\n", card);
Packit Service a9274b
	printf("  -d,--debug      debug mode\n");
Packit Service a9274b
	printf("  -n,--nocheck    do not perform range checking\n");
Packit Service a9274b
	printf("  -v,--version    print version of this program\n");
Packit Service a9274b
	printf("  -q,--quiet      be quiet\n");
Packit Service a9274b
	printf("  -i,--inactive   show also inactive controls\n");
Packit Service a9274b
	printf("  -a,--abstract L select abstraction level (none or basic)\n");
Packit Service a9274b
	printf("  -s,--stdin      Read and execute commands from stdin sequentially\n");
Packit Service a9274b
	printf("  -R,--raw-volume Use the raw value (default)\n");
Packit Service a9274b
	printf("  -M,--mapped-volume Use the mapped volume\n");
Packit Service a9274b
	printf("\nAvailable commands:\n");
Packit Service a9274b
	printf("  scontrols       show all mixer simple controls\n");
Packit Service a9274b
	printf("  scontents	  show contents of all mixer simple controls (default command)\n");
Packit Service a9274b
	printf("  sset sID P      set contents for one mixer simple control\n");
Packit Service a9274b
	printf("  sget sID        get contents for one mixer simple control\n");
Packit Service a9274b
	printf("  controls        show all controls for given card\n");
Packit Service a9274b
	printf("  contents        show contents of all controls for given card\n");
Packit Service a9274b
	printf("  cset cID P      set control contents for one control\n");
Packit Service a9274b
	printf("  cget cID        get control contents for one control\n");
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int info(void)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	snd_ctl_t *handle;
Packit Service a9274b
	snd_mixer_t *mhandle;
Packit Service a9274b
	snd_ctl_card_info_t *info;
Packit Service a9274b
	snd_ctl_elem_list_t *clist;
Packit Service a9274b
	snd_ctl_card_info_alloca(&info;;
Packit Service a9274b
	snd_ctl_elem_list_alloca(&clist);
Packit Service a9274b
	
Packit Service a9274b
	if ((err = snd_ctl_open(&handle, card, 0)) < 0) {
Packit Service a9274b
		error("Control device %s open error: %s", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	
Packit Service a9274b
	if ((err = snd_ctl_card_info(handle, info)) < 0) {
Packit Service a9274b
		error("Control device %s hw info error: %s", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	printf("Card %s '%s'/'%s'\n", card, snd_ctl_card_info_get_id(info),
Packit Service a9274b
	       snd_ctl_card_info_get_longname(info));
Packit Service a9274b
	printf("  Mixer name	: '%s'\n", snd_ctl_card_info_get_mixername(info));
Packit Service a9274b
	printf("  Components	: '%s'\n", snd_ctl_card_info_get_components(info));
Packit Service a9274b
	if ((err = snd_ctl_elem_list(handle, clist)) < 0) {
Packit Service a9274b
		error("snd_ctl_elem_list failure: %s", snd_strerror(err));
Packit Service a9274b
	} else {
Packit Service a9274b
		printf("  Controls      : %i\n", snd_ctl_elem_list_get_count(clist));
Packit Service a9274b
	}
Packit Service a9274b
	snd_ctl_close(handle);
Packit Service a9274b
	if ((err = snd_mixer_open(&mhandle, 0)) < 0) {
Packit Service a9274b
		error("Mixer open error: %s", snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if (smixer_level == 0 && (err = snd_mixer_attach(mhandle, card)) < 0) {
Packit Service a9274b
		error("Mixer attach %s error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(mhandle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if ((err = snd_mixer_selem_register(mhandle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
Packit Service a9274b
		error("Mixer register error: %s", snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(mhandle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	err = snd_mixer_load(mhandle);
Packit Service a9274b
	if (err < 0) {
Packit Service a9274b
		error("Mixer load %s error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(mhandle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	printf("  Simple ctrls  : %i\n", snd_mixer_get_count(mhandle));
Packit Service a9274b
	snd_mixer_close(mhandle);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static const char *control_type(snd_ctl_elem_info_t *info)
Packit Service a9274b
{
Packit Service a9274b
	return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static const char *control_access(snd_ctl_elem_info_t *info)
Packit Service a9274b
{
Packit Service a9274b
	static char result[10];
Packit Service a9274b
	char *res = result;
Packit Service a9274b
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_readable(info) ? 'r' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_writable(info) ? 'w' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_inactive(info) ? 'i' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_volatile(info) ? 'v' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_locked(info) ? 'l' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_tlv_readable(info) ? 'R' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_tlv_writable(info) ? 'W' : '-';
Packit Service a9274b
	*res++ = snd_ctl_elem_info_is_tlv_commandable(info) ? 'C' : '-';
Packit Service a9274b
	*res++ = '\0';
Packit Service a9274b
	return result;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
#define check_range(val, min, max) \
Packit Service a9274b
	(no_check ? (val) : ((val < min) ? (min) : (val > max) ? (max) : (val))) 
Packit Service a9274b
#if 0
Packit Service a9274b
static int convert_range(int val, int omin, int omax, int nmin, int nmax)
Packit Service a9274b
{
Packit Service a9274b
	int orange = omax - omin, nrange = nmax - nmin;
Packit Service a9274b
	
Packit Service a9274b
	if (orange == 0)
Packit Service a9274b
		return 0;
Packit Service a9274b
	return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / ((double)orange + (double)nmin));
Packit Service a9274b
}
Packit Service a9274b
#endif
Packit Service a9274b
Packit Service a9274b
#if 0
Packit Service a9274b
static int convert_db_range(int val, int omin, int omax, int nmin, int nmax)
Packit Service a9274b
{
Packit Service a9274b
	int orange = omax - omin, nrange = nmax - nmin;
Packit Service a9274b
	
Packit Service a9274b
	if (orange == 0)
Packit Service a9274b
		return 0;
Packit Service a9274b
	return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / (double)orange + (double)nmin);
Packit Service a9274b
}
Packit Service a9274b
#endif
Packit Service a9274b
Packit Service a9274b
/* Fuction to convert from volume to percentage. val = volume */
Packit Service a9274b
Packit Service a9274b
static int convert_prange(long val, long min, long max)
Packit Service a9274b
{
Packit Service a9274b
	long range = max - min;
Packit Service a9274b
	int tmp;
Packit Service a9274b
Packit Service a9274b
	if (range == 0)
Packit Service a9274b
		return min;
Packit Service a9274b
	val -= min;
Packit Service a9274b
	tmp = rint((double)val/(double)range * 100);
Packit Service a9274b
	return tmp;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* Function to convert from percentage to volume. perc = percentage */
Packit Service a9274b
static long convert_prange1(long perc, long min, long max)
Packit Service a9274b
{
Packit Service a9274b
	long tmp;
Packit Service a9274b
Packit Service a9274b
	tmp = rint((double)perc * (double)(max - min) * 0.01);
Packit Service a9274b
	if (tmp == 0 && perc > 0)
Packit Service a9274b
		tmp++;
Packit Service a9274b
	return tmp + min;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
struct volume_ops {
Packit Service a9274b
	int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max);
Packit Service a9274b
	int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
Packit Service a9274b
		   long *value);
Packit Service a9274b
	int (*set)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
Packit Service a9274b
		   long value, int dir);
Packit Service a9274b
};
Packit Service a9274b
	
Packit Service a9274b
enum { VOL_RAW, VOL_DB, VOL_MAP };
Packit Service a9274b
Packit Service a9274b
struct volume_ops_set {
Packit Service a9274b
	int (*has_volume)(snd_mixer_elem_t *elem);
Packit Service a9274b
	struct volume_ops v[3];
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int set_playback_dB(snd_mixer_elem_t *elem,
Packit Service a9274b
			   snd_mixer_selem_channel_id_t c, long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return snd_mixer_selem_set_playback_dB(elem, c, value, dir);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int set_capture_dB(snd_mixer_elem_t *elem,
Packit Service a9274b
			  snd_mixer_selem_channel_id_t c, long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return snd_mixer_selem_set_capture_dB(elem, c, value, dir);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int set_playback_raw_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				   snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				   long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return snd_mixer_selem_set_playback_volume(elem, c, value);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int set_capture_raw_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				  snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				  long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return snd_mixer_selem_set_capture_volume(elem, c, value);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/* FIXME: normalize to int32 space to be compatible with other types */
Packit Service a9274b
#define MAP_VOL_RES	(INT32_MAX / 100)
Packit Service a9274b
Packit Service a9274b
static int get_mapped_volume_range(snd_mixer_elem_t *elem,
Packit Service a9274b
				   long *pmin, long *pmax)
Packit Service a9274b
{
Packit Service a9274b
	*pmin = 0;
Packit Service a9274b
	*pmax = MAP_VOL_RES;
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int get_playback_mapped_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				      snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				      long *value)
Packit Service a9274b
{
Packit Service a9274b
	*value = (rint)(get_normalized_playback_volume(elem, c) * MAP_VOL_RES);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int set_playback_mapped_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				      snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				      long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return set_normalized_playback_volume(elem, c,
Packit Service a9274b
					      (double)value / MAP_VOL_RES, dir);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int get_capture_mapped_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				     snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				     long *value)
Packit Service a9274b
{
Packit Service a9274b
	*value = (rint)(get_normalized_capture_volume(elem, c) * MAP_VOL_RES);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int set_capture_mapped_volume(snd_mixer_elem_t *elem,
Packit Service a9274b
				     snd_mixer_selem_channel_id_t c,
Packit Service a9274b
				     long value, int dir)
Packit Service a9274b
{
Packit Service a9274b
	return set_normalized_capture_volume(elem, c,
Packit Service a9274b
					     (double)value / MAP_VOL_RES, dir);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static const struct volume_ops_set vol_ops[2] = {
Packit Service a9274b
	{
Packit Service a9274b
		.has_volume = snd_mixer_selem_has_playback_volume,
Packit Service a9274b
		.v = {{ snd_mixer_selem_get_playback_volume_range,
Packit Service a9274b
			snd_mixer_selem_get_playback_volume,
Packit Service a9274b
			set_playback_raw_volume },
Packit Service a9274b
		      { snd_mixer_selem_get_playback_dB_range,
Packit Service a9274b
			snd_mixer_selem_get_playback_dB,
Packit Service a9274b
			set_playback_dB },
Packit Service a9274b
		      { get_mapped_volume_range,
Packit Service a9274b
			get_playback_mapped_volume,
Packit Service a9274b
			set_playback_mapped_volume },
Packit Service a9274b
		},
Packit Service a9274b
	},
Packit Service a9274b
	{
Packit Service a9274b
		.has_volume = snd_mixer_selem_has_capture_volume,
Packit Service a9274b
		.v = {{ snd_mixer_selem_get_capture_volume_range,
Packit Service a9274b
			snd_mixer_selem_get_capture_volume,
Packit Service a9274b
			set_capture_raw_volume },
Packit Service a9274b
		      { snd_mixer_selem_get_capture_dB_range,
Packit Service a9274b
			snd_mixer_selem_get_capture_dB,
Packit Service a9274b
			set_capture_dB },
Packit Service a9274b
		      { get_mapped_volume_range,
Packit Service a9274b
			get_capture_mapped_volume,
Packit Service a9274b
			set_capture_mapped_volume },
Packit Service a9274b
		},
Packit Service a9274b
	},
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int std_vol_type = VOL_RAW;
Packit Service a9274b
Packit Service a9274b
static int set_volume_simple(snd_mixer_elem_t *elem,
Packit Service a9274b
			     snd_mixer_selem_channel_id_t chn,
Packit Service a9274b
			     char **ptr, int dir)
Packit Service a9274b
{
Packit Service a9274b
	long val, orig, pmin, pmax;
Packit Service a9274b
	char *p = *ptr, *s;
Packit Service a9274b
	int invalid = 0, percent = 0, err = 0;
Packit Service a9274b
	int vol_type;
Packit Service a9274b
	double scale = 1.0;
Packit Service a9274b
	int correct = 0;
Packit Service a9274b
Packit Service a9274b
	if (! vol_ops[dir].has_volume(elem))
Packit Service a9274b
		invalid = 1;
Packit Service a9274b
Packit Service a9274b
	if (*p == ':')
Packit Service a9274b
		p++;
Packit Service a9274b
	if (*p == '\0' || (!isdigit(*p) && *p != '-'))
Packit Service a9274b
		goto skip;
Packit Service a9274b
Packit Service a9274b
	s = p;
Packit Service a9274b
	val = strtol(s, &p, 10);
Packit Service a9274b
	if (*p == '.') {
Packit Service a9274b
		p++;
Packit Service a9274b
		strtol(p, &p, 10);
Packit Service a9274b
	}
Packit Service a9274b
	if (*p == '%') {
Packit Service a9274b
		vol_type = std_vol_type;
Packit Service a9274b
		percent = 1;
Packit Service a9274b
		p++;
Packit Service a9274b
	} else if (toupper(p[0]) == 'D' && toupper(p[1]) == 'B') {
Packit Service a9274b
		vol_type = VOL_DB;
Packit Service a9274b
		p += 2;
Packit Service a9274b
		scale = 100;
Packit Service a9274b
	} else {
Packit Service a9274b
		vol_type = VOL_RAW;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (*p && !strchr(",:+-", *p))
Packit Service a9274b
		invalid = 1;
Packit Service a9274b
Packit Service a9274b
	val = (long)(strtod(s, NULL) * scale);
Packit Service a9274b
	if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
Packit Service a9274b
		invalid = 1;
Packit Service a9274b
	if (percent)
Packit Service a9274b
		val = (long)convert_prange1(val, pmin, pmax);
Packit Service a9274b
	if (*p == '+' || *p == '-') {
Packit Service a9274b
		if (! invalid) {
Packit Service a9274b
			if (vol_ops[dir].v[vol_type].get(elem, chn, &orig) < 0)
Packit Service a9274b
				invalid = 1;
Packit Service a9274b
			if (*p == '+') {
Packit Service a9274b
				val = orig + val;
Packit Service a9274b
				correct = 1;
Packit Service a9274b
			} else {
Packit Service a9274b
				val = orig - val;
Packit Service a9274b
				correct = -1;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		p++;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (*p && !strchr(",:", *p))
Packit Service a9274b
		invalid = 1;
Packit Service a9274b
Packit Service a9274b
	if (! invalid) {
Packit Service a9274b
		val = check_range(val, pmin, pmax);
Packit Service a9274b
		err = vol_ops[dir].v[vol_type].set(elem, chn, val, correct);
Packit Service a9274b
	}
Packit Service a9274b
 skip:
Packit Service a9274b
	if (*p == ',')
Packit Service a9274b
		p++;
Packit Service a9274b
	*ptr = p;
Packit Service a9274b
	return err ? err : (invalid ? -ENOENT : 0);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int get_bool_simple(char **ptr, char *str, int invert, int orig)
Packit Service a9274b
{
Packit Service a9274b
	if (**ptr == ':')
Packit Service a9274b
		(*ptr)++;
Packit Service a9274b
	if (!strncasecmp(*ptr, str, strlen(str))) {
Packit Service a9274b
		orig = 1 ^ (invert ? 1 : 0);
Packit Service a9274b
		while (**ptr != '\0' && **ptr != ',' && **ptr != ':')
Packit Service a9274b
			(*ptr)++;
Packit Service a9274b
	}
Packit Service a9274b
	if (**ptr == ',' || **ptr == ':')
Packit Service a9274b
		(*ptr)++;
Packit Service a9274b
	return orig;
Packit Service a9274b
}
Packit Service a9274b
		
Packit Service a9274b
static int simple_skip_word(char **ptr, char *str)
Packit Service a9274b
{
Packit Service a9274b
	char *xptr = *ptr;
Packit Service a9274b
	if (*xptr == ':')
Packit Service a9274b
		xptr++;
Packit Service a9274b
	if (!strncasecmp(xptr, str, strlen(str))) {
Packit Service a9274b
		while (*xptr != '\0' && *xptr != ',' && *xptr != ':')
Packit Service a9274b
			xptr++;
Packit Service a9274b
		if (*xptr == ',' || *xptr == ':')
Packit Service a9274b
			xptr++;
Packit Service a9274b
		*ptr = xptr;
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
		
Packit Service a9274b
static void show_control_id(snd_ctl_elem_id_t *id)
Packit Service a9274b
{
Packit Service a9274b
	char *str;
Packit Service a9274b
Packit Service a9274b
	str = snd_ctl_ascii_elem_id_get(id);
Packit Service a9274b
	if (str)
Packit Service a9274b
		printf("%s", str);
Packit Service a9274b
	free(str);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void print_spaces(unsigned int spaces)
Packit Service a9274b
{
Packit Service a9274b
	while (spaces-- > 0)
Packit Service a9274b
		putc(' ', stdout);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void print_dB(long dB)
Packit Service a9274b
{
Packit Service a9274b
	if (dB < 0) {
Packit Service a9274b
		printf("-%li.%02lidB", -dB / 100, -dB % 100);
Packit Service a9274b
	} else {
Packit Service a9274b
		printf("%li.%02lidB", dB / 100, dB % 100);
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int type = tlv[0];
Packit Service a9274b
	unsigned int size;
Packit Service a9274b
	unsigned int idx = 0;
Packit Service a9274b
	const char *chmap_type = NULL;
Packit Service a9274b
	int lf = 1;
Packit Service a9274b
Packit Service a9274b
	if (tlv_size < 2 * sizeof(unsigned int)) {
Packit Service a9274b
		printf("TLV size error!\n");
Packit Service a9274b
		return;
Packit Service a9274b
	}
Packit Service a9274b
	print_spaces(spaces);
Packit Service a9274b
	printf("| ");
Packit Service a9274b
	type = tlv[idx++];
Packit Service a9274b
	size = tlv[idx++];
Packit Service a9274b
	tlv_size -= 2 * sizeof(unsigned int);
Packit Service a9274b
	if (size > tlv_size) {
Packit Service a9274b
		printf("TLV size error (%u, %u, %u)!\n", type, size, tlv_size);
Packit Service a9274b
		return;
Packit Service a9274b
	}
Packit Service a9274b
	switch (type) {
Packit Service a9274b
	case SND_CTL_TLVT_CONTAINER:
Packit Service a9274b
		printf("container\n");
Packit Service a9274b
		size += sizeof(unsigned int) -1;
Packit Service a9274b
		size /= sizeof(unsigned int);
Packit Service a9274b
		while (idx < size) {
Packit Service a9274b
			if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) {
Packit Service a9274b
				printf("TLV size error in compound!\n");
Packit Service a9274b
				return;
Packit Service a9274b
			}
Packit Service a9274b
			decode_tlv(spaces + 2, tlv + idx, tlv[idx+1] + 8);
Packit Service a9274b
			idx += 2 + (tlv[idx+1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
Packit Service a9274b
		}
Packit Service a9274b
		lf = 0;
Packit Service a9274b
		break;
Packit Service a9274b
	case SND_CTL_TLVT_DB_SCALE:
Packit Service a9274b
		printf("dBscale-");
Packit Service a9274b
		if (size != 2 * sizeof(unsigned int)) {
Packit Service a9274b
			while (size > 0) {
Packit Service a9274b
				printf("0x%08x,", tlv[idx++]);
Packit Service a9274b
				size -= sizeof(unsigned int);
Packit Service a9274b
			}
Packit Service a9274b
		} else {
Packit Service a9274b
			printf("min=");
Packit Service a9274b
			print_dB((int)tlv[2]);
Packit Service a9274b
			printf(",step=");
Packit Service a9274b
			print_dB(tlv[3] & 0xffff);
Packit Service a9274b
			printf(",mute=%i", (tlv[3] >> 16) & 1);
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
#ifdef SND_CTL_TLVT_DB_LINEAR
Packit Service a9274b
	case SND_CTL_TLVT_DB_LINEAR:
Packit Service a9274b
		printf("dBlinear-");
Packit Service a9274b
		if (size != 2 * sizeof(unsigned int)) {
Packit Service a9274b
			while (size > 0) {
Packit Service a9274b
				printf("0x%08x,", tlv[idx++]);
Packit Service a9274b
				size -= sizeof(unsigned int);
Packit Service a9274b
			}
Packit Service a9274b
		} else {
Packit Service a9274b
			printf("min=");
Packit Service a9274b
			print_dB((int)tlv[2]);
Packit Service a9274b
			printf(",max=");
Packit Service a9274b
			print_dB((int)tlv[3]);
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
#endif
Packit Service a9274b
#ifdef SND_CTL_TLVT_DB_RANGE
Packit Service a9274b
	case SND_CTL_TLVT_DB_RANGE:
Packit Service a9274b
		printf("dBrange-\n");
Packit Service a9274b
		if ((size % (6 * sizeof(unsigned int))) != 0) {
Packit Service a9274b
			while (size > 0) {
Packit Service a9274b
				printf("0x%08x,", tlv[idx++]);
Packit Service a9274b
				size -= sizeof(unsigned int);
Packit Service a9274b
			}
Packit Service a9274b
			break;
Packit Service a9274b
		}
Packit Service a9274b
		while (size > 0) {
Packit Service a9274b
			print_spaces(spaces + 2);
Packit Service a9274b
			printf("rangemin=%i,", tlv[idx++]);
Packit Service a9274b
			printf(",rangemax=%i\n", tlv[idx++]);
Packit Service a9274b
			decode_tlv(spaces + 4, tlv + idx, 4 * sizeof(unsigned int));
Packit Service a9274b
			idx += 4;
Packit Service a9274b
			size -= 6 * sizeof(unsigned int);
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
#endif
Packit Service a9274b
#ifdef SND_CTL_TLVT_DB_MINMAX
Packit Service a9274b
	case SND_CTL_TLVT_DB_MINMAX:
Packit Service a9274b
	case SND_CTL_TLVT_DB_MINMAX_MUTE:
Packit Service a9274b
		if (type == SND_CTL_TLVT_DB_MINMAX_MUTE)
Packit Service a9274b
			printf("dBminmaxmute-");
Packit Service a9274b
		else
Packit Service a9274b
			printf("dBminmax-");
Packit Service a9274b
		if (size != 2 * sizeof(unsigned int)) {
Packit Service a9274b
			while (size > 0) {
Packit Service a9274b
				printf("0x%08x,", tlv[idx++]);
Packit Service a9274b
				size -= sizeof(unsigned int);
Packit Service a9274b
			}
Packit Service a9274b
		} else {
Packit Service a9274b
			printf("min=");
Packit Service a9274b
			print_dB((int)tlv[2]);
Packit Service a9274b
			printf(",max=");
Packit Service a9274b
			print_dB((int)tlv[3]);
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
#endif
Packit Service a9274b
#ifdef SND_CTL_TLVT_CHMAP_FIXED
Packit Service a9274b
	case SND_CTL_TLVT_CHMAP_FIXED:
Packit Service a9274b
		chmap_type = "fixed";
Packit Service a9274b
		/* Fall through */
Packit Service a9274b
	case SND_CTL_TLVT_CHMAP_VAR:
Packit Service a9274b
		if (!chmap_type)
Packit Service a9274b
			chmap_type = "variable";
Packit Service a9274b
		/* Fall through */
Packit Service a9274b
	case SND_CTL_TLVT_CHMAP_PAIRED:
Packit Service a9274b
		if (!chmap_type)
Packit Service a9274b
			chmap_type = "paired";
Packit Service a9274b
		printf("chmap-%s=", chmap_type);
Packit Service a9274b
Packit Service a9274b
		while (size > 0) {
Packit Service a9274b
			printf("%s", snd_pcm_chmap_name(tlv[idx++]));
Packit Service a9274b
			size -= sizeof(unsigned int);
Packit Service a9274b
			if (size > 0)
Packit Service a9274b
				printf(",");
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
#endif
Packit Service a9274b
	default:
Packit Service a9274b
		printf("unk-%u-", type);
Packit Service a9274b
		while (size > 0) {
Packit Service a9274b
			printf("0x%08x,", tlv[idx++]);
Packit Service a9274b
			size -= sizeof(unsigned int);
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
	}
Packit Service a9274b
	if (lf)
Packit Service a9274b
		putc('\n', stdout);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int show_control(const char *space, snd_hctl_elem_t *elem,
Packit Service a9274b
			int level)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	unsigned int item, idx, count, *tlv;
Packit Service a9274b
	snd_ctl_elem_type_t type;
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_info_t *info;
Packit Service a9274b
	snd_ctl_elem_value_t *control;
Packit Service a9274b
	snd_aes_iec958_t iec958;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_ctl_elem_info_alloca(&info;;
Packit Service a9274b
	snd_ctl_elem_value_alloca(&control);
Packit Service a9274b
	if ((err = snd_hctl_elem_info(elem, info)) < 0) {
Packit Service a9274b
		error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if (level & LEVEL_ID) {
Packit Service a9274b
		snd_hctl_elem_get_id(elem, id);
Packit Service a9274b
		show_control_id(id);
Packit Service a9274b
		printf("\n");
Packit Service a9274b
	}
Packit Service a9274b
	count = snd_ctl_elem_info_get_count(info);
Packit Service a9274b
	type = snd_ctl_elem_info_get_type(info);
Packit Service a9274b
	printf("%s; type=%s,access=%s,values=%u", space, control_type(info), control_access(info), count);
Packit Service a9274b
	switch (type) {
Packit Service a9274b
	case SND_CTL_ELEM_TYPE_INTEGER:
Packit Service a9274b
		printf(",min=%li,max=%li,step=%li\n", 
Packit Service a9274b
		       snd_ctl_elem_info_get_min(info),
Packit Service a9274b
		       snd_ctl_elem_info_get_max(info),
Packit Service a9274b
		       snd_ctl_elem_info_get_step(info));
Packit Service a9274b
		break;
Packit Service a9274b
	case SND_CTL_ELEM_TYPE_INTEGER64:
Packit Service a9274b
		printf(",min=%lli,max=%lli,step=%lli\n",
Packit Service a9274b
		       snd_ctl_elem_info_get_min64(info),
Packit Service a9274b
		       snd_ctl_elem_info_get_max64(info),
Packit Service a9274b
		       snd_ctl_elem_info_get_step64(info));
Packit Service a9274b
		break;
Packit Service a9274b
	case SND_CTL_ELEM_TYPE_ENUMERATED:
Packit Service a9274b
	{
Packit Service a9274b
		unsigned int items = snd_ctl_elem_info_get_items(info);
Packit Service a9274b
		printf(",items=%u\n", items);
Packit Service a9274b
		for (item = 0; item < items; item++) {
Packit Service a9274b
			snd_ctl_elem_info_set_item(info, item);
Packit Service a9274b
			if ((err = snd_hctl_elem_info(elem, info)) < 0) {
Packit Service a9274b
				error("Control %s element info error: %s\n", card, snd_strerror(err));
Packit Service a9274b
				return err;
Packit Service a9274b
			}
Packit Service a9274b
			printf("%s; Item #%u '%s'\n", space, item, snd_ctl_elem_info_get_item_name(info));
Packit Service a9274b
		}
Packit Service a9274b
		break;
Packit Service a9274b
	}
Packit Service a9274b
	default:
Packit Service a9274b
		printf("\n");
Packit Service a9274b
		break;
Packit Service a9274b
	}
Packit Service a9274b
	if (level & LEVEL_BASIC) {
Packit Service a9274b
		if (!snd_ctl_elem_info_is_readable(info))
Packit Service a9274b
			goto __skip_read;
Packit Service a9274b
		if ((err = snd_hctl_elem_read(elem, control)) < 0) {
Packit Service a9274b
			error("Control %s element read error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		printf("%s: values=", space);
Packit Service a9274b
		for (idx = 0; idx < count; idx++) {
Packit Service a9274b
			if (idx > 0)
Packit Service a9274b
				printf(",");
Packit Service a9274b
			switch (type) {
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_BOOLEAN:
Packit Service a9274b
				printf("%s", snd_ctl_elem_value_get_boolean(control, idx) ? "on" : "off");
Packit Service a9274b
				break;
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_INTEGER:
Packit Service a9274b
				printf("%li", snd_ctl_elem_value_get_integer(control, idx));
Packit Service a9274b
				break;
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_INTEGER64:
Packit Service a9274b
				printf("%lli", snd_ctl_elem_value_get_integer64(control, idx));
Packit Service a9274b
				break;
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_ENUMERATED:
Packit Service a9274b
				printf("%u", snd_ctl_elem_value_get_enumerated(control, idx));
Packit Service a9274b
				break;
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_BYTES:
Packit Service a9274b
				printf("0x%02x", snd_ctl_elem_value_get_byte(control, idx));
Packit Service a9274b
				break;
Packit Service a9274b
			case SND_CTL_ELEM_TYPE_IEC958:
Packit Service a9274b
				snd_ctl_elem_value_get_iec958(control, &iec958);
Packit Service a9274b
				printf("[AES0=0x%02x AES1=0x%02x AES2=0x%02x AES3=0x%02x]",
Packit Service a9274b
				       iec958.status[0], iec958.status[1],
Packit Service a9274b
				       iec958.status[2], iec958.status[3]);
Packit Service a9274b
				break;
Packit Service a9274b
			default:
Packit Service a9274b
				printf("?");
Packit Service a9274b
				break;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		printf("\n");
Packit Service a9274b
	      __skip_read:
Packit Service a9274b
		if (!snd_ctl_elem_info_is_tlv_readable(info))
Packit Service a9274b
			goto __skip_tlv;
Packit Service a9274b
		/* skip ASoC ext bytes controls that may have huge binary TLV data */
Packit Service a9274b
		if (type == SND_CTL_ELEM_TYPE_BYTES &&
Packit Service a9274b
				!snd_ctl_elem_info_is_readable(info) &&
Packit Service a9274b
				!snd_ctl_elem_info_is_writable(info)) {
Packit Service a9274b
			printf("%s; ASoC TLV Byte control, skipping bytes dump\n", space);
Packit Service a9274b
			goto __skip_tlv;
Packit Service a9274b
		}
Packit Service a9274b
Packit Service a9274b
		tlv = malloc(4096);
Packit Service a9274b
		if ((err = snd_hctl_elem_tlv_read(elem, tlv, 4096)) < 0) {
Packit Service a9274b
			error("Control %s element TLV read error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			free(tlv);
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		decode_tlv(strlen(space), tlv, 4096);
Packit Service a9274b
		free(tlv);
Packit Service a9274b
	}
Packit Service a9274b
      __skip_tlv:
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int controls(int level)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	snd_hctl_t *handle;
Packit Service a9274b
	snd_hctl_elem_t *elem;
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_info_t *info;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_ctl_elem_info_alloca(&info;;
Packit Service a9274b
	
Packit Service a9274b
	if ((err = snd_hctl_open(&handle, card, 0)) < 0) {
Packit Service a9274b
		error("Control %s open error: %s", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if ((err = snd_hctl_load(handle)) < 0) {
Packit Service a9274b
		error("Control %s local error: %s\n", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	for (elem = snd_hctl_first_elem(handle); elem; elem = snd_hctl_elem_next(elem)) {
Packit Service a9274b
		if ((err = snd_hctl_elem_info(elem, info)) < 0) {
Packit Service a9274b
			error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		if (!(level & LEVEL_INACTIVE) && snd_ctl_elem_info_is_inactive(info))
Packit Service a9274b
			continue;
Packit Service a9274b
		snd_hctl_elem_get_id(elem, id);
Packit Service a9274b
		show_control_id(id);
Packit Service a9274b
		printf("\n");
Packit Service a9274b
		if (level & LEVEL_BASIC)
Packit Service a9274b
			show_control("  ", elem, 1);
Packit Service a9274b
	}
Packit Service a9274b
	snd_hctl_close(handle);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void show_selem_volume(snd_mixer_elem_t *elem, 
Packit Service a9274b
			      snd_mixer_selem_channel_id_t chn, int dir,
Packit Service a9274b
			      long min, long max)
Packit Service a9274b
{
Packit Service a9274b
	long raw, val;
Packit Service a9274b
	vol_ops[dir].v[VOL_RAW].get(elem, chn, &raw;;
Packit Service a9274b
	if (std_vol_type == VOL_RAW)
Packit Service a9274b
		val = convert_prange(raw, min, max);
Packit Service a9274b
	else {
Packit Service a9274b
		vol_ops[dir].v[std_vol_type].get(elem, chn, &val;;
Packit Service a9274b
		val = convert_prange(val, 0, MAP_VOL_RES);
Packit Service a9274b
	}
Packit Service a9274b
	printf(" %li [%li%%]", raw, val);
Packit Service a9274b
	if (!vol_ops[dir].v[VOL_DB].get(elem, chn, &val)) {
Packit Service a9274b
		printf(" [");
Packit Service a9274b
		print_dB(val);
Packit Service a9274b
		printf("]");
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_selem_channel_id_t chn;
Packit Service a9274b
	long pmin = 0, pmax = 0;
Packit Service a9274b
	long cmin = 0, cmax = 0;
Packit Service a9274b
	int psw, csw;
Packit Service a9274b
	int pmono, cmono, mono_ok = 0;
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	
Packit Service a9274b
	elem = snd_mixer_find_selem(handle, id);
Packit Service a9274b
	if (!elem) {
Packit Service a9274b
		error("Mixer %s simple element not found", card);
Packit Service a9274b
		return -ENOENT;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (level & LEVEL_BASIC) {
Packit Service a9274b
		printf("%sCapabilities:", space);
Packit Service a9274b
		if (snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
			printf(" volume");
Packit Service a9274b
			if (snd_mixer_selem_has_playback_volume_joined(elem))
Packit Service a9274b
				printf(" volume-joined");
Packit Service a9274b
		} else {
Packit Service a9274b
			if (snd_mixer_selem_has_playback_volume(elem)) {
Packit Service a9274b
				printf(" pvolume");
Packit Service a9274b
				if (snd_mixer_selem_has_playback_volume_joined(elem))
Packit Service a9274b
					printf(" pvolume-joined");
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
				printf(" cvolume");
Packit Service a9274b
				if (snd_mixer_selem_has_capture_volume_joined(elem))
Packit Service a9274b
					printf(" cvolume-joined");
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
			printf(" switch");
Packit Service a9274b
			if (snd_mixer_selem_has_playback_switch_joined(elem))
Packit Service a9274b
				printf(" switch-joined");
Packit Service a9274b
		} else {
Packit Service a9274b
			if (snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
				printf(" pswitch");
Packit Service a9274b
				if (snd_mixer_selem_has_playback_switch_joined(elem))
Packit Service a9274b
					printf(" pswitch-joined");
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
				printf(" cswitch");
Packit Service a9274b
				if (snd_mixer_selem_has_capture_switch_joined(elem))
Packit Service a9274b
					printf(" cswitch-joined");
Packit Service a9274b
				if (snd_mixer_selem_has_capture_switch_exclusive(elem))
Packit Service a9274b
					printf(" cswitch-exclusive");
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_mixer_selem_is_enum_playback(elem)) {
Packit Service a9274b
			printf(" penum");
Packit Service a9274b
		} else if (snd_mixer_selem_is_enum_capture(elem)) {
Packit Service a9274b
			printf(" cenum");
Packit Service a9274b
		} else if (snd_mixer_selem_is_enumerated(elem)) {
Packit Service a9274b
			printf(" enum");
Packit Service a9274b
		}
Packit Service a9274b
		printf("\n");
Packit Service a9274b
		if (snd_mixer_selem_is_enumerated(elem)) {
Packit Service a9274b
			int i, items;
Packit Service a9274b
			unsigned int idx;
Packit Service a9274b
			/*
Packit Service a9274b
			 * See snd_ctl_elem_init_enum_names() in
Packit Service a9274b
			 * sound/core/control.c.
Packit Service a9274b
			 */
Packit Service a9274b
			char itemname[64];
Packit Service a9274b
			items = snd_mixer_selem_get_enum_items(elem);
Packit Service a9274b
			printf("  Items:");
Packit Service a9274b
			for (i = 0; i < items; i++) {
Packit Service a9274b
				snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname);
Packit Service a9274b
				printf(" '%s'", itemname);
Packit Service a9274b
			}
Packit Service a9274b
			printf("\n");
Packit Service a9274b
			for (i = 0; !snd_mixer_selem_get_enum_item(elem, i, &idx); i++) {
Packit Service a9274b
				snd_mixer_selem_get_enum_item_name(elem, idx, sizeof(itemname) - 1, itemname);
Packit Service a9274b
				printf("  Item%d: '%s'\n", i, itemname);
Packit Service a9274b
			}
Packit Service a9274b
			return 0; /* no more thing to do */
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_mixer_selem_has_capture_switch_exclusive(elem))
Packit Service a9274b
			printf("%sCapture exclusive group: %i\n", space,
Packit Service a9274b
			       snd_mixer_selem_get_capture_group(elem));
Packit Service a9274b
		if (snd_mixer_selem_has_playback_volume(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
			printf("%sPlayback channels:", space);
Packit Service a9274b
			if (snd_mixer_selem_is_playback_mono(elem)) {
Packit Service a9274b
				printf(" Mono");
Packit Service a9274b
			} else {
Packit Service a9274b
				int first = 1;
Packit Service a9274b
				for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
Packit Service a9274b
					if (!snd_mixer_selem_has_playback_channel(elem, chn))
Packit Service a9274b
						continue;
Packit Service a9274b
					if (!first)
Packit Service a9274b
						printf(" -");
Packit Service a9274b
					printf(" %s", snd_mixer_selem_channel_name(chn));
Packit Service a9274b
					first = 0;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			printf("\n");
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_mixer_selem_has_capture_volume(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
			printf("%sCapture channels:", space);
Packit Service a9274b
			if (snd_mixer_selem_is_capture_mono(elem)) {
Packit Service a9274b
				printf(" Mono");
Packit Service a9274b
			} else {
Packit Service a9274b
				int first = 1;
Packit Service a9274b
				for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
Packit Service a9274b
					if (!snd_mixer_selem_has_capture_channel(elem, chn))
Packit Service a9274b
						continue;
Packit Service a9274b
					if (!first)
Packit Service a9274b
						printf(" -");
Packit Service a9274b
					printf(" %s", snd_mixer_selem_channel_name(chn));
Packit Service a9274b
					first = 0;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			printf("\n");
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_mixer_selem_has_playback_volume(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
			printf("%sLimits:", space);
Packit Service a9274b
			if (snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
				snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
Packit Service a9274b
				snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
Packit Service a9274b
				printf(" %li - %li", pmin, pmax);
Packit Service a9274b
			} else {
Packit Service a9274b
				if (snd_mixer_selem_has_playback_volume(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
Packit Service a9274b
					printf(" Playback %li - %li", pmin, pmax);
Packit Service a9274b
				}
Packit Service a9274b
				if (snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
Packit Service a9274b
					printf(" Capture %li - %li", cmin, cmax);
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			printf("\n");
Packit Service a9274b
		}
Packit Service a9274b
		pmono = snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO) &&
Packit Service a9274b
		        (snd_mixer_selem_is_playback_mono(elem) || 
Packit Service a9274b
			 (!snd_mixer_selem_has_playback_volume(elem) &&
Packit Service a9274b
			  !snd_mixer_selem_has_playback_switch(elem)));
Packit Service a9274b
		cmono = snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO) &&
Packit Service a9274b
		        (snd_mixer_selem_is_capture_mono(elem) || 
Packit Service a9274b
			 (!snd_mixer_selem_has_capture_volume(elem) &&
Packit Service a9274b
			  !snd_mixer_selem_has_capture_switch(elem)));
Packit Service a9274b
#if 0
Packit Service a9274b
		printf("pmono = %i, cmono = %i (%i, %i, %i, %i)\n", pmono, cmono,
Packit Service a9274b
				snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO),
Packit Service a9274b
				snd_mixer_selem_is_capture_mono(elem),
Packit Service a9274b
				snd_mixer_selem_has_capture_volume(elem),
Packit Service a9274b
				snd_mixer_selem_has_capture_switch(elem));
Packit Service a9274b
#endif
Packit Service a9274b
		if (pmono || cmono) {
Packit Service a9274b
			if (!mono_ok) {
Packit Service a9274b
				printf("%s%s:", space, "Mono");
Packit Service a9274b
				mono_ok = 1;
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
				show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
				snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw;;
Packit Service a9274b
				printf(" [%s]", psw ? "on" : "off");
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		if (pmono && snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO)) {
Packit Service a9274b
			int title = 0;
Packit Service a9274b
			if (!mono_ok) {
Packit Service a9274b
				printf("%s%s:", space, "Mono");
Packit Service a9274b
				mono_ok = 1;
Packit Service a9274b
			}
Packit Service a9274b
			if (!snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
				if (snd_mixer_selem_has_playback_volume(elem)) {
Packit Service a9274b
					printf(" Playback");
Packit Service a9274b
					title = 1;
Packit Service a9274b
					show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			if (!snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
				if (snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					if (!title)
Packit Service a9274b
						printf(" Playback");
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw;;
Packit Service a9274b
					printf(" [%s]", psw ? "on" : "off");
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		if (cmono && snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO)) {
Packit Service a9274b
			int title = 0;
Packit Service a9274b
			if (!mono_ok) {
Packit Service a9274b
				printf("%s%s:", space, "Mono");
Packit Service a9274b
				mono_ok = 1;
Packit Service a9274b
			}
Packit Service a9274b
			if (!snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
				if (snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
					printf(" Capture");
Packit Service a9274b
					title = 1;
Packit Service a9274b
					show_selem_volume(elem, SND_MIXER_SCHN_MONO, 1, cmin, cmax);
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			if (!snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
				if (snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					if (!title)
Packit Service a9274b
						printf(" Capture");
Packit Service a9274b
					snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_MONO, &csw;;
Packit Service a9274b
					printf(" [%s]", csw ? "on" : "off");
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		if (pmono || cmono)
Packit Service a9274b
			printf("\n");
Packit Service a9274b
		if (!pmono || !cmono) {
Packit Service a9274b
			for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
Packit Service a9274b
				if ((pmono || !snd_mixer_selem_has_playback_channel(elem, chn)) &&
Packit Service a9274b
				    (cmono || !snd_mixer_selem_has_capture_channel(elem, chn)))
Packit Service a9274b
					continue;
Packit Service a9274b
				printf("%s%s:", space, snd_mixer_selem_channel_name(chn));
Packit Service a9274b
				if (!pmono && !cmono && snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
					show_selem_volume(elem, chn, 0, pmin, pmax);
Packit Service a9274b
				}
Packit Service a9274b
				if (!pmono && !cmono && snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, chn, &psw;;
Packit Service a9274b
					printf(" [%s]", psw ? "on" : "off");
Packit Service a9274b
				}
Packit Service a9274b
				if (!pmono && snd_mixer_selem_has_playback_channel(elem, chn)) {
Packit Service a9274b
					int title = 0;
Packit Service a9274b
					if (!snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
						if (snd_mixer_selem_has_playback_volume(elem)) {
Packit Service a9274b
							printf(" Playback");
Packit Service a9274b
							title = 1;
Packit Service a9274b
							show_selem_volume(elem, chn, 0, pmin, pmax);
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
					if (!snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
						if (snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
							if (!title)
Packit Service a9274b
								printf(" Playback");
Packit Service a9274b
							snd_mixer_selem_get_playback_switch(elem, chn, &psw;;
Packit Service a9274b
							printf(" [%s]", psw ? "on" : "off");
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if (!cmono && snd_mixer_selem_has_capture_channel(elem, chn)) {
Packit Service a9274b
					int title = 0;
Packit Service a9274b
					if (!snd_mixer_selem_has_common_volume(elem)) {
Packit Service a9274b
						if (snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
							printf(" Capture");
Packit Service a9274b
							title = 1;
Packit Service a9274b
							show_selem_volume(elem, chn, 1, cmin, cmax);
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
					if (!snd_mixer_selem_has_common_switch(elem)) {
Packit Service a9274b
						if (snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
							if (!title)
Packit Service a9274b
								printf(" Capture");
Packit Service a9274b
							snd_mixer_selem_get_capture_switch(elem, chn, &csw;;
Packit Service a9274b
							printf(" [%s]", csw ? "on" : "off");
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				printf("\n");
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int selems(int level)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	snd_mixer_t *handle;
Packit Service a9274b
	snd_mixer_selem_id_t *sid;
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	snd_mixer_selem_id_alloca(&sid;;
Packit Service a9274b
	
Packit Service a9274b
	if ((err = snd_mixer_open(&handle, 0)) < 0) {
Packit Service a9274b
		error("Mixer %s open error: %s", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
Packit Service a9274b
		error("Mixer attach %s error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
Packit Service a9274b
		error("Mixer register error: %s", snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	err = snd_mixer_load(handle);
Packit Service a9274b
	if (err < 0) {
Packit Service a9274b
		error("Mixer %s load error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
Packit Service a9274b
		snd_mixer_selem_get_id(elem, sid);
Packit Service a9274b
		if (!(level & LEVEL_INACTIVE) && !snd_mixer_selem_is_active(elem))
Packit Service a9274b
			continue;
Packit Service a9274b
		printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
		show_selem(handle, sid, "  ", level);
Packit Service a9274b
	}
Packit Service a9274b
	snd_mixer_close(handle);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
Packit Service a9274b
{
Packit Service a9274b
	int c, size;
Packit Service a9274b
	char buf[128];
Packit Service a9274b
	char *ptr = buf;
Packit Service a9274b
Packit Service a9274b
	while (*str == ' ' || *str == '\t')
Packit Service a9274b
		str++;
Packit Service a9274b
	if (!(*str))
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	size = 1;	/* for '\0' */
Packit Service a9274b
	if (*str != '"' && *str != '\'') {
Packit Service a9274b
		while (*str && *str != ',') {
Packit Service a9274b
			if (size < (int)sizeof(buf)) {
Packit Service a9274b
				*ptr++ = *str;
Packit Service a9274b
				size++;
Packit Service a9274b
			}
Packit Service a9274b
			str++;
Packit Service a9274b
		}
Packit Service a9274b
	} else {
Packit Service a9274b
		c = *str++;
Packit Service a9274b
		while (*str && *str != c) {
Packit Service a9274b
			if (size < (int)sizeof(buf)) {
Packit Service a9274b
				*ptr++ = *str;
Packit Service a9274b
				size++;
Packit Service a9274b
			}
Packit Service a9274b
			str++;
Packit Service a9274b
		}
Packit Service a9274b
		if (*str == c)
Packit Service a9274b
			str++;
Packit Service a9274b
	}
Packit Service a9274b
	if (*str == '\0') {
Packit Service a9274b
		snd_mixer_selem_id_set_index(sid, 0);
Packit Service a9274b
		*ptr = 0;
Packit Service a9274b
		goto _set;
Packit Service a9274b
	}
Packit Service a9274b
	if (*str != ',')
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	*ptr = 0;	/* terminate the string */
Packit Service a9274b
	str++;
Packit Service a9274b
	if (!isdigit(*str))
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	snd_mixer_selem_id_set_index(sid, atoi(str));
Packit Service a9274b
       _set:
Packit Service a9274b
	snd_mixer_selem_id_set_name(sid, buf);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int cset(int argc, char *argv[], int roflag, int keep_handle)
Packit Service a9274b
{
Packit Service a9274b
	int err;
Packit Service a9274b
	static snd_ctl_t *handle = NULL;
Packit Service a9274b
	snd_ctl_elem_info_t *info;
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_value_t *control;
Packit Service a9274b
	snd_ctl_elem_info_alloca(&info;;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_ctl_elem_value_alloca(&control);
Packit Service a9274b
Packit Service a9274b
	if (argc < 1) {
Packit Service a9274b
		fprintf(stderr, "Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n");
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	}
Packit Service a9274b
	if (snd_ctl_ascii_elem_id_parse(id, argv[0])) {
Packit Service a9274b
		fprintf(stderr, "Wrong control identifier: %s\n", argv[0]);
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
	}
Packit Service a9274b
	if (debugflag) {
Packit Service a9274b
		printf("VERIFY ID: ");
Packit Service a9274b
		show_control_id(id);
Packit Service a9274b
		printf("\n");
Packit Service a9274b
	}
Packit Service a9274b
	if (handle == NULL &&
Packit Service a9274b
	    (err = snd_ctl_open(&handle, card, 0)) < 0) {
Packit Service a9274b
		error("Control %s open error: %s\n", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	snd_ctl_elem_info_set_id(info, id);
Packit Service a9274b
	if ((err = snd_ctl_elem_info(handle, info)) < 0) {
Packit Service a9274b
		if (ignore_error)
Packit Service a9274b
			return 0;
Packit Service a9274b
		error("Cannot find the given element from control %s\n", card);
Packit Service a9274b
		if (! keep_handle) {
Packit Service a9274b
			snd_ctl_close(handle);
Packit Service a9274b
			handle = NULL;
Packit Service a9274b
		}
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
Packit Service a9274b
	if (!roflag) {
Packit Service a9274b
		snd_ctl_elem_value_set_id(control, id);
Packit Service a9274b
		if ((err = snd_ctl_elem_read(handle, control)) < 0) {
Packit Service a9274b
			if (ignore_error)
Packit Service a9274b
				return 0;
Packit Service a9274b
			error("Cannot read the given element from control %s\n", card);
Packit Service a9274b
			if (! keep_handle) {
Packit Service a9274b
				snd_ctl_close(handle);
Packit Service a9274b
				handle = NULL;
Packit Service a9274b
			}
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]);
Packit Service a9274b
		if (err < 0) {
Packit Service a9274b
 			if (!ignore_error)
Packit Service a9274b
				error("Control %s parse error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			if (!keep_handle) {
Packit Service a9274b
				snd_ctl_close(handle);
Packit Service a9274b
				handle = NULL;
Packit Service a9274b
			}
Packit Service a9274b
			return ignore_error ? 0 : err;
Packit Service a9274b
		}
Packit Service a9274b
		if ((err = snd_ctl_elem_write(handle, control)) < 0) {
Packit Service a9274b
			if (!ignore_error)
Packit Service a9274b
				error("Control %s element write error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			if (!keep_handle) {
Packit Service a9274b
				snd_ctl_close(handle);
Packit Service a9274b
				handle = NULL;
Packit Service a9274b
			}
Packit Service a9274b
			return ignore_error ? 0 : err;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	if (! keep_handle) {
Packit Service a9274b
		snd_ctl_close(handle);
Packit Service a9274b
		handle = NULL;
Packit Service a9274b
	}
Packit Service a9274b
	if (!quiet) {
Packit Service a9274b
		snd_hctl_t *hctl;
Packit Service a9274b
		snd_hctl_elem_t *elem;
Packit Service a9274b
		if ((err = snd_hctl_open(&hctl, card, 0)) < 0) {
Packit Service a9274b
			error("Control %s open error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		if ((err = snd_hctl_load(hctl)) < 0) {
Packit Service a9274b
			error("Control %s load error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		elem = snd_hctl_find_elem(hctl, id);
Packit Service a9274b
		if (elem)
Packit Service a9274b
			show_control("  ", elem, LEVEL_BASIC | LEVEL_ID);
Packit Service a9274b
		else
Packit Service a9274b
			printf("Could not find the specified element\n");
Packit Service a9274b
		snd_hctl_close(hctl);
Packit Service a9274b
	}
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
typedef struct channel_mask {
Packit Service a9274b
	char *name;
Packit Service a9274b
	unsigned int mask;
Packit Service a9274b
} channel_mask_t;
Packit Service a9274b
static const channel_mask_t chanmask[] = {
Packit Service a9274b
	{"frontleft", 1 << SND_MIXER_SCHN_FRONT_LEFT},
Packit Service a9274b
	{"frontright", 1 << SND_MIXER_SCHN_FRONT_RIGHT},
Packit Service a9274b
	{"frontcenter", 1 << SND_MIXER_SCHN_FRONT_CENTER},
Packit Service a9274b
	{"front", ((1 << SND_MIXER_SCHN_FRONT_LEFT) |
Packit Service a9274b
		   (1 << SND_MIXER_SCHN_FRONT_RIGHT))},
Packit Service a9274b
	{"center", 1 << SND_MIXER_SCHN_FRONT_CENTER},
Packit Service a9274b
	{"rearleft", 1 << SND_MIXER_SCHN_REAR_LEFT},
Packit Service a9274b
	{"rearright", 1 << SND_MIXER_SCHN_REAR_RIGHT},
Packit Service a9274b
	{"rear", ((1 << SND_MIXER_SCHN_REAR_LEFT) |
Packit Service a9274b
		  (1 << SND_MIXER_SCHN_REAR_RIGHT))},
Packit Service a9274b
	{"woofer", 1 << SND_MIXER_SCHN_WOOFER},
Packit Service a9274b
	{NULL, 0}
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static unsigned int channels_mask(char **arg, unsigned int def)
Packit Service a9274b
{
Packit Service a9274b
	const channel_mask_t *c;
Packit Service a9274b
Packit Service a9274b
	for (c = chanmask; c->name; c++) {
Packit Service a9274b
		if (strncasecmp(*arg, c->name, strlen(c->name)) == 0) {
Packit Service a9274b
			while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t')
Packit Service a9274b
				(*arg)++;
Packit Service a9274b
			if (**arg == ',' || **arg == ' ' || **arg == '\t')
Packit Service a9274b
				(*arg)++;
Packit Service a9274b
			return c->mask;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return def;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static unsigned int dir_mask(char **arg, unsigned int def)
Packit Service a9274b
{
Packit Service a9274b
	int findend = 0;
Packit Service a9274b
Packit Service a9274b
	if (strncasecmp(*arg, "playback", 8) == 0)
Packit Service a9274b
		def = findend = 1;
Packit Service a9274b
	else if (strncasecmp(*arg, "capture", 8) == 0)
Packit Service a9274b
		def = findend = 2;
Packit Service a9274b
	if (findend) {
Packit Service a9274b
		while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t')
Packit Service a9274b
			(*arg)++;
Packit Service a9274b
		if (**arg == ',' || **arg == ' ' || **arg == '\t')
Packit Service a9274b
			(*arg)++;
Packit Service a9274b
	}
Packit Service a9274b
	return def;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int get_enum_item_index(snd_mixer_elem_t *elem, char **ptrp)
Packit Service a9274b
{
Packit Service a9274b
	char *ptr = *ptrp;
Packit Service a9274b
	int items, i, len;
Packit Service a9274b
Packit Service a9274b
	/* See snd_ctl_elem_init_enum_names() in sound/core/control.c. */
Packit Service a9274b
	char name[64];
Packit Service a9274b
	
Packit Service a9274b
	items = snd_mixer_selem_get_enum_items(elem);
Packit Service a9274b
	if (items <= 0)
Packit Service a9274b
		return -1;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < items; i++) {
Packit Service a9274b
		if (snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name) < 0)
Packit Service a9274b
			continue;
Packit Service a9274b
Packit Service a9274b
		len = strlen(name);
Packit Service a9274b
		if (! strncmp(name, ptr, len)) {
Packit Service a9274b
			if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
Packit Service a9274b
				ptr += len;
Packit Service a9274b
				*ptrp = ptr;
Packit Service a9274b
				return i;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return -1;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int sset_enum(snd_mixer_elem_t *elem, unsigned int argc, char **argv)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int idx, item = 0;
Packit Service a9274b
	int check_flag = ignore_error ? 0 : -1;
Packit Service a9274b
Packit Service a9274b
	for (idx = 1; idx < argc; idx++) {
Packit Service a9274b
		char *ptr = argv[idx];
Packit Service a9274b
		while (*ptr) {
Packit Service a9274b
			int ival = get_enum_item_index(elem, &ptr);
Packit Service a9274b
			if (ival < 0)
Packit Service a9274b
				return check_flag;
Packit Service a9274b
			if (snd_mixer_selem_set_enum_item(elem, item++, ival) >= 0)
Packit Service a9274b
				check_flag = 1;
Packit Service a9274b
			/* skip separators */
Packit Service a9274b
			while (*ptr == ',' || isspace(*ptr))
Packit Service a9274b
				ptr++;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return check_flag;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int sset_channels(snd_mixer_elem_t *elem, unsigned int argc, char **argv)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int channels = ~0U;
Packit Service a9274b
	unsigned int dir = 3, okflag = 3;
Packit Service a9274b
	unsigned int idx;
Packit Service a9274b
	snd_mixer_selem_channel_id_t chn;
Packit Service a9274b
	int check_flag = ignore_error ? 0 : -1;
Packit Service a9274b
Packit Service a9274b
	for (idx = 1; idx < argc; idx++) {
Packit Service a9274b
		char *ptr = argv[idx], *optr;
Packit Service a9274b
		int multi, firstchn = 1;
Packit Service a9274b
		channels = channels_mask(&ptr, channels);
Packit Service a9274b
		if (*ptr == '\0')
Packit Service a9274b
			continue;
Packit Service a9274b
		dir = dir_mask(&ptr, dir);
Packit Service a9274b
		if (*ptr == '\0')
Packit Service a9274b
			continue;
Packit Service a9274b
		multi = (strchr(ptr, ',') != NULL);
Packit Service a9274b
		optr = ptr;
Packit Service a9274b
		for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
Packit Service a9274b
			char *sptr = NULL;
Packit Service a9274b
			int ival;
Packit Service a9274b
Packit Service a9274b
			if (!(channels & (1 << chn)))
Packit Service a9274b
				continue;
Packit Service a9274b
Packit Service a9274b
			if ((dir & 1) && snd_mixer_selem_has_playback_channel(elem, chn)) {
Packit Service a9274b
				sptr = ptr;
Packit Service a9274b
				if (!strncmp(ptr, "mute", 4) && snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "mute", 1, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "off", 3) && snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "off", 1, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "unmute", 6) && snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "unmute", 0, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "on", 2) && snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "on", 0, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_playback_switch(elem)) {
Packit Service a9274b
					if (firstchn || !snd_mixer_selem_has_playback_switch_joined(elem)) {
Packit Service a9274b
						snd_mixer_selem_get_playback_switch(elem, chn, &ival);
Packit Service a9274b
						if (snd_mixer_selem_set_playback_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
Packit Service a9274b
							check_flag = 1;
Packit Service a9274b
					}
Packit Service a9274b
					simple_skip_word(&ptr, "toggle");
Packit Service a9274b
				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
Packit Service a9274b
					if (set_volume_simple(elem, chn, &ptr, 0) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (simple_skip_word(&ptr, "cap") || simple_skip_word(&ptr, "rec") ||
Packit Service a9274b
					   simple_skip_word(&ptr, "nocap") || simple_skip_word(&ptr, "norec")) {
Packit Service a9274b
					/* nothing */
Packit Service a9274b
				} else {
Packit Service a9274b
					okflag &= ~1;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			if ((dir & 2) && snd_mixer_selem_has_capture_channel(elem, chn)) {
Packit Service a9274b
				if (sptr != NULL)
Packit Service a9274b
					ptr = sptr;
Packit Service a9274b
				sptr = ptr;
Packit Service a9274b
				if (!strncmp(ptr, "cap", 3) && snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "cap", 0, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "rec", 3) && snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "rec", 0, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "nocap", 5) && snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "nocap", 1, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "norec", 5) && snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
Packit Service a9274b
					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "norec", 1, ival)) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_capture_switch(elem)) {
Packit Service a9274b
					if (firstchn || !snd_mixer_selem_has_capture_switch_joined(elem)) {
Packit Service a9274b
						snd_mixer_selem_get_capture_switch(elem, chn, &ival);
Packit Service a9274b
						if (snd_mixer_selem_set_capture_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
Packit Service a9274b
							check_flag = 1;
Packit Service a9274b
					}
Packit Service a9274b
					simple_skip_word(&ptr, "toggle");
Packit Service a9274b
				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
Packit Service a9274b
					if (set_volume_simple(elem, chn, &ptr, 1) >= 0)
Packit Service a9274b
						check_flag = 1;
Packit Service a9274b
				} else if (simple_skip_word(&ptr, "mute") || simple_skip_word(&ptr, "off") ||
Packit Service a9274b
					   simple_skip_word(&ptr, "unmute") || simple_skip_word(&ptr, "on")) {
Packit Service a9274b
					/* nothing */
Packit Service a9274b
				} else {
Packit Service a9274b
					okflag &= ~2;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			if (okflag == 0) {
Packit Service a9274b
				if (debugflag) {
Packit Service a9274b
					if (dir & 1)
Packit Service a9274b
						error("Unknown playback setup '%s'..", ptr);
Packit Service a9274b
					if (dir & 2)
Packit Service a9274b
						error("Unknown capture setup '%s'..", ptr);
Packit Service a9274b
				}
Packit Service a9274b
				return 0; /* just skip it */
Packit Service a9274b
			}
Packit Service a9274b
			if (!multi)
Packit Service a9274b
				ptr = optr;
Packit Service a9274b
			firstchn = 0;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return check_flag;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int sset(unsigned int argc, char *argv[], int roflag, int keep_handle)
Packit Service a9274b
{
Packit Service a9274b
	int err = 0;
Packit Service a9274b
	static snd_mixer_t *handle = NULL;
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	snd_mixer_selem_id_t *sid;
Packit Service a9274b
	snd_mixer_selem_id_alloca(&sid;;
Packit Service a9274b
Packit Service a9274b
	if (argc < 1) {
Packit Service a9274b
		fprintf(stderr, "Specify a scontrol identifier: 'name',index\n");
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	if (parse_simple_id(argv[0], sid)) {
Packit Service a9274b
		fprintf(stderr, "Wrong scontrol identifier: %s\n", argv[0]);
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	if (!roflag && argc < 2) {
Packit Service a9274b
		fprintf(stderr, "Specify what you want to set...\n");
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	if (handle == NULL) {
Packit Service a9274b
		if ((err = snd_mixer_open(&handle, 0)) < 0) {
Packit Service a9274b
			error("Mixer %s open error: %s\n", card, snd_strerror(err));
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
Packit Service a9274b
			error("Mixer attach %s error: %s", card, snd_strerror(err));
Packit Service a9274b
			snd_mixer_close(handle);
Packit Service a9274b
			handle = NULL;
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
Packit Service a9274b
			error("Mixer register error: %s", snd_strerror(err));
Packit Service a9274b
			snd_mixer_close(handle);
Packit Service a9274b
			handle = NULL;
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
		err = snd_mixer_load(handle);
Packit Service a9274b
		if (err < 0) {
Packit Service a9274b
			error("Mixer %s load error: %s", card, snd_strerror(err));
Packit Service a9274b
			snd_mixer_close(handle);
Packit Service a9274b
			handle = NULL;
Packit Service a9274b
			return err;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	elem = snd_mixer_find_selem(handle, sid);
Packit Service a9274b
	if (!elem) {
Packit Service a9274b
		if (ignore_error)
Packit Service a9274b
			return 0;
Packit Service a9274b
		error("Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		handle = NULL;
Packit Service a9274b
		return -ENOENT;
Packit Service a9274b
	}
Packit Service a9274b
	if (!roflag) {
Packit Service a9274b
		/* enum control */
Packit Service a9274b
		if (snd_mixer_selem_is_enumerated(elem))
Packit Service a9274b
			err = sset_enum(elem, argc, argv);
Packit Service a9274b
		else
Packit Service a9274b
			err = sset_channels(elem, argc, argv);
Packit Service a9274b
Packit Service a9274b
		if (!err)
Packit Service a9274b
			goto done;
Packit Service a9274b
		if (err < 0) {
Packit Service a9274b
			error("Invalid command!");
Packit Service a9274b
			goto done;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	if (!quiet) {
Packit Service a9274b
		printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
		show_selem(handle, sid, "  ", 1);
Packit Service a9274b
	}
Packit Service a9274b
 done:
Packit Service a9274b
	if (! keep_handle) {
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		handle = NULL;
Packit Service a9274b
	}
Packit Service a9274b
	return err < 0 ? 1 : 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void events_info(snd_hctl_elem_t *helem)
Packit Service a9274b
{
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_hctl_elem_get_id(helem, id);
Packit Service a9274b
	printf("event info: ");
Packit Service a9274b
	show_control_id(id);
Packit Service a9274b
	printf("\n");
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void events_value(snd_hctl_elem_t *helem)
Packit Service a9274b
{
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_hctl_elem_get_id(helem, id);
Packit Service a9274b
	printf("event value: ");
Packit Service a9274b
	show_control_id(id);
Packit Service a9274b
	printf("\n");
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void events_remove(snd_hctl_elem_t *helem)
Packit Service a9274b
{
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_hctl_elem_get_id(helem, id);
Packit Service a9274b
	printf("event remove: ");
Packit Service a9274b
	show_control_id(id);
Packit Service a9274b
	printf("\n");
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int element_callback(snd_hctl_elem_t *elem, unsigned int mask)
Packit Service a9274b
{
Packit Service a9274b
	if (mask == SND_CTL_EVENT_MASK_REMOVE) {
Packit Service a9274b
		events_remove(elem);
Packit Service a9274b
		return 0;
Packit Service a9274b
	}
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_INFO) 
Packit Service a9274b
		events_info(elem);
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_VALUE) 
Packit Service a9274b
		events_value(elem);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void events_add(snd_hctl_elem_t *helem)
Packit Service a9274b
{
Packit Service a9274b
	snd_ctl_elem_id_t *id;
Packit Service a9274b
	snd_ctl_elem_id_alloca(&id;;
Packit Service a9274b
	snd_hctl_elem_get_id(helem, id);
Packit Service a9274b
	printf("event add: ");
Packit Service a9274b
	show_control_id(id);
Packit Service a9274b
	printf("\n");
Packit Service a9274b
	snd_hctl_elem_set_callback(helem, element_callback);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int ctl_callback(snd_hctl_t *ctl, unsigned int mask,
Packit Service a9274b
		 snd_hctl_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_ADD)
Packit Service a9274b
		events_add(elem);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int events(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED)
Packit Service a9274b
{
Packit Service a9274b
	snd_hctl_t *handle;
Packit Service a9274b
	snd_hctl_elem_t *helem;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	if ((err = snd_hctl_open(&handle, card, 0)) < 0) {
Packit Service a9274b
		error("Control %s open error: %s\n", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	snd_hctl_set_callback(handle, ctl_callback);
Packit Service a9274b
	if ((err = snd_hctl_load(handle)) < 0) {
Packit Service a9274b
		error("Control %s hbuild error: %s\n", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	for (helem = snd_hctl_first_elem(handle); helem; helem = snd_hctl_elem_next(helem)) {
Packit Service a9274b
		snd_hctl_elem_set_callback(helem, element_callback);
Packit Service a9274b
	}
Packit Service a9274b
	printf("Ready to listen...\n");
Packit Service a9274b
	while (1) {
Packit Service a9274b
		int res = snd_hctl_wait(handle, -1);
Packit Service a9274b
		if (res >= 0) {
Packit Service a9274b
			printf("Poll ok: %i\n", res);
Packit Service a9274b
			res = snd_hctl_handle_events(handle);
Packit Service a9274b
			assert(res > 0);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	snd_hctl_close(handle);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void sevents_value(snd_mixer_selem_id_t *sid)
Packit Service a9274b
{
Packit Service a9274b
	printf("event value: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void sevents_info(snd_mixer_selem_id_t *sid)
Packit Service a9274b
{
Packit Service a9274b
	printf("event info: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void sevents_remove(snd_mixer_selem_id_t *sid)
Packit Service a9274b
{
Packit Service a9274b
	printf("event remove: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int melem_event(snd_mixer_elem_t *elem, unsigned int mask)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_selem_id_t *sid;
Packit Service a9274b
	snd_mixer_selem_id_alloca(&sid;;
Packit Service a9274b
	snd_mixer_selem_get_id(elem, sid);
Packit Service a9274b
	if (mask == SND_CTL_EVENT_MASK_REMOVE) {
Packit Service a9274b
		sevents_remove(sid);
Packit Service a9274b
		return 0;
Packit Service a9274b
	}
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_INFO) 
Packit Service a9274b
		sevents_info(sid);
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_VALUE) 
Packit Service a9274b
		sevents_value(sid);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void sevents_add(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_selem_id_t *sid;
Packit Service a9274b
	snd_mixer_selem_id_alloca(&sid;;
Packit Service a9274b
	snd_mixer_selem_get_id(elem, sid);
Packit Service a9274b
	printf("event add: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
Packit Service a9274b
	snd_mixer_elem_set_callback(elem, melem_event);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int mixer_event(snd_mixer_t *mixer, unsigned int mask,
Packit Service a9274b
		snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	if (mask & SND_CTL_EVENT_MASK_ADD)
Packit Service a9274b
		sevents_add(elem);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int sevents(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_t *handle;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	if ((err = snd_mixer_open(&handle, 0)) < 0) {
Packit Service a9274b
		error("Mixer %s open error: %s", card, snd_strerror(err));
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
Packit Service a9274b
		error("Mixer attach %s error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
Packit Service a9274b
		error("Mixer register error: %s", snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
	snd_mixer_set_callback(handle, mixer_event);
Packit Service a9274b
	err = snd_mixer_load(handle);
Packit Service a9274b
	if (err < 0) {
Packit Service a9274b
		error("Mixer %s load error: %s", card, snd_strerror(err));
Packit Service a9274b
		snd_mixer_close(handle);
Packit Service a9274b
		return err;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	printf("Ready to listen...\n");
Packit Service a9274b
	while (1) {
Packit Service a9274b
		int res;
Packit Service a9274b
		res = snd_mixer_wait(handle, -1);
Packit Service a9274b
		if (res >= 0) {
Packit Service a9274b
			printf("Poll ok: %i\n", res);
Packit Service a9274b
			res = snd_mixer_handle_events(handle);
Packit Service a9274b
			assert(res >= 0);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	snd_mixer_close(handle);
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * split a line into tokens
Packit Service a9274b
 * the content in the line buffer is modified
Packit Service a9274b
 */
Packit Service a9274b
static int split_line(char *buf, char **token, int max_token)
Packit Service a9274b
{
Packit Service a9274b
	char *dst;
Packit Service a9274b
	int n, esc, quote;
Packit Service a9274b
Packit Service a9274b
	for (n = 0; n < max_token; n++) {
Packit Service a9274b
		while (isspace(*buf))
Packit Service a9274b
			buf++;
Packit Service a9274b
		if (! *buf || *buf == '\n')
Packit Service a9274b
			return n;
Packit Service a9274b
		/* skip comments */
Packit Service a9274b
		if (*buf == '#' || *buf == '!')
Packit Service a9274b
			return n;
Packit Service a9274b
		esc = 0;
Packit Service a9274b
		quote = 0;
Packit Service a9274b
		token[n] = buf;
Packit Service a9274b
		for (dst = buf; *buf && *buf != '\n'; buf++) {
Packit Service a9274b
			if (esc)
Packit Service a9274b
				esc = 0;
Packit Service a9274b
			else if (isspace(*buf) && !quote) {
Packit Service a9274b
				buf++;
Packit Service a9274b
				break;
Packit Service a9274b
			} else if (*buf == '\\') {
Packit Service a9274b
				esc = 1;
Packit Service a9274b
				continue;
Packit Service a9274b
			} else if (*buf == '\'' || *buf == '"') {
Packit Service a9274b
				if (! quote) {
Packit Service a9274b
					quote = *buf;
Packit Service a9274b
					continue;
Packit Service a9274b
				} else if (*buf == quote) {
Packit Service a9274b
					quote = 0;
Packit Service a9274b
					continue;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			*dst++ = *buf;
Packit Service a9274b
		}
Packit Service a9274b
		*dst = 0;
Packit Service a9274b
	}
Packit Service a9274b
	return n;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
#define MAX_ARGS	32
Packit Service a9274b
Packit Service a9274b
static int exec_stdin(void)
Packit Service a9274b
{
Packit Service a9274b
	int narg;
Packit Service a9274b
	char buf[256], *args[MAX_ARGS];
Packit Service a9274b
	int err = 0;
Packit Service a9274b
Packit Service a9274b
	/* quiet = 1; */
Packit Service a9274b
	ignore_error = 1;
Packit Service a9274b
Packit Service a9274b
	while (fgets(buf, sizeof(buf), stdin)) {
Packit Service a9274b
		narg = split_line(buf, args, MAX_ARGS);
Packit Service a9274b
		if (narg > 0) {
Packit Service a9274b
			if (!strcmp(args[0], "sset") || !strcmp(args[0], "set"))
Packit Service a9274b
				err = sset(narg - 1, args + 1, 0, 1);
Packit Service a9274b
			else if (!strcmp(args[0], "cset"))
Packit Service a9274b
				err = cset(narg - 1, args + 1, 0, 1);
Packit Service a9274b
			if (err < 0)
Packit Service a9274b
				return 1;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
Packit Service a9274b
int main(int argc, char *argv[])
Packit Service a9274b
{
Packit Service a9274b
	int morehelp, level = 0;
Packit Service a9274b
	int read_stdin = 0;
Packit Service a9274b
	static const struct option long_option[] =
Packit Service a9274b
	{
Packit Service a9274b
		{"help", 0, NULL, 'h'},
Packit Service a9274b
		{"card", 1, NULL, 'c'},
Packit Service a9274b
		{"device", 1, NULL, 'D'},
Packit Service a9274b
		{"quiet", 0, NULL, 'q'},
Packit Service a9274b
		{"inactive", 0, NULL, 'i'},
Packit Service a9274b
		{"debug", 0, NULL, 'd'},
Packit Service a9274b
		{"nocheck", 0, NULL, 'n'},
Packit Service a9274b
		{"version", 0, NULL, 'v'},
Packit Service a9274b
		{"abstract", 1, NULL, 'a'},
Packit Service a9274b
		{"stdin", 0, NULL, 's'},
Packit Service a9274b
		{"raw-volume", 0, NULL, 'R'},
Packit Service a9274b
		{"mapped-volume", 0, NULL, 'M'},
Packit Service a9274b
		{NULL, 0, NULL, 0},
Packit Service a9274b
	};
Packit Service a9274b
Packit Service a9274b
	morehelp = 0;
Packit Service a9274b
	while (1) {
Packit Service a9274b
		int c;
Packit Service a9274b
Packit Service a9274b
		if ((c = getopt_long(argc, argv, "hc:D:qidnva:sRM", long_option, NULL)) < 0)
Packit Service a9274b
			break;
Packit Service a9274b
		switch (c) {
Packit Service a9274b
		case 'h':
Packit Service a9274b
			help();
Packit Service a9274b
			return 0;
Packit Service a9274b
		case 'c':
Packit Service a9274b
			{
Packit Service a9274b
				int i;
Packit Service a9274b
				i = snd_card_get_index(optarg);
Packit Service a9274b
				if (i >= 0 && i < 32)
Packit Service a9274b
					sprintf(card, "hw:%i", i);
Packit Service a9274b
				else {
Packit Service a9274b
					fprintf(stderr, "Invalid card number.\n");
Packit Service a9274b
					morehelp++;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			break;
Packit Service a9274b
		case 'D':
Packit Service a9274b
			strncpy(card, optarg, sizeof(card)-1);
Packit Service a9274b
			card[sizeof(card)-1] = '\0';
Packit Service a9274b
			break;
Packit Service a9274b
		case 'q':
Packit Service a9274b
			quiet = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'i':
Packit Service a9274b
			level |= LEVEL_INACTIVE;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'd':
Packit Service a9274b
			debugflag = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'n':
Packit Service a9274b
			no_check = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'v':
Packit Service a9274b
			printf("amixer version " SND_UTIL_VERSION_STR "\n");
Packit Service a9274b
			return 1;
Packit Service a9274b
		case 'a':
Packit Service a9274b
			smixer_level = 1;
Packit Service a9274b
			memset(&smixer_options, 0, sizeof(smixer_options));
Packit Service a9274b
			smixer_options.ver = 1;
Packit Service a9274b
			if (!strcmp(optarg, "none"))
Packit Service a9274b
				smixer_options.abstract = SND_MIXER_SABSTRACT_NONE;
Packit Service a9274b
			else if (!strcmp(optarg, "basic"))
Packit Service a9274b
				smixer_options.abstract = SND_MIXER_SABSTRACT_BASIC;
Packit Service a9274b
			else {
Packit Service a9274b
				fprintf(stderr, "Select correct abstraction level (none or basic)...\n");
Packit Service a9274b
				morehelp++;
Packit Service a9274b
			}
Packit Service a9274b
			break;
Packit Service a9274b
		case 's':
Packit Service a9274b
			read_stdin = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'R':
Packit Service a9274b
			std_vol_type = VOL_RAW;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'M':
Packit Service a9274b
			std_vol_type = VOL_MAP;
Packit Service a9274b
			break;
Packit Service a9274b
		default:
Packit Service a9274b
			fprintf(stderr, "Invalid switch or option needs an argument.\n");
Packit Service a9274b
			morehelp++;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	if (morehelp) {
Packit Service a9274b
		help();
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	smixer_options.device = card;
Packit Service a9274b
Packit Service a9274b
	if (read_stdin)
Packit Service a9274b
		return exec_stdin();
Packit Service a9274b
Packit Service a9274b
	if (argc - optind <= 0) {
Packit Service a9274b
		return selems(LEVEL_BASIC | level) ? 1 : 0;
Packit Service a9274b
	}
Packit Service a9274b
	if (!strcmp(argv[optind], "help")) {
Packit Service a9274b
		return help() ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "info")) {
Packit Service a9274b
		return info() ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "controls")) {
Packit Service a9274b
		return controls(level) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "contents")) {
Packit Service a9274b
		return controls(LEVEL_BASIC | level) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "scontrols") || !strcmp(argv[optind], "simple")) {
Packit Service a9274b
		return selems(level) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "scontents")) {
Packit Service a9274b
		return selems(LEVEL_BASIC | level) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "sset") || !strcmp(argv[optind], "set")) {
Packit Service a9274b
		return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "sget") || !strcmp(argv[optind], "get")) {
Packit Service a9274b
		return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "cset")) {
Packit Service a9274b
		return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "cget")) {
Packit Service a9274b
		return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0;
Packit Service a9274b
	} else if (!strcmp(argv[optind], "events")) {
Packit Service a9274b
		return events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL);
Packit Service a9274b
	} else if (!strcmp(argv[optind], "sevents")) {
Packit Service a9274b
		return sevents(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL);
Packit Service a9274b
	} else {
Packit Service a9274b
		fprintf(stderr, "amixer: Unknown command '%s'...\n", argv[optind]);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}