2005-04-17 02:20:36 +04:00
/*
* Maintained by Jaroslav Kysela < perex @ suse . cz >
* Originated by audio @ tridentmicro . com
* Fri Feb 19 15 : 55 : 28 MST 1999
* Routines for control of Trident 4 DWave ( DX and NX ) chip
*
* BUGS :
*
* TODO :
* - - -
*
* 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
*
*
* SiS7018 S / PDIF support by Thomas Winischhofer < thomas @ winischhofer . net >
*/
# include <sound/driver.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/pci.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/gameport.h>
# include <sound/core.h>
# include <sound/info.h>
# include <sound/control.h>
# include <sound/trident.h>
# include <sound/asoundef.h>
# include <asm/io.h>
static int snd_trident_pcm_mixer_build ( trident_t * trident , snd_trident_voice_t * voice , snd_pcm_substream_t * substream ) ;
static int snd_trident_pcm_mixer_free ( trident_t * trident , snd_trident_voice_t * voice , snd_pcm_substream_t * substream ) ;
static irqreturn_t snd_trident_interrupt ( int irq , void * dev_id , struct pt_regs * regs ) ;
# ifdef CONFIG_PM
static int snd_trident_suspend ( snd_card_t * card , pm_message_t state ) ;
static int snd_trident_resume ( snd_card_t * card ) ;
# endif
static int snd_trident_sis_reset ( trident_t * trident ) ;
static void snd_trident_clear_voices ( trident_t * trident , unsigned short v_min , unsigned short v_max ) ;
static int snd_trident_free ( trident_t * trident ) ;
/*
* common I / O routines
*/
#if 0
static void snd_trident_print_voice_regs ( trident_t * trident , int voice )
{
unsigned int val , tmp ;
printk ( " Trident voice %i: \n " , voice ) ;
outb ( voice , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
val = inl ( TRID_REG ( trident , CH_LBA ) ) ;
printk ( " LBA: 0x%x \n " , val ) ;
val = inl ( TRID_REG ( trident , CH_GVSEL_PAN_VOL_CTRL_EC ) ) ;
printk ( " GVSel: %i \n " , val > > 31 ) ;
printk ( " Pan: 0x%x \n " , ( val > > 24 ) & 0x7f ) ;
printk ( " Vol: 0x%x \n " , ( val > > 16 ) & 0xff ) ;
printk ( " CTRL: 0x%x \n " , ( val > > 12 ) & 0x0f ) ;
printk ( " EC: 0x%x \n " , val & 0x0fff ) ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_NX ) {
val = inl ( TRID_REG ( trident , CH_DX_CSO_ALPHA_FMS ) ) ;
printk ( " CSO: 0x%x \n " , val > > 16 ) ;
printk ( " Alpha: 0x%x \n " , ( val > > 4 ) & 0x0fff ) ;
printk ( " FMS: 0x%x \n " , val & 0x0f ) ;
val = inl ( TRID_REG ( trident , CH_DX_ESO_DELTA ) ) ;
printk ( " ESO: 0x%x \n " , val > > 16 ) ;
printk ( " Delta: 0x%x \n " , val & 0xffff ) ;
val = inl ( TRID_REG ( trident , CH_DX_FMC_RVOL_CVOL ) ) ;
} else { // TRIDENT_DEVICE_ID_NX
val = inl ( TRID_REG ( trident , CH_NX_DELTA_CSO ) ) ;
tmp = ( val > > 24 ) & 0xff ;
printk ( " CSO: 0x%x \n " , val & 0x00ffffff ) ;
val = inl ( TRID_REG ( trident , CH_NX_DELTA_ESO ) ) ;
tmp | = ( val > > 16 ) & 0xff00 ;
printk ( " Delta: 0x%x \n " , tmp ) ;
printk ( " ESO: 0x%x \n " , val & 0x00ffffff ) ;
val = inl ( TRID_REG ( trident , CH_NX_ALPHA_FMS_FMC_RVOL_CVOL ) ) ;
printk ( " Alpha: 0x%x \n " , val > > 20 ) ;
printk ( " FMS: 0x%x \n " , ( val > > 16 ) & 0x0f ) ;
}
printk ( " FMC: 0x%x \n " , ( val > > 14 ) & 3 ) ;
printk ( " RVol: 0x%x \n " , ( val > > 7 ) & 0x7f ) ;
printk ( " CVol: 0x%x \n " , val & 0x7f ) ;
}
# endif
/*---------------------------------------------------------------------------
unsigned short snd_trident_codec_read ( ac97_t * ac97 , unsigned short reg )
Description : This routine will do all of the reading from the external
CODEC ( AC97 ) .
Parameters : ac97 - ac97 codec structure
reg - CODEC register index , from AC97 Hal .
returns : 16 bit value read from the AC97 .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static unsigned short snd_trident_codec_read ( ac97_t * ac97 , unsigned short reg )
{
unsigned int data = 0 , treg ;
unsigned short count = 0xffff ;
unsigned long flags ;
trident_t * trident = ac97 - > private_data ;
spin_lock_irqsave ( & trident - > reg_lock , flags ) ;
if ( trident - > device = = TRIDENT_DEVICE_ID_DX ) {
data = ( DX_AC97_BUSY_READ | ( reg & 0x000000ff ) ) ;
outl ( data , TRID_REG ( trident , DX_ACR1_AC97_R ) ) ;
do {
data = inl ( TRID_REG ( trident , DX_ACR1_AC97_R ) ) ;
if ( ( data & DX_AC97_BUSY_READ ) = = 0 )
break ;
} while ( - - count ) ;
} else if ( trident - > device = = TRIDENT_DEVICE_ID_NX ) {
data = ( NX_AC97_BUSY_READ | ( reg & 0x000000ff ) ) ;
treg = ac97 - > num = = 0 ? NX_ACR2_AC97_R_PRIMARY : NX_ACR3_AC97_R_SECONDARY ;
outl ( data , TRID_REG ( trident , treg ) ) ;
do {
data = inl ( TRID_REG ( trident , treg ) ) ;
if ( ( data & 0x00000C00 ) = = 0 )
break ;
} while ( - - count ) ;
} else if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
data = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY | ( reg & 0x000000ff ) ;
if ( ac97 - > num = = 1 )
data | = SI_AC97_SECONDARY ;
outl ( data , TRID_REG ( trident , SI_AC97_READ ) ) ;
do {
data = inl ( TRID_REG ( trident , SI_AC97_READ ) ) ;
if ( ( data & ( SI_AC97_BUSY_READ ) ) = = 0 )
break ;
} while ( - - count ) ;
}
if ( count = = 0 & & ! trident - > ac97_detect ) {
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " ac97 codec read TIMEOUT [0x%x/0x%x]!!! \n " , reg , data ) ;
2005-04-17 02:20:36 +04:00
data = 0 ;
}
spin_unlock_irqrestore ( & trident - > reg_lock , flags ) ;
return ( ( unsigned short ) ( data > > 16 ) ) ;
}
/*---------------------------------------------------------------------------
void snd_trident_codec_write ( ac97_t * ac97 , unsigned short reg , unsigned short wdata )
Description : This routine will do all of the writing to the external
CODEC ( AC97 ) .
Parameters : ac97 - ac97 codec structure
reg - CODEC register index , from AC97 Hal .
data - Lower 16 bits are the data to write to CODEC .
returns : TRUE if everything went ok , else FALSE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_codec_write ( ac97_t * ac97 , unsigned short reg , unsigned short wdata )
{
unsigned int address , data ;
unsigned short count = 0xffff ;
unsigned long flags ;
trident_t * trident = ac97 - > private_data ;
data = ( ( unsigned long ) wdata ) < < 16 ;
spin_lock_irqsave ( & trident - > reg_lock , flags ) ;
if ( trident - > device = = TRIDENT_DEVICE_ID_DX ) {
address = DX_ACR0_AC97_W ;
/* read AC-97 write register status */
do {
if ( ( inw ( TRID_REG ( trident , address ) ) & DX_AC97_BUSY_WRITE ) = = 0 )
break ;
} while ( - - count ) ;
data | = ( DX_AC97_BUSY_WRITE | ( reg & 0x000000ff ) ) ;
} else if ( trident - > device = = TRIDENT_DEVICE_ID_NX ) {
address = NX_ACR1_AC97_W ;
/* read AC-97 write register status */
do {
if ( ( inw ( TRID_REG ( trident , address ) ) & NX_AC97_BUSY_WRITE ) = = 0 )
break ;
} while ( - - count ) ;
data | = ( NX_AC97_BUSY_WRITE | ( ac97 - > num < < 8 ) | ( reg & 0x000000ff ) ) ;
} else if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
address = SI_AC97_WRITE ;
/* read AC-97 write register status */
do {
if ( ( inw ( TRID_REG ( trident , address ) ) & ( SI_AC97_BUSY_WRITE ) ) = = 0 )
break ;
} while ( - - count ) ;
data | = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY | ( reg & 0x000000ff ) ;
if ( ac97 - > num = = 1 )
data | = SI_AC97_SECONDARY ;
} else {
address = 0 ; /* keep GCC happy */
count = 0 ; /* return */
}
if ( count = = 0 ) {
spin_unlock_irqrestore ( & trident - > reg_lock , flags ) ;
return ;
}
outl ( data , TRID_REG ( trident , address ) ) ;
spin_unlock_irqrestore ( & trident - > reg_lock , flags ) ;
}
/*---------------------------------------------------------------------------
void snd_trident_enable_eso ( trident_t * trident )
Description : This routine will enable end of loop interrupts .
End of loop interrupts will occur when a running
channel reaches ESO .
Also enables middle of loop interrupts .
Parameters : trident - pointer to target device class for 4 DWave .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_enable_eso ( trident_t * trident )
{
unsigned int val ;
val = inl ( TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
val | = ENDLP_IE ;
val | = MIDLP_IE ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 )
val | = BANK_B_EN ;
outl ( val , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
}
/*---------------------------------------------------------------------------
void snd_trident_disable_eso ( trident_t * trident )
Description : This routine will disable end of loop interrupts .
End of loop interrupts will occur when a running
channel reaches ESO .
Also disables middle of loop interrupts .
Parameters :
trident - pointer to target device class for 4 DWave .
returns : TRUE if everything went ok , else FALSE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_disable_eso ( trident_t * trident )
{
unsigned int tmp ;
tmp = inl ( TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
tmp & = ~ ENDLP_IE ;
tmp & = ~ MIDLP_IE ;
outl ( tmp , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
}
/*---------------------------------------------------------------------------
void snd_trident_start_voice ( trident_t * trident , unsigned int voice )
Description : Start a voice , any channel 0 thru 63.
This routine automatically handles the fact that there are
more than 32 channels available .
Parameters : voice - Voice number 0 thru n .
trident - pointer to target device class for 4 DWave .
Return Value : None .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void snd_trident_start_voice ( trident_t * trident , unsigned int voice )
{
unsigned int mask = 1 < < ( voice & 0x1f ) ;
unsigned int reg = ( voice & 0x20 ) ? T4D_START_B : T4D_START_A ;
outl ( mask , TRID_REG ( trident , reg ) ) ;
}
/*---------------------------------------------------------------------------
void snd_trident_stop_voice ( trident_t * trident , unsigned int voice )
Description : Stop a voice , any channel 0 thru 63.
This routine automatically handles the fact that there are
more than 32 channels available .
Parameters : voice - Voice number 0 thru n .
trident - pointer to target device class for 4 DWave .
Return Value : None .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void snd_trident_stop_voice ( trident_t * trident , unsigned int voice )
{
unsigned int mask = 1 < < ( voice & 0x1f ) ;
unsigned int reg = ( voice & 0x20 ) ? T4D_STOP_B : T4D_STOP_A ;
outl ( mask , TRID_REG ( trident , reg ) ) ;
}
/*---------------------------------------------------------------------------
int snd_trident_allocate_pcm_channel ( trident_t * trident )
Description : Allocate hardware channel in Bank B ( 32 - 63 ) .
Parameters : trident - pointer to target device class for 4 DWave .
Return Value : hardware channel - 32 - 63 or - 1 when no channel is available
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_allocate_pcm_channel ( trident_t * trident )
{
int idx ;
if ( trident - > ChanPCMcnt > = trident - > ChanPCM )
return - 1 ;
for ( idx = 31 ; idx > = 0 ; idx - - ) {
if ( ! ( trident - > ChanMap [ T4D_BANK_B ] & ( 1 < < idx ) ) ) {
trident - > ChanMap [ T4D_BANK_B ] | = 1 < < idx ;
trident - > ChanPCMcnt + + ;
return idx + 32 ;
}
}
return - 1 ;
}
/*---------------------------------------------------------------------------
void snd_trident_free_pcm_channel ( int channel )
Description : Free hardware channel in Bank B ( 32 - 63 )
Parameters : trident - pointer to target device class for 4 DWave .
channel - hardware channel number 0 - 63
Return Value : none
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_free_pcm_channel ( trident_t * trident , int channel )
{
if ( channel < 32 | | channel > 63 )
return ;
channel & = 0x1f ;
if ( trident - > ChanMap [ T4D_BANK_B ] & ( 1 < < channel ) ) {
trident - > ChanMap [ T4D_BANK_B ] & = ~ ( 1 < < channel ) ;
trident - > ChanPCMcnt - - ;
}
}
/*---------------------------------------------------------------------------
unsigned int snd_trident_allocate_synth_channel ( void )
Description : Allocate hardware channel in Bank A ( 0 - 31 ) .
Parameters : trident - pointer to target device class for 4 DWave .
Return Value : hardware channel - 0 - 31 or - 1 when no channel is available
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_allocate_synth_channel ( trident_t * trident )
{
int idx ;
for ( idx = 31 ; idx > = 0 ; idx - - ) {
if ( ! ( trident - > ChanMap [ T4D_BANK_A ] & ( 1 < < idx ) ) ) {
trident - > ChanMap [ T4D_BANK_A ] | = 1 < < idx ;
trident - > synth . ChanSynthCount + + ;
return idx ;
}
}
return - 1 ;
}
/*---------------------------------------------------------------------------
void snd_trident_free_synth_channel ( int channel )
Description : Free hardware channel in Bank B ( 0 - 31 ) .
Parameters : trident - pointer to target device class for 4 DWave .
channel - hardware channel number 0 - 63
Return Value : none
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_free_synth_channel ( trident_t * trident , int channel )
{
if ( channel < 0 | | channel > 31 )
return ;
channel & = 0x1f ;
if ( trident - > ChanMap [ T4D_BANK_A ] & ( 1 < < channel ) ) {
trident - > ChanMap [ T4D_BANK_A ] & = ~ ( 1 < < channel ) ;
trident - > synth . ChanSynthCount - - ;
}
}
/*---------------------------------------------------------------------------
snd_trident_write_voice_regs
Description : This routine will complete and write the 5 hardware channel
registers to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
Each register field .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void snd_trident_write_voice_regs ( trident_t * trident ,
snd_trident_voice_t * voice )
{
unsigned int FmcRvolCvol ;
unsigned int regs [ 5 ] ;
regs [ 1 ] = voice - > LBA ;
regs [ 4 ] = ( voice - > GVSel < < 31 ) |
( ( voice - > Pan & 0x0000007f ) < < 24 ) |
( ( voice - > CTRL & 0x0000000f ) < < 12 ) ;
FmcRvolCvol = ( ( voice - > FMC & 3 ) < < 14 ) |
( ( voice - > RVol & 0x7f ) < < 7 ) |
( voice - > CVol & 0x7f ) ;
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_SI7018 :
regs [ 4 ] | = voice - > number > 31 ?
( voice - > Vol & 0x000003ff ) :
( ( voice - > Vol & 0x00003fc ) < < ( 16 - 2 ) ) |
( voice - > EC & 0x00000fff ) ;
regs [ 0 ] = ( voice - > CSO < < 16 ) | ( ( voice - > Alpha & 0x00000fff ) < < 4 ) | ( voice - > FMS & 0x0000000f ) ;
regs [ 2 ] = ( voice - > ESO < < 16 ) | ( voice - > Delta & 0x0ffff ) ;
regs [ 3 ] = ( voice - > Attribute < < 16 ) | FmcRvolCvol ;
break ;
case TRIDENT_DEVICE_ID_DX :
regs [ 4 ] | = ( ( voice - > Vol & 0x000003fc ) < < ( 16 - 2 ) ) |
( voice - > EC & 0x00000fff ) ;
regs [ 0 ] = ( voice - > CSO < < 16 ) | ( ( voice - > Alpha & 0x00000fff ) < < 4 ) | ( voice - > FMS & 0x0000000f ) ;
regs [ 2 ] = ( voice - > ESO < < 16 ) | ( voice - > Delta & 0x0ffff ) ;
regs [ 3 ] = FmcRvolCvol ;
break ;
case TRIDENT_DEVICE_ID_NX :
regs [ 4 ] | = ( ( voice - > Vol & 0x000003fc ) < < ( 16 - 2 ) ) |
( voice - > EC & 0x00000fff ) ;
regs [ 0 ] = ( voice - > Delta < < 24 ) | ( voice - > CSO & 0x00ffffff ) ;
regs [ 2 ] = ( ( voice - > Delta < < 16 ) & 0xff000000 ) | ( voice - > ESO & 0x00ffffff ) ;
regs [ 3 ] = ( voice - > Alpha < < 20 ) | ( ( voice - > FMS & 0x0000000f ) < < 16 ) | FmcRvolCvol ;
break ;
default :
snd_BUG ( ) ;
2005-06-27 17:07:33 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
outl ( regs [ 0 ] , TRID_REG ( trident , CH_START + 0 ) ) ;
outl ( regs [ 1 ] , TRID_REG ( trident , CH_START + 4 ) ) ;
outl ( regs [ 2 ] , TRID_REG ( trident , CH_START + 8 ) ) ;
outl ( regs [ 3 ] , TRID_REG ( trident , CH_START + 12 ) ) ;
outl ( regs [ 4 ] , TRID_REG ( trident , CH_START + 16 ) ) ;
#if 0
printk ( " written %i channel: \n " , voice - > number ) ;
printk ( " regs[0] = 0x%x/0x%x \n " , regs [ 0 ] , inl ( TRID_REG ( trident , CH_START + 0 ) ) ) ;
printk ( " regs[1] = 0x%x/0x%x \n " , regs [ 1 ] , inl ( TRID_REG ( trident , CH_START + 4 ) ) ) ;
printk ( " regs[2] = 0x%x/0x%x \n " , regs [ 2 ] , inl ( TRID_REG ( trident , CH_START + 8 ) ) ) ;
printk ( " regs[3] = 0x%x/0x%x \n " , regs [ 3 ] , inl ( TRID_REG ( trident , CH_START + 12 ) ) ) ;
printk ( " regs[4] = 0x%x/0x%x \n " , regs [ 4 ] , inl ( TRID_REG ( trident , CH_START + 16 ) ) ) ;
# endif
}
/*---------------------------------------------------------------------------
snd_trident_write_cso_reg
Description : This routine will write the new CSO offset
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
CSO - new CSO value
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_cso_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int CSO )
{
voice - > CSO = CSO ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_NX ) {
outw ( voice - > CSO , TRID_REG ( trident , CH_DX_CSO_ALPHA_FMS ) + 2 ) ;
} else {
outl ( ( voice - > Delta < < 24 ) | ( voice - > CSO & 0x00ffffff ) , TRID_REG ( trident , CH_NX_DELTA_CSO ) ) ;
}
}
/*---------------------------------------------------------------------------
snd_trident_write_eso_reg
Description : This routine will write the new ESO offset
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
ESO - new ESO value
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_eso_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int ESO )
{
voice - > ESO = ESO ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_NX ) {
outw ( voice - > ESO , TRID_REG ( trident , CH_DX_ESO_DELTA ) + 2 ) ;
} else {
outl ( ( ( voice - > Delta < < 16 ) & 0xff000000 ) | ( voice - > ESO & 0x00ffffff ) , TRID_REG ( trident , CH_NX_DELTA_ESO ) ) ;
}
}
/*---------------------------------------------------------------------------
snd_trident_write_vol_reg
Description : This routine will write the new voice volume
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
Vol - new voice volume
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_vol_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int Vol )
{
voice - > Vol = Vol ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_DX :
case TRIDENT_DEVICE_ID_NX :
outb ( voice - > Vol > > 2 , TRID_REG ( trident , CH_GVSEL_PAN_VOL_CTRL_EC + 2 ) ) ;
break ;
case TRIDENT_DEVICE_ID_SI7018 :
// printk("voice->Vol = 0x%x\n", voice->Vol);
outw ( ( voice - > CTRL < < 12 ) | voice - > Vol , TRID_REG ( trident , CH_GVSEL_PAN_VOL_CTRL_EC ) ) ;
break ;
}
}
/*---------------------------------------------------------------------------
snd_trident_write_pan_reg
Description : This routine will write the new voice pan
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
Pan - new pan value
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_pan_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int Pan )
{
voice - > Pan = Pan ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
outb ( ( ( voice - > GVSel & 0x01 ) < < 7 ) | ( voice - > Pan & 0x7f ) , TRID_REG ( trident , CH_GVSEL_PAN_VOL_CTRL_EC + 3 ) ) ;
}
/*---------------------------------------------------------------------------
snd_trident_write_rvol_reg
Description : This routine will write the new reverb volume
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
RVol - new reverb volume
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_rvol_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int RVol )
{
voice - > RVol = RVol ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
outw ( ( ( voice - > FMC & 0x0003 ) < < 14 ) | ( ( voice - > RVol & 0x007f ) < < 7 ) | ( voice - > CVol & 0x007f ) ,
TRID_REG ( trident , trident - > device = = TRIDENT_DEVICE_ID_NX ? CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL ) ) ;
}
/*---------------------------------------------------------------------------
snd_trident_write_cvol_reg
Description : This routine will write the new chorus volume
register to hardware .
Paramters : trident - pointer to target device class for 4 DWave .
voice - synthesizer voice structure
CVol - new chorus volume
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void snd_trident_write_cvol_reg ( trident_t * trident , snd_trident_voice_t * voice , unsigned int CVol )
{
voice - > CVol = CVol ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
outw ( ( ( voice - > FMC & 0x0003 ) < < 14 ) | ( ( voice - > RVol & 0x007f ) < < 7 ) | ( voice - > CVol & 0x007f ) ,
TRID_REG ( trident , trident - > device = = TRIDENT_DEVICE_ID_NX ? CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL ) ) ;
}
/*---------------------------------------------------------------------------
snd_trident_convert_rate
Description : This routine converts rate in HZ to hardware delta value .
Paramters : trident - pointer to target device class for 4 DWave .
rate - Real or Virtual channel number .
Returns : Delta value .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static unsigned int snd_trident_convert_rate ( unsigned int rate )
{
unsigned int delta ;
// We special case 44100 and 8000 since rounding with the equation
// does not give us an accurate enough value. For 11025 and 22050
// the equation gives us the best answer. All other frequencies will
// also use the equation. JDW
if ( rate = = 44100 )
delta = 0xeb3 ;
else if ( rate = = 8000 )
delta = 0x2ab ;
else if ( rate = = 48000 )
delta = 0x1000 ;
else
delta = ( ( ( rate < < 12 ) + 24000 ) / 48000 ) & 0x0000ffff ;
return delta ;
}
/*---------------------------------------------------------------------------
snd_trident_convert_adc_rate
Description : This routine converts rate in HZ to hardware delta value .
Paramters : trident - pointer to target device class for 4 DWave .
rate - Real or Virtual channel number .
Returns : Delta value .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static unsigned int snd_trident_convert_adc_rate ( unsigned int rate )
{
unsigned int delta ;
// We special case 44100 and 8000 since rounding with the equation
// does not give us an accurate enough value. For 11025 and 22050
// the equation gives us the best answer. All other frequencies will
// also use the equation. JDW
if ( rate = = 44100 )
delta = 0x116a ;
else if ( rate = = 8000 )
delta = 0x6000 ;
else if ( rate = = 48000 )
delta = 0x1000 ;
else
delta = ( ( 48000 < < 12 ) / rate ) & 0x0000ffff ;
return delta ;
}
/*---------------------------------------------------------------------------
snd_trident_spurious_threshold
Description : This routine converts rate in HZ to spurious threshold .
Paramters : trident - pointer to target device class for 4 DWave .
rate - Real or Virtual channel number .
Returns : Delta value .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static unsigned int snd_trident_spurious_threshold ( unsigned int rate , unsigned int period_size )
{
unsigned int res = ( rate * period_size ) / 48000 ;
if ( res < 64 )
res = res / 2 ;
else
res - = 32 ;
return res ;
}
/*---------------------------------------------------------------------------
snd_trident_control_mode
Description : This routine returns a control mode for a PCM channel .
Paramters : trident - pointer to target device class for 4 DWave .
substream - PCM substream
Returns : Control value .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static unsigned int snd_trident_control_mode ( snd_pcm_substream_t * substream )
{
unsigned int CTRL ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
/* set ctrl mode
CTRL default : 8 - bit ( unsigned ) mono , loop mode enabled
*/
CTRL = 0x00000001 ;
if ( snd_pcm_format_width ( runtime - > format ) = = 16 )
CTRL | = 0x00000008 ; // 16-bit data
if ( snd_pcm_format_signed ( runtime - > format ) )
CTRL | = 0x00000002 ; // signed data
if ( runtime - > channels > 1 )
CTRL | = 0x00000004 ; // stereo data
return CTRL ;
}
/*
* PCM part
*/
/*---------------------------------------------------------------------------
snd_trident_ioctl
Description : Device I / O control handler for playback / capture parameters .
Paramters : substream - PCM substream class
cmd - what ioctl message to process
arg - additional message infoarg
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_ioctl ( snd_pcm_substream_t * substream ,
unsigned int cmd ,
void * arg )
{
/* FIXME: it seems that with small periods the behaviour of
trident hardware is unpredictable and interrupt generator
is broken */
return snd_pcm_lib_ioctl ( substream , cmd , arg ) ;
}
/*---------------------------------------------------------------------------
snd_trident_allocate_pcm_mem
Description : Allocate PCM ring buffer for given substream
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_allocate_pcm_mem ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
int err ;
if ( ( err = snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( hw_params ) ) ) < 0 )
return err ;
if ( trident - > tlb . entries ) {
if ( err > 0 ) { /* change */
if ( voice - > memblk )
snd_trident_free_pages ( trident , voice - > memblk ) ;
voice - > memblk = snd_trident_alloc_pages ( trident , substream ) ;
if ( voice - > memblk = = NULL )
return - ENOMEM ;
}
}
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_allocate_evoice
Description : Allocate extra voice as interrupt generator
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_allocate_evoice ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice - > extra ;
/* voice management */
if ( params_buffer_size ( hw_params ) / 2 ! = params_period_size ( hw_params ) ) {
if ( evoice = = NULL ) {
evoice = snd_trident_alloc_voice ( trident , SNDRV_TRIDENT_VOICE_TYPE_PCM , 0 , 0 ) ;
if ( evoice = = NULL )
return - ENOMEM ;
voice - > extra = evoice ;
evoice - > substream = substream ;
}
} else {
if ( evoice ! = NULL ) {
snd_trident_free_voice ( trident , evoice ) ;
voice - > extra = evoice = NULL ;
}
}
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_hw_params
Description : Set the hardware parameters for the playback device .
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_hw_params ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
int err ;
err = snd_trident_allocate_pcm_mem ( substream , hw_params ) ;
if ( err > = 0 )
err = snd_trident_allocate_evoice ( substream , hw_params ) ;
return err ;
}
/*---------------------------------------------------------------------------
snd_trident_playback_hw_free
Description : Release the hardware resources for the playback device .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_hw_free ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice ? voice - > extra : NULL ;
if ( trident - > tlb . entries ) {
if ( voice & & voice - > memblk ) {
snd_trident_free_pages ( trident , voice - > memblk ) ;
voice - > memblk = NULL ;
}
}
snd_pcm_lib_free_pages ( substream ) ;
if ( evoice ! = NULL ) {
snd_trident_free_voice ( trident , evoice ) ;
voice - > extra = NULL ;
}
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_playback_prepare
Description : Prepare playback device for playback .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_playback_prepare ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice - > extra ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ substream - > number ] ;
spin_lock_irq ( & trident - > reg_lock ) ;
/* set delta (rate) value */
voice - > Delta = snd_trident_convert_rate ( runtime - > rate ) ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( runtime - > rate , runtime - > period_size ) ;
/* set Loop Begin Address */
if ( voice - > memblk )
voice - > LBA = voice - > memblk - > offset ;
else
voice - > LBA = runtime - > dma_addr ;
voice - > CSO = 0 ;
voice - > ESO = runtime - > buffer_size - 1 ; /* in samples */
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 3 ;
voice - > GVSel = 1 ;
voice - > EC = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Vol = mix - > vol ;
voice - > RVol = mix - > rvol ;
voice - > CVol = mix - > cvol ;
voice - > Pan = mix - > pan ;
voice - > Attribute = 0 ;
#if 0
voice - > Attribute = ( 1 < < ( 30 - 16 ) ) | ( 2 < < ( 26 - 16 ) ) |
( 0 < < ( 24 - 16 ) ) | ( 0x1f < < ( 19 - 16 ) ) ;
# else
voice - > Attribute = 0 ;
# endif
snd_trident_write_voice_regs ( trident , voice ) ;
if ( evoice ! = NULL ) {
evoice - > Delta = voice - > Delta ;
evoice - > spurious_threshold = voice - > spurious_threshold ;
evoice - > LBA = voice - > LBA ;
evoice - > CSO = 0 ;
evoice - > ESO = ( runtime - > period_size * 2 ) + 4 - 1 ; /* in samples */
evoice - > CTRL = voice - > CTRL ;
evoice - > FMC = 3 ;
evoice - > GVSel = trident - > device = = TRIDENT_DEVICE_ID_SI7018 ? 0 : 1 ;
evoice - > EC = 0 ;
evoice - > Alpha = 0 ;
evoice - > FMS = 0 ;
evoice - > Vol = 0x3ff ; /* mute */
evoice - > RVol = evoice - > CVol = 0x7f ; /* mute */
evoice - > Pan = 0x7f ; /* mute */
#if 0
evoice - > Attribute = ( 1 < < ( 30 - 16 ) ) | ( 2 < < ( 26 - 16 ) ) |
( 0 < < ( 24 - 16 ) ) | ( 0x1f < < ( 19 - 16 ) ) ;
# else
evoice - > Attribute = 0 ;
# endif
snd_trident_write_voice_regs ( trident , evoice ) ;
evoice - > isync2 = 1 ;
evoice - > isync_mark = runtime - > period_size ;
evoice - > ESO = ( runtime - > period_size * 2 ) - 1 ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_capture_hw_params
Description : Set the hardware parameters for the capture device .
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_capture_hw_params ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
return snd_trident_allocate_pcm_mem ( substream , hw_params ) ;
}
/*---------------------------------------------------------------------------
snd_trident_capture_prepare
Description : Prepare capture device for playback .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_capture_prepare ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
unsigned int val , ESO_bytes ;
spin_lock_irq ( & trident - > reg_lock ) ;
// Initilize the channel and set channel Mode
outb ( 0 , TRID_REG ( trident , LEGACY_DMAR15 ) ) ;
// Set DMA channel operation mode register
outb ( 0x54 , TRID_REG ( trident , LEGACY_DMAR11 ) ) ;
// Set channel buffer Address, DMAR0 expects contiguous PCI memory area
voice - > LBA = runtime - > dma_addr ;
outl ( voice - > LBA , TRID_REG ( trident , LEGACY_DMAR0 ) ) ;
if ( voice - > memblk )
voice - > LBA = voice - > memblk - > offset ;
// set ESO
ESO_bytes = snd_pcm_lib_buffer_bytes ( substream ) - 1 ;
outb ( ( ESO_bytes & 0x00ff0000 ) > > 16 , TRID_REG ( trident , LEGACY_DMAR6 ) ) ;
outw ( ( ESO_bytes & 0x0000ffff ) , TRID_REG ( trident , LEGACY_DMAR4 ) ) ;
ESO_bytes + + ;
// Set channel sample rate, 4.12 format
val = ( ( ( unsigned int ) 48000L < < 12 ) + ( runtime - > rate / 2 ) ) / runtime - > rate ;
outw ( val , TRID_REG ( trident , T4D_SBDELTA_DELTA_R ) ) ;
// Set channel interrupt blk length
if ( snd_pcm_format_width ( runtime - > format ) = = 16 ) {
val = ( unsigned short ) ( ( ESO_bytes > > 1 ) - 1 ) ;
} else {
val = ( unsigned short ) ( ESO_bytes - 1 ) ;
}
outl ( ( val < < 16 ) | val , TRID_REG ( trident , T4D_SBBL_SBCL ) ) ;
// Right now, set format and start to run captureing,
// continuous run loop enable.
trident - > bDMAStart = 0x19 ; // 0001 1001b
if ( snd_pcm_format_width ( runtime - > format ) = = 16 )
trident - > bDMAStart | = 0x80 ;
if ( snd_pcm_format_signed ( runtime - > format ) )
trident - > bDMAStart | = 0x20 ;
if ( runtime - > channels > 1 )
trident - > bDMAStart | = 0x40 ;
// Prepare capture intr channel
voice - > Delta = snd_trident_convert_rate ( runtime - > rate ) ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( runtime - > rate , runtime - > period_size ) ;
voice - > isync = 1 ;
voice - > isync_mark = runtime - > period_size ;
voice - > isync_max = runtime - > buffer_size ;
// Set voice parameters
voice - > CSO = 0 ;
voice - > ESO = voice - > isync_ESO = ( runtime - > period_size * 2 ) + 6 - 1 ;
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 3 ;
voice - > RVol = 0x7f ;
voice - > CVol = 0x7f ;
voice - > GVSel = 1 ;
voice - > Pan = 0x7f ; /* mute */
voice - > Vol = 0x3ff ; /* mute */
voice - > EC = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Attribute = 0 ;
snd_trident_write_voice_regs ( trident , voice ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_si7018_capture_hw_params
Description : Set the hardware parameters for the capture device .
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_si7018_capture_hw_params ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
int err ;
if ( ( err = snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( hw_params ) ) ) < 0 )
return err ;
return snd_trident_allocate_evoice ( substream , hw_params ) ;
}
/*---------------------------------------------------------------------------
snd_trident_si7018_capture_hw_free
Description : Release the hardware resources for the capture device .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_si7018_capture_hw_free ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice ? voice - > extra : NULL ;
snd_pcm_lib_free_pages ( substream ) ;
if ( evoice ! = NULL ) {
snd_trident_free_voice ( trident , evoice ) ;
voice - > extra = NULL ;
}
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_si7018_capture_prepare
Description : Prepare capture device for playback .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_si7018_capture_prepare ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice - > extra ;
spin_lock_irq ( & trident - > reg_lock ) ;
voice - > LBA = runtime - > dma_addr ;
voice - > Delta = snd_trident_convert_adc_rate ( runtime - > rate ) ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( runtime - > rate , runtime - > period_size ) ;
// Set voice parameters
voice - > CSO = 0 ;
voice - > ESO = runtime - > buffer_size - 1 ; /* in samples */
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 0 ;
voice - > RVol = 0 ;
voice - > CVol = 0 ;
voice - > GVSel = 1 ;
voice - > Pan = T4D_DEFAULT_PCM_PAN ;
voice - > Vol = 0 ;
voice - > EC = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Attribute = ( 2 < < ( 30 - 16 ) ) |
( 2 < < ( 26 - 16 ) ) |
( 2 < < ( 24 - 16 ) ) |
( 1 < < ( 23 - 16 ) ) ;
snd_trident_write_voice_regs ( trident , voice ) ;
if ( evoice ! = NULL ) {
evoice - > Delta = snd_trident_convert_rate ( runtime - > rate ) ;
evoice - > spurious_threshold = voice - > spurious_threshold ;
evoice - > LBA = voice - > LBA ;
evoice - > CSO = 0 ;
evoice - > ESO = ( runtime - > period_size * 2 ) + 20 - 1 ; /* in samples, 20 means correction */
evoice - > CTRL = voice - > CTRL ;
evoice - > FMC = 3 ;
evoice - > GVSel = 0 ;
evoice - > EC = 0 ;
evoice - > Alpha = 0 ;
evoice - > FMS = 0 ;
evoice - > Vol = 0x3ff ; /* mute */
evoice - > RVol = evoice - > CVol = 0x7f ; /* mute */
evoice - > Pan = 0x7f ; /* mute */
evoice - > Attribute = 0 ;
snd_trident_write_voice_regs ( trident , evoice ) ;
evoice - > isync2 = 1 ;
evoice - > isync_mark = runtime - > period_size ;
evoice - > ESO = ( runtime - > period_size * 2 ) - 1 ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_prepare
Description : Prepare foldback capture device for playback .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_foldback_prepare ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice - > extra ;
spin_lock_irq ( & trident - > reg_lock ) ;
/* Set channel buffer Address */
if ( voice - > memblk )
voice - > LBA = voice - > memblk - > offset ;
else
voice - > LBA = runtime - > dma_addr ;
/* set target ESO for channel */
voice - > ESO = runtime - > buffer_size - 1 ; /* in samples */
/* set sample rate */
voice - > Delta = 0x1000 ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( 48000 , runtime - > period_size ) ;
voice - > CSO = 0 ;
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 3 ;
voice - > RVol = 0x7f ;
voice - > CVol = 0x7f ;
voice - > GVSel = 1 ;
voice - > Pan = 0x7f ; /* mute */
voice - > Vol = 0x3ff ; /* mute */
voice - > EC = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Attribute = 0 ;
/* set up capture channel */
outb ( ( ( voice - > number & 0x3f ) | 0x80 ) , TRID_REG ( trident , T4D_RCI + voice - > foldback_chan ) ) ;
snd_trident_write_voice_regs ( trident , voice ) ;
if ( evoice ! = NULL ) {
evoice - > Delta = voice - > Delta ;
evoice - > spurious_threshold = voice - > spurious_threshold ;
evoice - > LBA = voice - > LBA ;
evoice - > CSO = 0 ;
evoice - > ESO = ( runtime - > period_size * 2 ) + 4 - 1 ; /* in samples */
evoice - > CTRL = voice - > CTRL ;
evoice - > FMC = 3 ;
evoice - > GVSel = trident - > device = = TRIDENT_DEVICE_ID_SI7018 ? 0 : 1 ;
evoice - > EC = 0 ;
evoice - > Alpha = 0 ;
evoice - > FMS = 0 ;
evoice - > Vol = 0x3ff ; /* mute */
evoice - > RVol = evoice - > CVol = 0x7f ; /* mute */
evoice - > Pan = 0x7f ; /* mute */
evoice - > Attribute = 0 ;
snd_trident_write_voice_regs ( trident , evoice ) ;
evoice - > isync2 = 1 ;
evoice - > isync_mark = runtime - > period_size ;
evoice - > ESO = ( runtime - > period_size * 2 ) - 1 ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif_hw_params
Description : Set the hardware parameters for the spdif device .
Parameters : substream - PCM substream class
hw_params - hardware parameters
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_hw_params ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
unsigned int old_bits = 0 , change = 0 ;
int err ;
err = snd_trident_allocate_pcm_mem ( substream , hw_params ) ;
if ( err < 0 )
return err ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
err = snd_trident_allocate_evoice ( substream , hw_params ) ;
if ( err < 0 )
return err ;
}
/* prepare SPDIF channel */
spin_lock_irq ( & trident - > reg_lock ) ;
old_bits = trident - > spdif_pcm_bits ;
if ( old_bits & IEC958_AES0_PROFESSIONAL )
trident - > spdif_pcm_bits & = ~ IEC958_AES0_PRO_FS ;
else
trident - > spdif_pcm_bits & = ~ ( IEC958_AES3_CON_FS < < 24 ) ;
if ( params_rate ( hw_params ) > = 48000 ) {
trident - > spdif_pcm_ctrl = 0x3c ; // 48000 Hz
trident - > spdif_pcm_bits | =
trident - > spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_48000 :
( IEC958_AES3_CON_FS_48000 < < 24 ) ;
}
else if ( params_rate ( hw_params ) > = 44100 ) {
trident - > spdif_pcm_ctrl = 0x3e ; // 44100 Hz
trident - > spdif_pcm_bits | =
trident - > spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_44100 :
( IEC958_AES3_CON_FS_44100 < < 24 ) ;
}
else {
trident - > spdif_pcm_ctrl = 0x3d ; // 32000 Hz
trident - > spdif_pcm_bits | =
trident - > spdif_bits & IEC958_AES0_PROFESSIONAL ?
IEC958_AES0_PRO_FS_32000 :
( IEC958_AES3_CON_FS_32000 < < 24 ) ;
}
change = old_bits ! = trident - > spdif_pcm_bits ;
spin_unlock_irq ( & trident - > reg_lock ) ;
if ( change )
snd_ctl_notify ( trident - > card , SNDRV_CTL_EVENT_MASK_VALUE , & trident - > spdif_pcm_ctl - > id ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif_prepare
Description : Prepare SPDIF device for playback .
Parameters : substream - PCM substream class
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_prepare ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_voice_t * evoice = voice - > extra ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ substream - > number ] ;
unsigned int RESO , LBAO ;
unsigned int temp ;
spin_lock_irq ( & trident - > reg_lock ) ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
/* set delta (rate) value */
voice - > Delta = snd_trident_convert_rate ( runtime - > rate ) ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( runtime - > rate , runtime - > period_size ) ;
/* set Loop Back Address */
LBAO = runtime - > dma_addr ;
if ( voice - > memblk )
voice - > LBA = voice - > memblk - > offset ;
else
voice - > LBA = LBAO ;
voice - > isync = 1 ;
voice - > isync3 = 1 ;
voice - > isync_mark = runtime - > period_size ;
voice - > isync_max = runtime - > buffer_size ;
/* set target ESO for channel */
RESO = runtime - > buffer_size - 1 ;
voice - > ESO = voice - > isync_ESO = ( runtime - > period_size * 2 ) + 6 - 1 ;
/* set ctrl mode */
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 3 ;
voice - > RVol = 0x7f ;
voice - > CVol = 0x7f ;
voice - > GVSel = 1 ;
voice - > Pan = 0x7f ;
voice - > Vol = 0x3ff ;
voice - > EC = 0 ;
voice - > CSO = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Attribute = 0 ;
/* prepare surrogate IRQ channel */
snd_trident_write_voice_regs ( trident , voice ) ;
outw ( ( RESO & 0xffff ) , TRID_REG ( trident , NX_SPESO ) ) ;
outb ( ( RESO > > 16 ) , TRID_REG ( trident , NX_SPESO + 2 ) ) ;
outl ( ( LBAO & 0xfffffffc ) , TRID_REG ( trident , NX_SPLBA ) ) ;
outw ( ( voice - > CSO & 0xffff ) , TRID_REG ( trident , NX_SPCTRL_SPCSO ) ) ;
outb ( ( voice - > CSO > > 16 ) , TRID_REG ( trident , NX_SPCTRL_SPCSO + 2 ) ) ;
/* set SPDIF setting */
outb ( trident - > spdif_pcm_ctrl , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
outl ( trident - > spdif_pcm_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
} else { /* SiS */
/* set delta (rate) value */
voice - > Delta = 0x800 ;
voice - > spurious_threshold = snd_trident_spurious_threshold ( 48000 , runtime - > period_size ) ;
/* set Loop Begin Address */
if ( voice - > memblk )
voice - > LBA = voice - > memblk - > offset ;
else
voice - > LBA = runtime - > dma_addr ;
voice - > CSO = 0 ;
voice - > ESO = runtime - > buffer_size - 1 ; /* in samples */
voice - > CTRL = snd_trident_control_mode ( substream ) ;
voice - > FMC = 3 ;
voice - > GVSel = 1 ;
voice - > EC = 0 ;
voice - > Alpha = 0 ;
voice - > FMS = 0 ;
voice - > Vol = mix - > vol ;
voice - > RVol = mix - > rvol ;
voice - > CVol = mix - > cvol ;
voice - > Pan = mix - > pan ;
voice - > Attribute = ( 1 < < ( 30 - 16 ) ) | ( 7 < < ( 26 - 16 ) ) |
( 0 < < ( 24 - 16 ) ) | ( 0 < < ( 19 - 16 ) ) ;
snd_trident_write_voice_regs ( trident , voice ) ;
if ( evoice ! = NULL ) {
evoice - > Delta = voice - > Delta ;
evoice - > spurious_threshold = voice - > spurious_threshold ;
evoice - > LBA = voice - > LBA ;
evoice - > CSO = 0 ;
evoice - > ESO = ( runtime - > period_size * 2 ) + 4 - 1 ; /* in samples */
evoice - > CTRL = voice - > CTRL ;
evoice - > FMC = 3 ;
evoice - > GVSel = trident - > device = = TRIDENT_DEVICE_ID_SI7018 ? 0 : 1 ;
evoice - > EC = 0 ;
evoice - > Alpha = 0 ;
evoice - > FMS = 0 ;
evoice - > Vol = 0x3ff ; /* mute */
evoice - > RVol = evoice - > CVol = 0x7f ; /* mute */
evoice - > Pan = 0x7f ; /* mute */
evoice - > Attribute = 0 ;
snd_trident_write_voice_regs ( trident , evoice ) ;
evoice - > isync2 = 1 ;
evoice - > isync_mark = runtime - > period_size ;
evoice - > ESO = ( runtime - > period_size * 2 ) - 1 ;
}
outl ( trident - > spdif_pcm_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
temp = inl ( TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
temp & = ~ ( 1 < < 19 ) ;
outl ( temp , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
temp = inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
temp | = SPDIF_EN ;
outl ( temp , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_trigger
Description : Start / stop devices
Parameters : substream - PCM substream class
cmd - trigger command ( STOP , GO )
Returns : Error status
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_trigger ( snd_pcm_substream_t * substream ,
int cmd )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
struct list_head * pos ;
snd_pcm_substream_t * s ;
unsigned int what , whati , capture_flag , spdif_flag ;
snd_trident_voice_t * voice , * evoice ;
unsigned int val , go ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
case SNDRV_PCM_TRIGGER_RESUME :
go = 1 ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
case SNDRV_PCM_TRIGGER_SUSPEND :
go = 0 ;
break ;
default :
return - EINVAL ;
}
what = whati = capture_flag = spdif_flag = 0 ;
spin_lock ( & trident - > reg_lock ) ;
val = inl ( TRID_REG ( trident , T4D_STIMER ) ) & 0x00ffffff ;
snd_pcm_group_for_each ( pos , substream ) {
s = snd_pcm_group_substream_entry ( pos ) ;
if ( ( trident_t * ) snd_pcm_substream_chip ( s ) = = trident ) {
voice = ( snd_trident_voice_t * ) s - > runtime - > private_data ;
evoice = voice - > extra ;
what | = 1 < < ( voice - > number & 0x1f ) ;
if ( evoice = = NULL ) {
whati | = 1 < < ( voice - > number & 0x1f ) ;
} else {
what | = 1 < < ( evoice - > number & 0x1f ) ;
whati | = 1 < < ( evoice - > number & 0x1f ) ;
if ( go )
evoice - > stimer = val ;
}
if ( go ) {
voice - > running = 1 ;
voice - > stimer = val ;
} else {
voice - > running = 0 ;
}
snd_pcm_trigger_done ( s , substream ) ;
if ( voice - > capture )
capture_flag = 1 ;
if ( voice - > spdif )
spdif_flag = 1 ;
}
}
if ( spdif_flag ) {
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
outl ( trident - > spdif_pcm_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
outb ( trident - > spdif_pcm_ctrl , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
} else {
outl ( trident - > spdif_pcm_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
val = inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) | SPDIF_EN ;
outl ( val , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
}
}
if ( ! go )
outl ( what , TRID_REG ( trident , T4D_STOP_B ) ) ;
val = inl ( TRID_REG ( trident , T4D_AINTEN_B ) ) ;
if ( go ) {
val | = whati ;
} else {
val & = ~ whati ;
}
outl ( val , TRID_REG ( trident , T4D_AINTEN_B ) ) ;
if ( go ) {
outl ( what , TRID_REG ( trident , T4D_START_B ) ) ;
if ( capture_flag & & trident - > device ! = TRIDENT_DEVICE_ID_SI7018 )
outb ( trident - > bDMAStart , TRID_REG ( trident , T4D_SBCTRL_SBE2R_SBDD ) ) ;
} else {
if ( capture_flag & & trident - > device ! = TRIDENT_DEVICE_ID_SI7018 )
outb ( 0x00 , TRID_REG ( trident , T4D_SBCTRL_SBE2R_SBDD ) ) ;
}
spin_unlock ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_playback_pointer
Description : This routine return the playback position
Parameters : substream - PCM substream class
Returns : position of buffer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static snd_pcm_uframes_t snd_trident_playback_pointer ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
unsigned int cso ;
if ( ! voice - > running )
return 0 ;
spin_lock ( & trident - > reg_lock ) ;
outb ( voice - > number , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_NX ) {
cso = inw ( TRID_REG ( trident , CH_DX_CSO_ALPHA_FMS + 2 ) ) ;
} else { // ID_4DWAVE_NX
cso = ( unsigned int ) inl ( TRID_REG ( trident , CH_NX_DELTA_CSO ) ) & 0x00ffffff ;
}
spin_unlock ( & trident - > reg_lock ) ;
if ( cso > = runtime - > buffer_size )
cso = 0 ;
return cso ;
}
/*---------------------------------------------------------------------------
snd_trident_capture_pointer
Description : This routine return the capture position
Paramters : pcm1 - PCM device class
Returns : position of buffer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static snd_pcm_uframes_t snd_trident_capture_pointer ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
unsigned int result ;
if ( ! voice - > running )
return 0 ;
result = inw ( TRID_REG ( trident , T4D_SBBL_SBCL ) ) ;
if ( runtime - > channels > 1 )
result > > = 1 ;
if ( result > 0 )
result = runtime - > buffer_size - result ;
return result ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif_pointer
Description : This routine return the SPDIF playback position
Parameters : substream - PCM substream class
Returns : position of buffer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static snd_pcm_uframes_t snd_trident_spdif_pointer ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
unsigned int result ;
if ( ! voice - > running )
return 0 ;
result = inl ( TRID_REG ( trident , NX_SPCTRL_SPCSO ) ) & 0x00ffffff ;
return result ;
}
/*
* Playback support device description
*/
static snd_pcm_hardware_t snd_trident_playback =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
2005-08-18 15:43:12 +04:00
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */ ) ,
2005-04-17 02:20:36 +04:00
. formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE ) ,
. rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 ,
. rate_min = 4000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 256 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 256 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
/*
* Capture support device description
*/
static snd_pcm_hardware_t snd_trident_capture =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
2005-08-18 15:43:12 +04:00
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */ ) ,
2005-04-17 02:20:36 +04:00
. formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE ) ,
. rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 ,
. rate_min = 4000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 128 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
/*
* Foldback capture support device description
*/
static snd_pcm_hardware_t snd_trident_foldback =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
2005-08-18 15:43:12 +04:00
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */ ) ,
2005-04-17 02:20:36 +04:00
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_48000 ,
. rate_min = 48000 ,
. rate_max = 48000 ,
. channels_min = 2 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 128 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
/*
* SPDIF playback support device description
*/
static snd_pcm_hardware_t snd_trident_spdif =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
2005-08-18 15:43:12 +04:00
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */ ) ,
2005-04-17 02:20:36 +04:00
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = ( SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 ) ,
. rate_min = 32000 ,
. rate_max = 48000 ,
. channels_min = 2 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 128 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
static snd_pcm_hardware_t snd_trident_spdif_7018 =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
2005-08-18 15:43:12 +04:00
SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */ ) ,
2005-04-17 02:20:36 +04:00
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_48000 ,
. rate_min = 48000 ,
. rate_max = 48000 ,
. channels_min = 2 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 128 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
static void snd_trident_pcm_free_substream ( snd_pcm_runtime_t * runtime )
{
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
trident_t * trident ;
if ( voice ) {
trident = voice - > trident ;
snd_trident_free_voice ( trident , voice ) ;
}
}
static int snd_trident_playback_open ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice ;
voice = snd_trident_alloc_voice ( trident , SNDRV_TRIDENT_VOICE_TYPE_PCM , 0 , 0 ) ;
if ( voice = = NULL )
return - EAGAIN ;
snd_trident_pcm_mixer_build ( trident , voice , substream ) ;
voice - > substream = substream ;
runtime - > private_data = voice ;
runtime - > private_free = snd_trident_pcm_free_substream ;
runtime - > hw = snd_trident_playback ;
snd_pcm_set_sync ( substream ) ;
snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_BUFFER_SIZE , 0 , 64 * 1024 ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_playback_close
Description : This routine will close the 4 DWave playback device . For now
we will simply free the dma transfer buffer .
Parameters : substream - PCM substream class
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_playback_close ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
snd_trident_voice_t * voice = ( snd_trident_voice_t * ) runtime - > private_data ;
snd_trident_pcm_mixer_free ( trident , voice , substream ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif_open
Description : This routine will open the 4 DWave SPDIF device .
Parameters : substream - PCM substream class
Returns : status - success or failure flag
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_open ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_trident_voice_t * voice ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
voice = snd_trident_alloc_voice ( trident , SNDRV_TRIDENT_VOICE_TYPE_PCM , 0 , 0 ) ;
if ( voice = = NULL )
return - EAGAIN ;
voice - > spdif = 1 ;
voice - > substream = substream ;
spin_lock_irq ( & trident - > reg_lock ) ;
trident - > spdif_pcm_bits = trident - > spdif_bits ;
spin_unlock_irq ( & trident - > reg_lock ) ;
runtime - > private_data = voice ;
runtime - > private_free = snd_trident_pcm_free_substream ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
runtime - > hw = snd_trident_spdif ;
} else {
runtime - > hw = snd_trident_spdif_7018 ;
}
trident - > spdif_pcm_ctl - > vd [ 0 ] . access & = ~ SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
snd_ctl_notify ( trident - > card , SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO , & trident - > spdif_pcm_ctl - > id ) ;
snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_BUFFER_SIZE , 0 , 64 * 1024 ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif_close
Description : This routine will close the 4 DWave SPDIF device .
Parameters : substream - PCM substream class
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_close ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
unsigned int temp ;
spin_lock_irq ( & trident - > reg_lock ) ;
// restore default SPDIF setting
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
outb ( trident - > spdif_ctrl , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
outl ( trident - > spdif_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
} else {
outl ( trident - > spdif_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
temp = inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
if ( trident - > spdif_ctrl ) {
temp | = SPDIF_EN ;
} else {
temp & = ~ SPDIF_EN ;
}
outl ( temp , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
trident - > spdif_pcm_ctl - > vd [ 0 ] . access | = SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
snd_ctl_notify ( trident - > card , SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO , & trident - > spdif_pcm_ctl - > id ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_capture_open
Description : This routine will open the 4 DWave capture device .
Parameters : substream - PCM substream class
Returns : status - success or failure flag
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_capture_open ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_trident_voice_t * voice ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
voice = snd_trident_alloc_voice ( trident , SNDRV_TRIDENT_VOICE_TYPE_PCM , 0 , 0 ) ;
if ( voice = = NULL )
return - EAGAIN ;
voice - > capture = 1 ;
voice - > substream = substream ;
runtime - > private_data = voice ;
runtime - > private_free = snd_trident_pcm_free_substream ;
runtime - > hw = snd_trident_capture ;
snd_pcm_set_sync ( substream ) ;
snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_BUFFER_SIZE , 0 , 64 * 1024 ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_capture_close
Description : This routine will close the 4 DWave capture device . For now
we will simply free the dma transfer buffer .
Parameters : substream - PCM substream class
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_capture_close ( snd_pcm_substream_t * substream )
{
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_open
Description : This routine will open the 4 DWave foldback capture device .
Parameters : substream - PCM substream class
Returns : status - success or failure flag
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_foldback_open ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_trident_voice_t * voice ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
voice = snd_trident_alloc_voice ( trident , SNDRV_TRIDENT_VOICE_TYPE_PCM , 0 , 0 ) ;
if ( voice = = NULL )
return - EAGAIN ;
voice - > foldback_chan = substream - > number ;
voice - > substream = substream ;
runtime - > private_data = voice ;
runtime - > private_free = snd_trident_pcm_free_substream ;
runtime - > hw = snd_trident_foldback ;
snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_BUFFER_SIZE , 0 , 64 * 1024 ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_close
Description : This routine will close the 4 DWave foldback capture device .
For now we will simply free the dma transfer buffer .
Parameters : substream - PCM substream class
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_foldback_close ( snd_pcm_substream_t * substream )
{
trident_t * trident = snd_pcm_substream_chip ( substream ) ;
snd_trident_voice_t * voice ;
snd_pcm_runtime_t * runtime = substream - > runtime ;
voice = ( snd_trident_voice_t * ) runtime - > private_data ;
/* stop capture channel */
spin_lock_irq ( & trident - > reg_lock ) ;
outb ( 0x00 , TRID_REG ( trident , T4D_RCI + voice - > foldback_chan ) ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
PCM operations
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static snd_pcm_ops_t snd_trident_playback_ops = {
. open = snd_trident_playback_open ,
. close = snd_trident_playback_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_playback_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
} ;
static snd_pcm_ops_t snd_trident_nx_playback_ops = {
. open = snd_trident_playback_open ,
. close = snd_trident_playback_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_playback_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
. page = snd_pcm_sgbuf_ops_page ,
} ;
static snd_pcm_ops_t snd_trident_capture_ops = {
. open = snd_trident_capture_open ,
. close = snd_trident_capture_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_capture_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_capture_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_capture_pointer ,
} ;
static snd_pcm_ops_t snd_trident_si7018_capture_ops = {
. open = snd_trident_capture_open ,
. close = snd_trident_capture_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_si7018_capture_hw_params ,
. hw_free = snd_trident_si7018_capture_hw_free ,
. prepare = snd_trident_si7018_capture_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
} ;
static snd_pcm_ops_t snd_trident_foldback_ops = {
. open = snd_trident_foldback_open ,
. close = snd_trident_foldback_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_foldback_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
} ;
static snd_pcm_ops_t snd_trident_nx_foldback_ops = {
. open = snd_trident_foldback_open ,
. close = snd_trident_foldback_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_foldback_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
. page = snd_pcm_sgbuf_ops_page ,
} ;
static snd_pcm_ops_t snd_trident_spdif_ops = {
. open = snd_trident_spdif_open ,
. close = snd_trident_spdif_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_spdif_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_spdif_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_spdif_pointer ,
} ;
static snd_pcm_ops_t snd_trident_spdif_7018_ops = {
. open = snd_trident_spdif_open ,
. close = snd_trident_spdif_close ,
. ioctl = snd_trident_ioctl ,
. hw_params = snd_trident_spdif_hw_params ,
. hw_free = snd_trident_hw_free ,
. prepare = snd_trident_spdif_prepare ,
. trigger = snd_trident_trigger ,
. pointer = snd_trident_playback_pointer ,
} ;
/*---------------------------------------------------------------------------
snd_trident_pcm
Description : This routine registers the 4 DWave device for PCM support .
Paramters : trident - pointer to target device class for 4 DWave .
Returns : None
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int __devinit snd_trident_pcm ( trident_t * trident , int device , snd_pcm_t * * rpcm )
{
snd_pcm_t * pcm ;
int err ;
if ( rpcm )
* rpcm = NULL ;
if ( ( err = snd_pcm_new ( trident - > card , " trident_dx_nx " , device , trident - > ChanPCM , 1 , & pcm ) ) < 0 )
return err ;
pcm - > private_data = trident ;
if ( trident - > tlb . entries ) {
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_trident_nx_playback_ops ) ;
} else {
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_trident_playback_ops ) ;
}
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE ,
trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ?
& snd_trident_capture_ops :
& snd_trident_si7018_capture_ops ) ;
pcm - > info_flags = 0 ;
pcm - > dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX ;
strcpy ( pcm - > name , " Trident 4DWave " ) ;
trident - > pcm = pcm ;
if ( trident - > tlb . entries ) {
snd_pcm_substream_t * substream ;
for ( substream = pcm - > streams [ SNDRV_PCM_STREAM_PLAYBACK ] . substream ; substream ; substream = substream - > next )
snd_pcm_lib_preallocate_pages ( substream , SNDRV_DMA_TYPE_DEV_SG ,
snd_dma_pci_data ( trident - > pci ) ,
64 * 1024 , 128 * 1024 ) ;
snd_pcm_lib_preallocate_pages ( pcm - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ,
SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( trident - > pci ) ,
64 * 1024 , 128 * 1024 ) ;
} else {
snd_pcm_lib_preallocate_pages_for_all ( pcm , SNDRV_DMA_TYPE_DEV ,
snd_dma_pci_data ( trident - > pci ) , 64 * 1024 , 128 * 1024 ) ;
}
if ( rpcm )
* rpcm = pcm ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_foldback_pcm
Description : This routine registers the 4 DWave device for foldback PCM support .
Paramters : trident - pointer to target device class for 4 DWave .
Returns : None
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int __devinit snd_trident_foldback_pcm ( trident_t * trident , int device , snd_pcm_t * * rpcm )
{
snd_pcm_t * foldback ;
int err ;
int num_chan = 3 ;
snd_pcm_substream_t * substream ;
if ( rpcm )
* rpcm = NULL ;
if ( trident - > device = = TRIDENT_DEVICE_ID_NX )
num_chan = 4 ;
if ( ( err = snd_pcm_new ( trident - > card , " trident_dx_nx " , device , 0 , num_chan , & foldback ) ) < 0 )
return err ;
foldback - > private_data = trident ;
if ( trident - > tlb . entries )
snd_pcm_set_ops ( foldback , SNDRV_PCM_STREAM_CAPTURE , & snd_trident_nx_foldback_ops ) ;
else
snd_pcm_set_ops ( foldback , SNDRV_PCM_STREAM_CAPTURE , & snd_trident_foldback_ops ) ;
foldback - > info_flags = 0 ;
strcpy ( foldback - > name , " Trident 4DWave " ) ;
substream = foldback - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ;
strcpy ( substream - > name , " Front Mixer " ) ;
substream = substream - > next ;
strcpy ( substream - > name , " Reverb Mixer " ) ;
substream = substream - > next ;
strcpy ( substream - > name , " Chorus Mixer " ) ;
if ( num_chan = = 4 ) {
substream = substream - > next ;
strcpy ( substream - > name , " Second AC'97 ADC " ) ;
}
trident - > foldback = foldback ;
if ( trident - > tlb . entries )
snd_pcm_lib_preallocate_pages_for_all ( foldback , SNDRV_DMA_TYPE_DEV_SG ,
snd_dma_pci_data ( trident - > pci ) , 0 , 128 * 1024 ) ;
else
snd_pcm_lib_preallocate_pages_for_all ( foldback , SNDRV_DMA_TYPE_DEV ,
snd_dma_pci_data ( trident - > pci ) , 64 * 1024 , 128 * 1024 ) ;
if ( rpcm )
* rpcm = foldback ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_spdif
Description : This routine registers the 4 DWave - NX device for SPDIF support .
Paramters : trident - pointer to target device class for 4 DWave - NX .
Returns : None
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int __devinit snd_trident_spdif_pcm ( trident_t * trident , int device , snd_pcm_t * * rpcm )
{
snd_pcm_t * spdif ;
int err ;
if ( rpcm )
* rpcm = NULL ;
if ( ( err = snd_pcm_new ( trident - > card , " trident_dx_nx IEC958 " , device , 1 , 0 , & spdif ) ) < 0 )
return err ;
spdif - > private_data = trident ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
snd_pcm_set_ops ( spdif , SNDRV_PCM_STREAM_PLAYBACK , & snd_trident_spdif_ops ) ;
} else {
snd_pcm_set_ops ( spdif , SNDRV_PCM_STREAM_PLAYBACK , & snd_trident_spdif_7018_ops ) ;
}
spdif - > info_flags = 0 ;
strcpy ( spdif - > name , " Trident 4DWave IEC958 " ) ;
trident - > spdif = spdif ;
snd_pcm_lib_preallocate_pages_for_all ( spdif , SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( trident - > pci ) , 64 * 1024 , 128 * 1024 ) ;
if ( rpcm )
* rpcm = spdif ;
return 0 ;
}
/*
* Mixer part
*/
/*---------------------------------------------------------------------------
snd_trident_spdif_control
Description : enable / disable S / PDIF out from ac97 mixer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
static int snd_trident_spdif_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned char val ;
spin_lock_irq ( & trident - > reg_lock ) ;
val = trident - > spdif_ctrl ;
ucontrol - > value . integer . value [ 0 ] = val = = kcontrol - > private_value ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
static int snd_trident_spdif_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned char val ;
int change ;
val = ucontrol - > value . integer . value [ 0 ] ? ( unsigned char ) kcontrol - > private_value : 0x00 ;
spin_lock_irq ( & trident - > reg_lock ) ;
/* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */
change = trident - > spdif_ctrl ! = val ;
trident - > spdif_ctrl = val ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
if ( ( inb ( TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) & 0x10 ) = = 0 ) {
outl ( trident - > spdif_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
outb ( trident - > spdif_ctrl , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
}
} else {
if ( trident - > spdif = = NULL ) {
unsigned int temp ;
outl ( trident - > spdif_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
temp = inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) & ~ SPDIF_EN ;
if ( val )
temp | = SPDIF_EN ;
outl ( temp , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
}
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_spdif_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = SNDRV_CTL_NAME_IEC958 ( " " , PLAYBACK , SWITCH ) ,
. info = snd_trident_spdif_control_info ,
. get = snd_trident_spdif_control_get ,
. put = snd_trident_spdif_control_put ,
. private_value = 0x28 ,
} ;
/*---------------------------------------------------------------------------
snd_trident_spdif_default
Description : put / get the S / PDIF default settings
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_default_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_IEC958 ;
uinfo - > count = 1 ;
return 0 ;
}
static int snd_trident_spdif_default_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
ucontrol - > value . iec958 . status [ 0 ] = ( trident - > spdif_bits > > 0 ) & 0xff ;
ucontrol - > value . iec958 . status [ 1 ] = ( trident - > spdif_bits > > 8 ) & 0xff ;
ucontrol - > value . iec958 . status [ 2 ] = ( trident - > spdif_bits > > 16 ) & 0xff ;
ucontrol - > value . iec958 . status [ 3 ] = ( trident - > spdif_bits > > 24 ) & 0xff ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
static int snd_trident_spdif_default_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned int val ;
int change ;
val = ( ucontrol - > value . iec958 . status [ 0 ] < < 0 ) |
( ucontrol - > value . iec958 . status [ 1 ] < < 8 ) |
( ucontrol - > value . iec958 . status [ 2 ] < < 16 ) |
( ucontrol - > value . iec958 . status [ 3 ] < < 24 ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
change = trident - > spdif_bits ! = val ;
trident - > spdif_bits = val ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
if ( ( inb ( TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) & 0x10 ) = = 0 )
outl ( trident - > spdif_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
} else {
if ( trident - > spdif = = NULL )
outl ( trident - > spdif_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_spdif_default __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_PCM ,
. name = SNDRV_CTL_NAME_IEC958 ( " " , PLAYBACK , DEFAULT ) ,
. info = snd_trident_spdif_default_info ,
. get = snd_trident_spdif_default_get ,
. put = snd_trident_spdif_default_put
} ;
/*---------------------------------------------------------------------------
snd_trident_spdif_mask
Description : put / get the S / PDIF mask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_mask_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_IEC958 ;
uinfo - > count = 1 ;
return 0 ;
}
static int snd_trident_spdif_mask_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
ucontrol - > value . iec958 . status [ 0 ] = 0xff ;
ucontrol - > value . iec958 . status [ 1 ] = 0xff ;
ucontrol - > value . iec958 . status [ 2 ] = 0xff ;
ucontrol - > value . iec958 . status [ 3 ] = 0xff ;
return 0 ;
}
static snd_kcontrol_new_t snd_trident_spdif_mask __devinitdata =
{
. access = SNDRV_CTL_ELEM_ACCESS_READ ,
. iface = SNDRV_CTL_ELEM_IFACE_PCM ,
. name = SNDRV_CTL_NAME_IEC958 ( " " , PLAYBACK , MASK ) ,
. info = snd_trident_spdif_mask_info ,
. get = snd_trident_spdif_mask_get ,
} ;
/*---------------------------------------------------------------------------
snd_trident_spdif_stream
Description : put / get the S / PDIF stream settings
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_spdif_stream_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_IEC958 ;
uinfo - > count = 1 ;
return 0 ;
}
static int snd_trident_spdif_stream_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
ucontrol - > value . iec958 . status [ 0 ] = ( trident - > spdif_pcm_bits > > 0 ) & 0xff ;
ucontrol - > value . iec958 . status [ 1 ] = ( trident - > spdif_pcm_bits > > 8 ) & 0xff ;
ucontrol - > value . iec958 . status [ 2 ] = ( trident - > spdif_pcm_bits > > 16 ) & 0xff ;
ucontrol - > value . iec958 . status [ 3 ] = ( trident - > spdif_pcm_bits > > 24 ) & 0xff ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
static int snd_trident_spdif_stream_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned int val ;
int change ;
val = ( ucontrol - > value . iec958 . status [ 0 ] < < 0 ) |
( ucontrol - > value . iec958 . status [ 1 ] < < 8 ) |
( ucontrol - > value . iec958 . status [ 2 ] < < 16 ) |
( ucontrol - > value . iec958 . status [ 3 ] < < 24 ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
change = trident - > spdif_pcm_bits ! = val ;
trident - > spdif_pcm_bits = val ;
if ( trident - > spdif ! = NULL ) {
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
outl ( trident - > spdif_pcm_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
} else {
outl ( trident - > spdif_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
}
}
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_spdif_stream __devinitdata =
{
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE ,
. iface = SNDRV_CTL_ELEM_IFACE_PCM ,
. name = SNDRV_CTL_NAME_IEC958 ( " " , PLAYBACK , PCM_STREAM ) ,
. info = snd_trident_spdif_stream_info ,
. get = snd_trident_spdif_stream_get ,
. put = snd_trident_spdif_stream_put
} ;
/*---------------------------------------------------------------------------
snd_trident_ac97_control
Description : enable / disable rear path for ac97
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_ac97_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
static int snd_trident_ac97_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned char val ;
spin_lock_irq ( & trident - > reg_lock ) ;
val = trident - > ac97_ctrl = inl ( TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
ucontrol - > value . integer . value [ 0 ] = ( val & ( 1 < < kcontrol - > private_value ) ) ? 1 : 0 ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return 0 ;
}
static int snd_trident_ac97_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned char val ;
int change = 0 ;
spin_lock_irq ( & trident - > reg_lock ) ;
val = trident - > ac97_ctrl = inl ( TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
val & = ~ ( 1 < < kcontrol - > private_value ) ;
if ( ucontrol - > value . integer . value [ 0 ] )
val | = 1 < < kcontrol - > private_value ;
change = val ! = trident - > ac97_ctrl ;
trident - > ac97_ctrl = val ;
outl ( trident - > ac97_ctrl = val , TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_ac97_rear_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Rear Path " ,
. info = snd_trident_ac97_control_info ,
. get = snd_trident_ac97_control_get ,
. put = snd_trident_ac97_control_put ,
. private_value = 4 ,
} ;
/*---------------------------------------------------------------------------
snd_trident_vol_control
Description : wave & music volume control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_vol_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 2 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 255 ;
return 0 ;
}
static int snd_trident_vol_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned int val ;
val = trident - > musicvol_wavevol ;
ucontrol - > value . integer . value [ 0 ] = 255 - ( ( val > > kcontrol - > private_value ) & 0xff ) ;
ucontrol - > value . integer . value [ 1 ] = 255 - ( ( val > > ( kcontrol - > private_value + 8 ) ) & 0xff ) ;
return 0 ;
}
static int snd_trident_vol_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
unsigned int val ;
int change = 0 ;
spin_lock_irq ( & trident - > reg_lock ) ;
val = trident - > musicvol_wavevol ;
val & = ~ ( 0xffff < < kcontrol - > private_value ) ;
val | = ( ( 255 - ( ucontrol - > value . integer . value [ 0 ] & 0xff ) ) |
( ( 255 - ( ucontrol - > value . integer . value [ 1 ] & 0xff ) ) < < 8 ) ) < < kcontrol - > private_value ;
change = val ! = trident - > musicvol_wavevol ;
outl ( trident - > musicvol_wavevol = val , TRID_REG ( trident , T4D_MUSICVOL_WAVEVOL ) ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_vol_music_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Music Playback Volume " ,
. info = snd_trident_vol_control_info ,
. get = snd_trident_vol_control_get ,
. put = snd_trident_vol_control_put ,
. private_value = 16 ,
} ;
static snd_kcontrol_new_t snd_trident_vol_wave_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Wave Playback Volume " ,
. info = snd_trident_vol_control_info ,
. get = snd_trident_vol_control_get ,
. put = snd_trident_vol_control_put ,
. private_value = 0 ,
} ;
/*---------------------------------------------------------------------------
snd_trident_pcm_vol_control
Description : PCM front volume control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_pcm_vol_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 255 ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 )
uinfo - > value . integer . max = 1023 ;
return 0 ;
}
static int snd_trident_pcm_vol_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
ucontrol - > value . integer . value [ 0 ] = 1023 - mix - > vol ;
} else {
ucontrol - > value . integer . value [ 0 ] = 255 - ( mix - > vol > > 2 ) ;
}
return 0 ;
}
static int snd_trident_pcm_vol_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
unsigned int val ;
int change = 0 ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
val = 1023 - ( ucontrol - > value . integer . value [ 0 ] & 1023 ) ;
} else {
val = ( 255 - ( ucontrol - > value . integer . value [ 0 ] & 255 ) ) < < 2 ;
}
spin_lock_irq ( & trident - > reg_lock ) ;
change = val ! = mix - > vol ;
mix - > vol = val ;
if ( mix - > voice ! = NULL )
snd_trident_write_vol_reg ( trident , mix - > voice , val ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_pcm_vol_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " PCM Front Playback Volume " ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE ,
. count = 32 ,
. info = snd_trident_pcm_vol_control_info ,
. get = snd_trident_pcm_vol_control_get ,
. put = snd_trident_pcm_vol_control_put ,
} ;
/*---------------------------------------------------------------------------
snd_trident_pcm_pan_control
Description : PCM front pan control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_pcm_pan_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 127 ;
return 0 ;
}
static int snd_trident_pcm_pan_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
ucontrol - > value . integer . value [ 0 ] = mix - > pan ;
if ( ucontrol - > value . integer . value [ 0 ] & 0x40 ) {
ucontrol - > value . integer . value [ 0 ] = ( 0x3f - ( ucontrol - > value . integer . value [ 0 ] & 0x3f ) ) ;
} else {
ucontrol - > value . integer . value [ 0 ] | = 0x40 ;
}
return 0 ;
}
static int snd_trident_pcm_pan_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
unsigned char val ;
int change = 0 ;
if ( ucontrol - > value . integer . value [ 0 ] & 0x40 )
val = ucontrol - > value . integer . value [ 0 ] & 0x3f ;
else
val = ( 0x3f - ( ucontrol - > value . integer . value [ 0 ] & 0x3f ) ) | 0x40 ;
spin_lock_irq ( & trident - > reg_lock ) ;
change = val ! = mix - > pan ;
mix - > pan = val ;
if ( mix - > voice ! = NULL )
snd_trident_write_pan_reg ( trident , mix - > voice , val ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_pcm_pan_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " PCM Pan Playback Control " ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE ,
. count = 32 ,
. info = snd_trident_pcm_pan_control_info ,
. get = snd_trident_pcm_pan_control_get ,
. put = snd_trident_pcm_pan_control_put ,
} ;
/*---------------------------------------------------------------------------
snd_trident_pcm_rvol_control
Description : PCM reverb volume control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_pcm_rvol_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 127 ;
return 0 ;
}
static int snd_trident_pcm_rvol_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
ucontrol - > value . integer . value [ 0 ] = 127 - mix - > rvol ;
return 0 ;
}
static int snd_trident_pcm_rvol_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
unsigned short val ;
int change = 0 ;
val = 0x7f - ( ucontrol - > value . integer . value [ 0 ] & 0x7f ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
change = val ! = mix - > rvol ;
mix - > rvol = val ;
if ( mix - > voice ! = NULL )
snd_trident_write_rvol_reg ( trident , mix - > voice , val ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_pcm_rvol_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " PCM Reverb Playback Volume " ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE ,
. count = 32 ,
. info = snd_trident_pcm_rvol_control_info ,
. get = snd_trident_pcm_rvol_control_get ,
. put = snd_trident_pcm_rvol_control_put ,
} ;
/*---------------------------------------------------------------------------
snd_trident_pcm_cvol_control
Description : PCM chorus volume control
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_pcm_cvol_control_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 127 ;
return 0 ;
}
static int snd_trident_pcm_cvol_control_get ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
ucontrol - > value . integer . value [ 0 ] = 127 - mix - > cvol ;
return 0 ;
}
static int snd_trident_pcm_cvol_control_put ( snd_kcontrol_t * kcontrol ,
snd_ctl_elem_value_t * ucontrol )
{
trident_t * trident = snd_kcontrol_chip ( kcontrol ) ;
snd_trident_pcm_mixer_t * mix = & trident - > pcm_mixer [ snd_ctl_get_ioffnum ( kcontrol , & ucontrol - > id ) ] ;
unsigned short val ;
int change = 0 ;
val = 0x7f - ( ucontrol - > value . integer . value [ 0 ] & 0x7f ) ;
spin_lock_irq ( & trident - > reg_lock ) ;
change = val ! = mix - > cvol ;
mix - > cvol = val ;
if ( mix - > voice ! = NULL )
snd_trident_write_cvol_reg ( trident , mix - > voice , val ) ;
spin_unlock_irq ( & trident - > reg_lock ) ;
return change ;
}
static snd_kcontrol_new_t snd_trident_pcm_cvol_control __devinitdata =
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " PCM Chorus Playback Volume " ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE ,
. count = 32 ,
. info = snd_trident_pcm_cvol_control_info ,
. get = snd_trident_pcm_cvol_control_get ,
. put = snd_trident_pcm_cvol_control_put ,
} ;
static void snd_trident_notify_pcm_change1 ( snd_card_t * card , snd_kcontrol_t * kctl , int num , int activate )
{
snd_ctl_elem_id_t id ;
2005-10-10 13:46:31 +04:00
if ( ! kctl )
return ;
2005-04-17 02:20:36 +04:00
if ( activate )
kctl - > vd [ num ] . access & = ~ SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
else
kctl - > vd [ num ] . access | = SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO ,
snd_ctl_build_ioff ( & id , kctl , num ) ) ;
}
static void snd_trident_notify_pcm_change ( trident_t * trident , snd_trident_pcm_mixer_t * tmix , int num , int activate )
{
snd_trident_notify_pcm_change1 ( trident - > card , trident - > ctl_vol , num , activate ) ;
snd_trident_notify_pcm_change1 ( trident - > card , trident - > ctl_pan , num , activate ) ;
snd_trident_notify_pcm_change1 ( trident - > card , trident - > ctl_rvol , num , activate ) ;
snd_trident_notify_pcm_change1 ( trident - > card , trident - > ctl_cvol , num , activate ) ;
}
static int snd_trident_pcm_mixer_build ( trident_t * trident , snd_trident_voice_t * voice , snd_pcm_substream_t * substream )
{
snd_trident_pcm_mixer_t * tmix ;
snd_assert ( trident ! = NULL & & voice ! = NULL & & substream ! = NULL , return - EINVAL ) ;
tmix = & trident - > pcm_mixer [ substream - > number ] ;
tmix - > voice = voice ;
tmix - > vol = T4D_DEFAULT_PCM_VOL ;
tmix - > pan = T4D_DEFAULT_PCM_PAN ;
tmix - > rvol = T4D_DEFAULT_PCM_RVOL ;
tmix - > cvol = T4D_DEFAULT_PCM_CVOL ;
snd_trident_notify_pcm_change ( trident , tmix , substream - > number , 1 ) ;
return 0 ;
}
static int snd_trident_pcm_mixer_free ( trident_t * trident , snd_trident_voice_t * voice , snd_pcm_substream_t * substream )
{
snd_trident_pcm_mixer_t * tmix ;
snd_assert ( trident ! = NULL & & substream ! = NULL , return - EINVAL ) ;
tmix = & trident - > pcm_mixer [ substream - > number ] ;
tmix - > voice = NULL ;
snd_trident_notify_pcm_change ( trident , tmix , substream - > number , 0 ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_mixer
Description : This routine registers the 4 DWave device for mixer support .
Paramters : trident - pointer to target device class for 4 DWave .
Returns : None
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int __devinit snd_trident_mixer ( trident_t * trident , int pcm_spdif_device )
{
ac97_template_t _ac97 ;
snd_card_t * card = trident - > card ;
snd_kcontrol_t * kctl ;
snd_ctl_elem_value_t * uctl ;
int idx , err , retries = 2 ;
static ac97_bus_ops_t ops = {
. write = snd_trident_codec_write ,
. read = snd_trident_codec_read ,
} ;
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 16:21:46 +04:00
uctl = kzalloc ( sizeof ( * uctl ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! uctl )
return - ENOMEM ;
if ( ( err = snd_ac97_bus ( trident - > card , 0 , & ops , NULL , & trident - > ac97_bus ) ) < 0 )
goto __out ;
memset ( & _ac97 , 0 , sizeof ( _ac97 ) ) ;
_ac97 . private_data = trident ;
trident - > ac97_detect = 1 ;
__again :
if ( ( err = snd_ac97_mixer ( trident - > ac97_bus , & _ac97 , & trident - > ac97 ) ) < 0 ) {
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
if ( ( err = snd_trident_sis_reset ( trident ) ) < 0 )
goto __out ;
if ( retries - - > 0 )
goto __again ;
err = - EIO ;
}
goto __out ;
}
/* secondary codec? */
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 & &
( inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) & SI_AC97_PRIMARY_READY ) ! = 0 ) {
_ac97 . num = 1 ;
err = snd_ac97_mixer ( trident - > ac97_bus , & _ac97 , & trident - > ac97_sec ) ;
if ( err < 0 )
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " SI7018: the secondary codec - invalid access \n " ) ;
2005-04-17 02:20:36 +04:00
#if 0 // only for my testing purpose --jk
{
ac97_t * mc97 ;
err = snd_ac97_modem ( trident - > card , & _ac97 , & mc97 ) ;
if ( err < 0 )
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " snd_ac97_modem returned error %i \n " , err ) ;
2005-04-17 02:20:36 +04:00
}
# endif
}
trident - > ac97_detect = 0 ;
if ( trident - > device ! = TRIDENT_DEVICE_ID_SI7018 ) {
if ( ( err = snd_ctl_add ( card , kctl = snd_ctl_new1 ( & snd_trident_vol_wave_control , trident ) ) ) < 0 )
goto __out ;
kctl - > put ( kctl , uctl ) ;
if ( ( err = snd_ctl_add ( card , kctl = snd_ctl_new1 ( & snd_trident_vol_music_control , trident ) ) ) < 0 )
goto __out ;
kctl - > put ( kctl , uctl ) ;
outl ( trident - > musicvol_wavevol = 0x00000000 , TRID_REG ( trident , T4D_MUSICVOL_WAVEVOL ) ) ;
} else {
outl ( trident - > musicvol_wavevol = 0xffff0000 , TRID_REG ( trident , T4D_MUSICVOL_WAVEVOL ) ) ;
}
for ( idx = 0 ; idx < 32 ; idx + + ) {
snd_trident_pcm_mixer_t * tmix ;
tmix = & trident - > pcm_mixer [ idx ] ;
tmix - > voice = NULL ;
}
if ( ( trident - > ctl_vol = snd_ctl_new1 ( & snd_trident_pcm_vol_control , trident ) ) = = NULL )
goto __nomem ;
if ( ( err = snd_ctl_add ( card , trident - > ctl_vol ) ) )
goto __out ;
if ( ( trident - > ctl_pan = snd_ctl_new1 ( & snd_trident_pcm_pan_control , trident ) ) = = NULL )
goto __nomem ;
if ( ( err = snd_ctl_add ( card , trident - > ctl_pan ) ) )
goto __out ;
if ( ( trident - > ctl_rvol = snd_ctl_new1 ( & snd_trident_pcm_rvol_control , trident ) ) = = NULL )
goto __nomem ;
if ( ( err = snd_ctl_add ( card , trident - > ctl_rvol ) ) )
goto __out ;
if ( ( trident - > ctl_cvol = snd_ctl_new1 ( & snd_trident_pcm_cvol_control , trident ) ) = = NULL )
goto __nomem ;
if ( ( err = snd_ctl_add ( card , trident - > ctl_cvol ) ) )
goto __out ;
if ( trident - > device = = TRIDENT_DEVICE_ID_NX ) {
if ( ( err = snd_ctl_add ( card , kctl = snd_ctl_new1 ( & snd_trident_ac97_rear_control , trident ) ) ) < 0 )
goto __out ;
kctl - > put ( kctl , uctl ) ;
}
if ( trident - > device = = TRIDENT_DEVICE_ID_NX | | trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
kctl = snd_ctl_new1 ( & snd_trident_spdif_control , trident ) ;
if ( kctl = = NULL ) {
err = - ENOMEM ;
goto __out ;
}
if ( trident - > ac97 - > ext_id & AC97_EI_SPDIF )
kctl - > id . index + + ;
if ( trident - > ac97_sec & & ( trident - > ac97_sec - > ext_id & AC97_EI_SPDIF ) )
kctl - > id . index + + ;
idx = kctl - > id . index ;
if ( ( err = snd_ctl_add ( card , kctl ) ) < 0 )
goto __out ;
kctl - > put ( kctl , uctl ) ;
kctl = snd_ctl_new1 ( & snd_trident_spdif_default , trident ) ;
if ( kctl = = NULL ) {
err = - ENOMEM ;
goto __out ;
}
kctl - > id . index = idx ;
kctl - > id . device = pcm_spdif_device ;
if ( ( err = snd_ctl_add ( card , kctl ) ) < 0 )
goto __out ;
kctl = snd_ctl_new1 ( & snd_trident_spdif_mask , trident ) ;
if ( kctl = = NULL ) {
err = - ENOMEM ;
goto __out ;
}
kctl - > id . index = idx ;
kctl - > id . device = pcm_spdif_device ;
if ( ( err = snd_ctl_add ( card , kctl ) ) < 0 )
goto __out ;
kctl = snd_ctl_new1 ( & snd_trident_spdif_stream , trident ) ;
if ( kctl = = NULL ) {
err = - ENOMEM ;
goto __out ;
}
kctl - > id . index = idx ;
kctl - > id . device = pcm_spdif_device ;
if ( ( err = snd_ctl_add ( card , kctl ) ) < 0 )
goto __out ;
trident - > spdif_pcm_ctl = kctl ;
}
err = 0 ;
goto __out ;
__nomem :
err = - ENOMEM ;
__out :
kfree ( uctl ) ;
return err ;
}
/*
* gameport interface
*/
# if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
static unsigned char snd_trident_gameport_read ( struct gameport * gameport )
{
trident_t * chip = gameport_get_port_data ( gameport ) ;
snd_assert ( chip , return 0 ) ;
return inb ( TRID_REG ( chip , GAMEPORT_LEGACY ) ) ;
}
static void snd_trident_gameport_trigger ( struct gameport * gameport )
{
trident_t * chip = gameport_get_port_data ( gameport ) ;
snd_assert ( chip , return ) ;
outb ( 0xff , TRID_REG ( chip , GAMEPORT_LEGACY ) ) ;
}
static int snd_trident_gameport_cooked_read ( struct gameport * gameport , int * axes , int * buttons )
{
trident_t * chip = gameport_get_port_data ( gameport ) ;
int i ;
snd_assert ( chip , return 0 ) ;
* buttons = ( ~ inb ( TRID_REG ( chip , GAMEPORT_LEGACY ) ) > > 4 ) & 0xf ;
for ( i = 0 ; i < 4 ; i + + ) {
axes [ i ] = inw ( TRID_REG ( chip , GAMEPORT_AXES + i * 2 ) ) ;
if ( axes [ i ] = = 0xffff ) axes [ i ] = - 1 ;
}
return 0 ;
}
static int snd_trident_gameport_open ( struct gameport * gameport , int mode )
{
trident_t * chip = gameport_get_port_data ( gameport ) ;
snd_assert ( chip , return 0 ) ;
switch ( mode ) {
case GAMEPORT_MODE_COOKED :
outb ( GAMEPORT_MODE_ADC , TRID_REG ( chip , GAMEPORT_GCR ) ) ;
[ALSA] sound/pci: fix-up sleeping paths
ENS1370/1+ driver,ES1968 driver,Intel8x0 driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,ALI5451 driver,CS46xx driver
MIXART driver,RME HDSP driver,Trident driver,YMFPCI driver
Description: Fix-up sleeping in sound/pci. These changes fall under the
following two categories:
1) Replace schedule_timeout() with msleep() to guarantee the
task delays as expected. This also involved replacing/removing
custom sleep functions.
2) Do not assume jiffies will only increment by one if you
request a 1 jiffy sleep, i.e. use time_after/time_before in
while loops.
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2005-07-09 12:13:22 +04:00
msleep ( 20 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
case GAMEPORT_MODE_RAW :
outb ( 0 , TRID_REG ( chip , GAMEPORT_GCR ) ) ;
return 0 ;
default :
return - 1 ;
}
}
int __devinit snd_trident_create_gameport ( trident_t * chip )
{
struct gameport * gp ;
chip - > gameport = gp = gameport_allocate_port ( ) ;
if ( ! gp ) {
printk ( KERN_ERR " trident: cannot allocate memory for gameport \n " ) ;
return - ENOMEM ;
}
gameport_set_name ( gp , " Trident 4DWave " ) ;
gameport_set_phys ( gp , " pci%s/gameport0 " , pci_name ( chip - > pci ) ) ;
gameport_set_dev_parent ( gp , & chip - > pci - > dev ) ;
gameport_set_port_data ( gp , chip ) ;
gp - > fuzz = 64 ;
gp - > read = snd_trident_gameport_read ;
gp - > trigger = snd_trident_gameport_trigger ;
gp - > cooked_read = snd_trident_gameport_cooked_read ;
gp - > open = snd_trident_gameport_open ;
gameport_register_port ( gp ) ;
return 0 ;
}
static inline void snd_trident_free_gameport ( trident_t * chip )
{
if ( chip - > gameport ) {
gameport_unregister_port ( chip - > gameport ) ;
chip - > gameport = NULL ;
}
}
# else
int __devinit snd_trident_create_gameport ( trident_t * chip ) { return - ENOSYS ; }
static inline void snd_trident_free_gameport ( trident_t * chip ) { }
# endif /* CONFIG_GAMEPORT */
/*
* delay for 1 tick
*/
2005-07-27 22:46:09 +04:00
static inline void do_delay ( trident_t * chip )
2005-04-17 02:20:36 +04:00
{
2005-10-24 17:02:37 +04:00
schedule_timeout_uninterruptible ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* SiS reset routine
*/
static int snd_trident_sis_reset ( trident_t * trident )
{
unsigned long end_time ;
unsigned int i ;
int r ;
r = trident - > in_suspend ? 0 : 2 ; /* count of retries */
__si7018_retry :
pci_write_config_byte ( trident - > pci , 0x46 , 0x04 ) ; /* SOFTWARE RESET */
udelay ( 100 ) ;
pci_write_config_byte ( trident - > pci , 0x46 , 0x00 ) ;
udelay ( 100 ) ;
/* disable AC97 GPIO interrupt */
outb ( 0x00 , TRID_REG ( trident , SI_AC97_GPIO ) ) ;
/* initialize serial interface, force cold reset */
i = PCMOUT | SURROUT | CENTEROUT | LFEOUT | SECONDARY_ID | COLD_RESET ;
outl ( i , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
udelay ( 1000 ) ;
/* remove cold reset */
i & = ~ COLD_RESET ;
outl ( i , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
udelay ( 2000 ) ;
/* wait, until the codec is ready */
end_time = ( jiffies + ( HZ * 3 ) / 4 ) + 1 ;
do {
if ( ( inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) & SI_AC97_PRIMARY_READY ) ! = 0 )
goto __si7018_ok ;
do_delay ( trident ) ;
} while ( time_after_eq ( end_time , jiffies ) ) ;
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " AC'97 codec ready error [0x%x] \n " , inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ) ;
2005-04-17 02:20:36 +04:00
if ( r - - > 0 ) {
end_time = jiffies + HZ ;
do {
do_delay ( trident ) ;
} while ( time_after_eq ( end_time , jiffies ) ) ;
goto __si7018_retry ;
}
__si7018_ok :
/* wait for the second codec */
do {
if ( ( inl ( TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) & SI_AC97_SECONDARY_READY ) ! = 0 )
break ;
do_delay ( trident ) ;
} while ( time_after_eq ( end_time , jiffies ) ) ;
/* enable 64 channel mode */
outl ( BANK_B_EN , TRID_REG ( trident , T4D_LFO_GC_CIR ) ) ;
return 0 ;
}
/*
* / proc interface
*/
static void snd_trident_proc_read ( snd_info_entry_t * entry ,
snd_info_buffer_t * buffer )
{
trident_t * trident = entry - > private_data ;
char * s ;
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_SI7018 :
s = " SiS 7018 Audio " ;
break ;
case TRIDENT_DEVICE_ID_DX :
s = " Trident 4DWave PCI DX " ;
break ;
case TRIDENT_DEVICE_ID_NX :
s = " Trident 4DWave PCI NX " ;
break ;
default :
s = " ??? " ;
}
snd_iprintf ( buffer , " %s \n \n " , s ) ;
snd_iprintf ( buffer , " Spurious IRQs : %d \n " , trident - > spurious_irq_count ) ;
snd_iprintf ( buffer , " Spurious IRQ dlta: %d \n " , trident - > spurious_irq_max_delta ) ;
if ( trident - > device = = TRIDENT_DEVICE_ID_NX | | trident - > device = = TRIDENT_DEVICE_ID_SI7018 )
snd_iprintf ( buffer , " IEC958 Mixer Out : %s \n " , trident - > spdif_ctrl = = 0x28 ? " on " : " off " ) ;
if ( trident - > device = = TRIDENT_DEVICE_ID_NX ) {
snd_iprintf ( buffer , " Rear Speakers : %s \n " , trident - > ac97_ctrl & 0x00000010 ? " on " : " off " ) ;
if ( trident - > tlb . entries ) {
snd_iprintf ( buffer , " \n Virtual Memory \n " ) ;
snd_iprintf ( buffer , " Memory Maximum : %d \n " , trident - > tlb . memhdr - > size ) ;
snd_iprintf ( buffer , " Memory Used : %d \n " , trident - > tlb . memhdr - > used ) ;
snd_iprintf ( buffer , " Memory Free : %d \n " , snd_util_mem_avail ( trident - > tlb . memhdr ) ) ;
}
}
# if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
snd_iprintf ( buffer , " \n Wavetable Synth \n " ) ;
snd_iprintf ( buffer , " Memory Maximum : %d \n " , trident - > synth . max_size ) ;
snd_iprintf ( buffer , " Memory Used : %d \n " , trident - > synth . current_size ) ;
snd_iprintf ( buffer , " Memory Free : %d \n " , ( trident - > synth . max_size - trident - > synth . current_size ) ) ;
# endif
}
static void __devinit snd_trident_proc_init ( trident_t * trident )
{
snd_info_entry_t * entry ;
const char * s = " trident " ;
if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 )
s = " sis7018 " ;
if ( ! snd_card_proc_new ( trident - > card , s , & entry ) )
snd_info_set_text_ops ( entry , trident , 1024 , snd_trident_proc_read ) ;
}
static int snd_trident_dev_free ( snd_device_t * device )
{
trident_t * trident = device - > device_data ;
return snd_trident_free ( trident ) ;
}
/*---------------------------------------------------------------------------
snd_trident_tlb_alloc
Description : Allocate and set up the TLB page table on 4 D NX .
Each entry has 4 bytes ( physical PCI address ) .
Paramters : trident - pointer to target device class for 4 DWave .
Returns : 0 or negative error code
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int __devinit snd_trident_tlb_alloc ( trident_t * trident )
{
int i ;
/* TLB array must be aligned to 16kB !!! so we allocate
32 kB region and correct offset when necessary */
if ( snd_dma_alloc_pages ( SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( trident - > pci ) ,
2 * SNDRV_TRIDENT_MAX_PAGES * 4 , & trident - > tlb . buffer ) < 0 ) {
snd_printk ( KERN_ERR " trident: unable to allocate TLB buffer \n " ) ;
return - ENOMEM ;
}
trident - > tlb . entries = ( unsigned int * ) ( ( ( unsigned long ) trident - > tlb . buffer . area + SNDRV_TRIDENT_MAX_PAGES * 4 - 1 ) & ~ ( SNDRV_TRIDENT_MAX_PAGES * 4 - 1 ) ) ;
trident - > tlb . entries_dmaaddr = ( trident - > tlb . buffer . addr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1 ) & ~ ( SNDRV_TRIDENT_MAX_PAGES * 4 - 1 ) ;
/* allocate shadow TLB page table (virtual addresses) */
trident - > tlb . shadow_entries = ( unsigned long * ) vmalloc ( SNDRV_TRIDENT_MAX_PAGES * sizeof ( unsigned long ) ) ;
if ( trident - > tlb . shadow_entries = = NULL ) {
snd_printk ( KERN_ERR " trident: unable to allocate shadow TLB entries \n " ) ;
return - ENOMEM ;
}
/* allocate and setup silent page and initialise TLB entries */
if ( snd_dma_alloc_pages ( SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( trident - > pci ) ,
SNDRV_TRIDENT_PAGE_SIZE , & trident - > tlb . silent_page ) < 0 ) {
snd_printk ( KERN_ERR " trident: unable to allocate silent page \n " ) ;
return - ENOMEM ;
}
memset ( trident - > tlb . silent_page . area , 0 , SNDRV_TRIDENT_PAGE_SIZE ) ;
for ( i = 0 ; i < SNDRV_TRIDENT_MAX_PAGES ; i + + ) {
trident - > tlb . entries [ i ] = cpu_to_le32 ( trident - > tlb . silent_page . addr & ~ ( SNDRV_TRIDENT_PAGE_SIZE - 1 ) ) ;
trident - > tlb . shadow_entries [ i ] = ( unsigned long ) trident - > tlb . silent_page . area ;
}
/* use emu memory block manager code to manage tlb page allocation */
trident - > tlb . memhdr = snd_util_memhdr_new ( SNDRV_TRIDENT_PAGE_SIZE * SNDRV_TRIDENT_MAX_PAGES ) ;
if ( trident - > tlb . memhdr = = NULL )
return - ENOMEM ;
trident - > tlb . memhdr - > block_extra_size = sizeof ( snd_trident_memblk_arg_t ) ;
return 0 ;
}
/*
* initialize 4 D DX chip
*/
static void snd_trident_stop_all_voices ( trident_t * trident )
{
outl ( 0xffffffff , TRID_REG ( trident , T4D_STOP_A ) ) ;
outl ( 0xffffffff , TRID_REG ( trident , T4D_STOP_B ) ) ;
outl ( 0 , TRID_REG ( trident , T4D_AINTEN_A ) ) ;
outl ( 0 , TRID_REG ( trident , T4D_AINTEN_B ) ) ;
}
static int snd_trident_4d_dx_init ( trident_t * trident )
{
struct pci_dev * pci = trident - > pci ;
unsigned long end_time ;
/* reset the legacy configuration and whole audio/wavetable block */
pci_write_config_dword ( pci , 0x40 , 0 ) ; /* DDMA */
pci_write_config_byte ( pci , 0x44 , 0 ) ; /* ports */
pci_write_config_byte ( pci , 0x45 , 0 ) ; /* Legacy DMA */
pci_write_config_byte ( pci , 0x46 , 4 ) ; /* reset */
udelay ( 100 ) ;
pci_write_config_byte ( pci , 0x46 , 0 ) ; /* release reset */
udelay ( 100 ) ;
/* warm reset of the AC'97 codec */
outl ( 0x00000001 , TRID_REG ( trident , DX_ACR2_AC97_COM_STAT ) ) ;
udelay ( 100 ) ;
outl ( 0x00000000 , TRID_REG ( trident , DX_ACR2_AC97_COM_STAT ) ) ;
/* DAC on, disable SB IRQ and try to force ADC valid signal */
trident - > ac97_ctrl = 0x0000004a ;
outl ( trident - > ac97_ctrl , TRID_REG ( trident , DX_ACR2_AC97_COM_STAT ) ) ;
/* wait, until the codec is ready */
end_time = ( jiffies + ( HZ * 3 ) / 4 ) + 1 ;
do {
if ( ( inl ( TRID_REG ( trident , DX_ACR2_AC97_COM_STAT ) ) & 0x0010 ) ! = 0 )
goto __dx_ok ;
do_delay ( trident ) ;
} while ( time_after_eq ( end_time , jiffies ) ) ;
snd_printk ( KERN_ERR " AC'97 codec ready error \n " ) ;
return - EIO ;
__dx_ok :
snd_trident_stop_all_voices ( trident ) ;
return 0 ;
}
/*
* initialize 4 D NX chip
*/
static int snd_trident_4d_nx_init ( trident_t * trident )
{
struct pci_dev * pci = trident - > pci ;
unsigned long end_time ;
/* reset the legacy configuration and whole audio/wavetable block */
pci_write_config_dword ( pci , 0x40 , 0 ) ; /* DDMA */
pci_write_config_byte ( pci , 0x44 , 0 ) ; /* ports */
pci_write_config_byte ( pci , 0x45 , 0 ) ; /* Legacy DMA */
pci_write_config_byte ( pci , 0x46 , 1 ) ; /* reset */
udelay ( 100 ) ;
pci_write_config_byte ( pci , 0x46 , 0 ) ; /* release reset */
udelay ( 100 ) ;
/* warm reset of the AC'97 codec */
outl ( 0x00000001 , TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
udelay ( 100 ) ;
outl ( 0x00000000 , TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
/* wait, until the codec is ready */
end_time = ( jiffies + ( HZ * 3 ) / 4 ) + 1 ;
do {
if ( ( inl ( TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) & 0x0008 ) ! = 0 )
goto __nx_ok ;
do_delay ( trident ) ;
} while ( time_after_eq ( end_time , jiffies ) ) ;
snd_printk ( KERN_ERR " AC'97 codec ready error [0x%x] \n " , inl ( TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ) ;
return - EIO ;
__nx_ok :
/* DAC on */
trident - > ac97_ctrl = 0x00000002 ;
outl ( trident - > ac97_ctrl , TRID_REG ( trident , NX_ACR0_AC97_COM_STAT ) ) ;
/* disable SB IRQ */
outl ( NX_SB_IRQ_DISABLE , TRID_REG ( trident , T4D_MISCINT ) ) ;
snd_trident_stop_all_voices ( trident ) ;
if ( trident - > tlb . entries ! = NULL ) {
unsigned int i ;
/* enable virtual addressing via TLB */
i = trident - > tlb . entries_dmaaddr ;
i | = 0x00000001 ;
outl ( i , TRID_REG ( trident , NX_TLBC ) ) ;
} else {
outl ( 0 , TRID_REG ( trident , NX_TLBC ) ) ;
}
/* initialize S/PDIF */
outl ( trident - > spdif_bits , TRID_REG ( trident , NX_SPCSTATUS ) ) ;
outb ( trident - > spdif_ctrl , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
return 0 ;
}
/*
* initialize sis7018 chip
*/
static int snd_trident_sis_init ( trident_t * trident )
{
int err ;
if ( ( err = snd_trident_sis_reset ( trident ) ) < 0 )
return err ;
snd_trident_stop_all_voices ( trident ) ;
/* initialize S/PDIF */
outl ( trident - > spdif_bits , TRID_REG ( trident , SI_SPDIF_CS ) ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_create
Description : This routine will create the device specific class for
the 4 DWave card . It will also perform basic initialization .
Paramters : card - which card to create
pci - interface to PCI bus resource info
dma1ptr - playback dma buffer
dma2ptr - capture dma buffer
irqptr - interrupt resource info
Returns : 4 DWave device class private data
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int __devinit snd_trident_create ( snd_card_t * card ,
struct pci_dev * pci ,
int pcm_streams ,
int pcm_spdif_device ,
int max_wavetable_size ,
trident_t * * rtrident )
{
trident_t * trident ;
int i , err ;
snd_trident_voice_t * voice ;
snd_trident_pcm_mixer_t * tmix ;
static snd_device_ops_t ops = {
. dev_free = snd_trident_dev_free ,
} ;
* rtrident = NULL ;
/* enable PCI device */
if ( ( err = pci_enable_device ( pci ) ) < 0 )
return err ;
/* check, if we can restrict PCI DMA transfers to 30 bits */
if ( pci_set_dma_mask ( pci , 0x3fffffff ) < 0 | |
pci_set_consistent_dma_mask ( pci , 0x3fffffff ) < 0 ) {
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " architecture does not support 30bit PCI busmaster DMA \n " ) ;
2005-04-17 02:20:36 +04:00
pci_disable_device ( pci ) ;
return - ENXIO ;
}
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 16:21:46 +04:00
trident = kzalloc ( sizeof ( * trident ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( trident = = NULL ) {
pci_disable_device ( pci ) ;
return - ENOMEM ;
}
trident - > device = ( pci - > vendor < < 16 ) | pci - > device ;
trident - > card = card ;
trident - > pci = pci ;
spin_lock_init ( & trident - > reg_lock ) ;
spin_lock_init ( & trident - > event_lock ) ;
spin_lock_init ( & trident - > voice_alloc ) ;
if ( pcm_streams < 1 )
pcm_streams = 1 ;
if ( pcm_streams > 32 )
pcm_streams = 32 ;
trident - > ChanPCM = pcm_streams ;
if ( max_wavetable_size < 0 )
max_wavetable_size = 0 ;
trident - > synth . max_size = max_wavetable_size * 1024 ;
trident - > irq = - 1 ;
trident - > midi_port = TRID_REG ( trident , T4D_MPU401_BASE ) ;
pci_set_master ( pci ) ;
if ( ( err = pci_request_regions ( pci , " Trident Audio " ) ) < 0 ) {
kfree ( trident ) ;
pci_disable_device ( pci ) ;
return err ;
}
trident - > port = pci_resource_start ( pci , 0 ) ;
if ( request_irq ( pci - > irq , snd_trident_interrupt , SA_INTERRUPT | SA_SHIRQ , " Trident Audio " , ( void * ) trident ) ) {
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " unable to grab IRQ %d \n " , pci - > irq ) ;
2005-04-17 02:20:36 +04:00
snd_trident_free ( trident ) ;
return - EBUSY ;
}
trident - > irq = pci - > irq ;
/* allocate 16k-aligned TLB for NX cards */
trident - > tlb . entries = NULL ;
trident - > tlb . buffer . area = NULL ;
if ( trident - > device = = TRIDENT_DEVICE_ID_NX ) {
if ( ( err = snd_trident_tlb_alloc ( trident ) ) < 0 ) {
snd_trident_free ( trident ) ;
return err ;
}
}
trident - > spdif_bits = trident - > spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF ;
/* initialize chip */
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_DX :
err = snd_trident_4d_dx_init ( trident ) ;
break ;
case TRIDENT_DEVICE_ID_NX :
err = snd_trident_4d_nx_init ( trident ) ;
break ;
case TRIDENT_DEVICE_ID_SI7018 :
err = snd_trident_sis_init ( trident ) ;
break ;
default :
snd_BUG ( ) ;
break ;
}
if ( err < 0 ) {
snd_trident_free ( trident ) ;
return err ;
}
if ( ( err = snd_device_new ( card , SNDRV_DEV_LOWLEVEL , trident , & ops ) ) < 0 ) {
snd_trident_free ( trident ) ;
return err ;
}
if ( ( err = snd_trident_mixer ( trident , pcm_spdif_device ) ) < 0 )
return err ;
/* initialise synth voices */
for ( i = 0 ; i < 64 ; i + + ) {
voice = & trident - > synth . voices [ i ] ;
voice - > number = i ;
voice - > trident = trident ;
}
/* initialize pcm mixer entries */
for ( i = 0 ; i < 32 ; i + + ) {
tmix = & trident - > pcm_mixer [ i ] ;
tmix - > vol = T4D_DEFAULT_PCM_VOL ;
tmix - > pan = T4D_DEFAULT_PCM_PAN ;
tmix - > rvol = T4D_DEFAULT_PCM_RVOL ;
tmix - > cvol = T4D_DEFAULT_PCM_CVOL ;
}
snd_trident_enable_eso ( trident ) ;
snd_card_set_pm_callback ( card , snd_trident_suspend , snd_trident_resume , trident ) ;
snd_trident_proc_init ( trident ) ;
snd_card_set_dev ( card , & pci - > dev ) ;
* rtrident = trident ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_free
Description : This routine will free the device specific class for
the 4 DWave card .
Paramters : trident - device specific private data for 4 DWave card
Returns : None .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int snd_trident_free ( trident_t * trident )
{
snd_trident_free_gameport ( trident ) ;
snd_trident_disable_eso ( trident ) ;
// Disable S/PDIF out
if ( trident - > device = = TRIDENT_DEVICE_ID_NX )
outb ( 0x00 , TRID_REG ( trident , NX_SPCTRL_SPCSO + 3 ) ) ;
else if ( trident - > device = = TRIDENT_DEVICE_ID_SI7018 ) {
outl ( 0 , TRID_REG ( trident , SI_SERIAL_INTF_CTRL ) ) ;
}
if ( trident - > tlb . buffer . area ) {
outl ( 0 , TRID_REG ( trident , NX_TLBC ) ) ;
if ( trident - > tlb . memhdr )
snd_util_memhdr_free ( trident - > tlb . memhdr ) ;
if ( trident - > tlb . silent_page . area )
snd_dma_free_pages ( & trident - > tlb . silent_page ) ;
vfree ( trident - > tlb . shadow_entries ) ;
snd_dma_free_pages ( & trident - > tlb . buffer ) ;
}
if ( trident - > irq > = 0 )
free_irq ( trident - > irq , ( void * ) trident ) ;
pci_release_regions ( trident - > pci ) ;
pci_disable_device ( trident - > pci ) ;
kfree ( trident ) ;
return 0 ;
}
/*---------------------------------------------------------------------------
snd_trident_interrupt
Description : ISR for Trident 4 DWave device
Paramters : trident - device specific private data for 4 DWave card
Problems : It seems that Trident chips generates interrupts more than
one time in special cases . The spurious interrupts are
detected via sample timer ( T4D_STIMER ) and computing
corresponding delta value . The limits are detected with
the method try & fail so it is possible that it won ' t
work on all computers . [ jaroslav ]
Returns : None .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static irqreturn_t snd_trident_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
trident_t * trident = dev_id ;
unsigned int audio_int , chn_int , stimer , channel , mask , tmp ;
int delta ;
snd_trident_voice_t * voice ;
audio_int = inl ( TRID_REG ( trident , T4D_MISCINT ) ) ;
if ( ( audio_int & ( ADDRESS_IRQ | MPU401_IRQ ) ) = = 0 )
return IRQ_NONE ;
if ( audio_int & ADDRESS_IRQ ) {
// get interrupt status for all channels
spin_lock ( & trident - > reg_lock ) ;
stimer = inl ( TRID_REG ( trident , T4D_STIMER ) ) & 0x00ffffff ;
chn_int = inl ( TRID_REG ( trident , T4D_AINT_A ) ) ;
if ( chn_int = = 0 )
goto __skip1 ;
outl ( chn_int , TRID_REG ( trident , T4D_AINT_A ) ) ; /* ack */
__skip1 :
chn_int = inl ( TRID_REG ( trident , T4D_AINT_B ) ) ;
if ( chn_int = = 0 )
goto __skip2 ;
for ( channel = 63 ; channel > = 32 ; channel - - ) {
mask = 1 < < ( channel & 0x1f ) ;
if ( ( chn_int & mask ) = = 0 )
continue ;
voice = & trident - > synth . voices [ channel ] ;
if ( ! voice - > pcm | | voice - > substream = = NULL ) {
outl ( mask , TRID_REG ( trident , T4D_STOP_B ) ) ;
continue ;
}
delta = ( int ) stimer - ( int ) voice - > stimer ;
if ( delta < 0 )
delta = - delta ;
if ( ( unsigned int ) delta < voice - > spurious_threshold ) {
/* do some statistics here */
trident - > spurious_irq_count + + ;
if ( trident - > spurious_irq_max_delta < ( unsigned int ) delta )
trident - > spurious_irq_max_delta = delta ;
continue ;
}
voice - > stimer = stimer ;
if ( voice - > isync ) {
if ( ! voice - > isync3 ) {
tmp = inw ( TRID_REG ( trident , T4D_SBBL_SBCL ) ) ;
if ( trident - > bDMAStart & 0x40 )
tmp > > = 1 ;
if ( tmp > 0 )
tmp = voice - > isync_max - tmp ;
} else {
tmp = inl ( TRID_REG ( trident , NX_SPCTRL_SPCSO ) ) & 0x00ffffff ;
}
if ( tmp < voice - > isync_mark ) {
if ( tmp > 0x10 )
tmp = voice - > isync_ESO - 7 ;
else
tmp = voice - > isync_ESO + 2 ;
/* update ESO for IRQ voice to preserve sync */
snd_trident_stop_voice ( trident , voice - > number ) ;
snd_trident_write_eso_reg ( trident , voice , tmp ) ;
snd_trident_start_voice ( trident , voice - > number ) ;
}
} else if ( voice - > isync2 ) {
voice - > isync2 = 0 ;
/* write original ESO and update CSO for IRQ voice to preserve sync */
snd_trident_stop_voice ( trident , voice - > number ) ;
snd_trident_write_cso_reg ( trident , voice , voice - > isync_mark ) ;
snd_trident_write_eso_reg ( trident , voice , voice - > ESO ) ;
snd_trident_start_voice ( trident , voice - > number ) ;
}
#if 0
if ( voice - > extra ) {
/* update CSO for extra voice to preserve sync */
snd_trident_stop_voice ( trident , voice - > extra - > number ) ;
snd_trident_write_cso_reg ( trident , voice - > extra , 0 ) ;
snd_trident_start_voice ( trident , voice - > extra - > number ) ;
}
# endif
spin_unlock ( & trident - > reg_lock ) ;
snd_pcm_period_elapsed ( voice - > substream ) ;
spin_lock ( & trident - > reg_lock ) ;
}
outl ( chn_int , TRID_REG ( trident , T4D_AINT_B ) ) ; /* ack */
__skip2 :
spin_unlock ( & trident - > reg_lock ) ;
}
if ( audio_int & MPU401_IRQ ) {
if ( trident - > rmidi ) {
snd_mpu401_uart_interrupt ( irq , trident - > rmidi - > private_data , regs ) ;
} else {
inb ( TRID_REG ( trident , T4D_MPUR0 ) ) ;
}
}
// outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(trident, T4D_MISCINT));
return IRQ_HANDLED ;
}
/*---------------------------------------------------------------------------
snd_trident_attach_synthesizer
Description : Attach synthesizer hooks
Paramters : trident - device specific private data for 4 DWave card
Returns : None .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int snd_trident_attach_synthesizer ( trident_t * trident )
{
# if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
if ( snd_seq_device_new ( trident - > card , 1 , SNDRV_SEQ_DEV_ID_TRIDENT ,
sizeof ( trident_t * ) , & trident - > seq_dev ) > = 0 ) {
strcpy ( trident - > seq_dev - > name , " 4DWave " ) ;
* ( trident_t * * ) SNDRV_SEQ_DEVICE_ARGPTR ( trident - > seq_dev ) = trident ;
}
# endif
return 0 ;
}
snd_trident_voice_t * snd_trident_alloc_voice ( trident_t * trident , int type , int client , int port )
{
snd_trident_voice_t * pvoice ;
unsigned long flags ;
int idx ;
spin_lock_irqsave ( & trident - > voice_alloc , flags ) ;
if ( type = = SNDRV_TRIDENT_VOICE_TYPE_PCM ) {
idx = snd_trident_allocate_pcm_channel ( trident ) ;
if ( idx < 0 ) {
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
return NULL ;
}
pvoice = & trident - > synth . voices [ idx ] ;
pvoice - > use = 1 ;
pvoice - > pcm = 1 ;
pvoice - > capture = 0 ;
pvoice - > spdif = 0 ;
pvoice - > memblk = NULL ;
pvoice - > substream = NULL ;
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
return pvoice ;
}
if ( type = = SNDRV_TRIDENT_VOICE_TYPE_SYNTH ) {
idx = snd_trident_allocate_synth_channel ( trident ) ;
if ( idx < 0 ) {
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
return NULL ;
}
pvoice = & trident - > synth . voices [ idx ] ;
pvoice - > use = 1 ;
pvoice - > synth = 1 ;
pvoice - > client = client ;
pvoice - > port = port ;
pvoice - > memblk = NULL ;
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
return pvoice ;
}
if ( type = = SNDRV_TRIDENT_VOICE_TYPE_MIDI ) {
}
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
return NULL ;
}
void snd_trident_free_voice ( trident_t * trident , snd_trident_voice_t * voice )
{
unsigned long flags ;
void ( * private_free ) ( snd_trident_voice_t * ) ;
void * private_data ;
if ( voice = = NULL | | ! voice - > use )
return ;
snd_trident_clear_voices ( trident , voice - > number , voice - > number ) ;
spin_lock_irqsave ( & trident - > voice_alloc , flags ) ;
private_free = voice - > private_free ;
private_data = voice - > private_data ;
voice - > private_free = NULL ;
voice - > private_data = NULL ;
if ( voice - > pcm )
snd_trident_free_pcm_channel ( trident , voice - > number ) ;
if ( voice - > synth )
snd_trident_free_synth_channel ( trident , voice - > number ) ;
voice - > use = voice - > pcm = voice - > synth = voice - > midi = 0 ;
voice - > capture = voice - > spdif = 0 ;
voice - > sample_ops = NULL ;
voice - > substream = NULL ;
voice - > extra = NULL ;
spin_unlock_irqrestore ( & trident - > voice_alloc , flags ) ;
if ( private_free )
private_free ( voice ) ;
}
static void snd_trident_clear_voices ( trident_t * trident , unsigned short v_min , unsigned short v_max )
{
unsigned int i , val , mask [ 2 ] = { 0 , 0 } ;
snd_assert ( v_min < = 63 , return ) ;
snd_assert ( v_max < = 63 , return ) ;
for ( i = v_min ; i < = v_max ; i + + )
mask [ i > > 5 ] | = 1 < < ( i & 0x1f ) ;
if ( mask [ 0 ] ) {
outl ( mask [ 0 ] , TRID_REG ( trident , T4D_STOP_A ) ) ;
val = inl ( TRID_REG ( trident , T4D_AINTEN_A ) ) ;
outl ( val & ~ mask [ 0 ] , TRID_REG ( trident , T4D_AINTEN_A ) ) ;
}
if ( mask [ 1 ] ) {
outl ( mask [ 1 ] , TRID_REG ( trident , T4D_STOP_B ) ) ;
val = inl ( TRID_REG ( trident , T4D_AINTEN_B ) ) ;
outl ( val & ~ mask [ 1 ] , TRID_REG ( trident , T4D_AINTEN_B ) ) ;
}
}
# ifdef CONFIG_PM
static int snd_trident_suspend ( snd_card_t * card , pm_message_t state )
{
trident_t * trident = card - > pm_private_data ;
trident - > in_suspend = 1 ;
snd_pcm_suspend_all ( trident - > pcm ) ;
if ( trident - > foldback )
snd_pcm_suspend_all ( trident - > foldback ) ;
if ( trident - > spdif )
snd_pcm_suspend_all ( trident - > spdif ) ;
snd_ac97_suspend ( trident - > ac97 ) ;
if ( trident - > ac97_sec )
snd_ac97_suspend ( trident - > ac97_sec ) ;
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_DX :
case TRIDENT_DEVICE_ID_NX :
break ; /* TODO */
case TRIDENT_DEVICE_ID_SI7018 :
break ;
}
pci_disable_device ( trident - > pci ) ;
return 0 ;
}
static int snd_trident_resume ( snd_card_t * card )
{
trident_t * trident = card - > pm_private_data ;
pci_enable_device ( trident - > pci ) ;
if ( pci_set_dma_mask ( trident - > pci , 0x3fffffff ) < 0 | |
pci_set_consistent_dma_mask ( trident - > pci , 0x3fffffff ) < 0 )
snd_printk ( KERN_WARNING " trident: can't set the proper DMA mask \n " ) ;
pci_set_master ( trident - > pci ) ; /* to be sure */
switch ( trident - > device ) {
case TRIDENT_DEVICE_ID_DX :
snd_trident_4d_dx_init ( trident ) ;
break ;
case TRIDENT_DEVICE_ID_NX :
snd_trident_4d_nx_init ( trident ) ;
break ;
case TRIDENT_DEVICE_ID_SI7018 :
snd_trident_sis_init ( trident ) ;
break ;
}
snd_ac97_resume ( trident - > ac97 ) ;
if ( trident - > ac97_sec )
snd_ac97_resume ( trident - > ac97_sec ) ;
/* restore some registers */
outl ( trident - > musicvol_wavevol , TRID_REG ( trident , T4D_MUSICVOL_WAVEVOL ) ) ;
snd_trident_enable_eso ( trident ) ;
trident - > in_suspend = 0 ;
return 0 ;
}
# endif /* CONFIG_PM */
EXPORT_SYMBOL ( snd_trident_alloc_voice ) ;
EXPORT_SYMBOL ( snd_trident_free_voice ) ;
EXPORT_SYMBOL ( snd_trident_start_voice ) ;
EXPORT_SYMBOL ( snd_trident_stop_voice ) ;
EXPORT_SYMBOL ( snd_trident_write_voice_regs ) ;
/* trident_memory.c symbols */
EXPORT_SYMBOL ( snd_trident_synth_alloc ) ;
EXPORT_SYMBOL ( snd_trident_synth_free ) ;
EXPORT_SYMBOL ( snd_trident_synth_copy_from_user ) ;