cs46xx_lib.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
pcm->private_data = chip; pcm->private_free = snd_cs46xx_pcm_iec958_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_iec958_ops); /* global setup */ pcm->info_flags = 0; strcpy(pcm->name, "CS46xx - IEC958"); chip->pcm_rear = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; return 0;}#endif/* * Mixer routines */static void snd_cs46xx_mixer_free_ac97_bus(ac97_bus_t *bus){ cs46xx_t *chip = snd_magic_cast(cs46xx_t, bus->private_data, return); chip->ac97_bus = NULL;}static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97){ cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); snd_assert ((ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) || (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]), return); if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) { chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = NULL; chip->eapd_switch = NULL; } else chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] = NULL;}static int snd_cs46xx_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 0x7fff; return 0;}static int snd_cs46xx_vol_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; unsigned int val = snd_cs46xx_peek(chip, reg); ucontrol->value.integer.value[0] = 0xffff - (val >> 16); ucontrol->value.integer.value[1] = 0xffff - (val & 0xffff); return 0;}static int snd_cs46xx_vol_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; unsigned int val = ((0xffff - ucontrol->value.integer.value[0]) << 16 | (0xffff - ucontrol->value.integer.value[1])); unsigned int old = snd_cs46xx_peek(chip, reg); int change = (old != val); if (change) { snd_cs46xx_poke(chip, reg, val); } return change;}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_left; ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_right; return 0;}static int snd_cs46xx_vol_dac_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int change = 0; if (chip->dsp_spos_instance->dac_volume_right != ucontrol->value.integer.value[0] || chip->dsp_spos_instance->dac_volume_left != ucontrol->value.integer.value[1]) { cs46xx_dsp_set_dac_volume(chip, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); change = 1; } return change;}#if 0static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_left; ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_right; return 0;}static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int change = 0; if (chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[0] || chip->dsp_spos_instance->spdif_input_volume_right!= ucontrol->value.integer.value[1]) { cs46xx_dsp_set_iec958_volume (chip, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]); change = 1; } return change;}#endifstatic int snd_mixer_boolean_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_cs46xx_iec958_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; if (reg == CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT) ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); else ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in; return 0;}static int snd_cs46xx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int change, res; switch (kcontrol->private_value) { case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT: down (&chip->spos_mutex); change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED); if (ucontrol->value.integer.value[0] && !change) cs46xx_dsp_enable_spdif_out(chip); else if (change && !ucontrol->value.integer.value[0]) cs46xx_dsp_disable_spdif_out(chip); res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED)); up (&chip->spos_mutex); break; case CS46XX_MIXER_SPDIF_INPUT_ELEMENT: change = chip->dsp_spos_instance->spdif_status_in; if (ucontrol->value.integer.value[0] && !change) { cs46xx_dsp_enable_spdif_in(chip); /* restore volume */ } else if (change && !ucontrol->value.integer.value[0]) cs46xx_dsp_disable_spdif_in(chip); res = (change != chip->dsp_spos_instance->spdif_status_in); break; default: res = -EINVAL; snd_assert(0, (void)0); } return res;}static int snd_cs46xx_adc_capture_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; if (ins->adc_input != NULL) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; return 0;}static int snd_cs46xx_adc_capture_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; int change = 0; if (ucontrol->value.integer.value[0] && !ins->adc_input) { cs46xx_dsp_enable_adc_capture(chip); change = 1; } else if (!ucontrol->value.integer.value[0] && ins->adc_input) { cs46xx_dsp_disable_adc_capture(chip); change = 1; } return change;}static int snd_cs46xx_pcm_capture_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; if (ins->pcm_input != NULL) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; return 0;}static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; int change = 0; if (ucontrol->value.integer.value[0] && !ins->pcm_input) { cs46xx_dsp_enable_pcm_capture(chip); change = 1; } else if (!ucontrol->value.integer.value[0] && ins->pcm_input) { cs46xx_dsp_disable_pcm_capture(chip); change = 1; } return change;}static int snd_herc_spdif_select_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int val1 = snd_cs46xx_peekBA0(chip, BA0_EGPIODR); if (val1 & EGPIODR_GPOE0) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; return 0;}/* * Game Theatre XP card - EGPIO[0] is used to select SPDIF input optical or coaxial. */ static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int val1 = snd_cs46xx_peekBA0(chip, BA0_EGPIODR); int val2 = snd_cs46xx_peekBA0(chip, BA0_EGPIOPTR); if (ucontrol->value.integer.value[0]) { /* optical is default */ snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0 | val1); /* enable EGPIO0 output */ snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIOPTR_GPPT0 | val2); /* open-drain on output */ } else { /* coaxial */ snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, val1 & ~EGPIODR_GPOE0); /* disable */ snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, val2 & ~EGPIOPTR_GPPT0); /* disable */ } /* checking diff from the EGPIO direction register should be enough */ return (val1 != (int)snd_cs46xx_peekBA0(chip, BA0_EGPIODR));}static int snd_cs46xx_spdif_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_cs46xx_spdif_default_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; down (&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff); up (&chip->spos_mutex); return 0;}static int snd_cs46xx_spdif_default_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t * chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; unsigned int val; int change; down (&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | /* left and right validity bit */ (1 << 13) | (1 << 12); change = (unsigned int)ins->spdif_csuv_default != val; ins->spdif_csuv_default = val; if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); up (&chip->spos_mutex); return change;}static int snd_cs46xx_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ucontrol->value.iec958.status[0] = 0xff; ucontrol->value.iec958.status[1] = 0xff; ucontrol->value.iec958.status[2] = 0x00; ucontrol->value.iec958.status[3] = 0xff; return 0;}static int snd_cs46xx_spdif_stream_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; down (&chip->spos_mutex); ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff); ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff); ucontrol->value.iec958.status[2] = 0; ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff); up (&chip->spos_mutex); return 0;}static int snd_cs46xx_spdif_stream_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t * chip = snd_kcontrol_chip(kcontrol); dsp_spos_instance_t * ins = chip->dsp_spos_instance; unsigned int val; int change; down (&chip->spos_mutex); val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) | ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) | /* left and right validity bit */ (1 << 13) | (1 << 12); change = ins->spdif_csuv_stream != val; ins->spdif_csuv_stream = val; if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN ) cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val); up (&chip->spos_mutex); return change;}#endif /* CONFIG_SND_CS46XX_NEW_DSP */#ifdef CONFIG_SND_CS46XX_DEBUG_GPIOstatic int snd_cs46xx_egpio_select_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 8; return 0;}static int snd_cs46xx_egpio_select_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->current_gpio; return 0;}static int snd_cs46xx_egpio_select_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int change = (chip->current_gpio != ucontrol->value.integer.value[0]); chip->current_gpio = ucontrol->value.integer.value[0]; return change;}static int snd_cs46xx_egpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?