diff -r f1ca33c27609 audio.c
--- a/audio.c	Mon Jun 13 01:23:06 2011 +0200
+++ b/audio.c	Tue Jun 21 13:51:32 2011 +0200
@@ -52,6 +52,7 @@
 CONFIG_INT( "audio.mgain",	mgain,		4 );
 CONFIG_INT( "audio.dgain.l",	dgain_l,	0 );
 CONFIG_INT( "audio.dgain.r",	dgain_r,	0 );
+CONFIG_INT( "audio.dgain.out",	dgain_out,	0 );
 CONFIG_INT( "audio.mic-power",	mic_power,	1 );
 CONFIG_INT( "audio.lovl",	lovl,		0 );
 CONFIG_INT( "audio.o2gain",	o2gain,		0 );
@@ -83,17 +84,16 @@
 }
 
 // from Morgan Look
-// THIS FUNCTION IS NOT TESTED!!! (it may work, or it may not)
 void masked_audio_ic_write(
-   unsigned reg,     // the register we wish to manipulate (eg AUDIO_IC_SIG1)
+   unsigned reg,  // the register we wish to manipulate (eg AUDIO_IC_SIG1)
    unsigned mask, // the range of bits we want to manipulate (eg 0x05 or b0000111) to only allow changes to b3,b2,b0
-   unsigned bits     // the bits we wish to set (eg 0x02 or b000010 to set b1, while clearing others within scope of the mask)
+   unsigned bits  // the bits we wish to set (eg 0x02 or b000010 to set b1, while clearing others within scope of the mask)
 )
 {
-   unsigned old;                       // variable to store current register value
+   unsigned old;              // variable to store current register value
    old = audio_ic_read(reg);  // read current register value
-   old &= ~mask;                     // bitwise AND old value against inverted mask
-   bits &= mask;                      // limit scope of new bits with mask
+   old &= ~mask;              // bitwise AND old value against inverted mask
+   bits &= mask;              // limit scope of new bits with mask
    _audio_ic_write(reg | bits | old);    // bitwise OR everything together and call _audio_ic_write function
 }
 
@@ -282,6 +282,12 @@
 	draw_meter( 0, &audio_levels[0], left_label);
 	draw_ticks( 12, 4 );
 	draw_meter( 16, &audio_levels[1], right_label);
+
+	if (gui_menu_shown() && alc_enable)
+	{
+		int dgain_x1000 = audio_cmd_to_gain_x1000(audio_ic_read(AUDIO_IC_ALCVOL));
+		bmp_printf(FONT_MED, 550, 450, "AGC: %d.%03d dB", dgain_x1000 / 1000, dgain_x1000 % 1000);
+	}
 }
 
 #endif
@@ -412,19 +418,12 @@
 )
 {
 	unsigned bits = mgain_index2bits(index);
-	bits &= 0x7;
-	unsigned sig1 = audio_ic_read( AUDIO_IC_SIG1 );
-	sig1 &= ~0x3;
-	sig1 |= (bits & 1);
-	sig1 |= (bits & 4) >> 1;
-	audio_ic_write( AUDIO_IC_SIG1 | sig1 );
-	gain.sig1 = sig1;
 
-	unsigned sig2 = audio_ic_read( AUDIO_IC_SIG2 );
-	sig2 &= ~(1<<5);
-	sig2 |= (bits & 2) << 4;
-	audio_ic_write( AUDIO_IC_SIG2 | sig2 );
-	gain.sig2 = sig2;
+	masked_audio_ic_write(AUDIO_IC_SIG1, 0x3, (bits & 1) | ((bits & 4) >> 1));
+	gain.sig1 = audio_ic_read( AUDIO_IC_SIG1 );
+
+	masked_audio_ic_write(AUDIO_IC_SIG2, 1<<5, (bits & 2) << 4);
+	gain.sig2 = audio_ic_read( AUDIO_IC_SIG2 );
 }
 
 
@@ -439,6 +438,14 @@
 	return cmd;
 }
 
+int
+audio_cmd_to_gain_x1000(
+	int			cmd
+)
+{
+	int gain_x1000 = (cmd - 145) * 375;
+	return gain_x1000;
+}
 
 static inline void
 audio_ic_set_input_volume(
@@ -447,12 +454,17 @@
 )
 {
 	unsigned cmd = audio_gain_to_cmd( gain );
-	if( channel )
-		cmd |= AUDIO_IC_IVL;
-	else
-		cmd |= AUDIO_IC_IVR;
+	masked_audio_ic_write(channel ? AUDIO_IC_IVL : AUDIO_IC_IVR, 0xff, cmd);
+}
 
-	audio_ic_write( cmd );
+static inline void
+audio_ic_set_output_volume(
+	int			channel,
+	int			gain
+)
+{
+	unsigned cmd = audio_gain_to_cmd( gain );
+	masked_audio_ic_write(channel ? AUDIO_IC_OVL : AUDIO_IC_OVR, 0xff, cmd);
 }
 
 
@@ -631,33 +643,36 @@
 	//~ static int iter=0;
 	//~ bmp_printf(FONT_MED, 0, 70, "audio configure(%d)", iter++);
 
-	audio_ic_write( AUDIO_IC_PM1 | 0x6D ); // power up ADC and DAC
+	masked_audio_ic_write( AUDIO_IC_PM1, 0xFF, 0x6D ); // power up ADC and DAC
 	
 	//mic_power is forced on if input source is 0 or 1
 	int mic_pow = get_mic_power(input_source);
 				 
-	audio_ic_write( AUDIO_IC_SIG1
-		| 0x10
-		| ( mic_pow ? 0x4 : 0x0 )
-	); // power up, no gain
+	
+	masked_audio_ic_write( AUDIO_IC_SIG1, 0b00110111, 
+		0x10 | // DACL ?! enable stereo line output maybe?
+		( mic_pow ? 0x4 : 0x0 ) // mic power
+	);
 
-	audio_ic_write( AUDIO_IC_SIG2
-		| 0x04 // external, no gain
-		| ( lovl & 0x3) << 0 // line output level
+	masked_audio_ic_write( AUDIO_IC_SIG2, 0b00000111, 
+		0x04 //external, no gain (BEEPL)
+		| (lovl & 0x3) // line output level
 	);
 
 	//PM3 is set according to the input choice
-	audio_ic_write( AUDIO_IC_PM3 | pm3[input_source] );
+	masked_audio_ic_write( AUDIO_IC_PM3, 0b00011111, pm3[input_source] );
 
-	gain.alc1 = alc_enable ? (1<<5) : 0;
-	audio_ic_write( AUDIO_IC_ALC1 | gain.alc1 ); // disable all ALC
+	masked_audio_ic_write( AUDIO_IC_ALC1, 1<<5, alc_enable ? (1<<5) : 0 ); // disable all ALC
+	gain.alc1 = audio_ic_read( AUDIO_IC_ALC1 );
 
-	// Control left/right gain independently
-	audio_ic_write( AUDIO_IC_MODE4 | 0x00 );
+	// Control left/right gain independently (IVOLC)
+	masked_audio_ic_write( AUDIO_IC_MODE4, 1<<3, 0 );
 
 	audio_ic_set_input_volume( 0, dgain_r );
 	audio_ic_set_input_volume( 1, dgain_l );
 	audio_ic_set_mgain( mgain );
+	audio_ic_set_output_volume( 0, dgain_out );
+	audio_ic_set_output_volume( 1, dgain_out );
 
 	if (disable_filters) {
 		audio_ic_write( AUDIO_IC_FIL1 | 0x00 ); //no need to set them all to 0Hz, just turn em off, in one easy register
@@ -666,9 +681,8 @@
 	// Enable loop mode and output digital volume2
 	uint32_t mode3 = audio_ic_read( AUDIO_IC_MODE3 );
 	mode3 &= ~0x5C; // disable loop, olvc, datt0/1
-	audio_ic_write( AUDIO_IC_MODE3
-		| mode3				// old value
-		| loopback << 6		// loop mode
+	masked_audio_ic_write( AUDIO_IC_MODE3, 0b01001100, 
+		loopback << 6		// loop mode
 		| (o2gain & 0x3) << 2	// output volume
 	);
 
@@ -748,7 +762,7 @@
 		"Analog Gain   : %d dB",
 		mgain_index2gain(gain_index)
 	);
-	menu_draw_icon(x, y, alc_enable ? MNI_WARNING : MNI_PERCENT, mgain_index2gain(gain_index) * 100 / 32);
+	menu_draw_icon(x, y, MNI_PERCENT, mgain_index2gain(gain_index) * 100 / 32);
 }
 
 
@@ -782,12 +796,13 @@
 	bmp_printf(
 		selected ? MENU_FONT_SEL : MENU_FONT,
 		x, y,
-		// 23456789012
 		"%s-DigitalGain : %d dB",
-		priv == &dgain_l ? "L" : "R",
-		*(unsigned*) priv
+		priv == &dgain_l ? "L" :
+		priv == &dgain_r ? "R" :
+		priv == &dgain_out ? "O" : "?",
+		*(int*)priv
 	);
-	menu_draw_icon(x, y, alc_enable ? MNI_WARNING : MNI_PERCENT, (*(unsigned*) priv) * 100 / 36);
+	menu_draw_icon(x, y, alc_enable && priv != &dgain_out ? MNI_WARNING : MNI_PERCENT, (*(unsigned*) priv) * 100 / 36);
 }
 
 
@@ -1054,6 +1069,13 @@
 		.help = "Output volume for audio monitoring (headphones only)."
 	},
 	{
+		.priv		= &dgain_out,
+		.select		= audio_dgain_toggle,
+		.select_reverse = audio_dgain_toggle_reverse,
+		.display	= audio_dgain_display,
+		.help = "Digital gain for audio monitoring maybe?"
+	},
+	{
 		.priv = &audio_monitoring,
 		.select		= audio_monitoring_toggle,
 		.display	= audio_monitoring_display,
