Martin Stransky 2351ac
/* Copyright 2005 Red Hat, Inc.
Martin Stransky 2351ac
 *
Martin Stransky 2351ac
 * Portions extraced from various ALSA code:
Martin Stransky 2351ac
 *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
Martin Stransky 2351ac
 *                   Jaroslav Kysela <perex@suse.cz>
Martin Stransky 2351ac
 *                   Takashi Iwai <tiwai@suse.de>
Martin Stransky 2351ac
 *                   Bernd Kaindl <bk@suse.de>
Martin Stransky 2351ac
 *                   Jan ONDREJ (SAL) <ondrejj@salstar.sk>
Martin Stransky 2351ac
 *
Martin Stransky 2351ac
 * This software may be freely redistributed under the terms of the GNU
Martin Stransky 2351ac
 * public license.
Martin Stransky 2351ac
 *
Martin Stransky 2351ac
 * You should have received a copy of the GNU General Public License
Martin Stransky 2351ac
 * along with this program; if not, write to the Free Software
Martin Stransky 2351ac
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Martin Stransky 2351ac
 *
Martin Stransky 2351ac
 */
Martin Stransky 2351ac
Martin Stransky 55ae1d
#define  VERSION  "0.2"
Martin Stransky 55ae1d
Martin Stransky 2351ac
#include <stdio.h>
Martin Stransky 2351ac
#include <stdlib.h>
Martin Stransky 2351ac
#include <string.h>
Martin Stransky 2351ac
#include <ctype.h>
Martin Stransky 2351ac
Martin Stransky 2351ac
#include <alsa asoundlib.h="">
Martin Stransky 2351ac
Martin Stransky 2351ac
#define TRUE  (1==1)
Martin Stransky 2351ac
#define FALSE (1!=1)
Martin Stransky 2351ac
Martin Stransky 2351ac
int verbose = 0;
Martin Stransky 2351ac
Martin Stransky 2351ac
typedef struct _CHANNEL {
Martin Stransky 2351ac
Martin Stransky 2351ac
  char name[100];
Martin Stransky 2351ac
  int play_volume;
Martin Stransky 2351ac
  int play_switch;
Martin Stransky 2351ac
  int rec_volume;
Martin Stransky 2351ac
  int rec_switch;
Martin Stransky 2351ac
  char driver[100];
Martin Stransky 2351ac
Martin Stransky 2351ac
} CHANNEL;
Martin Stransky 2351ac
Martin Stransky 2351ac
CHANNEL channels[] = {
Martin Stransky 2351ac
Martin Stransky 2351ac
//   channel          pl vol  pl swt  rec vol  rec swt     driver
Martin Stransky 2351ac
Martin Stransky 2351ac
  {"Master", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"Front", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"PCM", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"PCM-2", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"Synth", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"CD", 		75, 	1, 	90, 	1, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // mute mic
Martin Stransky 2351ac
  {"Mic", 		0, 	0, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Trident/YMFPCI/emu10k1
Martin Stransky 2351ac
  {"Wave", 		100, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"Music", 		100, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"AC97", 		100, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // CS4237B chipset
Martin Stransky 2351ac
  {"Master Digital", 	75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Envy24 chips with analog outs
Martin Stransky 2351ac
  {"DAC", 		75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Powermacs
Martin Stransky 2351ac
  {"DRC Range", 	75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // some notebooks use headphone instead of master
Martin Stransky 2351ac
  {"Headphone", 	75, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
  {"Playback", 		100, 	1, 	0, 	0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // turn off digital switches
Martin Stransky 2351ac
  {"SB Live Analog/Digital Output Jack", 0, 0, 0, 0, 	""},
Martin Stransky 2351ac
  {"Audigy Analog/Digital Output Jack", 0, 0, 0, 0, 	""},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Specific config for ca0106
Martin Stransky 2351ac
  {"Analog Front",	75, 	1, 	0, 	0, 	"snd-ca0106"},
Martin Stransky 2351ac
  {"Analog Rear",	75, 	1, 	0, 	0, 	"snd-ca0106"},
Martin Stransky 2351ac
  {"SPDIF Out",		 0, 	0, 	0, 	0, 	"snd-ca0106"},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Specific config for snd-emu10k1
Martin Stransky 2351ac
  {"Audigy Analog/Digital Output Jack",	0,1,0, 	0, 	"snd-emu10k1"},
Martin Stransky 2351ac
  {"IEC958 Optical Raw", 0,	0,	0, 	0, 	"snd-emu10k1"},
Martin Stransky 2351ac
  {"Tone", 		 0,	0,	0, 	0, 	"snd-emu10k1"},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Specific config for snd-intel8x0
Martin Stransky 241693
  {"External Amplifier", 1,	1,	0, 	0, 	"snd-intel8x0"},
Martin Stransky 2351ac
Martin Stransky 2351ac
  // Specific config for snd-intel8x0 (xw8000)
Martin Stransky 2351ac
  {"Master Mono", 	75,	1,	0, 	0, 	"snd-intel8x0"},  
Martin Stransky 2351ac
Martin Stransky fbbfc1
  // Specific config for snd-ens1371
Martin Stransky fc00f4
  {"IEC958", 		0,	0,	0, 	0, 	"snd-ens1371"},
Martin Stransky fbbfc1
Martin Stransky 0268ed
  // Specific config for snd-azx/snd-hda
Martin Stransky 0268ed
  {"Mono", 		75,	1,	0, 	0, 	"snd-azx"},
Martin Stransky 0268ed
  {"Mono", 		75,	1,	0, 	0, 	"snd-hda"}
Martin Stransky 2351ac
};
Martin Stransky 2351ac
Martin Stransky 2351ac
char * strlwr(char *a)     
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  char *ret = a;
Martin Stransky 2351ac
Martin Stransky 2351ac
  while (*a != '\0') {
Martin Stransky 2351ac
    if (isupper (*a))
Martin Stransky 2351ac
      *a = tolower (*a);
Martin Stransky 2351ac
    a++;
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
  return ret;
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
CHANNEL * channel_find(const char *p_name, const char *p_driver) {
Martin Stransky 2351ac
  int i;
Martin Stransky 2351ac
Martin Stransky 2351ac
  for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++)
Martin Stransky 2351ac
    if (!strcmp(channels[i].driver, p_driver) && !strcmp(channels[i].name, p_name))
Martin Stransky 2351ac
      return (channels + i);
Martin Stransky 2351ac
Martin Stransky 2351ac
  return (NULL);
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
int calc_volume(long min, long max, int percent)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  return ((int)(min + ((max - min) / 100.0f) * percent));
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
int unmute_card(int index, const char *p_driver)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  CHANNEL *p_chan;
Martin Stransky 2351ac
  long pmin, pmax;
Martin Stransky 2351ac
  long rmin, rmax;
Martin Stransky 2351ac
  int rc = 0;
Martin Stransky 2351ac
  char card[32];
Martin Stransky 2351ac
  char channel_name[500];
Martin Stransky 2351ac
  int c,vol;
Martin Stransky 2351ac
Martin Stransky 2351ac
  snd_mixer_t *handle;
Martin Stransky 2351ac
  snd_mixer_selem_id_t *sid;
Martin Stransky 2351ac
  snd_mixer_elem_t *elem;
Martin Stransky 2351ac
  snd_mixer_selem_id_alloca(&sid);
Martin Stransky 2351ac
Martin Stransky 2351ac
  if(verbose) {
Martin Stransky 2351ac
    fprintf(stderr,"Unmuting %s...\n",p_driver ? p_driver : "");
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
Martin Stransky 2351ac
  sprintf(card, "hw:%d", index);
Martin Stransky 2351ac
  if ((rc = snd_mixer_open(&handle, 0)) < 0) {
Martin Stransky 2351ac
    if(verbose) {
Martin Stransky 2351ac
      fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
    return rc;
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
  if ((rc = snd_mixer_attach(handle, card)) < 0) {
Martin Stransky 2351ac
    if(verbose) {
Martin Stransky 2351ac
      fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
    goto out;
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
  if ((rc = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
Martin Stransky 2351ac
    if(verbose) {
Martin Stransky 2351ac
      fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
    goto out;
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
  rc = snd_mixer_load(handle);
Martin Stransky 2351ac
  if (rc < 0) {
Martin Stransky 2351ac
    if(verbose) {
Martin Stransky 2351ac
      fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
    goto out;
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
Martin Stransky 2351ac
  for (elem = snd_mixer_first_elem(handle); elem;
Martin Stransky 2351ac
       elem = snd_mixer_elem_next(elem)) {
Martin Stransky 2351ac
Martin Stransky 2351ac
    snd_mixer_selem_get_id(elem, sid);
Martin Stransky 2351ac
    strncpy(channel_name,snd_mixer_selem_id_get_name(sid),500);    
Martin Stransky 2351ac
    channel_name[499] = '\0';
Martin Stransky 2351ac
    p_chan = channel_find(strlwr(channel_name),p_driver);
Martin Stransky 2351ac
    if (!p_chan)
Martin Stransky 2351ac
      continue;
Martin Stransky 2351ac
Martin Stransky 2351ac
    for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
Martin Stransky 2351ac
Martin Stransky 2351ac
      if (snd_mixer_selem_has_capture_channel(elem, c)) {
Martin Stransky 2351ac
        if (snd_mixer_selem_has_capture_switch(elem)) {
Martin Stransky 2351ac
          snd_mixer_selem_set_capture_switch(elem, c, p_chan->rec_switch);
Martin Stransky 2351ac
	  if(verbose) {
Martin Stransky 2351ac
             fprintf(stderr,"Cap. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->rec_switch);
Martin Stransky 2351ac
          }
Martin Stransky 2351ac
	}
Martin Stransky 2351ac
        if (snd_mixer_selem_has_capture_volume(elem)) {
Martin Stransky 2351ac
          snd_mixer_selem_get_capture_volume_range(elem, &rmin, &rmax);
Martin Stransky 2351ac
	  vol = calc_volume(rmin, rmax,p_chan->rec_volume);
Martin Stransky 2351ac
          snd_mixer_selem_set_capture_volume(elem, c, vol);
Martin Stransky 2351ac
	  if(verbose) {
Martin Stransky 2351ac
             fprintf(stderr,"Cap. Volume %s(%d) to %d\n",p_chan->name,c,vol);
Martin Stransky 2351ac
          }	
Martin Stransky 2351ac
        }
Martin Stransky 2351ac
      }
Martin Stransky 2351ac
Martin Stransky 2351ac
      if (snd_mixer_selem_has_playback_channel(elem, c)) {
Martin Stransky 2351ac
        if (snd_mixer_selem_has_playback_switch(elem)) {
Martin Stransky 2351ac
          snd_mixer_selem_set_playback_switch(elem, c, p_chan->play_switch);
Martin Stransky 2351ac
	  if(verbose) {
Martin Stransky 2351ac
             fprintf(stderr,"Play. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->play_switch);
Martin Stransky 2351ac
          }
Martin Stransky 2351ac
	}
Martin Stransky 2351ac
        if (snd_mixer_selem_has_playback_volume(elem)) {
Martin Stransky 2351ac
          snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
Martin Stransky 2351ac
	  vol = calc_volume(pmin, pmax,p_chan->play_volume);
Martin Stransky 2351ac
          snd_mixer_selem_set_playback_volume(elem, c, vol);
Martin Stransky 2351ac
	  if(verbose) {
Martin Stransky 2351ac
             fprintf(stderr,"Play. Volume %s(%d) to %d\n",p_chan->name,c,vol);
Martin Stransky 2351ac
          }	             
Martin Stransky 2351ac
        }
Martin Stransky 2351ac
      }
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
  return(TRUE);
Martin Stransky 2351ac
Martin Stransky 2351ac
out:
Martin Stransky 2351ac
  snd_mixer_close(handle);
Martin Stransky 2351ac
  return rc;
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
char * check_driver_name(char *p_name)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  char *p_tmp = strchr(p_name,'-');
Martin Stransky 2351ac
  if(p_tmp) {
Martin Stransky 2351ac
    *p_tmp = '_';
Martin Stransky 2351ac
  }    
Martin Stransky 2351ac
  return(p_name);
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
#define PROC_MODULES "/proc/asound/modules"
Martin Stransky 2351ac
Martin Stransky 2351ac
static char  driver_name[100];
Martin Stransky 2351ac
Martin Stransky 2351ac
const char * get_card_driver(int index)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  FILE *f = fopen(PROC_MODULES,"r");
Martin Stransky 2351ac
  char  tmp[100];
Martin Stransky 2351ac
  char *p_tmp;  
Martin Stransky 2351ac
  int   id;
Martin Stransky 2351ac
Martin Stransky 2351ac
  if(!f)
Martin Stransky 2351ac
    return(NULL);
Martin Stransky 2351ac
Martin Stransky 2351ac
  while(fgets(tmp,100,f)) {
Martin Stransky 2351ac
    sscanf(tmp," %d %s",&id,driver_name);
Martin Stransky 2351ac
    if(id == index) {
Martin Stransky 2351ac
      return(check_driver_name(driver_name));
Martin Stransky 2351ac
    }
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
 
Martin Stransky 2351ac
  return(NULL);
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 55ae1d
void set_volume(int volume)
Martin Stransky 55ae1d
{
Martin Stransky 55ae1d
  int i;
Martin Stransky 55ae1d
Martin Stransky 55ae1d
  for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) {
Martin Stransky 55ae1d
    if (channels[i].play_volume > 1)
Martin Stransky 55ae1d
        channels[i].play_volume = volume;
Martin Stransky 55ae1d
  }
Martin Stransky 55ae1d
}
Martin Stransky 55ae1d
Martin Stransky 2351ac
void check_data(void)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  char *p_tmp;
Martin Stransky 2351ac
  int i;
Martin Stransky 2351ac
Martin Stransky 2351ac
  for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) {
Martin Stransky 2351ac
    strlwr(channels[i].name);
Martin Stransky 2351ac
    check_driver_name(channels[i].driver);
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
void usage(char *p_name)
Martin Stransky 2351ac
{
Martin Stransky 55ae1d
  printf("Alsa Unmute utility, Version %s, Copyright 2005 Red Hat, Inc.\n",VERSION);
Martin Stransky 2351ac
  printf("This software may be freely redistributed under the terms of the GNU\n");
Martin Stransky 2351ac
  printf("public license.\n\n");
Martin Stransky 2351ac
Martin Stransky 55ae1d
  printf("Usage: alsaunmute card_number [-v] [-s volume]\n\n", p_name);
Martin Stransky 55ae1d
  printf("  card_number       - number of unmuted card\n");
Martin Stransky 55ae1d
  printf("  [-v]              - verbose mode\n");
Martin Stransky 55ae1d
  printf("  [-s volume]       - set this volume level instead of the default (75%)\n");
Martin Stransky 55ae1d
  printf("                      the volume is number from 0 to 100\n\n");
Martin Stransky 2351ac
  exit(0);
Martin Stransky 2351ac
}
Martin Stransky 2351ac
Martin Stransky 2351ac
/* 
Martin Stransky 2351ac
   Unmute specified card  
Martin Stransky 2351ac
   alsaunmute 0 
Martin Stransky 2351ac
*/
Martin Stransky 2351ac
int main(int argc, char **argv)
Martin Stransky 2351ac
{
Martin Stransky 2351ac
  const char *p_driver;
Martin Stransky 2351ac
  int index;
Martin Stransky 55ae1d
  int volume = 75;
Martin Stransky 55ae1d
  int param;
Martin Stransky 2351ac
Martin Stransky 2351ac
  if (argc < 2) {
Martin Stransky 2351ac
    usage(argv[0]);
Martin Stransky 2351ac
    exit(0);
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
Martin Stransky 2351ac
  index = atoi(argv[1]);
Martin Stransky 2351ac
  p_driver = get_card_driver(index);
Martin Stransky 55ae1d
  
Martin Stransky 55ae1d
  for(param = 2; param < argc; param++) {  
Martin Stransky 55ae1d
    if (!strcmp(argv[param],"-v") || !strcmp(argv[param],"-V")) {
Martin Stransky 55ae1d
      verbose = TRUE;
Martin Stransky 55ae1d
      continue;
Martin Stransky 55ae1d
    }
Martin Stransky 2351ac
Martin Stransky 55ae1d
    if (param+1 < argc && (!strcmp(argv[param],"-s") || !strcmp(argv[param],"-S"))) {
Martin Stransky 55ae1d
      param++;
Martin Stransky 55ae1d
      volume = atoi(argv[param]);
Martin Stransky 55ae1d
    }
Martin Stransky 2351ac
  }
Martin Stransky 55ae1d
Martin Stransky 2351ac
  
Martin Stransky 2351ac
  if(!p_driver) {
Martin Stransky 2351ac
    fprintf(stderr,"Wrong card index %d...\n",index);
Martin Stransky 2351ac
    return(1);  
Martin Stransky 2351ac
  } 
Martin Stransky 2351ac
Martin Stransky 2351ac
  if(verbose) {
Martin Stransky 55ae1d
    fprintf(stderr,"Card %d Driver %s Volume %d%%...\n",index,p_driver,volume);
Martin Stransky 2351ac
  }
Martin Stransky 2351ac
Martin Stransky 2351ac
  check_data();
Martin Stransky 2351ac
Martin Stransky 55ae1d
  // setting volume
Martin Stransky 55ae1d
  set_volume(volume);
Martin Stransky 55ae1d
Martin Stransky 2351ac
  // default settings for all cards
Martin Stransky 2351ac
  unmute_card(index,"");
Martin Stransky 2351ac
Martin Stransky 2351ac
  // specific setting for selected card_number  
Martin Stransky 2351ac
  unmute_card(index,p_driver);
Martin Stransky 2351ac
Martin Stransky 2351ac
  return (0);
Martin Stransky 2351ac
}