s3c2450下AC97驱动研究
来源:互联网 发布:淘宝网二手市场在哪 编辑:程序博客网 时间:2024/06/03 23:04
AC97驱动分析
总体而言,AC97驱动是wavedev结构的驱动,上层应用通过调用WAVEAPI函数,和驱动接口HandleWaveMessage进行交互,驱动根据传递的WIDM_XXX系列值进行操作。现在以Wince5自带的waverec例程进行分析
一、流程
1、初始化过程
这个是设备启动时,由设备管理器加载驱动。调用了WAV_Init、WAV_OPEN、WAV_CLOSE三个函数;传递WIDM_GETNUMDEVS、WODM_GETNUMDEVS、WODM_GETEXTDEVCAPS、WODM_OPEN、WODM_SETVOLUME共五个控制码,如果系统设置为有开机声音还会传递WODM_WRITE、WODM_UNPREPARE、WODM_CLOSE。
在WAV_INIT中会调用CreateHWContext创建全局硬件上下文,完成初始化GPIO、分配DMA内存、初始化AC97控制器和外部codec、创建输入/输出IST
2、录音过程
(1)WIDM_OPEN
(a)获取设备上下文:DeviceContext *pDeviceContext = g_pHWContext->GetInputDeviceContext(uDeviceId); ===> InputDeviceContext对象
(b)打开输入流:pDeviceContext->OpenStream;
第一步:创建输入流
pStreamContext = CreateStream(lpWOD); ===> InputStreamContext对象
父类DeviceContext的CreateStream为纯虚函数,它派生的的两个子类InputDeviceContext和OutputDeviceContext重载了此函数
InputDeviceContext的CreateStream只是创建了一个对象InputStreamContext
OutputDeviceContext的处理要复杂一点,它有CMidiStream、OutputStreamContextM8、OutputStreamContextM16、OutputStreamContextS8、OutputStreamContextS16五个子类,针对输入格式、声道、采样位数创建不同的子类
第二步:打开输入流
Result = pStreamContext->Open(this,lpWOD,dwFlags);
根据派生关系先隐式调用WaveStreamContext的Open,再显式调用StreamContext的Open。到这一步,录音的初始化基本完成。
(2)WIDM_PREPARE
无操作
(3)WIDM_ADDBUFFER
pStreamContext->QueueBuffer((LPWAVEHDR)dwParam1);
dwParam1对应的就是应用程序传递的参数(因不在同一地址空间,所以其地址是不一样的),将它加入到一个单链表中(具体说明见相关数据结构的第4点)
(4)WIDM_START
启动DMA输入:pStreamContext->Run();
m_pDeviceContext->StreamReadyToRender(this); ===> InputDeviceContext对象
g_pHWContext->StartInputDMA(); ===> 初次调用,在IST中每次TransferInputBuffers中会调用此函数(如果BytesTransferred为0则StopImputDMA)
第一步:DMA通道状态设置(开/关)
Codec_channel()
第二步:
m_InputDMAStatus = (DMA_DONEA | DMA_DONEB) & ~DMA_BIU;
第三步:配置DMA输入通道
InitInputDMA()
第四步:打开输入音量
AudioMute(DMA_CH_MIC, FALSE);
第五步:开始DMA输入
AUDIO_RESET_RECORD_POINTER();
SELECT_AUDIO_DMA_INPUT_BUFFER_A(); ===> 选择BUFFER_A做为DMA输入缓冲
Codec_channel();
AUDIO_IN_DMA_ENABLE(); ===> 设置DMA控制器使能DMA传输
SELECT_AUDIO_DMA_INPUT_BUFFER_B(); ===> 选择BUFFER_B做为DMA输入缓冲 ===> A为下次传输做准备,不让DMA空置停机
到这一步,DMA传输就绪,接下来就由IST等待中断事件并进行数据处理。
(5)WIDM_UNPREPARE
无操作
(6)WIDM_CLOSE
释放输入流:pStreamContext->Release();
m_pDeviceContext->DeleteStream(this); //引用计数为0才真正释放
3、HardwareContext的IST流程
(1)等待DMA中断事件产生
(2)根据m_InputDMAStatus判断是BUFFER_A还是BUFFER_B完成DMA传输,并切换到另一个缓冲做DMA传输
(3)AUDIO_IN_DMA_ENABLE(); ===> 发出新的DMA请求
(4)InputTransferred = TransferInputBuffers(m_InputDMAStatus); ===>这是个很重要的函数,将DMA收到的数据进行Render(插值运算转换采样率,AC97源采样率44100)
a)HardwareContext::TransferInputBuffer
b)DeviceContext::TransferBuffer
c)StreamContext::Render ===> 纯虚函数,实际调用WaveStreamContext::Render
d)StreamContext::GetNextBuffer ===> 子类都要调用此函数,目的是提高代码复用性
从StreamContext的单链表(具体说明见相关数据结构的第4点)取出一个LPWAVEHEAD(由QueueBuffer加入链表)获得成员lpData赋值给m_lpCurrData(具体说明见相关数据结构),并返回。
e)WaveStreamContext::Render2 ===> 纯虚函数,实际调用派生子类(详见相关数据结构中的说明)的函数。具体算法参见各子类的Render2(待深入研究)
将DMA中的数据render后放到m_lpCurrData中(LPWAVEHEADER),应用程序通过MM_WIN_DATA应该能从WAVEHEADER中获得此数据
(5)重复第(1)步
二、相关数据结构
1、全局硬件上下文
HardwareContext *g_pHWContext
2、设备上下文
派生关系:
InputDeviceContext <-- DeviceContext
OutputDeviceContext <-- DeviceContext
3、数据流上下文
派生关系:
InputStreamContext <-- WaveStreamContext <-- StreamContext
CMidiStream <-- StreamContext
OutputStreamContextM8(M16/S8/S16) <-- OutputStreamContext <-- WaveStreamContext <-- StreamContext
4、StreamContext的WAVEHDR单链表
LPWAVEHDR m_lpWaveHdrHead;
LPWAVEHDR m_lpWaveHdrCurrent;
LPWAVEHDR m_lpWaveHdrTail;
5、StreamContext的数据缓冲区指针
PBYTE m_lpCurrData; // position in current buffer
PBYTE m_lpCurrDataEnd; // end of current buffer
在调用QueueBuffer(WIDM_ADDBUFFER)的时候进行赋值,m_lpCurrData赋值是LPWAVEHDR中的lpData,也就是应用程序接收缓冲区首地址;m_lpCurrDataEnd赋值是应用程序接收缓冲区未地址
6、DeviceContext的linklist双向链表,管理流上下文对象
LIST_ENTRY m_StreamList; // List of streams rendering to/from this device
根据其成员Flink查找相应StreamContext对象(Flink对应StreamContext成员m_Link)
7、DMA通道状态设置
BOOL m_InputDMARunning;
BOOL m_OutputDMARunning;
8、DMA控制器状态记录
//----- Used to track DMA controllers status -----
#define DMA_CLEAR 0x00000000
#define DMA_DONEA 0x00000008
#define DMA_STRTA 0x00000010
#define DMA_DONEB 0x00000020
#define DMA_STRTB 0x00000040
#define DMA_BIU 0x00000080 // Determines which buffer is in use: (A=0, B=1)
DWORD m_InputDMAStatus; // Input DMA channel's status
9、DMA缓冲区页面大小(输入/输出都有两个缓冲区A和B进行双缓冲操作)
#define AUDIO_DMA_PAGE_SIZE (4096)
10、DMA缓冲区接收数据大小数组
m_InBytes[IN_BUFFER_A];
m_InBytes[IN_BUFFER_B];
11、DMA接收缓冲区A/B首地址
PBYTE m_Input_pbDMA_PAGES[2];
12、IST中断事件
HANDLE m_hAudioInterruptInput;
三、容易混淆的概念
1、WIDM_XXX/WODM_XXX、WOM_XXX/WIM_XXX、MM_WOM_XXX/MM_WIM_XXX的区别
(1)在waveapi通过DeviceIoControl调用驱动的WAV_IOControl时传递的参数
(2)传递给回调函数waveInProc或waveOutProc的消息,回调函数是waveInOpen或waveOutOpen的参数
(3)传递给窗口的消息。就是说要基于窗口类的程序才有用,可以认此种情况不能用于控制台程序,第二种情况则可以
- s3c2450下AC97驱动研究
- s3c2450下AC97驱动研究
- linux下ac97声卡的alsa驱动方法
- WINCE6.0下的 IMX51 AC97驱动 简述
- AC97+UCB1400驱动
- Android AC97驱动杂记
- S3C6410裸机AC97驱动
- AC97声卡的驱动安装
- Tiny210加入AC97驱动Wm9713
- SB600 AC97 CODEC 声卡驱动解决方案
- s5pv210开发板linux ac97 alsa驱动
- wince下LCD16032驱动研究(ST7920)
- Linux下USB摄像头驱动研究
- 基于S3C2450 + WINCE的背光驱动及背光亮度调节应用程序移植详解之驱动篇
- Linux驱动的开发与移值——为Tiny210加入AC97驱动Wm9713
- Linux驱动的开发与移值——为Tiny210加入AC97驱动Wm9713
- 基于S3C2450 + WINCE的背光驱动及背光亮度调节应用程序移植详解之驱动篇[原创]
- AC97声卡
- asp.net 实现邮箱验证(注册的时候发送邮件激活链接的那种)
- windows 2003 Windows无法访问指定设备路径或文件,您可能没有合适的权限访问这个项目
- 查处数据库所有可编辑性数据
- 无法解析的外部符号的 3 种可能
- Linux 全屏幕编辑器VI
- s3c2450下AC97驱动研究
- myeclipse tomcat jsp servlet javabean的学习(持续更新)
- 精妙SQL語句
- javaScript随笔
- 基于tm-extractor的Word文档内容搜索软件开发
- 选中下拉菜单的一项后,下面的两个文本框的内容随之改变
- CRM词汇宝典
- C语言中localtime函数
- 在线修改redo.log文件的大小