📄 ymfpci_main.c
字号:
static int snd_ymfpci_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item >= 4) uinfo->value.enumerated.item = 3; sprintf(uinfo->value.enumerated.name, "port 0x%x", ymfpci_joystick_ports[uinfo->value.enumerated.item]); return 0;}static int snd_ymfpci_joystick_addr_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->joystick_port; return 0;}static int snd_ymfpci_joystick_addr_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ymfpci_t *chip = snd_kcontrol_chip(kcontrol); if (ucontrol->value.integer.value[0] != chip->joystick_port) { snd_assert(ucontrol->value.integer.value[0] >= 0 && ucontrol->value.integer.value[0] < 4, return -EINVAL); chip->joystick_port = ucontrol->value.integer.value[0]; setup_joystick_base(chip); return 1; } return 0;}static snd_kcontrol_new_t snd_ymfpci_control_joystick __devinitdata = { name: "Joystick", iface: SNDRV_CTL_ELEM_IFACE_CARD, info: snd_ymfpci_joystick_info, get: snd_ymfpci_joystick_get, put: snd_ymfpci_joystick_put,};static snd_kcontrol_new_t snd_ymfpci_control_joystick_addr __devinitdata = { name: "Joystick Address", iface: SNDRV_CTL_ELEM_IFACE_CARD, info: snd_ymfpci_joystick_addr_info, get: snd_ymfpci_joystick_addr_get, put: snd_ymfpci_joystick_addr_put,};int __devinit snd_ymfpci_joystick(ymfpci_t *chip){ int err; chip->joystick_port = 0; /* default */ if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick, chip))) < 0) return err; if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick_addr, chip))) < 0) return err; return 0;}/* * proc interface */static void snd_ymfpci_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ // ymfpci_t *chip = snd_magic_cast(ymfpci_t, private_data, return); snd_iprintf(buffer, "YMFPCI\n\n");}static int __devinit snd_ymfpci_proc_init(snd_card_t * card, ymfpci_t *chip){ snd_info_entry_t *entry; entry = snd_info_create_card_entry(card, "ymfpci", card->proc_root); if (entry) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; entry->c.text.read_size = 4096; entry->c.text.read = snd_ymfpci_proc_read; if (snd_info_register(entry) < 0) { snd_info_unregister(entry); entry = NULL; } } chip->proc_entry = entry; return 0;}static int snd_ymfpci_proc_done(ymfpci_t *chip){ if (chip->proc_entry) snd_info_unregister((snd_info_entry_t *) chip->proc_entry); 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(ymfpci_t *chip){ snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000001);}static void snd_ymfpci_disable_dsp(ymfpci_t *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; }}#include "ymfpci_image.h"static void snd_ymfpci_download_image(ymfpci_t *chip){ int i; u16 ctrl; unsigned long *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 */ for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]); /* setup control instruction code */ switch (chip->device_id) { case PCI_DEVICE_ID_YAMAHA_724F: case PCI_DEVICE_ID_YAMAHA_740C: case PCI_DEVICE_ID_YAMAHA_744: case PCI_DEVICE_ID_YAMAHA_754: inst = CntrlInst1E; break; default: inst = CntrlInst; break; } 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(ymfpci_t *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 = ((playback_ctrl_size + 0x00ff) & ~0x00ff) + ((chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0x00ff) & ~0x00ff) + ((chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0x00ff) & ~0x00ff) + ((chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0x00ff) & ~0x00ff) + chip->work_size; /* work_ptr must be aligned to 256 bytes, but it's already covered with the kernel page allocation mechanism */ if ((ptr = snd_malloc_pci_pages(chip->pci, size, &ptr_addr)) == NULL) return -ENOMEM; memset(ptr, 0, size); /* for sure */ chip->work_ptr = ptr; chip->work_ptr_addr = ptr_addr; chip->work_ptr_size = size; 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 += (playback_ctrl_size + 0x00ff) & ~0x00ff; ptr_addr += (playback_ctrl_size + 0x00ff) & ~0x00ff; for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) { chip->voices[voice].number = voice; chip->voices[voice].bank = (snd_ymfpci_playback_bank_t *)ptr; chip->voices[voice].bank_addr = ptr_addr; for (bank = 0; bank < 2; bank++) { chip->bank_playback[voice][bank] = (snd_ymfpci_playback_bank_t *)ptr; ptr += chip->bank_size_playback; ptr_addr += chip->bank_size_playback; } } ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff); ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff; 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] = (snd_ymfpci_capture_bank_t *)ptr; ptr += chip->bank_size_capture; ptr_addr += chip->bank_size_capture; } ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff); ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff; 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] = (snd_ymfpci_effect_bank_t *)ptr; ptr += chip->bank_size_effect; ptr_addr += chip->bank_size_effect; } ptr = (char *)(((unsigned long)ptr + 0x00ff) & ~0x00ff); ptr_addr = (ptr_addr + 0x00ff) & ~0x00ff; chip->work_base = ptr; chip->work_base_addr = ptr_addr; snd_assert(ptr + chip->work_size == chip->work_ptr + chip->work_ptr_size, ); snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr); snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr); snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, chip->bank_base_effect_addr); snd_ymfpci_writel(chip, YDSXGR_WORKBASE, chip->work_base_addr); snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, chip->work_size >> 2); /* S/PDIF output initialization */ chip->spdif_bits = chip->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF & 0xffff; snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 0); snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); /* S/PDIF input initialization */ snd_ymfpci_writew(chip, YDSXGR_SPDIFINCTRL, 0); /* digital mixer setup */ for (reg = 0x80; reg < 0xc0; reg += 4) snd_ymfpci_writel(chip, reg, 0); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACINVOL, 0x3fff3fff); snd_ymfpci_writel(chip, YDSXGR_PRIADCLOOPVOL, 0x3fff3fff); return 0;}static int snd_ymfpci_free(ymfpci_t *chip){ u16 ctrl; snd_assert(chip != NULL, return -EINVAL); snd_ymfpci_proc_done(chip); if (chip->res_reg_area) { /* don't touch busy hardware */ snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_STATUS, ~0); snd_ymfpci_disable_dsp(chip); snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0); snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0); snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0); snd_ymfpci_writel(chip, YDSXGR_WORKBASE, 0); snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, 0); ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); } /* Set PCI device to D3 state */ // pci_set_power_state(chip->pci, 3);#ifdef CONFIG_PM if (chip->saved_regs) kfree(chip->saved_regs);#endif if (chip->reg_area_virt) iounmap((void *)chip->reg_area_virt); if (chip->work_ptr) snd_free_pci_pages(chip->pci, chip->work_ptr_size, chip->work_ptr, chip->work_ptr_addr); if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); if (chip->res_reg_area) { release_resource(chip->res_reg_area); kfree_nocheck(chip->res_reg_area); } pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); snd_magic_kfree(chip); return 0;}static int snd_ymfpci_dev_free(snd_device_t *device){ ymfpci_t *chip = snd_magic_cast(ymfpci_t, device->device_data, return -ENXIO); return snd_ymfpci_free(chip);}#ifdef CONFIG_PMstatic int saved_regs_index[] = { /* spdif */ YDSXGR_SPDIFOUTCTRL, YDSXGR_SPDIFOUTSTATUS, YDSXGR_SPDIFINCTRL, /* volumes */ YDSXGR_PRIADCLOOPVOL, YDSXGR_NATIVEDACINVOL, YDSXGR_NATIVEDACOUTVOL, // YDSXGR_BUF441OUTVOL, YDSXGR_NATIVEADCINVOL, YDSXGR_SPDIFLOOPVOL, YDSXGR_SPDIFOUTVOL, YDSXGR_ZVOUTVOL, /* address bases */ YDSXGR_PLAYCTRLBASE, YDSXGR_RECCTRLBASE, YDSXGR_EFFCTRLBASE, YDSXGR_WORKBASE, /* capture set up */ YDSXGR_MAPOFREC, YDSXGR_RECFORMAT, YDSXGR_RECSLOTSR, YDSXGR_ADCFORMAT, YDSXGR_ADCSLOTSR,};#define YDSXGR_NUM_SAVED_REGS (sizeof(saved_regs_index)/sizeof(saved_regs_index[0]))void snd_ymfpci_suspend(ymfpci_t *chip){ snd_card_t *card = chip->card; int i; snd_power_lock(card); if (card->power_state == SNDRV_CTL_POWER_D3hot) goto __skip; snd_pcm_suspend_all(chip->pcm); snd_pcm_suspend_all(chip->pcm2); snd_pcm_suspend_all(chip->pcm_spdif); snd_pcm_suspend_all(chip->pcm_4ch); for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_disable_dsp(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); __skip: snd_power_unlock(card);}void snd_ymfpci_resume(ymfpci_t *chip){ snd_card_t *card = chip->card; int i; snd_power_lock(card); if (card->power_state == SNDRV_CTL_POWER_D0) goto __skip; pci_enable_device(chip->pci); pci_set_master(chip->pci); snd_ymfpci_aclink_reset(chip->pci); snd_ymfpci_codec_ready(chip, 0, 0); snd_ymfpci_download_image(chip); udelay(100); for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) snd_ymfpci_writel(chip, saved_regs_index[i], chip->saved_regs[i]); snd_ac97_resume(chip->ac97); /* start hw again */ if (chip->start_count > 0) { spin_lock(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode); chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT); spin_unlock(&chip->reg_lock); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); __skip: snd_power_unlock(card);}static int snd_ymfpci_set_power_state(snd_card_t *card, unsigned int power_state){ ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->power_state_private_data, return -ENXIO); switch (power_state) { case SNDRV_CTL_POWER_D0: case SNDRV_CTL_POWER_D1: case SNDRV_CTL_POWER_D2: snd_ymfpci_resume(chip); break; case SNDRV_CTL_POWER_D3hot: case SNDRV_CTL_POWER_D3cold: snd_ymfpci_suspend(chip); break; default: return -EINVAL; } return 0;}#endif /* CONFIG_PM */int __devinit snd_ymfpci_create(snd_card_t * card, struct pci_dev * pci, unsigned short old_legacy_ctrl, ymfpci_t ** rchip){ ymfpci_t *chip; int err; static snd_device_ops_t ops = { dev_free: snd_ymfpci_dev_free, }; *rchip = NULL; /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; chip = snd_magic_kcalloc(ymfpci_t, 0, GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->old_legacy_ctrl = old_legacy_ctrl; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->voice_lock); init_waitqueue_head(&chip->interrupt_sleep); atomic_set(&chip->interrupt_sleep_count, 0); chip->card = card; chip->pci = pci; chip->irq = -1; chip->device_id = pci->device; pci_read_config_byte(pci, PCI_REVISION_ID, (u8 *)&chip->rev); chip->reg_area_phys = pci_resource_start(pci, 0); chip->reg_area_virt = (unsigned long)ioremap_nocache(chip->reg_area_phys, 0x8000); pci_set_master(pci); if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { snd_ymfpci_free(chip); snd_printk("unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); return -EBUSY; } if (request_irq(pci->irq, snd_ymfpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "YMFPCI", (void *) chip)) { snd_ymfpci_free(chip); snd_printk("unable to grab IRQ %d\n", pci->irq); return -EBUSY; } chip->irq = pci->irq; snd_ymfpci_aclink_reset(pci); if (snd_ymfpci_codec_ready(chip, 0, 1) < 0) { snd_ymfpci_free(chip); return -EIO; } snd_ymfpci_download_image(chip); udelay(100); /* seems we need a delay after downloading image.. */ if (snd_ymfpci_memalloc(chip) < 0) { snd_ymfpci_free(chip); return -EIO; }#ifdef CONFIG_PM chip->saved_regs = kmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32), GFP_KERNEL); if (chip->saved_regs == NULL) { snd_ymfpci_free(chip); return -ENOMEM; } card->set_power_state = snd_ymfpci_set_power_state; card->power_state_private_data = chip;#endif snd_ymfpci_proc_init(card, chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_ymfpci_free(chip); return err; } *rchip = chip; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -