Author Topic: Failed to GetDescriptor of device under usb hub (stm32f207 with ULPI module)  (Read 12484 times)

xiaokucha

  • Member
  • ***
  • Posts: 9
Hello guys,

while trying to make usb hub work on the stm32f2xx usb stack, I met a problem.  The enumeration of usb hub is working, I can get the number of hub ports, power on the port, reset the port, and the port status is ok, after reset which is

03 01 00 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER

But when I try to get the descriptor of the device attached to the port(port number is 1), there is no response to the GetDescriptor request(URB status is IDLE).

I used USBH_Modify_Channel to change the channel from address(0x04) to default address(0).

Could anyone help tell me why there is no response to the get descriptor request?

Following is the code for test purpose,
Code: [Select]
static USBH_Status USBH_HandleEnum(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost)
{
  USBH_Status Status = USBH_BUSY;  

  uint8_t Local_Buffer[64];
  static uint8_t tag;
  static uint8_t loop_num;
  uint8_t *evtBuff = pdev->host.Rx_Buffer;

  
  switch (phost->EnumState)
  {
  case ENUM_IDLE:

    /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
    if ( USBH_Get_DevDesc(pdev , phost, 8 ) == USBH_OK)
    {
 phost->Control.ep0size = phost->device_prop.Dev_Desc.bMaxPacketSize;
 phost->usr_cb->PrintHubNum(phost->device_prop.Dev_Desc.bDeviceClass);
 USB_OTG_BSP_mDelay(2000);
 /* Issue Reset  */
          HCD_ResetPort(pdev);

phost->EnumState = ENUM_GET_FULL_DEV_DESC;

      /* modify control channels configuration for MaxPacket size */
      USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_out,
                           0,
                           0,
                           0,
                           phost->Control.ep0size);
      
      USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_in,
                           0,
                           0,
                           0,
                           phost->Control.ep0size);      
    }
    break;  
  case ENUM_GET_FULL_DEV_DESC:  
    /* Get FULL Device Desc  */
    if ( USBH_Get_DevDesc(pdev, phost, USB_DEVICE_DESC_SIZE)\
      == USBH_OK)
    {

      /* user callback for device descriptor available */
      phost->usr_cb->DeviceDescAvailable(&phost->device_prop.Dev_Desc);      
      phost->EnumState = ENUM_SET_ADDR;
    }
    break;
  
  case ENUM_SET_ADDR:
    /* set address */
    if ( USBH_SetAddress(pdev, phost, 4) == USBH_OK)
    {
      phost->device_prop.address = 4;
      
      /* user callback for device address assigned */
      phost->usr_cb->DeviceAddressAssigned();
      /* phost->EnumState = ENUM_GET_CFG_DESC; */
      phost->EnumState = ENUM_GET_CFG_DESC;
      /* modify control channels to upate device address */
      USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_in,
                           phost->device_prop.address,
                           0,
                           0,
                           0);
      
      USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_out,
                           phost->device_prop.address,
                           0,
                           0,
                           0);        
    }
    break;
    
  case ENUM_GET_CFG_DESC:  
    /* get standard configuration descriptor */

    if ( USBH_Get_CfgDesc(pdev,
                          phost,
                          USB_CONFIGURATION_DESC_SIZE) == USBH_OK)
    {
      phost->EnumState = ENUM_GET_FULL_CFG_DESC;
    }
    break;
    
  case ENUM_GET_FULL_CFG_DESC:
    
    /* get FULL config descriptor (config, interface, endpoints) */
    if (USBH_Get_CfgDesc(pdev,
                         phost,
                         phost->device_prop.Cfg_Desc.wTotalLength) == USBH_OK)
    {
      /* User callback for configuration descriptors available */
      phost->usr_cb->ConfigurationDescAvailable(&phost->device_prop.Cfg_Desc,
                                                      phost->device_prop.Itf_Desc,
                                                      phost->device_prop.Ep_Desc[0]);
      
      phost->EnumState = ENUM_SET_CONFIGURATION;
    }
    break;
  case ENUM_SET_CONFIGURATION:
  
    /* set configuration  (default config) */
    if (USBH_SetCfg(pdev,
                    phost,
                    phost->device_prop.Cfg_Desc.bConfigurationValue) == USBH_OK)
    {
phost->EnumState = ENUM_GET_HUB_DESC;
    }
    break;
   case ENUM_GET_HUB_DESC:

     if (USBH_Get_HubDesc(pdev, phost, 8 ) == USBH_OK)
 {
loop_num = phost->device_prop.Hub_Desc.bNbrPorts;
                                tag = 0;
phost->EnumState = ENUM_PWR_ON_PORTS;
 }
  break;
  case ENUM_PWR_ON_PORTS:    
//if (loop_num == 0)
if (tag == 1)
{
phost->EnumState = ENUM_DEV_HUB_TEST;
loop_num = phost->device_prop.Hub_Desc.bNbrPorts;
break;
}  

if (USBH_SetPortFeature(pdev,
phost,
USB_DESC_TYPE_INTERFACE_POWER, /* power on*/
1,
//loop_num,
0) == USBH_OK)
{
tag = 1;
//loop_num--;
}


break;

  case ENUM_DEV_HUB_TEST:
if (loop_num == 0)
{
tag = 0;
phost->EnumState = ENUM_DEV_HUB_CLR;
USB_OTG_BSP_mDelay(100);
break;
}  

if (USBH_GetPortStatus (pdev,
phost,
loop_num,
4,
evtBuff) == USBH_OK)
{
phost->usr_cb->PrintHubNum(evtBuff[0]);
phost->usr_cb->PrintHubNum(evtBuff[1]);
phost->usr_cb->PrintHubNum(evtBuff[2]);
phost->usr_cb->PrintHubNum(evtBuff[3]);

loop_num--;
}
   break;
  case ENUM_DEV_HUB_CLR:
   if (tag == 1)
{
if (USBH_GetPortStatus (pdev,
phost,
1,    /* for test purpose */
4,
evtBuff) == USBH_OK)
{
phost->usr_cb->PrintHubNum(evtBuff[0]);
phost->usr_cb->PrintHubNum(evtBuff[1]);
phost->usr_cb->PrintHubNum(evtBuff[2]);
phost->usr_cb->PrintHubNum(evtBuff[3]);
USB_OTG_BSP_mDelay(1000);
tag = 0;
phost->EnumState = ENUM_DEV_HUB_PORT_RESET;
break;
}
}

if (tag == 0)
{
USB_OTG_BSP_mDelay(1000);
   if (USBH_ClrPortFeature(pdev,
phost,
HUB_FEATURE_C_PORT_CONNECTION,
1,
0) == USBH_OK)
{

tag = 1;
USB_OTG_BSP_mDelay(1000);
}
}
    break;
  case ENUM_DEV_HUB_PORT_RESET:  
   if (tag == 1);
{
if (USBH_GetPortStatus (pdev,
phost,
1,    /* for test purpose */
4,
evtBuff) == USBH_OK)
{

phost->usr_cb->PrintHubNum(evtBuff[0]);
phost->usr_cb->PrintHubNum(evtBuff[1]);
phost->usr_cb->PrintHubNum(evtBuff[2]);
phost->usr_cb->PrintHubNum(evtBuff[3]);
phost->EnumState = ENUM_DEV_HUB_PORT_CLR_RESET;
USB_OTG_BSP_mDelay(1000);
tag = 0;
break;
}
}

if (tag == 0)
{
   if (USBH_SetPortFeature(pdev,
phost,
HUB_FEATURE_PORT_RESET,
1,
0) == USBH_OK)
{
USB_OTG_BSP_mDelay(100);
tag = 1;
}
}
   break;
  case ENUM_DEV_HUB_PORT_CLR_RESET:
   if (tag == 0)
{
   if (USBH_GetPortStatus (pdev,
phost,
1,    /* for test purpose */
4,
evtBuff) == USBH_OK)
{

phost->usr_cb->PrintHubNum(evtBuff[0]);
phost->usr_cb->PrintHubNum(evtBuff[1]);
phost->usr_cb->PrintHubNum(evtBuff[2]);
phost->usr_cb->PrintHubNum(evtBuff[3]);
tag = 1;
}
   }

if (tag == 1)
{
if (USBH_ClrPortFeature(pdev,
phost,
HUB_FEATURE_C_PORT_RESET,
1,
0) == USBH_OK)
{
tag = 2;
USB_OTG_BSP_mDelay(1000);
}
}

if (tag == 2)
{
   if (USBH_GetPortStatus (pdev,
phost,
1,    /* for test purpose */
4,
evtBuff) == USBH_OK)
{

phost->usr_cb->PrintHubNum(evtBuff[0]);
phost->usr_cb->PrintHubNum(evtBuff[1]);
phost->usr_cb->PrintHubNum(evtBuff[2]);
phost->usr_cb->PrintHubNum(evtBuff[3]);
tag = 0;
phost->EnumState = ENUM_DEV_GET_PORT_DESC;
phost->device_prop.address = 0;
USB_OTG_BSP_mDelay(1000);
USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_in,
                           phost->device_prop.address,
                           0,
                           0,
                           64);
      
       USBH_Modify_Channel (pdev,
                           phost->Control.hc_num_out,
                           phost->device_prop.address,
                           0,
                           0,
                           64);

}
}
break;
case ENUM_DEV_GET_PORT_DESC:
if ( USBH_Get_DevDesc(pdev , phost, 8 ) == USBH_OK)
        {
 phost->Control.ep0size = phost->device_prop.Dev_Desc.bMaxPacketSize;
 phost->usr_cb->PrintHubNum(phost->device_prop.Dev_Desc.bDeviceClass);
 USB_OTG_BSP_mDelay(2000);
 phost->EnumState = ENUM_DEV_CONFIGURED;
}
break;
  
  case ENUM_DEV_CONFIGURED:
    /* user callback for enumeration done */
    Status = USBH_OK;
    break;
    
  default:
    break;
  }  
  return Status;
}

Thanks.
« Last Edit: August 24, 2013, 02:01:35 pm by xiaokucha »

xiaokucha

  • Member
  • ***
  • Posts: 9
phost->usr_cb->PrintHubNum(num); is used to print the content of "num" to the LCD screen for debugging.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Did the host send a Set Port Feature request the hub to reset the port with the attached device?

A hardware protocol analyzer will show what is happening on the bus.

xiaokucha

  • Member
  • ***
  • Posts: 9
Did the host send a Set Port Feature request the hub to reset the port with the attached device?

A hardware protocol analyzer will show what is happening on the bus.

Yes, I don't have a analyzer :(, but I can print the port status to the LCD, in the reset process, the status is as follows,

 Set Port Feature (Port1, PORT_RESET)           
 Get Port Status (Port1)                       
              11 01 00 00        PORT_CONNECTION, PORT_RESET, PORT_POWER
 
 Get Port Status (Port1)             
              03 01 10 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER, C_PORT_RESET
 Clear Port Feature (Port1, C_PORT_RESET)     
 Get Port Status (Port1)                       
              03 01 00 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER

xiaokucha

  • Member
  • ***
  • Posts: 9
Did the host send a Set Port Feature request the hub to reset the port with the attached device?

A hardware protocol analyzer will show what is happening on the bus.

Could you help recommend a analyzer? where to buy it? I am new to hardware, this is just a hobby project to kill my free time. :D

xiaokucha

  • Member
  • ***
  • Posts: 9
Just to mention another issue, I didn't handle the Interrupt from hub(maybe endpoint 1) which indicates the port change.  In my example, I just know which port has a device, then go to reset that port directly.

xiaokucha

  • Member
  • ***
  • Posts: 9
After reset port, to change the control channel from 4 to 0(default address), I used USBH_Modify_Channel, wonder if this is correct...  ??? ???

xiaokucha

  • Member
  • ***
  • Posts: 9
I found one analyzer(which I can afford  :'(  ) on ebay ..  http://www.ebay.com/itm/ITIC-1480A-USB-2-0-Protocol-Analyzer-/151085564956?pt=LH_DefaultDomain_0&hash=item232d66c41c 

Has anyone used this before?

Tsuneo

  • Frequent Contributor
  • ****
  • Posts: 145
Quote
03 01 00 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER

This port status means that the target device is a full-speed (FS) device.
wPortStatus: 0x0103
- PORT_LOW_SPEED (bit 9): 0
- PORT_HIGH_SPEED (bit 10): 0

For a FS device under a high-speed hub, you have to set up the host controller for split transactions - the host controller should know the hub address and the port address to fill up split transactions.

On the OTG_HS of STM32F2xx/4xx, OTG_HS_HCSPLTx register is the one to be set up.

Unfortunately, STM32_USB-Host-Device_Lib_V2.1.0 doesn't fully support this function yet.
Just these definitions in usb_regs.h
- USB_OTG_HC_REGS.HCSPLT
- USB_OTG_HCSPLT_TypeDef

And then, you have to implement this function separately.

Tsuneo

xiaokucha

  • Member
  • ***
  • Posts: 9
Quote
03 01 00 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER

This port status means that the target device is a full-speed (FS) device.
wPortStatus: 0x0103
- PORT_LOW_SPEED (bit 9): 0
- PORT_HIGH_SPEED (bit 10): 0

For a FS device under a high-speed hub, you have to set up the host controller for split transactions - the host controller should know the hub address and the port address to fill up split transactions.

On the OTG_HS of STM32F2xx/4xx, OTG_HS_HCSPLTx register is the one to be set up.

Unfortunately, STM32_USB-Host-Device_Lib_V2.1.0 doesn't fully support this function yet.
Just these definitions in usb_regs.h
- USB_OTG_HC_REGS.HCSPLT
- USB_OTG_HCSPLT_TypeDef

And then, you have to implement this function separately.

Tsuneo
Thank you Tsuneo, actually the port setup steps are following your posts in other forums :D

Is there any example/reference(USB specification?) for me to refer to while coding the split transaction? I am blind here...  :'(

xiaokucha

  • Member
  • ***
  • Posts: 9
Quote
03 01 00 00        PORT_CONNECTION, PORT_ENABLE, PORT_POWER

This port status means that the target device is a full-speed (FS) device.
wPortStatus: 0x0103
- PORT_LOW_SPEED (bit 9): 0
- PORT_HIGH_SPEED (bit 10): 0

For a FS device under a high-speed hub, you have to set up the host controller for split transactions - the host controller should know the hub address and the port address to fill up split transactions.

On the OTG_HS of STM32F2xx/4xx, OTG_HS_HCSPLTx register is the one to be set up.

Unfortunately, STM32_USB-Host-Device_Lib_V2.1.0 doesn't fully support this function yet.
Just these definitions in usb_regs.h
- USB_OTG_HC_REGS.HCSPLT
- USB_OTG_HCSPLT_TypeDef

And then, you have to implement this function separately.

Tsuneo
Thank you Tsuneo, actually the port setup steps are following your posts in other forums :D

Is there any example/reference(USB specification?) for me to refer to while coding the split transaction? I am blind here...  :'(

Found some code in freebsd for hub driver, it seems help a lot.