www.Walzer.cn - Tech & Management Blog

Focus on mobile dev
本博客文章,未在标题中写明转载的, 均为原创.
所谓高手,也就是熟悉别人制定的游戏规则、并且能在规则内跳舞的人。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

翻译截下的USB Endpoint初始化过往数据

Posted on 2006-02-05 11:23  Walzer  阅读(3014)  评论(7编辑  收藏  举报

作者:Walzer
日期:2005.3.30

前阵子调试平台的mass-storage function, 想借机把USB Initialization过程了解清楚. 以前的理解都是基于代码的, PC机那边会怎么响应完全是黑盒, 不可见的. 而在初始化过程中不能加入break point, 否则请求超时后, 即使单步调试最后把请求的数据发回, 也被主机认为初始化失败. 因此只能在endpoint的XmitData和ReceiveData函数里添加调试信息把数据都打印出来, 然后根据USB协议还原成REQUEST和PACKET.

    在设备Attach后, 果如所料, client产生了一个EP0 out packet completed的中断, 从device controller的IST分流到EP0 IST中处理,  EP0 IST在确定是setup packet后, 从data register读了32bit进来, 并根据协议分解了该request: 
    Endpoint Zero Setup bmRequestType = 0x80, bRequest=0x6,  wValue=0x100,wIndex=0x0,wLength=0x40.
    其中0x80=设备到主机/标准请求类型/设备接受, 0x6=Get_Descriptor, 0x100=Device_Descriptor.
    下面EP0就XmitData了, 每次写32bit, 分5次写完0x12byte. 注意由于EP0的MaxPacketSize=16byte, 所以第一次IST中写了16byte, 第二次再写2byte.
    msb 0020  0112  lsb
          1000  0000 
          FFFF   0453
          0201  0000
          03F4  0100  
    按照协议翻译出来就是bLength=0x12, bDescriptorType=0x1(device descriptor), bcdUSB=0x0200(protocol 2.0), bDeviceClass=0, bDeviceSubClass=0, bDeviceProtocol=0x0, bMaxPacketSize=0x10(16byte), idVendor=0x0453(Microsoft), idProduct=0xffff(OEM), bcdDevice=0, iManufacturer=1, iProduct=2, iSerialNumber=0, bNumConfigurations=1.  后面的就没有用了. 注意iManufacturer, iProduct, iSerialNumber, 这个决定了后面GetString请求里wValue掉低字节的值和所获得string的关系. 如果发送的device descriptor不足18byte的话, host会再次发送get device descriptor的request直至host收全了这18byte.

    第二步host就发过来Get Config Descriptor的请求了, 此时client需将该config下的所有interface和endpoint描述符全部发送给host. 但这其中又分了两步. 首先是纯粹地get config descriptor:
    Endpoint Zero Setup bmRequestType = 0x80, bRequest=0x6, wValue=0x200,wIndex=0x0,wLength=0x9
    0x80=设备到主机/标准请求/设备接受, 0x6=GetDescriptor, 0x200=Config_Descriptor. 注意到Length=9正好为config descriptor的长度.
    这时client返回数据如下:
 0020  0209
 C000  0101
 C000  0100
    翻译出来bLength=9, bDescriptorType=2(config descriptor), wTotalLength=0x20(该配置返回的数据总长度,包括其下interface, endpoint descriptor的总长度), 后面的就先不看了,没有意义. host主要就是想索取这个wTotalLength以决定下一次需要获取多少长度.
    马上host再发了一个get config descriptor,
    Endpoint Zero Setup bmRequestType = 0xx80, bRequest=0x6, wValue=0x200,wIndex=0x0,wLength=0xff
    它倒聪明, 对wTotalLength看都不看, 直接给了个0xff长度, 有多少要多少.
    client就老老实实填满0x20byte发过去了
 0020  0209 CONFIG: bLength=9, bDescriptorType=2(config), wTotalLength=0x20,
 C000  0101 bNumInterface=1, bConfigurationValue=1, iConfiguration=0, bmAttributes=0xC0(self-powered)
 0004  0900 bMaxPower=0   //  INTERFACE: bLength=9, bDescriptorType=4(interface), bInterfaceNumber=0
 0608  0200 bNumEndpoints=2(except ep0, bulk-only transport), bInterfaceClass=8(mass storage class), bInterfaceSubClass=6(SCSI)
 0507  0050 bInterfaceProtocol=0x50(bulk-only transport), iInterface=0. // ENDPOINT1: bLength=7, bDescriptorType=5(endpoint)
 0040  0281 bEndpointAddress=0x81(ep1, in), bmAttributes=2(bulk, non-sync, data), wMaxPacketSize=0x40(64byte),
 0205  0700 bInterval=0(ignore for bulk ep). // ENDPOINT2: bLength=7, bDescriptorType=5, bEndpointAddress=2(ep2, out)
 0000  4002 bmAttributes=2(bulk, non-sync, data), wMaxPacketSize=0x40, bInterval=0
   最后还得SendControlStatusHandshake.

    接下来是Endpoint Zero Setup bmRequestType = 0xx80, bRequest=0x6, wValue=0x300,wIndex=0x0,wLength=0xff,  host想要get string descriptor(wValue高八位=0x3)了,这回wValue低八位=0, 对应SupportedLanguage. CLIENT返回了04090304, 翻译出来是bLength=4, bDescriptorType=3(string), wLANGID=0409(english-only).

    下面这个要发的就多了 Endpoint Zero Setup bmRequestType = 0xx80, bRequest=0x6, wValue=0x302,wIndex=0x409,wLength=0xff.
    这里wValue低八位=2, 对应Product String. 只见CLIENT发了N多数据过去, 把这些数据按照ASCII编码翻译过来,就是体现在host端的device name了.

    理论上还应该有get manufacturer string descriptor和get serial number string descriptor的过程, 但在这次调试中没有看到. 最终mass storage client由于没有store objet而在OpenStore函数的CreateFile处失败了.