2005-04-17 02:20:36 +04:00
# undef FKS_LOGGING
# undef FKS_TEST
/*
* tabs should be 4 spaces , in vi ( m ) : set tabstop = 4
*
* TODO : consistency speed calculations ! !
* cleanup !
* ? ? ? ? : Did I break MIDI support ?
*
* History :
*
* Rolf Fokkens ( Dec 20 1998 ) : ES188x recording level support on a per
* fokkensr @ vertis . nl input basis .
* ( Dec 24 1998 ) : Recognition of ES1788 , ES1887 , ES1888 ,
* ES1868 , ES1869 and ES1878 . Could be used for
* specific handling in the future . All except
* ES1887 and ES1888 and ES688 are handled like
* ES1688 .
* ( Dec 27 1998 ) : RECLEV for all ( ? ) ES1688 + chips . ES188x now
* have the " Dec 20 " support + RECLEV
* ( Jan 2 1999 ) : Preparation for Full Duplex . This means
* Audio 2 is now used for playback when dma16
* is specified . The next step would be to use
* Audio 1 and Audio 2 at the same time .
* ( Jan 9 1999 ) : Put all ESS stuff into sb_ess . [ ch ] , this
* includes both the ESS stuff that has been in
* sb_ * [ ch ] before I touched it and the ESS support
* I added later
* ( Jan 23 1999 ) : Full Duplex seems to work . I wrote a small
* test proggy which works OK . Haven ' t found
* any applications to test it though . So why did
* I bother to create it anyway ? ? : ) Just for
* fun .
* ( May 2 1999 ) : I tried to be too smart by " introducing "
* ess_calc_best_speed ( ) . The idea was that two
* dividers could be used to setup a samplerate ,
* ess_calc_best_speed ( ) would choose the best .
* This works for playback , but results in
* recording problems for high samplerates . I
* fixed this by removing ess_calc_best_speed ( )
* and just doing what the documentation says .
* Andy Sloane ( Jun 4 1999 ) : Stole some code from ALSA to fix the playback
* andy @ guildsoftware . com speed on ES1869 , ES1879 , ES1887 , and ES1888 .
* 1879 ' s were previously ignored by this driver ;
* added ( untested ) support for those .
* Cvetan Ivanov ( Oct 27 1999 ) : Fixed ess_dsp_init to call ess_set_dma_hw for
* zezo @ inet . bg _ALL_ ESS models , not only ES1887
*
* This files contains ESS chip specifics . It ' s based on the existing ESS
* handling as it resided in sb_common . c , sb_mixer . c and sb_audio . c . This
* file adds features like :
* - Chip Identification ( as shown in / proc / sound )
* - RECLEV support for ES1688 and later
* - 6 bits playback level support chips later than ES1688
* - Recording level support on a per - device basis for ES1887
* - Full - Duplex for ES1887
*
* Full duplex is enabled by specifying dma16 . While the normal dma must
* be one of 0 , 1 or 3 , dma16 can be one of 0 , 1 , 3 or 5. DMA 5 is a 16 bit
* DMA channel , while the others are 8 bit . .
*
* ESS detection isn ' t full proof ( yet ) . If it fails an additional module
* parameter esstype can be specified to be one of the following :
* - 1 , 0 , 688 , 1688 , 1868 , 1869 , 1788 , 1887 , 1888
* - 1 means : mimic 2.0 behaviour ,
* 0 means : auto detect .
* others : explicitly specify chip
* - 1 is default , cause auto detect still doesn ' t work .
*/
/*
* About the documentation
*
* I don ' t know if the chips all are OK , but the documentation is buggy . ' cause
* I don ' t have all the cips myself , there ' s a lot I cannot verify . I ' ll try to
* keep track of my latest insights about his here . If you have additional info ,
* please enlighten me ( fokkensr @ vertis . nl ) !
*
* I had the impression that ES1688 also has 6 bit master volume control . The
* documentation about ES1888 ( rev C , october ' 95 ) claims that ES1888 has
* the following features ES1688 doesn ' t have :
* - 6 bit master volume
* - Full Duplex
* So ES1688 apparently doesn ' t have 6 bit master volume control , but the
* ES1688 does have RECLEV control . Makes me wonder : does ES688 have it too ?
* Without RECLEV ES688 won ' t be much fun I guess .
*
* From the ES1888 ( rev C , october ' 95 ) documentation I got the impression
* that registers 0x68 to 0x6e don ' t exist which means : no recording volume
* controls . To my surprise the ES888 documentation ( 1 / 14 / 96 ) claims that
* ES888 does have these record mixer registers , but that ES1888 doesn ' t have
* 0x69 and 0x6b . So the rest should be there .
*
* I ' m trying to get ES1887 Full Duplex . Audio 2 is playback only , while Audio 2
* is both record and playback . I think I should use Audio 2 for all playback .
*
* The documentation is an adventure : it ' s close but not fully accurate . I
* found out that after a reset some registers are * NOT * reset , though the
2006-06-26 20:35:02 +04:00
* docs say the would be . Interesting ones are 0x7f , 0x7d and 0x7a . They are
* related to the Audio 2 channel . I also was surprised about the consequences
2005-04-17 02:20:36 +04:00
* of writing 0x00 to 0x7f ( which should be done by reset ) : The ES1887 moves
* into ES1888 mode . This means that it claims IRQ 11 , which happens to be my
* ISDN adapter . Needless to say it no longer worked . I now understand why
* after rebooting 0x7f already was 0x05 , the value of my choice : the BIOS
* did it .
*
2006-06-26 20:35:02 +04:00
* Oh , and this is another trap : in ES1887 docs mixer register 0x70 is
* described as if it ' s exactly the same as register 0xa1 . This is * NOT * true .
* The description of 0x70 in ES1869 docs is accurate however .
2005-04-17 02:20:36 +04:00
* Well , the assumption about ES1869 was wrong : register 0x70 is very much
2006-06-26 20:35:02 +04:00
* like register 0xa1 , except that bit 7 is always 1 , whatever you want
2005-04-17 02:20:36 +04:00
* it to be .
*
* When using audio 2 mixer register 0x72 seems te be meaningless . Only 0xa2
* has effect .
*
* Software reset not being able to reset all registers is great ! Especially
* the fact that register 0x78 isn ' t reset is great when you wanna change back
2006-06-26 20:35:02 +04:00
* to single dma operation ( simplex ) : audio 2 is still operational , and uses
* the same dma as audio 1 : your ess changes into a funny echo machine .
2005-04-17 02:20:36 +04:00
*
2006-06-26 20:35:02 +04:00
* Received the news that ES1688 is detected as a ES1788 . Did some thinking :
2005-04-17 02:20:36 +04:00
* the ES1887 detection scheme suggests in step 2 to try if bit 3 of register
* 0x64 can be changed . This is inaccurate , first I inverted the * check : " If
* can be modified , it ' s a 1688 " , which lead to a correct detection
* of my ES1887 . It resulted however in bad detection of 1688 ( reported by mail )
* and 1868 ( if no PnP detection first ) : they result in a 1788 being detected .
* I don ' t have docs on 1688 , but I do have docs on 1868 : The documentation is
* probably inaccurate in the fact that I should check bit 2 , not bit 3. This
* is what I do now .
*/
/*
* About recognition of ESS chips
*
* The distinction of ES688 , ES1688 , ES1788 , ES1887 and ES1888 is described in
2006-06-26 20:35:02 +04:00
* a ( preliminary ? ? ) datasheet on ES1887 . Its aim is to identify ES1887 , but
2005-04-17 02:20:36 +04:00
* during detection the text claims that " this chip may be ... " when a step
* fails . This scheme is used to distinct between the above chips .
* It appears however that some PnP chips like ES1868 are recognized as ES1788
* by the ES1887 detection scheme . These PnP chips can be detected in another
* way however : ES1868 , ES1869 and ES1878 can be recognized ( full proof I think )
* by repeatedly reading mixer register 0x40 . This is done by ess_identify in
* sb_common . c .
* This results in the following detection steps :
* - distinct between ES688 and ES1688 + ( as always done in this driver )
* if ES688 we ' re ready
* - try to detect ES1868 , ES1869 or ES1878
* if successful we ' re ready
* - try to detect ES1888 , ES1887 or ES1788
* if successful we ' re ready
* - Dunno . Must be 1688. Will do in general
*
* About RECLEV support :
*
* The existing ES1688 support didn ' t take care of the ES1688 + recording
* levels very well . Whenever a device was selected ( recmask ) for recording
2006-06-26 20:35:02 +04:00
* its recording level was loud , and it couldn ' t be changed . The fact that
2005-04-17 02:20:36 +04:00
* internal register 0xb4 could take care of RECLEV , didn ' t work meaning until
2006-06-26 20:35:02 +04:00
* its value was restored every time the chip was reset ; this reset the
2005-04-17 02:20:36 +04:00
* value of 0xb4 too . I guess that ' s what 4f ront also had ( have ? ) trouble with .
*
* About ES1887 support :
*
* The ES1887 has separate registers to control the recording levels , for all
* inputs . The ES1887 specific software makes these levels the same as their
* corresponding playback levels , unless recmask says they aren ' t recorded . In
* the latter case the recording volumes are 0.
* Now recording levels of inputs can be controlled , by changing the playback
2011-03-31 05:57:33 +04:00
* levels . Furthermore several devices can be recorded together ( which is not
2006-06-26 20:35:02 +04:00
* possible with the ES1688 ) .
2005-04-17 02:20:36 +04:00
* Besides the separate recording level control for each input , the common
2006-06-26 20:35:02 +04:00
* recording level can also be controlled by RECLEV as described above .
2005-04-17 02:20:36 +04:00
*
* Not only ES1887 have this recording mixer . I know the following from the
* documentation :
* ES688 no
* ES1688 no
* ES1868 no
* ES1869 yes
* ES1878 no
* ES1879 yes
* ES1888 no / yes Contradicting documentation ; most recent : yes
* ES1946 yes This is a PCI chip ; not handled by this driver
*/
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include "sound_config.h"
# include "sb_mixer.h"
# include "sb.h"
# include "sb_ess.h"
# define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */
# define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */
# define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */
# define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */
# define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */
# define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */
# define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */
# define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */
# define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */
# define SB_CAP_ES18XX_RATE 0x100
# define ES1688_CLOCK1 795444 /* 128 - div */
# define ES1688_CLOCK2 397722 /* 256 - div */
# define ES18XX_CLOCK1 793800 /* 128 - div */
# define ES18XX_CLOCK2 768000 /* 256 - div */
# ifdef FKS_LOGGING
static void ess_show_mixerregs ( sb_devc * devc ) ;
# endif
static int ess_read ( sb_devc * devc , unsigned char reg ) ;
static int ess_write ( sb_devc * devc , unsigned char reg , unsigned char data ) ;
static void ess_chgmixer
( sb_devc * devc , unsigned int reg , unsigned int mask , unsigned int val ) ;
/****************************************************************************
* *
* ESS audio *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct ess_command { short cmd ; short data ; } ;
/*
* Commands for initializing Audio 1 for input ( record )
*/
static struct ess_command ess_i08m [ ] = /* input 8 bit mono */
{ { 0xb7 , 0x51 } , { 0xb7 , 0xd0 } , { - 1 , 0 } } ;
static struct ess_command ess_i16m [ ] = /* input 16 bit mono */
{ { 0xb7 , 0x71 } , { 0xb7 , 0xf4 } , { - 1 , 0 } } ;
static struct ess_command ess_i08s [ ] = /* input 8 bit stereo */
{ { 0xb7 , 0x51 } , { 0xb7 , 0x98 } , { - 1 , 0 } } ;
static struct ess_command ess_i16s [ ] = /* input 16 bit stereo */
{ { 0xb7 , 0x71 } , { 0xb7 , 0xbc } , { - 1 , 0 } } ;
static struct ess_command * ess_inp_cmds [ ] =
{ ess_i08m , ess_i16m , ess_i08s , ess_i16s } ;
/*
* Commands for initializing Audio 1 for output ( playback )
*/
static struct ess_command ess_o08m [ ] = /* output 8 bit mono */
{ { 0xb6 , 0x80 } , { 0xb7 , 0x51 } , { 0xb7 , 0xd0 } , { - 1 , 0 } } ;
static struct ess_command ess_o16m [ ] = /* output 16 bit mono */
{ { 0xb6 , 0x00 } , { 0xb7 , 0x71 } , { 0xb7 , 0xf4 } , { - 1 , 0 } } ;
static struct ess_command ess_o08s [ ] = /* output 8 bit stereo */
{ { 0xb6 , 0x80 } , { 0xb7 , 0x51 } , { 0xb7 , 0x98 } , { - 1 , 0 } } ;
static struct ess_command ess_o16s [ ] = /* output 16 bit stereo */
{ { 0xb6 , 0x00 } , { 0xb7 , 0x71 } , { 0xb7 , 0xbc } , { - 1 , 0 } } ;
static struct ess_command * ess_out_cmds [ ] =
{ ess_o08m , ess_o16m , ess_o08s , ess_o16s } ;
static void ess_exec_commands
( sb_devc * devc , struct ess_command * cmdtab [ ] )
{
struct ess_command * cmd ;
cmd = cmdtab [ ( ( devc - > channels ! = 1 ) < < 1 ) + ( devc - > bits ! = AFMT_U8 ) ] ;
while ( cmd - > cmd ! = - 1 ) {
ess_write ( devc , cmd - > cmd , cmd - > data ) ;
cmd + + ;
}
}
static void ess_change
( sb_devc * devc , unsigned int reg , unsigned int mask , unsigned int val )
{
int value ;
value = ess_read ( devc , reg ) ;
value = ( value & ~ mask ) | ( val & mask ) ;
ess_write ( devc , reg , value ) ;
}
static void ess_set_output_parms
( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( devc - > duplex ) {
devc - > trg_buf_16 = buf ;
devc - > trg_bytes_16 = nr_bytes ;
devc - > trg_intrflag_16 = intrflag ;
devc - > irq_mode_16 = IMODE_OUTPUT ;
} else {
devc - > trg_buf = buf ;
devc - > trg_bytes = nr_bytes ;
devc - > trg_intrflag = intrflag ;
devc - > irq_mode = IMODE_OUTPUT ;
}
}
static void ess_set_input_parms
( int dev , unsigned long buf , int count , int intrflag )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
devc - > trg_buf = buf ;
devc - > trg_bytes = count ;
devc - > trg_intrflag = intrflag ;
devc - > irq_mode = IMODE_INPUT ;
}
static int ess_calc_div ( int clock , int revert , int * speedp , int * diffp )
{
int divider ;
int speed , diff ;
int retval ;
speed = * speedp ;
divider = ( clock + speed / 2 ) / speed ;
retval = revert - divider ;
if ( retval > revert - 1 ) {
retval = revert - 1 ;
divider = revert - retval ;
}
/* This line is suggested. Must be wrong I think
* speedp = ( clock + divider / 2 ) / divider ;
So I chose the next one */
* speedp = clock / divider ;
diff = speed - * speedp ;
if ( diff < 0 ) diff = - diff ;
* diffp = diff ;
return retval ;
}
static int ess_calc_best_speed
( int clock1 , int rev1 , int clock2 , int rev2 , int * divp , int * speedp )
{
int speed1 = * speedp , speed2 = * speedp ;
int div1 , div2 ;
int diff1 , diff2 ;
int retval ;
div1 = ess_calc_div ( clock1 , rev1 , & speed1 , & diff1 ) ;
div2 = ess_calc_div ( clock2 , rev2 , & speed2 , & diff2 ) ;
if ( diff1 < diff2 ) {
* divp = div1 ;
* speedp = speed1 ;
retval = 1 ;
} else {
/* *divp = div2; */
* divp = 0x80 | div2 ;
* speedp = speed2 ;
retval = 2 ;
}
return retval ;
}
/*
* Depending on the audiochannel ESS devices can
* have different clock settings . These are made consistent for duplex
* however .
* callers of ess_speed only do an audionum suggestion , which means
* input suggests 1 , output suggests 2. This suggestion is only true
* however when doing duplex .
*/
static void ess_common_speed ( sb_devc * devc , int * speedp , int * divp )
{
int diff = 0 , div ;
if ( devc - > duplex ) {
/*
* The 0x80 is important for the first audio channel
*/
if ( devc - > submodel = = SUBMDL_ES1888 ) {
div = 0x80 | ess_calc_div ( 795500 , 256 , speedp , & diff ) ;
} else {
div = 0x80 | ess_calc_div ( 795500 , 128 , speedp , & diff ) ;
}
} else if ( devc - > caps & SB_CAP_ES18XX_RATE ) {
if ( devc - > submodel = = SUBMDL_ES1888 ) {
ess_calc_best_speed ( 397700 , 128 , 795500 , 256 ,
& div , speedp ) ;
} else {
ess_calc_best_speed ( ES18XX_CLOCK1 , 128 , ES18XX_CLOCK2 , 256 ,
& div , speedp ) ;
}
} else {
if ( * speedp > 22000 ) {
div = 0x80 | ess_calc_div ( ES1688_CLOCK1 , 256 , speedp , & diff ) ;
} else {
div = 0x00 | ess_calc_div ( ES1688_CLOCK2 , 128 , speedp , & diff ) ;
}
}
* divp = div ;
}
static void ess_speed ( sb_devc * devc , int audionum )
{
int speed ;
int div , div2 ;
ess_common_speed ( devc , & ( devc - > speed ) , & div ) ;
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " FKS: ess_speed (%d) b speed = %d, div=%x \n " , audionum , devc - > speed , div ) ;
# endif
/* Set filter roll-off to 90% of speed/2 */
speed = ( devc - > speed * 9 ) / 20 ;
div2 = 256 - 7160000 / ( speed * 82 ) ;
if ( ! devc - > duplex ) audionum = 1 ;
if ( audionum = = 1 ) {
/* Change behaviour of register A1 *
sb_chg_mixer ( devc , 0x71 , 0x20 , 0x20 )
* For ES1869 only ? ? ? */
ess_write ( devc , 0xa1 , div ) ;
ess_write ( devc , 0xa2 , div2 ) ;
} else {
ess_setmixer ( devc , 0x70 , div ) ;
/*
* FKS : fascinating : 0x72 doesn ' t seem to work .
*/
ess_write ( devc , 0xa2 , div2 ) ;
ess_setmixer ( devc , 0x72 , div2 ) ;
}
}
static int ess_audio_prepare_for_input ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
ess_speed ( devc , 1 ) ;
sb_dsp_command ( devc , DSP_CMD_SPKOFF ) ;
ess_write ( devc , 0xb8 , 0x0e ) ; /* Auto init DMA mode */
ess_change ( devc , 0xa8 , 0x03 , 3 - devc - > channels ) ; /* Mono/stereo */
ess_write ( devc , 0xb9 , 2 ) ; /* Demand mode (4 bytes/DMA request) */
ess_exec_commands ( devc , ess_inp_cmds ) ;
ess_change ( devc , 0xb1 , 0xf0 , 0x50 ) ;
ess_change ( devc , 0xb2 , 0xf0 , 0x50 ) ;
devc - > trigger_bits = 0 ;
return 0 ;
}
static int ess_audio_prepare_for_output_audio1 ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
sb_dsp_reset ( devc ) ;
ess_speed ( devc , 1 ) ;
ess_write ( devc , 0xb8 , 4 ) ; /* Auto init DMA mode */
ess_change ( devc , 0xa8 , 0x03 , 3 - devc - > channels ) ; /* Mono/stereo */
ess_write ( devc , 0xb9 , 2 ) ; /* Demand mode (4 bytes/request) */
ess_exec_commands ( devc , ess_out_cmds ) ;
ess_change ( devc , 0xb1 , 0xf0 , 0x50 ) ; /* Enable DMA */
ess_change ( devc , 0xb2 , 0xf0 , 0x50 ) ; /* Enable IRQ */
sb_dsp_command ( devc , DSP_CMD_SPKON ) ; /* There be sound! */
devc - > trigger_bits = 0 ;
return 0 ;
}
static int ess_audio_prepare_for_output_audio2 ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned char bits ;
/* FKS: qqq
sb_dsp_reset ( devc ) ;
*/
/*
* Auto - Initialize :
* DMA mode + demand mode ( 8 bytes / request , yes I want it all ! )
* But leave 16 - bit DMA bit untouched !
*/
ess_chgmixer ( devc , 0x78 , 0xd0 , 0xd0 ) ;
ess_speed ( devc , 2 ) ;
/* bits 4:3 on ES1887 represent recording source. Keep them! */
bits = ess_getmixer ( devc , 0x7a ) & 0x18 ;
/* Set stereo/mono */
if ( devc - > channels ! = 1 ) bits | = 0x02 ;
/* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */
if ( devc - > bits ! = AFMT_U8 ) bits | = 0x05 ; /* 16 bit */
/* Enable DMA, IRQ will be shared (hopefully)*/
bits | = 0x60 ;
ess_setmixer ( devc , 0x7a , bits ) ;
ess_mixer_reload ( devc , SOUND_MIXER_PCM ) ; /* There be sound! */
devc - > trigger_bits = 0 ;
return 0 ;
}
static int ess_audio_prepare_for_output ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " ess_audio_prepare_for_output: dma_out=%d,dma_in=%d \n "
, audio_devs [ dev ] - > dmap_out - > dma , audio_devs [ dev ] - > dmap_in - > dma ) ;
# endif
if ( devc - > duplex ) {
return ess_audio_prepare_for_output_audio2 ( dev , bsize , bcount ) ;
} else {
return ess_audio_prepare_for_output_audio1 ( dev , bsize , bcount ) ;
}
}
static void ess_audio_halt_xfer ( int dev )
{
unsigned long flags ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
sb_dsp_reset ( devc ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
/*
* Audio 2 may still be operational ! Creates awful sounds !
*/
if ( devc - > duplex ) ess_chgmixer ( devc , 0x78 , 0x03 , 0x00 ) ;
}
static void ess_audio_start_input
( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
short c = - nr_bytes ;
/*
* Start a DMA input to the buffer pointed by dmaqtail
*/
if ( audio_devs [ dev ] - > dmap_in - > dma > 3 ) count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_INPUT ;
ess_write ( devc , 0xa4 , ( unsigned char ) ( ( unsigned short ) c & 0xff ) ) ;
ess_write ( devc , 0xa5 , ( unsigned char ) ( ( ( unsigned short ) c > > 8 ) & 0xff ) ) ;
ess_change ( devc , 0xb8 , 0x0f , 0x0f ) ; /* Go */
devc - > intr_active = 1 ;
}
static void ess_audio_output_block_audio1
( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
short c = - nr_bytes ;
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 )
count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_OUTPUT ;
ess_write ( devc , 0xa4 , ( unsigned char ) ( ( unsigned short ) c & 0xff ) ) ;
ess_write ( devc , 0xa5 , ( unsigned char ) ( ( ( unsigned short ) c > > 8 ) & 0xff ) ) ;
ess_change ( devc , 0xb8 , 0x05 , 0x05 ) ; /* Go */
devc - > intr_active = 1 ;
}
static void ess_audio_output_block_audio2
( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
short c = - nr_bytes ;
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 ) count > > = 1 ;
count - - ;
ess_setmixer ( devc , 0x74 , ( unsigned char ) ( ( unsigned short ) c & 0xff ) ) ;
ess_setmixer ( devc , 0x76 , ( unsigned char ) ( ( ( unsigned short ) c > > 8 ) & 0xff ) ) ;
ess_chgmixer ( devc , 0x78 , 0x03 , 0x03 ) ; /* Go */
devc - > irq_mode_16 = IMODE_OUTPUT ;
devc - > intr_active_16 = 1 ;
}
static void ess_audio_output_block
( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( devc - > duplex ) {
ess_audio_output_block_audio2 ( dev , buf , nr_bytes , intrflag ) ;
} else {
ess_audio_output_block_audio1 ( dev , buf , nr_bytes , intrflag ) ;
}
}
/*
* FKS : the if - statements for both bits and bits_16 are quite alike .
* Combine this . . .
*/
static void ess_audio_trigger ( int dev , int bits )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
int bits_16 = bits & devc - > irq_mode_16 ;
bits & = devc - > irq_mode ;
if ( ! bits & & ! bits_16 ) {
/* FKS oh oh.... wrong?? for dma 16? */
sb_dsp_command ( devc , 0xd0 ) ; /* Halt DMA */
}
if ( bits ) {
switch ( devc - > irq_mode )
{
case IMODE_INPUT :
ess_audio_start_input ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
case IMODE_OUTPUT :
ess_audio_output_block ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
}
}
if ( bits_16 ) {
switch ( devc - > irq_mode_16 ) {
case IMODE_INPUT :
ess_audio_start_input ( dev , devc - > trg_buf_16 , devc - > trg_bytes_16 ,
devc - > trg_intrflag_16 ) ;
break ;
case IMODE_OUTPUT :
ess_audio_output_block ( dev , devc - > trg_buf_16 , devc - > trg_bytes_16 ,
devc - > trg_intrflag_16 ) ;
break ;
}
}
devc - > trigger_bits = bits | bits_16 ;
}
static int ess_audio_set_speed ( int dev , int speed )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
int minspeed , maxspeed , dummydiv ;
if ( speed > 0 ) {
minspeed = ( devc - > duplex ? 6215 : 5000 ) ;
maxspeed = ( devc - > duplex ? 44100 : 48000 ) ;
if ( speed < minspeed ) speed = minspeed ;
if ( speed > maxspeed ) speed = maxspeed ;
ess_common_speed ( devc , & speed , & dummydiv ) ;
devc - > speed = speed ;
}
return devc - > speed ;
}
/*
* FKS : This is a one - on - one copy of sb1_audio_set_bits
*/
static unsigned int ess_audio_set_bits ( int dev , unsigned int bits )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( bits ! = 0 ) {
if ( bits = = AFMT_U8 | | bits = = AFMT_S16_LE ) {
devc - > bits = bits ;
} else {
devc - > bits = AFMT_U8 ;
}
}
return devc - > bits ;
}
/*
* FKS : This is a one - on - one copy of sbpro_audio_set_channels
* ( * ) Modified it ! !
*/
static short ess_audio_set_channels ( int dev , short channels )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( channels = = 1 | | channels = = 2 ) devc - > channels = channels ;
return devc - > channels ;
}
static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = ess_set_output_parms ,
. start_input = ess_set_input_parms ,
. prepare_for_input = ess_audio_prepare_for_input ,
. prepare_for_output = ess_audio_prepare_for_output ,
. halt_io = ess_audio_halt_xfer ,
. trigger = ess_audio_trigger ,
. set_speed = ess_audio_set_speed ,
. set_bits = ess_audio_set_bits ,
. set_channels = ess_audio_set_channels
} ;
/*
* ess_audio_init must be called from sb_audio_init
*/
struct audio_driver * ess_audio_init
( sb_devc * devc , int * audio_flags , int * format_mask )
{
* audio_flags = DMA_AUTOMODE ;
* format_mask | = AFMT_S16_LE ;
if ( devc - > duplex ) {
int tmp_dma ;
/*
* sb_audio_init thinks dma8 is for playback and
* dma16 is for record . Not now ! So swap them .
*/
tmp_dma = devc - > dma16 ;
devc - > dma16 = devc - > dma8 ;
devc - > dma8 = tmp_dma ;
* audio_flags | = DMA_DUPLEX ;
}
return & ess_audio_driver ;
}
/****************************************************************************
* *
* ESS common *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void ess_handle_channel
( char * channel , int dev , int intr_active , unsigned char flag , int irq_mode )
{
if ( ! intr_active | | ! flag ) return ;
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " FKS: ess_handle_channel %s irq_mode=%d \n " , channel , irq_mode ) ;
# endif
switch ( irq_mode ) {
case IMODE_OUTPUT :
DMAbuf_outputintr ( dev , 1 ) ;
break ;
case IMODE_INPUT :
DMAbuf_inputintr ( dev ) ;
break ;
case IMODE_INIT :
break ;
default : ;
2009-11-05 03:04:52 +03:00
/* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */
2005-04-17 02:20:36 +04:00
}
}
/*
* FKS : TODO ! ! ! Finish this !
*
* I think midi stuff uses uart401 , without interrupts .
* So IMODE_MIDI isn ' t a value for devc - > irq_mode .
*/
void ess_intr ( sb_devc * devc )
{
int status ;
unsigned char src ;
if ( devc - > submodel = = SUBMDL_ES1887 ) {
src = ess_getmixer ( devc , 0x7f ) > > 4 ;
} else {
src = 0xff ;
}
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " FKS: sbintr src=%x \n " , ( int ) src ) ;
# endif
ess_handle_channel
( " Audio 1 "
, devc - > dev , devc - > intr_active , src & 0x01 , devc - > irq_mode ) ;
ess_handle_channel
( " Audio 2 "
, devc - > dev , devc - > intr_active_16 , src & 0x02 , devc - > irq_mode_16 ) ;
/*
* Acknowledge interrupts
*/
if ( devc - > submodel = = SUBMDL_ES1887 & & ( src & 0x02 ) ) {
ess_chgmixer ( devc , 0x7a , 0x80 , 0x00 ) ;
}
if ( src & 0x01 ) {
status = inb ( DSP_DATA_AVAIL ) ;
}
}
static void ess_extended ( sb_devc * devc )
{
/* Enable extended mode */
sb_dsp_command ( devc , 0xc6 ) ;
}
static int ess_write ( sb_devc * devc , unsigned char reg , unsigned char data )
{
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " FKS: write reg %x: %x \n " , reg , data ) ;
# endif
/* Write a byte to an extended mode register of ES1688 */
if ( ! sb_dsp_command ( devc , reg ) )
return 0 ;
return sb_dsp_command ( devc , data ) ;
}
static int ess_read ( sb_devc * devc , unsigned char reg )
{
/* Read a byte from an extended mode register of ES1688 */
/* Read register command */
if ( ! sb_dsp_command ( devc , 0xc0 ) ) return - 1 ;
if ( ! sb_dsp_command ( devc , reg ) ) return - 1 ;
return sb_dsp_get_byte ( devc ) ;
}
int ess_dsp_reset ( sb_devc * devc )
{
int loopc ;
# ifdef FKS_REG_LOGGING
printk ( KERN_INFO " FKS: ess_dsp_reset 1 \n " ) ;
ess_show_mixerregs ( devc ) ;
# endif
outb ( 3 , DSP_RESET ) ; /* Reset FIFO too */
udelay ( 10 ) ;
outb ( 0 , DSP_RESET ) ;
udelay ( 30 ) ;
for ( loopc = 0 ; loopc < 1000 & & ! ( inb ( DSP_DATA_AVAIL ) & 0x80 ) ; loopc + + ) ;
if ( inb ( DSP_READ ) ! = 0xAA ) {
DDB ( printk ( " sb: No response to RESET \n " ) ) ;
return 0 ; /* Sorry */
}
ess_extended ( devc ) ;
# ifdef FKS_LOGGING
printk ( KERN_INFO " FKS: dsp_reset 2 \n " ) ;
ess_show_mixerregs ( devc ) ;
# endif
return 1 ;
}
static int ess_irq_bits ( int irq )
{
switch ( irq ) {
case 2 :
case 9 :
return 0 ;
case 5 :
return 1 ;
case 7 :
return 2 ;
case 10 :
return 3 ;
default :
printk ( KERN_ERR " ESS1688: Invalid IRQ %d \n " , irq ) ;
return - 1 ;
}
}
/*
* Set IRQ configuration register for all ESS models
*/
static int ess_common_set_irq_hw ( sb_devc * devc )
{
int irq_bits ;
if ( ( irq_bits = ess_irq_bits ( devc - > irq ) ) = = - 1 ) return 0 ;
if ( ! ess_write ( devc , 0xb1 , 0x50 | ( irq_bits < < 2 ) ) ) {
printk ( KERN_ERR " ES1688: Failed to write to IRQ config register \n " ) ;
return 0 ;
}
return 1 ;
}
/*
* I wanna use modern ES1887 mixer irq handling . Funny is the
* fact that my BIOS wants the same . But suppose someone ' s BIOS
* doesn ' t do this !
* This is independent of duplex . If there ' s a 1887 this will
* prevent it from going into 1888 mode .
*/
static void ess_es1887_set_irq_hw ( sb_devc * devc )
{
int irq_bits ;
if ( ( irq_bits = ess_irq_bits ( devc - > irq ) ) = = - 1 ) return ;
ess_chgmixer ( devc , 0x7f , 0x0f , 0x01 | ( ( irq_bits + 1 ) < < 1 ) ) ;
}
static int ess_set_irq_hw ( sb_devc * devc )
{
if ( devc - > submodel = = SUBMDL_ES1887 ) ess_es1887_set_irq_hw ( devc ) ;
return ess_common_set_irq_hw ( devc ) ;
}
# ifdef FKS_TEST
/*
* FKS_test :
* for ES1887 : 00 , 18 , non wr bits : 0001 1000
* for ES1868 : 00 , b8 , non wr bits : 1011 1000
* for ES1888 : 00 , f8 , non wr bits : 1111 1000
* for ES1688 : 00 , f8 , non wr bits : 1111 1000
* + ES968
*/
static void FKS_test ( sb_devc * devc )
{
int val1 , val2 ;
val1 = ess_getmixer ( devc , 0x64 ) ;
ess_setmixer ( devc , 0x64 , ~ val1 ) ;
val2 = ess_getmixer ( devc , 0x64 ) ^ ~ val1 ;
ess_setmixer ( devc , 0x64 , val1 ) ;
val1 ^ = ess_getmixer ( devc , 0x64 ) ;
printk ( KERN_INFO " FKS: FKS_test %02x, %02x \n " , ( val1 & 0x0ff ) , ( val2 & 0x0ff ) ) ;
} ;
# endif
static unsigned int ess_identify ( sb_devc * devc )
{
unsigned int val ;
unsigned long flags ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
outb ( ( ( unsigned char ) ( 0x40 & 0xff ) ) , MIXER_ADDR ) ;
udelay ( 20 ) ;
val = inb ( MIXER_DATA ) < < 8 ;
udelay ( 20 ) ;
val | = inb ( MIXER_DATA ) ;
udelay ( 20 ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return val ;
}
/*
* ESS technology describes a detection scheme in their docs . It involves
* fiddling with the bits in certain mixer registers . ess_probe is supposed
* to help .
*
* FKS : tracing shows ess_probe writes wrong value to 0x64 . Bit 3 reads 1 , but
* should be written 0 only . Check this .
*/
static int ess_probe ( sb_devc * devc , int reg , int xorval )
{
int val1 , val2 , val3 ;
val1 = ess_getmixer ( devc , reg ) ;
val2 = val1 ^ xorval ;
ess_setmixer ( devc , reg , val2 ) ;
val3 = ess_getmixer ( devc , reg ) ;
ess_setmixer ( devc , reg , val1 ) ;
return ( val2 = = val3 ) ;
}
int ess_init ( sb_devc * devc , struct address_info * hw_config )
{
unsigned char cfg ;
int ess_major = 0 , ess_minor = 0 ;
int i ;
static char name [ 100 ] , modelname [ 10 ] ;
/*
* Try to detect ESS chips .
*/
sb_dsp_command ( devc , 0xe7 ) ; /* Return identification */
for ( i = 1000 ; i ; i - - ) {
if ( inb ( DSP_DATA_AVAIL ) & 0x80 ) {
if ( ess_major = = 0 ) {
ess_major = inb ( DSP_READ ) ;
} else {
ess_minor = inb ( DSP_READ ) ;
break ;
}
}
}
if ( ess_major = = 0 ) return 0 ;
if ( ess_major = = 0x48 & & ( ess_minor & 0xf0 ) = = 0x80 ) {
sprintf ( name , " ESS ES488 AudioDrive (rev %d) " ,
ess_minor & 0x0f ) ;
hw_config - > name = name ;
devc - > model = MDL_SBPRO ;
return 1 ;
}
/*
* This the detection heuristic of ESS technology , though somewhat
* changed to actually make it work .
* This results in the following detection steps :
* - distinct between ES688 and ES1688 + ( as always done in this driver )
* if ES688 we ' re ready
* - try to detect ES1868 , ES1869 or ES1878 ( ess_identify )
* if successful we ' re ready
* - try to detect ES1888 , ES1887 or ES1788 ( aim : detect ES1887 )
* if successful we ' re ready
* - Dunno . Must be 1688. Will do in general
*
* This is the most BETA part of the software : Will the detection
* always work ?
*/
devc - > model = MDL_ESS ;
devc - > submodel = ess_minor & 0x0f ;
if ( ess_major = = 0x68 & & ( ess_minor & 0xf0 ) = = 0x80 ) {
char * chip = NULL ;
int submodel = - 1 ;
switch ( devc - > sbmo . esstype ) {
case ESSTYPE_DETECT :
case ESSTYPE_LIKE20 :
break ;
case 688 :
submodel = 0x00 ;
break ;
case 1688 :
submodel = 0x08 ;
break ;
case 1868 :
submodel = SUBMDL_ES1868 ;
break ;
case 1869 :
submodel = SUBMDL_ES1869 ;
break ;
case 1788 :
submodel = SUBMDL_ES1788 ;
break ;
case 1878 :
submodel = SUBMDL_ES1878 ;
break ;
case 1879 :
submodel = SUBMDL_ES1879 ;
break ;
case 1887 :
submodel = SUBMDL_ES1887 ;
break ;
case 1888 :
submodel = SUBMDL_ES1888 ;
break ;
default :
printk ( KERN_ERR " Invalid esstype=%d specified \n " , devc - > sbmo . esstype ) ;
return 0 ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
if ( submodel ! = - 1 ) {
devc - > submodel = submodel ;
sprintf ( modelname , " ES%d " , devc - > sbmo . esstype ) ;
chip = modelname ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
if ( chip = = NULL & & ( ess_minor & 0x0f ) < 8 ) {
chip = " ES688 " ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
# ifdef FKS_TEST
FKS_test ( devc ) ;
# endif
/*
* If Nothing detected yet , and we want 2.0 behaviour . . .
* Then let ' s assume it ' s ES1688 .
*/
if ( chip = = NULL & & devc - > sbmo . esstype = = ESSTYPE_LIKE20 ) {
chip = " ES1688 " ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
if ( chip = = NULL ) {
int type ;
type = ess_identify ( devc ) ;
switch ( type ) {
case 0x1868 :
chip = " ES1868 " ;
devc - > submodel = SUBMDL_ES1868 ;
break ;
case 0x1869 :
chip = " ES1869 " ;
devc - > submodel = SUBMDL_ES1869 ;
break ;
case 0x1878 :
chip = " ES1878 " ;
devc - > submodel = SUBMDL_ES1878 ;
break ;
case 0x1879 :
chip = " ES1879 " ;
devc - > submodel = SUBMDL_ES1879 ;
break ;
default :
if ( ( type & 0x00ff ) ! = ( ( type > > 8 ) & 0x00ff ) ) {
printk ( " ess_init: Unrecognized %04x \n " , type ) ;
}
2012-09-28 13:24:57 +04:00
}
}
2005-04-17 02:20:36 +04:00
#if 0
/*
* this one failed :
* the probing of bit 4 is another thought : from ES1788 and up , all
* chips seem to have hardware volume control . Bit 4 is readonly to
* check if a hardware volume interrupt has fired .
* Cause ES688 / ES1688 don ' t have this feature , bit 4 might be writeable
* for these chips .
*/
if ( chip = = NULL & & ! ess_probe ( devc , 0x64 , ( 1 < < 4 ) ) ) {
# endif
/*
* the probing of bit 2 is my idea . The ES1887 docs want me to probe
* bit 3. This results in ES1688 being detected as ES1788 .
* Bit 2 is for " Enable HWV IRQE " , but as ES ( 1 ) 688 chips don ' t have
* HardWare Volume , I think they don ' t have this IRQE .
*/
if ( chip = = NULL & & ess_probe ( devc , 0x64 , ( 1 < < 2 ) ) ) {
if ( ess_probe ( devc , 0x70 , 0x7f ) ) {
if ( ess_probe ( devc , 0x64 , ( 1 < < 5 ) ) ) {
chip = " ES1887 " ;
devc - > submodel = SUBMDL_ES1887 ;
} else {
chip = " ES1888 " ;
devc - > submodel = SUBMDL_ES1888 ;
}
} else {
chip = " ES1788 " ;
devc - > submodel = SUBMDL_ES1788 ;
}
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
if ( chip = = NULL ) {
chip = " ES1688 " ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " ESS chip %s %s%s \n "
, chip
, ( devc - > sbmo . esstype = = ESSTYPE_DETECT | | devc - > sbmo . esstype = = ESSTYPE_LIKE20
? " detected "
: " specified "
)
, ( devc - > sbmo . esstype = = ESSTYPE_LIKE20
? " (kernel 2.0 compatible) "
: " "
)
) ;
sprintf ( name , " ESS %s AudioDrive (rev %d) " , chip , ess_minor & 0x0f ) ;
} else {
strcpy ( name , " Jazz16 " ) ;
}
/* AAS: info stolen from ALSA: these boards have different clocks */
switch ( devc - > submodel ) {
/* APPARENTLY NOT 1869 AND 1887
case SUBMDL_ES1869 :
case SUBMDL_ES1887 :
*/
case SUBMDL_ES1888 :
devc - > caps | = SB_CAP_ES18XX_RATE ;
break ;
}
hw_config - > name = name ;
/* FKS: sb_dsp_reset to enable extended mode???? */
sb_dsp_reset ( devc ) ; /* Turn on extended mode */
/*
* Enable joystick and OPL3
*/
cfg = ess_getmixer ( devc , 0x40 ) ;
ess_setmixer ( devc , 0x40 , cfg | 0x03 ) ;
if ( devc - > submodel > = 8 ) { /* ES1688 */
devc - > caps | = SB_NO_MIDI ; /* ES1688 uses MPU401 MIDI mode */
}
sb_dsp_reset ( devc ) ;
/*
* This is important ! If it ' s not done , the IRQ probe in sb_dsp_init
* may fail .
*/
return ess_set_irq_hw ( devc ) ;
}
static int ess_set_dma_hw ( sb_devc * devc )
{
unsigned char cfg , dma_bits = 0 , dma16_bits ;
int dma ;
# ifdef FKS_LOGGING
printk ( KERN_INFO " ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d \n "
, devc - > dma8 , devc - > dma16 , devc - > duplex ) ;
# endif
/*
* FKS : It seems as if this duplex flag isn ' t set yet . Check it .
*/
dma = devc - > dma8 ;
if ( dma > 3 | | dma < 0 | | dma = = 2 ) {
dma_bits = 0 ;
printk ( KERN_ERR " ESS1688: Invalid DMA8 %d \n " , dma ) ;
return 0 ;
} else {
/* Extended mode DMA enable */
cfg = 0x50 ;
if ( dma = = 3 ) {
dma_bits = 3 ;
} else {
dma_bits = dma + 1 ;
}
}
if ( ! ess_write ( devc , 0xb2 , cfg | ( dma_bits < < 2 ) ) ) {
printk ( KERN_ERR " ESS1688: Failed to write to DMA config register \n " ) ;
return 0 ;
}
if ( devc - > duplex ) {
dma = devc - > dma16 ;
dma16_bits = 0 ;
if ( dma > = 0 ) {
switch ( dma ) {
case 0 :
dma_bits = 0x04 ;
break ;
case 1 :
dma_bits = 0x05 ;
break ;
case 3 :
dma_bits = 0x06 ;
break ;
case 5 :
dma_bits = 0x07 ;
dma16_bits = 0x20 ;
break ;
default :
printk ( KERN_ERR " ESS1887: Invalid DMA16 %d \n " , dma ) ;
return 0 ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
ess_chgmixer ( devc , 0x78 , 0x20 , dma16_bits ) ;
ess_chgmixer ( devc , 0x7d , 0x07 , dma_bits ) ;
}
}
return 1 ;
}
/*
* This one is called from sb_dsp_init .
*
* Return values :
* 0 : Failed
* 1 : Succeeded or doesn ' t apply ( not SUBMDL_ES1887 )
*/
int ess_dsp_init ( sb_devc * devc , struct address_info * hw_config )
{
/*
* Caller also checks this , but anyway
*/
if ( devc - > model ! = MDL_ESS ) {
printk ( KERN_INFO " ess_dsp_init for non ESS chip \n " ) ;
return 1 ;
}
/*
* This for ES1887 to run Full Duplex . Actually ES1888
* is allowed to do so too . I have no idea yet if this
* will work for ES1888 however .
*
* For SB16 having both dma8 and dma16 means enable
* Full Duplex . Let ' s try this for ES1887 too
*
*/
if ( devc - > submodel = = SUBMDL_ES1887 ) {
if ( hw_config - > dma2 ! = - 1 ) {
devc - > dma16 = hw_config - > dma2 ;
}
/*
* devc - > duplex initialization is put here , cause
* ess_set_dma_hw needs it .
*/
if ( devc - > dma8 ! = devc - > dma16 & & devc - > dma16 ! = - 1 ) {
devc - > duplex = 1 ;
}
}
if ( ! ess_set_dma_hw ( devc ) ) {
free_irq ( devc - > irq , devc ) ;
return 0 ;
}
return 1 ;
}
/****************************************************************************
* *
* ESS mixer *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define ES688_RECORDING_DEVICES \
( SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD )
# define ES688_MIXER_DEVICES \
( SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE \
| SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME \
| SOUND_MASK_LINE2 | SOUND_MASK_SPEAKER )
# define ES1688_RECORDING_DEVICES \
( ES688_RECORDING_DEVICES )
# define ES1688_MIXER_DEVICES \
( ES688_MIXER_DEVICES | SOUND_MASK_RECLEV )
# define ES1887_RECORDING_DEVICES \
( ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 | SOUND_MASK_SYNTH )
# define ES1887_MIXER_DEVICES \
( ES1688_MIXER_DEVICES )
/*
* Mixer registers of ES1887
*
* These registers specifically take care of recording levels . To make the
* mapping from playback devices to recording devices every recording
* devices = playback device + ES_REC_MIXER_RECDIFF
*/
# define ES_REC_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1)
# define ES_REC_MIXER_RECDIFF (ES_REC_MIXER_RECBASE - SOUND_MIXER_SYNTH)
# define ES_REC_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECPCM (SOUND_MIXER_PCM + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECLINE (SOUND_MIXER_LINE + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECMIC (SOUND_MIXER_MIC + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECCD (SOUND_MIXER_CD + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES_REC_MIXER_RECDIFF)
# define ES_REC_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES_REC_MIXER_RECDIFF)
static mixer_tab es688_mix = {
MIX_ENT ( SOUND_MIXER_VOLUME , 0x32 , 7 , 4 , 0x32 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_BASS , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_TREBLE , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_SYNTH , 0x36 , 7 , 4 , 0x36 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_PCM , 0x14 , 7 , 4 , 0x14 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_SPEAKER , 0x3c , 2 , 3 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE , 0x3e , 7 , 4 , 0x3e , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_MIC , 0x1a , 7 , 4 , 0x1a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_CD , 0x38 , 7 , 4 , 0x38 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_ALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_RECLEV , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_IGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_OGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE2 , 0x3a , 7 , 4 , 0x3a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_LINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 )
} ;
/*
* The ES1688 specifics . . . hopefully correct . . .
* - 6 bit master volume
* I was wrong , ES1888 docs say ES1688 didn ' t have it .
* - RECLEV control
* These may apply to ES688 too . I have no idea .
*/
static mixer_tab es1688_mix = {
MIX_ENT ( SOUND_MIXER_VOLUME , 0x32 , 7 , 4 , 0x32 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_BASS , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_TREBLE , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_SYNTH , 0x36 , 7 , 4 , 0x36 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_PCM , 0x14 , 7 , 4 , 0x14 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_SPEAKER , 0x3c , 2 , 3 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE , 0x3e , 7 , 4 , 0x3e , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_MIC , 0x1a , 7 , 4 , 0x1a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_CD , 0x38 , 7 , 4 , 0x38 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_ALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_RECLEV , 0xb4 , 7 , 4 , 0xb4 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_OGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE2 , 0x3a , 7 , 4 , 0x3a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_LINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 )
} ;
static mixer_tab es1688later_mix = {
MIX_ENT ( SOUND_MIXER_VOLUME , 0x60 , 5 , 6 , 0x62 , 5 , 6 ) ,
MIX_ENT ( SOUND_MIXER_BASS , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_TREBLE , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_SYNTH , 0x36 , 7 , 4 , 0x36 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_PCM , 0x14 , 7 , 4 , 0x14 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_SPEAKER , 0x3c , 2 , 3 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE , 0x3e , 7 , 4 , 0x3e , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_MIC , 0x1a , 7 , 4 , 0x1a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_CD , 0x38 , 7 , 4 , 0x38 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_ALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_RECLEV , 0xb4 , 7 , 4 , 0xb4 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_OGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE2 , 0x3a , 7 , 4 , 0x3a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_LINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 )
} ;
/*
* This one is for all ESS chips with a record mixer .
* It ' s not used ( yet ) however
*/
static mixer_tab es_rec_mix = {
MIX_ENT ( SOUND_MIXER_VOLUME , 0x60 , 5 , 6 , 0x62 , 5 , 6 ) ,
MIX_ENT ( SOUND_MIXER_BASS , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_TREBLE , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_SYNTH , 0x36 , 7 , 4 , 0x36 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_PCM , 0x14 , 7 , 4 , 0x14 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_SPEAKER , 0x3c , 2 , 3 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE , 0x3e , 7 , 4 , 0x3e , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_MIC , 0x1a , 7 , 4 , 0x1a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_CD , 0x38 , 7 , 4 , 0x38 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_ALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_RECLEV , 0xb4 , 7 , 4 , 0xb4 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_OGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE2 , 0x3a , 7 , 4 , 0x3a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_LINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECSYNTH , 0x6b , 7 , 4 , 0x6b , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECSPEAKER , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE , 0x6e , 7 , 4 , 0x6e , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECMIC , 0x68 , 7 , 4 , 0x68 , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECCD , 0x6a , 7 , 4 , 0x6a , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECIMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECRECLEV , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECIGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECOGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE2 , 0x6c , 7 , 4 , 0x6c , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 )
} ;
/*
* This one is for ES1887 . It ' s little different from es_rec_mix : it
* has 0x7c for PCM playback level . This is because ES1887 uses
* Audio 2 for playback .
*/
static mixer_tab es1887_mix = {
MIX_ENT ( SOUND_MIXER_VOLUME , 0x60 , 5 , 6 , 0x62 , 5 , 6 ) ,
MIX_ENT ( SOUND_MIXER_BASS , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_TREBLE , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_SYNTH , 0x36 , 7 , 4 , 0x36 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_PCM , 0x7c , 7 , 4 , 0x7c , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_SPEAKER , 0x3c , 2 , 3 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE , 0x3e , 7 , 4 , 0x3e , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_MIC , 0x1a , 7 , 4 , 0x1a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_CD , 0x38 , 7 , 4 , 0x38 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_ALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_RECLEV , 0xb4 , 7 , 4 , 0xb4 , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_IGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_OGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( SOUND_MIXER_LINE2 , 0x3a , 7 , 4 , 0x3a , 3 , 4 ) ,
MIX_ENT ( SOUND_MIXER_LINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECSYNTH , 0x6b , 7 , 4 , 0x6b , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECSPEAKER , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE , 0x6e , 7 , 4 , 0x6e , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECMIC , 0x68 , 7 , 4 , 0x68 , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECCD , 0x6a , 7 , 4 , 0x6a , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECIMIX , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECALTPCM , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECRECLEV , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECIGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECOGAIN , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE1 , 0x00 , 0 , 0 , 0x00 , 0 , 0 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE2 , 0x6c , 7 , 4 , 0x6c , 3 , 4 ) ,
MIX_ENT ( ES_REC_MIXER_RECLINE3 , 0x00 , 0 , 0 , 0x00 , 0 , 0 )
} ;
static int ess_has_rec_mixer ( int submodel )
{
switch ( submodel ) {
case SUBMDL_ES1887 :
return 1 ;
default :
return 0 ;
2013-10-09 02:55:45 +04:00
}
2005-04-17 02:20:36 +04:00
} ;
# ifdef FKS_LOGGING
static int ess_mixer_mon_regs [ ]
= { 0x70 , 0x71 , 0x72 , 0x74 , 0x76 , 0x78 , 0x7a , 0x7c , 0x7d , 0x7f
, 0xa1 , 0xa2 , 0xa4 , 0xa5 , 0xa8 , 0xa9
, 0xb1 , 0xb2 , 0xb4 , 0xb5 , 0xb6 , 0xb7 , 0xb9
, 0x00 } ;
static void ess_show_mixerregs ( sb_devc * devc )
{
int * mp = ess_mixer_mon_regs ;
return ;
while ( * mp ! = 0 ) {
printk ( KERN_INFO " res (%x)=%x \n " , * mp , ( int ) ( ess_getmixer ( devc , * mp ) ) ) ;
mp + + ;
}
}
# endif
void ess_setmixer ( sb_devc * devc , unsigned int port , unsigned int value )
{
unsigned long flags ;
# ifdef FKS_LOGGING
printk ( KERN_INFO " FKS: write mixer %x: %x \n " , port , value ) ;
# endif
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( port > = 0xa0 ) {
ess_write ( devc , port , value ) ;
} else {
outb ( ( ( unsigned char ) ( port & 0xff ) ) , MIXER_ADDR ) ;
udelay ( 20 ) ;
outb ( ( ( unsigned char ) ( value & 0xff ) ) , MIXER_DATA ) ;
udelay ( 20 ) ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
unsigned int ess_getmixer ( sb_devc * devc , unsigned int port )
{
unsigned int val ;
unsigned long flags ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( port > = 0xa0 ) {
val = ess_read ( devc , port ) ;
} else {
outb ( ( ( unsigned char ) ( port & 0xff ) ) , MIXER_ADDR ) ;
udelay ( 20 ) ;
val = inb ( MIXER_DATA ) ;
udelay ( 20 ) ;
}
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return val ;
}
static void ess_chgmixer
( sb_devc * devc , unsigned int reg , unsigned int mask , unsigned int val )
{
int value ;
value = ess_getmixer ( devc , reg ) ;
value = ( value & ~ mask ) | ( val & mask ) ;
ess_setmixer ( devc , reg , value ) ;
}
/*
* ess_mixer_init must be called from sb_mixer_init
*/
void ess_mixer_init ( sb_devc * devc )
{
devc - > mixer_caps = SOUND_CAP_EXCL_INPUT ;
/*
* Take care of ES1887 specifics . . .
*/
switch ( devc - > submodel ) {
case SUBMDL_ES1887 :
devc - > supported_devices = ES1887_MIXER_DEVICES ;
devc - > supported_rec_devices = ES1887_RECORDING_DEVICES ;
# ifdef FKS_LOGGING
printk ( KERN_INFO " FKS: ess_mixer_init dup = %d \n " , devc - > duplex ) ;
# endif
if ( devc - > duplex ) {
devc - > iomap = & es1887_mix ;
devc - > iomap_sz = ARRAY_SIZE ( es1887_mix ) ;
} else {
devc - > iomap = & es_rec_mix ;
devc - > iomap_sz = ARRAY_SIZE ( es_rec_mix ) ;
}
break ;
default :
if ( devc - > submodel < 8 ) {
devc - > supported_devices = ES688_MIXER_DEVICES ;
devc - > supported_rec_devices = ES688_RECORDING_DEVICES ;
devc - > iomap = & es688_mix ;
devc - > iomap_sz = ARRAY_SIZE ( es688_mix ) ;
} else {
/*
* es1688 has 4 bits master vol .
* later chips have 6 bits ( ? )
*/
devc - > supported_devices = ES1688_MIXER_DEVICES ;
devc - > supported_rec_devices = ES1688_RECORDING_DEVICES ;
if ( devc - > submodel < 0x10 ) {
devc - > iomap = & es1688_mix ;
devc - > iomap_sz = ARRAY_SIZE ( es688_mix ) ;
} else {
devc - > iomap = & es1688later_mix ;
devc - > iomap_sz = ARRAY_SIZE ( es1688later_mix ) ;
}
}
}
}
/*
* Changing playback levels at an ESS chip with record mixer means having to
* take care of recording levels of recorded inputs ( devc - > recmask ) too !
*/
int ess_mixer_set ( sb_devc * devc , int dev , int left , int right )
{
if ( ess_has_rec_mixer ( devc - > submodel ) & & ( devc - > recmask & ( 1 < < dev ) ) ) {
sb_common_mixer_set ( devc , dev + ES_REC_MIXER_RECDIFF , left , right ) ;
}
return sb_common_mixer_set ( devc , dev , left , right ) ;
}
/*
* After a sb_dsp_reset extended register 0xb4 ( RECLEV ) is reset too . After
* sb_dsp_reset RECLEV has to be restored . This is where ess_mixer_reload
* helps .
*/
void ess_mixer_reload ( sb_devc * devc , int dev )
{
int left , right , value ;
value = devc - > levels [ dev ] ;
left = value & 0x000000ff ;
right = ( value & 0x0000ff00 ) > > 8 ;
sb_common_mixer_set ( devc , dev , left , right ) ;
}
static int es_rec_set_recmask ( sb_devc * devc , int mask )
{
int i , i_mask , cur_mask , diff_mask ;
int value , left , right ;
# ifdef FKS_LOGGING
printk ( KERN_INFO " FKS: es_rec_set_recmask mask = %x \n " , mask ) ;
# endif
/*
* Changing the recmask on an ESS chip with recording mixer means :
* ( 1 ) Find the differences
* ( 2 ) For " turned-on " inputs : make the recording level the playback level
* ( 3 ) For " turned-off " inputs : make the recording level zero
*/
cur_mask = devc - > recmask ;
diff_mask = ( cur_mask ^ mask ) ;
for ( i = 0 ; i < 32 ; i + + ) {
i_mask = ( 1 < < i ) ;
if ( diff_mask & i_mask ) { /* Difference? (1) */
if ( mask & i_mask ) { /* Turn it on (2) */
value = devc - > levels [ i ] ;
left = value & 0x000000ff ;
right = ( value & 0x0000ff00 ) > > 8 ;
} else { /* Turn it off (3) */
left = 0 ;
right = 0 ;
}
sb_common_mixer_set ( devc , i + ES_REC_MIXER_RECDIFF , left , right ) ;
}
}
return mask ;
}
int ess_set_recmask ( sb_devc * devc , int * mask )
{
/* This applies to ESS chips with record mixers only! */
if ( ess_has_rec_mixer ( devc - > submodel ) ) {
* mask = es_rec_set_recmask ( devc , * mask ) ;
return 1 ; /* Applied */
} else {
return 0 ; /* Not applied */
}
}
/*
* ess_mixer_reset must be called from sb_mixer_reset
*/
int ess_mixer_reset ( sb_devc * devc )
{
/*
* Separate actions for ESS chips with a record mixer :
*/
if ( ess_has_rec_mixer ( devc - > submodel ) ) {
switch ( devc - > submodel ) {
case SUBMDL_ES1887 :
/*
* Separate actions for ES1887 :
* Change registers 7 a and 1 c to make the record mixer the
* actual recording source .
*/
ess_chgmixer ( devc , 0x7a , 0x18 , 0x08 ) ;
ess_chgmixer ( devc , 0x1c , 0x07 , 0x07 ) ;
break ;
2012-09-28 13:24:57 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Call set_recmask for proper initialization
*/
devc - > recmask = devc - > supported_rec_devices ;
es_rec_set_recmask ( devc , 0 ) ;
devc - > recmask = 0 ;
return 1 ; /* We took care of recmask. */
} else {
return 0 ; /* We didn't take care; caller do it */
}
}
/****************************************************************************
* *
* ESS midi *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* FKS : IRQ may be shared . Hm . And if so ? Then What ?
*/
int ess_midi_init ( sb_devc * devc , struct address_info * hw_config )
{
unsigned char cfg , tmp ;
cfg = ess_getmixer ( devc , 0x40 ) & 0x03 ;
if ( devc - > submodel < 8 ) {
ess_setmixer ( devc , 0x40 , cfg | 0x03 ) ; /* Enable OPL3 & joystick */
return 0 ; /* ES688 doesn't support MPU401 mode */
}
tmp = ( hw_config - > io_base & 0x0f0 ) > > 4 ;
if ( tmp > 3 ) {
ess_setmixer ( devc , 0x40 , cfg ) ;
return 0 ;
}
cfg | = tmp < < 3 ;
tmp = 1 ; /* MPU enabled without interrupts */
/* May be shared: if so the value is -ve */
switch ( abs ( hw_config - > irq ) ) {
case 9 :
tmp = 0x4 ;
break ;
case 5 :
tmp = 0x5 ;
break ;
case 7 :
tmp = 0x6 ;
break ;
case 10 :
tmp = 0x7 ;
break ;
default :
return 0 ;
}
cfg | = tmp < < 5 ;
ess_setmixer ( devc , 0x40 , cfg | 0x03 ) ;
return 1 ;
}