Garyyin
驱动牛犊
驱动牛犊
  • 注册日期2007-05-07
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分102分
  • 威望22点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
阅读:2356回复:5

关于Bulk Only数据传输的疑问...

楼主#
更多 发布于:2007-05-07 16:38
  我最近在做U盘驱动,前面的控制传输阶段通过了,但是对使用SCSI Command Set的bulk only传输有些疑问:
我参考的例子代码如下:
//////////////////////////////////
void Ep2()//端口2中断处理函数
{
  unsigned char data i;
  unsigned char data Buf[64];
  i = ReadEp(2,Buf);
  bulk_CSW[4] = Buf[4];  bulk_CSW[5] = Buf[5]; bulk_CSW[6] = Buf[6]; bulk_CSW[7] = Buf[7];
 for(i=0;i<12;i++) bulk_CBW.CBWCB = Buf[i+15];
 switch(bulk_CBW.CBWCB[0])
  {
  case Inquiry                     :WriteEpBulk(1,36,B_InquiryData);break;
  case Mode_Sense                 :SCSI_Mode_Sense();              break;
  case Read10                     :SCSI_Read10();                  break;
  case Read_Capacity             :WriteEpBulk(1, sizeof(B_Read_Capacity), B_Read_Capacity);break;
  case Read_Format_Capacities     :SCSI_Read_Format_Capacities();  break;
  case Test_Unit_Ready             :TransmitCSW();                  break;
  case Verify                     :TransmitCSW();                  break;
  case Write10                     :SCSI_Write10();                 break;
  case Medium_Removal             :TransmitCSW();                  break;
  }
}

//SCSI_Read10()代码
/////////////////////////////////////////////////////////////////////////
void SCSI_Read10()//FLASH读处理函数
{
  unsigned char data i;
  unsigned char    Addr[4];
  unsigned char length;
  /*读操作的起始地址*/
  Addr[2] = bulk_CBW.CBWCB[4];
  Addr[3] = bulk_CBW.CBWCB[5];
  /*读操作的扇区长度*/
  length = bulk_CBW.CBWCB[8];
  while(length>0)
  {
  P5 = COMMAND;
  io_port1 = 0x00;//FLASH读命令码
  P5 = ADDRESS;
  io_port1 = 0;
  io_port1 = Addr[3];
  io_port1 = Addr[2];
  P5 = D_DATA;
  UEPNUM=0x01;
  UEPSTAX|=DIR;
  while(!(P5 & RB));
  /*读取一个扇区的数据*/
  for(i=0;i<8;i++)
  {
  ReadFlash();
  UEPSTAX|=TXRDY;
  while(!(UEPSTAX&TXCMP));
  UEPSTAX&=(~(TXCMP));      }
  io_port1 = INACTIVE;
  length--;    
  Addr[3]++;
 if(Addr[3]==255)
  {
  Addr[3]=0;
  Addr[2]++;
  }  
  }
  TransmitCSW();
}

/////////////////////////////////疑问如下///////////////////////////////
结合相关资料,对于一次bulk-in传输流程我是这样理解的:
1.Host发送CBW到OUT端点,Device回送ACK读取CBW,没有数据阶段。
2.Host发送PID为IN的数据包,指示Device传数据,Device向Host传数据,Host应答。
3.Host发送PID为IN的数据包,指示Device传状态,Device向Host传CSW,Host应答。

但从上述代码看,设备端收到CBW并解析后就直接回传数据和CSW,这样Host能正确区分这些数据吗??
请高人指点。。。
Garyyin
驱动牛犊
驱动牛犊
  • 注册日期2007-05-07
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分102分
  • 威望22点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-05-08 09:23
这个驱动很急啊,请各位不吝赐教!!
Garyyin
驱动牛犊
驱动牛犊
  • 注册日期2007-05-07
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分102分
  • 威望22点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-05-08 13:01
可能是讲的不够清楚,重新发一下:

关于Bulk only传输的疑问:
Bulk-Only传输模块按照规范协议将SCSI-2指令打包成CBW命令包,通过输出请求,由主机向设备送出,在没有传输失败的情况下,紧接着发出输入请求接收命令请求所要获取的数据,而后发出输入请求得到CSW状态包,用以判断数据的传输正常与否。也就是说一次Bulk only传输中间Host会发出3次请求,但下面代码不是这样做的:

void Ep2()//端口2中断处理函数
{
unsigned char data i;
unsigned char data Buf[64];
i = ReadEp(2,Buf);
bulk_CSW[4] = Buf[4]; bulk_CSW[5] = Buf[5]; bulk_CSW[6] = Buf[6]; bulk_CSW[7] = Buf[7];
for(i=0;i<12;i++) bulk_CBW.CBWCB = Buf[i+15];
switch(bulk_CBW.CBWCB[0])
{
case Inquiry:                 WriteEpBulk(1,36,B_InquiryData);break;
case Mode_Sense:              SCSI_Mode_Sense();         break;
case Read10:                  SCSI_Read10();             break;
case Read_Capacity:           WriteEpBulk(1, sizeof(B_Read_Capacity), Read_Capacity();break;
case Read_Format_Capacities:  SCSI_Read_Format_Capacities(); break;
case Test_Unit_Ready:         TransmitCSW();             break;
case Verify:                  TransmitCSW();             break;
case Write10:                 SCSI_Write10();           break;
case Medium_Removal:          TransmitCSW();             break;
}
}

SCSI_Read10()代码:
void SCSI_Read10()//FLASH读处理函数
{
unsigned char data i;
unsigned char    Addr[4];
unsigned char length;
/*读操作的起始地址*/
Addr[2] = bulk_CBW.CBWCB[4];
Addr[3] = bulk_CBW.CBWCB[5];
/*读操作的扇区长度*/
length = bulk_CBW.CBWCB[8];
while(length>0)
{
    P5 = COMMAND;
    io_port1 = 0x00;//FLASH读命令码
    P5 = ADDRESS;
    io_port1 = 0;
    io_port1 = Addr[3];
    io_port1 = Addr[2];
    P5 = D_DATA;
    UEPNUM=0x01;
    UEPSTAX|=DIR;
    while(!(P5 & RB));

    /*读取一个扇区的数据*/
    for(i=0;i<8;i++)
    {
        ReadFlash();
        UEPSTAX|=TXRDY;
        while(!(UEPSTAX&TXCMP));
        UEPSTAX&=(~(TXCMP));
    }
    io_port1 = INACTIVE;
    length--;    
    Addr[3]++;
    if(Addr[3]==255)
    {
        Addr[3]=0;
        Addr[2]++;
    }
}//End while(length>0)

TransmitCSW();
}

我的疑问是:
1。为什么在端点2中断中读出数据包分析为Read10命令后就直接向主机发数据了,为什么不等待下一个IN令牌包再发数据?
2。在SCSI_Read10()函数中为什么数据和CSW是连续发送的?CSW应该在数据发送完成后,等待接到一个IN令牌包才被发送啊。。。

这些问题很急,望不吝赐教,非常感谢!
bbkwym
驱动牛犊
驱动牛犊
  • 注册日期2006-07-28
  • 最后登录2007-05-12
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望6点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-05-08 19:33
while(!(UEPSTAX&TXCMP));   好象是在等待传输完成吧。
Garyyin
驱动牛犊
驱动牛犊
  • 注册日期2007-05-07
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分102分
  • 威望22点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2007-05-08 21:03
while(!(UEPSTAX&TXCMP)); 确实是在等待数据传输完成,但我不清楚的是:
Device在收到CBW后应答Host,然后Host会发起下一次数据传输,也就是会先发送一个IN令牌包,引起Device的IN端口中断,然后device向host发送数据,发完后,host应答device,之后host发起第3次数据传输,会先发送一个IN令牌包要求device发送CSW,device发送完CSW后,host应答,这样一次Bulk In数据传输过程才结束,包括CBW -> DATA -> CSW三次数据传输事务,应该引起device端的3次中断,可是上述程序好像没有明确区分!???
不知我说的有道理否。。。。。。。
Garyyin
驱动牛犊
驱动牛犊
  • 注册日期2007-05-07
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分102分
  • 威望22点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2007-05-09 12:51
顶一下...
游客

返回顶部