es18xx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,223 行 · 第 1/5 页
C
2,223 行
return -EBUSY; } chip->dma2_shift = shift; } else { chip->dma1_shift = shift; } if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; return 0;}static int snd_es18xx_pcm_hw_free(snd_pcm_substream_t * substream){ return snd_pcm_lib_free_pages(substream);}static int snd_es18xx_playback1_prepare(es18xx_t *chip, snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma2_size = size; snd_es18xx_rate_set(chip, substream, DAC2); /* Transfer Count Reload */ count = 0x10000 - count; snd_es18xx_mixer_write(chip, 0x74, count & 0xff); snd_es18xx_mixer_write(chip, 0x76, count >> 8); /* Set format */ snd_es18xx_mixer_bits(chip, 0x7A, 0x07, ((runtime->channels == 1) ? 0x00 : 0x02) | (snd_pcm_format_width(runtime->format) == 16 ? 0x01 : 0x00) | (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x04)); /* Set DMA controller */ snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0;}static int snd_es18xx_playback1_trigger(es18xx_t *chip, snd_pcm_substream_t * substream, int cmd){ switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (chip->active & DAC2) return 0; chip->active |= DAC2; /* Start DMA */ if (chip->dma2 >= 4) snd_es18xx_mixer_write(chip, 0x78, 0xb3); else snd_es18xx_mixer_write(chip, 0x78, 0x93);#ifdef AVOID_POPS /* Avoid pops */ udelay(100000); if (chip->caps & ES18XX_PCM2) /* Restore Audio 2 volume */ snd_es18xx_mixer_write(chip, 0x7C, chip->audio2_vol); else /* Enable PCM output */ snd_es18xx_dsp_command(chip, 0xD1);#endif break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (!(chip->active & DAC2)) return 0; chip->active &= ~DAC2; /* Stop DMA */ snd_es18xx_mixer_write(chip, 0x78, 0x00);#ifdef AVOID_POPS udelay(25000); if (chip->caps & ES18XX_PCM2) /* Set Audio 2 volume to 0 */ snd_es18xx_mixer_write(chip, 0x7C, 0); else /* Disable PCM output */ snd_es18xx_dsp_command(chip, 0xD3);#endif break; default: return -EINVAL; } return 0;}static int snd_es18xx_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ es18xx_t *chip = snd_pcm_substream_chip(substream); int shift, err; shift = 0; if ((chip->caps & ES18XX_DUPLEX_MONO) && chip->playback_a_substream && params_channels(hw_params) != 1) { _snd_pcm_hw_param_setempty(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS); return -EBUSY; } if (params_channels(hw_params) == 2) shift++; if (snd_pcm_format_width(params_format(hw_params)) == 16) shift++; chip->dma1_shift = shift; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; return 0;}static int snd_es18xx_capture_prepare(snd_pcm_substream_t *substream){ es18xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma1_size = size; snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ snd_es18xx_bits(chip, 0xA8, 0x03, runtime->channels == 1 ? 0x02 : 0x01); snd_es18xx_rate_set(chip, substream, ADC1); /* Transfer Count Reload */ count = 0x10000 - count; snd_es18xx_write(chip, 0xA4, count & 0xff); snd_es18xx_write(chip, 0xA5, count >> 8);#ifdef AVOID_POPS udelay(100000);#endif /* Set format */ snd_es18xx_write(chip, 0xB7, snd_pcm_format_unsigned(runtime->format) ? 0x51 : 0x71); snd_es18xx_write(chip, 0xB7, 0x90 | ((runtime->channels == 1) ? 0x40 : 0x08) | (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) | (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20)); /* Set DMA controler */ snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); return 0;}static int snd_es18xx_capture_trigger(snd_pcm_substream_t *substream, int cmd){ es18xx_t *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (chip->active & ADC1) return 0; chip->active |= ADC1; /* Start DMA */ snd_es18xx_write(chip, 0xB8, 0x0f); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (!(chip->active & ADC1)) return 0; chip->active &= ~ADC1; /* Stop DMA */ snd_es18xx_write(chip, 0xB8, 0x00); break; default: return -EINVAL; } return 0;}static int snd_es18xx_playback2_prepare(es18xx_t *chip, snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); chip->dma1_size = size; snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ snd_es18xx_bits(chip, 0xA8, 0x03, runtime->channels == 1 ? 0x02 : 0x01); snd_es18xx_rate_set(chip, substream, DAC1); /* Transfer Count Reload */ count = 0x10000 - count; snd_es18xx_write(chip, 0xA4, count & 0xff); snd_es18xx_write(chip, 0xA5, count >> 8); /* Set format */ snd_es18xx_write(chip, 0xB6, snd_pcm_format_unsigned(runtime->format) ? 0x80 : 0x00); snd_es18xx_write(chip, 0xB7, snd_pcm_format_unsigned(runtime->format) ? 0x51 : 0x71); snd_es18xx_write(chip, 0xB7, 0x90 | (runtime->channels == 1 ? 0x40 : 0x08) | (snd_pcm_format_width(runtime->format) == 16 ? 0x04 : 0x00) | (snd_pcm_format_unsigned(runtime->format) ? 0x00 : 0x20)); /* Set DMA controler */ snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0;}static int snd_es18xx_playback2_trigger(es18xx_t *chip, snd_pcm_substream_t *substream, int cmd){ switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (chip->active & DAC1) return 0; chip->active |= DAC1; /* Start DMA */ snd_es18xx_write(chip, 0xB8, 0x05);#ifdef AVOID_POPS /* Avoid pops */ udelay(100000); /* Enable Audio 1 */ snd_es18xx_dsp_command(chip, 0xD1);#endif break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (!(chip->active & DAC1)) return 0; chip->active &= ~DAC1; /* Stop DMA */ snd_es18xx_write(chip, 0xB8, 0x00);#ifdef AVOID_POPS /* Avoid pops */ udelay(25000); /* Disable Audio 1 */ snd_es18xx_dsp_command(chip, 0xD3);#endif break; default: return -EINVAL; } return 0;}static int snd_es18xx_playback_prepare(snd_pcm_substream_t *substream){ es18xx_t *chip = snd_pcm_substream_chip(substream); if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) return snd_es18xx_playback1_prepare(chip, substream); else return snd_es18xx_playback2_prepare(chip, substream);}static int snd_es18xx_playback_trigger(snd_pcm_substream_t *substream, int cmd){ es18xx_t *chip = snd_pcm_substream_chip(substream); if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) return snd_es18xx_playback1_trigger(chip, substream, cmd); else return snd_es18xx_playback2_trigger(chip, substream, cmd);}static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){ es18xx_t *chip = dev_id; unsigned char status; if (chip->caps & ES18XX_CONTROL) { /* Read Interrupt status */ status = inb(chip->ctrl_port + 6); } else { /* Read Interrupt status */ status = snd_es18xx_mixer_read(chip, 0x7f) >> 4; }#if 0 else { status = 0; if (inb(chip->port + 0x0C) & 0x01) status |= AUDIO1_IRQ; if (snd_es18xx_mixer_read(chip, 0x7A) & 0x80) status |= AUDIO2_IRQ; if ((chip->caps & ES18XX_HWV) && snd_es18xx_mixer_read(chip, 0x64) & 0x10) status |= HWV_IRQ; }#endif /* Audio 1 & Audio 2 */ if (status & AUDIO2_IRQ) { if (chip->active & DAC2) snd_pcm_period_elapsed(chip->playback_a_substream); /* ack interrupt */ snd_es18xx_mixer_bits(chip, 0x7A, 0x80, 0x00); } if (status & AUDIO1_IRQ) { /* ok.. capture is active */ if (chip->active & ADC1) snd_pcm_period_elapsed(chip->capture_a_substream); /* ok.. playback2 is active */ else if (chip->active & DAC1) snd_pcm_period_elapsed(chip->playback_b_substream); /* ack interrupt */ inb(chip->port + 0x0E); } /* MPU */ if ((status & MPU_IRQ) && chip->rmidi) snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); /* Hardware volume */ if (status & HWV_IRQ) { int split = snd_es18xx_mixer_read(chip, 0x64) & 0x80; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id); if (!split) { snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); } /* ack interrupt */ snd_es18xx_mixer_write(chip, 0x66, 0x00); } return IRQ_HANDLED;}static snd_pcm_uframes_t snd_es18xx_playback_pointer(snd_pcm_substream_t * substream){ es18xx_t *chip = snd_pcm_substream_chip(substream); int pos; if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if (!(chip->active & DAC2)) return 0; pos = snd_dma_pointer(chip->dma2, chip->dma2_size); return pos >> chip->dma2_shift; } else { if (!(chip->active & DAC1)) return 0; pos = snd_dma_pointer(chip->dma1, chip->dma1_size); return pos >> chip->dma1_shift; }}static snd_pcm_uframes_t snd_es18xx_capture_pointer(snd_pcm_substream_t * substream){ es18xx_t *chip = snd_pcm_substream_chip(substream); int pos; if (!(chip->active & ADC1)) return 0; pos = snd_dma_pointer(chip->dma1, chip->dma1_size); return pos >> chip->dma1_shift;}static snd_pcm_hardware_t snd_es18xx_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 64, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static snd_pcm_hardware_t snd_es18xx_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 64, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_es18xx_playback_open(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; es18xx_t *chip = snd_pcm_substream_chip(substream); if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if ((chip->caps & ES18XX_DUPLEX_MONO) && chip->capture_a_substream && chip->capture_a_substream->runtime->channels != 1) return -EAGAIN; chip->playback_a_substream = substream; } else if (substream->number <= 1) { if (chip->capture_a_substream) return -EAGAIN; chip->playback_b_substream = substream; } else { snd_BUG(); return -EINVAL; } substream->runtime->hw = snd_es18xx_playback; snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, (chip->caps & ES18XX_NEW_RATE) ? &new_hw_constraints_clocks : &old_hw_constraints_clocks); return 0;}static int snd_es18xx_capture_open(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; es18xx_t *chip = snd_pcm_substream_chip(substream); if (chip->playback_b_substream) return -EAGAIN; if ((chip->caps & ES18XX_DUPLEX_MONO) &&
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?