OHCI 的体系下,判断数据是否传输完毕是需要通过中断程序来判断的,当 USB 主机设置了 HcControl HcCommandStatus 寄存器开始传输数据后, AM9200 自动开始数据传输,并且定期的检查 HcDoneHead 寄存器的内容,并且将其转移到 HCCA.DoneHead 。然后产生中断,触发中断处理程序。
 
在中断处理程序中,需要检查 HcInterruptStatus 寄存器的内容,判断 WDH 位是否为 1 ,以便确定是否有 TD 被处理完毕。一般来说,其余的中断状态位不用理会。当发现有 TD 被处理完毕,则还需要判断已经完成的 TD 是否是当前传输命令的最后一个 TD ,如果是则标志命令执行结束,上层程序可以进行后续处理。
 
/**
 * OHCI 中断处理程序
 */
void AT91F_UHP_Handler( void )
{
    unsigned int status;
    unsigned char idx;
    unsigned char cc;
    //unsigned int control;
   
    // 得到 HcInterruptStatus 寄存器的内容
    status = ohciGetIntrStatus();
    // 检查 WDH 位,判断是否有 TD 传输完毕
    if ((status & OHCI_HC_INTR_WDH) != 0)
    {
       // 根据当前执行的命令类型,确定 TD 的数量
       switch (usbCmdState. cmdType )
       {
       case USB_CMD_TYPE_BULK_WRITE:
       case USB_CMD_TYPE_BULK_READ:
           idx = 3;
           break ;
          
       case USB_CMD_TYPE_CTRL_READ:
           idx = 2;
           break ;
          
       case USB_CMD_TYPE_CTRL_WRITE:
           idx = 1;
           break ;
          
       default :
           usbCmdState. state = USB_CMD_OVER;
           ohciClearIntrStatus();
           return ;
       }
      
       // 取得当前完成的 TD Complete Code
       cc = getTdCC(ohciGetHccaDoneHead());
       // 判断当前完成的 TD 是否是命令的最后一个 TD
       if (ohciGetHccaDoneHead() == usbGetLastTdAddr(idx))
       {
           usbCmdState. cmdResult = cc;
           usbCmdState. state = USB_CMD_OVER;
       }
       else
       {
           // 当前 TD 不是最后一个 TD ,但是执行失败,不会继续处理 TD 列表,因此需要返回
           if (cc)
           {
              usbCmdState. cmdResult = cc;
              usbCmdState. state = USB_CMD_OVER;
           }
           else
              // 当前 TD 不是最后一个 TD ,等待继续处理
              usbCmdState. state ++;
       }
    }
    // 清除 HcInterruptStatus 寄存器的内容,以便能够产生新的中断
    ohciClearIntrStatus();
}
 
在最初的代码中,不是通过中断来判断 TD 数据是否处理完毕的,而是直接调用 ohciGetIntrStatus() 函数并判断返回值的,但是实际调试时发现这样不能正确得到 TD 数据处理完毕的信息。通过对中断程序的实际调试发现,因为 ED 会带有多个 TD AM9200 在处理的时候可能是处理速度的原因,会产生 1 个或多个中断,因此在中断处理程序中需要判断当前结束的 TD 是否是当前命令的最后一个 TD ,这样才能确保整个 ED 处理完毕。
 
说实话,我不认为上面的判断 ED 队列执行完毕的方法是好的方法,本来我一直以为会有一个寄存器,在 ED 队列处理完毕的时候会跳出来告诉我说队列执行完毕了,可是找了半天也没有找到,只好采用这个笨方法了。