📄 es1938.c
字号:
static void snd_es1938_rate_set(struct es1938 *chip, struct snd_pcm_substream *substream, int mode){ unsigned int bits, div0; struct snd_pcm_runtime *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(struct es1938 *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(struct es1938 *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(struct es1938 *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(struct snd_pcm_substream *substream, int cmd){ struct es1938 *chip = snd_pcm_substream_chip(substream); int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: val = 0x0f; chip->active |= ADC1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: 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(struct snd_pcm_substream *substream, int cmd){ struct es1938 *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: /* 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: case SNDRV_PCM_TRIGGER_SUSPEND: 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(struct snd_pcm_substream *substream, int cmd){ struct es1938 *chip = snd_pcm_substream_chip(substream); int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: val = 5; chip->active |= DAC1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: 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(struct snd_pcm_substream *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(struct snd_pcm_substream *substream){ struct es1938 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *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(struct snd_pcm_substream *substream){ struct es1938 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *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(struct snd_pcm_substream *substream){ struct es1938 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *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(struct snd_pcm_substream *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(struct snd_pcm_substream *substream){ struct es1938 *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(struct snd_pcm_substream *substream){ struct es1938 *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(struct snd_pcm_substream *substream){ struct es1938 *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(struct snd_pcm_substream *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(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){ struct snd_pcm_runtime *runtime = substream->runtime; struct es1938 *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(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *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(struct snd_pcm_substream *substream){ return snd_pcm_lib_free_pages(substream);}/* ---------------------------------------------------------------------- * Audio1 Capture (ADC) * ----------------------------------------------------------------------*/static struct snd_pcm_hardware snd_es1938_capture ={ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 6000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256,};/* ----------------------------------------------------------------------- * Audio2 Playback (DAC) * -----------------------------------------------------------------------*/static struct snd_pcm_hardware snd_es1938_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 6000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256,};static int snd_es1938_capture_open(struct snd_pcm_substream *substream){ struct es1938 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; if (chip->playback2_substream) return -EAGAIN; chip->capture_substream = substream; runtime->hw = snd_es1938_capture; snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clocks); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00); return 0;}static int snd_es1938_playback_open(struct snd_pcm_substream *substream){ struct es1938 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; switch (substream->number) { case 0: chip->playback1_substream = substream;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -