📄 ymfpci_main.c
字号:
.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(struct snd_ac97_bus *bus){ struct snd_ymfpci *chip = bus->private_data; chip->ac97_bus = NULL;}static void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97){ struct snd_ymfpci *chip = ac97->private_data; chip->ac97 = NULL;}int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch){ struct snd_ac97_template ac97; struct snd_kcontrol *kctl; struct snd_pcm_substream *substream; unsigned int idx; int err; static struct snd_ac97_bus_ops 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) { if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip))) < 0) return err; } /* per-voice volume */ substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; for (idx = 0; idx < 32; ++idx) { kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip); if (!kctl) return -ENOMEM; kctl->id.device = chip->pcm->device; kctl->id.subdevice = idx; kctl->private_value = (unsigned long)substream; if ((err = snd_ctl_add(chip->card, kctl)) < 0) return err; chip->pcm_mixer[idx].left = 0x8000; chip->pcm_mixer[idx].right = 0x8000; chip->pcm_mixer[idx].ctl = kctl; substream = substream->next; } return 0;}/* * timer */static int snd_ymfpci_timer_start(struct snd_timer *timer){ struct snd_ymfpci *chip; unsigned long flags; unsigned int count; chip = snd_timer_chip(timer); count = (timer->sticks << 1) - 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_ymfpci_timer_stop(struct snd_timer *timer){ struct snd_ymfpci *chip; unsigned long flags; chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00); spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_ymfpci_timer_precise_resolution(struct snd_timer *timer, unsigned long *num, unsigned long *den){ *num = 1; *den = 48000; return 0;}static struct snd_timer_hardware snd_ymfpci_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, .resolution = 20833, /* 1/fs = 20.8333...us */ .ticks = 0x8000, .start = snd_ymfpci_timer_start, .stop = snd_ymfpci_timer_stop, .precise_resolution = snd_ymfpci_timer_precise_resolution,};int __devinit snd_ymfpci_timer(struct snd_ymfpci *chip, int device){ struct snd_timer *timer = NULL; struct snd_timer_id tid; int err; tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = chip->card->number; tid.device = device; tid.subdevice = 0; if ((err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer)) >= 0) { strcpy(timer->name, "YMFPCI timer"); timer->private_data = chip; timer->hw = snd_ymfpci_timer_hw; } chip->timer = timer; return err;}/* * proc interface */static void snd_ymfpci_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct snd_ymfpci *chip = entry->private_data; int i; snd_iprintf(buffer, "YMFPCI\n\n"); for (i = 0; i <= YDSXGR_WORKBASE; i += 4) snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i));}static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip){ struct snd_info_entry *entry; if (! snd_card_proc_new(card, "ymfpci", &entry)) snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); return 0;}/* * initialization routines */static void snd_ymfpci_aclink_reset(struct pci_dev * pci){ u8 cmd; pci_read_config_byte(pci, PCIR_DSXG_CTRL, &cmd);#if 0 // force to reset if (cmd & 0x03) {#endif pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc); pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd | 0x03); pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc); pci_write_config_word(pci, PCIR_DSXG_PWRCTRL1, 0); pci_write_config_word(pci, PCIR_DSXG_PWRCTRL2, 0);#if 0 }#endif}static void snd_ymfpci_enable_dsp(struct snd_ymfpci *chip){ snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000001);}static void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip){ u32 val; int timeout = 1000; val = snd_ymfpci_readl(chip, YDSXGR_CONFIG); if (val) snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000000); while (timeout-- > 0) { val = snd_ymfpci_readl(chip, YDSXGR_STATUS); if ((val & 0x00000002) == 0) break; }}#ifdef CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL#include "ymfpci_image.h"static struct firmware snd_ymfpci_dsp_microcode = { .size = YDSXG_DSPLENGTH, .data = (u8 *)DspInst,};static struct firmware snd_ymfpci_controller_microcode = { .size = YDSXG_CTRLLENGTH, .data = (u8 *)CntrlInst,};static struct firmware snd_ymfpci_controller_1e_microcode = { .size = YDSXG_CTRLLENGTH, .data = (u8 *)CntrlInst1E,};#endif#ifdef CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNELstatic int snd_ymfpci_request_firmware(struct snd_ymfpci *chip){ chip->dsp_microcode = &snd_ymfpci_dsp_microcode; if (chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || chip->device_id == PCI_DEVICE_ID_YAMAHA_754) chip->controller_microcode = &snd_ymfpci_controller_1e_microcode; else chip->controller_microcode = &snd_ymfpci_controller_microcode; return 0;}#else /* use fw_loader */#ifdef __LITTLE_ENDIANstatic inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }#elsestatic void snd_ymfpci_convert_from_le(const struct firmware *fw){ int i; u32 *data = (u32 *)fw->data; for (i = 0; i < fw->size / 4; ++i) le32_to_cpus(&data[i]);}#endifstatic int snd_ymfpci_request_firmware(struct snd_ymfpci *chip){ int err, is_1e; const char *name; err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw", &chip->pci->dev); if (err >= 0) { if (chip->dsp_microcode->size == YDSXG_DSPLENGTH) snd_ymfpci_convert_from_le(chip->dsp_microcode); else { snd_printk(KERN_ERR "DSP microcode has wrong size\n"); err = -EINVAL; } } if (err < 0) return err; is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || chip->device_id == PCI_DEVICE_ID_YAMAHA_754; name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw"; err = request_firmware(&chip->controller_microcode, name, &chip->pci->dev); if (err >= 0) { if (chip->controller_microcode->size == YDSXG_CTRLLENGTH) snd_ymfpci_convert_from_le(chip->controller_microcode); else { snd_printk(KERN_ERR "controller microcode" " has wrong size\n"); err = -EINVAL; } } if (err < 0) return err; return 0;}MODULE_FIRMWARE("yamaha/ds1_dsp.fw");MODULE_FIRMWARE("yamaha/ds1_ctrl.fw");MODULE_FIRMWARE("yamaha/ds1e_ctrl.fw");#endifstatic void snd_ymfpci_download_image(struct snd_ymfpci *chip){ int i; u16 ctrl; u32 *inst; snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); snd_ymfpci_disable_dsp(chip); snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00010000); snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00000000); snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, 0x00000000); snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 0x00000000); snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0x00000000); snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0x00000000); snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0x00000000); ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); /* setup DSP instruction code */ inst = (u32 *)chip->dsp_microcode->data; for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]); /* setup control instruction code */ inst = (u32 *)chip->controller_microcode->data; for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]); snd_ymfpci_enable_dsp(chip);}static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip){ long size, playback_ctrl_size; int voice, bank, reg; u8 *ptr; dma_addr_t ptr_addr; playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES; chip->bank_size_playback = snd_ymfpci_readl(chip, YDSXGR_PLAYCTRLSIZE) << 2; chip->bank_size_capture = snd_ymfpci_readl(chip, YDSXGR_RECCTRLSIZE) << 2; chip->bank_size_effect = snd_ymfpci_readl(chip, YDSXGR_EFFCTRLSIZE) << 2; chip->work_size = YDSXG_DEFAULT_WORK_SIZE; size = ALIGN(playback_ctrl_size, 0x100) + ALIGN(chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES, 0x100) + ALIGN(chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES, 0x100) + ALIGN(chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES, 0x100) + chip->work_size; /* work_ptr must be aligned to 256 bytes, but it's already covered with the kernel page allocation mechanism */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), size, &chip->work_ptr) < 0) return -ENOMEM; ptr = chip->work_ptr.area; ptr_addr = chip->work_ptr.addr; memset(ptr, 0, size); /* for sure */ chip->bank_base_playback = ptr; chip->bank_base_playback_addr = ptr_addr; chip->ctrl_playback = (u32 *)ptr; chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES); ptr += ALIGN(playback_ctrl_size, 0x100); ptr_addr += ALIGN(playback_ctrl_size, 0x100); for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) { chip->voices[voice].number = voice; chip->voices[voice].bank = (struct snd_ymfpci_playback_bank *)ptr; chip->voices[voice].bank_addr = ptr_addr; for (bank = 0; bank < 2; bank++) { chip->bank_playback[voice][bank] = (struct snd_ymfpci_playback_bank *)ptr; ptr += chip->bank_size_playback; ptr_addr += chip->bank_size_playback; } } ptr = (char *)ALIGN((unsigned long)ptr, 0x100); ptr_addr = ALIGN(ptr_addr, 0x100); chip->bank_base_capture = ptr; chip->bank_base_capture_addr = ptr_addr; for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++) for (bank = 0; bank < 2; bank++) { chip->bank_capture[voice][bank] = (struct snd_ymfpci_capture_bank *)ptr; ptr += chip->bank_size_capture; ptr_addr += chip->bank_size_capture; } ptr = (char *)ALIGN((unsigned long)ptr, 0x100); ptr_addr = ALIGN(ptr_addr, 0x100); chip->bank_base_effect = ptr; chip->bank_base_effect_addr = ptr_addr; for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++) for (bank = 0; bank < 2; bank++) { chip->bank_effect[voice][bank] = (struct snd_ymfpci_effect_bank *)ptr; ptr += chip->bank_size_effect; ptr_addr += chip->bank_size_effect; } ptr = (char *)ALIGN((unsigned long)ptr, 0x100); ptr_addr = ALIGN(ptr_addr, 0x100); chip->work_base = ptr; chip->work_base_addr = ptr_addr; snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, ); snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -