2005-04-17 02:20:36 +04:00
/*
2007-10-15 11:50:19 +04:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-17 02:20:36 +04:00
* Routines for Sound Blaster mixer control
*
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <asm/io.h>
# include <linux/delay.h>
# include <linux/time.h>
# include <sound/core.h>
# include <sound/sb.h>
# include <sound/control.h>
# undef IO_DEBUG
2005-11-17 16:34:36 +03:00
void snd_sbmixer_write ( struct snd_sb * chip , unsigned char reg , unsigned char data )
2005-04-17 02:20:36 +04:00
{
outb ( reg , SBP ( chip , MIXER_ADDR ) ) ;
udelay ( 10 ) ;
outb ( data , SBP ( chip , MIXER_DATA ) ) ;
udelay ( 10 ) ;
# ifdef IO_DEBUG
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_DEBUG " mixer_write 0x%x 0x%x \n " , reg , data ) ;
2005-04-17 02:20:36 +04:00
# endif
}
2005-11-17 16:34:36 +03:00
unsigned char snd_sbmixer_read ( struct snd_sb * chip , unsigned char reg )
2005-04-17 02:20:36 +04:00
{
unsigned char result ;
outb ( reg , SBP ( chip , MIXER_ADDR ) ) ;
udelay ( 10 ) ;
result = inb ( SBP ( chip , MIXER_DATA ) ) ;
udelay ( 10 ) ;
# ifdef IO_DEBUG
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_DEBUG " mixer_read 0x%x 0x%x \n " , reg , result ) ;
2005-04-17 02:20:36 +04:00
# endif
return result ;
}
/*
* Single channel mixer element
*/
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_info_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
uinfo - > type = mask = = 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = mask ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_get_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int reg = kcontrol - > private_value & 0xff ;
int shift = ( kcontrol - > private_value > > 16 ) & 0xff ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
unsigned char val ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
val = ( snd_sbmixer_read ( sb , reg ) > > shift ) & mask ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
ucontrol - > value . integer . value [ 0 ] = val ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_put_single ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int reg = kcontrol - > private_value & 0xff ;
int shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int change ;
unsigned char val , oval ;
val = ( ucontrol - > value . integer . value [ 0 ] & mask ) < < shift ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , reg ) ;
val = ( oval & ~ ( mask < < shift ) ) | val ;
change = val ! = oval ;
if ( change )
snd_sbmixer_write ( sb , reg , val ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
/*
* Double channel mixer element
*/
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_info_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
uinfo - > type = mask = = 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = mask ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_get_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int left_reg = kcontrol - > private_value & 0xff ;
int right_reg = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int right_shift = ( kcontrol - > private_value > > 19 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
unsigned char left , right ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
left = ( snd_sbmixer_read ( sb , left_reg ) > > left_shift ) & mask ;
right = ( snd_sbmixer_read ( sb , right_reg ) > > right_shift ) & mask ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
ucontrol - > value . integer . value [ 0 ] = left ;
ucontrol - > value . integer . value [ 1 ] = right ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_put_double ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int left_reg = kcontrol - > private_value & 0xff ;
int right_reg = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x07 ;
int right_shift = ( kcontrol - > private_value > > 19 ) & 0x07 ;
int mask = ( kcontrol - > private_value > > 24 ) & 0xff ;
int change ;
unsigned char left , right , oleft , oright ;
left = ( ucontrol - > value . integer . value [ 0 ] & mask ) < < left_shift ;
right = ( ucontrol - > value . integer . value [ 1 ] & mask ) < < right_shift ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
if ( left_reg = = right_reg ) {
oleft = snd_sbmixer_read ( sb , left_reg ) ;
left = ( oleft & ~ ( ( mask < < left_shift ) | ( mask < < right_shift ) ) ) | left | right ;
change = left ! = oleft ;
if ( change )
snd_sbmixer_write ( sb , left_reg , left ) ;
} else {
oleft = snd_sbmixer_read ( sb , left_reg ) ;
oright = snd_sbmixer_read ( sb , right_reg ) ;
left = ( oleft & ~ ( mask < < left_shift ) ) | left ;
right = ( oright & ~ ( mask < < right_shift ) ) | right ;
change = left ! = oleft | | right ! = oright ;
if ( change ) {
snd_sbmixer_write ( sb , left_reg , left ) ;
snd_sbmixer_write ( sb , right_reg , right ) ;
}
}
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
/*
* DT - 01 9 x / ALS - 007 capture / input switch
*/
2005-11-17 16:34:36 +03:00
static int snd_dt019x_input_sw_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
2014-10-20 20:14:51 +04:00
static const char * const texts [ 5 ] = {
2005-04-17 02:20:36 +04:00
" CD " , " Mic " , " Line " , " Synth " , " Master "
} ;
2014-10-20 20:14:51 +04:00
return snd_ctl_enum_info ( uinfo , 1 , 5 , texts ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 16:34:36 +03:00
static int snd_dt019x_input_sw_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
unsigned char oval ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_DT019X_CAPTURE_SW ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
switch ( oval & 0x07 ) {
case SB_DT019X_CAP_CD :
ucontrol - > value . enumerated . item [ 0 ] = 0 ;
break ;
case SB_DT019X_CAP_MIC :
ucontrol - > value . enumerated . item [ 0 ] = 1 ;
break ;
case SB_DT019X_CAP_LINE :
ucontrol - > value . enumerated . item [ 0 ] = 2 ;
break ;
case SB_DT019X_CAP_MAIN :
ucontrol - > value . enumerated . item [ 0 ] = 4 ;
break ;
/* To record the synth on these cards you must record the main. */
/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
/* duplicate case labels if left uncommented. */
/* case SB_DT019X_CAP_SYNTH:
* ucontrol - > value . enumerated . item [ 0 ] = 3 ;
* break ;
*/
default :
ucontrol - > value . enumerated . item [ 0 ] = 4 ;
break ;
}
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_dt019x_input_sw_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int change ;
unsigned char nval , oval ;
if ( ucontrol - > value . enumerated . item [ 0 ] > 4 )
return - EINVAL ;
switch ( ucontrol - > value . enumerated . item [ 0 ] ) {
case 0 :
nval = SB_DT019X_CAP_CD ;
break ;
case 1 :
nval = SB_DT019X_CAP_MIC ;
break ;
case 2 :
nval = SB_DT019X_CAP_LINE ;
break ;
case 3 :
nval = SB_DT019X_CAP_SYNTH ;
break ;
case 4 :
nval = SB_DT019X_CAP_MAIN ;
break ;
default :
nval = SB_DT019X_CAP_MAIN ;
}
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_DT019X_CAPTURE_SW ) ;
change = nval ! = oval ;
if ( change )
snd_sbmixer_write ( sb , SB_DT019X_CAPTURE_SW , nval ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
2009-02-22 22:33:41 +03:00
/*
* ALS4000 mono recording control switch
*/
static int snd_als4k_mono_capture_route_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
2014-10-20 20:14:51 +04:00
static const char * const texts [ 3 ] = {
2009-02-22 22:33:41 +03:00
" L chan only " , " R chan only " , " L ch/2 + R ch/2 "
} ;
2014-10-20 20:14:51 +04:00
return snd_ctl_enum_info ( uinfo , 1 , 3 , texts ) ;
2009-02-22 22:33:41 +03:00
}
static int snd_als4k_mono_capture_route_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
unsigned long flags ;
unsigned char oval ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_ALS4000_MONO_IO_CTRL ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
oval > > = 6 ;
if ( oval > 2 )
oval = 2 ;
ucontrol - > value . enumerated . item [ 0 ] = oval ;
return 0 ;
}
static int snd_als4k_mono_capture_route_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
unsigned long flags ;
int change ;
unsigned char nval , oval ;
if ( ucontrol - > value . enumerated . item [ 0 ] > 2 )
return - EINVAL ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_ALS4000_MONO_IO_CTRL ) ;
nval = ( oval & ~ ( 3 < < 6 ) )
| ( ucontrol - > value . enumerated . item [ 0 ] < < 6 ) ;
change = nval ! = oval ;
if ( change )
snd_sbmixer_write ( sb , SB_ALS4000_MONO_IO_CTRL , nval ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
2005-04-17 02:20:36 +04:00
/*
* SBPRO input multiplexer
*/
2005-11-17 16:34:36 +03:00
static int snd_sb8mixer_info_mux ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
2014-10-20 20:14:51 +04:00
static const char * const texts [ 3 ] = {
2005-04-17 02:20:36 +04:00
" Mic " , " CD " , " Line "
} ;
2014-10-20 20:14:51 +04:00
return snd_ctl_enum_info ( uinfo , 1 , 3 , texts ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 16:34:36 +03:00
static int snd_sb8mixer_get_mux ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
unsigned char oval ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_DSP_CAPTURE_SOURCE ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
switch ( ( oval > > 0x01 ) & 0x03 ) {
case SB_DSP_MIXS_CD :
ucontrol - > value . enumerated . item [ 0 ] = 1 ;
break ;
case SB_DSP_MIXS_LINE :
ucontrol - > value . enumerated . item [ 0 ] = 2 ;
break ;
default :
ucontrol - > value . enumerated . item [ 0 ] = 0 ;
break ;
}
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sb8mixer_put_mux ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int change ;
unsigned char nval , oval ;
if ( ucontrol - > value . enumerated . item [ 0 ] > 2 )
return - EINVAL ;
switch ( ucontrol - > value . enumerated . item [ 0 ] ) {
case 1 :
nval = SB_DSP_MIXS_CD ;
break ;
case 2 :
nval = SB_DSP_MIXS_LINE ;
break ;
default :
nval = SB_DSP_MIXS_MIC ;
}
nval < < = 1 ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval = snd_sbmixer_read ( sb , SB_DSP_CAPTURE_SOURCE ) ;
nval | = oval & ~ 0x06 ;
change = nval ! = oval ;
if ( change )
snd_sbmixer_write ( sb , SB_DSP_CAPTURE_SOURCE , nval ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
/*
* SB16 input switch
*/
2005-11-17 16:34:36 +03:00
static int snd_sb16mixer_info_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-17 02:20:36 +04:00
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = 4 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sb16mixer_get_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int reg1 = kcontrol - > private_value & 0xff ;
int reg2 = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x0f ;
int right_shift = ( kcontrol - > private_value > > 24 ) & 0x0f ;
unsigned char val1 , val2 ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
val1 = snd_sbmixer_read ( sb , reg1 ) ;
val2 = snd_sbmixer_read ( sb , reg2 ) ;
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
ucontrol - > value . integer . value [ 0 ] = ( val1 > > left_shift ) & 0x01 ;
ucontrol - > value . integer . value [ 1 ] = ( val2 > > left_shift ) & 0x01 ;
ucontrol - > value . integer . value [ 2 ] = ( val1 > > right_shift ) & 0x01 ;
ucontrol - > value . integer . value [ 3 ] = ( val2 > > right_shift ) & 0x01 ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
static int snd_sb16mixer_put_input_sw ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_sb * sb = snd_kcontrol_chip ( kcontrol ) ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
int reg1 = kcontrol - > private_value & 0xff ;
int reg2 = ( kcontrol - > private_value > > 8 ) & 0xff ;
int left_shift = ( kcontrol - > private_value > > 16 ) & 0x0f ;
int right_shift = ( kcontrol - > private_value > > 24 ) & 0x0f ;
int change ;
unsigned char val1 , val2 , oval1 , oval2 ;
spin_lock_irqsave ( & sb - > mixer_lock , flags ) ;
oval1 = snd_sbmixer_read ( sb , reg1 ) ;
oval2 = snd_sbmixer_read ( sb , reg2 ) ;
val1 = oval1 & ~ ( ( 1 < < left_shift ) | ( 1 < < right_shift ) ) ;
val2 = oval2 & ~ ( ( 1 < < left_shift ) | ( 1 < < right_shift ) ) ;
val1 | = ( ucontrol - > value . integer . value [ 0 ] & 1 ) < < left_shift ;
val2 | = ( ucontrol - > value . integer . value [ 1 ] & 1 ) < < left_shift ;
val1 | = ( ucontrol - > value . integer . value [ 2 ] & 1 ) < < right_shift ;
val2 | = ( ucontrol - > value . integer . value [ 3 ] & 1 ) < < right_shift ;
change = val1 ! = oval1 | | val2 ! = oval2 ;
if ( change ) {
snd_sbmixer_write ( sb , reg1 , val1 ) ;
snd_sbmixer_write ( sb , reg2 , val2 ) ;
}
spin_unlock_irqrestore ( & sb - > mixer_lock , flags ) ;
return change ;
}
/*
*/
/*
*/
2005-11-17 16:34:36 +03:00
int snd_sbmixer_add_ctl ( struct snd_sb * chip , const char * name , int index , int type , unsigned long value )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
static struct snd_kcontrol_new newctls [ ] = {
2005-04-17 02:20:36 +04:00
[ SB_MIX_SINGLE ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_sbmixer_info_single ,
. get = snd_sbmixer_get_single ,
. put = snd_sbmixer_put_single ,
} ,
[ SB_MIX_DOUBLE ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_sbmixer_info_double ,
. get = snd_sbmixer_get_double ,
. put = snd_sbmixer_put_double ,
} ,
[ SB_MIX_INPUT_SW ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_sb16mixer_info_input_sw ,
. get = snd_sb16mixer_get_input_sw ,
. put = snd_sb16mixer_put_input_sw ,
} ,
[ SB_MIX_CAPTURE_PRO ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_sb8mixer_info_mux ,
. get = snd_sb8mixer_get_mux ,
. put = snd_sb8mixer_put_mux ,
} ,
[ SB_MIX_CAPTURE_DT019X ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_dt019x_input_sw_info ,
. get = snd_dt019x_input_sw_get ,
. put = snd_dt019x_input_sw_put ,
} ,
2009-02-22 22:33:41 +03:00
[ SB_MIX_MONO_CAPTURE_ALS4K ] = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. info = snd_als4k_mono_capture_route_info ,
. get = snd_als4k_mono_capture_route_get ,
. put = snd_als4k_mono_capture_route_put ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2005-11-17 16:34:36 +03:00
struct snd_kcontrol * ctl ;
2005-04-17 02:20:36 +04:00
int err ;
ctl = snd_ctl_new1 ( & newctls [ type ] , chip ) ;
if ( ! ctl )
return - ENOMEM ;
strlcpy ( ctl - > id . name , name , sizeof ( ctl - > id . name ) ) ;
ctl - > id . index = index ;
ctl - > private_value = value ;
2006-03-06 15:28:34 +03:00
if ( ( err = snd_ctl_add ( chip - > card , ctl ) ) < 0 )
2005-04-17 02:20:36 +04:00
return err ;
return 0 ;
}
/*
* SB 2.0 specific mixer elements
*/
2009-12-13 23:13:44 +03:00
static struct sbmix_elem snd_sb20_controls [ ] = {
SB_SINGLE ( " Master Playback Volume " , SB_DSP20_MASTER_DEV , 1 , 7 ) ,
SB_SINGLE ( " PCM Playback Volume " , SB_DSP20_PCM_DEV , 1 , 3 ) ,
SB_SINGLE ( " Synth Playback Volume " , SB_DSP20_FM_DEV , 1 , 7 ) ,
SB_SINGLE ( " CD Playback Volume " , SB_DSP20_CD_DEV , 1 , 7 )
2005-04-17 02:20:36 +04:00
} ;
static unsigned char snd_sb20_init_values [ ] [ 2 ] = {
{ SB_DSP20_MASTER_DEV , 0 } ,
{ SB_DSP20_FM_DEV , 0 } ,
} ;
/*
* SB Pro specific mixer elements
*/
2009-12-13 23:13:44 +03:00
static struct sbmix_elem snd_sbpro_controls [ ] = {
SB_DOUBLE ( " Master Playback Volume " ,
SB_DSP_MASTER_DEV , SB_DSP_MASTER_DEV , 5 , 1 , 7 ) ,
SB_DOUBLE ( " PCM Playback Volume " ,
SB_DSP_PCM_DEV , SB_DSP_PCM_DEV , 5 , 1 , 7 ) ,
SB_SINGLE ( " PCM Playback Filter " , SB_DSP_PLAYBACK_FILT , 5 , 1 ) ,
SB_DOUBLE ( " Synth Playback Volume " ,
SB_DSP_FM_DEV , SB_DSP_FM_DEV , 5 , 1 , 7 ) ,
SB_DOUBLE ( " CD Playback Volume " , SB_DSP_CD_DEV , SB_DSP_CD_DEV , 5 , 1 , 7 ) ,
SB_DOUBLE ( " Line Playback Volume " ,
SB_DSP_LINE_DEV , SB_DSP_LINE_DEV , 5 , 1 , 7 ) ,
SB_SINGLE ( " Mic Playback Volume " , SB_DSP_MIC_DEV , 1 , 3 ) ,
2005-04-17 02:20:36 +04:00
{
. name = " Capture Source " ,
. type = SB_MIX_CAPTURE_PRO
2009-12-13 23:13:44 +03:00
} ,
SB_SINGLE ( " Capture Filter " , SB_DSP_CAPTURE_FILT , 5 , 1 ) ,
SB_SINGLE ( " Capture Low-Pass Filter " , SB_DSP_CAPTURE_FILT , 3 , 1 )
2005-04-17 02:20:36 +04:00
} ;
static unsigned char snd_sbpro_init_values [ ] [ 2 ] = {
{ SB_DSP_MASTER_DEV , 0 } ,
{ SB_DSP_PCM_DEV , 0 } ,
{ SB_DSP_FM_DEV , 0 } ,
} ;
/*
* SB16 specific mixer elements
*/
2009-12-13 23:13:44 +03:00
static struct sbmix_elem snd_sb16_controls [ ] = {
SB_DOUBLE ( " Master Playback Volume " ,
SB_DSP4_MASTER_DEV , ( SB_DSP4_MASTER_DEV + 1 ) , 3 , 3 , 31 ) ,
SB_DOUBLE ( " PCM Playback Volume " ,
SB_DSP4_PCM_DEV , ( SB_DSP4_PCM_DEV + 1 ) , 3 , 3 , 31 ) ,
SB16_INPUT_SW ( " Synth Capture Route " ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT , 6 , 5 ) ,
SB_DOUBLE ( " Synth Playback Volume " ,
SB_DSP4_SYNTH_DEV , ( SB_DSP4_SYNTH_DEV + 1 ) , 3 , 3 , 31 ) ,
SB16_INPUT_SW ( " CD Capture Route " ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT , 2 , 1 ) ,
SB_DOUBLE ( " CD Playback Switch " ,
SB_DSP4_OUTPUT_SW , SB_DSP4_OUTPUT_SW , 2 , 1 , 1 ) ,
SB_DOUBLE ( " CD Playback Volume " ,
SB_DSP4_CD_DEV , ( SB_DSP4_CD_DEV + 1 ) , 3 , 3 , 31 ) ,
SB16_INPUT_SW ( " Mic Capture Route " ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT , 0 , 0 ) ,
SB_SINGLE ( " Mic Playback Switch " , SB_DSP4_OUTPUT_SW , 0 , 1 ) ,
SB_SINGLE ( " Mic Playback Volume " , SB_DSP4_MIC_DEV , 3 , 31 ) ,
SB_SINGLE ( " Beep Volume " , SB_DSP4_SPEAKER_DEV , 6 , 3 ) ,
SB_DOUBLE ( " Capture Volume " ,
SB_DSP4_IGAIN_DEV , ( SB_DSP4_IGAIN_DEV + 1 ) , 6 , 6 , 3 ) ,
SB_DOUBLE ( " Playback Volume " ,
SB_DSP4_OGAIN_DEV , ( SB_DSP4_OGAIN_DEV + 1 ) , 6 , 6 , 3 ) ,
SB16_INPUT_SW ( " Line Capture Route " ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT , 4 , 3 ) ,
SB_DOUBLE ( " Line Playback Switch " ,
SB_DSP4_OUTPUT_SW , SB_DSP4_OUTPUT_SW , 4 , 3 , 1 ) ,
SB_DOUBLE ( " Line Playback Volume " ,
SB_DSP4_LINE_DEV , ( SB_DSP4_LINE_DEV + 1 ) , 3 , 3 , 31 ) ,
SB_SINGLE ( " Mic Auto Gain " , SB_DSP4_MIC_AGC , 0 , 1 ) ,
SB_SINGLE ( " 3D Enhancement Switch " , SB_DSP4_3DSE , 0 , 1 ) ,
SB_DOUBLE ( " Tone Control - Bass " ,
SB_DSP4_BASS_DEV , ( SB_DSP4_BASS_DEV + 1 ) , 4 , 4 , 15 ) ,
SB_DOUBLE ( " Tone Control - Treble " ,
SB_DSP4_TREBLE_DEV , ( SB_DSP4_TREBLE_DEV + 1 ) , 4 , 4 , 15 )
2005-04-17 02:20:36 +04:00
} ;
static unsigned char snd_sb16_init_values [ ] [ 2 ] = {
{ SB_DSP4_MASTER_DEV + 0 , 0 } ,
{ SB_DSP4_MASTER_DEV + 1 , 0 } ,
{ SB_DSP4_PCM_DEV + 0 , 0 } ,
{ SB_DSP4_PCM_DEV + 1 , 0 } ,
{ SB_DSP4_SYNTH_DEV + 0 , 0 } ,
{ SB_DSP4_SYNTH_DEV + 1 , 0 } ,
{ SB_DSP4_INPUT_LEFT , 0 } ,
{ SB_DSP4_INPUT_RIGHT , 0 } ,
{ SB_DSP4_OUTPUT_SW , 0 } ,
{ SB_DSP4_SPEAKER_DEV , 0 } ,
} ;
/*
* DT019x specific mixer elements
*/
2009-12-13 23:13:44 +03:00
static struct sbmix_elem snd_dt019x_controls [ ] = {
/* ALS4000 below has some parts which we might be lacking,
* e . g . snd_als4000_ctl_mono_playback_switch - check it ! */
SB_DOUBLE ( " Master Playback Volume " ,
SB_DT019X_MASTER_DEV , SB_DT019X_MASTER_DEV , 4 , 0 , 15 ) ,
SB_DOUBLE ( " PCM Playback Switch " ,
SB_DT019X_OUTPUT_SW2 , SB_DT019X_OUTPUT_SW2 , 2 , 1 , 1 ) ,
SB_DOUBLE ( " PCM Playback Volume " ,
SB_DT019X_PCM_DEV , SB_DT019X_PCM_DEV , 4 , 0 , 15 ) ,
SB_DOUBLE ( " Synth Playback Switch " ,
SB_DT019X_OUTPUT_SW2 , SB_DT019X_OUTPUT_SW2 , 4 , 3 , 1 ) ,
SB_DOUBLE ( " Synth Playback Volume " ,
SB_DT019X_SYNTH_DEV , SB_DT019X_SYNTH_DEV , 4 , 0 , 15 ) ,
SB_DOUBLE ( " CD Playback Switch " ,
SB_DSP4_OUTPUT_SW , SB_DSP4_OUTPUT_SW , 2 , 1 , 1 ) ,
SB_DOUBLE ( " CD Playback Volume " ,
SB_DT019X_CD_DEV , SB_DT019X_CD_DEV , 4 , 0 , 15 ) ,
SB_SINGLE ( " Mic Playback Switch " , SB_DSP4_OUTPUT_SW , 0 , 1 ) ,
SB_SINGLE ( " Mic Playback Volume " , SB_DT019X_MIC_DEV , 4 , 7 ) ,
SB_SINGLE ( " Beep Volume " , SB_DT019X_SPKR_DEV , 0 , 7 ) ,
SB_DOUBLE ( " Line Playback Switch " ,
SB_DSP4_OUTPUT_SW , SB_DSP4_OUTPUT_SW , 4 , 3 , 1 ) ,
SB_DOUBLE ( " Line Playback Volume " ,
SB_DT019X_LINE_DEV , SB_DT019X_LINE_DEV , 4 , 0 , 15 ) ,
2005-04-17 02:20:36 +04:00
{
. name = " Capture Source " ,
. type = SB_MIX_CAPTURE_DT019X
2009-12-13 23:13:44 +03:00
}
2005-04-17 02:20:36 +04:00
} ;
static unsigned char snd_dt019x_init_values [ ] [ 2 ] = {
{ SB_DT019X_MASTER_DEV , 0 } ,
{ SB_DT019X_PCM_DEV , 0 } ,
{ SB_DT019X_SYNTH_DEV , 0 } ,
{ SB_DT019X_CD_DEV , 0 } ,
{ SB_DT019X_MIC_DEV , 0 } , /* Includes PC-speaker in high nibble */
{ SB_DT019X_LINE_DEV , 0 } ,
{ SB_DSP4_OUTPUT_SW , 0 } ,
{ SB_DT019X_OUTPUT_SW2 , 0 } ,
{ SB_DT019X_CAPTURE_SW , 0x06 } ,
} ;
/*
* ALS4000 specific mixer elements
*/
2009-12-13 23:13:44 +03:00
static struct sbmix_elem snd_als4000_controls [ ] = {
SB_DOUBLE ( " PCM Playback Switch " ,
SB_DT019X_OUTPUT_SW2 , SB_DT019X_OUTPUT_SW2 , 2 , 1 , 1 ) ,
SB_DOUBLE ( " Synth Playback Switch " ,
SB_DT019X_OUTPUT_SW2 , SB_DT019X_OUTPUT_SW2 , 4 , 3 , 1 ) ,
SB_SINGLE ( " Mic Boost (+20dB) " , SB_ALS4000_MIC_IN_GAIN , 0 , 0x03 ) ,
SB_SINGLE ( " Master Mono Playback Switch " , SB_ALS4000_MONO_IO_CTRL , 5 , 1 ) ,
{
2009-02-22 22:33:41 +03:00
. name = " Master Mono Capture Route " ,
. type = SB_MIX_MONO_CAPTURE_ALS4K
2009-12-13 23:13:44 +03:00
} ,
SB_SINGLE ( " Mono Playback Switch " , SB_DT019X_OUTPUT_SW2 , 0 , 1 ) ,
SB_SINGLE ( " Analog Loopback Switch " , SB_ALS4000_MIC_IN_GAIN , 7 , 0x01 ) ,
SB_SINGLE ( " 3D Control - Switch " , SB_ALS4000_3D_SND_FX , 6 , 0x01 ) ,
2009-02-22 22:33:41 +03:00
SB_SINGLE ( " Digital Loopback Switch " ,
2009-12-13 23:13:44 +03:00
SB_ALS4000_CR3_CONFIGURATION , 7 , 0x01 ) ,
/* FIXME: functionality of 3D controls might be swapped, I didn't find
* a description of how to identify what is supposed to be what */
SB_SINGLE ( " 3D Control - Level " , SB_ALS4000_3D_SND_FX , 0 , 0x07 ) ,
2005-11-17 13:03:31 +03:00
/* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
2009-12-13 23:13:44 +03:00
SB_SINGLE ( " 3D Control - Freq " , SB_ALS4000_3D_SND_FX , 4 , 0x03 ) ,
2005-11-17 13:03:31 +03:00
/* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
* but what ALSA 3 D attribute is that actually ? " Center " , " Depth " ,
* " Wide " or " Space " or even " Level " ? Assuming " Wide " for now . . . */
2009-12-13 23:13:44 +03:00
SB_SINGLE ( " 3D Control - Wide " , SB_ALS4000_3D_TIME_DELAY , 0 , 0x0f ) ,
SB_SINGLE ( " 3D PowerOff Switch " , SB_ALS4000_3D_TIME_DELAY , 4 , 0x01 ) ,
2009-02-22 22:33:41 +03:00
SB_SINGLE ( " Master Playback 8kHz / 20kHz LPF Switch " ,
2009-12-13 23:13:44 +03:00
SB_ALS4000_FMDAC , 5 , 0x01 ) ,
2005-07-27 22:45:17 +04:00
# ifdef NOT_AVAILABLE
2009-12-13 23:13:44 +03:00
SB_SINGLE ( " FMDAC Switch (Option ?) " , SB_ALS4000_FMDAC , 0 , 0x01 ) ,
SB_SINGLE ( " QSound Mode " , SB_ALS4000_QSOUND , 1 , 0x1f ) ,
2005-04-17 02:20:36 +04:00
# endif
} ;
static unsigned char snd_als4000_init_values [ ] [ 2 ] = {
{ SB_DSP4_MASTER_DEV + 0 , 0 } ,
{ SB_DSP4_MASTER_DEV + 1 , 0 } ,
{ SB_DSP4_PCM_DEV + 0 , 0 } ,
{ SB_DSP4_PCM_DEV + 1 , 0 } ,
{ SB_DSP4_SYNTH_DEV + 0 , 0 } ,
{ SB_DSP4_SYNTH_DEV + 1 , 0 } ,
{ SB_DSP4_SPEAKER_DEV , 0 } ,
{ SB_DSP4_OUTPUT_SW , 0 } ,
{ SB_DSP4_INPUT_LEFT , 0 } ,
{ SB_DSP4_INPUT_RIGHT , 0 } ,
{ SB_DT019X_OUTPUT_SW2 , 0 } ,
{ SB_ALS4000_MIC_IN_GAIN , 0 } ,
} ;
/*
*/
2005-11-17 16:34:36 +03:00
static int snd_sbmixer_init ( struct snd_sb * chip ,
2009-12-13 23:13:44 +03:00
struct sbmix_elem * controls ,
2005-04-17 02:20:36 +04:00
int controls_count ,
unsigned char map [ ] [ 2 ] ,
int map_count ,
char * name )
{
unsigned long flags ;
2005-11-17 16:34:36 +03:00
struct snd_card * card = chip - > card ;
2005-04-17 02:20:36 +04:00
int idx , err ;
/* mixer reset */
spin_lock_irqsave ( & chip - > mixer_lock , flags ) ;
snd_sbmixer_write ( chip , 0x00 , 0x00 ) ;
spin_unlock_irqrestore ( & chip - > mixer_lock , flags ) ;
/* mute and zero volume channels */
for ( idx = 0 ; idx < map_count ; idx + + ) {
spin_lock_irqsave ( & chip - > mixer_lock , flags ) ;
snd_sbmixer_write ( chip , map [ idx ] [ 0 ] , map [ idx ] [ 1 ] ) ;
spin_unlock_irqrestore ( & chip - > mixer_lock , flags ) ;
}
for ( idx = 0 ; idx < controls_count ; idx + + ) {
2009-12-13 23:13:44 +03:00
err = snd_sbmixer_add_ctl_elem ( chip , & controls [ idx ] ) ;
if ( err < 0 )
2005-04-17 02:20:36 +04:00
return err ;
}
snd_component_add ( card , name ) ;
strcpy ( card - > mixername , name ) ;
return 0 ;
}
2005-11-17 16:34:36 +03:00
int snd_sbmixer_new ( struct snd_sb * chip )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:34:36 +03:00
struct snd_card * card ;
2005-04-17 02:20:36 +04:00
int err ;
2008-08-08 19:11:45 +04:00
if ( snd_BUG_ON ( ! chip | | ! chip - > card ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
card = chip - > card ;
switch ( chip - > hardware ) {
case SB_HW_10 :
return 0 ; /* no mixer chip on SB1.x */
case SB_HW_20 :
case SB_HW_201 :
if ( ( err = snd_sbmixer_init ( chip ,
snd_sb20_controls ,
ARRAY_SIZE ( snd_sb20_controls ) ,
snd_sb20_init_values ,
ARRAY_SIZE ( snd_sb20_init_values ) ,
" CTL1335 " ) ) < 0 )
return err ;
break ;
case SB_HW_PRO :
2009-12-20 21:01:50 +03:00
case SB_HW_JAZZ16 :
2005-04-17 02:20:36 +04:00
if ( ( err = snd_sbmixer_init ( chip ,
snd_sbpro_controls ,
ARRAY_SIZE ( snd_sbpro_controls ) ,
snd_sbpro_init_values ,
ARRAY_SIZE ( snd_sbpro_init_values ) ,
" CTL1345 " ) ) < 0 )
return err ;
break ;
case SB_HW_16 :
case SB_HW_ALS100 :
2007-05-24 20:46:54 +04:00
case SB_HW_CS5530 :
2005-04-17 02:20:36 +04:00
if ( ( err = snd_sbmixer_init ( chip ,
snd_sb16_controls ,
ARRAY_SIZE ( snd_sb16_controls ) ,
snd_sb16_init_values ,
ARRAY_SIZE ( snd_sb16_init_values ) ,
" CTL1745 " ) ) < 0 )
return err ;
break ;
case SB_HW_ALS4000 :
2009-12-13 23:13:44 +03:00
/* use only the first 16 controls from SB16 */
err = snd_sbmixer_init ( chip ,
snd_sb16_controls ,
16 ,
snd_sb16_init_values ,
ARRAY_SIZE ( snd_sb16_init_values ) ,
" ALS4000 " ) ;
if ( err < 0 )
return err ;
2005-04-17 02:20:36 +04:00
if ( ( err = snd_sbmixer_init ( chip ,
snd_als4000_controls ,
ARRAY_SIZE ( snd_als4000_controls ) ,
snd_als4000_init_values ,
ARRAY_SIZE ( snd_als4000_init_values ) ,
" ALS4000 " ) ) < 0 )
return err ;
break ;
case SB_HW_DT019X :
2014-05-14 17:32:21 +04:00
err = snd_sbmixer_init ( chip ,
snd_dt019x_controls ,
ARRAY_SIZE ( snd_dt019x_controls ) ,
snd_dt019x_init_values ,
ARRAY_SIZE ( snd_dt019x_init_values ) ,
" DT019X " ) ;
if ( err < 0 )
return err ;
2005-04-17 02:20:36 +04:00
break ;
default :
strcpy ( card - > mixername , " ??? " ) ;
}
return 0 ;
}
2005-11-17 18:16:10 +03:00
# ifdef CONFIG_PM
static unsigned char sb20_saved_regs [ ] = {
SB_DSP20_MASTER_DEV ,
SB_DSP20_PCM_DEV ,
SB_DSP20_FM_DEV ,
SB_DSP20_CD_DEV ,
} ;
static unsigned char sbpro_saved_regs [ ] = {
SB_DSP_MASTER_DEV ,
SB_DSP_PCM_DEV ,
SB_DSP_PLAYBACK_FILT ,
SB_DSP_FM_DEV ,
SB_DSP_CD_DEV ,
SB_DSP_LINE_DEV ,
SB_DSP_MIC_DEV ,
SB_DSP_CAPTURE_SOURCE ,
SB_DSP_CAPTURE_FILT ,
} ;
static unsigned char sb16_saved_regs [ ] = {
SB_DSP4_MASTER_DEV , SB_DSP4_MASTER_DEV + 1 ,
SB_DSP4_3DSE ,
SB_DSP4_BASS_DEV , SB_DSP4_BASS_DEV + 1 ,
SB_DSP4_TREBLE_DEV , SB_DSP4_TREBLE_DEV + 1 ,
SB_DSP4_PCM_DEV , SB_DSP4_PCM_DEV + 1 ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT ,
SB_DSP4_SYNTH_DEV , SB_DSP4_SYNTH_DEV + 1 ,
SB_DSP4_OUTPUT_SW ,
SB_DSP4_CD_DEV , SB_DSP4_CD_DEV + 1 ,
SB_DSP4_LINE_DEV , SB_DSP4_LINE_DEV + 1 ,
SB_DSP4_MIC_DEV ,
SB_DSP4_SPEAKER_DEV ,
SB_DSP4_IGAIN_DEV , SB_DSP4_IGAIN_DEV + 1 ,
SB_DSP4_OGAIN_DEV , SB_DSP4_OGAIN_DEV + 1 ,
SB_DSP4_MIC_AGC
} ;
static unsigned char dt019x_saved_regs [ ] = {
SB_DT019X_MASTER_DEV ,
SB_DT019X_PCM_DEV ,
SB_DT019X_SYNTH_DEV ,
SB_DT019X_CD_DEV ,
SB_DT019X_MIC_DEV ,
SB_DT019X_SPKR_DEV ,
SB_DT019X_LINE_DEV ,
SB_DSP4_OUTPUT_SW ,
SB_DT019X_OUTPUT_SW2 ,
SB_DT019X_CAPTURE_SW ,
} ;
static unsigned char als4000_saved_regs [ ] = {
2009-02-22 22:33:41 +03:00
/* please verify in dsheet whether regs to be added
are actually real H / W or just dummy */
2005-11-17 18:16:10 +03:00
SB_DSP4_MASTER_DEV , SB_DSP4_MASTER_DEV + 1 ,
SB_DSP4_OUTPUT_SW ,
SB_DSP4_PCM_DEV , SB_DSP4_PCM_DEV + 1 ,
SB_DSP4_INPUT_LEFT , SB_DSP4_INPUT_RIGHT ,
SB_DSP4_SYNTH_DEV , SB_DSP4_SYNTH_DEV + 1 ,
SB_DSP4_CD_DEV , SB_DSP4_CD_DEV + 1 ,
SB_DSP4_MIC_DEV ,
SB_DSP4_SPEAKER_DEV ,
SB_DSP4_IGAIN_DEV , SB_DSP4_IGAIN_DEV + 1 ,
SB_DSP4_OGAIN_DEV , SB_DSP4_OGAIN_DEV + 1 ,
SB_DT019X_OUTPUT_SW2 ,
SB_ALS4000_MONO_IO_CTRL ,
SB_ALS4000_MIC_IN_GAIN ,
2009-02-22 22:33:41 +03:00
SB_ALS4000_FMDAC ,
2005-11-17 18:16:10 +03:00
SB_ALS4000_3D_SND_FX ,
SB_ALS4000_3D_TIME_DELAY ,
2009-02-22 22:33:41 +03:00
SB_ALS4000_CR3_CONFIGURATION ,
2005-11-17 18:16:10 +03:00
} ;
static void save_mixer ( struct snd_sb * chip , unsigned char * regs , int num_regs )
{
unsigned char * val = chip - > saved_regs ;
2008-08-08 19:11:45 +04:00
if ( snd_BUG_ON ( num_regs > ARRAY_SIZE ( chip - > saved_regs ) ) )
return ;
2005-11-17 18:16:10 +03:00
for ( ; num_regs ; num_regs - - )
* val + + = snd_sbmixer_read ( chip , * regs + + ) ;
}
static void restore_mixer ( struct snd_sb * chip , unsigned char * regs , int num_regs )
{
unsigned char * val = chip - > saved_regs ;
2008-08-08 19:11:45 +04:00
if ( snd_BUG_ON ( num_regs > ARRAY_SIZE ( chip - > saved_regs ) ) )
return ;
2005-11-17 18:16:10 +03:00
for ( ; num_regs ; num_regs - - )
snd_sbmixer_write ( chip , * regs + + , * val + + ) ;
}
void snd_sbmixer_suspend ( struct snd_sb * chip )
{
switch ( chip - > hardware ) {
case SB_HW_20 :
case SB_HW_201 :
save_mixer ( chip , sb20_saved_regs , ARRAY_SIZE ( sb20_saved_regs ) ) ;
break ;
case SB_HW_PRO :
2009-12-20 21:01:50 +03:00
case SB_HW_JAZZ16 :
2005-11-17 18:16:10 +03:00
save_mixer ( chip , sbpro_saved_regs , ARRAY_SIZE ( sbpro_saved_regs ) ) ;
break ;
case SB_HW_16 :
case SB_HW_ALS100 :
2007-05-24 20:46:54 +04:00
case SB_HW_CS5530 :
2005-11-17 18:16:10 +03:00
save_mixer ( chip , sb16_saved_regs , ARRAY_SIZE ( sb16_saved_regs ) ) ;
break ;
case SB_HW_ALS4000 :
save_mixer ( chip , als4000_saved_regs , ARRAY_SIZE ( als4000_saved_regs ) ) ;
break ;
case SB_HW_DT019X :
save_mixer ( chip , dt019x_saved_regs , ARRAY_SIZE ( dt019x_saved_regs ) ) ;
break ;
default :
break ;
}
}
void snd_sbmixer_resume ( struct snd_sb * chip )
{
switch ( chip - > hardware ) {
case SB_HW_20 :
case SB_HW_201 :
restore_mixer ( chip , sb20_saved_regs , ARRAY_SIZE ( sb20_saved_regs ) ) ;
break ;
case SB_HW_PRO :
2009-12-20 21:01:50 +03:00
case SB_HW_JAZZ16 :
2005-11-17 18:16:10 +03:00
restore_mixer ( chip , sbpro_saved_regs , ARRAY_SIZE ( sbpro_saved_regs ) ) ;
break ;
case SB_HW_16 :
case SB_HW_ALS100 :
2007-05-24 20:46:54 +04:00
case SB_HW_CS5530 :
2005-11-17 18:16:10 +03:00
restore_mixer ( chip , sb16_saved_regs , ARRAY_SIZE ( sb16_saved_regs ) ) ;
break ;
case SB_HW_ALS4000 :
restore_mixer ( chip , als4000_saved_regs , ARRAY_SIZE ( als4000_saved_regs ) ) ;
break ;
case SB_HW_DT019X :
restore_mixer ( chip , dt019x_saved_regs , ARRAY_SIZE ( dt019x_saved_regs ) ) ;
break ;
default :
break ;
}
}
# endif