📄 au88x0_pcm.c
字号:
/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Vortex PCM ALSA driver. * * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet. * It remains stuck,and DMA transfers do not happen. */#include <sound/asoundef.h>#include <sound/driver.h>#include <linux/time.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include "au88x0.h"#define VORTEX_PCM_TYPE(x) (x->name[40])/* hardware definition */static snd_pcm_hardware_t snd_vortex_playback_hw_adb = { .info = (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5000, .rate_max = 48000, .channels_min = 1,#ifdef CHIP_AU8830 .channels_max = 4,#else .channels_max = 2,#endif .buffer_bytes_max = 0x10000, .period_bytes_min = 0x1, .period_bytes_max = 0x1000, .periods_min = 2, .periods_max = 32,};#ifndef CHIP_AU8820static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = { .info = (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 5000, .rate_max = 48000, .channels_min = 1, .channels_max = 1, .buffer_bytes_max = 0x10000, .period_bytes_min = 0x100, .period_bytes_max = 0x1000, .periods_min = 2, .periods_max = 64,};#endifstatic snd_pcm_hardware_t snd_vortex_playback_hw_spdif = { .info = (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 32000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x10000, .period_bytes_min = 0x100, .period_bytes_max = 0x1000, .periods_min = 2, .periods_max = 64,};#ifndef CHIP_AU8810static snd_pcm_hardware_t snd_vortex_playback_hw_wt = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x10000, .period_bytes_min = 0x0400, .period_bytes_max = 0x1000, .periods_min = 2, .periods_max = 64,};#endif/* open callback */static int snd_vortex_pcm_open(snd_pcm_substream_t * substream){ vortex_t *vortex = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; /* Force equal size periods */ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; /* Avoid PAGE_SIZE boundary to fall inside of a period. */ if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {#ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { runtime->hw = snd_vortex_playback_hw_a3d; }#endif if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { runtime->hw = snd_vortex_playback_hw_spdif; switch (vortex->spdif_sr) { case 32000: runtime->hw.rates = SNDRV_PCM_RATE_32000; break; case 44100: runtime->hw.rates = SNDRV_PCM_RATE_44100; break; case 48000: runtime->hw.rates = SNDRV_PCM_RATE_48000; break; } } if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) runtime->hw = snd_vortex_playback_hw_adb; substream->runtime->private_data = NULL; }#ifndef CHIP_AU8810 else { runtime->hw = snd_vortex_playback_hw_wt; substream->runtime->private_data = NULL; }#endif return 0;}/* close callback */static int snd_vortex_pcm_close(snd_pcm_substream_t * substream){ //vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) substream->runtime->private_data; // the hardware-specific codes will be here if (stream != NULL) { stream->substream = NULL; stream->nr_ch = 0; } substream->runtime->private_data = NULL; return 0;}/* hw_params callback */static intsnd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) (substream->runtime->private_data); snd_pcm_sgbuf_t *sgbuf; int err; // Alloc buffer memory. err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) { printk(KERN_ERR "Vortex: pcm page alloc failed!\n"); return err; } //sgbuf = (snd_pcm_sgbuf_t *) substream->runtime->dma_private; sgbuf = snd_pcm_substream_sgbuf(substream); /* printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), params_period_bytes(hw_params), params_channels(hw_params)); */ spin_lock_irq(&chip->lock); // Make audio routes and config buffer DMA. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { int dma, type = VORTEX_PCM_TYPE(substream->pcm); /* Dealloc any routes. */ if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, stream->type); /* Alloc routes. */ dma = vortex_adb_allocroute(chip, -1, params_channels(hw_params), substream->stream, type); if (dma < 0) { spin_unlock_irq(&chip->lock); return dma; } stream = substream->runtime->private_data = &chip->dma_adb[dma]; stream->substream = substream; /* Setup Buffers. */ vortex_adbdma_setbuffers(chip, dma, sgbuf, params_period_bytes(hw_params), params_periods(hw_params)); }#ifndef CHIP_AU8810 else { /* if (stream != NULL) vortex_wt_allocroute(chip, substream->number, 0); */ vortex_wt_allocroute(chip, substream->number, params_channels(hw_params)); stream = substream->runtime->private_data = &chip->dma_wt[substream->number]; stream->dma = substream->number; stream->substream = substream; vortex_wtdma_setbuffers(chip, substream->number, sgbuf, params_period_bytes(hw_params), params_periods(hw_params)); }#endif spin_unlock_irq(&chip->lock); return 0;}/* hw_free callback */static int snd_vortex_pcm_hw_free(snd_pcm_substream_t * substream){ vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) (substream->runtime->private_data); spin_lock_irq(&chip->lock); // Delete audio routes. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, stream->type); }#ifndef CHIP_AU8810 else { if (stream != NULL) vortex_wt_allocroute(chip, stream->dma, 0); }#endif substream->runtime->private_data = NULL; spin_unlock_irq(&chip->lock); return snd_pcm_lib_free_pages(substream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -