📄 ymfpci_main.c
字号:
.put = snd_ymfpci_spdif_stream_put};static int snd_ymfpci_drec_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info){ static char *texts[3] = {"AC'97", "IEC958", "ZV Port"}; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; info->value.enumerated.items = 3; if (info->value.enumerated.item > 2) info->value.enumerated.item = 2; strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); return 0;}static int snd_ymfpci_drec_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); u16 reg; spin_lock_irq(&chip->reg_lock); reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); spin_unlock_irq(&chip->reg_lock); if (!(reg & 0x100)) value->value.enumerated.item[0] = 0; else value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0); return 0;}static int snd_ymfpci_drec_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); u16 reg, old_reg; spin_lock_irq(&chip->reg_lock); old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); if (value->value.enumerated.item[0] == 0) reg = old_reg & ~0x100; else reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9); snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg); spin_unlock_irq(&chip->reg_lock); return reg != old_reg;}static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Direct Recording Source", .info = snd_ymfpci_drec_source_info, .get = snd_ymfpci_drec_source_get, .put = snd_ymfpci_drec_source_put};/* * Mixer controls */#define YMFPCI_SINGLE(xname, xindex, reg, shift) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_ymfpci_info_single, \ .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \ .private_value = ((reg) | ((shift) << 16)) }static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ int reg = kcontrol->private_value & 0xffff; switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } 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_ymfpci_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xffff; unsigned int shift = (kcontrol->private_value >> 16) & 0xff; unsigned int mask = 1; switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; return 0;}static int snd_ymfpci_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xffff; unsigned int shift = (kcontrol->private_value >> 16) & 0xff; unsigned int mask = 1; int change; unsigned int val, oval; switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } val = (ucontrol->value.integer.value[0] & mask); val <<= shift; spin_lock_irq(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); val = (oval & ~(mask << shift)) | val; change = val != oval; snd_ymfpci_writel(chip, reg, val); spin_unlock_irq(&chip->reg_lock); return change;}#define YMFPCI_DOUBLE(xname, xindex, reg) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_ymfpci_info_double, \ .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ .private_value = reg }static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ unsigned int reg = kcontrol->private_value; if (reg < 0x80 || reg >= 0xc0) return -EINVAL; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 16383; return 0;}static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; unsigned int shift_left = 0, shift_right = 16, mask = 16383; unsigned int val; if (reg < 0x80 || reg >= 0xc0) return -EINVAL; spin_lock_irq(&chip->reg_lock); val = snd_ymfpci_readl(chip, reg); spin_unlock_irq(&chip->reg_lock); ucontrol->value.integer.value[0] = (val >> shift_left) & mask; ucontrol->value.integer.value[1] = (val >> shift_right) & mask; return 0;}static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; unsigned int shift_left = 0, shift_right = 16, mask = 16383; int change; unsigned int val1, val2, oval; if (reg < 0x80 || reg >= 0xc0) return -EINVAL; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; val1 <<= shift_left; val2 <<= shift_right; spin_lock_irq(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; change = val1 != oval; snd_ymfpci_writel(chip, reg, val1); spin_unlock_irq(&chip->reg_lock); return change;}/* * 4ch duplication */static int snd_ymfpci_info_dup4ch(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_ymfpci_get_dup4ch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->mode_dup4ch; return 0;}static int snd_ymfpci_put_dup4ch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int change; change = (ucontrol->value.integer.value[0] != chip->mode_dup4ch); if (change) chip->mode_dup4ch = !!ucontrol->value.integer.value[0]; return change;}static snd_kcontrol_new_t snd_ymfpci_controls[] __devinitdata = {YMFPCI_DOUBLE("Wave Playback Volume", 0, YDSXGR_NATIVEDACOUTVOL),YMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL),YMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL),YMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL),YMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL),YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),YMFPCI_DOUBLE("FM Legacy Volume", 0, YDSXGR_LEGACYOUTVOL),YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL),YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0),YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0),YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "4ch Duplication", .info = snd_ymfpci_info_dup4ch, .get = snd_ymfpci_get_dup4ch, .put = snd_ymfpci_put_dup4ch,},};/* * GPIO */static int snd_ymfpci_get_gpio_out(ymfpci_t *chip, int pin){ u16 reg, mode; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); reg &= ~(1 << (pin + 8)); reg |= (1 << pin); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg); /* set the level mode for input line */ mode = snd_ymfpci_readw(chip, YDSXGR_GPIOTYPECONFIG); mode &= ~(3 << (pin * 2)); snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS); spin_unlock_irqrestore(&chip->reg_lock, flags); return (mode >> pin) & 1;}static int snd_ymfpci_set_gpio_out(ymfpci_t *chip, int pin, int enable){ u16 reg; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); reg &= ~(1 << pin); reg &= ~(1 << (pin + 8)); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg); snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin); snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_ymfpci_gpio_sw_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_ymfpci_gpio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int pin = (int)kcontrol->private_value; ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin); return 0;}static int snd_ymfpci_gpio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int pin = (int)kcontrol->private_value; if (snd_ymfpci_get_gpio_out(chip, pin) != ucontrol->value.integer.value[0]) { snd_ymfpci_set_gpio_out(chip, pin, !!ucontrol->value.integer.value[0]); ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin); return 1; } return 0;}static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = { .name = "Shared Rear/Line-In Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_ymfpci_gpio_sw_info, .get = snd_ymfpci_gpio_sw_get, .put = snd_ymfpci_gpio_sw_put, .private_value = 2,};/* * PCM voice volume */static int snd_ymfpci_pcm_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 = 0x8000; return 0;}static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int subs = kcontrol->id.subdevice; ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left; ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right; return 0;}static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int subs = kcontrol->id.subdevice; snd_pcm_substream_t *substream; unsigned long flags; if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left || ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; substream = (snd_pcm_substream_t *)kcontrol->private_value; spin_lock_irqsave(&chip->voice_lock, flags); if (substream->runtime && substream->runtime->private_data) { ymfpci_pcm_t *ypcm = substream->runtime->private_data; ypcm->update_pcm_vol = 2; } spin_unlock_irqrestore(&chip->voice_lock, flags); return 1; } return 0;}static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .info = snd_ymfpci_pcm_vol_info, .get = snd_ymfpci_pcm_vol_get, .put = snd_ymfpci_pcm_vol_put,};/* * Mixer routines */static void snd_ymfpci_mixer_free_ac97_bus(ac97_bus_t *bus){ ymfpci_t *chip = bus->private_data; chip->ac97_bus = NULL;}static void snd_ymfpci_mixer_free_ac97(ac97_t *ac97){ ymfpci_t *chip = ac97->private_data; chip->ac97 = NULL;}int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch){ ac97_template_t ac97; snd_kcontrol_t *kctl; snd_pcm_substream_t *substream; unsigned int idx; int err; static ac97_bus_ops_t ops = { .write = snd_ymfpci_codec_write, .read = snd_ymfpci_codec_read, }; if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) return err; chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus; chip->ac97_bus->no_vra = 1; /* YMFPCI doesn't need VRA */ memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_ymfpci_mixer_free_ac97; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; /* to be sure */ snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS, AC97_EA_VRA|AC97_EA_VRM, 0); for (idx = 0; idx < ARRAY_SIZE(snd_ymfpci_controls); idx++) { if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip))) < 0) return err; } /* add S/PDIF control */ snd_assert(chip->pcm_spdif != NULL, return -EIO); if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip))) < 0) return err; kctl->id.device = chip->pcm_spdif->device; if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip))) < 0) return err; kctl->id.device = chip->pcm_spdif->device; if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip))) < 0) return err; kctl->id.device = chip->pcm_spdif->device; chip->spdif_pcm_ctl = kctl; /* direct recording source */ if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && (err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip))) < 0) return err; /* * shared rear/line-in */ if (rear_switch) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -