WinDriver教程.docx
《WinDriver教程.docx》由会员分享,可在线阅读,更多相关《WinDriver教程.docx(9页珍藏版)》请在冰豆网上搜索。
WinDriver教程
一、如何用windrive打开、关闭设备以及查看设备的信息
1.所有有关的WD_API在安装后的相关目录下可以找到,建议打印出来,仔细看下。
2.打开、关闭设备与查看相应信息:
HANDLEm_hPex;
DWORDBus,Slot,Fun,Interrupt;
DWORDBaseAddrCS0,BaseAddrCS1,BaseAddrCS2,BaseAddrCS3;
DWORDRangeAddrCS0,RangeAddrCS1,RangeAddrCS2,RangeAddrCS3;
//打开设备:
WD_LICENSElic;
m_hPex=WD_Open();
if(m_hPex==INVALID_HANDLE_VALUE){
str="INVALID_HANDLE_VALUE";}
else
{
//重新注册wd,去除过期限制
strcpy(lic.cLicense,"你的注册号");
WD_License(m_hPex,&lic);}
//检查WD版本
WD_VERSIONver;
BZERO(ver);
WD_Version(m_hPex,&ver);
if(ver.dwVer{str="WindriverOverdue";}WD_PCI_SCAN_CARDSpciScan;WD_PCI_SLOTpciSlot;BZERO(pciScan);//以PEX8311为例pciScan.searchId.dwVendorId=0x10b5;pciScan.searchId.dwDeviceId=0x86e1;WD_PciScanCards(m_hPex,&pciScan);if(pciScan.dwCards>0){pciSlot=pciScan.cardSlot[0];WD_PCI_CARD_INFOpciCardInfo;WD_CARDCard;BZERO(pciCardInfo);pciCardInfo.pciSlot=pciSlot;WD_PciGetCardInfo(m_hPex,&pciCardInfo);if(pciCardInfo.Card.dwItems!=0){Card=pciCardInfo.Card;}else{str="Pcicard=0";}WD_CARD_REGISTERcardReg;//Card.Item[0]PC机基本端口操作//Card.Item[1]中断信息BZERO(cardReg);cardReg.Card=Card;cardReg.fCheckLockOnly=FALSE;WD_CardRegister(m_hPex,&cardReg);if(cardReg.hCard==0){str="cardReg=0";}str="opensuccessfully";//取得当前设备信息并显示Interrupt=Card.Item[1].I.Int.dwInterrupt);Bus=pciScan.cardSlot[0].dwBus;Slot=pciScan.cardSlot[0].dwSlot;Fun=pciScan.cardSlot[0].dwFunction;//CS0-CS3的地址映射信息BaseAddrCS0=Card.Item[2].I.Mem.dwPhysicalAddr;RangeAddrCS0=Card.Item[2].I.Mem.dwBytes;BaseAddrCS1=Card.Item[3].I.IO.dwAddr;RangeAddrCS1=Card.Item[3].I.Mem.dwBytes;BaseAddrCS2=Card.Item[4].I.Mem.dwPhysicalAddr;RangeAddrCS2=Card.Item[4].I.Mem.dwBytes;BaseAddrCS3=Card.Item[5].I.Mem.dwPhysicalAddr;RangeAddrCS3=Card.Item[5].I.Mem.dwBytes;else{str="OpenFailed";WD_Close(m_hPex);}AfxMessageBox(str);注:Card.Item[0-5]就是DEVICE/IO/MEM映射的地方,这里得到的值和windrivewizard里看到的是一样的。二、设备的读写操作1.写操作WD_TRANSFERtrans;BZERO(trans);trans.cmdTrans=WP_BYTE;//(WORD/DWORD)trans.dwPort=BaseAddrCS0;//可为其它的映射基地址trans.Data.Byte=0x00;//需要写的数据WD_Transfer(m_hPex,&trans);2.读操错WD_TRANSFERtrans;BZERO(trans);trans.cmdTrans=RP_BYTE;//(WORD/DWORD)trans.dwPort=BaseAddrCS1;//可为其它的映射基地址WD_Transfer(m_hPex,&trans);returntrans.Data.Bytes;三、其它有关windriver对寄存器的操作要用到WDC_***函数,还有DMA操作在(二)中阐述。三、寄存器的读写寄存器的读写用到一个非常好用的函数WD_PciConfigDump();具体的参数定义参照WD的API手册。WD_PCI_CONFIG_DUMPpciConfig;DWORDdwStatus;WORDarBuffer[2];BZERO(pciConfig);pciConfig.pciSlot.dwBus=Bus;pciConfig.pciSlot.dwSlot=Slot;pciConfig.pciSlot.dwFunction=Fun;pciConfig.pBuffer=arBuffer;pciConfig.dwBytes=sizeof(arBuffer);pciConfig.fIsRead=TRUE;pciConfig.dwOffset=每次累加4WD_PciConfigDump(m_hPex,&pciConfig);四、数据的块操作DWORDdataBuffer[8192];WD_TRANSFERtrans;*****************trans.Data.pBuffer=dataBuffer;利用WD_Transfer()函数来完成数据的块操作。五、DMA控制WinDriver为提供了一组API函数,但是其提供的DMA函数不是基于突发方式的,并且是以查询方式来检测DMA是否结束,比较适用于一次DMA读写。因此需要对其提供的DMAAPI函数及中断相关的函数进行改写,即在DMAOpen()函数中,需对DMAMODE寄存器的本地突发使能位(BIT8)与BTERM输入使能位(BIT7)置位,否则,DMA操作只能完成一个双字的突发传输,只有将此二位置1后,才能完成指定长度的DMA传输。因为传输量超过4KB,所以要置为分散/聚拢(scatter/gather)模式(BIT9),同时使能DMA中断完成位(BIT10)与DMA通道0中断选择位(BIT17)。重写DMA启动函数DMAStart(),设置每次DMA传输所需的PCI地址(主机物理内存地址)、本地地址、传输大小、传输方向等,并置DMA启动位。这样每次数据捕获满中断到来,启动DMA传输时,只需调用DMAStart()函数即可。如果采用Windriver提供的DMAWriteRead函数,每进行一次DMA传输都要重新打开一个DMA,分配空间,设置各种相应的寄存器等,增加了DMA传输的CPU开销。经过测试,当进行数据全速捕获时,如果采用Windriver提供的DmaWriteRead函数及DMA完成查询方式,CPU的负荷最高可达80%,严重影响了系统其他程序的执行。当采用修改后的DmaStart()函数及DMA中断方式后,全速进行数据捕获时,CPU的负荷只有25%左右,大幅降低了CPU的负荷,保证了整个系统软件的正常执行。在DMAStart()函数中,需要注意的是PCI地址寄存器的设置,因为传输数据量大于一页(4KB),所以采用了分散/聚集方式,即以分散的物理内存块映射连续分配的用户地址空间。与内存块分配方式不同,这时不是设置DMA的PCI地址与本地地址寄存器,而是设置DMA通道的描述符寄存器(DMADPR)。通过函数WD_DMALock()在物理内存中锁定所需大小的存储空间,取得每页的物理地址,大小以及相应的本地地址放入地址描述块链表中,在DMADPA寄存器中设置初时的描述块地址。1)Scatter/GatherDMABOOLDMARoutine(WDC_DEVICE_HANDLEhDev,DWORDdwBufSize,UINT32u32LocalAddr,DWORDdwOptions,BOOLfPolling,BOOLfToDev){PVOIDpBuf;WD_DMA*pDma=NULL;BOOLfRet=FALSE;/*Allocateauser-modebufferforScatter/GatherDMA*/pBuf=malloc(dwBufSize);if(!pBuf)returnFALSE;/*LocktheDMAbufferandprogramtheDMAcontroller*/if(!DMAOpen(hDev,pBuf,u32LocalAddr,dwBufSize,fToDev,&pDma))gotoExit;/*EnableDMAinterrupts(ifnotpolling)*/if(!fPolling){if(!MyDMAInterruptEnable(hDev,MyDmaIntHandler,pDma))gotoExit;/*FailedenablingDMAinterrupts*/}/*FlushtheCPUcaches(seedocumentationofWDC_DMASyncCpu())*/WDC_DMASyncCpu(pDma);/*StartDMA-writetothedevicetoinitiatetheDMAtransfer*/MyDMAStart(hDev,pDma);/*WaitfortheDMAtransfertocomplete*/MyDMAWaitForCompletion(hDev,pDma,fPolling);/*FlushtheI/Ocaches(seedocumentationofWDC_DMASyncIo())*/WDC_DMASyncIo(pDma);fRet=TRUE;Exit:DMAClose(pDma,fPolling);free(pBuf);returnfRet;}2)ContiguousBufferDMABOOLDMARoutine(WDC_DEVICE_HANDLEhDev,DWORDdwDMABufSize,UINT32u32LocalAddr,DWORDdwOptions,BOOLfPolling,BOOLfToDev){PVOIDpBuf=NULL;WD_DMA*pDma=NULL;BOOLfRet=FALSE;/*AllocateaDMAbufferandopenDMAfortheselectedchannel*/if(!DMAOpen(hDev,&pBuf,u32LocalAddr,dwDMABufSize,fToDev,&pDma))gotoExit;/*EnableDMAinterrupts(ifnotpolling)*/if(!fPolling){if(!MyDMAInterruptEnable(hDev,MyDmaIntHandler,pDma))gotoExit;/*FailedenablingDMAinterrupts*/}/*FlushtheCPUcaches(seedocumentationofWDC_DMASyncCpu())*/WDC_DMASyncCpu(pDma);/*StartDMA-writetothedevicetoinitiatetheDMAtransfer*/MyDMAStart(hDev,pDma);/*WaitfortheDMAtransfertocomplete*/MyDMAWaitForCompletion(hDev,pDma,fPolling);/*FlushtheI/Ocaches(seedocumentationofWDC_DMASyncIo())*/WDC_DMASyncIo(pDma);fRet=TRUE;Exit:DMAClose(pDma,fPolling);returnfRet;}六、windriverAPI的深入分析windriver作为Jungo公司出品的一个高效易用的驱动开发软件,方便用户基于此开发自己设备的驱动程序,而不需要对windowsDDK作更深入的研究(当然,要想称为驱动的高手,DDK是一定要钻研的)。windriver相比dirverstudio使用起来更为方便,同时,它支持windows、linux、Vxworks、winCE、solaris等OS,对当前流行的硬件设备,如端口、ISA、PCI(-X,-E)、PCMCIA、USB等都有很好的支持。作为驱动开发的入门工具,windriver是个很好的选择。当前windriver可以在网上得到的破解版是ver8.01,已经可以很好的支持大家的要求(如果有银子的话,要获得好的稳定的产品和更多的技术支持,还是买正版哦)。很快大家都会熟悉上面的这两个图标,这就是windriver安装后的两个重要的快捷方式。windriver的正常工作,需要辅助安装windowsDDK(95/98/2000/XP/2003。。。),和VisualC,,等才能正确编译。当然,这也需要你正确的设置应有的环境变量。在8.01版中,windriver支持了更多的编译器平台,如下图所示:安装windriver后的目录如下所示:其中docs中就是windriver的各种手册,大家也不需要到网上找什么教程吧,看这个绝对受益菲浅,而且也是正道。include目录里就是最通用的包含文件了;lib目录则是重要的api函数库文件了;redist目录下是windriver的缺省驱动程序和DLL;对PLX芯片使用而言,最重要的就是PLX目录和wizard目录了,wizard就是建立的驱动工程,正确编译后会找到驱动程序*.sys。plx目录则是windriver为PLX系里芯片进行的二次封装函数库,当前我还是建议打击使用原始的WD和WDC函数,但是,其中的调用思路就可以在这里寻找。有了对windriver的总体认识,相信大家能很快上手,朝正确的方向努力。整理中(待续)。。。
str="WindriverOverdue";
}
WD_PCI_SCAN_CARDSpciScan;
WD_PCI_SLOTpciSlot;
BZERO(pciScan);
//以PEX8311为例
pciScan.searchId.dwVendorId=0x10b5;pciScan.searchId.dwDeviceId=0x86e1;WD_PciScanCards(m_hPex,&pciScan);if(pciScan.dwCards>0)
pciSlot=pciScan.cardSlot[0];
WD_PCI_CARD_INFOpciCardInfo;
WD_CARDCard;
BZERO(pciCardInfo);
pciCardInfo.pciSlot=pciSlot;
WD_PciGetCardInfo(m_hPex,&pciCardInfo);
if(pciCardInfo.Card.dwItems!
=0)
Card=pciCardInfo.Card;
str="Pcicard=0";
WD_CARD_REGISTERcardReg;
//Card.Item[0]PC机基本端口操作
//Card.Item[1]中断信息
BZERO(cardReg);
cardReg.Card=Card;
cardReg.fCheckLockOnly=FALSE;
WD_CardRegister(m_hPex,&cardReg);
if(cardReg.hCard==0)
str="cardReg=0";
str="opensuccessfully";
//取得当前设备信息并显示
Interrupt=Card.Item[1].I.Int.dwInterrupt);
Bus=pciScan.cardSlot[0].dwBus;
Slot=pciScan.cardSlot[0].dwSlot;
Fun=pciScan.cardSlot[0].dwFunction;
//CS0-CS3的地址映射信息
BaseAddrCS0=Card.Item[2].I.Mem.dwPhysicalAddr;
RangeAddrCS0=Card.Item[2].I.Mem.dwBytes;
BaseAddrCS1=Card.Item[3].I.IO.dwAddr;
RangeAddrCS1=Card.Item[3].I.Mem.dwBytes;
BaseAddrCS2=Card.Item[4].I.Mem.dwPhysicalAddr;
RangeAddrCS2=Card.Item[4].I.Mem.dwBytes;
BaseAddrCS3=Card.Item[5].I.Mem.dwPhysicalAddr;
RangeAddrCS3=Card.Item[5].I.Mem.dwBytes;else
str="OpenFailed";
WD_Close(m_hPex);
AfxMessageBox(str);
注:
Card.Item[0-5]就是DEVICE/IO/MEM映射的地方,这里得到的值和windrivewizard里看到的是一样的。
二、设备的读写操作
1.写操作
WD_TRANSFERtrans;
BZERO(trans);
trans.cmdTrans=WP_BYTE;//(WORD/DWORD)
trans.dwPort=BaseAddrCS0;//可为其它的映射基地址
trans.Data.Byte=0x00;//需要写的数据
WD_Transfer(m_hPex,&trans);
2.读操错
trans.cmdTrans=RP_BYTE;//(WORD/DWORD)
trans.dwPort=BaseAddrCS1;//可为其它的映射基地址
returntrans.Data.Bytes;
三、其它
有关windriver对寄存器的操作要用到WDC_***函数,还有DMA操作在
(二)中阐述。
三、寄存器的读写
寄存器的读写用到一个非常好用的函数WD_PciConfigDump();具体的参数定义参照WD的API手册。
WD_PCI_CONFIG_DUMPpciConfig;
DWORDdwStatus;
WORDarBuffer[2];
BZERO(pciConfig);
pciConfig.pciSlot.dwBus=Bus;
pciConfig.pciSlot.dwSlot=Slot;
pciConfig.pciSlot.dwFunction=Fun;
pciConfig.pBuffer=arBuffer;
pciConfig.dwBytes=sizeof(arBuffer);
pciConfig.fIsRead=TRUE;
pciConfig.dwOffset=每次累加4
WD_PciConfigDump(m_hPex,&pciConfig);
四、数据的块操作
DWORDdataBuffer[8192];
*****************
trans.Data.pBuffer=dataBuffer;
利用WD_Transfer()函数来完成数据的块操作。
五、DMA控制
WinDriver为提供了一组API函数,但是其提供的DMA函数不是基于突发方式的,并且是以查询方式来检测DMA是否结束,比较适用于一次DMA读写。
因此需要对其提供的DMAAPI函数及中断相关的函数进行改写,即在DMAOpen()函数中,需对DMAMODE寄存器的本地突发使能位(BIT8)与BTERM输入使能位(BIT7)置位,否则,DMA操作只能完成一个双字的突发传输,只有将此二位置1后,才能完成指定长度的DMA传输。
因为传输量超过4KB,所以要置为分散/聚拢(scatter/gather)模式(BIT9),同时使能DMA中断完成位(BIT10)与DMA通道0中断选择位(BIT17)。
重写DMA启动函数DMAStart(),设置每次DMA传输所需的PCI地址(主机物理内存地址)、本地地址、传输大小、传输方向等,并置DMA启动位。
这样每次数据捕获满中断到来,启动DMA传输时,只需调用DMAStart()函数即可。
如果采用Windriver提供的DMAWriteRead函数,每进行一次DMA传输都要重新打开一个DMA,分配空间,设置各种相应的寄存器等,增加了DMA传输的CPU开销。
经过测试,当进行数据全速捕获时,如果采用Windriver提供的DmaWriteRead函数及DMA完成查询方式,CPU的负荷最高可达80%,严重影响了系统其他程序的执行。
当采用修改后的DmaStart()函数及DMA中断方式后,全速进行数据捕获时,CPU的负荷只有25%左右,大幅降低了CPU的负荷,保证了整个系统软件的正常执行。
在DMAStart()函数中,需要注意的是PCI地址寄存器的设置,因为传输数据量大于一页(4KB),所以采用了分散/聚集方式,即以分散的物理内存块映射连续分配的用户地址空间。
与内存块分配方式不同,这时不是设置DMA的PCI地址与本地地址寄存器,而是设置DMA通道的描述符寄存器
(DMADPR)。
通过函数WD_DMALock()在物理内存中锁定所需大小的存储空间,取得每页的物理地址,大小以及相应的本地地址放入地址描述块链表中,
在DMADPA寄存器中设置初时的描述块地址。
1)Scatter/GatherDMA
BOOLDMARoutine(WDC_DEVICE_HANDLEhDev,DWORDdwBufSize,UINT32u32LocalAddr,DWORDdwOptions,BOOLfPolling,BOOLfToDev){
PVOIDpBuf;
WD_DMA*pDma=NULL;
BOOLfRet=FALSE;
/*Allocateauser-modebufferforScatter/GatherDMA*/pBuf=malloc(dwBufSize);
if(!
pBuf)
returnFALSE;
/*LocktheDMAbufferandprogramtheDMAcontroller*/if(!
DMAOpen(hDev,pBuf,u32LocalAddr,dwBufSize,fToDev,&pDma))gotoExit;
/*EnableDMAinterrupts(ifnotpolling)*/
fPolling)
MyDMAInterruptEnable(hDev,MyDmaIntHandler,pDma))gotoExit;/*FailedenablingDMAinterrupts*/
/*FlushtheCPUcaches(seedocumentationofWDC_DMASyncCpu())*/WDC_DMASyncCpu(pDma);
/*StartDMA-writetothedevicetoinitiatetheDMAtransfer*/MyDMAStart(hDev,pDma);
/*WaitfortheDMAtransfertocomplete*/
MyDMAWaitForCompletion(hDev,pDma,fPolling);
/*FlushtheI/Ocaches(seedocumentationofWDC_DMASyncIo())*/WDC_DMASyncIo(pDma);
fRet=TRUE;
Exit:
DMAClose(pDma,fPolling);
free(pBuf);
returnfRet;
2)ContiguousBufferDMA
BOOLDMARoutine(WDC_DEVICE_HANDLEhDev,DWORDdwDMABufSize,UINT32u32LocalAddr,DWORDdwOptions,BOOLfPolling,BOOLfToDev){
PVOIDpBuf=NULL;
/*AllocateaDMAbufferandopenDMAfortheselectedchannel*/if(!
DMAOpen(hDev,&pBuf,u32LocalAddr,dwDMABufSize,fToDev,&pDma))gotoExit;
六、windriverAPI的深入分析
windriver作为Jungo公司出品的一个高效易用的驱动开发软件,方便用户基于此开发自己设备的驱动程序,而不需要对windowsDDK作更深入的
研究(当然,要想称为驱动的高手,DDK是一定要钻研的)。
windriver相比dirverstudio使用起来更为方便,同时,它支持windows、linux、Vxworks、winCE、solaris等OS,对当前流行的硬件设备,如端口、
ISA、PCI(-X,-E)、PCMCIA、USB等都有很好的支持。
作为驱动开发的入门工具,windriver是个很好的选择。
当前windriver可以在网上得到的破解版是ver8.01,已经可以很好的支持大家的要求(如果有银子的话,要获得好的稳定的产品和更多的技术支持,
还是买正版哦)。
很快大家都会熟悉上面的这两个图标,这就是windriver安装后的两个重要的快捷方式。
windriver的正常工作,需要辅助安装windowsDDK(95/98/2000/XP/2003。
。
),和VisualC,,等才能正确编译。
当然,这也需要你正确的设置应有的环境变量。
在8.01版中,windriver支持了更多的编译器平台,如下图所示:
安装windriver后的目录如下所示:
其中docs中就是windriver的各种手册,大家也不需要到网上找什么教程吧,看这个绝对受益菲浅,而且也是正道。
include目录里就是最通用的包含文件了;
lib目录则是重要的api函数库文件了;
redist目录下是windriver的缺省驱动程序和DLL;
对PLX芯片使用而言,最重要的就是PLX目录和wizard目录了,wizard就是建立的驱动工程,正确编译后会找到驱动程序*.sys。
plx目录则是windriver为PLX系里芯片进行的二次封装函数库,当前我还是建议打击使用原始的WD和WDC函数,但是,其中的调用思路就可以在这里寻找。
有了对windriver的总体认识,相信大家能很快上手,朝正确的方向努力。
整理中(待续)。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1