/*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 */
/*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_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 */