es1938.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
snd_es1938_bits(chip, ESS_CMD_DRQCONTROL, 0xf0, 0x50); snd_es1938_write_cmd(chip, ESS_CMD_ENABLEAUDIO1); /* Set spatializer parameters to recommended values */ snd_es1938_mixer_write(chip, 0x54, 0x8f); snd_es1938_mixer_write(chip, 0x56, 0x95); snd_es1938_mixer_write(chip, 0x58, 0x94); snd_es1938_mixer_write(chip, 0x5a, 0x80);}/* -------------------------------------------------------------------- * Reset the FIFOs * --------------------------------------------------------------------*/static void snd_es1938_reset_fifo(es1938_t *chip){ outb(2, SLSB_REG(chip, RESET)); outb(0, SLSB_REG(chip, RESET));}static ratnum_t clocks[2] = { { .num = 793800, .den_min = 1, .den_max = 128, .den_step = 1, }, { .num = 768000, .den_min = 1, .den_max = 128, .den_step = 1, }};static snd_pcm_hw_constraint_ratnums_t hw_constraints_clocks = { .nrats = 2, .rats = clocks,};static void snd_es1938_rate_set(es1938_t *chip, snd_pcm_substream_t *substream, int mode){ unsigned int bits, div0; snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->rate_num == clocks[0].num) bits = 128 - runtime->rate_den; else bits = 256 - runtime->rate_den; /* set filter register */ div0 = 256 - 7160000*20/(8*82*runtime->rate); if (mode == DAC2) { snd_es1938_mixer_write(chip, 0x70, bits); snd_es1938_mixer_write(chip, 0x72, div0); } else { snd_es1938_write(chip, 0xA1, bits); snd_es1938_write(chip, 0xA2, div0); }}/* -------------------------------------------------------------------- * Configure Solo1 builtin DMA Controller * --------------------------------------------------------------------*/static void snd_es1938_playback1_setdma(es1938_t *chip){ outb(0x00, SLIO_REG(chip, AUDIO2MODE)); outl(chip->dma2_start, SLIO_REG(chip, AUDIO2DMAADDR)); outw(0, SLIO_REG(chip, AUDIO2DMACOUNT)); outw(chip->dma2_size, SLIO_REG(chip, AUDIO2DMACOUNT));}static void snd_es1938_playback2_setdma(es1938_t *chip){ /* Enable DMA controller */ outb(0xc4, SLDM_REG(chip, DMACOMMAND)); /* 1. Master reset */ outb(0, SLDM_REG(chip, DMACLEAR)); /* 2. Mask DMA */ outb(1, SLDM_REG(chip, DMAMASK)); outb(0x18, SLDM_REG(chip, DMAMODE)); outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); /* 3. Unmask DMA */ outb(0, SLDM_REG(chip, DMAMASK));}static void snd_es1938_capture_setdma(es1938_t *chip){ /* Enable DMA controller */ outb(0xc4, SLDM_REG(chip, DMACOMMAND)); /* 1. Master reset */ outb(0, SLDM_REG(chip, DMACLEAR)); /* 2. Mask DMA */ outb(1, SLDM_REG(chip, DMAMASK)); outb(0x14, SLDM_REG(chip, DMAMODE)); outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); /* 3. Unmask DMA */ outb(0, SLDM_REG(chip, DMAMASK));}/* ---------------------------------------------------------------------- * * *** PCM part *** */static int snd_es1938_capture_trigger(snd_pcm_substream_t * substream, int cmd){ es1938_t *chip = snd_pcm_substream_chip(substream); int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: val = 0x0f; chip->active |= ADC1; break; case SNDRV_PCM_TRIGGER_STOP: val = 0x00; chip->active &= ~ADC1; break; default: return -EINVAL; } snd_es1938_write(chip, ESS_CMD_DMACONTROL, val); return 0;}static int snd_es1938_playback1_trigger(snd_pcm_substream_t * substream, int cmd){ es1938_t *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* According to the documentation this should be: 0x13 but that value may randomly swap stereo channels */ snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92); udelay(10); snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x93); /* This two stage init gives the FIFO -> DAC connection time to * settle before first data from DMA flows in. This should ensure * no swapping of stereo channels. Report a bug if otherwise :-) */ outb(0x0a, SLIO_REG(chip, AUDIO2MODE)); chip->active |= DAC2; break; case SNDRV_PCM_TRIGGER_STOP: outb(0, SLIO_REG(chip, AUDIO2MODE)); snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0); chip->active &= ~DAC2; break; default: return -EINVAL; } return 0;}static int snd_es1938_playback2_trigger(snd_pcm_substream_t * substream, int cmd){ es1938_t *chip = snd_pcm_substream_chip(substream); int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: val = 5; chip->active |= DAC1; break; case SNDRV_PCM_TRIGGER_STOP: val = 0; chip->active &= ~DAC1; break; default: return -EINVAL; } snd_es1938_write(chip, ESS_CMD_DMACONTROL, val); return 0;}static int snd_es1938_playback_trigger(snd_pcm_substream_t *substream, int cmd){ switch (substream->number) { case 0: return snd_es1938_playback1_trigger(substream, cmd); case 1: return snd_es1938_playback2_trigger(substream, cmd); } snd_BUG(); return -EINVAL;}/* -------------------------------------------------------------------- * First channel for Extended Mode Audio 1 ADC Operation * --------------------------------------------------------------------*/static int snd_es1938_capture_prepare(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int u, is8, mono; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma1_size = size; chip->dma1_start = runtime->dma_addr; mono = (runtime->channels > 1) ? 0 : 1; is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1; u = snd_pcm_format_unsigned(runtime->format); chip->dma1_shift = 2 - mono - is8; snd_es1938_reset_fifo(chip); /* program type */ snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1)); /* set clock and counters */ snd_es1938_rate_set(chip, substream, ADC1); count = 0x10000 - count; snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff); snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8); /* initialize and configure ADC */ snd_es1938_write(chip, ESS_CMD_SETFORMAT2, u ? 0x51 : 0x71); snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 0x90 | (u ? 0x00 : 0x20) | (is8 ? 0x00 : 0x04) | (mono ? 0x40 : 0x08)); // snd_es1938_reset_fifo(chip); /* 11. configure system interrupt controller and DMA controller */ snd_es1938_capture_setdma(chip); return 0;}/* ------------------------------------------------------------------------------ * Second Audio channel DAC Operation * ------------------------------------------------------------------------------*/static int snd_es1938_playback1_prepare(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int u, is8, mono; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma2_size = size; chip->dma2_start = runtime->dma_addr; mono = (runtime->channels > 1) ? 0 : 1; is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1; u = snd_pcm_format_unsigned(runtime->format); chip->dma2_shift = 2 - mono - is8; snd_es1938_reset_fifo(chip); /* set clock and counters */ snd_es1938_rate_set(chip, substream, DAC2); count >>= 1; count = 0x10000 - count; snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTL, count & 0xff); snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2TCOUNTH, count >> 8); /* initialize and configure Audio 2 DAC */ snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL2, 0x40 | (u ? 0 : 4) | (mono ? 0 : 2) | (is8 ? 0 : 1)); /* program DMA */ snd_es1938_playback1_setdma(chip); return 0;}static int snd_es1938_playback2_prepare(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int u, is8, mono; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma1_size = size; chip->dma1_start = runtime->dma_addr; mono = (runtime->channels > 1) ? 0 : 1; is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1; u = snd_pcm_format_unsigned(runtime->format); chip->dma1_shift = 2 - mono - is8; count = 0x10000 - count; /* reset */ snd_es1938_reset_fifo(chip); snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1)); /* set clock and counters */ snd_es1938_rate_set(chip, substream, DAC1); snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff); snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8); /* initialized and configure DAC */ snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x80 : 0x00); snd_es1938_write(chip, ESS_CMD_SETFORMAT, u ? 0x51 : 0x71); snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 0x90 | (mono ? 0x40 : 0x08) | (is8 ? 0x00 : 0x04) | (u ? 0x00 : 0x20)); /* program DMA */ snd_es1938_playback2_setdma(chip); return 0;}static int snd_es1938_playback_prepare(snd_pcm_substream_t *substream){ switch (substream->number) { case 0: return snd_es1938_playback1_prepare(substream); case 1: return snd_es1938_playback2_prepare(substream); } snd_BUG(); return -EINVAL;}static snd_pcm_uframes_t snd_es1938_capture_pointer(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); size_t ptr; size_t old, new;#if 1 /* This stuff is *needed*, don't ask why - AB */ old = inw(SLDM_REG(chip, DMACOUNT)); while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) old = new; ptr = chip->dma1_size - 1 - new;#else ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;#endif return ptr >> chip->dma1_shift;}static snd_pcm_uframes_t snd_es1938_playback1_pointer(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); size_t ptr;#if 1 ptr = chip->dma2_size - inw(SLIO_REG(chip, AUDIO2DMACOUNT));#else ptr = inl(SLIO_REG(chip, AUDIO2DMAADDR)) - chip->dma2_start;#endif return ptr >> chip->dma2_shift;}static snd_pcm_uframes_t snd_es1938_playback2_pointer(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); size_t ptr; size_t old, new;#if 1 /* This stuff is *needed*, don't ask why - AB */ old = inw(SLDM_REG(chip, DMACOUNT)); while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) old = new; ptr = chip->dma1_size - 1 - new;#else ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;#endif return ptr >> chip->dma1_shift;}static snd_pcm_uframes_t snd_es1938_playback_pointer(snd_pcm_substream_t *substream){ switch (substream->number) { case 0: return snd_es1938_playback1_pointer(substream); case 1: return snd_es1938_playback2_pointer(substream); } snd_BUG(); return -EINVAL;}static int snd_es1938_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){ snd_pcm_runtime_t *runtime = substream->runtime; es1938_t *chip = snd_pcm_substream_chip(substream); pos <<= chip->dma1_shift; count <<= chip->dma1_shift; snd_assert(pos + count <= chip->dma1_size, return -EINVAL); if (pos + count < chip->dma1_size) { if (copy_to_user(dst, runtime->dma_area + pos + 1, count)) return -EFAULT; } else { if (copy_to_user(dst, runtime->dma_area + pos + 1, count - 1)) return -EFAULT; if (put_user(runtime->dma_area[0], ((unsigned char __user *)dst) + count - 1)) return -EFAULT; } return 0;}/* * buffer management */static int snd_es1938_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params){ int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; return 0;}static int snd_es1938_pcm_hw_free(snd_pcm_substream_t *substream){ return snd_pcm_lib_free_pages(substream);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?