Ejemplo n.º 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 (uint8_t *, cfig_ptr)
*        is used to parse this buffer in various ways. 
* 
*END*--------------------------------------------------------------------*/
static void  usb_host_cntrl_transaction_done
(
    /* [IN] Unused */
    void*           tr_ptr,
    /* [IN] The user parameter */
    void*           user_parm,
    /* [IN] the buffer */
    uint8_t *         buffer,
    /* [IN] The length of the transfer */
    uint32_t           length,
    /* [IN] status of the transfer */
    usb_status        status
)
{
    usb_host_state_struct_t*    usb_host_ptr;
    dev_instance_t*             dev_inst_ptr = (dev_instance_t*)user_parm;
    pipe_struct_t*              pipe_ptr = dev_inst_ptr->control_pipe;
    descriptor_union_t          desc;
    int32_t                     config_size = 0;

    uint32_t                   aligned_config_size = 0;
	usb_host_api_functions_struct_t* host_api;
#ifdef USBCFG_OTG
    static bool                otg_hnp_support;
#endif
    usb_host_ptr = (usb_host_state_struct_t*)dev_inst_ptr->host;

	host_api = (usb_host_api_functions_struct_t*)usb_host_ptr->host_controller_api;


    if (usb_host_release_tr(usb_host_ptr, tr_ptr) != USB_OK)
    {
        printf("_usb_host_release_tr failed\n");
    }

    switch (status)
    {
        case USB_OK:
            dev_inst_ptr->ctrl_retries = USBCFG_HOST_CTRL_RETRY;
            dev_inst_ptr->stall_retries = USBCFG_HOST_CTRL_RETRY;
            break;
  
        case USBERR_TR_FAILED:
        case USBERR_ENDPOINT_STALLED:
        
            //printf("TR failed buffer : %x\n\r", buffer);
            dev_inst_ptr->ctrl_retries--;
            dev_inst_ptr->stall_retries--;
            if ((status == USBERR_ENDPOINT_STALLED)&&(dev_inst_ptr->stall_retries))
            {
               printf("USBERR_ENDPOINT_STALLED\n");
               status = _usb_host_ch9_clear_feature((usb_device_instance_handle)dev_inst_ptr, REQ_TYPE_ENDPOINT, 0, ENDPOINT_HALT);
            }
            else if ((dev_inst_ptr->stall_retries == 0) || ((dev_inst_ptr->ctrl_retries)&&(status == USBERR_TR_FAILED)))
            {
                /* if hub level is 1 will do port reset */
				if(dev_inst_ptr->level == 1)
                {
                    host_api = (usb_host_api_functions_struct_t*)usb_host_ptr->host_controller_api;

                    if (host_api->host_bus_control != NULL)
                    {
                        host_api->host_bus_control(usb_host_ptr->controller_handle, 1);
                    }
                    status = _usb_host_ch9_get_descriptor((usb_device_instance_handle)dev_inst_ptr,
                                                              USB_DESC_TYPE_DEV << 8, 0, 8, 
                                                              (uint8_t *)buffer);
                    dev_inst_ptr->state = DEVSTATE_DEVDESC8;
                }
                else  
                {
#if USBCFG_HOST_HUB                   
                    usb_host_hub_Port_Reset(dev_inst_ptr->hub_instance, dev_inst_ptr->port_no);
                    usb_host_dev_mng_detach(dev_inst_ptr->host, dev_inst_ptr->hub_no, dev_inst_ptr->port_no);
#endif
                }
            }

            break;
  
        
        default:
            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 
                    */
            //printf("dev8\n");
            pipe_ptr->max_packet_size = dev_inst_ptr->dev_descriptor.bMaxPacketSize;
            //printf("DEVSTATE_DEVDESC8 %d\n",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)
            {
                printf("update max packet size error\n");
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                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((usb_device_instance_handle)dev_inst_ptr);
            
            if (status != USB_OK)
            {
                printf("set address error\n");
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }
   
            break;
       case DEVSTATE_ADDR_SET:     /* address set */
            //pipe_ptr->DEVICE_ADDRESS = dev_inst_ptr->address;
         //   printf("add set %d\n", dev_inst_ptr->target_address);
            dev_inst_ptr->address = dev_inst_ptr->target_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)
            {
                printf("update device address error\n");
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }
            dev_inst_ptr->state = DEVSTATE_DEV_DESC;
            //printf("descriptor address 0x%x\n", &dev_inst_ptr->dev_descriptor);
            /* Now get the full descriptor */
            status = _usb_host_ch9_get_descriptor((usb_device_instance_handle)dev_inst_ptr,
                USB_DESC_TYPE_DEV << 8, 
                0, 
                USB_DESC_LEN_DEV,
                (uint8_t *)&dev_inst_ptr->dev_descriptor);
               
            if (status != USB_OK)
            {
                printf("get device descriptor error\n");
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                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;
            //printf("dev %d cfg, c %d 0x%x\n", dev_inst_ptr->dev_descriptor.bNumConfigurations, dev_inst_ptr->cfg_value, desc.pntr);
            dev_inst_ptr->state = DEVSTATE_GET_CFG9;
            status = _usb_host_ch9_get_descriptor((usb_device_instance_handle)dev_inst_ptr,
               USB_DESC_TYPE_CFG << 8 | dev_inst_ptr->cfg_value, 
               0, 
               sizeof(dev_inst_ptr->buffer),
               desc.bufr);
               
            if (status != USB_OK)
            {
                printf("get 9 byte configuration(%d) error\n", dev_inst_ptr->cfg_value);
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }
   
            break;
      case DEVSTATE_GET_CFG9:     /* Read 9 bytes of config descriptor */
          
            /* Now select the configuration as specified in the 
                    * descriptor 
                    */
            desc.cfig = (usb_configuration_descriptor_t*)dev_inst_ptr->buffer;
            config_size = USB_SHORT_UNALIGNED_LE_TO_HOST(desc.cfig->wTotalLength);
            
            /* for KHCI, the start address and the length should be 4 byte align */
            if ((config_size && 0x3) != 0)
            {
                aligned_config_size = (config_size & 0xFFFFFFFC) + 4;
            }

            if (dev_inst_ptr->lpConfiguration != NULL)
            {
                OS_Mem_free(dev_inst_ptr->lpConfiguration);
                dev_inst_ptr->lpConfiguration = NULL;
            }

            dev_inst_ptr->lpConfiguration = (void*)OS_Mem_alloc_uncached(aligned_config_size);
       
            if (dev_inst_ptr->lpConfiguration == NULL)
            {
                printf("get memory for full configuration(%d) error\n", dev_inst_ptr->cfg_value);
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }
           
            //printf("Get CFG9 %d %d %d\n",dev_inst_ptr->cfg_value, config_size,dev_inst_ptr->dev_descriptor.bNumConfigurations);
       
            /* We can only read one config descriptor at a time */
            status = _usb_host_ch9_get_descriptor((usb_device_instance_handle)dev_inst_ptr,
               (USB_DESC_TYPE_CFG << 8) | dev_inst_ptr->cfg_value, 
               0, 
               (uint16_t)config_size,
               dev_inst_ptr->lpConfiguration);
               
            if (status != USB_OK)
            {
                printf("get full configuration(%d) error\n", dev_inst_ptr->cfg_value);
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }    
#ifdef USBCFG_OTG
            dev_inst_ptr->state = DEVSTATE_CHK_OTG;
#else
            /*dev_inst_ptr->state = DEVSTATE_SET_CFG;*/
            dev_inst_ptr->state = DEVSTATE_CFG_READ;
#endif
           break;  

#ifdef USBCFG_OTG
        case DEVSTATE_CHK_OTG:
            otg_hnp_support = FALSE;
            /* Point to the memory owned by this device */
            /* FIXME: it is presumed that memlist points to the config descriptor */
            desc.pntr = dev_inst_ptr->lpConfiguration;

            /* We will always start with config desc so update the search pointer */
            config_size = USB_SHORT_UNALIGNED_LE_TO_HOST(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;
                }
                config_size -= desc.intf->bLength;
                desc.word += desc.intf->bLength;
            }

            /* Check for an OTG descriptor */
            dev_inst_ptr->state = DEVSTATE_CFG_READ;
       
            if (config_size && desc.otg->bDescriptorType == USB_DESC_TYPE_OTG &&
               (desc.otg->bmAttributes & OTG_HNP_SUPPORT))
            {
                otg_hnp_support = TRUE;
                if(_usb_otg_host_get_otg_attribute(usb_host_ptr->otg_handle,desc.otg->bmAttributes) == USB_OK)
                {
                    if(_usb_otg_host_set_feature_required(usb_host_ptr->otg_handle))
                    {
                        status = _usb_host_ch9_set_feature(dev_inst_ptr, 0, 0, OTG_A_HNP_SUPPORT);
                       
                        if (status != USB_OK)
                        {
                            printf("set feature for otg error\n");
                            usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                            break;
                        }
                        
                        else
                        {
                            dev_inst_ptr->state = DEVSTATE_SET_HNP;  
                            break;
                        }
                    }
                }
            }
        case DEVSTATE_SET_HNP:
            if (otg_hnp_support)
            {
                status = _usb_host_ch9_set_feature(dev_inst_ptr, 0, 0, OTG_B_HNP_ENABLE);
                if (status != USB_OK)
                {
                    dev_inst_ptr->state = DEVSTATE_INITIAL;
                }
                else
                {
                    dev_inst_ptr->state = DEVSTATE_SET_HNP_OK;
                }
                break; 
            }
        case  DEVSTATE_SET_HNP_OK:
            if(dev_inst_ptr->state == DEVSTATE_SET_HNP_OK)
            {
                _usb_otg_host_a_set_b_hnp_en(usb_host_ptr->otg_handle, TRUE);
            }
#endif  
        case DEVSTATE_CFG_READ:
            dev_inst_ptr->cfg_value++;
            //printf("cfg %d, %d\n", dev_inst_ptr->cfg_value,dev_inst_ptr->dev_descriptor.bNumConfigurations);
            if (usb_host_dev_mng_parse_configuration_descriptor(dev_inst_ptr) == USB_OK)
            {
                //printf("parse cfg\n");
                if (usb_host_dev_mng_check_configuration(dev_inst_ptr))
                {
                    //printf("check cfg\n");
                    usb_host_dev_notify(dev_inst_ptr, USB_ATTACH_EVENT);
                    /* enumeration done */
                    dev_inst_ptr->state = DEVSTATE_SET_CFG;
                    /* send set_configuration */
                    status = _usb_host_ch9_set_configuration(dev_inst_ptr, dev_inst_ptr->configuration.lpconfigurationDesc->bConfigurationValue);
                    if (status != USB_OK)
                    {
                        printf("set configuration(%d) error\n", dev_inst_ptr->cfg_value);
                        usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                        break;
                    }
                }
                else
                {
                    //printf("cfg %d %d\n", dev_inst_ptr->cfg_value,dev_inst_ptr->dev_descriptor.bNumConfigurations);
                    /* get next configuration */
                    if (dev_inst_ptr->cfg_value < dev_inst_ptr->dev_descriptor.bNumConfigurations)
                    {
                        //printf("invalid cfg re\n");
                        desc.pntr = &dev_inst_ptr->buffer;
                        dev_inst_ptr->state = DEVSTATE_GET_CFG9;
                        status = _usb_host_ch9_get_descriptor((usb_device_instance_handle)dev_inst_ptr,
                            USB_DESC_TYPE_CFG << 8 | dev_inst_ptr->cfg_value, 
                            0, 
                            sizeof(dev_inst_ptr->buffer),
                            desc.bufr);
                        if (status != USB_OK)
                        {
                            printf("get 9 byte configuration(%d) error\n", dev_inst_ptr->cfg_value);
                            usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                            break;
                        }
                   }
                   else
                   {
                       printf("unsupported device attached\n");
                       usb_host_dev_notify(dev_inst_ptr, USB_ATTACH_DEVICE_NOT_SUPPORT);
                       usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                       break;
                   }
               }
            }
            else
            {
                printf("parse configuration(%d) error\n", dev_inst_ptr->cfg_value);
                usb_host_dev_mng_pre_detach(dev_inst_ptr->host,dev_inst_ptr->hub_no,dev_inst_ptr->port_no);
                break;
            }
            break;
        case DEVSTATE_SET_CFG:     /* config descriptor [0..8] */
            dev_inst_ptr->state = DEVSTATE_ENUM_OK;
            usb_host_dev_notify(dev_inst_ptr, USB_CONFIG_EVENT);
#ifdef USBCFG_OTG
            _usb_otg_host_on_interface_event(usb_host_ptr->otg_handle, dev_inst_ptr);
#endif
            break;

        case DEVSTATE_SET_INTF:    /* Select interface done */
            dev_inst_ptr->state = DEVSTATE_ENUM_OK;
            usb_host_dev_notify(dev_inst_ptr, USB_INTF_OPENED_EVENT);
            break;
        case DEVSTATE_ENUM_OK:   /* enumeration complete */
            if ((dev_inst_ptr->control_callback != NULL))
            {
                dev_inst_ptr->control_callback(tr_ptr, dev_inst_ptr->control_callback_param, buffer, length, status);
            }
            break;
        default:
            break;
    } /* EndSwitch */
} /* EndBody */
Ejemplo n.º 2
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 */
Ejemplo n.º 3
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 */