📄 ymfpci_main.c
字号:
return 0; /* already allocated */ if (voices > 1) { if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) { snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[0]); ypcm->voices[0] = NULL; } } err = snd_ymfpci_voice_alloc(ypcm->chip, YMFPCI_PCM, voices > 1, &ypcm->voices[0]); if (err < 0) return err; ypcm->voices[0]->ypcm = ypcm; ypcm->voices[0]->interrupt = snd_ymfpci_pcm_interrupt; if (voices > 1) { ypcm->voices[1] = &ypcm->chip->voices[ypcm->voices[0]->number + 1]; ypcm->voices[1]->ypcm = ypcm; } return 0;}static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx, snd_pcm_runtime_t *runtime, int has_pcm_volume){ ymfpci_voice_t *voice = ypcm->voices[voiceidx]; u32 format; u32 delta = snd_ymfpci_calc_delta(runtime->rate); u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate); u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate); snd_ymfpci_playback_bank_t *bank; unsigned int nbank; u32 vol_left, vol_right; u8 use_left, use_right; snd_assert(voice != NULL, return); if (runtime->channels == 1) { use_left = 1; use_right = 1; } else { use_left = (voiceidx & 1) == 0; use_right = !use_left; } if (has_pcm_volume) { vol_left = cpu_to_le32(ypcm->chip->pcm_mixer [ypcm->substream->number].left << 15); vol_right = cpu_to_le32(ypcm->chip->pcm_mixer [ypcm->substream->number].right << 15); } else { vol_left = cpu_to_le32(0x40000000); vol_right = cpu_to_le32(0x40000000); } format = runtime->channels == 2 ? 0x00010000 : 0; if (snd_pcm_format_width(runtime->format) == 8) format |= 0x80000000; if (runtime->channels == 2 && (voiceidx & 1) != 0) format |= 1; for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; memset(bank, 0, sizeof(*bank)); bank->format = cpu_to_le32(format); bank->base = cpu_to_le32(runtime->dma_addr); bank->loop_end = cpu_to_le32(ypcm->buffer_size); bank->lpfQ = cpu_to_le32(lpfQ); bank->delta = bank->delta_end = cpu_to_le32(delta); bank->lpfK = bank->lpfK_end = cpu_to_le32(lpfK); bank->eg_gain = bank->eg_gain_end = cpu_to_le32(0x40000000); if (ypcm->output_front) { if (use_left) { bank->left_gain = bank->left_gain_end = vol_left; } if (use_right) { bank->right_gain = bank->right_gain_end = vol_right; } } if (ypcm->output_rear) { if (use_left) { bank->eff2_gain = bank->eff2_gain_end = vol_left; } if (use_right) { bank->eff3_gain = bank->eff3_gain_end = vol_right; } } }}static int __devinit snd_ymfpci_ac3_init(ymfpci_t *chip){ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 4096, &chip->ac3_tmp_base) < 0) return -ENOMEM; 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.area) { snd_dma_free_pages(&chip->ac3_tmp_base); chip->ac3_tmp_base.area = NULL; } return 0;}static int snd_ymfpci_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm = runtime->private_data; 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; 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 = runtime->private_data; /* 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; } 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 = runtime->private_data; unsigned 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, nvoice, runtime, substream->pcm == chip->pcm); 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 = runtime->private_data; 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 = runtime->private_data; 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 = runtime->private_data; 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); schedule_timeout_uninterruptible(msecs_to_jiffies(50)); remove_wait_queue(&chip->interrupt_sleep, &wait); }}static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs){ ymfpci_t *chip = dev_id; 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_readw(chip, YDSXGR_INTFLAG); if (status & 1) { if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); } snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); if (chip->rawmidi) snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs); return IRQ_HANDLED;}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){ kfree(runtime->private_data);}static int snd_ymfpci_playback_open_1(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 = kzalloc(sizeof(*ypcm), 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;}/* call with spinlock held */static void ymfpci_open_extension(ymfpci_t *chip){ if (! chip->rear_opened) { if (! chip->spdif_opened) /* set AC3 */ snd_ymfpci_writel(chip, YDSXGR_MODE, snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30)); /* enable second codec (4CHEN) */ snd_ymfpci_writew(chip, YDSXGR_SECCONFIG, (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010); }}/* call with spinlock held */static void ymfpci_close_extension(ymfpci_t *chip){ if (! chip->rear_opened) { if (! chip->spdif_opened) 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); }}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; snd_kcontrol_t *kctl; int err; if ((err = snd_ymfpci_playback_open_1(substream)) < 0) return err; ypcm = runtime->private_data; ypcm->output_front = 1; ypcm->output_rear = chip->mode_dup4ch ? 1 : 0; spin_lock_irq(&chip->reg_lock); if (ypcm->output_rear) { ymfpci_open_extension(chip); chip->rear_opened++; } spin_unlock_irq(&chip->reg_lock); kctl = chip->pcm_mixer[substream->number].ctl; kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return 0;}static int snd_ymfpci_playback_spdif_open(snd_pcm_substream_t * substream){ ymfpci_t *chip = snd_pcm_substream_chip(substream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -