Bill Nottingham 0e0d15
/* Copyright 2005 Red Hat, Inc.
Bill Nottingham 0e0d15
 *
Bill Nottingham 0e0d15
 * Portions extraced from various ALSA code:
Bill Nottingham 0e0d15
 *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
Bill Nottingham 0e0d15
 *                   Jaroslav Kysela <perex@suse.cz>
Bill Nottingham 0e0d15
 *
Bill Nottingham 0e0d15
 * This software may be freely redistributed under the terms of the GNU
Bill Nottingham 0e0d15
 * public license.
Bill Nottingham 0e0d15
 *
Bill Nottingham 0e0d15
 * You should have received a copy of the GNU General Public License
Bill Nottingham 0e0d15
 * along with this program; if not, write to the Free Software
Bill Nottingham 0e0d15
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Bill Nottingham 0e0d15
 *
Bill Nottingham 0e0d15
 */
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
#include <stdio.h>
Bill Nottingham 6c53f8
#include <stdlib.h>
Bill Nottingham 6c53f8
#include <string.h>
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
#include <alsa/asoundlib.h>
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
#define ALSA_CONFIG_PATH	"/etc/asound.state"
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
int get_card_number()
Bill Nottingham 6c53f8
{
Bill Nottingham 6c53f8
	char *devname, *action;
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
	action = getenv("ACTION");
Bill Nottingham 6c53f8
	if (!action || strcmp(action,"add"))
Bill Nottingham 6c53f8
		return -1;
Bill Nottingham 6c53f8
	devname = getenv("DEVNAME");
Bill Nottingham 6c53f8
	if (!devname)
Bill Nottingham 6c53f8
		return -1;
Bill Nottingham 6c53f8
	if (!strncmp(devname,"/dev/snd/controlC",17))
Bill Nottingham 6c53f8
		return atoi(devname+17);
Bill Nottingham 6c53f8
	if (!strncmp(devname,"/dev/snd/pcmC",13))
Bill Nottingham 6c53f8
		return atoi(devname+13);
Bill Nottingham 6c53f8
	return -1;
Bill Nottingham 6c53f8
}
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
int has_config(int index)
Bill Nottingham 6c53f8
{
Bill Nottingham 6c53f8
	int rc = 0;
Bill Nottingham 6c53f8
	snd_config_t *config, *control;
Bill Nottingham 6c53f8
	snd_input_t *in;
Bill Nottingham 6c53f8
	snd_ctl_t *handle;
Bill Nottingham 6c53f8
        snd_ctl_card_info_t *info;
Bill Nottingham 6c53f8
	const char *id;
Bill Nottingham 6c53f8
	char path[32];
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
	rc = snd_config_top(&config);
Bill Nottingham 6c53f8
	if (rc < 0)
Bill Nottingham 6c53f8
		goto out;
Bill Nottingham 6c53f8
	rc = snd_input_stdio_open(&in, ALSA_CONFIG_PATH, "r");
Bill Nottingham 6c53f8
	if (rc >= 0) {
Bill Nottingham 6c53f8
		rc = snd_config_load(config, in);
Bill Nottingham 6c53f8
		snd_input_close(in);
Bill Nottingham 6c53f8
		if (rc < 0)
Bill Nottingham 6c53f8
			goto out;
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
	sprintf(path, "hw:%d", index);
Bill Nottingham 6c53f8
	rc = snd_ctl_open(&handle, path, 0);
Bill Nottingham 6c53f8
	if (rc < 0) 
Bill Nottingham 6c53f8
		goto out;
Bill Nottingham 6c53f8
	snd_ctl_card_info_alloca(&info;;
Bill Nottingham 6c53f8
	rc = snd_ctl_card_info(handle, info);
Bill Nottingham 6c53f8
	if (rc < 0)
Bill Nottingham 6c53f8
		goto out_close;
Bill Nottingham 6c53f8
	id = snd_ctl_card_info_get_id(info);
Bill Nottingham 6c53f8
	rc = snd_config_searchv(config, &control, "state", id, "control", 0);
Bill Nottingham 6c53f8
out_close:
Bill Nottingham 6c53f8
	snd_ctl_close(handle);
Bill Nottingham 6c53f8
out:
Bill Nottingham 6c53f8
	return !rc;
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
}
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
int run_alsactl(int index)
Bill Nottingham 6c53f8
{
Bill Nottingham 6c53f8
	char *args[] = { "/sbin/alsactl", "restore", NULL, NULL };
Bill Nottingham 6c53f8
	char num[10];
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
	sprintf(num,"%d",index);
Bill Nottingham 6c53f8
	args[2] = num;
Bill Nottingham 6c53f8
	execv(args[0],args);
Bill Nottingham 6c53f8
        return 1;
Bill Nottingham 6c53f8
}
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
int frob_mixer(int index)
Bill Nottingham 6c53f8
{
Bill Nottingham 6c53f8
	int rc = 0;
Bill Nottingham 6c53f8
	char card[32];
Bill Nottingham 6c53f8
	snd_mixer_t *handle;
Bill Nottingham 6c53f8
	snd_mixer_selem_id_t *sid;
Bill Nottingham 6c53f8
	snd_mixer_elem_t *elem;
Bill Nottingham 6c53f8
	snd_mixer_selem_id_alloca(&sid;;
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
	sprintf(card,"hw:%d",index);
Bill Nottingham 6c53f8
	if ((rc = snd_mixer_open(&handle, 0)) < 0) {
Bill Nottingham 6c53f8
		return rc;
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
	if ((rc = snd_mixer_attach(handle, card)) < 0) {
Bill Nottingham 6c53f8
		goto out;
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
	if ((rc = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
Bill Nottingham 6c53f8
		goto out;
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
	rc = snd_mixer_load(handle);
Bill Nottingham 6c53f8
	if (rc < 0) {
Bill Nottingham 6c53f8
		goto out;
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
	for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
Bill Nottingham 6c53f8
		long pmin, pmax;
Bill Nottingham 6c53f8
		int c;
Bill Nottingham 6c53f8
		
Bill Nottingham 6c53f8
		snd_mixer_selem_get_id(elem, sid);
Bill Nottingham 6c53f8
		snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
Bill Nottingham 6c53f8
		for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
Bill Nottingham 6c53f8
			if (snd_mixer_selem_has_capture_channel(elem, c)) {
Bill Nottingham 6c53f8
				if (snd_mixer_selem_has_capture_volume(elem))
Bill Nottingham 6c53f8
					snd_mixer_selem_set_capture_volume(elem, c, 0);
Bill Nottingham 6c53f8
				if (!strcmp(snd_mixer_selem_id_get_name(sid),"CD")) {
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_capture_switch(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_capture_switch(elem, c, 1);
Bill Nottingham 6c53f8
				} else {
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_capture_switch(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_capture_switch(elem, c, 0);
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_playback_switch(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_playback_switch(elem, c, 0);
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_playback_volume(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_playback_volume(elem, c, 0);
Bill Nottingham 6c53f8
				} 
Bill Nottingham 6c53f8
			}
Bill Nottingham 6c53f8
			if (snd_mixer_selem_has_playback_channel(elem, c)) {
Bill Nottingham 6c53f8
				if (!snd_mixer_selem_has_capture_channel(elem, c) ||
Bill Nottingham 5fcade
				    !strcmp(snd_mixer_selem_id_get_name(sid),"CD") ||
Bill Nottingham 5fcade
				    !strcmp(snd_mixer_selem_id_get_name(sid),"Wave")) {
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_playback_switch(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_playback_switch(elem, c, 1);
Bill Nottingham 6c53f8
					if (snd_mixer_selem_has_playback_volume(elem))
Bill Nottingham 6c53f8
						snd_mixer_selem_set_playback_volume(elem, c, pmin + (pmax - pmin) * 0.75);
Bill Nottingham 6c53f8
				}
Bill Nottingham 6c53f8
			}
Bill Nottingham 6c53f8
		}
Bill Nottingham 6c53f8
	}
Bill Nottingham 6c53f8
out:
Bill Nottingham 6c53f8
	snd_mixer_close(handle);
Bill Nottingham 6c53f8
	return rc;
Bill Nottingham 6c53f8
}
Bill Nottingham 6c53f8
Bill Nottingham 6c53f8
int main(int argc, char **argv)
Bill Nottingham 6c53f8
{
Bill Nottingham 6c53f8
	int i;
Bill Nottingham 6c53f8
	
Bill Nottingham 6c53f8
	i = get_card_number();
Bill Nottingham 6c53f8
	if (i < 0)
Bill Nottingham 6c53f8
		return 0;
Bill Nottingham 6c53f8
	if (has_config(i))
Bill Nottingham 6c53f8
		return run_alsactl(i);
Bill Nottingham 6c53f8
	else
Bill Nottingham 6c53f8
		return frob_mixer(i);
Bill Nottingham 6c53f8
}