2005-04-17 02:20:36 +04:00
/*
2006-10-04 01:01:26 +04:00
* sound / oss / sb_audio . c
2005-04-17 02:20:36 +04:00
*
* Audio routines for Sound Blaster compatible cards .
*
*
* Copyright ( C ) by Hannu Savolainen 1993 - 1997
*
* OSS / Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE ( GPL )
* Version 2 ( June 1991 ) . See the " COPYING " file distributed with this software
* for more info .
*
* Changes
* Alan Cox : Formatting and clean ups
*
* Status
* Mostly working . Weird uart bug causing irq storms
*
* Daniel J . Rodriksson : Changes to make sb16 work full duplex .
* Maybe other 16 bit cards in this code could behave
* the same .
* Chris Rankin : Use spinlocks instead of CLI / STI
*/
# include <linux/spinlock.h>
# include "sound_config.h"
# include "sb_mixer.h"
# include "sb.h"
# include "sb_ess.h"
int sb_audio_open ( int dev , int mode )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long flags ;
if ( devc = = NULL )
{
printk ( KERN_ERR " Sound Blaster: incomplete initialization. \n " ) ;
return - ENXIO ;
}
if ( devc - > caps & SB_NO_RECORDING & & mode & OPEN_READ )
{
if ( mode = = OPEN_READ )
return - EPERM ;
}
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( devc - > opened )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return - EBUSY ;
}
if ( devc - > dma16 ! = - 1 & & devc - > dma16 ! = devc - > dma8 & & ! devc - > duplex )
{
if ( sound_open_dma ( devc - > dma16 , " Sound Blaster 16 bit " ) )
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
return - EBUSY ;
}
}
devc - > opened = mode ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > irq_mode = IMODE_NONE ;
devc - > irq_mode_16 = IMODE_NONE ;
devc - > fullduplex = devc - > duplex & &
( ( mode & OPEN_READ ) & & ( mode & OPEN_WRITE ) ) ;
sb_dsp_reset ( devc ) ;
/* At first glance this check isn't enough, some ESS chips might not
* have a RECLEV . However if they don ' t common_mixer_set will refuse
* cause devc - > iomap has no register mapping for RECLEV
*/
if ( devc - > model = = MDL_ESS ) ess_mixer_reload ( devc , SOUND_MIXER_RECLEV ) ;
/* The ALS007 seems to require that the DSP be removed from the output */
/* in order for recording to be activated properly. This is done by */
/* setting the appropriate bits of the output control register 4ch to */
/* zero. This code assumes that the output control registers are not */
/* used anywhere else and therefore the DSP bits are *always* ON for */
/* output and OFF for sampling. */
if ( devc - > submodel = = SUBMDL_ALS007 )
{
if ( mode & OPEN_READ )
sb_setmixer ( devc , ALS007_OUTPUT_CTRL2 ,
sb_getmixer ( devc , ALS007_OUTPUT_CTRL2 ) & 0xf9 ) ;
else
sb_setmixer ( devc , ALS007_OUTPUT_CTRL2 ,
sb_getmixer ( devc , ALS007_OUTPUT_CTRL2 ) | 0x06 ) ;
}
return 0 ;
}
void sb_audio_close ( int dev )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
/* fix things if mmap turned off fullduplex */
if ( devc - > duplex
& & ! devc - > fullduplex
& & ( devc - > opened & OPEN_READ ) & & ( devc - > opened & OPEN_WRITE ) )
{
struct dma_buffparms * dmap_temp ;
dmap_temp = audio_devs [ dev ] - > dmap_out ;
audio_devs [ dev ] - > dmap_out = audio_devs [ dev ] - > dmap_in ;
audio_devs [ dev ] - > dmap_in = dmap_temp ;
}
audio_devs [ dev ] - > dmap_out - > dma = devc - > dma8 ;
audio_devs [ dev ] - > dmap_in - > dma = ( devc - > duplex ) ?
devc - > dma16 : devc - > dma8 ;
if ( devc - > dma16 ! = - 1 & & devc - > dma16 ! = devc - > dma8 & & ! devc - > duplex )
sound_close_dma ( devc - > dma16 ) ;
/* For ALS007, turn DSP output back on if closing the device for read */
if ( ( devc - > submodel = = SUBMDL_ALS007 ) & & ( devc - > opened & OPEN_READ ) )
{
sb_setmixer ( devc , ALS007_OUTPUT_CTRL2 ,
sb_getmixer ( devc , ALS007_OUTPUT_CTRL2 ) | 0x06 ) ;
}
devc - > opened = 0 ;
}
static void sb_set_output_parms ( int dev , unsigned long buf , int nr_bytes ,
int intrflag )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( ! devc - > fullduplex | | devc - > bits = = AFMT_S16_LE )
{
devc - > trg_buf = buf ;
devc - > trg_bytes = nr_bytes ;
devc - > trg_intrflag = intrflag ;
devc - > irq_mode = IMODE_OUTPUT ;
}
else
{
devc - > trg_buf_16 = buf ;
devc - > trg_bytes_16 = nr_bytes ;
devc - > trg_intrflag_16 = intrflag ;
devc - > irq_mode_16 = IMODE_OUTPUT ;
}
}
static void sb_set_input_parms ( int dev , unsigned long buf , int count , int intrflag )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( ! devc - > fullduplex | | devc - > bits ! = AFMT_S16_LE )
{
devc - > trg_buf = buf ;
devc - > trg_bytes = count ;
devc - > trg_intrflag = intrflag ;
devc - > irq_mode = IMODE_INPUT ;
}
else
{
devc - > trg_buf_16 = buf ;
devc - > trg_bytes_16 = count ;
devc - > trg_intrflag_16 = intrflag ;
devc - > irq_mode_16 = IMODE_INPUT ;
}
}
/*
* SB1 . x compatible routines
*/
static void sb1_audio_output_block ( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
unsigned long flags ;
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 )
count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_OUTPUT ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x14 ) ) /* 8 bit DAC using DMA */
{
sb_dsp_command ( devc , ( unsigned char ) ( count & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( count > > 8 ) & 0xff ) ) ;
}
else
printk ( KERN_WARNING " Sound Blaster: unable to start DAC. \n " ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > intr_active = 1 ;
}
static void sb1_audio_start_input ( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
unsigned long flags ;
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
/*
* Start a DMA input to the buffer pointed by dmaqtail
*/
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 )
count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_INPUT ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x24 ) ) /* 8 bit ADC using DMA */
{
sb_dsp_command ( devc , ( unsigned char ) ( count & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( count > > 8 ) & 0xff ) ) ;
}
else
printk ( KERN_ERR " Sound Blaster: unable to start ADC. \n " ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > intr_active = 1 ;
}
static void sb1_audio_trigger ( int dev , int bits )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
bits & = devc - > irq_mode ;
if ( ! bits )
sb_dsp_command ( devc , 0xd0 ) ; /* Halt DMA */
else
{
switch ( devc - > irq_mode )
{
case IMODE_INPUT :
sb1_audio_start_input ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
case IMODE_OUTPUT :
sb1_audio_output_block ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
}
}
devc - > trigger_bits = bits ;
}
static int sb1_audio_prepare_for_input ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long flags ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x40 ) )
sb_dsp_command ( devc , devc - > tconst ) ;
sb_dsp_command ( devc , DSP_CMD_SPKOFF ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > trigger_bits = 0 ;
return 0 ;
}
static int sb1_audio_prepare_for_output ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long flags ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x40 ) )
sb_dsp_command ( devc , devc - > tconst ) ;
sb_dsp_command ( devc , DSP_CMD_SPKON ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > trigger_bits = 0 ;
return 0 ;
}
static int sb1_audio_set_speed ( int dev , int speed )
{
int max_speed = 23000 ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
int tmp ;
if ( devc - > opened & OPEN_READ )
max_speed = 13000 ;
if ( speed > 0 )
{
if ( speed < 4000 )
speed = 4000 ;
if ( speed > max_speed )
speed = max_speed ;
devc - > tconst = ( 256 - ( ( 1000000 + speed / 2 ) / speed ) ) & 0xff ;
tmp = 256 - devc - > tconst ;
speed = ( 1000000 + tmp / 2 ) / tmp ;
devc - > speed = speed ;
}
return devc - > speed ;
}
static short sb1_audio_set_channels ( int dev , short channels )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
return devc - > channels = 1 ;
}
static unsigned int sb1_audio_set_bits ( int dev , unsigned int bits )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
return devc - > bits = 8 ;
}
static void sb1_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 ) ;
}
/*
* SB 2.0 and SB 2.01 compatible routines
*/
static void sb20_audio_output_block ( int dev , unsigned long buf , int nr_bytes ,
int intrflag )
{
unsigned long flags ;
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned char cmd ;
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 )
count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_OUTPUT ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x48 ) ) /* DSP Block size */
{
sb_dsp_command ( devc , ( unsigned char ) ( count & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( count > > 8 ) & 0xff ) ) ;
if ( devc - > speed * devc - > channels < = 23000 )
cmd = 0x1c ; /* 8 bit PCM output */
else
cmd = 0x90 ; /* 8 bit high speed PCM output (SB2.01/Pro) */
if ( ! sb_dsp_command ( devc , cmd ) )
printk ( KERN_ERR " Sound Blaster: unable to start DAC. \n " ) ;
}
else
printk ( KERN_ERR " Sound Blaster: unable to start DAC. \n " ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > intr_active = 1 ;
}
static void sb20_audio_start_input ( int dev , unsigned long buf , int nr_bytes , int intrflag )
{
unsigned long flags ;
int count = nr_bytes ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned char cmd ;
/*
* Start a DMA input to the buffer pointed by dmaqtail
*/
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
if ( audio_devs [ dev ] - > dmap_out - > dma > 3 )
count > > = 1 ;
count - - ;
devc - > irq_mode = IMODE_INPUT ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x48 ) ) /* DSP Block size */
{
sb_dsp_command ( devc , ( unsigned char ) ( count & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( count > > 8 ) & 0xff ) ) ;
if ( devc - > speed * devc - > channels < = ( devc - > major = = 3 ? 23000 : 13000 ) )
cmd = 0x2c ; /* 8 bit PCM input */
else
cmd = 0x98 ; /* 8 bit high speed PCM input (SB2.01/Pro) */
if ( ! sb_dsp_command ( devc , cmd ) )
printk ( KERN_ERR " Sound Blaster: unable to start ADC. \n " ) ;
}
else
printk ( KERN_ERR " Sound Blaster: unable to start ADC. \n " ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > intr_active = 1 ;
}
static void sb20_audio_trigger ( int dev , int bits )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
bits & = devc - > irq_mode ;
if ( ! bits )
sb_dsp_command ( devc , 0xd0 ) ; /* Halt DMA */
else
{
switch ( devc - > irq_mode )
{
case IMODE_INPUT :
sb20_audio_start_input ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
case IMODE_OUTPUT :
sb20_audio_output_block ( dev , devc - > trg_buf , devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
}
}
devc - > trigger_bits = bits ;
}
/*
* SB2 .01 specific speed setup
*/
static int sb201_audio_set_speed ( int dev , int speed )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
int tmp ;
int s = speed * devc - > channels ;
if ( speed > 0 )
{
if ( speed < 4000 )
speed = 4000 ;
if ( speed > 44100 )
speed = 44100 ;
if ( devc - > opened & OPEN_READ & & speed > 15000 )
speed = 15000 ;
devc - > tconst = ( 256 - ( ( 1000000 + s / 2 ) / s ) ) & 0xff ;
tmp = 256 - devc - > tconst ;
speed = ( ( 1000000 + tmp / 2 ) / tmp ) / devc - > channels ;
devc - > speed = speed ;
}
return devc - > speed ;
}
/*
* SB Pro specific routines
*/
static int sbpro_audio_prepare_for_input ( int dev , int bsize , int bcount )
{ /* For SB Pro and Jazz16 */
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long flags ;
unsigned char bits = 0 ;
if ( devc - > dma16 > = 0 & & devc - > dma16 ! = devc - > dma8 )
audio_devs [ dev ] - > dmap_out - > dma = audio_devs [ dev ] - > dmap_in - > dma =
devc - > bits = = 16 ? devc - > dma16 : devc - > dma8 ;
if ( devc - > model = = MDL_JAZZ | | devc - > model = = MDL_SMW )
if ( devc - > bits = = AFMT_S16_LE )
bits = 0x04 ; /* 16 bit mode */
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x40 ) )
sb_dsp_command ( devc , devc - > tconst ) ;
sb_dsp_command ( devc , DSP_CMD_SPKOFF ) ;
if ( devc - > channels = = 1 )
sb_dsp_command ( devc , 0xa0 | bits ) ; /* Mono input */
else
sb_dsp_command ( devc , 0xa8 | bits ) ; /* Stereo input */
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
devc - > trigger_bits = 0 ;
return 0 ;
}
static int sbpro_audio_prepare_for_output ( int dev , int bsize , int bcount )
{ /* For SB Pro and Jazz16 */
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long flags ;
unsigned char tmp ;
unsigned char bits = 0 ;
if ( devc - > dma16 > = 0 & & devc - > dma16 ! = devc - > dma8 )
audio_devs [ dev ] - > dmap_out - > dma = audio_devs [ dev ] - > dmap_in - > dma = devc - > bits = = 16 ? devc - > dma16 : devc - > dma8 ;
if ( devc - > model = = MDL_SBPRO )
sb_mixer_set_stereo ( devc , devc - > channels = = 2 ) ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
if ( sb_dsp_command ( devc , 0x40 ) )
sb_dsp_command ( devc , devc - > tconst ) ;
sb_dsp_command ( devc , DSP_CMD_SPKON ) ;
if ( devc - > model = = MDL_JAZZ | | devc - > model = = MDL_SMW )
{
if ( devc - > bits = = AFMT_S16_LE )
bits = 0x04 ; /* 16 bit mode */
if ( devc - > channels = = 1 )
sb_dsp_command ( devc , 0xa0 | bits ) ; /* Mono output */
else
sb_dsp_command ( devc , 0xa8 | bits ) ; /* Stereo output */
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
else
{
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
tmp = sb_getmixer ( devc , 0x0e ) ;
if ( devc - > channels = = 1 )
tmp & = ~ 0x02 ;
else
tmp | = 0x02 ;
sb_setmixer ( devc , 0x0e , tmp ) ;
}
devc - > trigger_bits = 0 ;
return 0 ;
}
static int sbpro_audio_set_speed ( int dev , int speed )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( speed > 0 )
{
if ( speed < 4000 )
speed = 4000 ;
if ( speed > 44100 )
speed = 44100 ;
if ( devc - > channels > 1 & & speed > 22050 )
speed = 22050 ;
sb201_audio_set_speed ( dev , speed ) ;
}
return devc - > speed ;
}
static short sbpro_audio_set_channels ( int dev , short channels )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( channels = = 1 | | channels = = 2 )
{
if ( channels ! = devc - > channels )
{
devc - > channels = channels ;
if ( devc - > model = = MDL_SBPRO & & devc - > channels = = 2 )
sbpro_audio_set_speed ( dev , devc - > speed ) ;
}
}
return devc - > channels ;
}
static int jazz16_audio_set_speed ( int dev , int speed )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( speed > 0 )
{
int tmp ;
int s = speed * devc - > channels ;
if ( speed < 5000 )
speed = 5000 ;
if ( speed > 44100 )
speed = 44100 ;
devc - > tconst = ( 256 - ( ( 1000000 + s / 2 ) / s ) ) & 0xff ;
tmp = 256 - devc - > tconst ;
speed = ( ( 1000000 + tmp / 2 ) / tmp ) / devc - > channels ;
devc - > speed = speed ;
}
return devc - > speed ;
}
/*
* SB16 specific routines
*/
static int sb16_audio_set_speed ( int dev , int speed )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
int max_speed = devc - > submodel = = SUBMDL_ALS100 ? 48000 : 44100 ;
if ( speed > 0 )
{
if ( speed < 5000 )
speed = 5000 ;
if ( speed > max_speed )
speed = max_speed ;
devc - > speed = speed ;
}
return devc - > speed ;
}
static unsigned int sb16_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 ;
}
static int sb16_audio_prepare_for_input ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( ! devc - > fullduplex )
{
audio_devs [ dev ] - > dmap_out - > dma =
audio_devs [ dev ] - > dmap_in - > dma =
devc - > bits = = AFMT_S16_LE ?
devc - > dma16 : devc - > dma8 ;
}
else if ( devc - > bits = = AFMT_S16_LE )
{
audio_devs [ dev ] - > dmap_out - > dma = devc - > dma8 ;
audio_devs [ dev ] - > dmap_in - > dma = devc - > dma16 ;
}
else
{
audio_devs [ dev ] - > dmap_out - > dma = devc - > dma16 ;
audio_devs [ dev ] - > dmap_in - > dma = devc - > dma8 ;
}
devc - > trigger_bits = 0 ;
return 0 ;
}
static int sb16_audio_prepare_for_output ( int dev , int bsize , int bcount )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( ! devc - > fullduplex )
{
audio_devs [ dev ] - > dmap_out - > dma =
audio_devs [ dev ] - > dmap_in - > dma =
devc - > bits = = AFMT_S16_LE ?
devc - > dma16 : devc - > dma8 ;
}
else if ( devc - > bits = = AFMT_S16_LE )
{
audio_devs [ dev ] - > dmap_out - > dma = devc - > dma8 ;
audio_devs [ dev ] - > dmap_in - > dma = devc - > dma16 ;
}
else
{
audio_devs [ dev ] - > dmap_out - > dma = devc - > dma16 ;
audio_devs [ dev ] - > dmap_in - > dma = devc - > dma8 ;
}
devc - > trigger_bits = 0 ;
return 0 ;
}
static void sb16_audio_output_block ( int dev , unsigned long buf , int count ,
int intrflag )
{
unsigned long flags , cnt ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
unsigned long bits ;
if ( ! devc - > fullduplex | | devc - > bits = = AFMT_S16_LE )
{
devc - > irq_mode = IMODE_OUTPUT ;
devc - > intr_active = 1 ;
}
else
{
devc - > irq_mode_16 = IMODE_OUTPUT ;
devc - > intr_active_16 = 1 ;
}
/* save value */
spin_lock_irqsave ( & devc - > lock , flags ) ;
bits = devc - > bits ;
if ( devc - > fullduplex )
devc - > bits = ( devc - > bits = = AFMT_S16_LE ) ?
AFMT_U8 : AFMT_S16_LE ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
cnt = count ;
if ( devc - > bits = = AFMT_S16_LE )
cnt > > = 1 ;
cnt - - ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */
sb_dsp_command ( devc , 0x41 ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( devc - > speed > > 8 ) & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( devc - > speed & 0xff ) ) ;
sb_dsp_command ( devc , ( devc - > bits = = AFMT_S16_LE ? 0xb6 : 0xc6 ) ) ;
sb_dsp_command ( devc , ( ( devc - > channels = = 2 ? 0x20 : 0 ) +
( devc - > bits = = AFMT_S16_LE ? 0x10 : 0 ) ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( cnt & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( cnt > > 8 ) ) ;
/* restore real value after all programming */
devc - > bits = bits ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
/*
* This fails on the Cyrix MediaGX . If you don ' t have the DMA enabled
* before the first sample arrives it locks up . However even if you
* do enable the DMA in time you just get DMA timeouts and missing
* interrupts and stuff , so for now I ' ve not bothered fixing this either .
*/
static void sb16_audio_start_input ( int dev , unsigned long buf , int count , int intrflag )
{
unsigned long flags , cnt ;
sb_devc * devc = audio_devs [ dev ] - > devc ;
if ( ! devc - > fullduplex | | devc - > bits ! = AFMT_S16_LE )
{
devc - > irq_mode = IMODE_INPUT ;
devc - > intr_active = 1 ;
}
else
{
devc - > irq_mode_16 = IMODE_INPUT ;
devc - > intr_active_16 = 1 ;
}
cnt = count ;
if ( devc - > bits = = AFMT_S16_LE )
cnt > > = 1 ;
cnt - - ;
spin_lock_irqsave ( & devc - > lock , flags ) ;
/* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */
sb_dsp_command ( devc , 0x42 ) ;
sb_dsp_command ( devc , ( unsigned char ) ( ( devc - > speed > > 8 ) & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( devc - > speed & 0xff ) ) ;
sb_dsp_command ( devc , ( devc - > bits = = AFMT_S16_LE ? 0xbe : 0xce ) ) ;
sb_dsp_command ( devc , ( ( devc - > channels = = 2 ? 0x20 : 0 ) +
( devc - > bits = = AFMT_S16_LE ? 0x10 : 0 ) ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( cnt & 0xff ) ) ;
sb_dsp_command ( devc , ( unsigned char ) ( cnt > > 8 ) ) ;
spin_unlock_irqrestore ( & devc - > lock , flags ) ;
}
static void sb16_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 )
sb_dsp_command ( devc , 0xd0 ) ; /* Halt DMA */
else
{
if ( bits )
{
switch ( devc - > irq_mode )
{
case IMODE_INPUT :
sb16_audio_start_input ( dev ,
devc - > trg_buf ,
devc - > trg_bytes ,
devc - > trg_intrflag ) ;
break ;
case IMODE_OUTPUT :
sb16_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 :
sb16_audio_start_input ( dev ,
devc - > trg_buf_16 ,
devc - > trg_bytes_16 ,
devc - > trg_intrflag_16 ) ;
break ;
case IMODE_OUTPUT :
sb16_audio_output_block ( dev ,
devc - > trg_buf_16 ,
devc - > trg_bytes_16 ,
devc - > trg_intrflag_16 ) ;
break ;
}
}
}
devc - > trigger_bits = bits | bits_16 ;
}
static unsigned char lbuf8 [ 2048 ] ;
static signed short * lbuf16 = ( signed short * ) lbuf8 ;
# define LBUFCOPYSIZE 1024
static void
sb16_copy_from_user ( int dev ,
char * localbuf , int localoffs ,
const char __user * userbuf , int useroffs ,
int max_in , int max_out ,
int * used , int * returned ,
int len )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
int i , c , p , locallen ;
unsigned char * buf8 ;
signed short * buf16 ;
/* if not duplex no conversion */
if ( ! devc - > fullduplex )
{
if ( copy_from_user ( localbuf + localoffs ,
userbuf + useroffs , len ) )
return ;
* used = len ;
* returned = len ;
}
else if ( devc - > bits = = AFMT_S16_LE )
{
/* 16 -> 8 */
/* max_in >> 1, max number of samples in ( 16 bits ) */
/* max_out, max number of samples out ( 8 bits ) */
/* len, number of samples that will be taken ( 16 bits )*/
/* c, count of samples remaining in buffer ( 16 bits )*/
/* p, count of samples already processed ( 16 bits )*/
len = ( ( max_in > > 1 ) > max_out ) ? max_out : ( max_in > > 1 ) ;
c = len ;
p = 0 ;
buf8 = ( unsigned char * ) ( localbuf + localoffs ) ;
while ( c )
{
locallen = ( c > = LBUFCOPYSIZE ? LBUFCOPYSIZE : c ) ;
/* << 1 in order to get 16 bit samples */
if ( copy_from_user ( lbuf16 ,
userbuf + useroffs + ( p < < 1 ) ,
locallen < < 1 ) )
return ;
for ( i = 0 ; i < locallen ; i + + )
{
buf8 [ p + i ] = ~ ( ( lbuf16 [ i ] > > 8 ) & 0xff ) ^ 0x80 ;
}
c - = locallen ; p + = locallen ;
}
/* used = ( samples * 16 bits size ) */
* used = max_in > ( max_out < < 1 ) ? ( max_out < < 1 ) : max_in ;
/* returned = ( samples * 8 bits size ) */
* returned = len ;
}
else
{
/* 8 -> 16 */
/* max_in, max number of samples in ( 8 bits ) */
/* max_out >> 1, max number of samples out ( 16 bits ) */
/* len, number of samples that will be taken ( 8 bits )*/
/* c, count of samples remaining in buffer ( 8 bits )*/
/* p, count of samples already processed ( 8 bits )*/
len = max_in > ( max_out > > 1 ) ? ( max_out > > 1 ) : max_in ;
c = len ;
p = 0 ;
buf16 = ( signed short * ) ( localbuf + localoffs ) ;
while ( c )
{
locallen = ( c > = LBUFCOPYSIZE ? LBUFCOPYSIZE : c ) ;
if ( copy_from_user ( lbuf8 ,
userbuf + useroffs + p ,
locallen ) )
return ;
for ( i = 0 ; i < locallen ; i + + )
{
buf16 [ p + i ] = ( ~ lbuf8 [ i ] ^ 0x80 ) < < 8 ;
}
c - = locallen ; p + = locallen ;
}
/* used = ( samples * 8 bits size ) */
* used = len ;
/* returned = ( samples * 16 bits size ) */
* returned = len < < 1 ;
}
}
static void
sb16_audio_mmap ( int dev )
{
sb_devc * devc = audio_devs [ dev ] - > devc ;
devc - > fullduplex = 0 ;
}
static struct audio_driver sb1_audio_driver = /* SB1.x */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sb1_audio_prepare_for_input ,
. prepare_for_output = sb1_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. trigger = sb1_audio_trigger ,
. set_speed = sb1_audio_set_speed ,
. set_bits = sb1_audio_set_bits ,
. set_channels = sb1_audio_set_channels
} ;
static struct audio_driver sb20_audio_driver = /* SB2.0 */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sb1_audio_prepare_for_input ,
. prepare_for_output = sb1_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. trigger = sb20_audio_trigger ,
. set_speed = sb1_audio_set_speed ,
. set_bits = sb1_audio_set_bits ,
. set_channels = sb1_audio_set_channels
} ;
static struct audio_driver sb201_audio_driver = /* SB2.01 */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sb1_audio_prepare_for_input ,
. prepare_for_output = sb1_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. trigger = sb20_audio_trigger ,
. set_speed = sb201_audio_set_speed ,
. set_bits = sb1_audio_set_bits ,
. set_channels = sb1_audio_set_channels
} ;
static struct audio_driver sbpro_audio_driver = /* SB Pro */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sbpro_audio_prepare_for_input ,
. prepare_for_output = sbpro_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. trigger = sb20_audio_trigger ,
. set_speed = sbpro_audio_set_speed ,
. set_bits = sb1_audio_set_bits ,
. set_channels = sbpro_audio_set_channels
} ;
static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sbpro_audio_prepare_for_input ,
. prepare_for_output = sbpro_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. trigger = sb20_audio_trigger ,
. set_speed = jazz16_audio_set_speed ,
. set_bits = sb16_audio_set_bits ,
. set_channels = sbpro_audio_set_channels
} ;
static struct audio_driver sb16_audio_driver = /* SB16 */
{
. owner = THIS_MODULE ,
. open = sb_audio_open ,
. close = sb_audio_close ,
. output_block = sb_set_output_parms ,
. start_input = sb_set_input_parms ,
. prepare_for_input = sb16_audio_prepare_for_input ,
. prepare_for_output = sb16_audio_prepare_for_output ,
. halt_io = sb1_audio_halt_xfer ,
. copy_user = sb16_copy_from_user ,
. trigger = sb16_audio_trigger ,
. set_speed = sb16_audio_set_speed ,
. set_bits = sb16_audio_set_bits ,
. set_channels = sbpro_audio_set_channels ,
. mmap = sb16_audio_mmap
} ;
void sb_audio_init ( sb_devc * devc , char * name , struct module * owner )
{
int audio_flags = 0 ;
int format_mask = AFMT_U8 ;
struct audio_driver * driver = & sb1_audio_driver ;
switch ( devc - > model )
{
case MDL_SB1 : /* SB1.0 or SB 1.5 */
DDB ( printk ( " Will use standard SB1.x driver \n " ) ) ;
audio_flags = DMA_HARDSTOP ;
break ;
case MDL_SB2 :
DDB ( printk ( " Will use SB2.0 driver \n " ) ) ;
audio_flags = DMA_AUTOMODE ;
driver = & sb20_audio_driver ;
break ;
case MDL_SB201 :
DDB ( printk ( " Will use SB2.01 (high speed) driver \n " ) ) ;
audio_flags = DMA_AUTOMODE ;
driver = & sb201_audio_driver ;
break ;
case MDL_JAZZ :
case MDL_SMW :
DDB ( printk ( " Will use Jazz16 driver \n " ) ) ;
audio_flags = DMA_AUTOMODE ;
format_mask | = AFMT_S16_LE ;
driver = & jazz16_audio_driver ;
break ;
case MDL_ESS :
DDB ( printk ( " Will use ESS ES688/1688 driver \n " ) ) ;
driver = ess_audio_init ( devc , & audio_flags , & format_mask ) ;
break ;
case MDL_SB16 :
DDB ( printk ( " Will use SB16 driver \n " ) ) ;
audio_flags = DMA_AUTOMODE ;
format_mask | = AFMT_S16_LE ;
if ( devc - > dma8 ! = devc - > dma16 & & devc - > dma16 ! = - 1 )
{
audio_flags | = DMA_DUPLEX ;
devc - > duplex = 1 ;
}
driver = & sb16_audio_driver ;
break ;
default :
DDB ( printk ( " Will use SB Pro driver \n " ) ) ;
audio_flags = DMA_AUTOMODE ;
driver = & sbpro_audio_driver ;
}
if ( owner )
driver - > owner = owner ;
if ( ( devc - > dev = sound_install_audiodrv ( AUDIO_DRIVER_VERSION ,
name , driver , sizeof ( struct audio_driver ) ,
audio_flags , format_mask , devc ,
devc - > dma8 ,
devc - > duplex ? devc - > dma16 : devc - > dma8 ) ) < 0 )
{
printk ( KERN_ERR " Sound Blaster: unable to install audio. \n " ) ;
return ;
}
audio_devs [ devc - > dev ] - > mixer_dev = devc - > my_mixerdev ;
audio_devs [ devc - > dev ] - > min_fragment = 5 ;
}