2005-11-08 21:37:04 -08:00
/*
2005-11-08 21:37:11 -08:00
* SAA713x ALSA support for V4L
2005-11-08 21:37:04 -08:00
*
*
2005-11-08 21:37:11 -08:00
* Caveats :
* - Volume doesn ' t work ( it ' s always at max )
*
* 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 , version 2
*
* 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
2005-11-08 21:37:04 -08:00
*
*/
# include <sound/driver.h>
2005-11-08 21:37:11 -08:00
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/time.h>
# include <linux/wait.h>
# include <linux/moduleparam.h>
# include <linux/module.h>
2005-11-08 21:37:04 -08:00
# include <sound/core.h>
# include <sound/control.h>
2005-11-08 21:37:11 -08:00
# include <sound/pcm.h>
2005-11-13 16:08:10 -08:00
# include <sound/pcm_params.h>
2005-11-08 21:37:04 -08:00
# include <sound/initval.h>
2005-11-13 16:07:51 -08:00
# include <linux/interrupt.h>
2005-11-08 21:37:04 -08:00
# include "saa7134.h"
# include "saa7134-reg.h"
2005-11-08 21:38:53 -08:00
static unsigned int debug = 0 ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " enable debug messages [alsa] " ) ;
2005-11-08 21:37:14 -08:00
/*
* Configuration macros
*/
2005-11-08 21:37:11 -08:00
/* defaults */
2005-11-08 21:37:14 -08:00
# define MIXER_ADDR_TVTUNER 0
# define MIXER_ADDR_LINE1 1
# define MIXER_ADDR_LINE2 2
# define MIXER_ADDR_LAST 2
2005-11-08 21:37:04 -08:00
2005-12-12 00:37:28 -08:00
2005-11-08 21:37:11 -08:00
static int index [ SNDRV_CARDS ] = SNDRV_DEFAULT_IDX ; /* Index 0-MAX */
static char * id [ SNDRV_CARDS ] = SNDRV_DEFAULT_STR ; /* ID for this card */
static int enable [ SNDRV_CARDS ] = { 1 , [ 1 . . . ( SNDRV_CARDS - 1 ) ] = 0 } ;
2005-11-08 21:38:54 -08:00
module_param_array ( index , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( index , " Index value for SAA7134 capture interface(s). " ) ;
2005-11-08 21:38:53 -08:00
# define dprintk(fmt, arg...) if (debug) \
2005-12-19 08:53:59 -02:00
printk ( KERN_DEBUG " %s/alsa: " fmt , dev - > name , # # arg )
2005-12-12 00:37:28 -08:00
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:14 -08:00
/*
* Main chip structure
*/
2005-12-12 00:37:28 -08:00
2005-11-08 21:37:11 -08:00
typedef struct snd_card_saa7134 {
snd_card_t * card ;
spinlock_t mixer_lock ;
int mixer_volume [ MIXER_ADDR_LAST + 1 ] [ 2 ] ;
int capture_source [ MIXER_ADDR_LAST + 1 ] [ 2 ] ;
2005-11-08 21:37:43 -08:00
struct pci_dev * pci ;
2005-11-13 16:08:00 -08:00
struct saa7134_dev * dev ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:43 -08:00
unsigned long iobase ;
int irq ;
2005-11-08 21:37:11 -08:00
spinlock_t lock ;
} snd_card_saa7134_t ;
2005-11-08 21:38:14 -08:00
2005-11-08 21:37:14 -08:00
/*
* PCM structure
*/
2005-11-08 21:37:11 -08:00
typedef struct snd_card_saa7134_pcm {
2005-11-13 16:08:00 -08:00
struct saa7134_dev * dev ;
2005-11-08 21:37:11 -08:00
spinlock_t lock ;
2005-11-13 16:08:00 -08:00
2005-11-08 21:37:11 -08:00
snd_pcm_substream_t * substream ;
} snd_card_saa7134_pcm_t ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
static snd_card_t * snd_saa7134_cards [ SNDRV_CARDS ] ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:53 -08:00
2005-11-08 21:37:14 -08:00
/*
* saa7134 DMA audio stop
*
* Called when the capture device is released or the buffer overflows
*
2005-11-13 16:07:47 -08:00
* - Copied verbatim from saa7134 - oss ' s dsp_dma_stop .
2005-11-08 21:37:14 -08:00
*
*/
2005-11-08 21:37:11 -08:00
static void saa7134_dma_stop ( struct saa7134_dev * dev )
{
2005-11-08 21:38:54 -08:00
dev - > dmasound . dma_blk = - 1 ;
dev - > dmasound . dma_running = 0 ;
2005-11-08 21:37:43 -08:00
saa7134_set_dmabits ( dev ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* saa7134 DMA audio start
*
* Called when preparing the capture device for use
*
2005-11-13 16:07:47 -08:00
* - Copied verbatim from saa7134 - oss ' s dsp_dma_start .
2005-11-08 21:37:14 -08:00
*
*/
2005-11-08 21:37:11 -08:00
static void saa7134_dma_start ( struct saa7134_dev * dev )
{
2005-11-08 21:38:54 -08:00
dev - > dmasound . dma_blk = 0 ;
dev - > dmasound . dma_running = 1 ;
2005-11-08 21:37:43 -08:00
saa7134_set_dmabits ( dev ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* saa7134 audio DMA IRQ handler
*
* Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
* Handles shifting between the 2 buffers , manages the read counters ,
* and notifies ALSA when periods elapse
*
* - Mostly copied from saa7134 - oss ' s saa7134_irq_oss_done .
*
*/
2005-12-01 00:51:35 -08:00
static void saa7134_irq_alsa_done ( struct saa7134_dev * dev ,
unsigned long status )
2005-11-08 21:37:11 -08:00
{
int next_blk , reg = 0 ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
spin_lock ( & dev - > slock ) ;
2005-11-08 21:38:54 -08:00
if ( UNSET = = dev - > dmasound . dma_blk ) {
2005-11-08 21:37:11 -08:00
dprintk ( " irq: recording stopped \n " ) ;
goto done ;
}
if ( 0 ! = ( status & 0x0f000000 ) )
dprintk ( " irq: lost %ld \n " , ( status > > 24 ) & 0x0f ) ;
if ( 0 = = ( status & 0x10000000 ) ) {
/* odd */
2005-11-08 21:38:54 -08:00
if ( 0 = = ( dev - > dmasound . dma_blk & 0x01 ) )
2005-11-08 21:37:11 -08:00
reg = SAA7134_RS_BA1 ( 6 ) ;
} else {
/* even */
2005-11-08 21:38:54 -08:00
if ( 1 = = ( dev - > dmasound . dma_blk & 0x01 ) )
2005-11-08 21:37:11 -08:00
reg = SAA7134_RS_BA2 ( 6 ) ;
}
if ( 0 = = reg ) {
dprintk ( " irq: field oops [%s] \n " ,
( status & 0x10000000 ) ? " even " : " odd " ) ;
goto done ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
if ( dev - > dmasound . read_count > = dev - > dmasound . blksize * ( dev - > dmasound . blocks - 2 ) ) {
dprintk ( " irq: overrun [full=%d/%d] - Blocks in %d \n " , dev - > dmasound . read_count ,
dev - > dmasound . bufsize , dev - > dmasound . blocks ) ;
2005-11-13 16:08:10 -08:00
spin_unlock ( & dev - > slock ) ;
2005-11-08 21:38:54 -08:00
snd_pcm_stop ( dev - > dmasound . substream , SNDRV_PCM_STATE_XRUN ) ;
2005-11-13 16:08:10 -08:00
return ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:43 -08:00
/* next block addr */
2005-11-08 21:38:54 -08:00
next_blk = ( dev - > dmasound . dma_blk + 2 ) % dev - > dmasound . blocks ;
saa_writel ( reg , next_blk * dev - > dmasound . blksize ) ;
2005-11-08 21:38:53 -08:00
if ( debug > 2 )
2005-11-08 21:37:43 -08:00
dprintk ( " irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u \n " ,
( status & 0x10000000 ) ? " even " : " odd " , next_blk ,
2005-11-08 21:38:54 -08:00
next_blk * dev - > dmasound . blksize , dev - > dmasound . blocks , dev - > dmasound . blksize , dev - > dmasound . read_count ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:43 -08:00
/* update status & wake waiting readers */
2005-11-08 21:38:54 -08:00
dev - > dmasound . dma_blk = ( dev - > dmasound . dma_blk + 1 ) % dev - > dmasound . blocks ;
dev - > dmasound . read_count + = dev - > dmasound . blksize ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
dev - > dmasound . recording_on = reg ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
if ( dev - > dmasound . read_count > = snd_pcm_lib_period_bytes ( dev - > dmasound . substream ) ) {
2005-11-08 21:37:43 -08:00
spin_unlock ( & dev - > slock ) ;
2005-11-08 21:38:54 -08:00
snd_pcm_period_elapsed ( dev - > dmasound . substream ) ;
2005-11-08 21:37:43 -08:00
spin_lock ( & dev - > slock ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-13 16:08:00 -08:00
2005-11-08 21:37:11 -08:00
done :
2005-11-08 21:37:43 -08:00
spin_unlock ( & dev - > slock ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:53 -08:00
/*
* IRQ request handler
*
* Runs along with saa7134 ' s IRQ handler , discards anything that isn ' t
* DMA sound
*
*/
static irqreturn_t saa7134_alsa_irq ( int irq , void * dev_id , struct pt_regs * regs )
{
2005-12-12 00:37:27 -08:00
struct saa7134_dmasound * dmasound = dev_id ;
struct saa7134_dev * dev = dmasound - > priv_data ;
2005-11-13 16:08:00 -08:00
2005-11-08 21:38:53 -08:00
unsigned long report , status ;
int loop , handled = 0 ;
for ( loop = 0 ; loop < 10 ; loop + + ) {
report = saa_readl ( SAA7134_IRQ_REPORT ) ;
status = saa_readl ( SAA7134_IRQ_STATUS ) ;
if ( report & SAA7134_IRQ_REPORT_DONE_RA3 ) {
handled = 1 ;
saa_writel ( SAA7134_IRQ_REPORT , report ) ;
saa7134_irq_alsa_done ( dev , status ) ;
} else {
goto out ;
}
}
if ( loop = = 10 ) {
dprintk ( " error! looping IRQ! " ) ;
}
out :
return IRQ_RETVAL ( handled ) ;
}
2005-11-08 21:37:14 -08:00
/*
* ALSA capture trigger
*
* - One of the ALSA capture callbacks .
*
* Called whenever a capture is started or stopped . Must be defined ,
* but there ' s nothing we want to do here
*
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_card_saa7134_capture_trigger ( snd_pcm_substream_t * substream ,
int cmd )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:38:54 -08:00
snd_pcm_runtime_t * runtime = substream - > runtime ;
2005-11-13 16:08:00 -08:00
snd_card_saa7134_pcm_t * pcm = runtime - > private_data ;
struct saa7134_dev * dev = pcm - > dev ;
2005-11-08 21:38:54 -08:00
int err = 0 ;
2005-11-13 16:08:10 -08:00
spin_lock ( & dev - > slock ) ;
2005-11-13 16:07:47 -08:00
if ( cmd = = SNDRV_PCM_TRIGGER_START ) {
2005-11-08 21:38:54 -08:00
/* start dma */
saa7134_dma_start ( dev ) ;
2005-11-13 16:07:47 -08:00
} else if ( cmd = = SNDRV_PCM_TRIGGER_STOP ) {
2005-11-08 21:38:54 -08:00
/* stop dma */
saa7134_dma_stop ( dev ) ;
2005-11-13 16:07:47 -08:00
} else {
err = - EINVAL ;
}
2005-11-13 16:08:10 -08:00
spin_unlock ( & dev - > slock ) ;
2005-11-08 21:38:54 -08:00
2005-11-13 16:07:47 -08:00
return err ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:14 -08:00
/*
* DMA buffer initialization
*
* Uses V4L functions to initialize the DMA . Shouldn ' t be necessary in
* ALSA , but I was unable to use ALSA ' s own DMA , and had to force the
* usage of V4L ' s
*
2005-11-13 16:07:47 -08:00
* - Copied verbatim from saa7134 - oss .
*
2005-11-08 21:37:14 -08:00
*/
2005-11-08 21:37:11 -08:00
static int dsp_buffer_init ( struct saa7134_dev * dev )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:43 -08:00
int err ;
2005-11-13 16:08:00 -08:00
BUG_ON ( ! dev - > dmasound . bufsize ) ;
2005-11-08 21:38:54 -08:00
videobuf_dma_init ( & dev - > dmasound . dma ) ;
err = videobuf_dma_init_kernel ( & dev - > dmasound . dma , PCI_DMA_FROMDEVICE ,
( dev - > dmasound . bufsize + PAGE_SIZE ) > > PAGE_SHIFT ) ;
2005-11-08 21:37:43 -08:00
if ( 0 ! = err )
return err ;
return 0 ;
2005-11-08 21:37:04 -08:00
}
2005-11-13 16:08:10 -08:00
/*
* DMA buffer release
*
* Called after closing the device , during snd_card_saa7134_capture_close
*
*/
static int dsp_buffer_free ( struct saa7134_dev * dev )
{
if ( ! dev - > dmasound . blksize )
BUG ( ) ;
videobuf_dma_free ( & dev - > dmasound . dma ) ;
dev - > dmasound . blocks = 0 ;
dev - > dmasound . blksize = 0 ;
dev - > dmasound . bufsize = 0 ;
return 0 ;
}
2005-11-08 21:37:14 -08:00
/*
* ALSA PCM preparation
*
* - One of the ALSA capture callbacks .
*
* Called right after the capture device is opened , this function configures
* the buffer using the previously defined functions , allocates the memory ,
* sets up the hardware registers , and then starts the DMA . When this function
* returns , the audio should be flowing .
*
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
static int snd_card_saa7134_capture_prepare ( snd_pcm_substream_t * substream )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:11 -08:00
snd_pcm_runtime_t * runtime = substream - > runtime ;
2005-11-13 16:08:10 -08:00
int bswap , sign ;
2005-11-08 21:37:43 -08:00
u32 fmt , control ;
2005-11-08 21:37:11 -08:00
snd_card_saa7134_t * saa7134 = snd_pcm_substream_chip ( substream ) ;
2005-11-08 21:37:43 -08:00
struct saa7134_dev * dev ;
2005-11-13 16:08:00 -08:00
snd_card_saa7134_pcm_t * pcm = runtime - > private_data ;
2005-11-08 21:37:11 -08:00
2005-11-13 16:08:00 -08:00
pcm - > dev - > dmasound . substream = substream ;
2005-11-08 21:37:11 -08:00
2005-11-13 16:08:10 -08:00
dev = saa7134 - > dev ;
2005-11-08 21:37:11 -08:00
2005-11-13 16:08:10 -08:00
if ( snd_pcm_format_width ( runtime - > format ) = = 8 )
2005-11-08 21:37:11 -08:00
fmt = 0x00 ;
2005-11-13 16:08:10 -08:00
else
2005-11-08 21:37:11 -08:00
fmt = 0x01 ;
2005-11-08 21:37:43 -08:00
2005-11-13 16:08:10 -08:00
if ( snd_pcm_format_signed ( runtime - > format ) )
2005-11-08 21:37:11 -08:00
sign = 1 ;
2005-11-13 16:08:10 -08:00
else
2005-11-08 21:37:11 -08:00
sign = 0 ;
2005-11-13 16:08:10 -08:00
if ( snd_pcm_format_big_endian ( runtime - > format ) )
bswap = 1 ;
else
bswap = 0 ;
2005-11-08 21:37:43 -08:00
switch ( dev - > pci - > device ) {
case PCI_DEVICE_ID_PHILIPS_SAA7134 :
if ( 1 = = runtime - > channels )
fmt | = ( 1 < < 3 ) ;
if ( 2 = = runtime - > channels )
fmt | = ( 3 < < 3 ) ;
if ( sign )
fmt | = 0x04 ;
2005-11-08 21:38:54 -08:00
fmt | = ( MIXER_ADDR_TVTUNER = = dev - > dmasound . input ) ? 0xc0 : 0x80 ;
saa_writeb ( SAA7134_NUM_SAMPLES0 , ( ( dev - > dmasound . blksize - 1 ) & 0x0000ff ) ) ;
saa_writeb ( SAA7134_NUM_SAMPLES1 , ( ( dev - > dmasound . blksize - 1 ) & 0x00ff00 ) > > 8 ) ;
saa_writeb ( SAA7134_NUM_SAMPLES2 , ( ( dev - > dmasound . blksize - 1 ) & 0xff0000 ) > > 16 ) ;
2005-11-08 21:37:43 -08:00
saa_writeb ( SAA7134_AUDIO_FORMAT_CTRL , fmt ) ;
break ;
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
if ( 1 = = runtime - > channels )
fmt | = ( 1 < < 4 ) ;
if ( 2 = = runtime - > channels )
fmt | = ( 2 < < 4 ) ;
if ( ! sign )
fmt | = 0x04 ;
2005-11-08 21:38:54 -08:00
saa_writel ( SAA7133_NUM_SAMPLES , dev - > dmasound . blksize - 1 ) ;
2005-11-08 21:37:43 -08:00
saa_writel ( SAA7133_AUDIO_CHANNEL , 0x543210 | ( fmt < < 24 ) ) ;
break ;
}
dprintk ( " rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c \n " ,
runtime - > format , runtime - > channels , fmt ,
bswap ? ' b ' : ' - ' ) ;
/* dma: setup channel 6 (= AUDIO) */
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
2005-11-08 21:38:54 -08:00
( dev - > dmasound . pt . dma > > 12 ) ;
2005-11-08 21:37:43 -08:00
if ( bswap )
control | = SAA7134_RS_CONTROL_BSWAP ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:43 -08:00
saa_writel ( SAA7134_RS_BA1 ( 6 ) , 0 ) ;
2005-11-08 21:38:54 -08:00
saa_writel ( SAA7134_RS_BA2 ( 6 ) , dev - > dmasound . blksize ) ;
2005-11-08 21:37:43 -08:00
saa_writel ( SAA7134_RS_PITCH ( 6 ) , 0 ) ;
saa_writel ( SAA7134_RS_CONTROL ( 6 ) , control ) ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:38:54 -08:00
dev - > dmasound . rate = runtime - > rate ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
return 0 ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* ALSA pointer fetching
*
* - One of the ALSA capture callbacks .
*
* Called whenever a period elapses , it must return the current hardware
* position of the buffer .
* Also resets the read counter used to prevent overruns
*
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
static snd_pcm_uframes_t snd_card_saa7134_capture_pointer ( snd_pcm_substream_t * substream )
2005-11-08 21:37:04 -08:00
{
snd_pcm_runtime_t * runtime = substream - > runtime ;
2005-11-13 16:08:00 -08:00
snd_card_saa7134_pcm_t * pcm = runtime - > private_data ;
struct saa7134_dev * dev = pcm - > dev ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
if ( dev - > dmasound . read_count ) {
dev - > dmasound . read_count - = snd_pcm_lib_period_bytes ( substream ) ;
dev - > dmasound . read_offset + = snd_pcm_lib_period_bytes ( substream ) ;
if ( dev - > dmasound . read_offset = = dev - > dmasound . bufsize )
dev - > dmasound . read_offset = 0 ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
return bytes_to_frames ( runtime , dev - > dmasound . read_offset ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* ALSA hardware capabilities definition
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static snd_pcm_hardware_t snd_card_saa7134_capture =
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:43 -08:00
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
2005-11-08 21:37:45 -08:00
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID ) ,
2005-11-08 21:38:54 -08:00
. formats = SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_U16_BE ,
. rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 ,
. rate_min = 32000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 256 * 1024 ) ,
2005-11-08 21:37:11 -08:00
. period_bytes_min = 64 ,
2005-11-08 21:38:54 -08:00
. period_bytes_max = ( 256 * 1024 ) ,
. periods_min = 2 ,
. periods_max = 1024 ,
2005-11-08 21:37:11 -08:00
} ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static void snd_card_saa7134_runtime_free ( snd_pcm_runtime_t * runtime )
{
2005-11-13 16:08:00 -08:00
snd_card_saa7134_pcm_t * pcm = runtime - > private_data ;
2005-11-08 21:37:11 -08:00
2005-11-13 16:08:00 -08:00
kfree ( pcm ) ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:14 -08:00
/*
* ALSA hardware params
*
* - One of the ALSA capture callbacks .
*
* Called on initialization , right before the PCM preparation
*
*/
2005-11-08 21:37:11 -08:00
static int snd_card_saa7134_hw_params ( snd_pcm_substream_t * substream ,
snd_pcm_hw_params_t * hw_params )
2005-11-08 21:37:04 -08:00
{
2005-11-13 16:08:10 -08:00
snd_card_saa7134_t * saa7134 = snd_pcm_substream_chip ( substream ) ;
struct saa7134_dev * dev ;
unsigned int period_size , periods ;
int err ;
period_size = params_period_bytes ( hw_params ) ;
periods = params_periods ( hw_params ) ;
snd_assert ( period_size > = 0x100 & & period_size < = 0x10000 ,
return - EINVAL ) ;
snd_assert ( periods > = 2 , return - EINVAL ) ;
snd_assert ( period_size * periods < = 1024 * 1024 , return - EINVAL ) ;
dev = saa7134 - > dev ;
if ( dev - > dmasound . blocks = = periods & &
dev - > dmasound . blksize = = period_size )
return 0 ;
/* release the old buffer */
if ( substream - > runtime - > dma_area ) {
saa7134_pgtable_free ( dev - > pci , & dev - > dmasound . pt ) ;
videobuf_dma_pci_unmap ( dev - > pci , & dev - > dmasound . dma ) ;
dsp_buffer_free ( dev ) ;
substream - > runtime - > dma_area = NULL ;
}
dev - > dmasound . blocks = periods ;
dev - > dmasound . blksize = period_size ;
dev - > dmasound . bufsize = period_size * periods ;
err = dsp_buffer_init ( dev ) ;
if ( 0 ! = err ) {
dev - > dmasound . blocks = 0 ;
dev - > dmasound . blksize = 0 ;
dev - > dmasound . bufsize = 0 ;
return err ;
}
if ( 0 ! = ( err = videobuf_dma_pci_map ( dev - > pci , & dev - > dmasound . dma ) ) ) {
dsp_buffer_free ( dev ) ;
return err ;
}
if ( 0 ! = ( err = saa7134_pgtable_alloc ( dev - > pci , & dev - > dmasound . pt ) ) ) {
videobuf_dma_pci_unmap ( dev - > pci , & dev - > dmasound . dma ) ;
dsp_buffer_free ( dev ) ;
return err ;
}
if ( 0 ! = ( err = saa7134_pgtable_build ( dev - > pci , & dev - > dmasound . pt ,
dev - > dmasound . dma . sglist ,
dev - > dmasound . dma . sglen ,
0 ) ) ) {
saa7134_pgtable_free ( dev - > pci , & dev - > dmasound . pt ) ;
videobuf_dma_pci_unmap ( dev - > pci , & dev - > dmasound . dma ) ;
dsp_buffer_free ( dev ) ;
return err ;
}
/* I should be able to use runtime->dma_addr in the control
byte , but it doesn ' t work . So I allocate the DMA using the
V4L functions , and force ALSA to use that as the DMA area */
substream - > runtime - > dma_area = dev - > dmasound . dma . vmalloc ;
return 1 ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:14 -08:00
/*
* ALSA hardware release
*
* - One of the ALSA capture callbacks .
*
* Called after closing the device , but before snd_card_saa7134_capture_close
2005-11-13 16:08:10 -08:00
* It stops the DMA audio and releases the buffers .
2005-11-08 21:37:14 -08:00
*
*/
2005-11-08 21:37:11 -08:00
static int snd_card_saa7134_hw_free ( snd_pcm_substream_t * substream )
2005-11-08 21:37:04 -08:00
{
2005-11-13 16:08:10 -08:00
snd_card_saa7134_t * saa7134 = snd_pcm_substream_chip ( substream ) ;
struct saa7134_dev * dev ;
2005-11-08 21:37:04 -08:00
2005-11-13 16:08:10 -08:00
dev = saa7134 - > dev ;
2005-11-08 21:37:04 -08:00
2005-11-13 16:08:10 -08:00
if ( substream - > runtime - > dma_area ) {
saa7134_pgtable_free ( dev - > pci , & dev - > dmasound . pt ) ;
videobuf_dma_pci_unmap ( dev - > pci , & dev - > dmasound . dma ) ;
dsp_buffer_free ( dev ) ;
substream - > runtime - > dma_area = NULL ;
}
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:43 -08:00
return 0 ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:14 -08:00
/*
* ALSA capture finish
*
* - One of the ALSA capture callbacks .
*
2005-11-13 16:08:10 -08:00
* Called after closing the device .
2005-11-08 21:37:14 -08:00
*
*/
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:14 -08:00
static int snd_card_saa7134_capture_close ( snd_pcm_substream_t * substream )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:43 -08:00
return 0 ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:14 -08:00
/*
* ALSA capture start
*
* - One of the ALSA capture callbacks .
*
* Called when opening the device . It creates and populates the PCM
* structure
*
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
static int snd_card_saa7134_capture_open ( snd_pcm_substream_t * substream )
{
snd_pcm_runtime_t * runtime = substream - > runtime ;
2005-11-13 16:08:00 -08:00
snd_card_saa7134_pcm_t * pcm ;
2005-11-08 21:37:43 -08:00
snd_card_saa7134_t * saa7134 = snd_pcm_substream_chip ( substream ) ;
2005-11-13 16:08:00 -08:00
struct saa7134_dev * dev = saa7134 - > dev ;
2005-11-08 21:37:14 -08:00
int err ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
down ( & dev - > dmasound . lock ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:54 -08:00
dev - > dmasound . read_count = 0 ;
dev - > dmasound . read_offset = 0 ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:38:54 -08:00
up ( & dev - > dmasound . lock ) ;
2005-11-08 21:37:04 -08:00
2005-11-13 16:08:00 -08:00
pcm = kzalloc ( sizeof ( * pcm ) , GFP_KERNEL ) ;
if ( pcm = = NULL )
2005-11-08 21:37:11 -08:00
return - ENOMEM ;
2005-11-13 16:08:00 -08:00
pcm - > dev = saa7134 - > dev ;
spin_lock_init ( & pcm - > lock ) ;
2005-11-08 21:37:11 -08:00
2005-11-13 16:08:00 -08:00
pcm - > substream = substream ;
runtime - > private_data = pcm ;
2005-11-08 21:37:11 -08:00
runtime - > private_free = snd_card_saa7134_runtime_free ;
runtime - > hw = snd_card_saa7134_capture ;
2005-11-08 21:37:43 -08:00
if ( ( err = snd_pcm_hw_constraint_integer ( runtime , SNDRV_PCM_HW_PARAM_PERIODS ) ) < 0 )
return err ;
2005-11-08 21:37:04 -08:00
return 0 ;
}
2005-11-08 21:37:14 -08:00
/*
* ALSA capture callbacks definition
*/
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
. open = snd_card_saa7134_capture_open ,
. close = snd_card_saa7134_capture_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_card_saa7134_hw_params ,
. hw_free = snd_card_saa7134_hw_free ,
. prepare = snd_card_saa7134_capture_prepare ,
. trigger = snd_card_saa7134_capture_trigger ,
. pointer = snd_card_saa7134_capture_pointer ,
2005-11-08 21:37:04 -08:00
} ;
2005-11-08 21:37:14 -08:00
/*
* ALSA PCM setup
*
* Called when initializing the board . Sets up the name and hooks up
* the callbacks
*
*/
static int snd_card_saa7134_pcm ( snd_card_saa7134_t * saa7134 , int device )
2005-11-08 21:37:11 -08:00
{
snd_pcm_t * pcm ;
int err ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
if ( ( err = snd_pcm_new ( saa7134 - > card , " SAA7134 PCM " , device , 0 , 1 , & pcm ) ) < 0 )
return err ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE , & snd_card_saa7134_capture_ops ) ;
pcm - > private_data = saa7134 ;
pcm - > info_flags = 0 ;
strcpy ( pcm - > name , " SAA7134 PCM " ) ;
return 0 ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
# define SAA713x_VOLUME(xname, xindex, addr) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = xindex , \
. info = snd_saa7134_volume_info , \
. get = snd_saa7134_volume_get , . put = snd_saa7134_volume_put , \
. private_value = addr }
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_saa7134_volume_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 = 20 ;
return 0 ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_saa7134_volume_get ( snd_kcontrol_t * kcontrol , snd_ctl_elem_value_t * ucontrol )
{
snd_card_saa7134_t * chip = snd_kcontrol_chip ( kcontrol ) ;
int addr = kcontrol - > private_value ;
ucontrol - > value . integer . value [ 0 ] = chip - > mixer_volume [ addr ] [ 0 ] ;
ucontrol - > value . integer . value [ 1 ] = chip - > mixer_volume [ addr ] [ 1 ] ;
return 0 ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_saa7134_volume_put ( snd_kcontrol_t * kcontrol , snd_ctl_elem_value_t * ucontrol )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:11 -08:00
snd_card_saa7134_t * chip = snd_kcontrol_chip ( kcontrol ) ;
int change , addr = kcontrol - > private_value ;
int left , right ;
left = ucontrol - > value . integer . value [ 0 ] ;
if ( left < 0 )
left = 0 ;
if ( left > 20 )
left = 20 ;
right = ucontrol - > value . integer . value [ 1 ] ;
if ( right < 0 )
right = 0 ;
if ( right > 20 )
right = 20 ;
2005-11-13 16:08:10 -08:00
spin_lock_irq ( & chip - > mixer_lock ) ;
2005-11-08 21:37:11 -08:00
change = chip - > mixer_volume [ addr ] [ 0 ] ! = left | |
2005-11-08 21:37:43 -08:00
chip - > mixer_volume [ addr ] [ 1 ] ! = right ;
2005-11-08 21:37:11 -08:00
chip - > mixer_volume [ addr ] [ 0 ] = left ;
chip - > mixer_volume [ addr ] [ 1 ] = right ;
2005-11-13 16:08:10 -08:00
spin_unlock_irq ( & chip - > mixer_lock ) ;
2005-11-08 21:37:11 -08:00
return change ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
# define SAA713x_CAPSRC(xname, xindex, addr) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = xindex , \
. info = snd_saa7134_capsrc_info , \
. get = snd_saa7134_capsrc_get , . put = snd_saa7134_capsrc_put , \
. private_value = addr }
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_saa7134_capsrc_info ( snd_kcontrol_t * kcontrol , snd_ctl_elem_info_t * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
2005-11-08 21:37:14 -08:00
uinfo - > count = 2 ;
2005-11-08 21:37:11 -08:00
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
static int snd_saa7134_capsrc_get ( snd_kcontrol_t * kcontrol , snd_ctl_elem_value_t * ucontrol )
{
snd_card_saa7134_t * chip = snd_kcontrol_chip ( kcontrol ) ;
int addr = kcontrol - > private_value ;
2005-11-13 16:08:10 -08:00
spin_lock_irq ( & chip - > mixer_lock ) ;
2005-11-08 21:37:11 -08:00
ucontrol - > value . integer . value [ 0 ] = chip - > capture_source [ addr ] [ 0 ] ;
ucontrol - > value . integer . value [ 1 ] = chip - > capture_source [ addr ] [ 1 ] ;
2005-11-13 16:08:10 -08:00
spin_unlock_irq ( & chip - > mixer_lock ) ;
2005-11-13 16:08:00 -08:00
2005-11-08 21:37:04 -08:00
return 0 ;
}
2005-11-08 21:37:11 -08:00
static int snd_saa7134_capsrc_put ( snd_kcontrol_t * kcontrol , snd_ctl_elem_value_t * ucontrol )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:11 -08:00
snd_card_saa7134_t * chip = snd_kcontrol_chip ( kcontrol ) ;
int change , addr = kcontrol - > private_value ;
int left , right ;
2005-11-08 21:37:43 -08:00
u32 anabar , xbarin ;
2005-11-08 21:37:11 -08:00
int analog_io , rate ;
struct saa7134_dev * dev ;
2005-11-13 16:08:00 -08:00
dev = chip - > dev ;
2005-11-08 21:37:11 -08:00
left = ucontrol - > value . integer . value [ 0 ] & 1 ;
right = ucontrol - > value . integer . value [ 1 ] & 1 ;
2005-11-13 16:07:47 -08:00
spin_lock_irq ( & chip - > mixer_lock ) ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:14 -08:00
change = chip - > capture_source [ addr ] [ 0 ] ! = left | |
2005-11-08 21:37:43 -08:00
chip - > capture_source [ addr ] [ 1 ] ! = right ;
2005-11-08 21:37:11 -08:00
chip - > capture_source [ addr ] [ 0 ] = left ;
chip - > capture_source [ addr ] [ 1 ] = right ;
2005-11-08 21:38:54 -08:00
dev - > dmasound . input = addr ;
2005-11-13 16:07:47 -08:00
spin_unlock_irq ( & chip - > mixer_lock ) ;
2005-11-08 21:37:11 -08:00
2005-11-08 21:37:14 -08:00
if ( change ) {
2005-11-08 21:37:43 -08:00
switch ( dev - > pci - > device ) {
2005-11-08 21:37:11 -08:00
case PCI_DEVICE_ID_PHILIPS_SAA7134 :
2005-11-08 21:37:43 -08:00
switch ( addr ) {
case MIXER_ADDR_TVTUNER :
saa_andorb ( SAA7134_AUDIO_FORMAT_CTRL , 0xc0 , 0xc0 ) ;
saa_andorb ( SAA7134_SIF_SAMPLE_FREQ , 0x03 , 0x00 ) ;
break ;
case MIXER_ADDR_LINE1 :
case MIXER_ADDR_LINE2 :
analog_io = ( MIXER_ADDR_LINE1 = = addr ) ? 0x00 : 0x08 ;
2005-11-08 21:38:54 -08:00
rate = ( 32000 = = dev - > dmasound . rate ) ? 0x01 : 0x03 ;
2005-11-08 21:37:43 -08:00
saa_andorb ( SAA7134_ANALOG_IO_SELECT , 0x08 , analog_io ) ;
saa_andorb ( SAA7134_AUDIO_FORMAT_CTRL , 0xc0 , 0x80 ) ;
saa_andorb ( SAA7134_SIF_SAMPLE_FREQ , 0x03 , rate ) ;
break ;
}
break ;
2005-11-08 21:37:11 -08:00
case PCI_DEVICE_ID_PHILIPS_SAA7133 :
case PCI_DEVICE_ID_PHILIPS_SAA7135 :
2005-11-08 21:37:43 -08:00
xbarin = 0x03 ; // adc
2005-11-08 21:37:11 -08:00
anabar = 0 ;
2005-11-08 21:37:43 -08:00
switch ( addr ) {
case MIXER_ADDR_TVTUNER :
xbarin = 0 ; // Demodulator
anabar = 2 ; // DACs
break ;
case MIXER_ADDR_LINE1 :
anabar = 0 ; // aux1, aux1
break ;
case MIXER_ADDR_LINE2 :
anabar = 9 ; // aux2, aux2
break ;
}
2005-11-08 21:37:11 -08:00
/* output xbar always main channel */
2005-11-08 21:37:43 -08:00
saa_dsp_writel ( dev , SAA7133_DIGITAL_OUTPUT_SEL1 , 0xbbbb10 ) ;
2005-11-08 21:37:11 -08:00
if ( left | | right ) { // We've got data, turn the input on
2005-11-08 21:37:43 -08:00
saa_dsp_writel ( dev , SAA7133_DIGITAL_INPUT_XBAR1 , xbarin ) ;
saa_writel ( SAA7133_ANALOG_IO_SELECT , anabar ) ;
2005-11-08 21:37:11 -08:00
} else {
2005-11-08 21:37:43 -08:00
saa_dsp_writel ( dev , SAA7133_DIGITAL_INPUT_XBAR1 , 0 ) ;
saa_writel ( SAA7133_ANALOG_IO_SELECT , 0 ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:14 -08:00
break ;
2005-11-08 21:37:14 -08:00
}
2005-11-08 21:37:43 -08:00
}
2005-11-08 21:37:11 -08:00
return change ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:37:11 -08:00
static snd_kcontrol_new_t snd_saa7134_controls [ ] = {
SAA713x_VOLUME ( " Video Volume " , 0 , MIXER_ADDR_TVTUNER ) ,
SAA713x_CAPSRC ( " Video Capture Switch " , 0 , MIXER_ADDR_TVTUNER ) ,
SAA713x_VOLUME ( " Line Volume " , 1 , MIXER_ADDR_LINE1 ) ,
SAA713x_CAPSRC ( " Line Capture Switch " , 1 , MIXER_ADDR_LINE1 ) ,
SAA713x_VOLUME ( " Line Volume " , 2 , MIXER_ADDR_LINE2 ) ,
SAA713x_CAPSRC ( " Line Capture Switch " , 2 , MIXER_ADDR_LINE2 ) ,
} ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* ALSA mixer setup
*
* Called when initializing the board . Sets up the name and hooks up
* the callbacks
*
*/
static int snd_card_saa7134_new_mixer ( snd_card_saa7134_t * chip )
2005-11-08 21:37:11 -08:00
{
snd_card_t * card = chip - > card ;
unsigned int idx ;
int err ;
snd_assert ( chip ! = NULL , return - EINVAL ) ;
strcpy ( card - > mixername , " SAA7134 Mixer " ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
for ( idx = 0 ; idx < ARRAY_SIZE ( snd_saa7134_controls ) ; idx + + ) {
if ( ( err = snd_ctl_add ( card , snd_ctl_new1 ( & snd_saa7134_controls [ idx ] , chip ) ) ) < 0 )
return err ;
}
return 0 ;
}
2005-11-13 16:07:47 -08:00
static void snd_saa7134_free ( snd_card_t * card )
2005-11-08 21:37:04 -08:00
{
2005-11-13 16:08:10 -08:00
snd_card_saa7134_t * chip = card - > private_data ;
2005-11-13 16:07:47 -08:00
2005-11-13 16:08:00 -08:00
if ( chip - > dev - > dmasound . priv_data = = NULL )
2005-11-13 16:08:10 -08:00
return ;
2005-11-13 16:08:00 -08:00
2005-11-13 16:07:47 -08:00
if ( chip - > irq > = 0 ) {
synchronize_irq ( chip - > irq ) ;
2005-11-13 16:08:00 -08:00
free_irq ( chip - > irq , & chip - > dev - > dmasound ) ;
2005-11-13 16:07:47 -08:00
}
2005-11-13 16:08:00 -08:00
chip - > dev - > dmasound . priv_data = NULL ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:14 -08:00
/*
* ALSA initialization
*
2005-11-13 16:07:47 -08:00
* Called by the init routine , once for each saa7134 device present ,
* it creates the basic structures and registers the ALSA devices
2005-11-08 21:37:14 -08:00
*
*/
2005-12-01 00:51:35 -08:00
static int alsa_card_saa7134_create ( struct saa7134_dev * dev , int devnum )
2005-11-08 21:37:11 -08:00
{
2005-11-08 21:38:53 -08:00
2005-11-08 21:37:11 -08:00
snd_card_t * card ;
2005-11-08 21:37:14 -08:00
snd_card_saa7134_t * chip ;
2005-11-08 21:37:11 -08:00
int err ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:38:53 -08:00
2005-11-13 16:08:00 -08:00
if ( devnum > = SNDRV_CARDS )
2005-11-08 21:37:43 -08:00
return - ENODEV ;
2005-11-13 16:08:00 -08:00
if ( ! enable [ devnum ] )
2005-11-08 21:37:11 -08:00
return - ENODEV ;
2005-11-08 21:37:14 -08:00
2005-11-13 16:08:00 -08:00
card = snd_card_new ( index [ devnum ] , id [ devnum ] , THIS_MODULE , sizeof ( snd_card_saa7134_t ) ) ;
2005-11-08 21:38:54 -08:00
2005-11-08 21:37:11 -08:00
if ( card = = NULL )
return - ENOMEM ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
strcpy ( card - > driver , " SAA7134 " ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
/* Card "creation" */
2005-11-08 21:37:14 -08:00
2005-11-13 16:07:47 -08:00
card - > private_free = snd_saa7134_free ;
chip = ( snd_card_saa7134_t * ) card - > private_data ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:43 -08:00
spin_lock_init ( & chip - > lock ) ;
2005-11-08 21:38:54 -08:00
spin_lock_init ( & chip - > mixer_lock ) ;
2005-11-08 21:37:04 -08:00
2005-11-13 16:08:00 -08:00
chip - > dev = dev ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:43 -08:00
chip - > card = card ;
2005-11-08 21:37:14 -08:00
2005-11-13 16:08:00 -08:00
chip - > pci = dev - > pci ;
chip - > iobase = pci_resource_start ( dev - > pci , 0 ) ;
2005-11-08 21:37:04 -08:00
2005-11-13 16:08:00 -08:00
err = request_irq ( dev - > pci - > irq , saa7134_alsa_irq ,
SA_SHIRQ | SA_INTERRUPT , dev - > name ,
( void * ) & dev - > dmasound ) ;
2005-11-08 21:38:53 -08:00
if ( err < 0 ) {
printk ( KERN_ERR " %s: can't get IRQ %d for ALSA \n " ,
2005-11-13 16:08:00 -08:00
dev - > name , dev - > pci - > irq ) ;
2005-11-08 21:38:54 -08:00
goto __nodev ;
2005-11-08 21:38:53 -08:00
}
2005-11-13 16:08:10 -08:00
chip - > irq = dev - > pci - > irq ;
2005-11-13 16:08:00 -08:00
2005-11-13 16:08:10 -08:00
init_MUTEX ( & dev - > dmasound . lock ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
if ( ( err = snd_card_saa7134_new_mixer ( chip ) ) < 0 )
goto __nodev ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
if ( ( err = snd_card_saa7134_pcm ( chip , 0 ) ) < 0 )
goto __nodev ;
2005-11-08 21:37:14 -08:00
2005-11-08 21:37:11 -08:00
snd_card_set_dev ( card , & chip - > pci - > dev ) ;
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
/* End of "creation" */
2005-11-08 21:37:04 -08:00
2005-11-08 21:37:11 -08:00
strcpy ( card - > shortname , " SAA7134 " ) ;
2005-11-08 21:37:43 -08:00
sprintf ( card - > longname , " %s at 0x%lx irq %d " ,
2005-11-13 16:08:00 -08:00
chip - > dev - > name , chip - > iobase , chip - > irq ) ;
2005-11-08 21:37:04 -08:00
2005-12-01 00:51:20 -08:00
printk ( KERN_INFO " %s/alsa: %s registered as card %d \n " , dev - > name , card - > longname , index [ devnum ] ) ;
2005-11-08 21:37:11 -08:00
if ( ( err = snd_card_register ( card ) ) = = 0 ) {
2005-11-13 16:08:00 -08:00
snd_saa7134_cards [ devnum ] = card ;
2005-11-08 21:37:11 -08:00
return 0 ;
}
__nodev :
snd_card_free ( card ) ;
return err ;
2005-11-08 21:37:04 -08:00
}
2005-12-01 00:51:20 -08:00
static int alsa_device_init ( struct saa7134_dev * dev )
{
dev - > dmasound . priv_data = dev ;
alsa_card_saa7134_create ( dev , dev - > nr ) ;
return 1 ;
}
static int alsa_device_exit ( struct saa7134_dev * dev )
{
snd_card_free ( snd_saa7134_cards [ dev - > nr ] ) ;
snd_saa7134_cards [ dev - > nr ] = NULL ;
return 1 ;
}
2005-11-08 21:38:53 -08:00
/*
* Module initializer
*
* Loops through present saa7134 cards , and assigns an ALSA device
* to each one
*
*/
static int saa7134_alsa_init ( void )
{
2005-11-13 16:08:00 -08:00
struct saa7134_dev * dev = NULL ;
2005-11-13 16:07:47 -08:00
struct list_head * list ;
2005-11-08 21:38:53 -08:00
2005-12-20 18:26:26 -02:00
if ( ! dmasound_init & & ! dmasound_exit ) {
dmasound_init = alsa_device_init ;
dmasound_exit = alsa_device_exit ;
} else {
printk ( KERN_WARNING " saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS) \n " ) ;
return - EBUSY ;
}
2005-12-12 00:37:27 -08:00
printk ( KERN_INFO " saa7134 ALSA driver for DMA sound loaded \n " ) ;
2005-11-13 16:07:47 -08:00
list_for_each ( list , & saa7134_devlist ) {
2005-11-13 16:08:00 -08:00
dev = list_entry ( list , struct saa7134_dev , devlist ) ;
if ( dev - > dmasound . priv_data = = NULL ) {
2005-12-01 00:51:20 -08:00
alsa_device_init ( dev ) ;
2005-11-13 16:08:00 -08:00
} else {
printk ( KERN_ERR " saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s \n " , dev - > name ) ;
return - EBUSY ;
}
2005-11-13 16:07:47 -08:00
}
2005-11-08 21:38:53 -08:00
2005-11-13 16:08:00 -08:00
if ( dev = = NULL )
2005-11-08 21:38:53 -08:00
printk ( KERN_INFO " saa7134 ALSA: no saa7134 cards found \n " ) ;
return 0 ;
2005-12-12 00:37:28 -08:00
2005-11-08 21:38:53 -08:00
}
/*
* Module destructor
*/
2005-12-01 00:51:35 -08:00
static void saa7134_alsa_exit ( void )
2005-11-08 21:37:04 -08:00
{
2005-11-08 21:37:43 -08:00
int idx ;
2005-11-08 21:38:54 -08:00
2005-11-08 21:38:53 -08:00
for ( idx = 0 ; idx < SNDRV_CARDS ; idx + + ) {
2005-11-08 21:37:43 -08:00
snd_card_free ( snd_saa7134_cards [ idx ] ) ;
2005-11-08 21:37:11 -08:00
}
2005-11-08 21:38:54 -08:00
2005-12-20 18:26:26 -02:00
dmasound_init = NULL ;
dmasound_exit = NULL ;
2005-11-08 21:38:53 -08:00
printk ( KERN_INFO " saa7134 ALSA driver for DMA sound unloaded \n " ) ;
2005-11-08 21:38:54 -08:00
2005-11-08 21:38:53 -08:00
return ;
2005-11-08 21:37:04 -08:00
}
2005-11-08 21:38:53 -08:00
2005-12-21 14:52:32 -08:00
/* We initialize this late, to make sure the sound system is up and running */
late_initcall ( saa7134_alsa_init ) ;
2005-11-08 21:38:53 -08:00
module_exit ( saa7134_alsa_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Ricardo Cerqueira " ) ;
2005-12-12 00:37:28 -08:00