WinDriver高级编程

1、DMA 传输

使用DMA传输有两种方式:连续缓冲DMA 、离散DMA。离散DMA的效率比连续DMA 高,这种方式下Pci设备可以直接从不同的地址拷贝内存块,物理内存存在碎片,虚拟内存连续就可以和用户的缓冲区进行数据的交换。如果你的设备不支持离散DMA ,你就必须分配连续的物理内存给DMA 传输,然后再拷贝到你的数据缓冲区。
不同的PCI设备,DMA 编程也是很不相同的。一般情况下,你要明确PCI 设备的本地地址,主机地址(计算机中的物理内存地址),统计包(要传输的数据块)。给寄存器去传输。

1.1 离散DMA

DMA 传输举例
下面的过程介绍了离散DMA 传输,更详细的内容请参考:
\\ WinDriver\\plx\\9054\\lib\\p9054_lib.c
\\WinDriver\\plx\\9080\\lib\\p9080_lib.c
\\WinDriver\\marvell\\gt64\\lib\\gt64_lib.c
// DMA
BOOL DMA_routine(void *startAddress, DWORD transferCount, BOOL fDirection)
{

WD_DMA dma;
   int i;

BZERO (dma);//清零 
   dma.pUserAddr = startAddress; 
   dma.dwBytes = transferCount; 
   dma.dwOptions = 0;

// lock region in memory 
    WD_DMALock(hWD,&dma); 
    if (dma.hDma==0) 
      return FALSE;

for(i=0;i!=dma.dwPages;i++) 
   { 
      // Program the registers for each page of the transfer 
      My_DMA_Program_Page(dma.Page[i].pPhysicalAddr, 
      dma.Page[i].dwBytes, fDir);
    } 
    // write to the register that initiates the DMA transfer
    My_DMA_Initiate();
    // read register that tells when the DMA is done
   while(!My_DMA_Done());
   WD_DMAUnlock(hWD,&dma);
   return TRUE;
}

你需要弄清楚什么?
.   My_DMA_Program_page 将设备寄存器设为传输连接表的一部分。
.   My_DMA_Initiate 初始化DMA的位。
.   My_DMA_DONE 读设备的传输结束位

缓冲大于1M的离散DMA传输支持256 页。X86 处理器的每页4k,256X4kb=1MB.由于第一页和最后一页不能作为边界,所以256页可以使用1MB-8KB. 如果你要锁定大于1的缓冲,你需要DMA_LARGE_BUFFER 选项。
BOOL DMA_Large_routine(void *startAddress,
DWORD transferCount, BOOL fDirection)
{
    DWORD dwPagesNeeded = transferCount / 4096 + 2; 
   // WD_DMA structure already has space for WD_DMA_PAGES 
   // number of entries 
   WD_DMA *pDma=calloc(sizeof(WD_DMA)+sizeof(WD_DMA_PAGE)* (dwPagesNeeded - WD_DMA_PAGES),1); 
   pDma->pUserAddr = startAddress; 
   pDma->dwBytes = transferCount; 
   pDma->dwOptions = DMA_LARGE_BUFFER; 
   pDma->dwPages = dwPagesNeeded; 
   // lock region in memory 
   WD_DMALock(hWD,pDma); 
   // the rest is the same as in the DMA_routine() 
   // free the WD_DMA structure allocated 
   free (pDma);
}

1.2 连续缓冲的DMA传输

更详细的粒子在下列文件中:
 WinDriver\\QuickLogic\\lib\\pbclib.c
 WinDriver\\amcc\\lib\\amcclib.c
读的顺序
下面是从板子读到主机内存的先后顺序。
{
WD_DMA dma;
BZERO (dma);
// allocate the DMA buffer (100000 bytes)
dma.pUserAddr = NULL;
dma.dwBytes = 10000;
dma.dwOptions = DMA_KERNEL_BUFFER_ALLOC;
WD_DMALock(hWD, &dma);
if (dma.hDma==0)
return FALSE;
// transfer data from the card to the buffer
My_Program_DMA_Transfer(dma.Page[0].pPhysicalAddr,
dma.Page[0].dwBytes, fDir);
// Wait for transfer to end
while(!My_Dma_Done());
// now the data is the buffer, and can be used
UseDataReadFromCard(dma.pUserAddr);
// release the buffer
WD_DMAUnlock(hWD,&dma);
}

写的顺序
下面是从主机内存写入板子的过程
{

WD_DMA dma;
BZERO (dma);
//allocate the DMA buffer (100000 bytes)
dma.pUserAddr = NULL;
dma.dwBytes = 10000;
dma.dwOptions = DMA_KERNEL_BUFFER_ALLOC;
WD_DMALock(hWD, &dma);
if (dma.hDma==0)
return FALSE;
// prepare data into buffer
PrepareDataInBuffer(dma.pUserAddr);
// transfer data from the buffer to the card
My_Program_DMA_Transfer(dma.Page[0].pPhysicalAddr,
LocalAddr);
// Wait for transfer to end
while(!My_Dma_Done());
// release the buffer
WD_DMAUnlock(hWD,&dma);
}

2、中断处理

向导很容易处理中断,尽可能的自动生成中断处理代码。下面的内容帮助你理解中断处理的机理,你可以按照这个思想写你自己的中断处理代码。

2.1 一般的中断处理

1 生成线程来处理引入的中断。
2 线程进入死循环等待中断请求。
3 有中断发生,驱动的中断代码被调用。
4 中断返回,循环继续等待。
WD_IntWait 函数先让线程休眠,有中断发生时,唤醒线程。
在中断的等待过程中没有占用CPU,一旦中断发生,WinDriver 内和首先响应,然后,WD_IntWait 唤醒中断处理线称并返回。
由于中断线程运行在用户模式下,你可以调用任何API 函数。
边缘触发中断例程(常用于ISA/EISA 卡)

// interrupt structure
WD_INTERRUPT Intrp;
DWORD WINAPI wait_interrupt (PVOID pData)
{
printf (\"Waiting for interrupt\");
for (;;)
{
WD_IntWait (hWD, &Intrp);
if (Intrp.fStopped)
break; // WD_IntDisable called by parent

// call your interrupt routine here
printf (\"Got interrupt %d\\n\", Intrp.dwCounter);
}
return 0;
}
void Install_interrupt()
{
BZERO(Intrp);
// put interrupt handle returned by WD_CardRegister
Intrp.hInterrupt = cardReg.Card.Item[0].I.Int.hInterrupt;
// no kernel transfer commands to do upon interrupt
Intrp.Cmd = NULL;
Intrp.dwCmds = 0;
// no special interrupt options
Intrp.dwOptions = 0;
WD_IntEnable(hWD, &Intrp);
if (!Intrp.fEnableOk)
{
printf (\"Failed enabling interrupt\\n\");
return;
}

printf (\"starting interrupt thread\\n\");
thread_handle = CreateThread (0, 0x1000,
wait_interrupt, NULL, 0, &thread_id);
// call your driver code here
WD_IntDisable (hWD, &Intrp);
WaitForSingleObject(thread_handle, INFINITE);
}

简化的中断处理

WinDriver 提供了方便的中断处理函数,InterruptEnable 和InterruptDisable 。下面的代码重写的中断处理函数。
VOID interrupt_handler (PVOID pData)
{
WD_INTERRUPT * pIntrp = (WD_INTERRUPT *) pData;
// do your interrupt routine here
printf (\"Got interrupt %d\\n\", pIntrp->dwCounter);
}

...

nt main()
{
HANDLE hWD;
WD_CARD_REGISTER cardReg;
// interrupt structure
WD_INTERRUPT *pIntrp;
HANDLE thread_handle;
...
hWD = WD_Open();
BZERO(cardReg);
cardReg.Card.dwItems = 1;
cardReg.Card.Item[0].item = ITEM_INTERRUPT;
cardReg.Card.Item[0].fNotSharable = TRUE;
cardReg.Card.Item[0].I.Int.dwInterrupt = MY_IRQ;
cardReg.Card.Item[0].I.Int.dwOptions = 0;
...
WD_CardRegister (hWD, &cardReg);
...
pIntrp = malloc(sizeof(WD_INTERRUPT));
BZERO(*pIntrp);
pIntrp->hInterrupt =
cardReg.Card.Item[0].I.Int.hInterrupt;
printf (\"starting interrupt thread\\n\");
// this calls WD_IntEnable() and creates an interrupt
// handler thread

...

wStatus = InterruptEnable(&thread_handle, hWD, pIntrp,
interrupt_handler, pIntrp))
if (dwStatus)
{
printf (\"failed enabling interrupt Status 0x%x - %s\\n\",
dwStatus, Stat2Str(dwStatus));
}
else
{
// call your driver code here
printf (\"Press Enter to uninstall interrupt\\n\");
fgets(line, sizeof(line), stdin);

// this calls WD_IntDisable()
InterruptDisable(thread_handle);
}
WD_CardUnregister(hWD, &cardReg);
free(pIntrp);
....
}

2.2 ISA/EISA PCI 中断

通常情况下, ISA/EISA 的中断是边缘触发,PCI 中断是级优先中断。这按时了重担处理过程的原理。
边缘触发中断 当物理中断信号从低电平转为高电平时,中断产生。操作系统调用内核释放中断等待线程,中断没有回应的项。
级优先中断 当物理中断信号为高电平时,中断产生。如果中断信号电平高于前次中断产生时的电平,操作系统再次调用WinDriver 内核处理中断,挂起CPU .为了防止这种情况的发生, 中断必须得到WinDriver 中断处理的确认。
内核级传输命令 通常PCI 的中断处理需要在内核级别传输命令,来确认中断。在WD_IntWait 返回之前,WinDriver 内核中断处理传输命令,你首先要准备命令数组
(WD_Transfer 结构) ,把它传递给WD_IntEnable函数。
举例如下:
WD_TRANSFER trans[2];
BZERO(trans);
trans[0].cmdTrans = RP_DWORD; // Read Port Dword
// Set address of IO port to write to:
trans[0].dwPort = dwAddr;
trans[1].cmdTrans = WP_DWORD; // Write Port Dword
// address of IO port to write to
trans[1].dwPort = dwAddr;
// the data to write to the IO port
trans[1].Data.Dword = 0;
Intrp.dwCmds = 2;
Intrp.Cmd = trans;
Intrp.dwOptions =
INTERRUPT_LEVEL_SENSITIVE | INTERRUPT_CMD_COPY;
WD_IntEnable(hWD, &Intrp);
这个例子完成从I/O 地址的 DWORD 的读命令,然后给I/O 地址填“0”。
INTERRUPT_CMD_COPY 选项用于再写命令执行以前,恢复读到的值。
当你要先读一个寄存器,后写寄存器的值时,这一点很有用。如果你试图在WD_IntWait之后读寄存器的值,会发现寄存器早已被填0了,因为写操作运行在内核级上。
DWORD WINAPI wait_interrupt(PVOID pData)
{
printf(\"Waiting for interrupt\\n\");
for (;;)

{
WD_TRANSFER trans[2];
Intrp.dwCmds = 2;
Intrp.Cmd = trans;
WD_IntWait(hWD, &Intrp);
if (Intrp.fStopped)
break; // WD_IntDisable called by parent

// call your interrupt routine here
printf(\"Got interrupt %d. Value of register read %x\\n\",
Intrp.dwCounter, trans[0].Data.Dword);
}
return 0;
}

回调函数优化中断处理
VxWorks 支持回调函数,如果用户设置了此项,回调函数回加速中断的确认和处理过程。但常用的操作平台不需要这个例程,因为各自的内核插件增强了中断的处理速度。
使用 windrvr_isr 例程:
1. Include the following declaration in your code:
int (__cdecl *windrvr_isr)(void);
2. Set windrvr_isr to point to the interrupt handler routine that you wish to have performed immediately upon the arrival of an interrupt. For example:
3. int __cdecl my_isr(void)
4. {
5. // Add code here in order to verify that the ISR is called.
6. return TRUE; // If TRUE, continue regular handling of WinDriver; if FALSE, exit ISR.
7. }
8.
9. extern int (__cdecl *windrvr_isr)(void);
10.
11. // after calling drvrInit()
12. windrvr_isr = my_isr;

WinDriver高级编程相关推荐

  1. Go 学习推荐 —(Go by example 中文版、Go 构建 Web 应用、Go 学习笔记、Golang常见错误、Go 语言四十二章经、Go 语言高级编程)

    Go by example 中文版 Go 构建 Web 应用 Go 学习笔记:无痕 Go 标准库中文文档 Golang开发新手常犯的50个错误 50 Shades of Go: Traps, Gotc ...

  2. linux web高级编程,寒假学习 第16.17天 (linux 高级编程)

    寒假学习 第16.17天 (linux 高级编程) 笔记 总结 一.进程的基本控制(进程的同步) 1.进程的常见控制函数 pause   sleep/usleep atexit   on_exit i ...

  3. Oracle SQL高级编程——分析函数(窗口函数)全面讲解

    Oracle SQL高级编程--分析函数(窗口函数)全面讲解 注:本文来源于:<Oracle SQL高级编程--分析函数(窗口函数)全面讲解> 概述 分析函数是以一定的方法在一个与当前行相 ...

  4. 如何学习android高级编程

    学了android高级编程有前途吗?进入2010年之后,android的应用开发进入了一个爆炸式增长的状态,从去年的不到1万款应用程序增加到现在的9万,而且即将突破10万,这也从开发者这一方面展现了用 ...

  5. Linux环境高级编程函数,Linux环境高级编程--出错处理(CLStatus)

    很多程序库对外提供若干类,每个方法出错时如何告知调用者是否出错,以及出错码(在Linux上在error.h中的全局errno就是保存我们Linux程序执行的出错码的)?方法很多,为了简化起见,函数将返 ...

  6. PL/SQL高级编程

    PL/SQL高级编程 实验目的: 1.掌握PL/SQL的数据结构和编程结构,掌握应用PL/SQL编写简单程序的方法 2.理解存储过程的概念,掌握编写存储过程的方法 3.理解函数的概念,掌握编写存储过程 ...

  7. NDK 高级编程(笔记)

    Android 开发中针对 NDK 的书籍很少,<Pro Android C++ with the NDK>也是出版的比较早的一本书,有些内容可能对现在的开发并不适用.但是书中介绍的内容比 ...

  8. PHP 高级编程之多线程

    PHP 高级编程之多线程 http://netkiller.github.io/journal/thread.php.html Mr. Neo Chen (netkiller), 陈景峰(BG7NYT ...

  9. 《UNIX环境高级编程(第3版)》——1.7 出错处理

    本节书摘来自异步社区<UNIX环境高级编程(第3版)>一书中的第1章,第1.7节,作者:[美]W. Richard Stevens , Stephen A.Rago著,更多章节内容可以访问 ...

  10. OC高级编程——深入block,如何捕获变量,如何存储在堆上

    OC高级编程--深入block,如何捕获变量,如何存储在堆上 首先先看几道block相关的题目 这是一篇比较长的  博文 ,前部分是block的测试题目,中间是block的语法.特性,block讲解b ...

最新文章

  1. Mybatis的动态创建删除表
  2. UIAlertController的使用及其自定义
  3. cf 786 B 线段树优化建图
  4. 2021餐饮外卖商户研究报告
  5. Linux学习之Ubuntu安装Java
  6. Groq新进展!谷歌TPU原班人马明年发布首款AI芯片
  7. 《手机测试Robotium实战教程》——第2章,第2.2节Eclipse的安装
  8. jenkins的groovy脚本没权限
  9. H5本地存储 localStorage和sessionStorage区别 存储方式 用法
  10. HTC HD2解锁详细教程
  11. 明解C语言第三章习题
  12. 【测试】软件测试之测试用例的设计方法
  13. ​2021年度学习清单
  14. 数据库设计中的英文术语表
  15. 常见报错信息及解决方法
  16. scanf(3c,c);
  17. 纪中DAY5做题小结
  18. django设置为中文语言
  19. 什么是小波?小波是什么?
  20. C语言大学期末考试重点,快点码住,再也不用担心挂科啦

热门文章

  1. 全能视频播放器:OmniPlayer for Mac(1.4.6)
  2. 计算机按键去抖动的方式,按键消抖
  3. 有关python毕设题目_python毕设题目
  4. 食品饮料行业仓库库存管理系统软件,前十排行榜
  5. C4D学习笔记1-动画-动画关键帧
  6. 【webssh】网页上的SSH终端
  7. 高级计算机程序员实操题,国家计算机软考高级程序员历年真题1990.doc
  8. 设计图纸管理系统办公系统实现无纸化
  9. 【小憩】流光容易把人抛,红了樱桃,绿了芭蕉
  10. 高校公寓管理系统java下载_Spring+SpringMVC+Mybatis高校宿舍管理系统.zip