2005-04-16 15:20:36 -07:00
/*
2007-10-15 09:50:19 +02:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-16 15:20:36 -07:00
* Creative Labs , Inc .
* Routines for control of EMU10K1 chips / PCM routines
* Multichannel PCM support Copyright ( c ) Lee Revell < rlrevell @ joe - job . com >
*
* BUGS :
* - -
*
* TODO :
* - -
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/time.h>
# include <linux/init.h>
# include <sound/core.h>
# include <sound/emu10k1.h>
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_interrupt ( struct snd_emu10k1 * emu ,
struct snd_emu10k1_voice * voice )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1_pcm * epcm ;
2005-04-16 15:20:36 -07:00
if ( ( epcm = voice - > epcm ) = = NULL )
return ;
if ( epcm - > substream = = NULL )
return ;
#if 0
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev ,
" IRQ: position = 0x%x, period = 0x%x, size = 0x%x \n " ,
2005-04-16 15:20:36 -07:00
epcm - > substream - > runtime - > hw - > pointer ( emu , epcm - > substream ) ,
snd_pcm_lib_period_bytes ( epcm - > substream ) ,
snd_pcm_lib_buffer_bytes ( epcm - > substream ) ) ;
# endif
snd_pcm_period_elapsed ( epcm - > substream ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_ac97adc_interrupt ( struct snd_emu10k1 * emu ,
unsigned int status )
2005-04-16 15:20:36 -07:00
{
#if 0
if ( status & IPR_ADCBUFHALFFULL ) {
if ( emu - > pcm_capture_substream - > runtime - > mode = = SNDRV_PCM_MODE_FRAME )
return ;
}
# endif
snd_pcm_period_elapsed ( emu - > pcm_capture_substream ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_ac97mic_interrupt ( struct snd_emu10k1 * emu ,
unsigned int status )
2005-04-16 15:20:36 -07:00
{
#if 0
if ( status & IPR_MICBUFHALFFULL ) {
if ( emu - > pcm_capture_mic_substream - > runtime - > mode = = SNDRV_PCM_MODE_FRAME )
return ;
}
# endif
snd_pcm_period_elapsed ( emu - > pcm_capture_mic_substream ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_efx_interrupt ( struct snd_emu10k1 * emu ,
unsigned int status )
2005-04-16 15:20:36 -07:00
{
#if 0
if ( status & IPR_EFXBUFHALFFULL ) {
if ( emu - > pcm_capture_efx_substream - > runtime - > mode = = SNDRV_PCM_MODE_FRAME )
return ;
}
# endif
snd_pcm_period_elapsed ( emu - > pcm_capture_efx_substream ) ;
}
2005-11-17 14:50:13 +01:00
static snd_pcm_uframes_t snd_emu10k1_efx_playback_pointer ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
unsigned int ptr ;
if ( ! epcm - > running )
return 0 ;
ptr = snd_emu10k1_ptr_read ( emu , CCCA , epcm - > voices [ 0 ] - > number ) & 0x00ffffff ;
ptr + = runtime - > buffer_size ;
ptr - = epcm - > ccca_start_addr ;
ptr % = runtime - > buffer_size ;
return ptr ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_pcm_channel_alloc ( struct snd_emu10k1_pcm * epcm , int voices )
2005-04-16 15:20:36 -07:00
{
int err , i ;
if ( epcm - > voices [ 1 ] ! = NULL & & voices < 2 ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ 1 ] ) ;
epcm - > voices [ 1 ] = NULL ;
}
for ( i = 0 ; i < voices ; i + + ) {
if ( epcm - > voices [ i ] = = NULL )
break ;
}
if ( i = = voices )
return 0 ; /* already allocated */
for ( i = 0 ; i < ARRAY_SIZE ( epcm - > voices ) ; i + + ) {
if ( epcm - > voices [ i ] ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ i ] ) ;
epcm - > voices [ i ] = NULL ;
}
}
err = snd_emu10k1_voice_alloc ( epcm - > emu ,
epcm - > type = = PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX ,
voices ,
& epcm - > voices [ 0 ] ) ;
if ( err < 0 )
return err ;
epcm - > voices [ 0 ] - > epcm = epcm ;
if ( voices > 1 ) {
for ( i = 1 ; i < voices ; i + + ) {
epcm - > voices [ i ] = & epcm - > emu - > voices [ epcm - > voices [ 0 ] - > number + i ] ;
epcm - > voices [ i ] - > epcm = epcm ;
}
}
if ( epcm - > extra = = NULL ) {
err = snd_emu10k1_voice_alloc ( epcm - > emu ,
epcm - > type = = PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX ,
1 ,
& epcm - > extra ) ;
if ( err < 0 ) {
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev , " pcm_channel_alloc: "
2009-02-05 16:08:14 +01:00
" failed extra: voices=%d, frame=%d \n " ,
voices , frame ) ;
*/
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < voices ; i + + ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ i ] ) ;
epcm - > voices [ i ] = NULL ;
}
return err ;
}
epcm - > extra - > epcm = epcm ;
epcm - > extra - > interrupt = snd_emu10k1_pcm_interrupt ;
}
return 0 ;
}
static unsigned int capture_period_sizes [ 31 ] = {
384 , 448 , 512 , 640 ,
384 * 2 , 448 * 2 , 512 * 2 , 640 * 2 ,
384 * 4 , 448 * 4 , 512 * 4 , 640 * 4 ,
384 * 8 , 448 * 8 , 512 * 8 , 640 * 8 ,
384 * 16 , 448 * 16 , 512 * 16 , 640 * 16 ,
384 * 32 , 448 * 32 , 512 * 32 , 640 * 32 ,
384 * 64 , 448 * 64 , 512 * 64 , 640 * 64 ,
384 * 128 , 448 * 128 , 512 * 128
} ;
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = {
2005-04-16 15:20:36 -07:00
. count = 31 ,
. list = capture_period_sizes ,
. mask = 0
} ;
static unsigned int capture_rates [ 8 ] = {
8000 , 11025 , 16000 , 22050 , 24000 , 32000 , 44100 , 48000
} ;
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hw_constraint_list hw_constraints_capture_rates = {
2005-04-16 15:20:36 -07:00
. count = 8 ,
. list = capture_rates ,
. mask = 0
} ;
static unsigned int snd_emu10k1_capture_rate_reg ( unsigned int rate )
{
switch ( rate ) {
case 8000 : return ADCCR_SAMPLERATE_8 ;
case 11025 : return ADCCR_SAMPLERATE_11 ;
case 16000 : return ADCCR_SAMPLERATE_16 ;
case 22050 : return ADCCR_SAMPLERATE_22 ;
case 24000 : return ADCCR_SAMPLERATE_24 ;
case 32000 : return ADCCR_SAMPLERATE_32 ;
case 44100 : return ADCCR_SAMPLERATE_44 ;
case 48000 : return ADCCR_SAMPLERATE_48 ;
default :
snd_BUG ( ) ;
return ADCCR_SAMPLERATE_8 ;
}
}
static unsigned int snd_emu10k1_audigy_capture_rate_reg ( unsigned int rate )
{
switch ( rate ) {
case 8000 : return A_ADCCR_SAMPLERATE_8 ;
case 11025 : return A_ADCCR_SAMPLERATE_11 ;
case 12000 : return A_ADCCR_SAMPLERATE_12 ; /* really supported? */
case 16000 : return ADCCR_SAMPLERATE_16 ;
case 22050 : return ADCCR_SAMPLERATE_22 ;
case 24000 : return ADCCR_SAMPLERATE_24 ;
case 32000 : return ADCCR_SAMPLERATE_32 ;
case 44100 : return ADCCR_SAMPLERATE_44 ;
case 48000 : return ADCCR_SAMPLERATE_48 ;
default :
snd_BUG ( ) ;
return A_ADCCR_SAMPLERATE_8 ;
}
}
static unsigned int emu10k1_calc_pitch_target ( unsigned int rate )
{
unsigned int pitch_target ;
pitch_target = ( rate < < 8 ) / 375 ;
pitch_target = ( pitch_target > > 1 ) + ( pitch_target & 1 ) ;
return pitch_target ;
}
# define PITCH_48000 0x00004000
# define PITCH_96000 0x00008000
# define PITCH_85000 0x00007155
# define PITCH_80726 0x00006ba2
# define PITCH_67882 0x00005a82
# define PITCH_57081 0x00004c1c
static unsigned int emu10k1_select_interprom ( unsigned int pitch_target )
{
if ( pitch_target = = PITCH_48000 )
return CCCA_INTERPROM_0 ;
else if ( pitch_target < PITCH_48000 )
return CCCA_INTERPROM_1 ;
else if ( pitch_target > = PITCH_96000 )
return CCCA_INTERPROM_0 ;
else if ( pitch_target > = PITCH_85000 )
return CCCA_INTERPROM_6 ;
else if ( pitch_target > = PITCH_80726 )
return CCCA_INTERPROM_5 ;
else if ( pitch_target > = PITCH_67882 )
return CCCA_INTERPROM_4 ;
else if ( pitch_target > = PITCH_57081 )
return CCCA_INTERPROM_3 ;
else
return CCCA_INTERPROM_2 ;
}
/*
* calculate cache invalidate size
*
* stereo : channel is stereo
* w_16 : using 16 bit samples
*
* returns : cache invalidate size in samples
*/
2005-04-20 10:03:31 +02:00
static inline int emu10k1_ccis ( int stereo , int w_16 )
2005-04-16 15:20:36 -07:00
{
if ( w_16 ) {
return stereo ? 24 : 26 ;
} else {
return stereo ? 24 * 2 : 26 * 2 ;
}
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_init_voice ( struct snd_emu10k1 * emu ,
2005-04-16 15:20:36 -07:00
int master , int extra ,
2005-11-17 14:50:13 +01:00
struct snd_emu10k1_voice * evoice ,
2005-04-16 15:20:36 -07:00
unsigned int start_addr ,
unsigned int end_addr ,
2005-11-17 14:50:13 +01:00
struct snd_emu10k1_pcm_mixer * mix )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm_substream * substream = evoice - > epcm - > substream ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
2005-04-16 15:20:36 -07:00
unsigned int silent_page , tmp ;
int voice , stereo , w_16 ;
unsigned char attn , send_amount [ 8 ] ;
unsigned char send_routing [ 8 ] ;
unsigned long flags ;
unsigned int pitch_target ;
unsigned int ccis ;
voice = evoice - > number ;
stereo = runtime - > channels = = 2 ;
w_16 = snd_pcm_format_width ( runtime - > format ) = = 16 ;
if ( ! extra & & stereo ) {
start_addr > > = 1 ;
end_addr > > = 1 ;
}
if ( w_16 ) {
start_addr > > = 1 ;
end_addr > > = 1 ;
}
spin_lock_irqsave ( & emu - > reg_lock , flags ) ;
/* volume parameters */
if ( extra ) {
attn = 0 ;
memset ( send_routing , 0 , sizeof ( send_routing ) ) ;
send_routing [ 0 ] = 0 ;
send_routing [ 1 ] = 1 ;
send_routing [ 2 ] = 2 ;
send_routing [ 3 ] = 3 ;
memset ( send_amount , 0 , sizeof ( send_amount ) ) ;
} else {
/* mono, left, right (master voice = left) */
tmp = stereo ? ( master ? 1 : 2 ) : 0 ;
memcpy ( send_routing , & mix - > send_routing [ tmp ] [ 0 ] , 8 ) ;
memcpy ( send_amount , & mix - > send_volume [ tmp ] [ 0 ] , 8 ) ;
}
ccis = emu10k1_ccis ( stereo , w_16 ) ;
if ( master ) {
evoice - > epcm - > ccca_start_addr = start_addr + ccis ;
if ( extra ) {
start_addr + = ccis ;
2010-08-18 14:08:17 +02:00
end_addr + = ccis + emu - > delay_pcm_irq ;
2005-04-16 15:20:36 -07:00
}
if ( stereo & & ! extra ) {
snd_emu10k1_ptr_write ( emu , CPF , voice , CPF_STEREO_MASK ) ;
snd_emu10k1_ptr_write ( emu , CPF , ( voice + 1 ) , CPF_STEREO_MASK ) ;
} else {
snd_emu10k1_ptr_write ( emu , CPF , voice , 0 ) ;
}
}
2006-10-01 10:48:04 +01:00
/* setup routing */
2005-04-16 15:20:36 -07:00
if ( emu - > audigy ) {
snd_emu10k1_ptr_write ( emu , A_FXRT1 , voice ,
snd_emu10k1_compose_audigy_fxrt1 ( send_routing ) ) ;
snd_emu10k1_ptr_write ( emu , A_FXRT2 , voice ,
snd_emu10k1_compose_audigy_fxrt2 ( send_routing ) ) ;
snd_emu10k1_ptr_write ( emu , A_SENDAMOUNTS , voice ,
( ( unsigned int ) send_amount [ 4 ] < < 24 ) |
( ( unsigned int ) send_amount [ 5 ] < < 16 ) |
( ( unsigned int ) send_amount [ 6 ] < < 8 ) |
( unsigned int ) send_amount [ 7 ] ) ;
} else
snd_emu10k1_ptr_write ( emu , FXRT , voice ,
snd_emu10k1_compose_send_routing ( send_routing ) ) ;
2006-10-01 10:48:04 +01:00
/* Stop CA */
/* Assumption that PT is already 0 so no harm overwriting */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , PTRX , voice , ( send_amount [ 0 ] < < 8 ) | send_amount [ 1 ] ) ;
snd_emu10k1_ptr_write ( emu , DSL , voice , end_addr | ( send_amount [ 3 ] < < 24 ) ) ;
2010-08-18 14:08:17 +02:00
snd_emu10k1_ptr_write ( emu , PSST , voice ,
( start_addr + ( extra ? emu - > delay_pcm_irq : 0 ) ) |
( send_amount [ 2 ] < < 24 ) ) ;
2007-11-04 14:08:26 +00:00
if ( emu - > card_capabilities - > emu_model )
2006-10-10 18:08:45 +01:00
pitch_target = PITCH_48000 ; /* Disable interpolators on emu1010 card */
else
pitch_target = emu10k1_calc_pitch_target ( runtime - > rate ) ;
2005-04-16 15:20:36 -07:00
if ( extra )
snd_emu10k1_ptr_write ( emu , CCCA , voice , start_addr |
emu10k1_select_interprom ( pitch_target ) |
( w_16 ? 0 : CCCA_8BITSELECT ) ) ;
else
snd_emu10k1_ptr_write ( emu , CCCA , voice , ( start_addr + ccis ) |
emu10k1_select_interprom ( pitch_target ) |
( w_16 ? 0 : CCCA_8BITSELECT ) ) ;
2006-10-01 10:48:04 +01:00
/* Clear filter delay memory */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , Z1 , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , Z2 , voice , 0 ) ;
2006-10-01 10:48:04 +01:00
/* invalidate maps */
2015-04-28 21:57:29 +02:00
silent_page = ( ( unsigned int ) emu - > silent_page . addr < < emu - > address_mode ) | ( emu - > address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0 ) ;
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , MAPA , voice , silent_page ) ;
snd_emu10k1_ptr_write ( emu , MAPB , voice , silent_page ) ;
2006-10-01 10:48:04 +01:00
/* modulation envelope */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , CVCF , voice , 0xffff ) ;
snd_emu10k1_ptr_write ( emu , VTFT , voice , 0xffff ) ;
snd_emu10k1_ptr_write ( emu , ATKHLDM , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , DCYSUSM , voice , 0x007f ) ;
snd_emu10k1_ptr_write ( emu , LFOVAL1 , voice , 0x8000 ) ;
snd_emu10k1_ptr_write ( emu , LFOVAL2 , voice , 0x8000 ) ;
snd_emu10k1_ptr_write ( emu , FMMOD , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , TREMFRQ , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , FM2FRQ2 , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , ENVVAL , voice , 0x8000 ) ;
2006-10-01 10:48:04 +01:00
/* volume envelope */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , ATKHLDV , voice , 0x7f7f ) ;
snd_emu10k1_ptr_write ( emu , ENVVOL , voice , 0x0000 ) ;
2006-10-01 10:48:04 +01:00
/* filter envelope */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , PEFE_FILTERAMOUNT , voice , 0x7f ) ;
2006-10-01 10:48:04 +01:00
/* pitch envelope */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , PEFE_PITCHAMOUNT , voice , 0 ) ;
spin_unlock_irqrestore ( & emu - > reg_lock , flags ) ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * hw_params )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
int err ;
if ( ( err = snd_emu10k1_pcm_channel_alloc ( epcm , params_channels ( hw_params ) ) ) < 0 )
return err ;
if ( ( err = snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( hw_params ) ) ) < 0 )
return err ;
if ( err > 0 ) { /* change */
2005-11-17 10:44:51 +01:00
int mapped ;
2005-04-16 15:20:36 -07:00
if ( epcm - > memblk ! = NULL )
snd_emu10k1_free_pages ( emu , epcm - > memblk ) ;
2005-11-17 10:44:51 +01:00
epcm - > memblk = snd_emu10k1_alloc_pages ( emu , substream ) ;
epcm - > start_addr = 0 ;
if ( ! epcm - > memblk )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2005-11-17 14:50:13 +01:00
mapped = ( ( struct snd_emu10k1_memblk * ) epcm - > memblk ) - > mapped_page ;
2005-11-17 10:44:51 +01:00
if ( mapped < 0 )
return - ENOMEM ;
epcm - > start_addr = mapped < < PAGE_SHIFT ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_hw_free ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm ;
2005-04-16 15:20:36 -07:00
if ( runtime - > private_data = = NULL )
return 0 ;
epcm = runtime - > private_data ;
if ( epcm - > extra ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > extra ) ;
epcm - > extra = NULL ;
}
if ( epcm - > voices [ 1 ] ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ 1 ] ) ;
epcm - > voices [ 1 ] = NULL ;
}
if ( epcm - > voices [ 0 ] ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ 0 ] ) ;
epcm - > voices [ 0 ] = NULL ;
}
if ( epcm - > memblk ) {
snd_emu10k1_free_pages ( emu , epcm - > memblk ) ;
epcm - > memblk = NULL ;
epcm - > start_addr = 0 ;
}
snd_pcm_lib_free_pages ( substream ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_efx_playback_hw_free ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm ;
2005-04-16 15:20:36 -07:00
int i ;
if ( runtime - > private_data = = NULL )
return 0 ;
epcm = runtime - > private_data ;
if ( epcm - > extra ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > extra ) ;
epcm - > extra = NULL ;
}
2006-10-01 10:48:04 +01:00
for ( i = 0 ; i < NUM_EFX_PLAYBACK ; i + + ) {
2005-04-16 15:20:36 -07:00
if ( epcm - > voices [ i ] ) {
snd_emu10k1_voice_free ( epcm - > emu , epcm - > voices [ i ] ) ;
epcm - > voices [ i ] = NULL ;
}
}
if ( epcm - > memblk ) {
snd_emu10k1_free_pages ( emu , epcm - > memblk ) ;
epcm - > memblk = NULL ;
epcm - > start_addr = 0 ;
}
snd_pcm_lib_free_pages ( substream ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_prepare ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
unsigned int start_addr , end_addr ;
start_addr = epcm - > start_addr ;
end_addr = snd_pcm_lib_period_bytes ( substream ) ;
if ( runtime - > channels = = 2 ) {
start_addr > > = 1 ;
end_addr > > = 1 ;
}
end_addr + = start_addr ;
snd_emu10k1_pcm_init_voice ( emu , 1 , 1 , epcm - > extra ,
start_addr , end_addr , NULL ) ;
start_addr = epcm - > start_addr ;
end_addr = epcm - > start_addr + snd_pcm_lib_buffer_bytes ( substream ) ;
snd_emu10k1_pcm_init_voice ( emu , 1 , 0 , epcm - > voices [ 0 ] ,
start_addr , end_addr ,
& emu - > pcm_mixer [ substream - > number ] ) ;
if ( epcm - > voices [ 1 ] )
snd_emu10k1_pcm_init_voice ( emu , 0 , 0 , epcm - > voices [ 1 ] ,
start_addr , end_addr ,
& emu - > pcm_mixer [ substream - > number ] ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_efx_playback_prepare ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
unsigned int start_addr , end_addr ;
unsigned int channel_size ;
int i ;
start_addr = epcm - > start_addr ;
end_addr = epcm - > start_addr + snd_pcm_lib_buffer_bytes ( substream ) ;
/*
* the kX driver leaves some space between voices
*/
channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK ;
snd_emu10k1_pcm_init_voice ( emu , 1 , 1 , epcm - > extra ,
start_addr , start_addr + ( channel_size / 2 ) , NULL ) ;
/* only difference with the master voice is we use it for the pointer */
snd_emu10k1_pcm_init_voice ( emu , 1 , 0 , epcm - > voices [ 0 ] ,
start_addr , start_addr + channel_size ,
& emu - > efx_pcm_mixer [ 0 ] ) ;
start_addr + = channel_size ;
for ( i = 1 ; i < NUM_EFX_PLAYBACK ; i + + ) {
snd_emu10k1_pcm_init_voice ( emu , 0 , 0 , epcm - > voices [ i ] ,
start_addr , start_addr + channel_size ,
& emu - > efx_pcm_mixer [ i ] ) ;
start_addr + = channel_size ;
}
return 0 ;
}
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hardware snd_emu10k1_efx_playback =
2005-04-16 15:20:36 -07:00
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
2005-11-17 16:14:10 +01:00
SNDRV_PCM_INFO_RESUME |
2005-04-16 15:20:36 -07:00
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE ) ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_48000 ,
. rate_min = 48000 ,
. rate_max = 48000 ,
. channels_min = NUM_EFX_PLAYBACK ,
. channels_max = NUM_EFX_PLAYBACK ,
. buffer_bytes_max = ( 64 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 64 * 1024 ) ,
. periods_min = 2 ,
. periods_max = 2 ,
. fifo_size = 0 ,
} ;
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * hw_params )
2005-04-16 15:20:36 -07:00
{
return snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( hw_params ) ) ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_hw_free ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
return snd_pcm_lib_free_pages ( substream ) ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_prepare ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
int idx ;
/* zeroing the buffer size will stop capture */
snd_emu10k1_ptr_write ( emu , epcm - > capture_bs_reg , 0 , 0 ) ;
switch ( epcm - > type ) {
case CAPTURE_AC97ADC :
snd_emu10k1_ptr_write ( emu , ADCCR , 0 , 0 ) ;
break ;
case CAPTURE_EFX :
if ( emu - > audigy ) {
snd_emu10k1_ptr_write ( emu , A_FXWC1 , 0 , 0 ) ;
snd_emu10k1_ptr_write ( emu , A_FXWC2 , 0 , 0 ) ;
} else
snd_emu10k1_ptr_write ( emu , FXWC , 0 , 0 ) ;
break ;
default :
break ;
}
snd_emu10k1_ptr_write ( emu , epcm - > capture_ba_reg , 0 , runtime - > dma_addr ) ;
epcm - > capture_bufsize = snd_pcm_lib_buffer_bytes ( substream ) ;
epcm - > capture_bs_val = 0 ;
for ( idx = 0 ; idx < 31 ; idx + + ) {
if ( capture_period_sizes [ idx ] = = epcm - > capture_bufsize ) {
epcm - > capture_bs_val = idx + 1 ;
break ;
}
}
if ( epcm - > capture_bs_val = = 0 ) {
snd_BUG ( ) ;
epcm - > capture_bs_val + + ;
}
if ( epcm - > type = = CAPTURE_AC97ADC ) {
epcm - > capture_cr_val = emu - > audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE ;
if ( runtime - > channels > 1 )
epcm - > capture_cr_val | = emu - > audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE ;
epcm - > capture_cr_val | = emu - > audigy ?
snd_emu10k1_audigy_capture_rate_reg ( runtime - > rate ) :
snd_emu10k1_capture_rate_reg ( runtime - > rate ) ;
}
return 0 ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_playback_invalidate_cache ( struct snd_emu10k1 * emu , int extra , struct snd_emu10k1_voice * evoice )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm_runtime * runtime ;
2005-04-16 15:20:36 -07:00
unsigned int voice , stereo , i , ccis , cra = 64 , cs , sample ;
if ( evoice = = NULL )
return ;
runtime = evoice - > epcm - > substream - > runtime ;
voice = evoice - > number ;
stereo = ( ! extra & & runtime - > channels = = 2 ) ;
sample = snd_pcm_format_width ( runtime - > format ) = = 16 ? 0 : 0x80808080 ;
ccis = emu10k1_ccis ( stereo , sample = = 0 ) ;
2006-10-01 10:48:04 +01:00
/* set cs to 2 * number of cache registers beside the invalidated */
2005-04-16 15:20:36 -07:00
cs = ( sample = = 0 ) ? ( 32 - ccis ) : ( 64 - ccis + 1 ) > > 1 ;
if ( cs > 16 ) cs = 16 ;
for ( i = 0 ; i < cs ; i + + ) {
snd_emu10k1_ptr_write ( emu , CD0 + i , voice , sample ) ;
if ( stereo ) {
snd_emu10k1_ptr_write ( emu , CD0 + i , voice + 1 , sample ) ;
}
}
2006-10-01 10:48:04 +01:00
/* reset cache */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , CCR_CACHEINVALIDSIZE , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , CCR_READADDRESS , voice , cra ) ;
if ( stereo ) {
snd_emu10k1_ptr_write ( emu , CCR_CACHEINVALIDSIZE , voice + 1 , 0 ) ;
snd_emu10k1_ptr_write ( emu , CCR_READADDRESS , voice + 1 , cra ) ;
}
2006-10-01 10:48:04 +01:00
/* fill cache */
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , CCR_CACHEINVALIDSIZE , voice , ccis ) ;
if ( stereo ) {
snd_emu10k1_ptr_write ( emu , CCR_CACHEINVALIDSIZE , voice + 1 , ccis ) ;
}
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_playback_prepare_voice ( struct snd_emu10k1 * emu , struct snd_emu10k1_voice * evoice ,
2005-04-16 15:20:36 -07:00
int master , int extra ,
2005-11-17 14:50:13 +01:00
struct snd_emu10k1_pcm_mixer * mix )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm_substream * substream ;
struct snd_pcm_runtime * runtime ;
2005-04-16 15:20:36 -07:00
unsigned int attn , vattn ;
unsigned int voice , tmp ;
if ( evoice = = NULL ) /* skip second voice for mono */
return ;
substream = evoice - > epcm - > substream ;
runtime = substream - > runtime ;
voice = evoice - > number ;
attn = extra ? 0 : 0x00ff ;
tmp = runtime - > channels = = 2 ? ( master ? 1 : 2 ) : 0 ;
vattn = mix ! = NULL ? ( mix - > attn [ tmp ] < < 16 ) : 0 ;
snd_emu10k1_ptr_write ( emu , IFATN , voice , attn ) ;
snd_emu10k1_ptr_write ( emu , VTFT , voice , vattn | 0xffff ) ;
snd_emu10k1_ptr_write ( emu , CVCF , voice , vattn | 0xffff ) ;
snd_emu10k1_ptr_write ( emu , DCYSUSV , voice , 0x7f7f ) ;
snd_emu10k1_voice_clear_loop_stop ( emu , voice ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_playback_trigger_voice ( struct snd_emu10k1 * emu , struct snd_emu10k1_voice * evoice , int master , int extra )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm_substream * substream ;
struct snd_pcm_runtime * runtime ;
2005-04-16 15:20:36 -07:00
unsigned int voice , pitch , pitch_target ;
if ( evoice = = NULL ) /* skip second voice for mono */
return ;
substream = evoice - > epcm - > substream ;
runtime = substream - > runtime ;
voice = evoice - > number ;
pitch = snd_emu10k1_rate_to_pitch ( runtime - > rate ) > > 8 ;
2007-11-04 14:08:26 +00:00
if ( emu - > card_capabilities - > emu_model )
2006-10-10 18:08:45 +01:00
pitch_target = PITCH_48000 ; /* Disable interpolators on emu1010 card */
else
pitch_target = emu10k1_calc_pitch_target ( runtime - > rate ) ;
2005-04-16 15:20:36 -07:00
snd_emu10k1_ptr_write ( emu , PTRX_PITCHTARGET , voice , pitch_target ) ;
if ( master | | evoice - > epcm - > type = = PLAYBACK_EFX )
snd_emu10k1_ptr_write ( emu , CPF_CURRENTPITCH , voice , pitch_target ) ;
snd_emu10k1_ptr_write ( emu , IP , voice , pitch ) ;
if ( extra )
snd_emu10k1_voice_intr_enable ( emu , voice ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_playback_stop_voice ( struct snd_emu10k1 * emu , struct snd_emu10k1_voice * evoice )
2005-04-16 15:20:36 -07:00
{
unsigned int voice ;
if ( evoice = = NULL )
return ;
voice = evoice - > number ;
snd_emu10k1_voice_intr_disable ( emu , voice ) ;
snd_emu10k1_ptr_write ( emu , PTRX_PITCHTARGET , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , CPF_CURRENTPITCH , voice , 0 ) ;
snd_emu10k1_ptr_write ( emu , IFATN , voice , 0xffff ) ;
snd_emu10k1_ptr_write ( emu , VTFT , voice , 0xffff ) ;
snd_emu10k1_ptr_write ( emu , CVCF , voice , 0xffff ) ;
snd_emu10k1_ptr_write ( emu , IP , voice , 0 ) ;
}
2010-08-18 14:08:17 +02:00
static inline void snd_emu10k1_playback_mangle_extra ( struct snd_emu10k1 * emu ,
struct snd_emu10k1_pcm * epcm ,
struct snd_pcm_substream * substream ,
struct snd_pcm_runtime * runtime )
{
unsigned int ptr , period_pos ;
/* try to sychronize the current position for the interrupt
source voice */
period_pos = runtime - > status - > hw_ptr - runtime - > hw_ptr_interrupt ;
period_pos % = runtime - > period_size ;
ptr = snd_emu10k1_ptr_read ( emu , CCCA , epcm - > extra - > number ) ;
ptr & = ~ 0x00ffffff ;
ptr | = epcm - > ccca_start_addr + period_pos ;
snd_emu10k1_ptr_write ( emu , CCCA , epcm - > extra - > number , ptr ) ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_trigger ( struct snd_pcm_substream * substream ,
2005-04-16 15:20:36 -07:00
int cmd )
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
struct snd_emu10k1_pcm_mixer * mix ;
2005-04-16 15:20:36 -07:00
int result = 0 ;
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev ,
" trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i \n " ,
2009-02-05 16:08:14 +01:00
( int ) emu , cmd , substream - > ops - > pointer ( substream ) )
*/
2005-04-16 15:20:36 -07:00
spin_lock ( & emu - > reg_lock ) ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
snd_emu10k1_playback_invalidate_cache ( emu , 1 , epcm - > extra ) ; /* do we need this? */
snd_emu10k1_playback_invalidate_cache ( emu , 0 , epcm - > voices [ 0 ] ) ;
/* follow thru */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_RESUME :
2010-08-18 14:08:17 +02:00
if ( cmd = = SNDRV_PCM_TRIGGER_PAUSE_RELEASE )
snd_emu10k1_playback_mangle_extra ( emu , epcm , substream , runtime ) ;
2005-04-16 15:20:36 -07:00
mix = & emu - > pcm_mixer [ substream - > number ] ;
snd_emu10k1_playback_prepare_voice ( emu , epcm - > voices [ 0 ] , 1 , 0 , mix ) ;
snd_emu10k1_playback_prepare_voice ( emu , epcm - > voices [ 1 ] , 0 , 0 , mix ) ;
snd_emu10k1_playback_prepare_voice ( emu , epcm - > extra , 1 , 1 , NULL ) ;
snd_emu10k1_playback_trigger_voice ( emu , epcm - > voices [ 0 ] , 1 , 0 ) ;
snd_emu10k1_playback_trigger_voice ( emu , epcm - > voices [ 1 ] , 0 , 0 ) ;
snd_emu10k1_playback_trigger_voice ( emu , epcm - > extra , 1 , 1 ) ;
epcm - > running = 1 ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_SUSPEND :
2005-04-16 15:20:36 -07:00
epcm - > running = 0 ;
snd_emu10k1_playback_stop_voice ( emu , epcm - > voices [ 0 ] ) ;
snd_emu10k1_playback_stop_voice ( emu , epcm - > voices [ 1 ] ) ;
snd_emu10k1_playback_stop_voice ( emu , epcm - > extra ) ;
break ;
default :
result = - EINVAL ;
break ;
}
spin_unlock ( & emu - > reg_lock ) ;
return result ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_trigger ( struct snd_pcm_substream * substream ,
2005-04-16 15:20:36 -07:00
int cmd )
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
int result = 0 ;
spin_lock ( & emu - > reg_lock ) ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_RESUME :
2006-10-01 10:48:04 +01:00
/* hmm this should cause full and half full interrupt to be raised? */
2005-04-16 15:20:36 -07:00
outl ( epcm - > capture_ipr , emu - > port + IPR ) ;
snd_emu10k1_intr_enable ( emu , epcm - > capture_inte ) ;
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev , " adccr = 0x%x, adcbs = 0x%x \n " ,
2009-02-05 16:08:14 +01:00
epcm - > adccr , epcm - > adcbs ) ;
*/
2005-04-16 15:20:36 -07:00
switch ( epcm - > type ) {
case CAPTURE_AC97ADC :
snd_emu10k1_ptr_write ( emu , ADCCR , 0 , epcm - > capture_cr_val ) ;
break ;
case CAPTURE_EFX :
if ( emu - > audigy ) {
snd_emu10k1_ptr_write ( emu , A_FXWC1 , 0 , epcm - > capture_cr_val ) ;
snd_emu10k1_ptr_write ( emu , A_FXWC2 , 0 , epcm - > capture_cr_val2 ) ;
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev ,
" cr_val=0x%x, cr_val2=0x%x \n " ,
epcm - > capture_cr_val ,
epcm - > capture_cr_val2 ) ;
2005-04-16 15:20:36 -07:00
} else
snd_emu10k1_ptr_write ( emu , FXWC , 0 , epcm - > capture_cr_val ) ;
break ;
default :
break ;
}
snd_emu10k1_ptr_write ( emu , epcm - > capture_bs_reg , 0 , epcm - > capture_bs_val ) ;
epcm - > running = 1 ;
epcm - > first_ptr = 1 ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_SUSPEND :
2005-04-16 15:20:36 -07:00
epcm - > running = 0 ;
snd_emu10k1_intr_disable ( emu , epcm - > capture_inte ) ;
outl ( epcm - > capture_ipr , emu - > port + IPR ) ;
snd_emu10k1_ptr_write ( emu , epcm - > capture_bs_reg , 0 , 0 ) ;
switch ( epcm - > type ) {
case CAPTURE_AC97ADC :
snd_emu10k1_ptr_write ( emu , ADCCR , 0 , 0 ) ;
break ;
case CAPTURE_EFX :
if ( emu - > audigy ) {
snd_emu10k1_ptr_write ( emu , A_FXWC1 , 0 , 0 ) ;
snd_emu10k1_ptr_write ( emu , A_FXWC2 , 0 , 0 ) ;
} else
snd_emu10k1_ptr_write ( emu , FXWC , 0 , 0 ) ;
break ;
default :
break ;
}
break ;
default :
result = - EINVAL ;
}
spin_unlock ( & emu - > reg_lock ) ;
return result ;
}
2005-11-17 14:50:13 +01:00
static snd_pcm_uframes_t snd_emu10k1_playback_pointer ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
unsigned int ptr ;
if ( ! epcm - > running )
return 0 ;
ptr = snd_emu10k1_ptr_read ( emu , CCCA , epcm - > voices [ 0 ] - > number ) & 0x00ffffff ;
#if 0 /* Perex's code */
ptr + = runtime - > buffer_size ;
ptr - = epcm - > ccca_start_addr ;
ptr % = runtime - > buffer_size ;
# else /* EMU10K1 Open Source code from Creative */
if ( ptr < epcm - > ccca_start_addr )
ptr + = runtime - > buffer_size - epcm - > ccca_start_addr ;
else {
ptr - = epcm - > ccca_start_addr ;
if ( ptr > = runtime - > buffer_size )
ptr - = runtime - > buffer_size ;
}
# endif
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev ,
2010-08-18 14:08:17 +02:00
" ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx \n " ,
( long ) ptr , ( long ) runtime - > buffer_size ,
( long ) runtime - > period_size ) ;
2009-02-05 16:08:14 +01:00
*/
2005-04-16 15:20:36 -07:00
return ptr ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_efx_playback_trigger ( struct snd_pcm_substream * substream ,
2005-04-16 15:20:36 -07:00
int cmd )
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
int i ;
int result = 0 ;
spin_lock ( & emu - > reg_lock ) ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
2006-10-01 10:48:04 +01:00
/* prepare voices */
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < NUM_EFX_PLAYBACK ; i + + ) {
snd_emu10k1_playback_invalidate_cache ( emu , 0 , epcm - > voices [ i ] ) ;
}
snd_emu10k1_playback_invalidate_cache ( emu , 1 , epcm - > extra ) ;
/* follow thru */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_RESUME :
2005-04-16 15:20:36 -07:00
snd_emu10k1_playback_prepare_voice ( emu , epcm - > extra , 1 , 1 , NULL ) ;
snd_emu10k1_playback_prepare_voice ( emu , epcm - > voices [ 0 ] , 0 , 0 ,
& emu - > efx_pcm_mixer [ 0 ] ) ;
for ( i = 1 ; i < NUM_EFX_PLAYBACK ; i + + )
snd_emu10k1_playback_prepare_voice ( emu , epcm - > voices [ i ] , 0 , 0 ,
& emu - > efx_pcm_mixer [ i ] ) ;
snd_emu10k1_playback_trigger_voice ( emu , epcm - > voices [ 0 ] , 0 , 0 ) ;
snd_emu10k1_playback_trigger_voice ( emu , epcm - > extra , 1 , 1 ) ;
for ( i = 1 ; i < NUM_EFX_PLAYBACK ; i + + )
snd_emu10k1_playback_trigger_voice ( emu , epcm - > voices [ i ] , 0 , 0 ) ;
epcm - > running = 1 ;
break ;
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_SUSPEND :
2005-04-16 15:20:36 -07:00
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
epcm - > running = 0 ;
for ( i = 0 ; i < NUM_EFX_PLAYBACK ; i + + ) {
snd_emu10k1_playback_stop_voice ( emu , epcm - > voices [ i ] ) ;
}
snd_emu10k1_playback_stop_voice ( emu , epcm - > extra ) ;
break ;
default :
result = - EINVAL ;
break ;
}
spin_unlock ( & emu - > reg_lock ) ;
return result ;
}
2005-11-17 14:50:13 +01:00
static snd_pcm_uframes_t snd_emu10k1_capture_pointer ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm = runtime - > private_data ;
2005-04-16 15:20:36 -07:00
unsigned int ptr ;
if ( ! epcm - > running )
return 0 ;
if ( epcm - > first_ptr ) {
2006-10-01 10:48:04 +01:00
udelay ( 50 ) ; /* hack, it takes awhile until capture is started */
2005-04-16 15:20:36 -07:00
epcm - > first_ptr = 0 ;
}
ptr = snd_emu10k1_ptr_read ( emu , epcm - > capture_idx_reg , 0 ) & 0x0000ffff ;
return bytes_to_frames ( runtime , ptr ) ;
}
/*
* Playback support device description
*/
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hardware snd_emu10k1_playback =
2005-04-16 15:20:36 -07:00
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
2005-11-17 16:14:10 +01:00
SNDRV_PCM_INFO_RESUME |
2005-04-16 15:20:36 -07:00
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE ) ,
. formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000 ,
. rate_min = 4000 ,
. rate_max = 96000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 64 ,
. period_bytes_max = ( 128 * 1024 ) ,
. periods_min = 1 ,
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
/*
* Capture support device description
*/
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hardware snd_emu10k1_capture =
2005-04-16 15:20:36 -07:00
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
2005-11-17 16:14:10 +01:00
SNDRV_PCM_INFO_RESUME |
2005-04-16 15:20:36 -07:00
SNDRV_PCM_INFO_MMAP_VALID ) ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. rate_min = 8000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 2 ,
. buffer_bytes_max = ( 64 * 1024 ) ,
. period_bytes_min = 384 ,
. period_bytes_max = ( 64 * 1024 ) ,
. periods_min = 2 ,
. periods_max = 2 ,
. fifo_size = 0 ,
} ;
2006-10-01 10:48:04 +01:00
static struct snd_pcm_hardware snd_emu10k1_capture_efx =
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID ) ,
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 ,
. rate_min = 44100 ,
. rate_max = 192000 ,
. channels_min = 8 ,
. channels_max = 8 ,
. buffer_bytes_max = ( 64 * 1024 ) ,
. period_bytes_min = 384 ,
. period_bytes_max = ( 64 * 1024 ) ,
. periods_min = 2 ,
. periods_max = 2 ,
. fifo_size = 0 ,
} ;
2005-04-16 15:20:36 -07:00
/*
*
*/
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_mixer_notify1 ( struct snd_emu10k1 * emu , struct snd_kcontrol * kctl , int idx , int activate )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_ctl_elem_id id ;
2005-04-16 15:20:36 -07:00
2005-10-10 11:46:31 +02:00
if ( ! kctl )
return ;
2005-04-16 15:20:36 -07:00
if ( activate )
kctl - > vd [ idx ] . access & = ~ SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
else
kctl - > vd [ idx ] . access | = SNDRV_CTL_ELEM_ACCESS_INACTIVE ;
snd_ctl_notify ( emu - > card , SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO ,
snd_ctl_build_ioff ( & id , kctl , idx ) ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_mixer_notify ( struct snd_emu10k1 * emu , int idx , int activate )
2005-04-16 15:20:36 -07:00
{
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_send_routing , idx , activate ) ;
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_send_volume , idx , activate ) ;
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_attn , idx , activate ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_efx_mixer_notify ( struct snd_emu10k1 * emu , int idx , int activate )
2005-04-16 15:20:36 -07:00
{
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_efx_send_routing , idx , activate ) ;
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_efx_send_volume , idx , activate ) ;
snd_emu10k1_pcm_mixer_notify1 ( emu , emu - > ctl_efx_attn , idx , activate ) ;
}
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_pcm_free_substream ( struct snd_pcm_runtime * runtime )
2005-04-16 15:20:36 -07:00
{
[ALSA] Remove redundant NULL checks before kfree
Timer Midlevel,ALSA sequencer,ALSA<-OSS sequencer,Digigram VX core
I2C tea6330t,GUS Library,VIA82xx driver,VIA82xx-modem driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,YMFPCI driver
Digigram VX Pocket driver,Common EMU synth,USB generic driver,USB USX2Y
Checking a pointer for NULL before calling kfree() on it is redundant,
kfree() deals with NULL pointers just fine.
This patch removes such checks from sound/
This patch also makes another, but closely related, change.
It avoids casting pointers about to be kfree()'ed.
Signed-off-by: Jesper Juhl <juhl-lkml@dif.dk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-05-30 17:30:32 +02:00
kfree ( runtime - > private_data ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_efx_playback_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm_mixer * mix ;
2005-04-16 15:20:36 -07:00
int i ;
2006-10-01 10:48:04 +01:00
for ( i = 0 ; i < NUM_EFX_PLAYBACK ; i + + ) {
2005-04-16 15:20:36 -07:00
mix = & emu - > efx_pcm_mixer [ i ] ;
mix - > epcm = NULL ;
snd_emu10k1_pcm_efx_mixer_notify ( emu , i , 0 ) ;
}
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_efx_playback_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm * epcm ;
struct snd_emu10k1_pcm_mixer * mix ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
2005-04-16 15:20:36 -07:00
int i ;
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
epcm = kzalloc ( sizeof ( * epcm ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( epcm = = NULL )
return - ENOMEM ;
epcm - > emu = emu ;
epcm - > type = PLAYBACK_EFX ;
epcm - > substream = substream ;
emu - > pcm_playback_efx_substream = substream ;
runtime - > private_data = epcm ;
runtime - > private_free = snd_emu10k1_pcm_free_substream ;
runtime - > hw = snd_emu10k1_efx_playback ;
2006-10-01 10:48:04 +01:00
for ( i = 0 ; i < NUM_EFX_PLAYBACK ; i + + ) {
2005-04-16 15:20:36 -07:00
mix = & emu - > efx_pcm_mixer [ i ] ;
mix - > send_routing [ 0 ] [ 0 ] = i ;
memset ( & mix - > send_volume , 0 , sizeof ( mix - > send_volume ) ) ;
mix - > send_volume [ 0 ] [ 0 ] = 255 ;
mix - > attn [ 0 ] = 0xffff ;
mix - > epcm = epcm ;
snd_emu10k1_pcm_efx_mixer_notify ( emu , i , 1 ) ;
}
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm * epcm ;
struct snd_emu10k1_pcm_mixer * mix ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
2013-02-22 17:59:38 +00:00
int i , err , sample_rate ;
2005-04-16 15:20:36 -07:00
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
epcm = kzalloc ( sizeof ( * epcm ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( epcm = = NULL )
return - ENOMEM ;
epcm - > emu = emu ;
epcm - > type = PLAYBACK_EMUVOICE ;
epcm - > substream = substream ;
runtime - > private_data = epcm ;
runtime - > private_free = snd_emu10k1_pcm_free_substream ;
runtime - > hw = snd_emu10k1_playback ;
if ( ( err = snd_pcm_hw_constraint_integer ( runtime , SNDRV_PCM_HW_PARAM_PERIODS ) ) < 0 ) {
kfree ( epcm ) ;
return err ;
}
if ( ( err = snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_BUFFER_BYTES , 256 , UINT_MAX ) ) < 0 ) {
kfree ( epcm ) ;
return err ;
}
2013-02-22 17:59:38 +00:00
if ( emu - > card_capabilities - > emu_model & & emu - > emu1010 . internal_clock = = 0 )
sample_rate = 44100 ;
else
sample_rate = 48000 ;
err = snd_pcm_hw_rule_noresample ( runtime , sample_rate ) ;
2011-09-16 23:13:38 +02:00
if ( err < 0 ) {
kfree ( epcm ) ;
return err ;
}
2005-04-16 15:20:36 -07:00
mix = & emu - > pcm_mixer [ substream - > number ] ;
for ( i = 0 ; i < 4 ; i + + )
mix - > send_routing [ 0 ] [ i ] = mix - > send_routing [ 1 ] [ i ] = mix - > send_routing [ 2 ] [ i ] = i ;
memset ( & mix - > send_volume , 0 , sizeof ( mix - > send_volume ) ) ;
mix - > send_volume [ 0 ] [ 0 ] = mix - > send_volume [ 0 ] [ 1 ] =
mix - > send_volume [ 1 ] [ 0 ] = mix - > send_volume [ 2 ] [ 1 ] = 255 ;
mix - > attn [ 0 ] = mix - > attn [ 1 ] = mix - > attn [ 2 ] = 0xffff ;
mix - > epcm = epcm ;
snd_emu10k1_pcm_mixer_notify ( emu , substream - > number , 1 ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_playback_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm_mixer * mix = & emu - > pcm_mixer [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
mix - > epcm = NULL ;
snd_emu10k1_pcm_mixer_notify ( emu , substream - > number , 0 ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_pcm * epcm ;
2005-04-16 15:20:36 -07:00
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
epcm = kzalloc ( sizeof ( * epcm ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( epcm = = NULL )
return - ENOMEM ;
epcm - > emu = emu ;
epcm - > type = CAPTURE_AC97ADC ;
epcm - > substream = substream ;
epcm - > capture_ipr = IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL ;
epcm - > capture_inte = INTE_ADCBUFENABLE ;
epcm - > capture_ba_reg = ADCBA ;
epcm - > capture_bs_reg = ADCBS ;
epcm - > capture_idx_reg = emu - > audigy ? A_ADCIDX : ADCIDX ;
runtime - > private_data = epcm ;
runtime - > private_free = snd_emu10k1_pcm_free_substream ;
runtime - > hw = snd_emu10k1_capture ;
emu - > capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt ;
emu - > pcm_capture_substream = substream ;
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_PERIOD_BYTES , & hw_constraints_capture_period_sizes ) ;
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_RATE , & hw_constraints_capture_rates ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
2005-04-16 15:20:36 -07:00
emu - > capture_interrupt = NULL ;
emu - > pcm_capture_substream = NULL ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_mic_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm * epcm ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
2005-04-16 15:20:36 -07:00
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
epcm = kzalloc ( sizeof ( * epcm ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( epcm = = NULL )
return - ENOMEM ;
epcm - > emu = emu ;
epcm - > type = CAPTURE_AC97MIC ;
epcm - > substream = substream ;
epcm - > capture_ipr = IPR_MICBUFFULL | IPR_MICBUFHALFFULL ;
epcm - > capture_inte = INTE_MICBUFENABLE ;
epcm - > capture_ba_reg = MICBA ;
epcm - > capture_bs_reg = MICBS ;
epcm - > capture_idx_reg = emu - > audigy ? A_MICIDX : MICIDX ;
substream - > runtime - > private_data = epcm ;
substream - > runtime - > private_free = snd_emu10k1_pcm_free_substream ;
runtime - > hw = snd_emu10k1_capture ;
runtime - > hw . rates = SNDRV_PCM_RATE_8000 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 8000 ;
runtime - > hw . channels_min = 1 ;
emu - > capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt ;
emu - > pcm_capture_mic_substream = substream ;
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_PERIOD_BYTES , & hw_constraints_capture_period_sizes ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_mic_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
2005-04-16 15:20:36 -07:00
emu - > capture_interrupt = NULL ;
emu - > pcm_capture_mic_substream = NULL ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_efx_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_pcm * epcm ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
2005-04-16 15:20:36 -07:00
int nefx = emu - > audigy ? 64 : 32 ;
int idx ;
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
epcm = kzalloc ( sizeof ( * epcm ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( epcm = = NULL )
return - ENOMEM ;
epcm - > emu = emu ;
epcm - > type = CAPTURE_EFX ;
epcm - > substream = substream ;
epcm - > capture_ipr = IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL ;
epcm - > capture_inte = INTE_EFXBUFENABLE ;
epcm - > capture_ba_reg = FXBA ;
epcm - > capture_bs_reg = FXBS ;
epcm - > capture_idx_reg = FXIDX ;
substream - > runtime - > private_data = epcm ;
substream - > runtime - > private_free = snd_emu10k1_pcm_free_substream ;
2006-10-01 10:48:04 +01:00
runtime - > hw = snd_emu10k1_capture_efx ;
2005-04-16 15:20:36 -07:00
runtime - > hw . rates = SNDRV_PCM_RATE_48000 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 48000 ;
spin_lock_irq ( & emu - > reg_lock ) ;
2007-11-04 14:08:26 +00:00
if ( emu - > card_capabilities - > emu_model ) {
2007-06-11 12:21:20 +02:00
/* Nb. of channels has been increased to 16 */
/* TODO
2006-10-01 10:48:04 +01:00
* SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
* SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
* SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
* SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
* rate_min = 44100 ,
* rate_max = 192000 ,
2007-06-11 12:21:20 +02:00
* channels_min = 16 ,
* channels_max = 16 ,
2006-10-01 10:48:04 +01:00
* Need to add mixer control to fix sample rate
*
2007-06-11 12:21:20 +02:00
* There are 32 mono channels of 16 bits each .
2006-10-01 10:48:04 +01:00
* 24 bit Audio uses 2 x channels over 16 bit
* 96 kHz uses 2 x channels over 48 kHz
* 192 kHz uses 4 x channels over 48 kHz
2007-06-11 12:21:20 +02:00
* So , for 48 kHz 24 bit , one has 16 channels
* for 96 kHz 24 bit , one has 8 channels
* for 192 kHz 24 bit , one has 4 channels
*
2006-10-01 10:48:04 +01:00
*/
# if 1
2006-10-10 18:08:45 +01:00
switch ( emu - > emu1010 . internal_clock ) {
case 0 :
/* For 44.1kHz */
runtime - > hw . rates = SNDRV_PCM_RATE_44100 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 44100 ;
2007-06-11 12:21:20 +02:00
runtime - > hw . channels_min =
runtime - > hw . channels_max = 16 ;
2006-10-10 18:08:45 +01:00
break ;
case 1 :
/* For 48kHz */
runtime - > hw . rates = SNDRV_PCM_RATE_48000 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 48000 ;
2007-06-11 12:21:20 +02:00
runtime - > hw . channels_min =
runtime - > hw . channels_max = 16 ;
2006-10-10 18:08:45 +01:00
break ;
2012-09-28 11:24:57 +02:00
}
2006-10-01 10:48:04 +01:00
# endif
#if 0
/* For 96kHz */
runtime - > hw . rates = SNDRV_PCM_RATE_96000 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 96000 ;
runtime - > hw . channels_min = runtime - > hw . channels_max = 4 ;
# endif
#if 0
/* For 192kHz */
runtime - > hw . rates = SNDRV_PCM_RATE_192000 ;
runtime - > hw . rate_min = runtime - > hw . rate_max = 192000 ;
runtime - > hw . channels_min = runtime - > hw . channels_max = 2 ;
# endif
runtime - > hw . formats = SNDRV_PCM_FMTBIT_S32_LE ;
/* efx_voices_mask[0] is expected to be zero
2007-06-11 12:21:20 +02:00
* efx_voices_mask [ 1 ] is expected to have 32 bits set
2006-10-01 10:48:04 +01:00
*/
} else {
runtime - > hw . channels_min = runtime - > hw . channels_max = 0 ;
for ( idx = 0 ; idx < nefx ; idx + + ) {
if ( emu - > efx_voices_mask [ idx / 32 ] & ( 1 < < ( idx % 32 ) ) ) {
runtime - > hw . channels_min + + ;
runtime - > hw . channels_max + + ;
}
2005-04-16 15:20:36 -07:00
}
}
epcm - > capture_cr_val = emu - > efx_voices_mask [ 0 ] ;
epcm - > capture_cr_val2 = emu - > efx_voices_mask [ 1 ] ;
spin_unlock_irq ( & emu - > reg_lock ) ;
emu - > capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt ;
emu - > pcm_capture_efx_substream = substream ;
snd_pcm_hw_constraint_list ( runtime , 0 , SNDRV_PCM_HW_PARAM_PERIOD_BYTES , & hw_constraints_capture_period_sizes ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_capture_efx_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
2005-04-16 15:20:36 -07:00
emu - > capture_interrupt = NULL ;
emu - > pcm_capture_efx_substream = NULL ;
return 0 ;
}
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_playback_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_playback_open ,
. close = snd_emu10k1_playback_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_playback_hw_params ,
. hw_free = snd_emu10k1_playback_hw_free ,
. prepare = snd_emu10k1_playback_prepare ,
. trigger = snd_emu10k1_playback_trigger ,
. pointer = snd_emu10k1_playback_pointer ,
. page = snd_pcm_sgbuf_ops_page ,
} ;
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_capture_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_capture_open ,
. close = snd_emu10k1_capture_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_capture_hw_params ,
. hw_free = snd_emu10k1_capture_hw_free ,
. prepare = snd_emu10k1_capture_prepare ,
. trigger = snd_emu10k1_capture_trigger ,
. pointer = snd_emu10k1_capture_pointer ,
} ;
/* EFX playback */
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_efx_playback_open ,
. close = snd_emu10k1_efx_playback_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_playback_hw_params ,
. hw_free = snd_emu10k1_efx_playback_hw_free ,
. prepare = snd_emu10k1_efx_playback_prepare ,
. trigger = snd_emu10k1_efx_playback_trigger ,
. pointer = snd_emu10k1_efx_playback_pointer ,
. page = snd_pcm_sgbuf_ops_page ,
} ;
2015-01-02 12:24:49 +01:00
int snd_emu10k1_pcm ( struct snd_emu10k1 * emu , int device )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm * pcm ;
struct snd_pcm_substream * substream ;
2005-04-16 15:20:36 -07:00
int err ;
if ( ( err = snd_pcm_new ( emu - > card , " emu10k1 " , device , 32 , 1 , & pcm ) ) < 0 )
return err ;
pcm - > private_data = emu ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_emu10k1_playback_ops ) ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE , & snd_emu10k1_capture_ops ) ;
pcm - > info_flags = 0 ;
pcm - > dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX ;
strcpy ( pcm - > name , " ADC Capture/Standard PCM Playback " ) ;
emu - > pcm = pcm ;
for ( substream = pcm - > streams [ SNDRV_PCM_STREAM_PLAYBACK ] . substream ; substream ; substream = substream - > next )
if ( ( err = snd_pcm_lib_preallocate_pages ( substream , SNDRV_DMA_TYPE_DEV_SG , snd_dma_pci_data ( emu - > pci ) , 64 * 1024 , 64 * 1024 ) ) < 0 )
return err ;
for ( substream = pcm - > streams [ SNDRV_PCM_STREAM_CAPTURE ] . substream ; substream ; substream = substream - > next )
snd_pcm_lib_preallocate_pages ( substream , SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( emu - > pci ) , 64 * 1024 , 64 * 1024 ) ;
return 0 ;
}
2015-01-02 12:24:49 +01:00
int snd_emu10k1_pcm_multi ( struct snd_emu10k1 * emu , int device )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm * pcm ;
struct snd_pcm_substream * substream ;
2005-04-16 15:20:36 -07:00
int err ;
if ( ( err = snd_pcm_new ( emu - > card , " emu10k1 " , device , 1 , 0 , & pcm ) ) < 0 )
return err ;
pcm - > private_data = emu ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_emu10k1_efx_playback_ops ) ;
pcm - > info_flags = 0 ;
pcm - > dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX ;
strcpy ( pcm - > name , " Multichannel Playback " ) ;
2005-11-17 16:14:10 +01:00
emu - > pcm_multi = pcm ;
2005-04-16 15:20:36 -07:00
for ( substream = pcm - > streams [ SNDRV_PCM_STREAM_PLAYBACK ] . substream ; substream ; substream = substream - > next )
if ( ( err = snd_pcm_lib_preallocate_pages ( substream , SNDRV_DMA_TYPE_DEV_SG , snd_dma_pci_data ( emu - > pci ) , 64 * 1024 , 64 * 1024 ) ) < 0 )
return err ;
return 0 ;
}
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_capture_mic_open ,
. close = snd_emu10k1_capture_mic_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_capture_hw_params ,
. hw_free = snd_emu10k1_capture_hw_free ,
. prepare = snd_emu10k1_capture_prepare ,
. trigger = snd_emu10k1_capture_trigger ,
. pointer = snd_emu10k1_capture_pointer ,
} ;
2015-01-02 12:24:49 +01:00
int snd_emu10k1_pcm_mic ( struct snd_emu10k1 * emu , int device )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm * pcm ;
2005-04-16 15:20:36 -07:00
int err ;
if ( ( err = snd_pcm_new ( emu - > card , " emu10k1 mic " , device , 0 , 1 , & pcm ) ) < 0 )
return err ;
pcm - > private_data = emu ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE , & snd_emu10k1_capture_mic_ops ) ;
pcm - > info_flags = 0 ;
strcpy ( pcm - > name , " Mic Capture " ) ;
emu - > pcm_mic = pcm ;
snd_pcm_lib_preallocate_pages_for_all ( pcm , SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( emu - > pci ) , 64 * 1024 , 64 * 1024 ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_pcm_efx_voices_mask_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
int nefx = emu - > audigy ? 64 : 32 ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = nefx ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_pcm_efx_voices_mask_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
int nefx = emu - > audigy ? 64 : 32 ;
int idx ;
spin_lock_irq ( & emu - > reg_lock ) ;
for ( idx = 0 ; idx < nefx ; idx + + )
ucontrol - > value . integer . value [ idx ] = ( emu - > efx_voices_mask [ idx / 32 ] & ( 1 < < ( idx % 32 ) ) ) ? 1 : 0 ;
spin_unlock_irq ( & emu - > reg_lock ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_pcm_efx_voices_mask_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_kcontrol_chip ( kcontrol ) ;
2005-04-16 15:20:36 -07:00
unsigned int nval [ 2 ] , bits ;
int nefx = emu - > audigy ? 64 : 32 ;
int nefxb = emu - > audigy ? 7 : 6 ;
int change , idx ;
nval [ 0 ] = nval [ 1 ] = 0 ;
for ( idx = 0 , bits = 0 ; idx < nefx ; idx + + )
if ( ucontrol - > value . integer . value [ idx ] ) {
nval [ idx / 32 ] | = 1 < < ( idx % 32 ) ;
bits + + ;
}
for ( idx = 0 ; idx < nefxb ; idx + + )
if ( 1 < < idx = = bits )
break ;
if ( idx > = nefxb )
return - EINVAL ;
spin_lock_irq ( & emu - > reg_lock ) ;
change = ( nval [ 0 ] ! = emu - > efx_voices_mask [ 0 ] ) | |
( nval [ 1 ] ! = emu - > efx_voices_mask [ 1 ] ) ;
emu - > efx_voices_mask [ 0 ] = nval [ 0 ] ;
emu - > efx_voices_mask [ 1 ] = nval [ 1 ] ;
spin_unlock_irq ( & emu - > reg_lock ) ;
return change ;
}
2017-02-20 00:18:09 +05:30
static const struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = {
2005-04-16 15:20:36 -07:00
. iface = SNDRV_CTL_ELEM_IFACE_PCM ,
. name = " Captured FX8010 Outputs " ,
. info = snd_emu10k1_pcm_efx_voices_mask_info ,
. get = snd_emu10k1_pcm_efx_voices_mask_get ,
. put = snd_emu10k1_pcm_efx_voices_mask_put
} ;
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_capture_efx_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_capture_efx_open ,
. close = snd_emu10k1_capture_efx_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_capture_hw_params ,
. hw_free = snd_emu10k1_capture_hw_free ,
. prepare = snd_emu10k1_capture_prepare ,
. trigger = snd_emu10k1_capture_trigger ,
. pointer = snd_emu10k1_capture_pointer ,
} ;
/* EFX playback */
# define INITIAL_TRAM_SHIFT 14
# define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1)
2005-11-17 14:50:13 +01:00
static void snd_emu10k1_fx8010_playback_irq ( struct snd_emu10k1 * emu , void * private_data )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm_substream * substream = private_data ;
2005-04-16 15:20:36 -07:00
snd_pcm_period_elapsed ( substream ) ;
}
static void snd_emu10k1_fx8010_playback_tram_poke1 ( unsigned short * dst_left ,
unsigned short * dst_right ,
unsigned short * src ,
unsigned int count ,
unsigned int tram_shift )
{
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev ,
" tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
2009-02-05 16:08:14 +01:00
" src = 0x%p, count = 0x%x \n " ,
dst_left , dst_right , src , count ) ;
*/
2005-04-16 15:20:36 -07:00
if ( ( tram_shift & 1 ) = = 0 ) {
while ( count - - ) {
* dst_left - - = * src + + ;
* dst_right - - = * src + + ;
}
} else {
while ( count - - ) {
* dst_right - - = * src + + ;
* dst_left - - = * src + + ;
}
}
}
2005-11-17 14:50:13 +01:00
static void fx8010_pb_trans_copy ( struct snd_pcm_substream * substream ,
struct snd_pcm_indirect * rec , size_t bytes )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
unsigned int tram_size = pcm - > buffer_size ;
unsigned short * src = ( unsigned short * ) ( substream - > runtime - > dma_area + rec - > sw_data ) ;
unsigned int frames = bytes > > 2 , count ;
unsigned int tram_pos = pcm - > tram_pos ;
unsigned int tram_shift = pcm - > tram_shift ;
while ( frames > tram_pos ) {
count = tram_pos + 1 ;
snd_emu10k1_fx8010_playback_tram_poke1 ( ( unsigned short * ) emu - > fx8010 . etram_pages . area + tram_pos ,
( unsigned short * ) emu - > fx8010 . etram_pages . area + tram_pos + tram_size / 2 ,
src , count , tram_shift ) ;
src + = count * 2 ;
frames - = count ;
tram_pos = ( tram_size / 2 ) - 1 ;
tram_shift + + ;
}
snd_emu10k1_fx8010_playback_tram_poke1 ( ( unsigned short * ) emu - > fx8010 . etram_pages . area + tram_pos ,
( unsigned short * ) emu - > fx8010 . etram_pages . area + tram_pos + tram_size / 2 ,
src , frames , tram_shift ) ;
tram_pos - = frames ;
pcm - > tram_pos = tram_pos ;
pcm - > tram_shift = tram_shift ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_transfer ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
2017-05-19 18:49:23 +02:00
return snd_pcm_indirect_playback_transfer ( substream , & pcm - > pcm_rec ,
fx8010_pb_trans_copy ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * hw_params )
2005-04-16 15:20:36 -07:00
{
return snd_pcm_lib_malloc_pages ( substream , params_buffer_bytes ( hw_params ) ) ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_hw_free ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
unsigned int i ;
for ( i = 0 ; i < pcm - > channels ; i + + )
snd_emu10k1_ptr_write ( emu , TANKMEMADDRREGBASE + 0x80 + pcm - > etram [ i ] , 0 , 0 ) ;
snd_pcm_lib_free_pages ( substream ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_prepare ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
unsigned int i ;
2009-02-05 16:08:14 +01:00
/*
2014-02-25 17:02:09 +01:00
dev_dbg ( emu - > card - > dev , " prepare: etram_pages = 0x%p, dma_area = 0x%x, "
2009-02-05 16:08:14 +01:00
" buffer_size = 0x%x (0x%x) \n " ,
emu - > fx8010 . etram_pages , runtime - > dma_area ,
runtime - > buffer_size , runtime - > buffer_size < < 2 ) ;
*/
2005-04-16 15:20:36 -07:00
memset ( & pcm - > pcm_rec , 0 , sizeof ( pcm - > pcm_rec ) ) ;
pcm - > pcm_rec . hw_buffer_size = pcm - > buffer_size * 2 ; /* byte size */
pcm - > pcm_rec . sw_buffer_size = snd_pcm_lib_buffer_bytes ( substream ) ;
pcm - > tram_pos = INITIAL_TRAM_POS ( pcm - > buffer_size ) ;
pcm - > tram_shift = 0 ;
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_running , 0 , 0 ) ; /* reset */
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_trigger , 0 , 0 ) ; /* reset */
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_size , 0 , runtime - > buffer_size ) ;
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_ptr , 0 , 0 ) ; /* reset ptr number */
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_count , 0 , runtime - > period_size ) ;
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_tmpcount , 0 , runtime - > period_size ) ;
for ( i = 0 ; i < pcm - > channels ; i + + )
snd_emu10k1_ptr_write ( emu , TANKMEMADDRREGBASE + 0x80 + pcm - > etram [ i ] , 0 , ( TANKMEMADDRREG_READ | TANKMEMADDRREG_ALIGN ) + i * ( runtime - > buffer_size / pcm - > channels ) ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_trigger ( struct snd_pcm_substream * substream , int cmd )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
int result = 0 ;
spin_lock ( & emu - > reg_lock ) ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
/* follow thru */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_RESUME :
2005-04-16 15:20:36 -07:00
# ifdef EMU10K1_SET_AC3_IEC958
{
int i ;
for ( i = 0 ; i < 3 ; i + + ) {
unsigned int bits ;
bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA ;
snd_emu10k1_ptr_write ( emu , SPCS0 + i , 0 , bits ) ;
}
}
# endif
result = snd_emu10k1_fx8010_register_irq_handler ( emu , snd_emu10k1_fx8010_playback_irq , pcm - > gpr_running , substream , & pcm - > irq ) ;
if ( result < 0 )
goto __err ;
snd_emu10k1_fx8010_playback_transfer ( substream ) ; /* roll the ball */
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_trigger , 0 , 1 ) ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2005-11-17 16:14:10 +01:00
case SNDRV_PCM_TRIGGER_SUSPEND :
2005-04-16 15:20:36 -07:00
snd_emu10k1_fx8010_unregister_irq_handler ( emu , pcm - > irq ) ; pcm - > irq = NULL ;
snd_emu10k1_ptr_write ( emu , emu - > gpr_base + pcm - > gpr_trigger , 0 , 0 ) ;
pcm - > tram_pos = INITIAL_TRAM_POS ( pcm - > buffer_size ) ;
pcm - > tram_shift = 0 ;
break ;
default :
result = - EINVAL ;
break ;
}
__err :
spin_unlock ( & emu - > reg_lock ) ;
return result ;
}
2005-11-17 14:50:13 +01:00
static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
size_t ptr ; /* byte pointer */
if ( ! snd_emu10k1_ptr_read ( emu , emu - > gpr_base + pcm - > gpr_trigger , 0 ) )
return 0 ;
ptr = snd_emu10k1_ptr_read ( emu , emu - > gpr_base + pcm - > gpr_ptr , 0 ) < < 2 ;
return snd_pcm_indirect_playback_pointer ( substream , & pcm - > pcm_rec , ptr ) ;
}
2005-11-17 14:50:13 +01:00
static struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
2005-04-16 15:20:36 -07:00
{
. info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
2005-11-17 16:14:10 +01:00
SNDRV_PCM_INFO_RESUME |
2005-04-16 15:20:36 -07:00
/* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE ) ,
. formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE ,
. rates = SNDRV_PCM_RATE_48000 ,
. rate_min = 48000 ,
. rate_max = 48000 ,
. channels_min = 1 ,
. channels_max = 1 ,
. buffer_bytes_max = ( 128 * 1024 ) ,
. period_bytes_min = 1024 ,
. period_bytes_max = ( 128 * 1024 ) ,
2009-06-08 15:50:42 +02:00
. periods_min = 2 ,
2005-04-16 15:20:36 -07:00
. periods_max = 1024 ,
. fifo_size = 0 ,
} ;
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_open ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
runtime - > hw = snd_emu10k1_fx8010_playback ;
runtime - > hw . channels_min = runtime - > hw . channels_max = pcm - > channels ;
runtime - > hw . period_bytes_max = ( pcm - > buffer_size * 2 ) / 2 ;
spin_lock_irq ( & emu - > reg_lock ) ;
if ( pcm - > valid = = 0 ) {
spin_unlock_irq ( & emu - > reg_lock ) ;
return - ENODEV ;
}
pcm - > opened = 1 ;
spin_unlock_irq ( & emu - > reg_lock ) ;
return 0 ;
}
2005-11-17 14:50:13 +01:00
static int snd_emu10k1_fx8010_playback_close ( struct snd_pcm_substream * substream )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_emu10k1 * emu = snd_pcm_substream_chip ( substream ) ;
struct snd_emu10k1_fx8010_pcm * pcm = & emu - > fx8010 . pcm [ substream - > number ] ;
2005-04-16 15:20:36 -07:00
spin_lock_irq ( & emu - > reg_lock ) ;
pcm - > opened = 0 ;
spin_unlock_irq ( & emu - > reg_lock ) ;
return 0 ;
}
2016-09-02 00:13:10 +02:00
static const struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
2005-04-16 15:20:36 -07:00
. open = snd_emu10k1_fx8010_playback_open ,
. close = snd_emu10k1_fx8010_playback_close ,
. ioctl = snd_pcm_lib_ioctl ,
. hw_params = snd_emu10k1_fx8010_playback_hw_params ,
. hw_free = snd_emu10k1_fx8010_playback_hw_free ,
. prepare = snd_emu10k1_fx8010_playback_prepare ,
. trigger = snd_emu10k1_fx8010_playback_trigger ,
. pointer = snd_emu10k1_fx8010_playback_pointer ,
. ack = snd_emu10k1_fx8010_playback_transfer ,
} ;
2015-01-02 12:24:49 +01:00
int snd_emu10k1_pcm_efx ( struct snd_emu10k1 * emu , int device )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:50:13 +01:00
struct snd_pcm * pcm ;
struct snd_kcontrol * kctl ;
2005-04-16 15:20:36 -07:00
int err ;
if ( ( err = snd_pcm_new ( emu - > card , " emu10k1 efx " , device , 8 , 1 , & pcm ) ) < 0 )
return err ;
pcm - > private_data = emu ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_PLAYBACK , & snd_emu10k1_fx8010_playback_ops ) ;
snd_pcm_set_ops ( pcm , SNDRV_PCM_STREAM_CAPTURE , & snd_emu10k1_capture_efx_ops ) ;
pcm - > info_flags = 0 ;
strcpy ( pcm - > name , " Multichannel Capture/PT Playback " ) ;
emu - > pcm_efx = pcm ;
/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
* to these
*/
/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
if ( emu - > audigy ) {
emu - > efx_voices_mask [ 0 ] = 0 ;
2007-11-04 14:08:26 +00:00
if ( emu - > card_capabilities - > emu_model )
2007-06-11 12:21:20 +02:00
/* Pavel Hofman - 32 voices will be used for
* capture ( write mode ) -
* each bit = corresponding voice
*/
emu - > efx_voices_mask [ 1 ] = 0xffffffff ;
else
emu - > efx_voices_mask [ 1 ] = 0xffff ;
2005-04-16 15:20:36 -07:00
} else {
emu - > efx_voices_mask [ 0 ] = 0xffff0000 ;
emu - > efx_voices_mask [ 1 ] = 0 ;
}
2007-06-11 12:21:20 +02:00
/* For emu1010, the control has to set 32 upper bits (voices)
* out of the 64 bits ( voices ) to true for the 16 - channels capture
* to work correctly . Correct A_FXWC2 initial value ( 0xffffffff )
* is already defined but the snd_emu10k1_pcm_efx_voices_mask
* control can override this register ' s value .
*/
[ALSA] sound - fix .iface field of mixer control elements
Documentation,CS46xx driver,EMU10K1/EMU10K2 driver,AD1848 driver
SB16/AWE driver,CMIPCI driver,ENS1370/1+ driver,RME32 driver
RME96 driver,ICE1712 driver,ICE1724 driver,KORG1212 driver
RME HDSP driver,RME9652 driver
This patch changes .iface to SNDRV_CTL_ELEM_IFACE_MIXER whre _PCM or
_HWDEP was used in controls that are not associated with a specific PCM
(sub)stream or hwdep device, and changes some controls that got
inconsitent .iface values due to copy+paste errors. Furthermore, it
makes sure that all control that do use _PCM or _HWDEP use the correct
number in the .device field.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
2005-07-29 15:32:58 +02:00
kctl = snd_ctl_new1 ( & snd_emu10k1_pcm_efx_voices_mask , emu ) ;
if ( ! kctl )
return - ENOMEM ;
kctl - > id . device = device ;
snd_ctl_add ( emu - > card , kctl ) ;
2005-04-16 15:20:36 -07:00
snd_pcm_lib_preallocate_pages_for_all ( pcm , SNDRV_DMA_TYPE_DEV , snd_dma_pci_data ( emu - > pci ) , 64 * 1024 , 64 * 1024 ) ;
return 0 ;
}