cs46xx_lib.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
powerdown = 1; } /* * We want to clear out the serial port FIFOs so we don't end up playing * whatever random garbage happens to be in them. We fill the sample FIFOS * with zero (silence). */ snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0); /* * Fill all 256 sample FIFO locations. */ for (idx = 0; idx < 0xFF; idx++) { /* * Make sure the previous FIFO write operation has completed. */ if (cs46xx_wait_for_fifo(chip,1)) { snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx); if (powerdown) snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); break; } /* * Write the serial port FIFO index. */ snd_cs46xx_pokeBA0(chip, BA0_SERBAD, idx); /* * Tell the serial port to load the new value into the FIFO location. */ snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC); } /* * Now, if we powered up the devices, then power them back down again. * This is kinda ugly, but should never happen. */ if (powerdown) snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);}static void snd_cs46xx_proc_start(cs46xx_t *chip){ int cnt; /* * Set the frame timer to reflect the number of cycles per frame. */ snd_cs46xx_poke(chip, BA1_FRMT, 0xadf); /* * Turn on the run, run at frame, and DMA enable bits in the local copy of * the SP control register. */ snd_cs46xx_poke(chip, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); /* * Wait until the run at frame bit resets itself in the SP control * register. */ for (cnt = 0; cnt < 25; cnt++) { udelay(50); if (!(snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR)) break; } if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR) snd_printk("SPCR_RUNFR never reset\n");}static void snd_cs46xx_proc_stop(cs46xx_t *chip){ /* * Turn off the run, run at frame, and DMA enable bits in the local copy of * the SP control register. */ snd_cs46xx_poke(chip, BA1_SPCR, 0);}/* * Sample rate routines */#define GOF_PER_SEC 200static void snd_cs46xx_set_play_sample_rate(cs46xx_t *chip, unsigned int rate){ unsigned long flags; unsigned int tmp1, tmp2; unsigned int phiIncr; unsigned int correctionPerGOF, correctionPerSec; /* * Compute the values used to drive the actual sample rate conversion. * The following formulas are being computed, using inline assembly * since we need to use 64 bit arithmetic to compute the values: * * phiIncr = floor((Fs,in * 2^26) / Fs,out) * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / * GOF_PER_SEC) * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M * GOF_PER_SEC * correctionPerGOF * * i.e. * * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out) * correctionPerGOF:correctionPerSec = * dividend:remainder(ulOther / GOF_PER_SEC) */ tmp1 = rate << 16; phiIncr = tmp1 / 48000; tmp1 -= phiIncr * 48000; tmp1 <<= 10; phiIncr <<= 10; tmp2 = tmp1 / 48000; phiIncr += tmp2; tmp1 -= tmp2 * 48000; correctionPerGOF = tmp1 / GOF_PER_SEC; tmp1 -= correctionPerGOF * GOF_PER_SEC; correctionPerSec = tmp1; /* * Fill in the SampleRateConverter control block. */ spin_lock_irqsave(&chip->reg_lock, flags); snd_cs46xx_poke(chip, BA1_PSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); snd_cs46xx_poke(chip, BA1_PPI, phiIncr); spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs46xx_set_capture_sample_rate(cs46xx_t *chip, unsigned int rate){ unsigned long flags; unsigned int phiIncr, coeffIncr, tmp1, tmp2; unsigned int correctionPerGOF, correctionPerSec, initialDelay; unsigned int frameGroupLength, cnt; /* * We can only decimate by up to a factor of 1/9th the hardware rate. * Correct the value if an attempt is made to stray outside that limit. */ if ((rate * 9) < 48000) rate = 48000 / 9; /* * We can not capture at at rate greater than the Input Rate (48000). * Return an error if an attempt is made to stray outside that limit. */ if (rate > 48000) rate = 48000; /* * Compute the values used to drive the actual sample rate conversion. * The following formulas are being computed, using inline assembly * since we need to use 64 bit arithmetic to compute the values: * * coeffIncr = -floor((Fs,out * 2^23) / Fs,in) * phiIncr = floor((Fs,in * 2^26) / Fs,out) * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) / * GOF_PER_SEC) * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - * GOF_PER_SEC * correctionPerGOF * initialDelay = ceil((24 * Fs,in) / Fs,out) * * i.e. * * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) * correctionPerGOF:correctionPerSec = * dividend:remainder(ulOther / GOF_PER_SEC) * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) */ tmp1 = rate << 16; coeffIncr = tmp1 / 48000; tmp1 -= coeffIncr * 48000; tmp1 <<= 7; coeffIncr <<= 7; coeffIncr += tmp1 / 48000; coeffIncr ^= 0xFFFFFFFF; coeffIncr++; tmp1 = 48000 << 16; phiIncr = tmp1 / rate; tmp1 -= phiIncr * rate; tmp1 <<= 10; phiIncr <<= 10; tmp2 = tmp1 / rate; phiIncr += tmp2; tmp1 -= tmp2 * rate; correctionPerGOF = tmp1 / GOF_PER_SEC; tmp1 -= correctionPerGOF * GOF_PER_SEC; correctionPerSec = tmp1; initialDelay = ((48000 * 24) + rate - 1) / rate; /* * Fill in the VariDecimate control block. */ spin_lock_irqsave(&chip->reg_lock, flags); snd_cs46xx_poke(chip, BA1_CSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); snd_cs46xx_poke(chip, BA1_CCI, coeffIncr); snd_cs46xx_poke(chip, BA1_CD, (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); snd_cs46xx_poke(chip, BA1_CPI, phiIncr); spin_unlock_irqrestore(&chip->reg_lock, flags); /* * Figure out the frame group length for the write back task. Basically, * this is just the factors of 24000 (2^6*3*5^3) that are not present in * the output sample rate. */ frameGroupLength = 1; for (cnt = 2; cnt <= 64; cnt *= 2) { if (((rate / cnt) * cnt) != rate) frameGroupLength *= 2; } if (((rate / 3) * 3) != rate) { frameGroupLength *= 3; } for (cnt = 5; cnt <= 125; cnt *= 5) { if (((rate / cnt) * cnt) != rate) frameGroupLength *= 5; } /* * Fill in the WriteBack control block. */ spin_lock_irqsave(&chip->reg_lock, flags); snd_cs46xx_poke(chip, BA1_CFG1, frameGroupLength); snd_cs46xx_poke(chip, BA1_CFG2, (0x00800000 | frameGroupLength)); snd_cs46xx_poke(chip, BA1_CCST, 0x0000FFFF); snd_cs46xx_poke(chip, BA1_CSPB, ((65536 * rate) / 24000)); snd_cs46xx_poke(chip, (BA1_CSPB + 4), 0x0000FFFF); spin_unlock_irqrestore(&chip->reg_lock, flags);}/* * PCM part */static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream){ /* cs46xx_t *chip = snd_pcm_substream_chip(substream); */ snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; snd_pcm_sframes_t diff = appl_ptr - cpcm->appl_ptr; int buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift; if (diff) { if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; cpcm->sw_ready += diff * (1 << cpcm->shift); cpcm->appl_ptr = appl_ptr; } while (cpcm->hw_ready < buffer_size && cpcm->sw_ready > 0) { size_t hw_to_end = buffer_size - cpcm->hw_data; size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data; size_t bytes = buffer_size - cpcm->hw_ready; if (cpcm->sw_ready < (int)bytes) bytes = cpcm->sw_ready; if (hw_to_end < bytes) bytes = hw_to_end; if (sw_to_end < bytes) bytes = sw_to_end; memcpy(cpcm->hw_buf.area + cpcm->hw_data, runtime->dma_area + cpcm->sw_data, bytes); cpcm->hw_data += bytes; if ((int)cpcm->hw_data == buffer_size) cpcm->hw_data = 0; cpcm->sw_data += bytes; if (cpcm->sw_data == cpcm->sw_bufsize) cpcm->sw_data = 0; cpcm->hw_ready += bytes; cpcm->sw_ready -= bytes; } return 0;}static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr; int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift; if (diff) { if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) diff += runtime->boundary; chip->capt.sw_ready -= diff * (1 << chip->capt.shift); chip->capt.appl_ptr = appl_ptr; } while (chip->capt.hw_ready > 0 && chip->capt.sw_ready < (int)chip->capt.sw_bufsize) { size_t hw_to_end = buffer_size - chip->capt.hw_data; size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data; size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready; if (chip->capt.hw_ready < (int)bytes) bytes = chip->capt.hw_ready; if (hw_to_end < bytes) bytes = hw_to_end; if (sw_to_end < bytes) bytes = sw_to_end; memcpy(runtime->dma_area + chip->capt.sw_data, chip->capt.hw_buf.area + chip->capt.hw_data, bytes); chip->capt.hw_data += bytes; if ((int)chip->capt.hw_data == buffer_size) chip->capt.hw_data = 0; chip->capt.sw_data += bytes; if (chip->capt.sw_data == chip->capt.sw_bufsize) chip->capt.sw_data = 0; chip->capt.hw_ready -= bytes; chip->capt.sw_ready += bytes; } return 0;}static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr; cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); snd_assert (cpcm->pcm_channel,return -ENXIO);#ifdef CONFIG_SND_CS46XX_NEW_DSP ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);#else ptr = snd_cs46xx_peek(chip, BA1_PBA);#endif ptr -= cpcm->hw_buf.addr; return ptr >> cpcm->shift;}static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr; cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); ssize_t bytes; int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << cpcm->shift;#ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (cpcm->pcm_channel,return -ENXIO); ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);#else ptr = snd_cs46xx_peek(chip, BA1_PBA);#endif ptr -= cpcm->hw_buf.addr; bytes = ptr - cpcm->hw_io; if (bytes < 0) bytes += buffer_size; cpcm->hw_io = ptr; cpcm->hw_ready -= bytes; cpcm->sw_io += bytes; if (cpcm->sw_io >= cpcm->sw_bufsize) cpcm->sw_io -= cpcm->sw_bufsize; snd_cs46xx_playback_transfer(substream); return cpcm->sw_io >> cpcm->shift;}static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr; return ptr >> chip->capt.shift;}static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr; ssize_t bytes = ptr - chip->capt.hw_io; int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << chip->capt.shift; if (bytes < 0) bytes += buffer_size; chip->capt.hw_io = ptr; chip->capt.hw_ready += bytes; chip->capt.sw_io += bytes; if (chip->capt.sw_io >= chip->capt.sw_bufsize) chip->capt.sw_io -= chip->capt.sw_bufsize; snd_cs46xx_capture_transfer(substream); return chip->capt.sw_io >> chip->capt.shift;}static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, int cmd){ cs46xx_t *chip = snd_pcm_substream_chip(substream); /*snd_pcm_runtime_t *runtime = substream->runtime;*/ int result = 0;#ifdef CONFIG_SND_CS46XX_NEW_DSP cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);#else spin_lock(&chip->reg_lock);#endif#ifdef CONFIG_SND_CS46XX_NEW_DSP if (! cpcm->pcm_channel) { return -ENXIO; }#endif switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME:#ifdef CONFIG_SND_CS46XX_NEW_DSP /* magic value to unmute PCM stream playback volume */ snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + SCBVolumeCtrl) << 2, 0x80008000); if (cpcm->pcm_channel->unlinked) cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel); if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream);#else if (substream->runtime->periods != CS46XX_FRAGS) snd_cs46xx_playback_transfer(substream); { unsigned int tmp; tmp = snd_cs46xx_peek(chip, BA1_PCTL); tmp &= 0x0000ffff; snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp); }#endif break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND:#ifdef CONFIG_SND_CS46XX_NEW_DSP /* magic mute channel */ snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + SCBVolumeCtrl) << 2, 0xffffffff); if (!cpcm->pcm_channel->unlinked) cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);#else { unsigned int tmp; tmp = snd_cs46xx_peek(chip, BA1_PCTL); tmp &= 0x0000ffff; snd_cs46xx_poke(chip, BA1_PCTL, tmp); }#endif break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?