📄 cs46xx_lib.c
字号:
snd_assert (cpcm->pcm_channel != NULL); if (!cpcm->pcm_channel) { up (&chip->spos_mutex); return -ENXIO; } if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) { up (&chip->spos_mutex); return -EINVAL; } snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n", period_size, params_periods(hw_params), params_buffer_bytes(hw_params));#endif if (params_periods(hw_params) == CS46XX_FRAGS) { if (runtime->dma_area != cpcm->hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = cpcm->hw_buf.area; runtime->dma_addr = cpcm->hw_buf.addr; runtime->dma_bytes = cpcm->hw_buf.bytes;#ifdef CONFIG_SND_CS46XX_NEW_DSP if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) { substream->ops = &snd_cs46xx_playback_ops; } else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) { substream->ops = &snd_cs46xx_playback_rear_ops; } else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) { substream->ops = &snd_cs46xx_playback_clfe_ops; } else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) { substream->ops = &snd_cs46xx_playback_iec958_ops; } else { snd_assert(0); }#else substream->ops = &snd_cs46xx_playback_ops;#endif } else { if (runtime->dma_area == cpcm->hw_buf.area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; } if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {#ifdef CONFIG_SND_CS46XX_NEW_DSP up (&chip->spos_mutex);#endif return err; }#ifdef CONFIG_SND_CS46XX_NEW_DSP if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) { substream->ops = &snd_cs46xx_playback_indirect_ops; } else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) { substream->ops = &snd_cs46xx_playback_indirect_rear_ops; } else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) { substream->ops = &snd_cs46xx_playback_indirect_clfe_ops; } else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) { substream->ops = &snd_cs46xx_playback_indirect_iec958_ops; } else { snd_assert(0); }#else substream->ops = &snd_cs46xx_playback_indirect_ops;#endif }#ifdef CONFIG_SND_CS46XX_NEW_DSP up (&chip->spos_mutex);#endif return 0;}static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream){ /*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/ snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; cpcm = runtime->private_data; /* if play_back open fails, then this function is called and cpcm can actually be NULL here */ if (!cpcm) return -ENXIO; if (runtime->dma_area != cpcm->hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; return 0;}static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream){ unsigned int tmp; unsigned int pfie; cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; cpcm = runtime->private_data;#ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (cpcm->pcm_channel != NULL, return -ENXIO); pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 ); pfie &= ~0x0000f03f;#else /* old dsp */ pfie = snd_cs46xx_peek(chip, BA1_PFIE); pfie &= ~0x0000f03f;#endif cpcm->shift = 2; /* if to convert from stereo to mono */ if (runtime->channels == 1) { cpcm->shift--; pfie |= 0x00002000; } /* if to convert from 8 bit to 16 bit */ if (snd_pcm_format_width(runtime->format) == 8) { cpcm->shift--; pfie |= 0x00001000; } /* if to convert to unsigned */ if (snd_pcm_format_unsigned(runtime->format)) pfie |= 0x00008000; /* Never convert byte order when sample stream is 8 bit */ if (snd_pcm_format_width(runtime->format) != 8) { /* convert from big endian to little endian */ if (snd_pcm_format_big_endian(runtime->format)) pfie |= 0x00004000; } memset(&cpcm->pcm_rec, 0, sizeof(cpcm->pcm_rec)); cpcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); cpcm->pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;#ifdef CONFIG_SND_CS46XX_NEW_DSP tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2); tmp &= ~0x000003ff; tmp |= (4 << cpcm->shift) - 1; /* playback transaction count register */ snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2, tmp); /* playback format && interrupt enable */ snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot);#else snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_buf.addr); tmp = snd_cs46xx_peek(chip, BA1_PDTC); tmp &= ~0x000003ff; tmp |= (4 << cpcm->shift) - 1; snd_cs46xx_poke(chip, BA1_PDTC, tmp); snd_cs46xx_poke(chip, BA1_PFIE, pfie); snd_cs46xx_set_play_sample_rate(chip, runtime->rate);#endif return 0;}static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params));#endif if (runtime->periods == CS46XX_FRAGS) { if (runtime->dma_area != chip->capt.hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = chip->capt.hw_buf.area; runtime->dma_addr = chip->capt.hw_buf.addr; runtime->dma_bytes = chip->capt.hw_buf.bytes; substream->ops = &snd_cs46xx_capture_ops; } else { if (runtime->dma_area == chip->capt.hw_buf.area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; } if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; substream->ops = &snd_cs46xx_capture_indirect_ops; } return 0;}static int snd_cs46xx_capture_hw_free(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->dma_area != chip->capt.hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; return 0;}static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr); chip->capt.shift = 2; memset(&chip->capt.pcm_rec, 0, sizeof(chip->capt.pcm_rec)); chip->capt.pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); chip->capt.pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << 2; snd_cs46xx_set_capture_sample_rate(chip, runtime->rate); return 0;}static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){ cs46xx_t *chip = dev_id; u32 status1;#ifdef CONFIG_SND_CS46XX_NEW_DSP dsp_spos_instance_t * ins = chip->dsp_spos_instance; u32 status2; int i; cs46xx_pcm_t *cpcm = NULL;#endif /* * Read the Interrupt Status Register to clear the interrupt */ status1 = snd_cs46xx_peekBA0(chip, BA0_HISR); if ((status1 & 0x7fffffff) == 0) { snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV); return IRQ_NONE; }#ifdef CONFIG_SND_CS46XX_NEW_DSP status2 = snd_cs46xx_peekBA0(chip, BA0_HSR0); for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) { if (i <= 15) { if ( status1 & (1 << i) ) { if (i == CS46XX_DSP_CAPTURE_CHANNEL) { if (chip->capt.substream) snd_pcm_period_elapsed(chip->capt.substream); } else { if (ins->pcm_channels[i].active && ins->pcm_channels[i].private_data && !ins->pcm_channels[i].unlinked) { cpcm = ins->pcm_channels[i].private_data; snd_pcm_period_elapsed(cpcm->substream); } } } } else { if ( status2 & (1 << (i - 16))) { if (ins->pcm_channels[i].active && ins->pcm_channels[i].private_data && !ins->pcm_channels[i].unlinked) { cpcm = ins->pcm_channels[i].private_data; snd_pcm_period_elapsed(cpcm->substream); } } } }#else /* old dsp */ if ((status1 & HISR_VC0) && chip->playback_pcm) { if (chip->playback_pcm->substream) snd_pcm_period_elapsed(chip->playback_pcm->substream); } if ((status1 & HISR_VC1) && chip->pcm) { if (chip->capt.substream) snd_pcm_period_elapsed(chip->capt.substream); }#endif if ((status1 & HISR_MIDI) && chip->rmidi) { unsigned char c; spin_lock(&chip->reg_lock); while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) { c = snd_cs46xx_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & MIDCR_RIE) == 0) continue; spin_unlock(&chip->reg_lock); snd_rawmidi_receive(chip->midi_input, &c, 1); spin_lock(&chip->reg_lock); } while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) { if ((chip->midcr & MIDCR_TIE) == 0) break; if (snd_rawmidi_transmit(chip->midi_output, &c, 1) != 1) { chip->midcr &= ~MIDCR_TIE; snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); break; } snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c); } spin_unlock(&chip->reg_lock); } /* * EOI to the PCI part....reenables interrupts */ snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV); return IRQ_HANDLED;}static snd_pcm_hardware_t snd_cs46xx_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_RESUME), .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (256 * 1024), .period_bytes_min = CS46XX_MIN_PERIOD_SIZE, .period_bytes_max = CS46XX_MAX_PERIOD_SIZE, .periods_min = CS46XX_FRAGS, .periods_max = 1024, .fifo_size = 0,};static snd_pcm_hardware_t snd_cs46xx_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (256 * 1024), .period_bytes_min = CS46XX_MIN_PERIOD_SIZE, .period_bytes_max = CS46XX_MAX_PERIOD_SIZE, .periods_min = CS46XX_FRAGS, .periods_max = 1024, .fifo_size = 0,};#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic unsigned int period_sizes[] = { 32, 64, 128, 256, 512, 1024, 2048 };static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { .count = ARRAY_SIZE(period_sizes), .list = period_sizes, .mask = 0};#endifstatic void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime){ cs46xx_pcm_t * cpcm = runtime->private_data; kfree(cpcm);}static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id){ cs46xx_t *chip = snd_pcm_substream_chip(substream); cs46xx_pcm_t * cpcm; snd_pcm_runtime_t *runtime = substream->runtime; cpcm = kcalloc(1, sizeof(*cpcm), GFP_KERNEL); if (cpcm == NULL) return -ENOMEM; if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_SIZE, &cpcm->hw_buf) < 0) { kfree(cpcm); return -ENOMEM; } runtime->hw = snd_cs46xx_playback; runtime->private_data = cpcm; runtime->private_free = snd_cs46xx_pcm_free_substream; cpcm->substream = substream;#ifdef CONFIG_SND_CS46XX_NEW_DSP down (&chip->spos_mutex); cpcm->pcm_channel = NULL; cpcm->pcm_channel_id = pcm_channel_id; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_sizes); up (&chip->spos_mutex);#else chip->playback_pcm = cpcm; /* HACK */#endif if (chip->accept_valid) substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID; chip->active_ctrl(chip, 1); return 0;}static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream){ snd_printdd("open front channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int snd_cs46xx_playback_open_rear(snd_pcm_substream_t * substream){ snd_printdd("open rear channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);}static int snd_cs46xx_playback_open_clfe(snd_pcm_substream_t * substream){ snd_printdd("open center - LFE channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_CENTER_LFE_CHANNEL);}static int snd_cs46xx_playback_open_iec958(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_printdd("open raw iec958 channel\n"); down (&chip->spos_mutex); cs46xx_iec958_pre_open (chip); up (&chip->spos_mutex); return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -