📄 ymfpci_main.c
字号:
bank->eff3_gain = bank->eff3_gain_end = cpu_to_le32(0x40000000); } else { bank->format |= cpu_to_le32(1); bank->eff2_gain = bank->eff2_gain_end = cpu_to_le32(0x40000000); } } } }}static int snd_ymfpci_ac3_init(ymfpci_t *chip){ unsigned char *ptr; dma_addr_t ptr_addr; if (chip->ac3_tmp_base != NULL) return -EBUSY; if ((ptr = snd_malloc_pci_pages(chip->pci, 4096, &ptr_addr)) == NULL) return -ENOMEM; chip->ac3_tmp_base = ptr; chip->ac3_tmp_base_addr = ptr_addr; chip->bank_effect[3][0]->base = chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr); chip->bank_effect[3][0]->loop_end = chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024); chip->bank_effect[4][0]->base = chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr + 2048); chip->bank_effect[4][0]->loop_end = chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024); spin_lock_irq(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3); spin_unlock_irq(&chip->reg_lock); return 0;}static int snd_ymfpci_ac3_done(ymfpci_t *chip){ spin_lock_irq(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3)); spin_unlock_irq(&chip->reg_lock); snd_ymfpci_irq_wait(chip); if (chip->ac3_tmp_base) { snd_free_pci_pages(chip->pci, 4096, chip->ac3_tmp_base, chip->ac3_tmp_base_addr); chip->ac3_tmp_base = NULL; } return 0;}static int snd_ymfpci_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; if ((err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params))) < 0) return err; if (ypcm->spdif || ypcm->mode4ch) if ((err = snd_ymfpci_ac3_init(chip)) < 0) return err; return 0;}static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; if (runtime->private_data == NULL) return 0; ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); /* wait, until the PCI operations are not finished */ snd_ymfpci_irq_wait(chip); snd_pcm_lib_free_pages(substream); if (ypcm->voices[1]) { snd_ymfpci_voice_free(chip, ypcm->voices[1]); ypcm->voices[1] = NULL; } if (ypcm->voices[0]) { snd_ymfpci_voice_free(chip, ypcm->voices[0]); ypcm->voices[0] = NULL; } if (ypcm->spdif || ypcm->mode4ch) snd_ymfpci_ac3_done(chip); return 0;}static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream){ // ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); int nvoice; ypcm->period_size = runtime->period_size; ypcm->buffer_size = runtime->buffer_size; ypcm->period_pos = 0; ypcm->last_pos = 0; for (nvoice = 0; nvoice < runtime->channels; nvoice++) snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice], runtime->channels == 2, runtime->rate, snd_pcm_format_width(runtime->format) == 16, runtime->dma_addr, ypcm->buffer_size, ypcm->spdif || ypcm->mode4ch); return 0;}static int snd_ymfpci_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ymfpci_capture_hw_free(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); /* wait, until the PCI operations are not finished */ snd_ymfpci_irq_wait(chip); return snd_pcm_lib_free_pages(substream);}static int snd_ymfpci_capture_prepare(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); snd_ymfpci_capture_bank_t * bank; int nbank; u32 rate, format; ypcm->period_size = runtime->period_size; ypcm->buffer_size = runtime->buffer_size; ypcm->period_pos = 0; ypcm->last_pos = 0; ypcm->shift = 0; rate = ((48000 * 4096) / runtime->rate) - 1; format = 0; if (runtime->channels == 2) { format |= 2; ypcm->shift++; } if (snd_pcm_format_width(runtime->format) == 8) format |= 1; else ypcm->shift++; switch (ypcm->capture_bank_number) { case 0: snd_ymfpci_writel(chip, YDSXGR_RECFORMAT, format); snd_ymfpci_writel(chip, YDSXGR_RECSLOTSR, rate); break; case 1: snd_ymfpci_writel(chip, YDSXGR_ADCFORMAT, format); snd_ymfpci_writel(chip, YDSXGR_ADCSLOTSR, rate); break; } for (nbank = 0; nbank < 2; nbank++) { bank = chip->bank_capture[ypcm->capture_bank_number][nbank]; bank->base = cpu_to_le32(runtime->dma_addr); bank->loop_end = cpu_to_le32(ypcm->buffer_size << ypcm->shift); bank->start = 0; bank->num_of_loops = 0; } return 0;}static snd_pcm_uframes_t snd_ymfpci_playback_pointer(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); ymfpci_voice_t *voice = ypcm->voices[0]; if (!(ypcm->running && voice)) return 0; return le32_to_cpu(voice->bank[chip->active_bank].start);}static snd_pcm_uframes_t snd_ymfpci_capture_pointer(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); if (!ypcm->running) return 0; return le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift;}static void snd_ymfpci_irq_wait(ymfpci_t *chip){ wait_queue_t wait; int loops = 4; while (loops-- > 0) { if ((snd_ymfpci_readl(chip, YDSXGR_MODE) & 3) == 0) continue; init_waitqueue_entry(&wait, current); add_wait_queue(&chip->interrupt_sleep, &wait); atomic_inc(&chip->interrupt_sleep_count); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); remove_wait_queue(&chip->interrupt_sleep, &wait); }}static void snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs){ ymfpci_t *chip = snd_magic_cast(ymfpci_t, dev_id, return); u32 status, nvoice, mode; ymfpci_voice_t *voice; status = snd_ymfpci_readl(chip, YDSXGR_STATUS); if (status & 0x80000000) { chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1; spin_lock(&chip->voice_lock); for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { voice = &chip->voices[nvoice]; if (voice->interrupt) voice->interrupt(chip, voice); } for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { if (chip->capture_substream[nvoice]) snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]); }#if 0 for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) { if (chip->effect_substream[nvoice]) snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]); }#endif spin_unlock(&chip->voice_lock); spin_lock(&chip->reg_lock); snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000); mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2; snd_ymfpci_writel(chip, YDSXGR_MODE, mode); spin_unlock(&chip->reg_lock); if (atomic_read(&chip->interrupt_sleep_count)) { atomic_set(&chip->interrupt_sleep_count, 0); wake_up(&chip->interrupt_sleep); } } status = snd_ymfpci_readl(chip, YDSXGR_INTFLAG); if (status & 1) { /* timer handler */ snd_ymfpci_writel(chip, YDSXGR_INTFLAG, ~0); } if (chip->rawmidi) snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs);}static snd_pcm_hardware_t snd_ymfpci_playback ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), formats: SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, rate_min: 8000, rate_max: 48000, channels_min: 1, channels_max: 2, buffer_bytes_max: 256 * 1024, /* FIXME: enough? */ period_bytes_min: 64, period_bytes_max: 256 * 1024, /* FIXME: enough? */ periods_min: 3, periods_max: 1024, fifo_size: 0,};static snd_pcm_hardware_t snd_ymfpci_capture ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), formats: SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, rate_min: 8000, rate_max: 48000, channels_min: 1, channels_max: 2, buffer_bytes_max: 256 * 1024, /* FIXME: enough? */ period_bytes_min: 64, period_bytes_max: 256 * 1024, /* FIXME: enough? */ periods_min: 3, periods_max: 1024, fifo_size: 0,};static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime){ ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return); if (ypcm) snd_magic_kfree(ypcm);}static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; ypcm->type = PLAYBACK_VOICE; ypcm->substream = substream; runtime->hw = snd_ymfpci_playback; runtime->private_data = ypcm; runtime->private_free = snd_ymfpci_pcm_free_substream; /* FIXME? True value is 256/48 = 5.33333 ms */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); return 0;}static int snd_ymfpci_playback_spdif_open(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; unsigned long flags; int err; if ((err = snd_ymfpci_playback_open(substream)) < 0) return err; ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return 0); ypcm->spdif = 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2); snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30)); chip->spdif_pcm_bits = chip->spdif_bits; snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); spin_unlock_irqrestore(&chip->reg_lock, flags); chip->spdif_pcm_ctl->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id); /* FIXME? True value is 256/48 = 5.33333 ms */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); return 0;}static int snd_ymfpci_playback_4ch_open(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; unsigned long flags; int err; if ((err = snd_ymfpci_playback_open(substream)) < 0) return err; ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return 0); ypcm->mode4ch = 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writew(chip, YDSXGR_SECCONFIG, (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0030) | 0x0010); snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30)); spin_unlock_irqrestore(&chip->reg_lock, flags); /* FIXME? True value is 256/48 = 5.33333 ms */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); return 0;}static int snd_ymfpci_capture_open(snd_pcm_substream_t * substream, u32 capture_bank_number){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; ypcm->type = capture_bank_number + CAPTURE_REC; ypcm->substream = substream; ypcm->capture_bank_number = capture_bank_number; chip->capture_substream[capture_bank_number] = substream; runtime->hw = snd_ymfpci_capture; /* FIXME? True value is 256/48 = 5.33333 ms */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX); runtime->private_data = ypcm; runtime->private_free = snd_ymfpci_pcm_free_substream; snd_ymfpci_hw_start(chip); return 0;}static int snd_ymfpci_capture_rec_open(snd_pcm_substream_t * substream){ return snd_ymfpci_capture_open(substream, 0);}static int snd_ymfpci_capture_ac97_open(snd_pcm_substream_t * substream){ return snd_ymfpci_capture_open(substream, 1);}static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream){ return 0;}static int snd_ymfpci_playback_spdif_close(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30)); snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2); snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); spin_unlock_irqrestore(&chip->reg_lock, flags); chip->spdif_pcm_ctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id); return snd_ymfpci_playback_close(substream);}static int snd_ymfpci_playback_4ch_close(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30)); snd_ymfpci_writew(chip, YDSXGR_SECCONFIG, (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010); spin_unlock_irqrestore(&chip->reg_lock, flags); return snd_ymfpci_playback_close(substream);}static int snd_ymfpci_capture_close(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); if (ypcm != NULL) { chip->capture_substream[ypcm->capture_bank_number] = NULL; snd_ymfpci_hw_stop(chip); } return 0;}static snd_pcm_ops_t snd_ymfpci_playback_ops = { open: snd_ymfpci_playback_open, close: snd_ymfpci_playback_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_ymfpci_playback_hw_params, hw_free: snd_ymfpci_playback_hw_free, prepare: snd_ymfpci_playback_prepare, trigger: snd_ymfpci_playback_trigger, pointer: snd_ymfpci_playback_pointer,};static snd_pcm_ops_t snd_ymfpci_capture_rec_ops = { open: snd_ymfpci_capture_rec_open, close: snd_ymfpci_capture_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_ymfpci_capture_hw_params, hw_free: snd_ymfpci_capture_hw_free, prepare: snd_ymfpci_capture_prepare, trigger: snd_ymfpci_capture_trigger, pointer: snd_ymfpci_capture_pointer,};static void snd_ymfpci_pcm_free(snd_pcm_t *pcm){ ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return); chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}int __devinit snd_ymfpci_pcm(ymfpci_t *chip, int device, snd_pcm_t ** rpcm){ snd_pcm_t *pcm; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0) return err; pcm->private_data = chip; pcm->private_free = snd_ymfpci_pcm_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_rec_ops); /* global setup */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -