阅读:10983回复:24
WinDriver高级编程 (WinDriver 6.0 用户手册译文)
8 chapter WinDriver高级编程
如果你的硬件使用下列芯片,你就不必学习本章了。因为向导已经为你准备好了有关的函数。这些芯片是:PLX/Altera/Marvell/PLDA/AMCC/QuickLogic/Cypress/STMicroelectronics/Texas Instruments and Xilinx。 如果你的芯片不在此列,请你认真学习下面的内容。 8.1 DMA 传输 使用DMA传输有两种方式:连续缓冲DMA 、离散DMA。离散DMA的效率比连续DMA 高,这种方式下Pci设备可以直接从不同的地址拷贝内存块,物理内存存在碎片,虚拟内存连续就可以和用户的缓冲区进行数据的交换。如果你的设备不支持离散DMA ,你就必须分配连续的物理内存给DMA 传输,然后再拷贝到你的数据缓冲区。 不同的PCI设备,DMA 编程也是很不相同的。一般情况下,你要明确PCI 设备的本地地址,主机地址(计算机中的物理内存地址),统计包(要传输的数据块)。给寄存器去传输。 8.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.pPhysicalAddr, dma.Page.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); } 8.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); } 8.2 中断处理 向导很容易处理中断,尽可能的自动生成中断处理代码。下面的内容帮助你理解中断处理的机理,你可以按照这个思想写你自己的中断处理代码。 8.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); } ... int 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 ... dwStatus = 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); .... } 8.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; [编辑 - 6/12/05 by znsoft] |
|
最新喜欢:r2109t... |
沙发#
发布于:2003-04-13 10:21
受益啊 !
|
|
|
板凳#
发布于:2003-04-21 19:33
up!
|
|
|
地板#
发布于:2004-06-10 19:34
翻译!
|
|
地下室#
发布于:2004-07-06 22:45
好,还有吗?
|
|
5楼#
发布于:2004-07-14 13:33
有更多的吗?我想要。
给我发到邮箱里吧。小弟这里谢了先。 我的邮箱地址是:lc0060305@yeah.net |
|
|
6楼#
发布于:2004-07-16 11:05
好东东!
|
|
7楼#
发布于:2004-11-16 10:04
good
|
|
8楼#
发布于:2005-03-22 13:08
good, 有更多的吗,我也想要。我的信箱是yphilips@sjtu.edu.cn,先谢了
|
|
9楼#
发布于:2005-05-17 09:51
Good,顶! :P
|
|
10楼#
发布于:2005-05-22 23:07
好,能否都贴出来!
|
|
11楼#
发布于:2005-06-12 00:40
强
|
|
|
12楼#
发布于:2005-06-15 12:41
能不能不要用斜体字,,我脑袋都歪了
|
|
13楼#
发布于:2005-06-19 01:56
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
怎么用WINDRIVER做USB转虚串口的驱动啊,要学习上面的吗?????????菜鸟~~~~~~~~~~在线 |
|
14楼#
发布于:2005-06-19 09:44
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
我用WinDriver v6.02用国家半导体的usbn9604,是不是也不用看第八章,我用向导生成的驱动,我只需要基本的传输功能,配置,对生成的驱动需要修改吗?我的固件程序中有一个中断。 |
|
|
15楼#
发布于:2005-06-19 09:45
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
我用WinDriver v6.02用国家半导体的usbn9604,是不是也不用看第八章,我用向导生成的驱动,我只需要基本的传输功能,配置,对生成的驱动需要修改吗?我的固件程序中有一个中断。 |
|
|
16楼#
发布于:2005-06-28 00:39
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
受益 |
|
17楼#
发布于:2005-06-28 23:03
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
hehe ,好呀,多发些,让我多学学呀 |
|
18楼#
发布于:2005-08-11 10:51
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
不错!不错!不错!不错!不错!不错!不错!不错! |
|
19楼#
发布于:2007-04-23 16:52
Re:WinDriver高级编程 (WinDriver 6.0 用户手册译文)
好人,谢谢 |
|
上一页
下一页