关键词不能为空

当前您在: 主页 > 英语 >

alsa声卡dev_snd_pcmC0D0p的open打开流程

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-03-03 22:10
tags:

-

2021年3月3日发(作者:manic)


alsa


声卡


/dev/snd/pcmC0D 0p



open



流程



< br>原文地址:


/?uid=20564848&do=blog&cuid=211 6725



aplay.c


==> main


==> snd_pcm_open(&handle, pcm_name, stream, open_mode); //


打开一路


pcm,


刷新


config


配置



如果是



同时


type


等于


SND_C ONFIG_TYPE_COMPOUND


那么这里对应



static const char *const build_in_pcms[] = {









NULL


};


_snd_pcm_ empty_open



snd_pcm_open_name d_slave


==> snd_pcm_open_conf(pcmp, name, root, conf, stream, mode);


==> open_func = snd_dlobj_cache_lookup(open_name);


将获得


lib


库中


_s nd_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_open


filename


等于



==> snd_open_device(filename, fmode);



ctl->ops = &snd_ctl_hw_ops;



ctl->private_data = hw;



ctl->poll_fd = fd;



*handle = ctl;


filename

< p>
等于



==> 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, , 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(





return err;




}




hw->mmap_control = ptr; //


声卡驱动头部填充了一个结构体


sndrv_pcm_m map_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


中设置


< p>
type





ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->,


i->);


/*


mmap


==> snd_pcm_mmap_data


==> snd_pcm_default_mmap


// mmap the DMA buffer on RAM


static 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


空间


[ttp].



area->vm_flags |= VM_RESERVED;



atomic_inc(&substream->mmap_count);



return 0;


}


*/





if (ptr == MAP_FAILED) {






SYSERR(






return -errno;





}





i->addr = ptr;




==> snd_pcm_mmap_control


static 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_mm ap_control_fault


申请


1


page



< br>



return 0;


}





==> writei_func = snd_pcm_writei;


==> playback(argv[optind++]);


==> 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_p cm_plugin_write_areas


函数发送


102 4


帧音频数据


,


一帧对应一次完整采样


,


比如


stereo

< br>立体声



,24bits


量化< /p>


,


那么这里一帧对应


3*2


字节数据


,


即一次完整采样所需空间


[ttp].


==> plugin->write(pcm, areas, offset, frames,







slave_areas, slave_offset, &slave_frames);


即调用


snd_pcm_l inear_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) { //


可以将缓冲中的音频数据填充到硬件中


[ttp]




/*




* process all areas in one loop




* it optimizes the memory accesses for this case




*/




do_mix_areas(size * channels,






(unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,






(unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,






dmix->_buffer + dst_ofs * channels,






sample_size,






sample_size,






sizeof(signed int));




return;



}


==> do_mix_areas(size * channels,






(unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,






(unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,






dmix->_buffer + dst_ofs * channels,






sample_size,






sample_size,






sizeof(signed int));


这里的


do_mix_areas



i386



,


使用下 面完全用汇编实现的拷贝函数


MIX_AREAS_32


完成数 据从


src



dst

< br>的快速拷贝


,


每拷贝一次


,< /p>


声卡就会发出一点声音


[ttp]


/*


*


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_open




snd_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,


//


主设 备号为


116


的所有设备都为


alsa


设备


,


节点


方 法集为


snd_fops


static const struct file_operations snd_fops =


// alsa


的设备名为


pcmC0 D1c



pcmC0D1p



[ttp].


{


.owner =


THIS_MODULE,


.open =


snd_open


};


snd_open


==> __snd_open(inode, file);


==> __snd_open

-


-


-


-


-


-


-


-



本文更新与2021-03-03 22:10,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/703564.html

alsa声卡dev_snd_pcmC0D0p的open打开流程的相关文章