cs46xx_lib.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
default: result = -EINVAL; break; }#ifndef CONFIG_SND_CS46XX_NEW_DSP spin_unlock(&chip->reg_lock);#endif return result;}static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream, int cmd){ cs46xx_t *chip = snd_pcm_substream_chip(substream); unsigned int tmp; int result = 0; spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: tmp = snd_cs46xx_peek(chip, BA1_CCTL); tmp &= 0xffff0000; snd_cs46xx_poke(chip, BA1_CCTL, chip->capt.ctl | tmp); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: tmp = snd_cs46xx_peek(chip, BA1_CCTL); tmp &= 0xffff0000; snd_cs46xx_poke(chip, BA1_CCTL, tmp); break; default: result = -EINVAL; break; } spin_unlock(&chip->reg_lock); return result;}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm, int sample_rate) { /* If PCMReaderSCB and SrcTaskSCB not created yet ... */ if ( cpcm->pcm_channel == NULL) { cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id); if (cpcm->pcm_channel == NULL) { snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n"); return -ENOMEM; } cpcm->pcm_channel->sample_rate = sample_rate; } else /* if sample rate is changed */ if ((int)cpcm->pcm_channel->sample_rate != sample_rate) { int unlinked = cpcm->pcm_channel->unlinked; cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, cpcm->hw_buf.addr, cpcm->pcm_channel_id)) == NULL) { snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n"); return -ENOMEM; } if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel); cpcm->pcm_channel->sample_rate = sample_rate; } return 0;}#endifstatic int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP cs46xx_t *chip = snd_pcm_substream_chip(substream); int sample_rate = params_rate(hw_params); int period_size = params_period_bytes(hw_params);#endif cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);#ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (sample_rate != 0, return -ENXIO); down (&chip->spos_mutex); if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) { up (&chip->spos_mutex); return -ENXIO; } 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 = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); /* 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 = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);#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; } cpcm->sw_bufsize = snd_pcm_lib_buffer_bytes(substream); cpcm->sw_data = cpcm->sw_io = cpcm->sw_ready = 0; cpcm->hw_data = cpcm->hw_io = cpcm->hw_ready = 0; cpcm->appl_ptr = 0;#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; chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream); chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0; chip->capt.hw_data = chip->capt.hw_io = chip->capt.hw_ready = 0; chip->capt.appl_ptr = 0; 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 = snd_magic_cast(cs46xx_t, dev_id, return IRQ_NONE); 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 = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue); 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 = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue); 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; snd_rawmidi_receive(chip->midi_input, &c, 1); } 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 ={
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?