📄 ac97_codec.c
字号:
if (extst & AC97_EA_SPDIF) { snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } } up(&ac97->reg_mutex); 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; int change; value = (ucontrol->value.integer.value[0] & mask); down(&ac97->reg_mutex); mask <<= shift; value <<= shift; old = snd_ac97_read_cache(ac97, reg); new = (old & ~mask) | value; change = old != new; if (change) { unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS); snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */ change = snd_ac97_update_bits_nolock(ac97, reg, mask, value); if (extst & AC97_EA_SPDIF) snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */ } up(&ac97->reg_mutex); return change;}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_volsw, .get = snd_ac97_get_volsw, .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; down(&ac97->page_mutex); 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); up(&ac97->page_mutex); 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); kfree(bus->pcms); if (bus->private_free) bus->private_free(bus); kfree(bus); } return 0;}static int snd_ac97_bus_dev_free(snd_device_t *device){ ac97_bus_t *bus = device->device_data; 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); kfree(ac97); } return 0;}static int snd_ac97_dev_free(snd_device_t *device){ ac97_t *ac97 = device->device_data; 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 */}static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max, unsigned char *hi_max){ unsigned short cbit[3] = { 0x20, 0x10, 0x01 }; unsigned char max[3] = { 63, 31, 15 }; int i; *lo_max = *hi_max = 0; for (i = 0 ; i < ARRAY_SIZE(cbit); i++) { unsigned short val; snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); /* Do the read twice due to buffers on some ac97 codecs. * e.g. The STAC9704 returns exactly what you wrote the the register * if you read it immediately. This causes the detect routine to fail. */ val = snd_ac97_read(ac97, reg); val = snd_ac97_read(ac97, reg); if (! *lo_max && (val & 0x7f) == cbit[i]) *lo_max = max[i]; if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i]) *hi_max = max[i]; if (*lo_max && *hi_max) break; }}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;}/* check the volume resolution of center/lfe */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 inline int printable(unsigned int x){ x &= 0xff; if (x < ' ' || x >= 0x71) { if (x <= 0x89) return x - 0x71 + 'A'; return '?'; } return x;}snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97){ snd_kcontrol_new_t template; memcpy(&template, _template, sizeof(template)); template.index = ac97->num; return snd_ctl_new1(&template, ac97);}/* * create mute switch(es) for normal stereo controls */static int snd_ac97_cmute_new_stereo(snd_card_t *card, char *name, int reg, int check_stereo, ac97_t *ac97){ snd_kcontrol_t *kctl; int err; unsigned short val, val1, mute_mask; if (! snd_ac97_valid_reg(ac97, reg)) return 0; mute_mask = 0x8000; val = snd_ac97_read(ac97, reg); if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) { /* check whether both mute bits work */ val1 = val | 0x8080; snd_ac97_write(ac97, reg, val1); if (val1 == snd_ac97_read(ac97, reg)) mute_mask = 0x8080; } if (mute_mask == 0x8080) { snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } else { snd_kcontrol_new_t tmp = AC97_SINGLE(name, reg, 15, 1, 1); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } err = snd_ctl_add(card, kctl); if (err < 0) return err; /* mute as default */ snd_ac97_write_cache(ac97, reg, val | mute_mask); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -