Android音频驱动-ASOC之PCM Open
来源:互联网 发布:象棋软件排行 编辑:程序博客网 时间:2024/05/20 02:23
status_t AudioALSAPlaybackHandlerBase::openPcmDriver(const unsigned int device){ mPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(), device, PCM_OUT | PCM_MONOTONIC, &mConfig); return NO_ERROR;}struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config){ struct pcm *pcm; struct snd_pcm_info info; struct snd_pcm_hw_params params; struct snd_pcm_sw_params sparams; char fn[256]; int rc; pcm = calloc(1, sizeof(struct pcm)); pcm->config = *config; snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, flags & PCM_IN ? 'c' : 'p'); pcm->flags = flags; pcm->fd = open(fn, O_RDWR); ......}//在创建alsa主设备时设置了文件操作对象,PCM设备都是alsa的从设备,共享一个驱动,打开次设备时会调用主设备的open函数/*static const struct file_operations snd_fops ={ .owner = THIS_MODULE, .open = snd_open, .llseek = noop_llseek,};*/static int snd_open(struct inode *inode, struct file *file){ unsigned int minor = iminor(inode); struct snd_minor *mptr = NULL; const struct file_operations *new_fops; int err = 0; mptr = snd_minors[minor]; new_fops = fops_get(mptr->f_ops); replace_fops(file, new_fops); if (file->f_op->open) err = file->f_op->open(inode, file); return err;}//注册PCM设备时设置了PCM设备的文件操作对象/*const struct file_operations snd_pcm_f_ops[2] = { { .owner = THIS_MODULE, .write = snd_pcm_write, .aio_write = snd_pcm_aio_write, .open = snd_pcm_playback_open, .release = snd_pcm_release, .llseek = no_llseek, .poll = snd_pcm_playback_poll, .unlocked_ioctl = snd_pcm_playback_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, .get_unmapped_area = snd_pcm_get_unmapped_area, }, { .owner = THIS_MODULE, .read = snd_pcm_read, .aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, .llseek = no_llseek, .poll = snd_pcm_capture_poll, .unlocked_ioctl = snd_pcm_capture_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, .get_unmapped_area = snd_pcm_get_unmapped_area, }};*/static int snd_pcm_playback_open(struct inode *inode, struct file *file){ struct snd_pcm *pcm; int err = nonseekable_open(inode, file); pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK); err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); return err;}void *snd_lookup_minor_data(unsigned int minor, int type){ struct snd_minor *mreg; void *private_data; if (minor >= ARRAY_SIZE(snd_minors)) return NULL; mreg = snd_minors[minor]; if (mreg && mreg->type == type) { private_data = mreg->private_data; if (private_data && mreg->card_ptr) get_device(&mreg->card_ptr->card_dev); } else private_data = NULL; return private_data;}static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream){ int err; err = snd_card_file_add(pcm->card, file);//将file加入到card的files链表进行管理 while (1) { err = snd_pcm_open_file(file, pcm, stream); } return err;}static int snd_pcm_open_file(struct file *file, struct snd_pcm *pcm, int stream){ struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; int err; err = snd_pcm_open_substream(pcm, stream, file, &substream); pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); pcm_file->substream = substream;//将打开的substream保存在pcm_file中 if (substream->ref_count == 1) { substream->file = pcm_file; substream->pcm_release = pcm_release_private; } file->private_data = pcm_file;//file获得打开的substream return 0;}//打开pcm所属的substream,需要使用substream->ops操作函数int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file, struct snd_pcm_substream **rsubstream){ struct snd_pcm_substream *substream; int err; err = snd_pcm_attach_substream(pcm, stream, file, &substream);//获取pcm的substream err = snd_pcm_hw_constraints_init(substream);//初始化pcm硬件约束 if ((err = substream->ops->open(substream)) < 0)//调用substream的回调函数open goto error; substream->hw_opened = 1; err = snd_pcm_hw_constraints_complete(substream);//设置pcm硬件约束 *rsubstream = substream; return 0;}int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file, struct snd_pcm_substream **rsubstream){ struct snd_pcm_str * pstr; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; struct snd_ctl_file *kctl; struct snd_card *card; int prefer_subdevice = -1; size_t size; *rsubstream = NULL; pstr = &pcm->streams[stream]; card = pcm->card; list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == task_pid(current)) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) break; } } switch (stream) { case SNDRV_PCM_STREAM_PLAYBACK: if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { if (SUBSTREAM_BUSY(substream)) return -EAGAIN; } } break; case SNDRV_PCM_STREAM_CAPTURE: if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { if (SUBSTREAM_BUSY(substream)) return -EAGAIN; } } break; default: return -EINVAL; } if (file->f_flags & O_APPEND) { if (prefer_subdevice < 0) { if (pstr->substream_count > 1) return -EINVAL; /* must be unique */ substream = pstr->substream; } else { for (substream = pstr->substream; substream; substream = substream->next) if (substream->number == prefer_subdevice) break; } substream->ref_count++; *rsubstream = substream; return 0; } if (prefer_subdevice >= 0) { for (substream = pstr->substream; substream; substream = substream->next) if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) goto __ok; } for (substream = pstr->substream; substream; substream = substream->next) if (!SUBSTREAM_BUSY(substream)) break; __ok: runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)); runtime->status = snd_malloc_pages(size, GFP_KERNEL); memset((void*)runtime->status, 0, size); size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)); runtime->control = snd_malloc_pages(size, GFP_KERNEL); memset((void*)runtime->control, 0, size); runtime->status->state = SNDRV_PCM_STATE_OPEN; substream->runtime = runtime; substream->private_data = pcm->private_data; substream->ref_count = 1; substream->pid = get_pid(task_pid(current)); pstr->substream_opened++; *rsubstream = substream; return 0;}
在创建pcm设备时已经调用snd_pcm_set_ops函数设置了substream->ops,在打开pcm的时候需要调用substream的ops->open函数
static int soc_pcm_open(struct snd_pcm_substream *substream){ struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; const char *codec_dai_name = "multicodec"; int i, ret = 0; /* startup the audio subsystem */ if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai);//调用cpu dai driver的startup } if (platform->driver->ops && platform->driver->ops->open) { ret = platform->driver->ops->open(substream);//调用platform driver的open } for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai);//调用codec dai driver的startup } } if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream);//调用dai link的startup,没有实现 } /* Check that the codec and cpu DAIs are compatible */ soc_pcm_init_runtime_hw(substream);//检测codec和cup dai的兼容性 return ret;}
cpu dai driver、platform driver、codec dai driver的具体实现
static int multimedia_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai){ snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_sample_rates); return 0;}static int mtk_pcm_I2S0dl1_open(struct snd_pcm_substream *substream){ int ret = 0; struct snd_pcm_runtime *runtime = substream->runtime; AfeControlSramLock(); if (GetSramState() == SRAM_STATE_FREE) { mtk_I2S0dl1_hardware.buffer_bytes_max = GetPLaybackSramFullSize(); mPlaybackSramState = SRAM_STATE_PLAYBACKFULL; SetSramState(mPlaybackSramState); } else { mtk_I2S0dl1_hardware.buffer_bytes_max = GetPLaybackDramSize(); mPlaybackSramState = SRAM_STATE_PLAYBACKDRAM; } AfeControlSramUnLock(); if (mPlaybackSramState == SRAM_STATE_PLAYBACKDRAM) AudDrv_Emi_Clk_On(); runtime->hw = mtk_I2S0dl1_hardware; AudDrv_Clk_On(); memcpy((void *)(&(runtime->hw)), (void *)&mtk_I2S0dl1_hardware , sizeof(struct snd_pcm_hardware)); pI2S0dl1MemControl = Get_Mem_ControlT(Soc_Aud_Digital_Block_MEM_DL1); ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_sample_rates); return 0;}static int mt63xx_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *Daiport){ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && substream->runtime->rate) { mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] = substream->runtime->rate; } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && substream->runtime->rate) { mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC] = substream->runtime->rate; } return 0;}
阅读全文
0 0
- Android音频驱动-ASOC之PCM Open
- Android音频驱动-ASOC之PCM Prepare
- Android音频驱动-ASOC之PCM Write
- Android音频驱动-ASOC之Control Open
- Android音频驱动-ASOC之PCM Device创建
- Android音频驱动-ASOC之PCM HW Params
- Android音频驱动-ASOC之Machine
- Android音频驱动-ASOC之Codec
- Android音频驱动-ASOC之Platform
- Android音频驱动-ASOC之CPU DAI
- Android音频驱动-ASOC之常用对象
- Android音频驱动-ASOC之DAMP
- Android音频驱动-ASOC之Sound Card注册
- Android音频驱动-ASOC之Sound Card创建
- Android音频驱动-ASOC之主&从设备号
- Android音频驱动-ASOC之创建设备节点
- Android音频驱动-ASOC之Control Device创建
- Linux音频驱动之ASoC驱动架构
- Android音频驱动-ASOC之PCM Device创建
- Java GUI:图形用户界面三剑客相比拼
- Q:前端canvas标签的内容传递到后台保存为图片时出现无法正常显示的问题
- Python之常见问题和常见注意事项
- 基本数据结构:栈(stack)
- Android音频驱动-ASOC之PCM Open
- hiho一下,第165周 题目1 : 分隔相同字符
- VLC全部参数,libvlc_new函数参数,VLC SDK开发
- 大规模知识图谱的构建
- html学习12-内容丰富—图像
- esplorer v0.2.0 中文版
- (lintcode)第13题字符串的查找
- In function `lcd_draw_circle': lcd.c:(.text+0x2d8): undefined reference to `__aeabi_idiv' lcd
- 程序员的自我修养3