2005-04-16 15:20:36 -07:00
/*
* 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
*
*/
/*
* 2002 - 07 Benny Sjostrand benny @ hostmobility . com
*/
2015-01-28 16:49:33 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <linux/delay.h>
# include <linux/pm.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
2006-01-16 16:34:20 +01:00
# include <linux/mutex.h>
2005-04-16 15:20:36 -07:00
# include <sound/core.h>
# include <sound/control.h>
# include <sound/info.h>
# include <sound/asoundef.h>
2012-07-02 16:37:05 +02:00
# include "cs46xx.h"
2005-04-16 15:20:36 -07:00
# include "cs46xx_lib.h"
# include "dsp_spos.h"
2005-11-17 14:48:14 +01:00
static int cs46xx_dsp_async_init ( struct snd_cs46xx * chip ,
struct dsp_scb_descriptor * fg_entry ) ;
2005-04-16 15:20:36 -07:00
2005-11-17 14:48:14 +01:00
static enum wide_opcode wide_opcodes [ ] = {
2005-04-16 15:20:36 -07:00
WIDE_FOR_BEGIN_LOOP ,
WIDE_FOR_BEGIN_LOOP2 ,
WIDE_COND_GOTO_ADDR ,
WIDE_COND_GOTO_CALL ,
WIDE_TBEQ_COND_GOTO_ADDR ,
WIDE_TBEQ_COND_CALL_ADDR ,
WIDE_TBEQ_NCOND_GOTO_ADDR ,
WIDE_TBEQ_NCOND_CALL_ADDR ,
WIDE_TBEQ_COND_GOTO1_ADDR ,
WIDE_TBEQ_COND_CALL1_ADDR ,
WIDE_TBEQ_NCOND_GOTOI_ADDR ,
WIDE_TBEQ_NCOND_CALL1_ADDR
} ;
2005-11-17 14:48:14 +01:00
static int shadow_and_reallocate_code ( struct snd_cs46xx * chip , u32 * data , u32 size ,
u32 overlay_begin_address )
2005-04-16 15:20:36 -07:00
{
unsigned int i = 0 , j , nreallocated = 0 ;
u32 hival , loval , address ;
u32 mop_operands , mop_type , wide_op ;
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( size % 2 ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
while ( i < size ) {
loval = data [ i + + ] ;
hival = data [ i + + ] ;
if ( ins - > code . offset > 0 ) {
mop_operands = ( hival > > 6 ) & 0x03fff ;
mop_type = mop_operands > > 10 ;
/* check for wide type instruction */
if ( mop_type = = 0 & &
( mop_operands & WIDE_LADD_INSTR_MASK ) = = 0 & &
( mop_operands & WIDE_INSTR_MASK ) ! = 0 ) {
wide_op = loval & 0x7f ;
for ( j = 0 ; j < ARRAY_SIZE ( wide_opcodes ) ; + + j ) {
if ( wide_opcodes [ j ] = = wide_op ) {
/* need to reallocate instruction */
address = ( hival & 0x00FFF ) < < 5 ;
address | = loval > > 15 ;
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" handle_wideop[1]: %05x:%05x addr %04x \n " ,
hival , loval , address ) ;
2005-04-16 15:20:36 -07:00
if ( ! ( address & 0x8000 ) ) {
address + = ( ins - > code . offset / 2 ) - overlay_begin_address ;
} else {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" handle_wideop[1]: ROM symbol not reallocated \n " ) ;
2005-04-16 15:20:36 -07:00
}
hival & = 0xFF000 ;
loval & = 0x07FFF ;
hival | = ( ( address > > 5 ) & 0x00FFF ) ;
loval | = ( ( address < < 15 ) & 0xF8000 ) ;
address = ( hival & 0x00FFF ) < < 5 ;
address | = loval > > 15 ;
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" handle_wideop:[2] %05x:%05x addr %04x \n " ,
2016-12-07 14:22:50 +03:00
hival , loval , address ) ;
nreallocated + + ;
2005-04-16 15:20:36 -07:00
} /* wide_opcodes[j] == wide_op */
} /* for */
} /* mod_type == 0 ... */
} /* ins->code.offset > 0 */
ins - > code . data [ ins - > code . size + + ] = loval ;
ins - > code . data [ ins - > code . size + + ] = hival ;
}
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: %d instructions reallocated \n " , nreallocated ) ;
2005-04-16 15:20:36 -07:00
return nreallocated ;
}
2005-11-17 14:48:14 +01:00
static struct dsp_segment_desc * get_segment_desc ( struct dsp_module_desc * module , int seg_type )
2005-04-16 15:20:36 -07:00
{
int i ;
for ( i = 0 ; i < module - > nsegments ; + + i ) {
if ( module - > segments [ i ] . segment_type = = seg_type ) {
return ( module - > segments + i ) ;
}
}
return NULL ;
} ;
2005-11-17 14:48:14 +01:00
static int find_free_symbol_index ( struct dsp_spos_instance * ins )
2005-04-16 15:20:36 -07:00
{
int index = ins - > symbol_table . nsymbols , i ;
for ( i = ins - > symbol_table . highest_frag_index ; i < ins - > symbol_table . nsymbols ; + + i ) {
if ( ins - > symbol_table . symbols [ i ] . deleted ) {
index = i ;
break ;
}
}
return index ;
}
2005-11-17 14:48:14 +01:00
static int add_symbols ( struct snd_cs46xx * chip , struct dsp_module_desc * module )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
if ( module - > symbol_table . nsymbols > 0 ) {
if ( ! strcmp ( module - > symbol_table . symbols [ 0 ] . symbol_name , " OVERLAYBEGINADDRESS " ) & &
module - > symbol_table . symbols [ 0 ] . symbol_type = = SYMBOL_CONSTANT ) {
module - > overlay_begin_address = module - > symbol_table . symbols [ 0 ] . address ;
}
}
for ( i = 0 ; i < module - > symbol_table . nsymbols ; + + i ) {
if ( ins - > symbol_table . nsymbols = = ( DSP_MAX_SYMBOLS - 1 ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol table is full \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
if ( cs46xx_dsp_lookup_symbol ( chip ,
module - > symbol_table . symbols [ i ] . symbol_name ,
module - > symbol_table . symbols [ i ] . symbol_type ) = = NULL ) {
ins - > symbol_table . symbols [ ins - > symbol_table . nsymbols ] = module - > symbol_table . symbols [ i ] ;
ins - > symbol_table . symbols [ ins - > symbol_table . nsymbols ] . address + = ( ( ins - > code . offset / 2 ) - module - > overlay_begin_address ) ;
ins - > symbol_table . symbols [ ins - > symbol_table . nsymbols ] . module = module ;
ins - > symbol_table . symbols [ ins - > symbol_table . nsymbols ] . deleted = 0 ;
if ( ins - > symbol_table . nsymbols > ins - > symbol_table . highest_frag_index )
ins - > symbol_table . highest_frag_index = ins - > symbol_table . nsymbols ;
ins - > symbol_table . nsymbols + + ;
} else {
2014-02-25 16:36:51 +01:00
#if 0
dev_dbg ( chip - > card - > dev ,
" dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?) \n " ,
module - > symbol_table . symbols [ i ] . symbol_name ) ; */
# endif
2005-04-16 15:20:36 -07:00
}
}
return 0 ;
}
2005-11-17 14:48:14 +01:00
static struct dsp_symbol_entry *
add_symbol ( struct snd_cs46xx * chip , char * symbol_name , u32 address , int type )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_symbol_entry * symbol = NULL ;
2005-04-16 15:20:36 -07:00
int index ;
if ( ins - > symbol_table . nsymbols = = ( DSP_MAX_SYMBOLS - 1 ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev , " dsp_spos: symbol table is full \n " ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
if ( cs46xx_dsp_lookup_symbol ( chip ,
symbol_name ,
type ) ! = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol <%s> duplicated \n " , symbol_name ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
index = find_free_symbol_index ( ins ) ;
strcpy ( ins - > symbol_table . symbols [ index ] . symbol_name , symbol_name ) ;
ins - > symbol_table . symbols [ index ] . address = address ;
ins - > symbol_table . symbols [ index ] . symbol_type = type ;
ins - > symbol_table . symbols [ index ] . module = NULL ;
ins - > symbol_table . symbols [ index ] . deleted = 0 ;
symbol = ( ins - > symbol_table . symbols + index ) ;
if ( index > ins - > symbol_table . highest_frag_index )
ins - > symbol_table . highest_frag_index = index ;
if ( index = = ins - > symbol_table . nsymbols )
ins - > symbol_table . nsymbols + + ; /* no frag. in list */
return symbol ;
}
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * cs46xx_dsp_spos_create ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = kzalloc ( sizeof ( struct dsp_spos_instance ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
2010-10-29 22:54:45 +02:00
if ( ins = = NULL )
2005-04-16 15:20:36 -07:00
return NULL ;
/* better to use vmalloc for this big table */
2005-11-17 14:48:14 +01:00
ins - > symbol_table . symbols = vmalloc ( sizeof ( struct dsp_symbol_entry ) *
DSP_MAX_SYMBOLS ) ;
2010-10-29 22:54:45 +02:00
ins - > code . data = kmalloc ( DSP_CODE_BYTE_SIZE , GFP_KERNEL ) ;
ins - > modules = kmalloc ( sizeof ( struct dsp_module_desc ) * DSP_MAX_MODULES , GFP_KERNEL ) ;
if ( ! ins - > symbol_table . symbols | | ! ins - > code . data | | ! ins - > modules ) {
2005-04-16 15:20:36 -07:00
cs46xx_dsp_spos_destroy ( chip ) ;
2006-03-14 09:44:19 +01:00
goto error ;
2005-04-16 15:20:36 -07:00
}
2010-10-29 22:54:45 +02:00
ins - > symbol_table . nsymbols = 0 ;
ins - > symbol_table . highest_frag_index = 0 ;
2005-04-16 15:20:36 -07:00
ins - > code . offset = 0 ;
ins - > code . size = 0 ;
ins - > nscb = 0 ;
ins - > ntask = 0 ;
ins - > nmodules = 0 ;
/* default SPDIF input sample rate
to 48000 khz */
ins - > spdif_in_sample_rate = 48000 ;
/* maximize volume */
ins - > dac_volume_right = 0x8000 ;
ins - > dac_volume_left = 0x8000 ;
ins - > spdif_input_volume_right = 0x8000 ;
ins - > spdif_input_volume_left = 0x8000 ;
/* set left and right validity bits and
default channel status */
2010-10-29 22:54:45 +02:00
ins - > spdif_csuv_default =
ins - > spdif_csuv_stream =
2005-04-16 15:20:36 -07:00
/* byte 0 */ ( ( unsigned int ) _wrap_all_bits ( ( SNDRV_PCM_DEFAULT_CON_SPDIF & 0xff ) ) < < 24 ) |
/* byte 1 */ ( ( unsigned int ) _wrap_all_bits ( ( ( SNDRV_PCM_DEFAULT_CON_SPDIF > > 8 ) & 0xff ) ) < < 16 ) |
/* byte 3 */ ( unsigned int ) _wrap_all_bits ( ( SNDRV_PCM_DEFAULT_CON_SPDIF > > 24 ) & 0xff ) |
/* left and right validity bits */ ( 1 < < 13 ) | ( 1 < < 12 ) ;
return ins ;
2006-03-14 09:44:19 +01:00
error :
2010-10-29 22:54:45 +02:00
kfree ( ins - > modules ) ;
kfree ( ins - > code . data ) ;
vfree ( ins - > symbol_table . symbols ) ;
2006-03-14 09:44:19 +01:00
kfree ( ins ) ;
return NULL ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:48:14 +01:00
void cs46xx_dsp_spos_destroy ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! ins ) )
return ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < ins - > nscb ; + + i ) {
if ( ins - > scbs [ i ] . deleted ) continue ;
cs46xx_dsp_proc_free_scb_desc ( ( ins - > scbs + i ) ) ;
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2009-12-22 09:00:14 +01:00
kfree ( ins - > scbs [ i ] . data ) ;
# endif
2005-04-16 15:20:36 -07:00
}
kfree ( ins - > code . data ) ;
vfree ( ins - > symbol_table . symbols ) ;
kfree ( ins - > modules ) ;
kfree ( ins ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-19 11:23:21 +02:00
static int dsp_load_parameter ( struct snd_cs46xx * chip ,
struct dsp_segment_desc * parameter )
{
u32 doffset , dsize ;
if ( ! parameter ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: module got no parameter segment \n " ) ;
2007-07-19 11:23:21 +02:00
return 0 ;
}
doffset = ( parameter - > offset * 4 + DSP_PARAMETER_BYTE_OFFSET ) ;
dsize = parameter - > size * 4 ;
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: downloading parameter data to chip (%08x-%08x) \n " ,
2007-07-19 11:23:21 +02:00
doffset , doffset + dsize ) ;
if ( snd_cs46xx_download ( chip , parameter - > data , doffset , dsize ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: failed to download parameter data to DSP \n " ) ;
2007-07-19 11:23:21 +02:00
return - EINVAL ;
}
return 0 ;
}
static int dsp_load_sample ( struct snd_cs46xx * chip ,
struct dsp_segment_desc * sample )
{
u32 doffset , dsize ;
if ( ! sample ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: module got no sample segment \n " ) ;
2007-07-19 11:23:21 +02:00
return 0 ;
}
doffset = ( sample - > offset * 4 + DSP_SAMPLE_BYTE_OFFSET ) ;
dsize = sample - > size * 4 ;
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: downloading sample data to chip (%08x-%08x) \n " ,
2007-07-19 11:23:21 +02:00
doffset , doffset + dsize ) ;
if ( snd_cs46xx_download ( chip , sample - > data , doffset , dsize ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: failed to sample data to DSP \n " ) ;
2007-07-19 11:23:21 +02:00
return - EINVAL ;
}
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_load_module ( struct snd_cs46xx * chip , struct dsp_module_desc * module )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_segment_desc * code = get_segment_desc ( module , SEGTYPE_SP_PROGRAM ) ;
2005-04-16 15:20:36 -07:00
u32 doffset , dsize ;
2007-07-19 11:23:21 +02:00
int err ;
2005-04-16 15:20:36 -07:00
if ( ins - > nmodules = = DSP_MAX_MODULES - 1 ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: to many modules loaded into DSP \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: loading module %s into DSP \n " , module - > module_name ) ;
2005-04-16 15:20:36 -07:00
if ( ins - > nmodules = = 0 ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev , " dsp_spos: clearing parameter area \n " ) ;
2005-04-16 15:20:36 -07:00
snd_cs46xx_clear_BA1 ( chip , DSP_PARAMETER_BYTE_OFFSET , DSP_PARAMETER_BYTE_SIZE ) ;
}
2007-07-19 11:23:21 +02:00
err = dsp_load_parameter ( chip , get_segment_desc ( module ,
SEGTYPE_SP_PARAMETER ) ) ;
if ( err < 0 )
return err ;
2005-04-16 15:20:36 -07:00
if ( ins - > nmodules = = 0 ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev , " dsp_spos: clearing sample area \n " ) ;
2005-04-16 15:20:36 -07:00
snd_cs46xx_clear_BA1 ( chip , DSP_SAMPLE_BYTE_OFFSET , DSP_SAMPLE_BYTE_SIZE ) ;
}
2007-07-19 11:23:21 +02:00
err = dsp_load_sample ( chip , get_segment_desc ( module ,
SEGTYPE_SP_SAMPLE ) ) ;
if ( err < 0 )
return err ;
2005-04-16 15:20:36 -07:00
if ( ins - > nmodules = = 0 ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev , " dsp_spos: clearing code area \n " ) ;
2005-04-16 15:20:36 -07:00
snd_cs46xx_clear_BA1 ( chip , DSP_CODE_BYTE_OFFSET , DSP_CODE_BYTE_SIZE ) ;
}
if ( code = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: module got no code segment \n " ) ;
2005-04-16 15:20:36 -07:00
} else {
if ( ins - > code . offset + code - > size > DSP_CODE_BYTE_SIZE ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: no space available in DSP \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
module - > load_address = ins - > code . offset ;
module - > overlay_begin_address = 0x000 ;
/* if module has a code segment it must have
symbol table */
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! module - > symbol_table . symbols ) )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
if ( add_symbols ( chip , module ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: failed to load symbol table \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
doffset = ( code - > offset * 4 + ins - > code . offset * 4 + DSP_CODE_BYTE_OFFSET ) ;
dsize = code - > size * 4 ;
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev ,
" dsp_spos: downloading code to chip (%08x-%08x) \n " ,
2005-04-16 15:20:36 -07:00
doffset , doffset + dsize ) ;
module - > nfixups = shadow_and_reallocate_code ( chip , code - > data , code - > size , module - > overlay_begin_address ) ;
if ( snd_cs46xx_download ( chip , ( ins - > code . data + ins - > code . offset ) , doffset , dsize ) ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: failed to download code to DSP \n " ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
ins - > code . offset + = code - > size ;
}
/* NOTE: module segments and symbol table must be
statically allocated . Case that module data is
not generated by the ospparser */
ins - > modules [ ins - > nmodules ] = * module ;
ins - > nmodules + + ;
return 0 ;
}
2005-11-17 14:48:14 +01:00
struct dsp_symbol_entry *
cs46xx_dsp_lookup_symbol ( struct snd_cs46xx * chip , char * symbol_name , int symbol_type )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < ins - > symbol_table . nsymbols ; + + i ) {
if ( ins - > symbol_table . symbols [ i ] . deleted )
continue ;
if ( ! strcmp ( ins - > symbol_table . symbols [ i ] . symbol_name , symbol_name ) & &
ins - > symbol_table . symbols [ i ] . symbol_type = = symbol_type ) {
return ( ins - > symbol_table . symbols + i ) ;
}
}
#if 0
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev , " dsp_spos: symbol <%s> type %02x not found \n " ,
2005-04-16 15:20:36 -07:00
symbol_name , symbol_type ) ;
# endif
return NULL ;
}
2015-05-29 07:55:37 +02:00
# ifdef CONFIG_SND_PROC_FS
2005-11-17 14:48:14 +01:00
static struct dsp_symbol_entry *
cs46xx_dsp_lookup_symbol_addr ( struct snd_cs46xx * chip , u32 address , int symbol_type )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < ins - > symbol_table . nsymbols ; + + i ) {
if ( ins - > symbol_table . symbols [ i ] . deleted )
continue ;
if ( ins - > symbol_table . symbols [ i ] . address = = address & &
ins - > symbol_table . symbols [ i ] . symbol_type = = symbol_type ) {
return ( ins - > symbol_table . symbols + i ) ;
}
}
return NULL ;
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_symbol_table_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
int i ;
snd_iprintf ( buffer , " SYMBOLS: \n " ) ;
for ( i = 0 ; i < ins - > symbol_table . nsymbols ; + + i ) {
char * module_str = " system " ;
if ( ins - > symbol_table . symbols [ i ] . deleted )
continue ;
if ( ins - > symbol_table . symbols [ i ] . module ! = NULL ) {
module_str = ins - > symbol_table . symbols [ i ] . module - > module_name ;
}
snd_iprintf ( buffer , " %04X <%02X> %s [%s] \n " ,
ins - > symbol_table . symbols [ i ] . address ,
ins - > symbol_table . symbols [ i ] . symbol_type ,
ins - > symbol_table . symbols [ i ] . symbol_name ,
module_str ) ;
}
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_modules_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
int i , j ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
snd_iprintf ( buffer , " MODULES: \n " ) ;
for ( i = 0 ; i < ins - > nmodules ; + + i ) {
snd_iprintf ( buffer , " \n %s: \n " , ins - > modules [ i ] . module_name ) ;
snd_iprintf ( buffer , " %d symbols \n " , ins - > modules [ i ] . symbol_table . nsymbols ) ;
snd_iprintf ( buffer , " %d fixups \n " , ins - > modules [ i ] . nfixups ) ;
for ( j = 0 ; j < ins - > modules [ i ] . nsegments ; + + j ) {
2005-11-17 14:48:14 +01:00
struct dsp_segment_desc * desc = ( ins - > modules [ i ] . segments + j ) ;
2005-04-16 15:20:36 -07:00
snd_iprintf ( buffer , " segment %02x offset %08x size %08x \n " ,
desc - > segment_type , desc - > offset , desc - > size ) ;
}
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_task_tree_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
int i , j , col ;
2005-04-16 15:20:36 -07:00
void __iomem * dst = chip - > region . idx [ 1 ] . remap_addr + DSP_PARAMETER_BYTE_OFFSET ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
snd_iprintf ( buffer , " TASK TREES: \n " ) ;
for ( i = 0 ; i < ins - > ntask ; + + i ) {
snd_iprintf ( buffer , " \n %04x %s: \n " , ins - > tasks [ i ] . address , ins - > tasks [ i ] . task_name ) ;
for ( col = 0 , j = 0 ; j < ins - > tasks [ i ] . size ; j + + , col + + ) {
u32 val ;
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
val = readl ( dst + ( ins - > tasks [ i ] . address + j ) * sizeof ( u32 ) ) ;
snd_iprintf ( buffer , " %08x " , val ) ;
}
}
snd_iprintf ( buffer , " \n " ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_scb_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
int i ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
snd_iprintf ( buffer , " SCB's: \n " ) ;
for ( i = 0 ; i < ins - > nscb ; + + i ) {
if ( ins - > scbs [ i ] . deleted )
continue ;
snd_iprintf ( buffer , " \n %04x %s: \n \n " , ins - > scbs [ i ] . address , ins - > scbs [ i ] . scb_name ) ;
if ( ins - > scbs [ i ] . parent_scb_ptr ! = NULL ) {
snd_iprintf ( buffer , " parent [%s:%04x] " ,
ins - > scbs [ i ] . parent_scb_ptr - > scb_name ,
ins - > scbs [ i ] . parent_scb_ptr - > address ) ;
} else snd_iprintf ( buffer , " parent [none] " ) ;
snd_iprintf ( buffer , " sub_list_ptr [%s:%04x] \n next_scb_ptr [%s:%04x] task_entry [%s:%04x] \n " ,
ins - > scbs [ i ] . sub_list_ptr - > scb_name ,
ins - > scbs [ i ] . sub_list_ptr - > address ,
ins - > scbs [ i ] . next_scb_ptr - > scb_name ,
ins - > scbs [ i ] . next_scb_ptr - > address ,
ins - > scbs [ i ] . task_entry - > symbol_name ,
ins - > scbs [ i ] . task_entry - > address ) ;
}
snd_iprintf ( buffer , " \n " ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_parameter_dump_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
/*struct dsp_spos_instance * ins = chip->dsp_spos_instance; */
unsigned int i , col = 0 ;
2005-04-16 15:20:36 -07:00
void __iomem * dst = chip - > region . idx [ 1 ] . remap_addr + DSP_PARAMETER_BYTE_OFFSET ;
2005-11-17 14:48:14 +01:00
struct dsp_symbol_entry * symbol ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < DSP_PARAMETER_BYTE_SIZE ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( ( symbol = cs46xx_dsp_lookup_symbol_addr ( chip , i / sizeof ( u32 ) , SYMBOL_PARAMETER ) ) ! = NULL ) {
col = 0 ;
snd_iprintf ( buffer , " \n %s: \n " , symbol - > symbol_name ) ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i / ( unsigned int ) sizeof ( u32 ) ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_proc_sample_dump_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_cs46xx * chip = entry - > private_data ;
2005-04-16 15:20:36 -07:00
int i , col = 0 ;
void __iomem * dst = chip - > region . idx [ 2 ] . remap_addr ;
snd_iprintf ( buffer , " PCMREADER: \n " ) ;
for ( i = PCM_READER_BUF1 ; i < PCM_READER_BUF1 + 0x30 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n MIX_SAMPLE_BUF1: \n " ) ;
col = 0 ;
for ( i = MIX_SAMPLE_BUF1 ; i < MIX_SAMPLE_BUF1 + 0x40 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n SRC_TASK_SCB1: \n " ) ;
col = 0 ;
for ( i = 0x2480 ; i < 0x2480 + 0x40 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n SPDIFO_BUFFER: \n " ) ;
col = 0 ;
for ( i = SPDIFO_IP_OUTPUT_BUFFER1 ; i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n ... \n " ) ;
col = 0 ;
for ( i = SPDIFO_IP_OUTPUT_BUFFER1 + 0xD0 ; i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n OUTPUT_SNOOP: \n " ) ;
col = 0 ;
for ( i = OUTPUT_SNOOP_BUFFER ; i < OUTPUT_SNOOP_BUFFER + 0x40 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n CODEC_INPUT_BUF1: \n " ) ;
col = 0 ;
for ( i = CODEC_INPUT_BUF1 ; i < CODEC_INPUT_BUF1 + 0x40 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
#if 0
snd_iprintf ( buffer , " \n WRITE_BACK_BUF1: \n " ) ;
col = 0 ;
for ( i = WRITE_BACK_BUF1 ; i < WRITE_BACK_BUF1 + 0x40 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
# endif
snd_iprintf ( buffer , " \n SPDIFI_IP_OUTPUT_BUFFER1: \n " ) ;
col = 0 ;
for ( i = SPDIFI_IP_OUTPUT_BUFFER1 ; i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80 ; i + = sizeof ( u32 ) , col + + ) {
if ( col = = 4 ) {
snd_iprintf ( buffer , " \n " ) ;
col = 0 ;
}
if ( col = = 0 ) {
snd_iprintf ( buffer , " %04X " , i ) ;
}
snd_iprintf ( buffer , " %08X " , readl ( dst + i ) ) ;
}
snd_iprintf ( buffer , " \n " ) ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_proc_init ( struct snd_card * card , struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct snd_info_entry * entry ;
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
int i ;
ins - > snd_card = card ;
if ( ( entry = snd_info_create_card_entry ( card , " dsp " , card - > proc_root ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > mode = S_IFDIR | S_IRUGO | S_IXUGO ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_dsp_dir = entry ;
if ( ! ins - > proc_dsp_dir )
return - ENOMEM ;
if ( ( entry = snd_info_create_card_entry ( card , " spos_symbols " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_symbol_table_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_sym_info_entry = entry ;
if ( ( entry = snd_info_create_card_entry ( card , " spos_modules " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_modules_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_modules_info_entry = entry ;
if ( ( entry = snd_info_create_card_entry ( card , " parameter " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_parameter_dump_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_parameter_dump_info_entry = entry ;
if ( ( entry = snd_info_create_card_entry ( card , " sample " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_sample_dump_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_sample_dump_info_entry = entry ;
if ( ( entry = snd_info_create_card_entry ( card , " task_tree " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_task_tree_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_task_info_entry = entry ;
if ( ( entry = snd_info_create_card_entry ( card , " scb_info " , ins - > proc_dsp_dir ) ) ! = NULL ) {
entry - > content = SNDRV_INFO_CONTENT_TEXT ;
entry - > private_data = chip ;
entry - > mode = S_IFREG | S_IRUGO | S_IWUSR ;
entry - > c . text . read = cs46xx_dsp_proc_scb_read ;
if ( snd_info_register ( entry ) < 0 ) {
snd_info_free_entry ( entry ) ;
entry = NULL ;
}
}
ins - > proc_scb_info_entry = entry ;
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
/* register/update SCB's entries on proc */
for ( i = 0 ; i < ins - > nscb ; + + i ) {
if ( ins - > scbs [ i ] . deleted ) continue ;
cs46xx_dsp_proc_register_scb_desc ( chip , ( ins - > scbs + i ) ) ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_proc_done ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
int i ;
2006-06-23 14:37:59 +02:00
snd_info_free_entry ( ins - > proc_sym_info_entry ) ;
ins - > proc_sym_info_entry = NULL ;
snd_info_free_entry ( ins - > proc_modules_info_entry ) ;
ins - > proc_modules_info_entry = NULL ;
snd_info_free_entry ( ins - > proc_parameter_dump_info_entry ) ;
ins - > proc_parameter_dump_info_entry = NULL ;
snd_info_free_entry ( ins - > proc_sample_dump_info_entry ) ;
ins - > proc_sample_dump_info_entry = NULL ;
snd_info_free_entry ( ins - > proc_scb_info_entry ) ;
ins - > proc_scb_info_entry = NULL ;
snd_info_free_entry ( ins - > proc_task_info_entry ) ;
ins - > proc_task_info_entry = NULL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < ins - > nscb ; + + i ) {
if ( ins - > scbs [ i ] . deleted ) continue ;
cs46xx_dsp_proc_free_scb_desc ( ( ins - > scbs + i ) ) ;
}
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
2006-06-23 14:37:59 +02:00
snd_info_free_entry ( ins - > proc_dsp_dir ) ;
ins - > proc_dsp_dir = NULL ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2015-05-29 07:55:37 +02:00
# endif /* CONFIG_SND_PROC_FS */
2005-04-16 15:20:36 -07:00
2005-11-17 14:48:14 +01:00
static void _dsp_create_task_tree ( struct snd_cs46xx * chip , u32 * task_data ,
u32 dest , int size )
2005-04-16 15:20:36 -07:00
{
void __iomem * spdst = chip - > region . idx [ 1 ] . remap_addr +
DSP_PARAMETER_BYTE_OFFSET + dest * sizeof ( u32 ) ;
int i ;
for ( i = 0 ; i < size ; + + i ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev , " addr %p, val %08x \n " ,
spdst , task_data [ i ] ) ;
2005-04-16 15:20:36 -07:00
writel ( task_data [ i ] , spdst ) ;
spdst + = sizeof ( u32 ) ;
}
}
2005-11-17 14:48:14 +01:00
static void _dsp_create_scb ( struct snd_cs46xx * chip , u32 * scb_data , u32 dest )
2005-04-16 15:20:36 -07:00
{
void __iomem * spdst = chip - > region . idx [ 1 ] . remap_addr +
DSP_PARAMETER_BYTE_OFFSET + dest * sizeof ( u32 ) ;
int i ;
for ( i = 0 ; i < 0x10 ; + + i ) {
2014-02-25 16:36:51 +01:00
dev_dbg ( chip - > card - > dev , " addr %p, val %08x \n " ,
spdst , scb_data [ i ] ) ;
2005-04-16 15:20:36 -07:00
writel ( scb_data [ i ] , spdst ) ;
spdst + = sizeof ( u32 ) ;
}
}
2005-11-17 14:48:14 +01:00
static int find_free_scb_index ( struct dsp_spos_instance * ins )
2005-04-16 15:20:36 -07:00
{
int index = ins - > nscb , i ;
for ( i = ins - > scb_highest_frag_index ; i < ins - > nscb ; + + i ) {
if ( ins - > scbs [ i ] . deleted ) {
index = i ;
break ;
}
}
return index ;
}
2005-11-17 14:48:14 +01:00
static struct dsp_scb_descriptor * _map_scb ( struct snd_cs46xx * chip , char * name , u32 dest )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_scb_descriptor * desc = NULL ;
2005-04-16 15:20:36 -07:00
int index ;
if ( ins - > nscb = = DSP_MAX_SCB_DESC - 1 ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: got no place for other SCB \n " ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
index = find_free_scb_index ( ins ) ;
2009-12-22 09:00:14 +01:00
memset ( & ins - > scbs [ index ] , 0 , sizeof ( ins - > scbs [ index ] ) ) ;
2005-04-16 15:20:36 -07:00
strcpy ( ins - > scbs [ index ] . scb_name , name ) ;
ins - > scbs [ index ] . address = dest ;
ins - > scbs [ index ] . index = index ;
ins - > scbs [ index ] . ref_count = 1 ;
desc = ( ins - > scbs + index ) ;
ins - > scbs [ index ] . scb_symbol = add_symbol ( chip , name , dest , SYMBOL_PARAMETER ) ;
if ( index > ins - > scb_highest_frag_index )
ins - > scb_highest_frag_index = index ;
if ( index = = ins - > nscb )
ins - > nscb + + ;
return desc ;
}
2005-11-17 14:48:14 +01:00
static struct dsp_task_descriptor *
_map_task_tree ( struct snd_cs46xx * chip , char * name , u32 dest , u32 size )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_task_descriptor * desc = NULL ;
2005-04-16 15:20:36 -07:00
if ( ins - > ntask = = DSP_MAX_TASK_DESC - 1 ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: got no place for other TASK \n " ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
2007-07-19 11:23:21 +02:00
if ( name )
strcpy ( ins - > tasks [ ins - > ntask ] . task_name , name ) ;
else
strcpy ( ins - > tasks [ ins - > ntask ] . task_name , " (NULL) " ) ;
2005-04-16 15:20:36 -07:00
ins - > tasks [ ins - > ntask ] . address = dest ;
ins - > tasks [ ins - > ntask ] . size = size ;
/* quick find in list */
ins - > tasks [ ins - > ntask ] . index = ins - > ntask ;
desc = ( ins - > tasks + ins - > ntask ) ;
ins - > ntask + + ;
2007-07-19 11:23:21 +02:00
if ( name )
add_symbol ( chip , name , dest , SYMBOL_PARAMETER ) ;
2005-04-16 15:20:36 -07:00
return desc ;
}
2009-12-22 09:00:14 +01:00
# define SCB_BYTES (0x10 * 4)
2005-11-17 14:48:14 +01:00
struct dsp_scb_descriptor *
cs46xx_dsp_create_scb ( struct snd_cs46xx * chip , char * name , u32 * scb_data , u32 dest )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_scb_descriptor * desc ;
2005-04-16 15:20:36 -07:00
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2009-12-22 09:00:14 +01:00
/* copy the data for resume */
scb_data = kmemdup ( scb_data , SCB_BYTES , GFP_KERNEL ) ;
if ( ! scb_data )
return NULL ;
# endif
2005-04-16 15:20:36 -07:00
desc = _map_scb ( chip , name , dest ) ;
if ( desc ) {
2007-07-19 11:23:21 +02:00
desc - > data = scb_data ;
2005-04-16 15:20:36 -07:00
_dsp_create_scb ( chip , scb_data , dest ) ;
} else {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev , " dsp_spos: failed to map SCB \n " ) ;
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2009-12-22 09:00:14 +01:00
kfree ( scb_data ) ;
# endif
2005-04-16 15:20:36 -07:00
}
return desc ;
}
2005-11-17 14:48:14 +01:00
static struct dsp_task_descriptor *
cs46xx_dsp_create_task_tree ( struct snd_cs46xx * chip , char * name , u32 * task_data ,
u32 dest , int size )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_task_descriptor * desc ;
2005-04-16 15:20:36 -07:00
desc = _map_task_tree ( chip , name , dest , size ) ;
if ( desc ) {
2007-07-19 11:23:21 +02:00
desc - > data = task_data ;
2005-04-16 15:20:36 -07:00
_dsp_create_task_tree ( chip , task_data , dest , size ) ;
} else {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev , " dsp_spos: failed to map TASK \n " ) ;
2005-04-16 15:20:36 -07:00
}
return desc ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_scb_and_task_init ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_symbol_entry * fg_task_tree_header_code ;
struct dsp_symbol_entry * task_tree_header_code ;
struct dsp_symbol_entry * task_tree_thread ;
struct dsp_symbol_entry * null_algorithm ;
struct dsp_symbol_entry * magic_snoop_task ;
struct dsp_scb_descriptor * timing_master_scb ;
struct dsp_scb_descriptor * codec_out_scb ;
struct dsp_scb_descriptor * codec_in_scb ;
struct dsp_scb_descriptor * src_task_scb ;
struct dsp_scb_descriptor * master_mix_scb ;
struct dsp_scb_descriptor * rear_mix_scb ;
struct dsp_scb_descriptor * record_mix_scb ;
struct dsp_scb_descriptor * write_back_scb ;
struct dsp_scb_descriptor * vari_decimate_scb ;
struct dsp_scb_descriptor * rear_codec_out_scb ;
struct dsp_scb_descriptor * clfe_codec_out_scb ;
struct dsp_scb_descriptor * magic_snoop_scb ;
2005-04-16 15:20:36 -07:00
2005-11-17 14:48:14 +01:00
int fifo_addr , fifo_span , valid_slots ;
2005-04-16 15:20:36 -07:00
2005-11-17 14:48:14 +01:00
static struct dsp_spos_control_block sposcb = {
2005-04-16 15:20:36 -07:00
/* 0 */ HFG_TREE_SCB , HFG_STACK ,
/* 1 */ SPOSCB_ADDR , BG_TREE_SCB_ADDR ,
/* 2 */ DSP_SPOS_DC , 0 ,
/* 3 */ DSP_SPOS_DC , DSP_SPOS_DC ,
/* 4 */ 0 , 0 ,
/* 5 */ DSP_SPOS_UU , 0 ,
/* 6 */ FG_TASK_HEADER_ADDR , 0 ,
/* 7 */ 0 , 0 ,
/* 8 */ DSP_SPOS_UU , DSP_SPOS_DC ,
/* 9 */ 0 ,
/* A */ 0 , HFG_FIRST_EXECUTE_MODE ,
/* B */ DSP_SPOS_UU , DSP_SPOS_UU ,
/* C */ DSP_SPOS_DC_DC ,
/* D */ DSP_SPOS_DC_DC ,
/* E */ DSP_SPOS_DC_DC ,
/* F */ DSP_SPOS_DC_DC
} ;
cs46xx_dsp_create_task_tree ( chip , " sposCB " , ( u32 * ) & sposcb , SPOSCB_ADDR , 0x10 ) ;
null_algorithm = cs46xx_dsp_lookup_symbol ( chip , " NULLALGORITHM " , SYMBOL_CODE ) ;
if ( null_algorithm = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol NULLALGORITHM not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
fg_task_tree_header_code = cs46xx_dsp_lookup_symbol ( chip , " FGTASKTREEHEADERCODE " , SYMBOL_CODE ) ;
if ( fg_task_tree_header_code = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol FGTASKTREEHEADERCODE not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
task_tree_header_code = cs46xx_dsp_lookup_symbol ( chip , " TASKTREEHEADERCODE " , SYMBOL_CODE ) ;
if ( task_tree_header_code = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol TASKTREEHEADERCODE not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
task_tree_thread = cs46xx_dsp_lookup_symbol ( chip , " TASKTREETHREAD " , SYMBOL_CODE ) ;
if ( task_tree_thread = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol TASKTREETHREAD not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
magic_snoop_task = cs46xx_dsp_lookup_symbol ( chip , " MAGICSNOOPTASK " , SYMBOL_CODE ) ;
if ( magic_snoop_task = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol MAGICSNOOPTASK not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
{
/* create the null SCB */
2005-11-17 14:48:14 +01:00
static struct dsp_generic_scb null_scb = {
2005-04-16 15:20:36 -07:00
{ 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 } ,
NULL_SCB_ADDR , NULL_SCB_ADDR ,
0 , 0 , 0 , 0 , 0 ,
{
0 , 0 ,
0 , 0 ,
}
} ;
null_scb . entry_point = null_algorithm - > address ;
ins - > the_null_scb = cs46xx_dsp_create_scb ( chip , " nullSCB " , ( u32 * ) & null_scb , NULL_SCB_ADDR ) ;
ins - > the_null_scb - > task_entry = null_algorithm ;
ins - > the_null_scb - > sub_list_ptr = ins - > the_null_scb ;
ins - > the_null_scb - > next_scb_ptr = ins - > the_null_scb ;
ins - > the_null_scb - > parent_scb_ptr = NULL ;
cs46xx_dsp_proc_register_scb_desc ( chip , ins - > the_null_scb ) ;
}
{
/* setup foreground task tree */
2005-11-17 14:48:14 +01:00
static struct dsp_task_tree_control_block fg_task_tree_hdr = {
2005-04-16 15:20:36 -07:00
{ FG_TASK_HEADER_ADDR | ( DSP_SPOS_DC < < 0x10 ) ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
0x0000 , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC , DSP_SPOS_DC } ,
{
BG_TREE_SCB_ADDR , TIMINGMASTER_SCB_ADDR ,
0 ,
FG_TASK_HEADER_ADDR + TCBData ,
} ,
{
4 , 0 ,
1 , 0 ,
2 , SPOSCB_ADDR + HFGFlags ,
0 , 0 ,
FG_TASK_HEADER_ADDR + TCBContextBlk , FG_STACK
} ,
{
DSP_SPOS_DC , 0 ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DCDC ,
DSP_SPOS_UU , 1 ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC
} ,
{
FG_INTERVAL_TIMER_PERIOD , DSP_SPOS_UU ,
0 , 0
}
} ;
fg_task_tree_hdr . links . entry_point = fg_task_tree_header_code - > address ;
fg_task_tree_hdr . context_blk . stack0 = task_tree_thread - > address ;
cs46xx_dsp_create_task_tree ( chip , " FGtaskTreeHdr " , ( u32 * ) & fg_task_tree_hdr , FG_TASK_HEADER_ADDR , 0x35 ) ;
}
{
/* setup foreground task tree */
2005-11-17 14:48:14 +01:00
static struct dsp_task_tree_control_block bg_task_tree_hdr = {
2005-04-16 15:20:36 -07:00
{ DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC_DC ,
DSP_SPOS_DC , DSP_SPOS_DC } ,
{
NULL_SCB_ADDR , NULL_SCB_ADDR , /* Set up the background to do nothing */
0 ,
BG_TREE_SCB_ADDR + TCBData ,
} ,
{
9999 , 0 ,
0 , 1 ,
0 , SPOSCB_ADDR + HFGFlags ,
0 , 0 ,
BG_TREE_SCB_ADDR + TCBContextBlk , BG_STACK
} ,
{
DSP_SPOS_DC , 0 ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DC , DSP_SPOS_DC ,
DSP_SPOS_DCDC ,
DSP_SPOS_UU , 1 ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC ,
DSP_SPOS_DCDC
} ,
{
BG_INTERVAL_TIMER_PERIOD , DSP_SPOS_UU ,
0 , 0
}
} ;
bg_task_tree_hdr . links . entry_point = task_tree_header_code - > address ;
bg_task_tree_hdr . context_blk . stack0 = task_tree_thread - > address ;
cs46xx_dsp_create_task_tree ( chip , " BGtaskTreeHdr " , ( u32 * ) & bg_task_tree_hdr , BG_TREE_SCB_ADDR , 0x35 ) ;
}
/* create timing master SCB */
timing_master_scb = cs46xx_dsp_create_timing_master_scb ( chip ) ;
/* create the CODEC output task */
codec_out_scb = cs46xx_dsp_create_codec_out_scb ( chip , " CodecOutSCB_I " , 0x0010 , 0x0000 ,
MASTERMIX_SCB_ADDR ,
CODECOUT_SCB_ADDR , timing_master_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
if ( ! codec_out_scb ) goto _fail_end ;
/* create the master mix SCB */
master_mix_scb = cs46xx_dsp_create_mix_only_scb ( chip , " MasterMixSCB " ,
MIX_SAMPLE_BUF1 , MASTERMIX_SCB_ADDR ,
codec_out_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
ins - > master_mix_scb = master_mix_scb ;
if ( ! master_mix_scb ) goto _fail_end ;
/* create codec in */
codec_in_scb = cs46xx_dsp_create_codec_in_scb ( chip , " CodecInSCB " , 0x0010 , 0x00A0 ,
CODEC_INPUT_BUF1 ,
CODECIN_SCB_ADDR , codec_out_scb ,
SCB_ON_PARENT_NEXT_SCB ) ;
if ( ! codec_in_scb ) goto _fail_end ;
ins - > codec_in_scb = codec_in_scb ;
/* create write back scb */
write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb ( chip , " WriteBackSCB " ,
WRITE_BACK_BUF1 , WRITE_BACK_SPB ,
WRITEBACK_SCB_ADDR ,
timing_master_scb ,
SCB_ON_PARENT_NEXT_SCB ) ;
if ( ! write_back_scb ) goto _fail_end ;
{
2005-11-17 14:48:14 +01:00
static struct dsp_mix2_ostream_spb mix2_ostream_spb = {
2005-04-16 15:20:36 -07:00
0x00020000 ,
0x0000ffff
} ;
2007-07-19 11:23:21 +02:00
if ( ! cs46xx_dsp_create_task_tree ( chip , NULL ,
( u32 * ) & mix2_ostream_spb ,
WRITE_BACK_SPB , 2 ) )
goto _fail_end ;
2005-04-16 15:20:36 -07:00
}
/* input sample converter */
vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb ( chip , " VariDecimateSCB " ,
VARI_DECIMATE_BUF0 ,
VARI_DECIMATE_BUF1 ,
VARIDECIMATE_SCB_ADDR ,
write_back_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
if ( ! vari_decimate_scb ) goto _fail_end ;
/* create the record mixer SCB */
record_mix_scb = cs46xx_dsp_create_mix_only_scb ( chip , " RecordMixerSCB " ,
MIX_SAMPLE_BUF2 ,
RECORD_MIXER_SCB_ADDR ,
vari_decimate_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
ins - > record_mixer_scb = record_mix_scb ;
if ( ! record_mix_scb ) goto _fail_end ;
valid_slots = snd_cs46xx_peekBA0 ( chip , BA0_ACOSV ) ;
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( chip - > nr_ac97_codecs ! = 1 & & chip - > nr_ac97_codecs ! = 2 ) )
goto _fail_end ;
2005-04-16 15:20:36 -07:00
if ( chip - > nr_ac97_codecs = = 1 ) {
/* output on slot 5 and 11
on primary CODEC */
fifo_addr = 0x20 ;
fifo_span = 0x60 ;
/* enable slot 5 and 11 */
valid_slots | = ACOSV_SLV5 | ACOSV_SLV11 ;
} else {
/* output on slot 7 and 8
on secondary CODEC */
fifo_addr = 0x40 ;
fifo_span = 0x10 ;
/* enable slot 7 and 8 */
valid_slots | = ACOSV_SLV7 | ACOSV_SLV8 ;
}
/* create CODEC tasklet for rear speakers output*/
rear_codec_out_scb = cs46xx_dsp_create_codec_out_scb ( chip , " CodecOutSCB_Rear " , fifo_span , fifo_addr ,
REAR_MIXER_SCB_ADDR ,
REAR_CODECOUT_SCB_ADDR , codec_in_scb ,
SCB_ON_PARENT_NEXT_SCB ) ;
if ( ! rear_codec_out_scb ) goto _fail_end ;
/* create the rear PCM channel mixer SCB */
rear_mix_scb = cs46xx_dsp_create_mix_only_scb ( chip , " RearMixerSCB " ,
MIX_SAMPLE_BUF3 ,
REAR_MIXER_SCB_ADDR ,
rear_codec_out_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
ins - > rear_mix_scb = rear_mix_scb ;
if ( ! rear_mix_scb ) goto _fail_end ;
if ( chip - > nr_ac97_codecs = = 2 ) {
/* create CODEC tasklet for rear Center/LFE output
2016-09-01 11:15:44 +01:00
slot 6 and 9 on secondary CODEC */
2005-04-16 15:20:36 -07:00
clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb ( chip , " CodecOutSCB_CLFE " , 0x0030 , 0x0030 ,
CLFE_MIXER_SCB_ADDR ,
CLFE_CODEC_SCB_ADDR ,
rear_codec_out_scb ,
SCB_ON_PARENT_NEXT_SCB ) ;
if ( ! clfe_codec_out_scb ) goto _fail_end ;
/* create the rear PCM channel mixer SCB */
ins - > center_lfe_mix_scb = cs46xx_dsp_create_mix_only_scb ( chip , " CLFEMixerSCB " ,
MIX_SAMPLE_BUF4 ,
CLFE_MIXER_SCB_ADDR ,
clfe_codec_out_scb ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
if ( ! ins - > center_lfe_mix_scb ) goto _fail_end ;
/* enable slot 6 and 9 */
valid_slots | = ACOSV_SLV6 | ACOSV_SLV9 ;
} else {
clfe_codec_out_scb = rear_codec_out_scb ;
ins - > center_lfe_mix_scb = rear_mix_scb ;
}
/* enable slots depending on CODEC configuration */
snd_cs46xx_pokeBA0 ( chip , BA0_ACOSV , valid_slots ) ;
/* the magic snooper */
magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb ( chip , " MagicSnoopSCB_I " , OUTPUTSNOOP_SCB_ADDR ,
OUTPUT_SNOOP_BUFFER ,
codec_out_scb ,
clfe_codec_out_scb ,
SCB_ON_PARENT_NEXT_SCB ) ;
if ( ! magic_snoop_scb ) goto _fail_end ;
ins - > ref_snoop_scb = magic_snoop_scb ;
/* SP IO access */
if ( ! cs46xx_dsp_create_spio_write_scb ( chip , " SPIOWriteSCB " , SPIOWRITE_SCB_ADDR ,
magic_snoop_scb ,
SCB_ON_PARENT_NEXT_SCB ) )
goto _fail_end ;
/* SPDIF input sampel rate converter */
src_task_scb = cs46xx_dsp_create_src_task_scb ( chip , " SrcTaskSCB_SPDIFI " ,
ins - > spdif_in_sample_rate ,
SRC_OUTPUT_BUF1 ,
SRC_DELAY_BUF1 , SRCTASK_SCB_ADDR ,
master_mix_scb ,
SCB_ON_PARENT_SUBLIST_SCB , 1 ) ;
if ( ! src_task_scb ) goto _fail_end ;
cs46xx_src_unlink ( chip , src_task_scb ) ;
/* NOTE: when we now how to detect the SPDIF input
sample rate we will use this SRC to adjust it */
ins - > spdif_in_src = src_task_scb ;
cs46xx_dsp_async_init ( chip , timing_master_scb ) ;
return 0 ;
_fail_end :
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev , " dsp_spos: failed to setup SCB's in DSP \n " ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
2005-11-17 14:48:14 +01:00
static int cs46xx_dsp_async_init ( struct snd_cs46xx * chip ,
struct dsp_scb_descriptor * fg_entry )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_symbol_entry * s16_async_codec_input_task ;
struct dsp_symbol_entry * spdifo_task ;
struct dsp_symbol_entry * spdifi_task ;
struct dsp_scb_descriptor * spdifi_scb_desc , * spdifo_scb_desc , * async_codec_scb_desc ;
2005-04-16 15:20:36 -07:00
s16_async_codec_input_task = cs46xx_dsp_lookup_symbol ( chip , " S16_ASYNCCODECINPUTTASK " , SYMBOL_CODE ) ;
if ( s16_async_codec_input_task = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
spdifo_task = cs46xx_dsp_lookup_symbol ( chip , " SPDIFOTASK " , SYMBOL_CODE ) ;
if ( spdifo_task = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol SPDIFOTASK not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
spdifi_task = cs46xx_dsp_lookup_symbol ( chip , " SPDIFITASK " , SYMBOL_CODE ) ;
if ( spdifi_task = = NULL ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: symbol SPDIFITASK not found \n " ) ;
2005-04-16 15:20:36 -07:00
return - EIO ;
}
{
/* 0xBC0 */
2005-11-17 14:48:14 +01:00
struct dsp_spdifoscb spdifo_scb = {
2005-04-16 15:20:36 -07:00
/* 0 */ DSP_SPOS_UUUU ,
{
/* 1 */ 0xb0 ,
/* 2 */ 0 ,
/* 3 */ 0 ,
/* 4 */ 0 ,
} ,
/* NOTE: the SPDIF output task read samples in mono
format , the AsynchFGTxSCB task writes to buffer
in stereo format
*/
/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256 ,
/* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 < < 0x10 ) | 0xFFFC ,
/* 7 */ 0 , 0 ,
/* 8 */ 0 ,
/* 9 */ FG_TASK_HEADER_ADDR , NULL_SCB_ADDR ,
/* A */ spdifo_task - > address ,
SPDIFO_SCB_INST + SPDIFOFIFOPointer ,
{
/* B */ 0x0040 , /*DSP_SPOS_UUUU,*/
/* C */ 0x20ff , /*DSP_SPOS_UUUU,*/
} ,
/* D */ 0x804c , 0 , /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
/* E */ 0x0108 , 0x0001 , /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
/* F */ DSP_SPOS_UUUU /* SPDIFOFree; */
} ;
/* 0xBB0 */
2005-11-17 14:48:14 +01:00
struct dsp_spdifiscb spdifi_scb = {
2005-04-16 15:20:36 -07:00
/* 0 */ DSP_SPOS_UULO , DSP_SPOS_UUHI ,
/* 1 */ 0 ,
/* 2 */ 0 ,
/* 3 */ 1 , 4000 , /* SPDIFICountLimit SPDIFICount */
/* 4 */ DSP_SPOS_UUUU , /* SPDIFIStatusData */
/* 5 */ 0 , DSP_SPOS_UUHI , /* StatusData, Free4 */
/* 6 */ DSP_SPOS_UUUU , /* Free3 */
/* 7 */ DSP_SPOS_UU , DSP_SPOS_DC , /* Free2 BitCount*/
/* 8 */ DSP_SPOS_UUUU , /* TempStatus */
/* 9 */ SPDIFO_SCB_INST , NULL_SCB_ADDR ,
/* A */ spdifi_task - > address ,
SPDIFI_SCB_INST + SPDIFIFIFOPointer ,
/* NOTE: The SPDIF input task write the sample in mono
format from the HW FIFO , the AsynchFGRxSCB task reads
them in stereo
*/
/* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128 ,
/* C */ ( SPDIFI_IP_OUTPUT_BUFFER1 < < 0x10 ) | 0xFFFC ,
/* D */ 0x8048 , 0 ,
/* E */ 0x01f0 , 0x0001 ,
/* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */
} ;
/* 0xBA0 */
2005-11-17 14:48:14 +01:00
struct dsp_async_codec_input_scb async_codec_input_scb = {
2005-04-16 15:20:36 -07:00
/* 0 */ DSP_SPOS_UUUU ,
/* 1 */ 0 ,
/* 2 */ 0 ,
/* 3 */ 1 , 4000 ,
/* 4 */ 0x0118 , 0x0001 ,
/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64 ,
/* 6 */ ( ASYNC_IP_OUTPUT_BUFFER1 < < 0x10 ) | 0xFFFC ,
/* 7 */ DSP_SPOS_UU , 0x3 ,
/* 8 */ DSP_SPOS_UUUU ,
/* 9 */ SPDIFI_SCB_INST , NULL_SCB_ADDR ,
/* A */ s16_async_codec_input_task - > address ,
HFG_TREE_SCB + AsyncCIOFIFOPointer ,
/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64 ,
/* C */ ( ASYNC_IP_OUTPUT_BUFFER1 < < 0x10 ) , /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
# ifdef UseASER1Input
/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
Init . 0000 : 8042 : for ASER1
0000 : 8044 : for ASER2 */
/* D */ 0x8042 , 0 ,
/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
Init 1 stero : 8050 ASER1
Init 0 mono : 8070 ASER2
Init 1 Stereo : 0100 ASER1 ( Set by script ) */
/* E */ 0x0100 , 0x0001 ,
# endif
# ifdef UseASER2Input
/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
Init . 0000 : 8042 : for ASER1
0000 : 8044 : for ASER2 */
/* D */ 0x8044 , 0 ,
/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
Init 1 stero : 8050 ASER1
Init 0 mono : 8070 ASER2
Init 1 Stereo : 0100 ASER1 ( Set by script ) */
/* E */ 0x0110 , 0x0001 ,
# endif
/* short AsyncCIOutputBufModulo:AsyncCIFree;
AsyncCIOutputBufModulo : The modulo size for
the output buffer of this task */
/* F */ 0 , /* DSP_SPOS_UUUU */
} ;
spdifo_scb_desc = cs46xx_dsp_create_scb ( chip , " SPDIFOSCB " , ( u32 * ) & spdifo_scb , SPDIFO_SCB_INST ) ;
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! spdifo_scb_desc ) )
return - EIO ;
2005-04-16 15:20:36 -07:00
spdifi_scb_desc = cs46xx_dsp_create_scb ( chip , " SPDIFISCB " , ( u32 * ) & spdifi_scb , SPDIFI_SCB_INST ) ;
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! spdifi_scb_desc ) )
return - EIO ;
2005-04-16 15:20:36 -07:00
async_codec_scb_desc = cs46xx_dsp_create_scb ( chip , " AsynCodecInputSCB " , ( u32 * ) & async_codec_input_scb , HFG_TREE_SCB ) ;
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! async_codec_scb_desc ) )
return - EIO ;
2005-04-16 15:20:36 -07:00
async_codec_scb_desc - > parent_scb_ptr = NULL ;
async_codec_scb_desc - > next_scb_ptr = spdifi_scb_desc ;
async_codec_scb_desc - > sub_list_ptr = ins - > the_null_scb ;
async_codec_scb_desc - > task_entry = s16_async_codec_input_task ;
spdifi_scb_desc - > parent_scb_ptr = async_codec_scb_desc ;
spdifi_scb_desc - > next_scb_ptr = spdifo_scb_desc ;
spdifi_scb_desc - > sub_list_ptr = ins - > the_null_scb ;
spdifi_scb_desc - > task_entry = spdifi_task ;
spdifo_scb_desc - > parent_scb_ptr = spdifi_scb_desc ;
spdifo_scb_desc - > next_scb_ptr = fg_entry ;
spdifo_scb_desc - > sub_list_ptr = ins - > the_null_scb ;
spdifo_scb_desc - > task_entry = spdifo_task ;
/* this one is faked, as the parnet of SPDIFO task
is the FG task tree */
fg_entry - > parent_scb_ptr = spdifo_scb_desc ;
/* for proc fs */
cs46xx_dsp_proc_register_scb_desc ( chip , spdifo_scb_desc ) ;
cs46xx_dsp_proc_register_scb_desc ( chip , spdifi_scb_desc ) ;
cs46xx_dsp_proc_register_scb_desc ( chip , async_codec_scb_desc ) ;
/* Async MASTER ENABLE, affects both SPDIF input and output */
snd_cs46xx_pokeBA0 ( chip , BA0_ASER_MASTER , 0x1 ) ;
}
return 0 ;
}
2005-11-17 14:48:14 +01:00
static void cs46xx_dsp_disable_spdif_hw ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
/* set SPDIF output FIFO slot */
snd_cs46xx_pokeBA0 ( chip , BA0_ASER_FADDR , 0 ) ;
/* SPDIF output MASTER ENABLE */
cs46xx_poke_via_dsp ( chip , SP_SPDOUT_CONTROL , 0 ) ;
/* right and left validate bit */
/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
cs46xx_poke_via_dsp ( chip , SP_SPDOUT_CSUV , 0x0 ) ;
/* clear fifo pointer */
cs46xx_poke_via_dsp ( chip , SP_SPDIN_FIFOPTR , 0x0 ) ;
/* monitor state */
ins - > spdif_status_out & = ~ DSP_SPDIF_STATUS_HW_ENABLED ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_enable_spdif_hw ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
/* if hw-ctrl already enabled, turn off to reset logic ... */
cs46xx_dsp_disable_spdif_hw ( chip ) ;
udelay ( 50 ) ;
/* set SPDIF output FIFO slot */
snd_cs46xx_pokeBA0 ( chip , BA0_ASER_FADDR , ( 0x8000 | ( ( SP_SPDOUT_FIFO > > 4 ) < < 4 ) ) ) ;
/* SPDIF output MASTER ENABLE */
cs46xx_poke_via_dsp ( chip , SP_SPDOUT_CONTROL , 0x80000000 ) ;
/* right and left validate bit */
cs46xx_poke_via_dsp ( chip , SP_SPDOUT_CSUV , ins - > spdif_csuv_default ) ;
/* monitor state */
ins - > spdif_status_out | = DSP_SPDIF_STATUS_HW_ENABLED ;
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_enable_spdif_in ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
/* turn on amplifier */
chip - > active_ctrl ( chip , 1 ) ;
chip - > amplifier_ctrl ( chip , 1 ) ;
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ins - > asynch_rx_scb ) )
return - EINVAL ;
if ( snd_BUG_ON ( ! ins - > spdif_in_src ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( ! ( ins - > spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED ) ) {
/* time countdown enable */
cs46xx_poke_via_dsp ( chip , SP_ASER_COUNTDOWN , 0x80000005 ) ;
/* NOTE: 80000005 value is just magic. With all values
that I ' ve tested this one seem to give the best result .
Got no explication why . ( Benny ) */
/* SPDIF input MASTER ENABLE */
cs46xx_poke_via_dsp ( chip , SP_SPDIN_CONTROL , 0x800003ff ) ;
ins - > spdif_status_out | = DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED ;
}
/* create and start the asynchronous receiver SCB */
ins - > asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb ( chip , " AsynchFGRxSCB " ,
ASYNCRX_SCB_ADDR ,
SPDIFI_SCB_INST ,
SPDIFI_IP_OUTPUT_BUFFER1 ,
ins - > spdif_in_src ,
SCB_ON_PARENT_SUBLIST_SCB ) ;
spin_lock_irq ( & chip - > reg_lock ) ;
/* reset SPDIF input sample buffer pointer */
/*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
( SPDIFI_IP_OUTPUT_BUFFER1 < < 0x10 ) | 0xFFFC ) ; */
/* reset FIFO ptr */
/*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/
cs46xx_src_link ( chip , ins - > spdif_in_src ) ;
/* unmute SRC volume */
cs46xx_dsp_scb_set_volume ( chip , ins - > spdif_in_src , 0x7fff , 0x7fff ) ;
spin_unlock_irq ( & chip - > reg_lock ) ;
/* set SPDIF input sample rate and unmute
NOTE : only 48 khz support for SPDIF input this time */
/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
/* monitor state */
ins - > spdif_status_in = 1 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_disable_spdif_in ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! ins - > asynch_rx_scb ) )
return - EINVAL ;
if ( snd_BUG_ON ( ! ins - > spdif_in_src ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
/* Remove the asynchronous receiver SCB */
cs46xx_dsp_remove_scb ( chip , ins - > asynch_rx_scb ) ;
ins - > asynch_rx_scb = NULL ;
cs46xx_src_unlink ( chip , ins - > spdif_in_src ) ;
/* monitor state */
ins - > spdif_status_in = 0 ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
/* restore amplifier */
chip - > active_ctrl ( chip , - 1 ) ;
chip - > amplifier_ctrl ( chip , - 1 ) ;
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_enable_pcm_capture ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ins - > pcm_input ) )
return - EINVAL ;
if ( snd_BUG_ON ( ! ins - > ref_snoop_scb ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
ins - > pcm_input = cs46xx_add_record_source ( chip , ins - > ref_snoop_scb , PCMSERIALIN_PCM_SCB_ADDR ,
" PCMSerialInput_Wave " ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_disable_pcm_capture ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! ins - > pcm_input ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
cs46xx_dsp_remove_scb ( chip , ins - > pcm_input ) ;
ins - > pcm_input = NULL ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_enable_adc_capture ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ins - > adc_input ) )
return - EINVAL ;
if ( snd_BUG_ON ( ! ins - > codec_in_scb ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
ins - > adc_input = cs46xx_add_record_source ( chip , ins - > codec_in_scb , PCMSERIALIN_SCB_ADDR ,
" PCMSerialInput_ADC " ) ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_disable_adc_capture ( struct snd_cs46xx * chip )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2008-08-08 17:12:14 +02:00
if ( snd_BUG_ON ( ! ins - > adc_input ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
cs46xx_dsp_remove_scb ( chip , ins - > adc_input ) ;
ins - > adc_input = NULL ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_poke_via_dsp ( struct snd_cs46xx * chip , u32 address , u32 data )
2005-04-16 15:20:36 -07:00
{
u32 temp ;
int i ;
/* santiy check the parameters. (These numbers are not 100% correct. They are
a rough guess from looking at the controller spec . ) */
if ( address < 0x8000 | | address > = 0x9000 )
return - EINVAL ;
/* initialize the SP_IO_WRITE SCB with the data. */
temp = ( address < < 16 ) | ( address & 0x0000FFFF ) ; /* offset 0 <-- address2 : address1 */
snd_cs46xx_poke ( chip , ( SPIOWRITE_SCB_ADDR < < 2 ) , temp ) ;
snd_cs46xx_poke ( chip , ( ( SPIOWRITE_SCB_ADDR + 1 ) < < 2 ) , data ) ; /* offset 1 <-- data1 */
snd_cs46xx_poke ( chip , ( ( SPIOWRITE_SCB_ADDR + 2 ) < < 2 ) , data ) ; /* offset 1 <-- data2 */
/* Poke this location to tell the task to start */
snd_cs46xx_poke ( chip , ( ( SPIOWRITE_SCB_ADDR + 6 ) < < 2 ) , SPIOWRITE_SCB_ADDR < < 0x10 ) ;
/* Verify that the task ran */
for ( i = 0 ; i < 25 ; i + + ) {
udelay ( 125 ) ;
temp = snd_cs46xx_peek ( chip , ( ( SPIOWRITE_SCB_ADDR + 6 ) < < 2 ) ) ;
if ( temp = = 0x00000000 )
break ;
}
if ( i = = 25 ) {
2014-02-25 16:36:51 +01:00
dev_err ( chip - > card - > dev ,
" dsp_spos: SPIOWriteTask not responding \n " ) ;
2005-04-16 15:20:36 -07:00
return - EBUSY ;
}
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_set_dac_volume ( struct snd_cs46xx * chip , u16 left , u16 right )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:48:14 +01:00
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
struct dsp_scb_descriptor * scb ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
/* main output */
scb = ins - > master_mix_scb - > sub_list_ptr ;
while ( scb ! = ins - > the_null_scb ) {
cs46xx_dsp_scb_set_volume ( chip , scb , left , right ) ;
scb = scb - > next_scb_ptr ;
}
/* rear output */
scb = ins - > rear_mix_scb - > sub_list_ptr ;
while ( scb ! = ins - > the_null_scb ) {
cs46xx_dsp_scb_set_volume ( chip , scb , left , right ) ;
scb = scb - > next_scb_ptr ;
}
ins - > dac_volume_left = left ;
ins - > dac_volume_right = right ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-17 14:48:14 +01:00
int cs46xx_dsp_set_iec958_volume ( struct snd_cs46xx * chip , u16 left , u16 right )
{
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
2005-04-16 15:20:36 -07:00
2006-01-16 16:34:20 +01:00
mutex_lock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( ins - > asynch_rx_scb ! = NULL )
cs46xx_dsp_scb_set_volume ( chip , ins - > asynch_rx_scb ,
left , right ) ;
ins - > spdif_input_volume_left = left ;
ins - > spdif_input_volume_right = right ;
2006-01-16 16:34:20 +01:00
mutex_unlock ( & chip - > spos_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-19 11:23:21 +02:00
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2007-07-19 11:23:21 +02:00
int cs46xx_dsp_resume ( struct snd_cs46xx * chip )
{
struct dsp_spos_instance * ins = chip - > dsp_spos_instance ;
int i , err ;
/* clear parameter, sample and code areas */
snd_cs46xx_clear_BA1 ( chip , DSP_PARAMETER_BYTE_OFFSET ,
DSP_PARAMETER_BYTE_SIZE ) ;
snd_cs46xx_clear_BA1 ( chip , DSP_SAMPLE_BYTE_OFFSET ,
DSP_SAMPLE_BYTE_SIZE ) ;
snd_cs46xx_clear_BA1 ( chip , DSP_CODE_BYTE_OFFSET , DSP_CODE_BYTE_SIZE ) ;
for ( i = 0 ; i < ins - > nmodules ; i + + ) {
struct dsp_module_desc * module = & ins - > modules [ i ] ;
struct dsp_segment_desc * seg ;
u32 doffset , dsize ;
seg = get_segment_desc ( module , SEGTYPE_SP_PARAMETER ) ;
err = dsp_load_parameter ( chip , seg ) ;
if ( err < 0 )
return err ;
seg = get_segment_desc ( module , SEGTYPE_SP_SAMPLE ) ;
err = dsp_load_sample ( chip , seg ) ;
if ( err < 0 )
return err ;
seg = get_segment_desc ( module , SEGTYPE_SP_PROGRAM ) ;
if ( ! seg )
continue ;
doffset = seg - > offset * 4 + module - > load_address * 4
+ DSP_CODE_BYTE_OFFSET ;
dsize = seg - > size * 4 ;
err = snd_cs46xx_download ( chip ,
ins - > code . data + module - > load_address ,
doffset , dsize ) ;
if ( err < 0 )
return err ;
}
for ( i = 0 ; i < ins - > ntask ; i + + ) {
struct dsp_task_descriptor * t = & ins - > tasks [ i ] ;
_dsp_create_task_tree ( chip , t - > data , t - > address , t - > size ) ;
}
for ( i = 0 ; i < ins - > nscb ; i + + ) {
struct dsp_scb_descriptor * s = & ins - > scbs [ i ] ;
if ( s - > deleted )
continue ;
_dsp_create_scb ( chip , s - > data , s - > address ) ;
}
2009-12-22 09:00:14 +01:00
for ( i = 0 ; i < ins - > nscb ; i + + ) {
struct dsp_scb_descriptor * s = & ins - > scbs [ i ] ;
if ( s - > deleted )
continue ;
if ( s - > updated )
cs46xx_dsp_spos_update_scb ( chip , s ) ;
if ( s - > volume_set )
cs46xx_dsp_scb_set_volume ( chip , s ,
s - > volume [ 0 ] , s - > volume [ 1 ] ) ;
}
if ( ins - > spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED ) {
cs46xx_dsp_enable_spdif_hw ( chip ) ;
snd_cs46xx_poke ( chip , ( ins - > ref_snoop_scb - > address + 2 ) < < 2 ,
( OUTPUT_SNOOP_BUFFER + 0x10 ) < < 0x10 ) ;
if ( ins - > spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN )
cs46xx_poke_via_dsp ( chip , SP_SPDOUT_CSUV ,
ins - > spdif_csuv_stream ) ;
}
if ( chip - > dsp_spos_instance - > spdif_status_in ) {
cs46xx_poke_via_dsp ( chip , SP_ASER_COUNTDOWN , 0x80000005 ) ;
cs46xx_poke_via_dsp ( chip , SP_SPDIN_CONTROL , 0x800003ff ) ;
}
2007-07-19 11:23:21 +02:00
return 0 ;
}
# endif