alsa声卡dev-snd-pcmC0D0p的open打开流程_第1页
alsa声卡dev-snd-pcmC0D0p的open打开流程_第2页
alsa声卡dev-snd-pcmC0D0p的open打开流程_第3页
alsa声卡dev-snd-pcmC0D0p的open打开流程_第4页
alsa声卡dev-snd-pcmC0D0p的open打开流程_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

alsa声卡/dev/snd/pcmC0D0p的open打开流程原文地址:/space.php?uid=20564848&do=blog&cuid=2116725aplay.c= main= snd_pcm_open(&handle, pcm_name, stream, open_mode); / 打开一路pcm,刷新config配置如果是default,同时type等于SND_CONFIG_TYPE_COMPOUND那么这里对应emptystatic const char *const build_in_pcms = adpcm, alaw, copy, dmix, file, hooks, hw, ladspa, lfloat, linear, meter, mulaw, multi, null, empty, plug, rate, route, share, shm, dsnoop, dshare, asym, iec958, softvol, mmap_emul, NULL;_snd_pcm_empty_open和snd_pcm_open_named_slave= snd_pcm_open_conf(pcmp, name, root, conf, stream, mode);= open_func = snd_dlobj_cache_lookup(open_name);将获得lib库中_snd_pcm_empty_open函数 所以open_func将等于_snd_pcm_empty_open _snd_pcm_empty_open _snd_pcm_asym_open _snd_pcm_plug_open _snd_pcm_softvol_open _snd_pcm_dmix_open _snd_pcm_hw_open = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, mode | (nonblock ? SND_PCM_NONBLOCK : 0), 0, sync_ptr_ioctl);= snd_ctl_hw_openfilename等于/dev/snd/controlC0= snd_open_device(filename, fmode); ctl-ops = &snd_ctl_hw_ops; ctl-private_data = hw; ctl-poll_fd = fd; *handle = ctl;filename等于/dev/snd/pcmC0D0p= fd = snd_open_device(filename, fmode);= return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl);= snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode); pcm-ops = &snd_pcm_hw_ops; pcm-fast_ops = &snd_pcm_hw_fast_ops;static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) snd_pcm_hw_t *hw = pcm-private_data; void *ptr; int err; if (hw-sync_ptr = NULL) / 如果还没有mmap,那么执行mmap映射内核空间驱动使用的声音缓冲区 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, hw-fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); if (ptr = MAP_FAILED | ptr = NULL) err = -errno; SYSMSG(control mmap failed); return err; hw-mmap_control = ptr; / 声卡驱动头部填充了一个结构体sndrv_pcm_mmap_control,类似qvfb显示原理./ struct sndrv_pcm_mmap_control / sndrv_pcm_uframes_t appl_ptr; /* RW: appl ptr (0.boundary-1) */ sndrv_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ ; else hw-mmap_control-avail_min = 1; snd_pcm_set_appl_ptr(pcm, &hw-mmap_control-appl_ptr, hw-fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); return 0;snd_pcm_mmap switch (i-type) case SND_PCM_AREA_MMAP: / 表示为数据区分配驱动内存,在snd_pcm_hw_channel_info中设置了type ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i-u.mmap.fd, i-u.mmap.offset);/*mmap= snd_pcm_mmap_data= snd_pcm_default_mmap/ mmap the DMA buffer on RAMstatic int snd_pcm_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) area-vm_ops = &snd_pcm_vm_ops_data; / vma操作函数,当应用程序向该area读写不存在的内存数据时, area-vm_private_data = substream; / 将执行snd_pcm_vm_ops_data中的fault / 函数snd_pcm_mmap_data_fault进一步以页为单位申请内存空间,所以如果用户程序需要64k,那么将执行16次,每次申请4k空间luther.gliethttp. area-vm_flags |= VM_RESERVED; atomic_inc(&substream-mmap_count); return 0;*/ if (ptr = MAP_FAILED) SYSERR(mmap failed); return -errno; i-addr = ptr;= snd_pcm_mmap_controlstatic int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) struct snd_pcm_runtime *runtime; long size; if (!(area-vm_flags & VM_READ) return -EINVAL; runtime = substream-runtime; size = area-vm_end - area-vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control) return -EINVAL; area-vm_ops = &snd_pcm_vm_ops_control; / 当对( area-vm_start,area-vm_end)之间空间操作,发生 area-vm_private_data = substream; / 缺页时,内核将调用该vm_ops方法来处理fault异常, area-vm_flags |= VM_RESERVED; / 进而执行snd_pcm_mmap_control_fault申请1个page空间 return 0;= writei_func = snd_pcm_writei;= playback(argvoptind+);= playback_go(fd, dtawave, pbrec_count, FORMAT_WAVE, name);= pcm_write(audiobuf, l);= writei_func(handle, data, count);就是调用上面的snd_pcm_writei= snd_pcm_writei= _snd_pcm_writei= pcm-fast_ops-writei(pcm-fast_op_arg, buffer, size);= snd_pcm_plugin_writei= snd_pcm_write_areas(pcm, areas, 0, size, snd_pcm_plugin_write_areas);= avail = snd_pcm_avail_update(pcm); / 获取可用缓冲区位置偏移索引值= func()就是snd_pcm_plugin_write_areas函数发送1024帧音频数据,一帧对应一次完整采样,比如stereo立体声,24bits量化,那么这里一帧对应3*2字节数据,即一次完整采样所需空间luther.gliethttp.= plugin-write(pcm, areas, offset, frames, slave_areas, slave_offset, &slave_frames);即调用snd_pcm_linear_write_areas函数将areas中的frames频数据拷贝到slave_areas内存区= pcm-fast_ops-mmap_commit(pcm-fast_op_arg, offset, frames);= snd_pcm_dmix_mmap_commit= snd_pcm_dmix_sync_area/* synchronize shm ring buffer with hardware*/static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)= /* add sample areas here */ src_areas = snd_pcm_mmap_areas(pcm); dst_areas = snd_pcm_mmap_areas(dmix-spcm); / 添加= mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); if (dmix-interleaved) / 可以将缓冲中的音频数据填充到硬件中luther.gliethttp /* * process all areas in one loop * it optimizes the memory accesses for this case */ do_mix_areas(size * channels, (unsigned char *)dst_areas0.addr + sample_size * dst_ofs * channels, (unsigned char *)src_areas0.addr + sample_size * src_ofs * channels, dmix-u.dmix.sum_buffer + dst_ofs * channels, sample_size, sample_size, sizeof(signed int); return; = do_mix_areas(size * channels, (unsigned char *)dst_areas0.addr + sample_size * dst_ofs * channels, (unsigned char *)src_areas0.addr + sample_size * src_ofs * channels, dmix-u.dmix.sum_buffer + dst_ofs * channels, sample_size, sample_size, sizeof(signed int);这里的do_mix_areas在i386中,使用下面完全用汇编实现的拷贝函数MIX_AREAS_32完成数据从src到dst的快速拷贝,每拷贝一次,声卡就会发出一点声音luther.gliethttp/* for plain i386, 32-bit version (24-bit resolution)*/static void MIX_AREAS_32(unsigned int size, volatile signed int *dst, signed int *src, volatile signed int *sum, size_t dst_step, size_t src_step, size_t sum_step)_snd_pcm_asym_open_snd_pcm_dmix_opensnd_pcm_plugin_avail_update= snd_pcm_avail_update(slave);= pcm-fast_ops-avail_update(pcm-fast_op_arg);= snd_pcm_dmix_avail_update= snd_pcm_mmap_playback_avail(pcm);alsa_sound_init#define CONFIG_SND_MAJOR 116 /* standard configuration */static int major = CONFIG_SND_MAJOR;module_init(alsa_sound_init)alsa_sound_init= register_chrdev(major, alsa, &snd_fops) / 主设备号为116的所有设备都为alsa设备,节点方法集为snd_fopsstatic const struct file_operations snd_fops = / alsa的设备名为pcmC0D1c或pcmC0D1p等luther.gliethttp. .owner = THIS_MODULE, .open = snd_open;snd_open= _snd_open(inode, file);= _snd_open unsigned int minor = iminor(inode); mptr = snd_minorsminor; file-f_op = fops_get(mptr-f_ops); file-f_op-open(inode, file);const struct file_operations snd_pcm_f_ops2 = / alsa使用到的SNDRV_PCM_STREAM_PLAYBACK放音方法集luther.gliethttp .owner = THIS_MODULE, .write = snd_pcm_write, .aio_write = snd_pcm_aio_write, .open = snd_pcm_playback_open, .release = snd_pcm_release, .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 = dummy_get_unmapped_area, , / alsa使用到的SNDRV_PCM_STREAM_CAPTURE录音方法集luther.gliethttp .owner = THIS_MODULE, .read = snd_pcm_read, .aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, .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 = dummy_get_unmapped_area, ;=snd_intel8x0_probe= snd_intel8x0_create= request_irq(pci-irq, snd_intel8x0_interrupt, IRQF_SHARED,card-shortname, chip)snd_intel8x0_interruptsnd_intel8x0_updatesnd_open= snd_pcm_playback_open= snd_pcm_open= snd_pcm_open_file= snd_pcm_open_substream= substream-ops-open(substream)即snd_intel8x0_playback_ops.open= snd_intel8x0_playback_open= snd_intel8x0_pcm_openstatic int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream-runtime; int err; ichdev-substream = substream; runtime-hw = snd_intel8x0_stream; / 声卡配置硬件信息luther.gliethttp runtime-hw.rates = ichdev-pcm-rates; snd_pcm_limit_hw_rates(runtime); if (chip-device_type = DEVICE_SIS) runtime-hw.buffer_bytes_max = 64*1024; runtime-hw.period_bytes_max = 64*1024; if (err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS) private_data = ichdev; return 0;ioctl(SNDRV_PCM_IOCTL_HW_PARAMS)= snd_pcm_f_ops.unlocked_ioctl即:snd_pcm_playback_ioctl= snd_pcm_playback_ioctl= snd_pcm_playback_ioctl1= snd_pcm_common_ioctl1 case SNDRV_PCM_IOCTL_HW_PARAMS: return snd_pcm_hw_params_user(substream, arg);= snd_pcm_hw_params_user= snd_pcm_hw_params= substream-ops-hw_params即snd_intel8x0_playback_ops.hw_params= snd_intel8x0_hw_params= snd_ac97_pcm_open(ichdev-pcm, params_rate(hw_params), params_channels(hw_params), ichdev-pcm-rdbl.slots);ioctl(SNDRV_PCM_IOCTL_PREPARE)= snd_pcm_playback_ioctl= snd_pcm_playback_ioctl1= snd_pcm_common_ioctl1= snd_pcm_prepare / prepare the PCM substream to be triggerable= snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, f_flags);= snd_pcm_action_single(ops, substream, state); ops-pre_action(substream, state); ops-do_action(substream, state); ops-post_action(substream, state); 上面ops就是之前提到的snd_pcm_action_prepare= snd_pcm_do_prepare调用snd_pcm_do_reset(substream, 0);复位 substream-ops-prepare(substream);即snd_intel8x0_playback_ops.prepare= snd_intel8x0_pcm_preparestatic int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream-runtime; struct ichdev *ichdev = get_ichdev(substream); ichdev-physbuf = runtime-dma_addr; / dma缓冲区地址 ichdev-size = snd_pcm_lib_buffer_bytes(substream); / 将帧缓冲大小转为字节空间大小luther.gliethttp ichdev-fragsize = snd_pcm_lib_period_bytes(substream); if (ichdev-ichd = ICHD_PCMOUT) snd_intel8x0_setup_pcm_out(chip, runtime); / 为play模式设置ac97寄存器luther.gliethttp if (chip-device_type = DEVICE_INTEL_ICH4) ichdev-pos_shift = (runtime-sample_bits 16) ? 2 : 1; snd_intel8x0_setup_periods(chip, ichdev); / 设置PCI总线ac97的bank地址空间luther.gliethttp return 0;= snd_intel8x0_setup_pcm_outstatic void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, struct snd_pcm_runtime *runtime) unsigned int cnt; int dbl = runtime-rate 48000;/ 一共有如下几种设备:enum DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE ; spin_lock_irq(&chip-reg_lock); switch (chip-device_type) case DEVICE_ALI: cnt = igetdword(chip, ICHREG(ALI_SCR); cnt &= ICH_ALI_SC_PCM_246_MASK; if (runtime-channels = 4 | dbl) cnt |= ICH_ALI_SC_PCM_4; else if (runtime-channels = 6) cnt |= ICH_ALI_SC_PCM_6; iputdword(chip, ICHREG(ALI_SCR), cnt); break; case DEVICE_SIS: cnt = igetdword(chip, ICHREG(GLOB_CNT); cnt &= ICH_SIS_PCM_246_MASK; if (runtime-channels = 4 | dbl) cnt |= ICH_SIS_PCM_4; else if (runtime-channels = 6) cnt |= ICH_SIS_PCM_6; iputdword(chip, ICHREG(GLOB_CNT), cnt); break; default: cnt = igetdword(chip, ICHREG(GLOB_CNT); cnt &= (ICH_PCM_246_MASK | ICH_PCM_20BIT); if (runtime-channels = 4 | dbl) cnt |= ICH_PCM_4; else if (runtime-channels = 6) cnt |= ICH_PCM_6; else if (runtime-channels = 8) cnt |= ICH_PCM_8; if (chip-device_type = DEVICE_NFORCE) /* reset to 2ch once to keep the 6 channel data in alignment, * to start from Front Left always */ if (cnt & ICH_PCM_246_MASK) iputdword(chip, ICHREG(GLOB_CNT), cnt & ICH_PCM_246_MASK); spin_unlock_irq(&chip-reg_lock); msleep(50); /* grrr. */ spin_lock_irq(&chip-reg_lock); else if (chip-device_type = DEVICE_INTEL_ICH4) if (runtime-sample_bits 16) cnt |

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论