http://blog.csdn.net/alien75/article/details/4656922

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驱动研究相关推荐

  1. linux 网卡驱动分析,基于linux下网卡驱动分析及实现技术研究

    摘    要 Linux技术是当前计算机技术中最大的一个热点,在我国以及全世界得到了迅猛的发展,被广泛的应用于嵌入式系统.服务器.网络系统.安全等领域.从而使得掌握在 Linux环境下的开发技术,成为 ...

  2. WINCE6.0下的 IMX51 AC97驱动 简述

    AC97驱动接说明 本驱动使用IMX51的 SSI接口支持的AC97接口,对外接支持AC97 2.0协议的UCB1400芯片. 本驱动能够实现全双工的PCM码率的播放.录制,同时支持多种采样率的PCM ...

  3. linux系统下的打印机驱动下载,方法论:Linux下如何驱动主流品牌打印机

    薄荷站长浸淫 Linux 桌面领域十余年,一直致力于 Linux 桌面系统的推广.对于桌面用户办公中必需的打印功能,薄荷站长也是有所研究.为了使新手朋友们少走弯路,薄荷站长介绍一下常见品牌打印机的 L ...

  4. linux安装ati工具,Linux下ATI驱动安装傻瓜安装方法

    Linux下ATI驱动安装傻瓜安装方法 发布时间:2006-01-04 12:58:15来源:红联作者:zz123 菜鸟我刚刚接触Debian不久(其实时间也不短了,但是没有深研究),在各位前辈的指导 ...

  5. matlab的svpwm逆变器,基于svpwm三相逆变器在matlab下的仿真研究.doc

    基于svpwm三相逆变器在matlab下的仿真研究.doc 基于SVPWM三相逆变器在MATLAB下的仿真研究摘要介绍了电压空间矢量脉宽调制控制算法的基本概念并简要介绍了利用多种实际矢量合成所需电压矢 ...

  6. Android AC97驱动杂记

    AC97驱动从设备加载开始,对于AC97核心的加载暂时不说. 以WM9713+S3C6410为例说明一个设备的加载并且驱动,并且实现应用的整个过程. 对于驱动整个驱动而言以这四个文件为主 1.wm97 ...

  7. 【驱动】linux下I2C驱动架构全面分析

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

  8. 【WinCE】SD card技术了解并WINCE下SDHC驱动开发(updated)

    SD Card Driver on ADS Summary 了解SD card. 1 WinCE 5.0下SD Stack. 6 Bus Driver 7 Host Controller Driver ...

  9. arduinowin7_Win7系统下Arduino驱动安装失败的解决方法

    近日有不少win7系统用户反映说碰到这样一个现象,就是在电脑中连接Arduino单片机的时候,就会提示Arduino驱动安装失败,遇到这样的问题要如何处理呢,针对这个情况,小编就给大家分享一下Win7 ...

最新文章

  1. 缓存穿透、并发和雪崩那些事
  2. [CODEVS 1050] 棋盘染色 2
  3. Linux sed删除文件注释行并删除空行
  4. 打印JVM配置参数的命令
  5. 快速构建Windows 8风格应用22-MessageDialog
  6. HDFS的文件副本机制
  7. 210224阶段三信号量、互斥锁
  8. 一文读懂前端与HTML5技术的区别!
  9. 如何从技术上成功预测比特币价格?
  10. leetcode(106)从中序遍历和后序遍历构建二叉树
  11. 利用SusuCMS快速创建网站(一)
  12. html 简单表格代码
  13. Visual Studio 2010下载 + 附破解方法
  14. Linux 系统设置图形界面启动和黑窗口启动
  15. 遥感道路提取的补充C-UNet: Complement UNet for Remote Sensing Road Extraction
  16. web上传图片到七牛云服务器
  17. deeplearning.ai课程作业:Recurrent Neural Networks- Course 5 Week3
  18. JAVA usb发卡器_USB模拟键盘输出发卡器
  19. oracle 日期类型是什么,oracle date日期类型 精析
  20. aopalliance.jar是什么?

热门文章

  1. 车用瞬态抑制二极管的特性及防护过程讲解
  2. 点位盘源码php,2020.10新版外汇微盘微交易 时间盘 点位盘白色版源码下载
  3. python中invalid argument_Python创建文件报错OSError:[Errno 22] Invalid argument处理
  4. InDesign 教程:如何编辑段落样式?
  5. (21)给出年、月、日,计算该日是该年的第几天
  6. 星冰乐java chips_揭秘 | 星巴克内部员工推荐隐藏菜单
  7. SNMPV1, V2, V3 Agent 配置 + NMS测试
  8. 发动机曲轴加工工艺与专用机床夹具设计(论文+CAD图纸+工序卡+过程卡+开题报告+任务书+翻译……)
  9. Android 夜间模式实现
  10. cad连接不同线段的端点_【CAD图形】】为什么CAD连续的图形无法连接成完整的多段线...