Beispiel #1
0
/*FUNCTION*----------------------------------------------------------------
* 
* Function Name  : usb_host_cntrl_transaction_done
* Returned Value : none
* Comments       :
*     Callback function to process transaction-done events
*     State machine for enumeration/subsequent transactions
*     Between states, the 8-byte buffer in device_instance
*        is used to save the first part of the configuration.
*     Pointer desc in various flavors (uchar_ptr, cfig_ptr)
*        is used to parse this buffer in various ways. 
* 
*END*--------------------------------------------------------------------*/
static void  usb_host_cntrl_transaction_done
   (
      /* [IN] the pipe handle */
      _usb_pipe_handle  handle,

      /* [IN] The user parameter */
      pointer           user_parm,

      /* [IN] the buffer */
      uchar_ptr         buffer,

      /* [IN] The length of the transfer */
      uint_32           length,

      /* [IN] status of the transfer */
      uint_32           status
   )
{ /* Body */
   USB_HOST_STATE_STRUCT_PTR  usb_host_ptr;
   PIPE_DESCRIPTOR_STRUCT_PTR pipe_ptr =
      (PIPE_DESCRIPTOR_STRUCT_PTR)handle;
   DEV_INSTANCE_PTR           dev_inst_ptr =
      (DEV_INSTANCE_PTR)pipe_ptr->DEV_INSTANCE;
   DESCRIPTOR_UNION           desc;
   pointer                    temp = NULL;
   uint_32                    config_size;
   
   usb_host_ptr = (USB_HOST_STATE_STRUCT_PTR)dev_inst_ptr->host;

   /*----------------------------------------------------**
   ** Enumeration state machine -- cases are named after **
   ** the just-completed transactions.                   **
   **----------------------------------------------------*/
   
   switch (dev_inst_ptr->state) {
      case DEVSTATE_INITIAL:      /* initial device state */
         break;   
      case DEVSTATE_DEVDESC8:     /* device descriptor [0..7]*/
         /* We must have received the first 8 bytes in 
         ** dev_inst_ptr->dev_descriptor which contains the 
         ** max packet size for this control endpoint 
         */
         pipe_ptr->MAX_PACKET_SIZE = 
            dev_inst_ptr->dev_descriptor.bMaxPacketSize;
            
         /* Notify device driver of MaxPacketSize0 for this device */
         status = _usb_host_update_max_packet_size_call_interface (usb_host_ptr, pipe_ptr);
         
         if (status != USB_OK)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }
         else
         {
            dev_inst_ptr->state = DEVSTATE_ADDR_SET;
         }

         /* Now set the address that we assigned when we initialized 
         ** the device instance struct for this device 
         */
         status = _usb_host_ch9_set_address((pointer)dev_inst_ptr);
         
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;
      case DEVSTATE_ADDR_SET:     /* address set */
         pipe_ptr->DEVICE_ADDRESS = dev_inst_ptr->address;
         
         /* Notify device driver of USB device's new address */
         status = _usb_host_update_device_address_call_interface (usb_host_ptr, pipe_ptr);
         
         if (status != USB_OK)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         dev_inst_ptr->state = DEVSTATE_DEV_DESC;

         /* Now get the full descriptor */
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_DEV << 8, 
            0, 
            USB_DESC_LEN_DEV,
            (uchar_ptr)&dev_inst_ptr->dev_descriptor);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;   
      case DEVSTATE_DEV_DESC:     /* full device descriptor received */
         /* Now lets get the first 9 bytes of the configuration 
         ** descriptor 
         */
         desc.pntr = &dev_inst_ptr->buffer;
         dev_inst_ptr->state = DEVSTATE_GET_CFG9;
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_CFG << 8, 
            0, 
            sizeof(dev_inst_ptr->buffer),
            desc.bufr);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;
      case DEVSTATE_GET_CFG9:     /* Read 9 bytes of config descriptor */
         dev_inst_ptr->state = DEVSTATE_SET_CFG;
         /* Now select the configuration as specified in the 
         ** descriptor 
         */
         desc.cfig = (CONFIGURATION_DESCRIPTOR_PTR)dev_inst_ptr->buffer;
         config_size = utoh16(desc.cfig->wTotalLength);

         desc.pntr = &dev_inst_ptr->buffer;
         if (USB_OK != usb_dev_list_get_memory(dev_inst_ptr,
            config_size,
            USB_MEMTYPE_CONFIG,
            (pointer _PTR_)&desc))
         {
           return;
         }
         desc.word += MEM_HEADER_LEN; /* step past header */   
         dev_inst_ptr->state = DEVSTATE_SET_CFG;
#ifdef OTG_BUILD
        
         
         //the device has to be attached directly(no intervening hub between the Host and the B device) 
         if(dev_inst_ptr->next == (DEV_INSTANCE_PTR)NULL)
          {
          dev_inst_ptr->state = DEVSTATE_CHK_OTG;
          }
#endif
         /* We can only read one config descriptor at a time */
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_CFG << 8, 
            0, 
            (uint_16)config_size,
            desc.bufr);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;   
#ifdef OTG_BUILD
      case DEVSTATE_CHK_OTG:
         /* Point to the memory owned by this device */
         desc.pntr = &dev_inst_ptr->memlist->payload;

         /* We will always start with config desc so update the search pointer */
         config_size = utoh16(desc.cfig->wTotalLength);
         config_size -= desc.cfig->bLength;
         desc.word += desc.cfig->bLength;

         while (config_size) {
            if (desc.otg->bDescriptorType == USB_DESC_TYPE_OTG) {
               /* Found the OTG descriptor */
               break;
            } /* Endif */
            config_size -= desc.intf->bLength;
            desc.word += desc.intf->bLength;
         } /* EndWhile */

         /* Check for an OTG descriptor */
         dev_inst_ptr->state = DEVSTATE_SET_CFG;

         if (config_size && (desc.otg->bDescriptorType == USB_DESC_TYPE_OTG)) 
         {
           if(_usb_otg_get_otg_attribute( dev_inst_ptr , desc.otg->bmAttributes) == USB_OK )
           {
             if( _usb_otg_set_feature_required(dev_inst_ptr) )
             {
               status = _usb_host_ch9_set_feature(dev_inst_ptr, 0, 0, OTG_A_HNP_SUPPORT);
               if (status != USB_STATUS_TRANSFER_QUEUED)
               {
                 dev_inst_ptr->state = DEVSTATE_INITIAL;
               }
               else
               {
                 dev_inst_ptr->state = DEVSTATE_SET_HNP;
               }
               break;  
             }
            
            
            }
            
         } /* Endif */

         /* Fall through */
#endif         

      case DEVSTATE_SET_CFG:     /* config descriptor [0..8] */

         /* Point to the memory owned by this device */
         desc.pntr = &dev_inst_ptr->memlist->payload;
         dev_inst_ptr->state = DEVSTATE_CFG_READ;
         status = _usb_host_ch9_set_configuration(dev_inst_ptr, 
            desc.cfig->bConfigurationValue);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break; 
           
#ifdef OTG_BUILD
      case DEVSTATE_SET_HNP:
           dev_inst_ptr->state = DEVSTATE_SET_CFG;
           status = _usb_host_ch9_set_feature(dev_inst_ptr, 0, 0, OTG_B_HNP_ENABLE);
            
            if (status != USB_STATUS_TRANSFER_QUEUED)
            {
             dev_inst_ptr->state = DEVSTATE_INITIAL;
            }
            else
            {
             _usb_otg_a_set_b_hnp_en(dev_inst_ptr, TRUE);  
            }
           
           break;
#endif           
      case DEVSTATE_CFG_READ:     /* full config desc. read in */
         dev_inst_ptr->state = DEVSTATE_APP_CALL;

         /* Scan the configuration descriptor to find out the total 
         ** number of interfaces available. This will be the upper 
         ** bound for searching through the interface descriptors' 
         ** array
         */
         dev_inst_ptr->num_of_interfaces = 0;

         /* Point to the memory owned by this device */
         desc.pntr = &dev_inst_ptr->memlist->payload;
         /* We will always start with config desc so update the search pointer */
         config_size = utoh16(desc.cfig->wTotalLength);
         config_size -= desc.cfig->bLength;
         desc.word += desc.cfig->bLength;
         
         while (config_size) {
            if (desc.intf->bDescriptorType == USB_DESC_TYPE_IF) {
               /* Found an interface */
               dev_inst_ptr->num_of_interfaces++;
            } /* Endif */
            /* EAI - if desc.intf->bLength this while loop never exits!!!! */
            if (desc.intf->bLength) {
               config_size -= desc.intf->bLength;
               desc.word += desc.intf->bLength;
            } else {
               /* Not sure what proper error recovery is yet. */
               break;
            }
         } /* EndWhile */

         /* Don't select an interface here. The device driver will 
         ** select the interface 
         */

      case DEVSTATE_APP_CALL:     /* full config desc. read in */
         dev_inst_ptr->state = DEVSTATE_SET_INTF;
         if (dev_inst_ptr->new_config != 0) {
            /* We have just read a new configuration descriptor */
            dev_inst_ptr->new_config = 0;
            usb_hostdev_attach_detach(dev_inst_ptr, USB_CONFIG_EVENT);
         } else {
            usb_hostdev_attach_detach(dev_inst_ptr, USB_ATTACH_EVENT);
         } /* EndIf */
         break;

      case DEVSTATE_SET_INTF:    /* Select interface done */
         dev_inst_ptr->state = DEVSTATE_ENUM_OK;
         usb_hostdev_attach_detach(dev_inst_ptr, USB_INTF_EVENT);
         break;
      default:
         dev_inst_ptr->state = DEVSTATE_ENUM_OK;
         case DEVSTATE_ENUM_OK:   /* enumeration complete */
            if ((dev_inst_ptr->control_callback != NULL))
               dev_inst_ptr->control_callback
                  (handle,
                  user_parm,
                  buffer,
                  length,
                  status);
            break;   
      } /* EndSwitch */         
      
} /* EndBody */
/*FUNCTION*----------------------------------------------------------------
* 
* Function Name  : usb_dev_list_detach_device
* Returned Value : 
* Comments       :
*     This function will be called when detach interrupt happens.
* 
*END*--------------------------------------------------------------------*/
void  usb_dev_list_detach_device
   (
      _usb_host_handle  handle,
      uint_8            hub_no,
      uint_8            port_no
   )
{ /* Body */
   USB_HOST_STATE_STRUCT_PTR  usb_host_ptr = 
      (USB_HOST_STATE_STRUCT_PTR)handle;
   DEV_INSTANCE_PTR  dev_instance_ptr;
   DEV_INSTANCE_PTR  _PTR_ device_root = 
      (DEV_INSTANCE_PTR _PTR_)&usb_host_ptr->DEVICE_LIST_PTR;
   /* search device list for the one being detached */
   USB_lock();
   for (dev_instance_ptr = *device_root;   
      dev_instance_ptr != NULL;
      dev_instance_ptr = dev_instance_ptr->next)   
   {
      if (dev_instance_ptr->port_no != port_no)
         continue;
      if (dev_instance_ptr->hub_no != hub_no)
         continue;
      if (dev_instance_ptr->host != handle)
         continue;
      break;
   } /* EndFor */

   USB_unlock();

   if (dev_instance_ptr == NULL) {
      return;  /* No match, abandon ship! */
   } /* Endif */

   /* SGarg 09/23/2003 . Sometimes  a detach could come even before a 
   attach is finished. This means that we should make sure that device
   memory is not NULL before we try to clean it up. For example this happens
   with OPT tester test 4.10.*/
   
   if(dev_instance_ptr->memlist != NULL)
   {
      /* Notify the application of unavailable interfaces */
      usb_hostdev_attach_detach(dev_instance_ptr, USB_DETACH_EVENT);
      
   }

   /* Unlink device from the instance list */
   dev_instance_ptr->control_callback = NULL; /* no surprises */

   /* Close control pipe */
   usb_dev_list_close_pipe(handle, (PIPE_DESCRIPTOR_STRUCT_PTR)dev_instance_ptr->control_pipe);
   
   /* SGarg 09/24/2003 . Sometimes  a detach could come even before a 
   attach is finished. This means that we should make sure that device
   memory is not NULL before we try to clean it up. For example this happens
   with OPT tester test 4.10.*/
   if(dev_instance_ptr->memlist != NULL)
   {
      usb_dev_list_free_memory((pointer)dev_instance_ptr);
   }

   USB_lock();

   /* Find the address of the "pointer to the detached device" */
   while (*device_root != dev_instance_ptr) {
      device_root = &(*device_root)->next;
   } /* Endwhile */

   /* Remove the device */
   *device_root = dev_instance_ptr->next;

   USB_mem_free(dev_instance_ptr);

   USB_unlock();
} /* EndBody */
Beispiel #3
0
/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_dev_list_detach_device
* Returned Value :
* Comments       :
*     This function will be called when detach interrupt happens.
*
*END*--------------------------------------------------------------------*/
void  usb_dev_list_detach_device
(
    _usb_host_handle  handle,
    uint_8            hub_no,
    uint_8            port_no
)
{   /* Body */
    USB_HOST_STATE_STRUCT_PTR  usb_host_ptr = (USB_HOST_STATE_STRUCT_PTR)handle;
    DEV_INSTANCE_PTR  dev_instance_ptr;
    DEV_INSTANCE_PTR  _PTR_ device_root = (DEV_INSTANCE_PTR _PTR_)&usb_host_ptr->DEVICE_LIST_PTR;
#ifdef __USB_OTG__
    uint_32           state;
#endif

#ifdef _HOST_DEBUG_
    DEBUG_LOG_TRACE("usb_dev_list_detach_device");
#endif

    /* search device list for the one being detached */
    USB_lock();
    for (dev_instance_ptr = *device_root;
            dev_instance_ptr != NULL;
            dev_instance_ptr = dev_instance_ptr->next)
    {
        if (dev_instance_ptr->port_no != port_no)
            continue;
        if (dev_instance_ptr->hub_no != hub_no)
            continue;
        if (dev_instance_ptr->host != handle)
            continue;
        break;
    } /* EndFor */

    USB_unlock();

    if (dev_instance_ptr == NULL) {
#ifdef _HOST_DEBUG_
        DEBUG_LOG_TRACE("usb_dev_list_detach_device NULL device pointer");
#endif
        return;  /* No match, abandon ship! */
    } /* Endif */

    /* SGarg 09/23/2003 . Sometimes  a detach could come even before a
    attach is finished. This means that we should make sure that device
    memory is not NULL before we try to clean it up. For example this happens
    with OPT tester test 4.10.*/

    if(dev_instance_ptr->memlist != NULL)
    {
        /* Notify the application of unavailable interfaces */
        usb_hostdev_attach_detach(dev_instance_ptr, USB_DETACH_EVENT);

    }

    /* Unlink device from the instance list */
    dev_instance_ptr->control_callback = NULL; /* no surprises */

    /* Close control pipe */
    usb_dev_list_close_pipe(handle, (PIPE_STRUCT_PTR)dev_instance_ptr->control_pipe);

    /* SGarg 09/24/2003 . Sometimes  a detach could come even before a
    attach is finished. This means that we should make sure that device
    memory is not NULL before we try to clean it up. For example this happens
    with OPT tester test 4.10.*/
    if(dev_instance_ptr->memlist != NULL)
    {
        usb_dev_list_free_memlist((_usb_device_instance_handle)dev_instance_ptr);
    }

    USB_lock();

    /* Find the address of the "pointer to the detached device" */
    while (*device_root != dev_instance_ptr) {
        device_root = &(*device_root)->next;
    } /* Endwhile */

    /* Remove the device */
    *device_root = dev_instance_ptr->next;

    USB_mem_free(dev_instance_ptr);

#ifdef __USB_OTG__
    _usb_otg_get_status((pointer)usb_otg_state_struct_ptr,
                        USB_OTG_STATE, &state);

    if (state < B_IDLE) {
        _usb_otg_get_status((pointer)usb_otg_state_struct_ptr,
                            USB_OTG_B_CONN, &state);
        if (state) {
            _usb_otg_set_status((pointer)usb_otg_state_struct_ptr,
                                USB_OTG_B_CONN, FALSE);
        } /* Endif */
    } else {
        _usb_otg_get_status((pointer)usb_otg_state_struct_ptr,
                            USB_OTG_A_CONN, &state);
        if (state) {
            _usb_otg_set_status((pointer)usb_otg_state_struct_ptr,
                                USB_OTG_A_CONN, FALSE);
        } /* Endif */
    } /* Endif */
#endif

    USB_unlock();
#ifdef _HOST_DEBUG_
    DEBUG_LOG_TRACE("usb_dev_list_detach_device SUCCESSFUL");
#endif

} /* EndBody */
Beispiel #4
0
/*FUNCTION*----------------------------------------------------------------
* 
* Function Name  : usb_host_cntrl_transaction_done
* Returned Value : none
* Comments       :
*     Callback function to process transaction-done events
*     State machine for enumeration/subsequent transactions
*     Between states, the 8-byte buffer in device_instance
*        is used to save the first part of the configuration.
*     Pointer desc in various flavors (uchar_ptr, cfig_ptr)
*        is used to parse this buffer in various ways. 
* 
*END*--------------------------------------------------------------------*/
static void  usb_host_cntrl_transaction_done
   (
      /* [IN] the pipe handle */
      _usb_pipe_handle  handle,

      /* [IN] The user parameter */
      pointer           user_parm,

      /* [IN] the buffer */
      uchar_ptr         buffer,

      /* [IN] The length of the transfer */
      uint_32           length,

      /* [IN] status of the transfer */
      uint_32           status
   )
{ /* Body */
   USB_HOST_STATE_STRUCT_PTR  usb_host_ptr;
   PIPE_DESCRIPTOR_STRUCT_PTR pipe_ptr =
      (PIPE_DESCRIPTOR_STRUCT_PTR)handle;
   DEV_INSTANCE_PTR           dev_inst_ptr =
      (DEV_INSTANCE_PTR)pipe_ptr->DEV_INSTANCE;
   DESCRIPTOR_UNION           desc;
   int_32                     config_size;
   DEV_MEMORY_PTR             dev_mem;

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_host_cntrl_transaction_done");
   #endif

   usb_host_ptr = (USB_HOST_STATE_STRUCT_PTR)dev_inst_ptr->host;

   switch (status) {
      case USB_OK:
         dev_inst_ptr->ctrl_retries = USBCFG_CTRL_RETRY;
         break;

      case USBERR_TR_FAILED:
         if (buffer != NULL) {
            dev_inst_ptr->ctrl_retries--;
            if (dev_inst_ptr->ctrl_retries) {
               if (dev_inst_ptr->state == DEVSTATE_DEVDESC8) {
                  /* dont jump to DEVSTATE_INITIAL state, get descriptor instead */
                  status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
                     USB_DESC_TYPE_DEV << 8, 0, 8, 
                     (uchar_ptr)buffer);
                  return;
               }
               else {
                  dev_inst_ptr->state--; /* back to previous enum state */
                  status = USB_OK;
                  _time_delay(100);
               }
            }
         } else
            dev_inst_ptr->state = DEVSTATE_INITIAL;
         break;

      case USBERR_ENDPOINT_STALLED:
         dev_inst_ptr->ctrl_retries--;
         if (dev_inst_ptr->ctrl_retries) {
            status = _usb_host_ch9_clear_feature((pointer)dev_inst_ptr, REQ_TYPE_ENDPOINT, 0, ENDPOINT_HALT);
            if (status == USB_OK)
                _time_delay(100);
         }
         break;

      default:
         dev_inst_ptr->state = DEVSTATE_INITIAL;
         break;
   }

   if (status != USB_OK)
      return;

   /*----------------------------------------------------**
   ** Enumeration state machine -- cases are named after **
   ** the just-completed transactions.                   **
   **----------------------------------------------------*/
   
   switch (dev_inst_ptr->state) {
      case DEVSTATE_INITIAL:      /* initial device state = forever error state */
         break;   
      case DEVSTATE_DEVDESC8:     /* device descriptor [0..7]*/
         /* We must have received the first 8 bytes in 
         ** dev_inst_ptr->dev_descriptor which contains the 
         ** max packet size for this control endpoint 
         */
         pipe_ptr->MAX_PACKET_SIZE = 
            dev_inst_ptr->dev_descriptor.bMaxPacketSize;
            
         /* Notify device driver of MaxPacketSize0 for this device */
         status = _usb_host_update_max_packet_size_call_interface (usb_host_ptr, pipe_ptr);
         
         if (status != USB_OK)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }
         else
         {
            dev_inst_ptr->state = DEVSTATE_ADDR_SET;
         }

         /* Now set the address that we assigned when we initialized 
         ** the device instance struct for this device 
         */
         status = _usb_host_ch9_set_address((pointer)dev_inst_ptr);
         
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;
      case DEVSTATE_ADDR_SET:     /* address set */
         pipe_ptr->DEVICE_ADDRESS = dev_inst_ptr->address;
         
         /* Notify device driver of USB device's new address */
         status = _usb_host_update_device_address_call_interface (usb_host_ptr, pipe_ptr);
         
         if (status != USB_OK)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         dev_inst_ptr->state = DEVSTATE_DEV_DESC;

         /* Now get the full descriptor */
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_DEV << 8, 
            0, 
            USB_DESC_LEN_DEV,
            (uchar_ptr)&dev_inst_ptr->dev_descriptor);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;   
      case DEVSTATE_DEV_DESC:     /* full device descriptor received */
         /* Now lets get the first 9 bytes of the configuration 
         ** descriptor 
         */
         desc.pntr = &dev_inst_ptr->buffer;
         dev_inst_ptr->state = DEVSTATE_GET_CFG9;
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_CFG << 8, 
            0, 
            sizeof(dev_inst_ptr->buffer),
            desc.bufr);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;
      case DEVSTATE_GET_CFG9:     /* Read 9 bytes of config descriptor */
         dev_inst_ptr->state = DEVSTATE_SET_CFG;
         /* Now select the configuration as specified in the 
         ** descriptor 
         */
         desc.cfig = (CONFIGURATION_DESCRIPTOR_PTR)dev_inst_ptr->buffer;
         config_size = SHORT_LE_TO_HOST(*(uint_16*)desc.cfig->wTotalLength);

         desc.pntr = &dev_inst_ptr->buffer;
         if (USB_OK != usb_dev_list_get_mem(dev_inst_ptr,
            config_size,
            USB_MEMTYPE_CONFIG,
            1,
            &dev_mem))
         {
            #ifdef _HOST_DEBUG_
               DEBUG_LOG_TRACE("usb_host_cntrl_transaction_done");
            #endif
            return;
         }
         /* Move the pointer to the aligned payload */
         desc.pntr = dev_mem->payload.data + dev_mem->offset;
         
#ifdef __USB_OTG__
         dev_inst_ptr->state = DEVSTATE_CHK_OTG;
#else
         dev_inst_ptr->state = DEVSTATE_SET_CFG;
#endif
         /* We can only read one config descriptor at a time */
         status = _usb_host_ch9_get_descriptor((pointer)dev_inst_ptr,
            USB_DESC_TYPE_CFG << 8, 
            0, 
            (uint_16)config_size,
            desc.bufr);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;   

      case DEVSTATE_CHK_OTG:
         /* Point to the memory owned by this device */
         /* FIXME: it is presumed that memlist points to the config descriptor */
         desc.pntr = dev_inst_ptr->memlist->payload.data + dev_inst_ptr->memlist->offset;

         /* We will always start with config desc so update the search pointer */
         config_size = SHORT_LE_TO_HOST(*(uint_16*)desc.cfig->wTotalLength);
         config_size -= desc.cfig->bLength;
         desc.word += desc.cfig->bLength;

         while (config_size) {
            if (desc.otg->bDescriptorType == USB_DESC_TYPE_OTG) {
               /* Found the OTG descriptor */
               break;
            } /* Endif */
            config_size -= desc.intf->bLength;
            desc.word += desc.intf->bLength;
         } /* EndWhile */

         /* Check for an OTG descriptor */
         dev_inst_ptr->state = DEVSTATE_SET_CFG;

         if (config_size && desc.otg->bDescriptorType == USB_DESC_TYPE_OTG &&
            (desc.otg->bmAttributes & OTG_HNP_SUPPORT))
         {
            status = _usb_host_ch9_set_feature(dev_inst_ptr, 0, 0, 4);
            
            if (status != USB_STATUS_TRANSFER_QUEUED)
            {
               dev_inst_ptr->state = DEVSTATE_INITIAL;
               break;
            }
            else
            {
               break;
            }

         } /* Endif */

         /* Fall through */

      case DEVSTATE_SET_CFG:     /* config descriptor [0..8] */

         /* Point to the memory owned by this device */
         /* FIXME: it is presumed that memlist points to the config descriptor */
         desc.pntr = dev_inst_ptr->memlist->payload.data + dev_inst_ptr->memlist->offset;

         dev_inst_ptr->state = DEVSTATE_CFG_READ;
         status = _usb_host_ch9_set_configuration(dev_inst_ptr, 
            desc.cfig->bConfigurationValue);
            
         if (status != USB_STATUS_TRANSFER_QUEUED)
         {
            dev_inst_ptr->state = DEVSTATE_INITIAL;
            break;
         }

         break;   

      case DEVSTATE_CFG_READ:     /* full config desc. read in */
         dev_inst_ptr->state = DEVSTATE_APP_CALL;

         /* Scan the configuration descriptor to find out the total 
         ** number of interfaces available. This will be the upper 
         ** bound for searching through the interface descriptors' 
         ** array
         */
         dev_inst_ptr->num_of_interfaces = 0;

         /* Point to the memory owned by this device */
         /* FIXME: it is presumed that memlist points to the config descriptor */
         desc.pntr = dev_inst_ptr->memlist->payload.data + dev_inst_ptr->memlist->offset;

         /* We will always start with config desc so update the search pointer */
         config_size = SHORT_LE_TO_HOST(*(uint_16*)desc.cfig->wTotalLength);
         config_size -= desc.cfig->bLength;
         desc.word += desc.cfig->bLength;
         
         while (config_size > 0) {
            if (desc.intf->bDescriptorType == USB_DESC_TYPE_IF) {
               /* Found an interface */
               dev_inst_ptr->num_of_interfaces++;
            } /* Endif */
            if (desc.intf->bLength) {
               config_size -= desc.intf->bLength;
               desc.word += desc.intf->bLength;
            } else {
               /* Zero-sized interface found */
               status = USBERR_INVALID_CFIG_NUM;
               break;
            }
         } /* EndWhile */
         if (config_size < 0) {
            /* Error: we have not read the configuration descriptor properly,
            ** some part is missing. Symptom: there is not config descriptor
            ** info left for latest descriptor.
            */
            status = USBERR_INVALID_CFIG_NUM;
         }
         if (status == USBERR_INVALID_CFIG_NUM) {
            /* TODO: Remove config descriptor from memlist and try to re-read. */
            break;
         }

         /* Don't select an interface here. The device driver will 
         ** select the interface 
         */

      case DEVSTATE_APP_CALL:     /* full config desc. read in */
         dev_inst_ptr->state = DEVSTATE_SET_INTF;
         if (dev_inst_ptr->new_config != 0) {
            /* We have just read a new configuration descriptor */
            dev_inst_ptr->new_config = 0;
            usb_hostdev_attach_detach(dev_inst_ptr, USB_CONFIG_EVENT);
         } else {
            usb_hostdev_attach_detach(dev_inst_ptr, USB_ATTACH_EVENT);
         } /* EndIf */
         break;

      case DEVSTATE_SET_INTF:    /* Select interface done */
         dev_inst_ptr->state = DEVSTATE_ENUM_OK;
         usb_hostdev_attach_detach(dev_inst_ptr, USB_INTF_EVENT);
         break;
      default:
         dev_inst_ptr->state = DEVSTATE_ENUM_OK;
         case DEVSTATE_ENUM_OK:   /* enumeration complete */
            if ((dev_inst_ptr->control_callback != NULL))
               dev_inst_ptr->control_callback
                  (handle,
                  user_parm,
                  buffer,
                  length,
                  status);
            break;   
      } /* EndSwitch */

   #ifdef _HOST_DEBUG_
   if (dev_inst_ptr->state == DEVSTATE_INITIAL)
   {
      DEBUG_LOG_TRACE("usb_host_cntrl_transaction_done FAILED");
   }
   else
   {
      DEBUG_LOG_TRACE("usb_host_cntrl_transaction_done SUCCESSFUL");
   }
   #endif
      
} /* EndBody */