ac97_codec.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,915 行 · 第 1/5 页
C
1,915 行
case IEC958_AES0_PRO_FS_44100: val |= 0<<12; break; case IEC958_AES0_PRO_FS_48000: val |= 2<<12; break; case IEC958_AES0_PRO_FS_32000: val |= 3<<12; break; default: val |= 1<<12; break; } if ((new & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015) val |= 1<<3; } else { new |= ucontrol->value.iec958.status[0] & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT); new |= ((ucontrol->value.iec958.status[1] & (IEC958_AES1_CON_CATEGORY|IEC958_AES1_CON_ORIGINAL)) << 8); new |= ((ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) << 24); if ((new & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015) val |= 1<<3; if (!(new & IEC958_AES0_CON_NOT_COPYRIGHT)) val |= 1<<2; val |= ((new >> 8) & 0xff) << 4; // category + original switch ((new >> 24) & 0xff) { case IEC958_AES3_CON_FS_44100: val |= 0<<12; break; case IEC958_AES3_CON_FS_48000: val |= 2<<12; break; case IEC958_AES3_CON_FS_32000: val |= 3<<12; break; default: val |= 1<<12; break; } } change = ac97->spdif_status != new; ac97->spdif_status = new; spin_unlock(&ac97->reg_lock); if (ac97->flags & AC97_CS_SPDIF) { int x = (val >> 12) & 0x03; switch (x) { case 0: x = 1; break; // 44.1 case 2: x = 0; break; // 48.0 default: x = 0; break; // illegal. } change |= snd_ac97_update_bits(ac97, AC97_CSR_SPDIF, 0x3fff, ((val & 0xcfff) | (x << 12))); } else if (ac97->flags & AC97_CX_SPDIF) { int v; v = new & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT) ? 0 : AC97_CXR_COPYRGT; v |= new & IEC958_AES0_NONAUDIO ? AC97_CXR_SPDIF_AC3 : AC97_CXR_SPDIF_PCM; change |= snd_ac97_update_bits(ac97, AC97_CXR_AUDIO_MISC, AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT, v); } else { unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS); snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */ change |= snd_ac97_update_bits(ac97, AC97_SPDIF, 0x3fff, val); if (extst & AC97_EA_SPDIF) { snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } } return change;}static int snd_ac97_put_spsa(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; // int invert = (kcontrol->private_value >> 24) & 0xff; unsigned short value, old, new; value = (ucontrol->value.integer.value[0] & mask); mask <<= shift; value <<= shift; spin_lock(&ac97->reg_lock); old = snd_ac97_read_cache(ac97, reg); new = (old & ~mask) | value; spin_unlock(&ac97->reg_lock); if (old != new) { int change; unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS); snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */ change = snd_ac97_update_bits(ac97, reg, mask, value); if (extst & AC97_EA_SPDIF) snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ return change; } return 0;}const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), .info = snd_ac97_spdif_mask_info, .get = snd_ac97_spdif_cmask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), .info = snd_ac97_spdif_mask_info, .get = snd_ac97_spdif_pmask_get, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = snd_ac97_spdif_mask_info, .get = snd_ac97_spdif_default_get, .put = snd_ac97_spdif_default_put, }, AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),AC97_EXTENDED_STATUS, 2, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", .info = snd_ac97_info_single, .get = snd_ac97_get_single, .put = snd_ac97_put_spsa, .private_value = AC97_SINGLE_VALUE(AC97_EXTENDED_STATUS, 4, 3, 0) },};#define AD18XX_PCM_BITS(xname, codec, lshift, rshift, mask) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \ .get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \ .private_value = (codec) | ((lshift) << 8) | ((rshift) << 12) | ((mask) << 16) }static int snd_ac97_ad18xx_pcm_info_bits(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int mask = (kcontrol->private_value >> 16) & 0x0f; int lshift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES)) uinfo->count = 2; else uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_ac97_ad18xx_pcm_get_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; int lshift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; ucontrol->value.integer.value[0] = mask - ((ac97->spec.ad18xx.pcmreg[codec] >> lshift) & mask); if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES)) ucontrol->value.integer.value[1] = mask - ((ac97->spec.ad18xx.pcmreg[codec] >> rshift) & mask); return 0;}static int snd_ac97_ad18xx_pcm_put_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; int lshift = (kcontrol->private_value >> 8) & 0x0f; int rshift = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; unsigned short val, valmask; val = (mask - (ucontrol->value.integer.value[0] & mask)) << lshift; valmask = mask << lshift; if (lshift != rshift && (ac97->flags & AC97_STEREO_MUTES)) { val |= (mask - (ucontrol->value.integer.value[1] & mask)) << rshift; valmask |= mask << rshift; } return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, valmask, val);}#define AD18XX_PCM_VOLUME(xname, codec) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_volume, \ .get = snd_ac97_ad18xx_pcm_get_volume, .put = snd_ac97_ad18xx_pcm_put_volume, \ .private_value = codec }static int snd_ac97_ad18xx_pcm_info_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 = 31; return 0;}static int snd_ac97_ad18xx_pcm_get_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; spin_lock(&ac97->reg_lock); ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); spin_unlock(&ac97->reg_lock); return 0;}static int snd_ac97_ad18xx_pcm_put_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; unsigned short val1, val2; val1 = 31 - (ucontrol->value.integer.value[0] & 31); val2 = 31 - (ucontrol->value.integer.value[1] & 31); return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, 0x1f1f, (val1 << 8) | val2);}static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_pcm[2] = {AD18XX_PCM_BITS("PCM Playback Switch", 0, 15, 7, 1),AD18XX_PCM_VOLUME("PCM Playback Volume", 0)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_surround[2] = {AD18XX_PCM_BITS("Surround Playback Switch", 1, 15, 7, 1),AD18XX_PCM_VOLUME("Surround Playback Volume", 1)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_center[2] = {AD18XX_PCM_BITS("Center Playback Switch", 2, 15, 15, 1),AD18XX_PCM_BITS("Center Playback Volume", 2, 8, 8, 31)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_lfe[2] = {AD18XX_PCM_BITS("LFE Playback Switch", 2, 7, 7, 1),AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 0, 31)};/* * */static void snd_ac97_powerdown(ac97_t *ac97);static int snd_ac97_bus_free(ac97_bus_t *bus){ if (bus) { snd_ac97_bus_proc_done(bus); if (bus->pcms) kfree(bus->pcms); if (bus->private_free) bus->private_free(bus); snd_magic_kfree(bus); } return 0;}static int snd_ac97_bus_dev_free(snd_device_t *device){ ac97_bus_t *bus = snd_magic_cast(ac97_bus_t, device->device_data, return -ENXIO); return snd_ac97_bus_free(bus);}static int snd_ac97_free(ac97_t *ac97){ if (ac97) { snd_ac97_proc_done(ac97); if (ac97->bus) ac97->bus->codec[ac97->num] = NULL; if (ac97->private_free) ac97->private_free(ac97); snd_magic_kfree(ac97); } return 0;}static int snd_ac97_dev_free(snd_device_t *device){ ac97_t *ac97 = snd_magic_cast(ac97_t, device->device_data, return -ENXIO); snd_ac97_powerdown(ac97); /* for avoiding click noises during shut down */ return snd_ac97_free(ac97);}static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg){ unsigned short val, mask = 0x8000; if (! snd_ac97_valid_reg(ac97, reg)) return 0; switch (reg) { case AC97_MASTER_TONE: return ac97->caps & 0x04 ? 1 : 0; case AC97_HEADPHONE: return ac97->caps & 0x10 ? 1 : 0; case AC97_REC_GAIN_MIC: return ac97->caps & 0x01 ? 1 : 0; case AC97_3D_CONTROL: if (ac97->caps & 0x7c00) { val = snd_ac97_read(ac97, reg); /* if nonzero - fixed and we can't set it */ return val == 0; } return 0; case AC97_CENTER_LFE_MASTER: /* center */ if ((ac97->ext_id & AC97_EI_CDAC) == 0) return 0; break; case AC97_CENTER_LFE_MASTER+1: /* lfe */ if ((ac97->ext_id & AC97_EI_LDAC) == 0) return 0; reg = AC97_CENTER_LFE_MASTER; mask = 0x0080; break; case AC97_SURROUND_MASTER: if ((ac97->ext_id & AC97_EI_SDAC) == 0) return 0; break; } if (ac97->limited_regs && test_bit(reg, ac97->reg_accessed)) return 1; /* allow without check */ val = snd_ac97_read(ac97, reg); if (!(val & mask)) { /* nothing seems to be here - mute flag is not set */ /* try another test */ snd_ac97_write_cache(ac97, reg, val | mask); val = snd_ac97_read(ac97, reg); if (!(val & mask)) return 0; /* nothing here */ } return 1; /* success, useable */}int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit){ unsigned short mask, val, orig, res; mask = 1 << bit; orig = snd_ac97_read(ac97, reg); val = orig ^ mask; snd_ac97_write(ac97, reg, val); res = snd_ac97_read(ac97, reg); snd_ac97_write_cache(ac97, reg, orig); return res == val;}static void snd_ac97_change_volume_params1(ac97_t * ac97, int reg, unsigned char *max){ unsigned short val, val1; *max = 63; val = 0x8000 | 0x0020; snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 31; } /* reset volume to zero */ snd_ac97_write_cache(ac97, reg, 0x8000);}static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max){ unsigned short val, val1; *max = 63; val = 0x8080 | (0x20 << shift); snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 31; } /* reset volume to zero */ snd_ac97_write_cache(ac97, reg, 0x8080);}static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char *max){ unsigned short val, val1; *max = 31; val = 0x8000 | 0x0010; snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 15; } /* reset volume to zero */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?