newallan2003
驱动牛犊
驱动牛犊
  • 注册日期2003-03-02
  • 最后登录2004-04-12
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:10370回复:24

WinDriver高级编程 (WinDriver 6.0 用户手册译文)

楼主#
更多 发布于:2003-04-13 09:33
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]

最新喜欢:

r2109twr2109t...
hamsir
驱动小牛
驱动小牛
  • 注册日期2003-03-24
  • 最后登录2003-06-17
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2003-04-13 10:21
受益啊 !
一只流泪的鱼
heshw99
驱动牛犊
驱动牛犊
  • 注册日期2003-03-08
  • 最后登录2004-12-01
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-04-21 19:33
up!
凉风有性,秋月无边,亏我思娇的情绪好比度日如年,虽然我不是玉树临风,潇洒倜傥,但是我有广阔的胸襟和强健的背弯......
xhx7153
驱动牛犊
驱动牛犊
  • 注册日期2002-12-23
  • 最后登录2005-11-15
  • 粉丝0
  • 关注0
  • 积分44分
  • 威望5点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-06-10 19:34
翻译!
zhao_bian
驱动牛犊
驱动牛犊
  • 注册日期2003-06-18
  • 最后登录2016-01-07
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-07-06 22:45
好,还有吗?
lc0060305
驱动牛犊
驱动牛犊
  • 注册日期2004-06-21
  • 最后登录2007-04-29
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-07-14 13:33
有更多的吗?我想要。
给我发到邮箱里吧。小弟这里谢了先。
我的邮箱地址是:lc0060305@yeah.net
我想,我愿,我做
lansing
驱动牛犊
驱动牛犊
  • 注册日期2003-04-23
  • 最后登录2005-09-01
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望3点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-07-16 11:05
好东东!
lanren_me
驱动牛犊
驱动牛犊
  • 注册日期2004-11-11
  • 最后登录2007-02-26
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2004-11-16 10:04
good
yphilips
驱动牛犊
驱动牛犊
  • 注册日期2005-03-15
  • 最后登录2005-12-06
  • 粉丝0
  • 关注0
  • 积分12分
  • 威望3点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2005-03-22 13:08
good, 有更多的吗,我也想要。我的信箱是yphilips@sjtu.edu.cn,先谢了
eagelangel
驱动牛犊
驱动牛犊
  • 注册日期2005-04-13
  • 最后登录2005-06-29
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2005-05-17 09:51
Good,顶! :P
yczyl
驱动牛犊
驱动牛犊
  • 注册日期2005-03-20
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2005-05-22 23:07
好,能否都贴出来!
sonaing
驱动牛犊
驱动牛犊
  • 注册日期2005-04-23
  • 最后登录2007-04-17
  • 粉丝0
  • 关注0
  • 积分90分
  • 威望9点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2005-06-12 00:40
sona
naokizxx2005
驱动牛犊
驱动牛犊
  • 注册日期2005-05-13
  • 最后登录2009-09-21
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望26点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2005-06-15 12:41
能不能不要用斜体字,,我脑袋都歪了
wiroo
驱动牛犊
驱动牛犊
  • 注册日期2005-04-27
  • 最后登录2005-06-24
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望3点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2005-06-19 01:56
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
怎么用WINDRIVER做USB转虚串口的驱动啊,要学习上面的吗?????????
菜鸟~~~~~~~~~~在线
angleliu
驱动牛犊
驱动牛犊
  • 注册日期2005-04-30
  • 最后登录2005-08-25
  • 粉丝0
  • 关注0
  • 积分66分
  • 威望11点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2005-06-19 09:44
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
我用WinDriver  v6.02用国家半导体的usbn9604,是不是也不用看第八章,我用向导生成的驱动,我只需要基本的传输功能,配置,对生成的驱动需要修改吗?我的固件程序中有一个中断。
天涯
angleliu
驱动牛犊
驱动牛犊
  • 注册日期2005-04-30
  • 最后登录2005-08-25
  • 粉丝0
  • 关注0
  • 积分66分
  • 威望11点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2005-06-19 09:45
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
我用WinDriver  v6.02用国家半导体的usbn9604,是不是也不用看第八章,我用向导生成的驱动,我只需要基本的传输功能,配置,对生成的驱动需要修改吗?我的固件程序中有一个中断。
天涯
tiannan
驱动牛犊
驱动牛犊
  • 注册日期2004-04-26
  • 最后登录2005-06-28
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2005-06-28 00:39
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
受益
yihui286
驱动牛犊
驱动牛犊
  • 注册日期2005-06-28
  • 最后登录2005-07-17
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2005-06-28 23:03
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
hehe ,好呀,多发些,让我多学学呀
jst446806259
驱动牛犊
驱动牛犊
  • 注册日期2005-04-22
  • 最后登录2005-08-11
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2005-08-11 10:51
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
不错!不错!不错!不错!不错!不错!不错!不错!
yifenqian
驱动牛犊
驱动牛犊
  • 注册日期2004-10-09
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望47点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2007-04-23 16:52
Re:WinDriver高级编程   (WinDriver 6.0 用户手册译文)
好人,谢谢
上一页
游客

返回顶部