📄 em8xxx_alsa.c
字号:
/***************************************** Copyright � 2004-2005 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//** @file em8xxx_alsa.c @brief Alsa driver for the EM8xxx serie. Strategy : The main sound cards do not have their proper DRAM, and the sound engine just reads data from the DRAM of the computer and sends them to the DAC. We have an external harware buffer, and the strategy is to make an intermediate buffer and copy/set the data from it to the external hardware buffer in tasklets. We handle the interrupt which occurs when the send_data is complete, and in the tasklet we transfer another block of data. @author Yoann Walther @date 2005-07-21*/#ifndef __SNDEM8XXX_C__#define __SNDEM8XXX_C__#include "em8xxxalsa.h"extern struct em8xxxprivate Etable[MAXLLAD];RMstatus krua_register_sendcomplete_callback(void *pE, Alsa_callback callback);RMstatus krua_unregister_sendcomplete_callback(void *pE);RMstatus krua_register_event_callback(void *pE, RMuint32 ModuleID, RMuint32 mask,Event_callback callback);RMstatus krua_unregister_event_callback(void *pE,RMuint32 ModuleID,Event_callback callback); static u_long audio_decoder_index = 1;static u_long audio_engine_index;static u_long audio_capture_index;static u_long audio_mmID = 0;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)module_param(audio_decoder_index, ulong,0 );module_param(audio_mmID, ulong,0);#elseMODULE_PARM(audio_decoder_index, "l");MODULE_PARM(audio_mmID, "l");#endifMODULE_PARM_DESC(audio_decoder_index, "Audio Decoder in use\n");MODULE_PARM_DESC(audio_mmID, "Audio Memory Manager in use\n");MODULE_DESCRIPTION("EM8XXX Sound Alsa Driver");MODULE_AUTHOR("Yoann Walther <yoann_walther@realmagic.fr>");MODULE_LICENSE("Proprietary");static int snd_em8xxx_free(em8xxx_t *chip);static int snd_em8xxx_dev_free(snd_device_t *device);#if EM86XX_MODE==EM86XX_MODEID_WITHHOSTstatic int __devinit snd_em8xxx_create(snd_card_t * card,struct pci_dev * pci,em8xxx_t * chip);#elsestatic int __devinit snd_em8xxx_create(snd_card_t * card,em8xxx_t * chip);#endifstatic int sndprivate_init(struct em8xxxprivate *pE);static int sndprivate_cleanup(struct em8xxxprivate *pE);static int snd_em8xxx_info_hw_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);static int snd_em8xxx_get_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);static int snd_em8xxx_put_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);static void snd_em8xxx_hwv_free(snd_kcontrol_t *kcontrol);static int snd_em8xxx_info_weight(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);static int snd_em8xxx_get_weight(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);static int snd_em8xxx_put_weight(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);static void snd_em8xxx_weight_free(snd_kcontrol_t *kcontrol);static int __devinit snd_em8xxx_mixer(em8xxx_t *chip);static int snd_em8xxx_capture_open(snd_pcm_substream_t * substream);static int snd_em8xxx_playback_open(snd_pcm_substream_t * substream);static int snd_em8xxx_capture_close(snd_pcm_substream_t * substream);static int snd_em8xxx_playback_close(snd_pcm_substream_t * substream);static int snd_em8xxx_pcm_hw_params(snd_pcm_substream_t *substream,snd_pcm_hw_params_t * hw_params);static int snd_em8xxx_pcm_hw_free(snd_pcm_substream_t *substream);static int snd_em8xxx_playback_prepare(snd_pcm_substream_t * substream);static int snd_em8xxx_capture_prepare(snd_pcm_substream_t * substream);static int snd_em8xxx_playback_trigger(snd_pcm_substream_t * substream,int cmd);static int snd_em8xxx_capture_trigger(snd_pcm_substream_t * substream,int cmd);static snd_pcm_uframes_t snd_em8xxx_playback_pointer(snd_pcm_substream_t * substream);static snd_pcm_uframes_t snd_em8xxx_capture_pointer(snd_pcm_substream_t * substream);static int snd_em8xxx_playback_ack(snd_pcm_substream_t * substream);static int snd_em8xxx_capture_ack(snd_pcm_substream_t * substream);static void snd_em8xxx_free_pcm(snd_pcm_t *pcm);static int __devinit snd_em8xxx_new_pcm(em8xxx_t *chip, int device, snd_pcm_t ** rpcm);static RMstatus init_audio(em8xxx_t *pS);static RMstatus open_audio_capture(em8xxx_t *pS);static RMstatus open_audio_decoder(em8xxx_t *pS);static RMstatus set_audio_parameters(em8xxx_t *pS);static RMstatus prepare_audio_decoder(em8xxx_t *pS);static int send_data_callback(void *pE,RMuint32 bus_address);static RMuint32 receive_data_callback(void *pE,RMuint32 ModuleID,RMuint32 mask);static void em8xxx_playback_start_interrupt(unsigned long private_data);static void em8xxx_capture_start_interrupt(unsigned long private_data);static int em8xxx_pcm_playback_update (em8xxx_t *chip);static int em8xxx_pcm_capture_update (em8xxx_t *chip);static int playback_update_position (em8xxx_t *chip);static int capture_update_position (em8xxx_t *chip);static void em8xxx_playback_setaudio_interrupt(unsigned long private_data);static void em8xxx_capture_setaudio_interrupt(unsigned long private_data);static RMstatus start_stc(em8xxx_t *chip);static int snd_em8xxx_free_ptr(struct em8xxxprivate *pE,RMuint32 ptr);static void em8xxx_playback_stop_interrupt(unsigned long private_data);static void em8xxx_playback_stop_interrupt(unsigned long private_data);static int snd_em8xxx_spdif_mask_info(snd_kcontrol_t *kcontrol,snd_ctl_elem_info_t *uinfo);static int snd_em8xxx_spdif_mask_get(snd_kcontrol_t * kcontrol,snd_ctl_elem_value_t *ucontrol);static int snd_em8xxx_spdif_default_info(snd_kcontrol_t *kcontrol,snd_ctl_elem_info_t *uinfo);static int snd_em8xxx_spdif_default_get(snd_kcontrol_t *kcontrol,snd_ctl_elem_value_t *ucontrol);static int snd_em8xxx_spdif_default_put(snd_kcontrol_t * kcontrol,snd_ctl_elem_value_t * ucontrol);static void snd_em8xxx_spdif_default_free(snd_kcontrol_t *kcontrol);static void snd_em8xxx_spdif_mask_free(snd_kcontrol_t *kcontrol);static int snd_em8xxx_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo);static int snd_em8xxx_spdout_enable_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);static int snd_em8xxx_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol);static void snd_em8xxx_spdif_switch_free(snd_kcontrol_t *kcontrol);static RMstatus prepare_data(em8xxx_t *pS);/* ******************************************************************************* SPDIF PART DRIVER *********************************************************************************/static int snd_em8xxx_spdif_mask_info(snd_kcontrol_t *kcontrol,snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0;}static int snd_em8xxx_spdif_mask_get(snd_kcontrol_t * kcontrol,snd_ctl_elem_value_t *ucontrol){ int i; RMuint32 mask; em8xxx_t * chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioEngine_ChannelStatus_type channel_status; RMstatus err; EM8XXXSNDGP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_ChannelStatus,&channel_status,sizeof(channel_status)); channel_status.Mask=0xffffffff; /* When changing the value of the Channel Bit Status the hwlib do an and logic with the mask. This one was initialized to zero by default. */ EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_ChannelStatus,&channel_status,sizeof(channel_status)); mask=channel_status.Mask; kc_spin_lock_bh(pE->lock); for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (mask >> (i * 8)) & 0xff; kc_spin_unlock_bh(pE->lock); return 0;}static void snd_em8xxx_spdif_mask_free(snd_kcontrol_t *kcontrol){ em8xxx_t *chip = (em8xxx_t *) snd_kcontrol_chip(kcontrol); chip->spdif_mask_ctl = NULL;}static int snd_em8xxx_spdif_default_info(snd_kcontrol_t *kcontrol,snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0;}static int snd_em8xxx_spdif_default_get(snd_kcontrol_t *kcontrol,snd_ctl_elem_value_t *ucontrol){ int i; RMuint32 val; em8xxx_t * chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioEngine_ChannelStatus_type channel_status; RMstatus err; EM8XXXSNDGP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_ChannelStatus,&channel_status,sizeof(channel_status)); val = channel_status.Value; kc_spin_lock_bh(pE->lock); for (i = 0; i < 4; i++) ucontrol->value.iec958.status[i] = (val >> (i * 8)) & 0xff; kc_spin_unlock_bh(pE->lock); return 0;}static int snd_em8xxx_spdif_default_put(snd_kcontrol_t * kcontrol,snd_ctl_elem_value_t * ucontrol){ em8xxx_t *chip = snd_kcontrol_chip(kcontrol); int i, change; unsigned int val; struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioEngine_ChannelStatus_type channel_status; RMstatus err; RMuint32 value; EM8XXXSNDGP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_ChannelStatus,&channel_status,sizeof(channel_status)); value = channel_status.Value; val = 0; kc_spin_lock_bh(pE->lock); for (i = 0; i < 4; i++) val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8); change = val != value; channel_status.Value=val; channel_status.Mask=0xffffffff; EMhwlibSetProperty(pE->pemhwlib,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_ChannelStatus,&channel_status,sizeof(channel_status)); if(RMFAILED(err)){ printk("error while setting S/PDIF Channel Bit Status"); } kc_spin_unlock_bh(pE->lock); return change;}static void snd_em8xxx_spdif_default_free(snd_kcontrol_t *kcontrol){ em8xxx_t *chip = (em8xxx_t *) snd_kcontrol_chip(kcontrol); chip->spdif_default_ctl = NULL;}static int snd_em8xxx_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_em8xxx_spdout_enable_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ em8xxx_t *chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate *pE = Etable +(chip-Stable); enum AudioEngine_SpdifOut_type spdif_out; RMstatus err; RMuint32 audio_engine = EMHWLIB_MODULE(AudioEngine,audio_engine_index); EM8XXXSNDGP(pE, audio_engine, RMAudioEnginePropertyID_SpdifOut, &spdif_out, sizeof(spdif_out)); if (spdif_out==AudioEngine_SpdifOut_Active){ ucontrol->value.integer.value[0]=1; } else { ucontrol->value.integer.value[0]=0; } return 0;}static int snd_em8xxx_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ em8xxx_t *chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate *pE = Etable +(chip-Stable); enum AudioEngine_SpdifOut_type spdif_out; RMstatus err; RMuint32 audio_engine = EMHWLIB_MODULE(AudioEngine,audio_engine_index); int changed=0; if (ucontrol->value.integer.value[0]!=chip->spdif_enable){ changed=1; if (ucontrol->value.integer.value[0]) { spdif_out= AudioEngine_SpdifOut_Active; EM8XXXSNDSP(pE, audio_engine, RMAudioEnginePropertyID_SpdifOut, &spdif_out, sizeof(spdif_out)); chip->spdif_enable=1; } else { spdif_out= AudioEngine_SpdifOut_ActiveData0; EM8XXXSNDSP(pE, audio_engine, RMAudioEnginePropertyID_SpdifOut, &spdif_out, sizeof(spdif_out)); chip->spdif_enable=0; } } return changed;}static void snd_em8xxx_spdif_switch_free(snd_kcontrol_t *kcontrol){ em8xxx_t *chip = (em8xxx_t *) snd_kcontrol_chip(kcontrol); chip->spdif_switch_ctl = NULL;}/* ******************************************************************* ************* MIXER PART DRIVER ************* ******************************************************************* */static int snd_em8xxx_info_hw_volume(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 = 73; return 0;}static int snd_em8xxx_info_weight(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 = 73; return 0;}static int snd_em8xxx_get_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ em8xxx_t * chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioEngine_QueryVolume_in_type volume_in; struct AudioEngine_QueryVolume_out_type volume_out; RMstatus err; int l,r,volume_index; /* gets the left volume */ volume_in.Channel=0; EM8XXXSNDEXP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_QueryVolume,&volume_in,sizeof(volume_in),&volume_out,sizeof(volume_out)); l=volume_out.Volume; volume_index=0; while((l)>(VolumeTable[volume_index])){ volume_index++; } ucontrol->value.integer.value[0] = volume_index;; /* gets the right volume */ volume_in.Channel=2; EM8XXXSNDEXP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_QueryVolume,&volume_in,sizeof(volume_in),&volume_out,sizeof(volume_out)); r=volume_out.Volume; volume_index=0; while((r)>(VolumeTable[volume_index])){ volume_index++; } ucontrol->value.integer.value[1] = volume_index; return 0;}static int snd_em8xxx_get_weight(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ em8xxx_t * chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->weight_l; ucontrol->value.integer.value[1] = chip->weight_r; return 0;}static int snd_em8xxx_put_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ em8xxx_t *chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioEngine_Volume_type volume; int volume_index; RMstatus err; /* sets the left volume */ volume_index=ucontrol->value.integer.value[0]; volume.Channel=0; volume.Volume=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_Volume,&volume,sizeof(volume)); if (RMFAILED(err)){ printk("error while setting volume \n"); } /* sets the right volume */ volume_index=ucontrol->value.integer.value[1]; volume.Channel=2; volume.Volume=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_Volume,&volume,sizeof(volume)); if (RMFAILED(err)){ printk("error while setting volume \n"); } return 0;}static int snd_em8xxx_put_weight(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ em8xxx_t *chip = snd_kcontrol_chip(kcontrol); struct em8xxxprivate * pE = Etable + (chip-Stable); struct AudioDecoder_MixerWeight_type cmdblock; int volume_index; RMstatus err; /* sets the left volume */ volume_index=ucontrol->value.integer.value[0]; chip->weight_l=volume_index; cmdblock.MixerValue_ch0=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioDecoder,audio_decoder_index),RMAudioDecoderPropertyID_MixerWeight,&cmdblock,sizeof(cmdblock)); if (RMFAILED(err)){ printk("error while setting decoder weight \n"); } /* sets the right volume */ volume_index=ucontrol->value.integer.value[1]; chip->weight_r=volume_index; cmdblock.MixerValue_ch2=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioDecoder,audio_decoder_index),RMAudioDecoderPropertyID_MixerWeight,&cmdblock,sizeof(cmdblock)); if (RMFAILED(err)){ printk("error while setting decoder weight \n"); } return 0;}static void snd_em8xxx_hwv_free(snd_kcontrol_t *kcontrol){ em8xxx_t *chip = (em8xxx_t *) snd_kcontrol_chip(kcontrol); chip->master_volume = NULL;}static void snd_em8xxx_weight_free(snd_kcontrol_t *kcontrol){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -