/** * @brief USBH_HandleControl * Handles the USB control transfer state machine * @param pdev: Selected device * @retval Status */ USBH_Status USBH_HandleControl (USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { uint8_t direction; static uint16_t timeout = 0; USBH_Status status = USBH_OK; URB_STATE URB_Status = URB_IDLE; phost->Control.status = CTRL_START; switch (phost->Control.state) { case CTRL_SETUP: /* send a SETUP packet */ USBH_CtlSendSetup (pdev, phost->Control.setup.d8 , phost->Control.hc_num_out); phost->Control.state = CTRL_SETUP_WAIT; break; case CTRL_SETUP_WAIT: URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out); /* case SETUP packet sent successfully */ if(URB_Status == URB_DONE) { direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK); /* check if there is a data stage */ if (phost->Control.setup.b.wLength.w != 0 ) { timeout = DATA_STAGE_TIMEOUT; if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_DATA_IN; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_DATA_OUT; } } /* No DATA stage */ else { timeout = NODATA_STAGE_TIMEOUT; /* If there is No Data Transfer Stage */ if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_STATUS_OUT; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_STATUS_IN; } } /* Set the delay timer to enable timeout for data stage completion */ phost->Control.timer = HCD_GetCurrentFrame(pdev); } else if(URB_Status == URB_ERROR) { phost->Control.state = CTRL_ERROR; phost->Control.status = CTRL_XACTERR; } break; case CTRL_DATA_IN: /* Issue an IN token */ USBH_CtlReceiveData(pdev, phost->Control.buff, phost->Control.length, phost->Control.hc_num_in); phost->Control.state = CTRL_DATA_IN_WAIT; break; case CTRL_DATA_IN_WAIT: URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in); /* check is DATA packet transfered successfully */ if (URB_Status == URB_DONE) { phost->Control.state = CTRL_STATUS_OUT; } /* manage error cases*/ if (URB_Status == URB_STALL) { /* In stall case, return to previous machine state*/ phost->gState = phost->gStateBkp; } else if (URB_Status == URB_ERROR) { /* Device error */ phost->Control.state = CTRL_ERROR; } else if ((HCD_GetCurrentFrame(pdev)- phost->Control.timer) > timeout) { /* timeout for IN transfer */ phost->Control.state = CTRL_ERROR; } break; case CTRL_DATA_OUT: /* Start DATA out transfer (only one DATA packet)*/ pdev->host.hc[phost->Control.hc_num_out].toggle_out = 1; USBH_CtlSendData (pdev, phost->Control.buff, phost->Control.length , phost->Control.hc_num_out); phost->Control.state = CTRL_DATA_OUT_WAIT; break; case CTRL_DATA_OUT_WAIT: URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out); if (URB_Status == URB_DONE) { /* If the Setup Pkt is sent successful, then change the state */ phost->Control.state = CTRL_STATUS_IN; } /* handle error cases */ else if (URB_Status == URB_STALL) { /* In stall case, return to previous machine state*/ phost->gState = phost->gStateBkp; phost->Control.state = CTRL_STALLED; } else if (URB_Status == URB_NOTREADY) { /* Nack received from device */ phost->Control.state = CTRL_DATA_OUT; } else if (URB_Status == URB_ERROR) { /* device error */ phost->Control.state = CTRL_ERROR; } break; case CTRL_STATUS_IN: /* Send 0 bytes out packet */ USBH_CtlReceiveData (pdev, 0, 0, phost->Control.hc_num_in); phost->Control.state = CTRL_STATUS_IN_WAIT; break; case CTRL_STATUS_IN_WAIT: URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in); if ( URB_Status == URB_DONE) { /* Control transfers completed, Exit the State Machine */ phost->gState = phost->gStateBkp; phost->Control.state = CTRL_COMPLETE; } else if (URB_Status == URB_ERROR) { phost->Control.state = CTRL_ERROR; } else if((HCD_GetCurrentFrame(pdev)\ - phost->Control.timer) > timeout) { phost->Control.state = CTRL_ERROR; } else if(URB_Status == URB_STALL) { /* Control transfers completed, Exit the State Machine */ phost->gState = phost->gStateBkp; phost->Control.status = CTRL_STALL; status = USBH_NOT_SUPPORTED; } break; case CTRL_STATUS_OUT: pdev->host.hc[phost->Control.hc_num_out].toggle_out ^= 1; USBH_CtlSendData (pdev, 0, 0, phost->Control.hc_num_out); phost->Control.state = CTRL_STATUS_OUT_WAIT; break; case CTRL_STATUS_OUT_WAIT: URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out); if (URB_Status == URB_DONE) { phost->gState = phost->gStateBkp; phost->Control.state = CTRL_COMPLETE; } else if (URB_Status == URB_NOTREADY) { phost->Control.state = CTRL_STATUS_OUT; } else if (URB_Status == URB_ERROR) { phost->Control.state = CTRL_ERROR; } break; case CTRL_ERROR: /* After a halt condition is encountered or an error is detected by the host, a control endpoint is allowed to recover by accepting the next Setup PID; i.e., recovery actions via some other pipe are not required for control endpoints. For the Default Control Pipe, a device reset will ultimately be required to clear the halt or error condition if the next Setup PID is not accepted. */ if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT) { /* Do the transmission again, starting from SETUP Packet */ phost->Control.state = CTRL_SETUP; } else { phost->Control.status = CTRL_FAIL; phost->gState = phost->gStateBkp; status = USBH_FAIL; } break; default: break; } return status; }
/** * @brief USBH_HandleControl * Handles the USB control transfer state machine * @param phost: Host Handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) { uint8_t direction; USBH_StatusTypeDef status = USBH_BUSY; USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; switch (phost->Control.state) { case CTRL_SETUP: /* send a SETUP packet */ USBH_CtlSendSetup (phost, (uint8_t *)phost->Control.setup.d8 , phost->Control.pipe_out); phost->Control.state = CTRL_SETUP_WAIT; break; case CTRL_SETUP_WAIT: URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out); /* case SETUP packet sent successfully */ if(URB_Status == USBH_URB_DONE) { direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK); /* check if there is a data stage */ if (phost->Control.setup.b.wLength.w != 0 ) { if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_DATA_IN; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_DATA_OUT; } } /* No DATA stage */ else { /* If there is No Data Transfer Stage */ if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_STATUS_OUT; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_STATUS_IN; } } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if(URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_DATA_IN: /* Issue an IN token */ phost->Control.timer = phost->Timer; USBH_CtlReceiveData(phost, phost->Control.buff, phost->Control.length, phost->Control.pipe_in); phost->Control.state = CTRL_DATA_IN_WAIT; break; case CTRL_DATA_IN_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); /* check is DATA packet transfered successfully */ if (URB_Status == USBH_URB_DONE) { phost->Control.state = CTRL_STATUS_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } /* manage error cases*/ if (URB_Status == USBH_URB_STALL) { /* In stall case, return to previous machine state*/ status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { /* Device error */ phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_DATA_OUT: USBH_CtlSendData (phost, phost->Control.buff, phost->Control.length , phost->Control.pipe_out, 1); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_DATA_OUT_WAIT; break; case CTRL_DATA_OUT_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { /* If the Setup Pkt is sent successful, then change the state */ phost->Control.state = CTRL_STATUS_IN; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } /* handle error cases */ else if (URB_Status == USBH_URB_STALL) { /* In stall case, return to previous machine state*/ phost->Control.state = CTRL_STALLED; status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_NOTREADY) { /* Nack received from device */ phost->Control.state = CTRL_DATA_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { /* device error */ phost->Control.state = CTRL_ERROR; status = USBH_FAIL; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_STATUS_IN: /* Send 0 bytes out packet */ USBH_CtlReceiveData (phost, 0, 0, phost->Control.pipe_in); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_IN_WAIT; break; case CTRL_STATUS_IN_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); if ( URB_Status == USBH_URB_DONE) { /* Control transfers completed, Exit the State Machine */ phost->Control.state = CTRL_COMPLETE; status = USBH_OK; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if(URB_Status == USBH_URB_STALL) { /* Control transfers completed, Exit the State Machine */ status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_STATUS_OUT: USBH_CtlSendData (phost, 0, 0, phost->Control.pipe_out, 1); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_OUT_WAIT; break; case CTRL_STATUS_OUT_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { status = USBH_OK; phost->Control.state = CTRL_COMPLETE; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_NOTREADY) { phost->Control.state = CTRL_STATUS_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_ERROR: /* After a halt condition is encountered or an error is detected by the host, a control endpoint is allowed to recover by accepting the next Setup PID; i.e., recovery actions via some other pipe are not required for control endpoints. For the Default Control Pipe, a device reset will ultimately be required to clear the halt or error condition if the next Setup PID is not accepted. */ if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT) { /* try to recover control */ USBH_LL_Stop(phost); /* Do the transmission again, starting from SETUP Packet */ phost->Control.state = CTRL_SETUP; phost->RequestState = CMD_SEND; } else { phost->Control.errorcount = 0; USBH_ErrLog("Control error"); status = USBH_FAIL; } break; default: break; } return status; }
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit, uint8_t *data_p = NULL, uint16_t nbytes = 0, uint8_t hcnum = 0) { unsigned long timeout = millis() + USB_XFER_TIMEOUT; //unsigned long timeout2 = timeout; uint8_t tmpdata; uint8_t rcode = hrSUCCESS; uint8_t retry_count = 0; uint16_t nak_count = 0; USB_OTG_CORE_HANDLE *pdev = coreConfig; uint8_t pid = 0; pdev->host.hc[hcnum].nak_count = 0; pdev->host.hc[hcnum].nak_limit = nak_limit; while (timeout > millis()) { //regWr(rHXFR, (token | ep)); //launch the transfer if(token == tokSETUP) { USBH_CtlSendSetup(pdev, data_p, hcnum); //timeout2 = millis() + 10; } else { if(token == tokOUTHS) { pdev->host.hc[hcnum].toggle_out = 0x1; pdev->host.hc[hcnum].ep_is_in = 0; pid = HC_PID_DATA1; } else if (token == tokINHS) { pdev->host.hc[hcnum].toggle_in = 0x1; pdev->host.hc[hcnum].ep_is_in = 1; pid = HC_PID_DATA1; } else if (token == tokIN){ pdev->host.hc[hcnum].ep_is_in = 1; pid = (pdev->host.hc[hcnum].toggle_in)? HC_PID_DATA1 : HC_PID_DATA0; } else { pdev->host.hc[hcnum].ep_is_in = 0; pid = (pdev->host.hc[hcnum].toggle_out)? HC_PID_DATA1 : HC_PID_DATA0; }/* if(pid == HC_PID_DATA0) { STM_EVAL_LEDToggle(LED1); delay_ms(1); STM_EVAL_LEDToggle(LED1); delay_ms(1); STM_EVAL_LEDToggle(LED1); } if(pid == HC_PID_DATA1) { STM_EVAL_LEDToggle(LED1); delay_ms(1); STM_EVAL_LEDToggle(LED1); delay_ms(1); STM_EVAL_LEDToggle(LED1); delay_ms(1); STM_EVAL_LEDToggle(LED1); }*/ pdev->host.hc[hcnum].data_pid = pid; pdev->host.hc[hcnum].xfer_buff = data_p; pdev->host.hc[hcnum].xfer_len = nbytes; HCD_SubmitRequest(pdev, hcnum); } rcode = USB_ERROR_TRANSFER_TIMEOUT; while (timeout > millis()) //wait for transfer completion { tmpdata = HCD_GetURB_State(pdev, hcnum); //regRd(rHIRQ); if (tmpdata != URB_IDLE) { //& bmHXFRDNIRQ) { //regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt rcode = 0x00; break; } if (pdev->host.ConnSts == 0) { rcode = hrJERR; return rcode; } /* else { //todo: because in bt case, there are two in ep (int-in, bulk-in), that we need to check hid/msc case either. rcode = HCD_GetHCState(pdev, hcnum); if(rcode == hrNAK) { nak_count++; if (nak_limit && (nak_count == nak_limit)) return (rcode); uint8_t eptype = pdev->host.hc[hcnum].ep_type; if (eptype == EP_TYPE_INTR) { break; } else if ((eptype == EP_TYPE_CTRL) || (eptype == EP_TYPE_BULK)) { // re-activate the channel USB_OTG_HCCHAR_TypeDef hcchar; hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hcnum]->HCCHAR); hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hcnum]->HCCHAR, hcchar.d32); delay_us(200); } } }*/ } //if (rcode != 0x00) //exit if timeout // return ( rcode); rcode = HCD_GetHCState(pdev, hcnum); //(regRd(rHRSL) & 0x0f); //analyze transfer result switch (rcode) { case hrNAK: //todo: if timeout above with nak, we need to consider the next xfer. nak_count = pdev->host.hc[hcnum].nak_count; if (nak_limit && (nak_count == nak_limit)) return (rcode); break; case hrTIMEOUT: retry_count++; if (retry_count == USB_RETRY_LIMIT) return (rcode); break; default: return (rcode); } }//while( timeout > millis() return ( rcode); }
uint8_t USBPTD_SetupStage(USB_OTG_CORE_HANDLE* pcore, USB_SETUP_REQ* req) { // store for later use from another function memcpy(USBPT_LastSetupPacket, pcore->dev.setup_packet, 24); // print for monitoring USBPT_printf("\b\r\n USBPT:SETUP:"); for (uint8_t i = 0; i < 8; i++) { USBPT_printf(" 0x%02X", USBPT_LastSetupPacket[i]); } USBPT_printf("\r\n"); // prepare to be sent to the device memcpy(USBPT_Dev->Control.setup.d8, USBPT_LastSetupPacket, 8); // set address must be handled explicitly if ((req->bmRequest & 0x7F) == (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD) && req->bRequest == USB_REQ_SET_ADDRESS) { // let the internal code handle it for the device interface USBD_StdDevReq(pcore, req); // pass it to the downstream device USBH_CtlReq_Blocking(&USB_OTG_Core_host, USBPT_Dev, 0, 0, 100); USBD_CtlSendStatus(pcore); // modifiy our host channel to match USBPT_Dev->device_prop.address = (uint8_t)(req->wValue) & 0x7F; USBH_Modify_Channel (&USB_OTG_Core_host, USBPT_Dev->Control.hc_num_in, USBPT_Dev->device_prop.address, 0, 0, 0); USBH_Modify_Channel (&USB_OTG_Core_host, USBPT_Dev->Control.hc_num_out, USBPT_Dev->device_prop.address, 0, 0, 0); // modify all other channels to match for (uint8_t i = 0; i < USBPTH_MAX_LISTENERS; i++) { USBPTH_HC_EP_t* pl = &USBPTH_Listeners[i]; uint8_t hc = pl->hc; if (hc != 0 && hc != HC_ERROR) // if listener is actually allocated { USBH_EpDesc_TypeDef* epDesc = pl->epDesc; uint8_t epType = 0; if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_CTRL) { epType = EP_TYPE_CTRL; } USBH_Modify_Channel( &USB_OTG_Core_host, USBPTH_Listeners[i].hc, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, USBPTH_Listeners[i].epDesc->wMaxPacketSize); } } // note: out direction channels are dynamically allocated only when needed // so we don't need to modify those channel addresses return USBD_OK; } // no data means we can just directly relay the data if (req->wLength == 0) { USBH_CtlReq_Blocking(&USB_OTG_Core_host, USBPT_Dev, 0, 0, 100); USBD_CtlSendStatus(pcore); return USBD_OK; } // there is extra data later USBPT_CtrlDataLen = req->wLength; if (USBPT_CtrlData != 0) free(USBPT_CtrlData); USBPT_CtrlData = malloc(USBPT_CtrlDataLen); USBH_Status status; // wait until previous req is finished delay_1ms_cnt = 100; while (delay_1ms_cnt > 0 && USBPT_Dev->Control.state != CTRL_COMPLETE && USBPT_Dev->Control.state != CTRL_IDLE && USBPT_Dev->Control.state != CTRL_ERROR && USBPT_Dev->Control.state != CTRL_STALLED); { status = USBH_HandleControl(&USB_OTG_Core_host, USBPT_Dev); } // finalize previous ctrl req if (USBPT_Dev->RequestState == CMD_WAIT) { USBH_CtlReq(&USB_OTG_Core_host, USBPT_Dev, 0 , 0 ); } // prepare new setup USBH_SubmitSetupRequest(USBPT_Dev, USBPT_CtrlData, USBPT_CtrlDataLen); USBPT_Dev->RequestState = CMD_WAIT; USBH_CtlSendSetup (&USB_OTG_Core_host, USBPT_Dev->Control.setup.d8, USBPT_Dev->Control.hc_num_out); USBPT_Dev->Control.state = CTRL_SETUP_WAIT; USBPT_Dev->Control.timer = HCD_GetCurrentFrame(pcore); USBPT_Dev->Control.timeout = 50; if ((req->bmRequest & 0x80) == 0) { // H2D // we need to obtain the data from EP0_RxReady first USBD_CtlPrepareRx (pcore, USBPT_CtrlData, USBPT_CtrlDataLen); return USBD_OK; } else { // D2H // wait for request to finish delay_1ms_cnt = 100; do { status = USBH_CtlReq(&USB_OTG_Core_host, USBPT_Dev, USBPT_CtrlData , USBPT_CtrlDataLen ); if (status == USBH_OK || status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } else { status = USBH_HandleControl(&USB_OTG_Core_host, USBPT_Dev); if (status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { // timeout dbg_printf(DBGMODE_ERR, "USBPT Setup Timed Out \r\n"); USBD_CtlSendStatus(pcore); // we reply with nothing to simulate a timeout return USBH_OK; } else if (status == USBH_OK) { // all good, send back the data USBD_CtlSendData (pcore, USBPT_CtrlData, USBPT_CtrlDataLen); // handle config descriptors specially, we need to know what channels to open based on endpoints if ((req->bmRequest & 0x7F) == (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD) && req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == USB_DESC_CONFIGURATION && req->wLength > USB_CONFIGURATION_DESC_SIZE) { // this is a full length configuration descriptor // we need this info to open as many D2H endpoints to channels USBH_ParseCfgDesc(&USBPT_Dev->device_prop.Cfg_Desc, USBPT_Dev->device_prop.Itf_Desc, USBPT_Dev->device_prop.Ep_Desc, USBPT_CtrlData, USBPT_CtrlDataLen); USBPTH_OutEPCnt = 0; USBPT_GeneralInDataLen = 0; for (uint8_t i = 0; i < USBPT_Dev->device_prop.Cfg_Desc.bNumInterfaces && i < USBH_MAX_NUM_INTERFACES; i++) { for (uint8_t j = 0; j < USBPT_Dev->device_prop.Itf_Desc[i].bNumEndpoints && j < USBH_MAX_NUM_ENDPOINTS; j++) { USBH_EpDesc_TypeDef* epDesc = &USBPT_Dev->device_prop.Ep_Desc[i][j]; for (uint8_t k = 0; k < USBPTH_MAX_LISTENERS; k++) { if ((epDesc->bEndpointAddress & USB_EP_DIR_MSK) == USB_D2H && USBPTH_Listeners[k].used == 0) { USBPTH_Listeners[k].epDesc = epDesc; uint8_t epType = 0; if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_CTRL) { epType = EP_TYPE_CTRL; } USBH_Open_Channel( &USB_OTG_Core_host, &(USBPTH_Listeners[k].hc), epDesc->bEndpointAddress, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, USBPTH_Listeners[k].epDesc->wMaxPacketSize); if (USBPTH_Listeners[k].hc >= 0) { USBPTH_Listeners[k].used = 1; DCD_EP_Open(&USB_OTG_Core_dev, epDesc->bEndpointAddress, epDesc->wMaxPacketSize, epType); if (epDesc->wMaxPacketSize > USBPT_GeneralInDataMax) { USBPT_GeneralInDataMax = epDesc->wMaxPacketSize; } } } } if ((epDesc->bEndpointAddress & 0x80) == USB_H2D) { USBPTH_OutEPCnt++; } } } if (USBPT_GeneralInData != 0) free(USBPT_GeneralInData); // release memory if previously allocated USBPT_GeneralInData = malloc(USBPT_GeneralInDataMax); // only allocate the memory we need if (USBPTH_OutEP != 0) free(USBPTH_OutEP); // release memory if previously allocated USBPTH_OutEP = malloc(sizeof(USBH_EpDesc_TypeDef*) * USBPTH_OutEPCnt); // only allocate the memory we need uint8_t ec = 0; for (uint8_t i = 0; i < USBPT_Dev->device_prop.Cfg_Desc.bNumInterfaces && i < USBH_MAX_NUM_INTERFACES; i++) { for (uint8_t j = 0; j < USBPT_Dev->device_prop.Itf_Desc[i].bNumEndpoints && j < USBH_MAX_NUM_ENDPOINTS; j++) { USBH_EpDesc_TypeDef* epDesc = &USBPT_Dev->device_prop.Ep_Desc[i][j]; if ((epDesc->bEndpointAddress & 0x80) == USB_H2D) { // only save the H2D direction endpoints USBPTH_OutEP[ec] = epDesc; ec++; } } } } return USBH_OK; } else { if (status == USBH_STALL || status == USBH_NOT_SUPPORTED) { dbg_printf(DBGMODE_ERR, "USBPT Setup Stalled \r\n"); USBD_CtlError(pcore , req); return USBH_OK; } } return USBD_OK; } dbg_printf(DBGMODE_ERR, "USBPT Setup Unhandled Error \r\n"); USBD_CtlError(pcore , req); return USBD_OK; }
static int _usb_ctrl_request_handle(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost, wifi_usb_adapter_t *adapter) { wifi_usb_ctrl_request_t *ctl_req = &adapter->usb_ctrl_req; unsigned char direction; static unsigned short timeout = 0; URB_STATE URB_Status = URB_IDLE; int status = 1; phost->Control.status = CTRL_START; switch (ctl_req->state) { case CTRL_IDLE: status = 0; /* indicate the state machine could be blocked */ break; case CTRL_SETUP: /* Send a SETUP packet. */ pdev->host.hc[ctl_req->hc_num_out].toggle_out = 0; USBH_CtlSendSetup(pdev, ctl_req->ctrlreq.d8, ctl_req->hc_num_out); ctl_req->state = CTRL_SETUP_WAIT; break; case CTRL_SETUP_WAIT: URB_Status = HCD_GetURB_State(pdev , ctl_req->hc_num_out); ctl_req->status = URB_Status; if (URB_Status == URB_DONE) { direction = (ctl_req->ctrlreq.b.bmRequestType & USB_REQ_DIR_MASK); /* check if there is a data stage. */ if (ctl_req->ctrlreq.b.wLength.w != 0) { timeout = CTRL_DATA_STAGE_TIMEOUT; if (direction == USB_D2H) { /* Data Direction is IN. */ ctl_req->state = CTRL_DATA_IN; } else { /* Data Direction is OUT. */ ctl_req->state = CTRL_DATA_OUT; } } /* No DATA stage. */ else { timeout = CTRL_NODATA_STAGE_TIMEOUT; /* If there is No Data Transfer Stage. */ if (direction == USB_D2H) { /* Data Direction is IN. */ ctl_req->state = CTRL_STATUS_OUT; } else { /* Data Direction is OUT. */ ctl_req->state = CTRL_STATUS_IN; } } /* Set the delay timer to enable timeout for data stage completion. */ ctl_req->timer = HCD_GetCurrentFrame(pdev); } else if (URB_Status == URB_ERROR) { ctl_req->state = CTRL_ERROR; /* To be add. */ } break; case CTRL_DATA_IN: /* Issue an IN token. */ USBH_CtlReceiveData(pdev, ctl_req->buffer, ctl_req->length, ctl_req->hc_num_in); ctl_req->state = CTRL_DATA_IN_WAIT; break; case CTRL_DATA_IN_WAIT: USB_OTG_BSP_uDelay(200); URB_Status = HCD_GetURB_State(pdev , ctl_req->hc_num_in); ctl_req->status = URB_Status; /* check is DATA packet transfered successfully. */ if (URB_Status == URB_DONE) { ctl_req->state = CTRL_STATUS_OUT; } /* manage error cases. */ else if (URB_Status == URB_STALL) { ctl_req->state = CTRL_ERROR; } else if (URB_Status == URB_ERROR) { /* Device error. */ ctl_req->state = CTRL_ERROR; } break; case CTRL_DATA_OUT: /* Start DATA out transfer (only one DATA packet). */ USB_OTG_BSP_uDelay(200); pdev->host.hc[ctl_req->hc_num_out].toggle_out ^= 1; USBH_CtlSendData(pdev, ctl_req->buffer, ctl_req->length , ctl_req->hc_num_out); ctl_req->state = CTRL_DATA_OUT_WAIT; break; case CTRL_DATA_OUT_WAIT: URB_Status = HCD_GetURB_State(pdev, ctl_req->hc_num_out); ctl_req->status = URB_Status; if (URB_Status == URB_DONE) { /* If the Setup Pkt is sent successful, then change the state. */ ctl_req->state = CTRL_STATUS_IN; } /* handle error cases. */ else if (URB_Status == URB_STALL) { ctl_req->state = CTRL_ERROR; } else if (URB_Status == URB_NOTREADY) { /* Nack received from device. */ ctl_req->state = CTRL_DATA_OUT; } else if (URB_Status == URB_ERROR) { /* device error */ ctl_req->state = CTRL_ERROR; } break; case CTRL_STATUS_IN: /* Send 0 bytes out packet. */ USB_OTG_BSP_uDelay(200); USBH_CtlReceiveData(pdev, 0, 0, ctl_req->hc_num_in); ctl_req->state = CTRL_STATUS_IN_WAIT; break; case CTRL_STATUS_IN_WAIT: URB_Status = HCD_GetURB_State(pdev, ctl_req->hc_num_in); ctl_req->status = URB_Status; if (URB_Status == URB_DONE) { /* Control transfers completed, Exit the State Machine */ ctl_req->state = CTRL_IDLE; _usb_control_complete(adapter); } else if (URB_Status == URB_ERROR) { ctl_req->state = CTRL_ERROR; } else if (URB_Status == URB_STALL) { ctl_req->state = URB_STALL; /* NOTICE: here maybe a error to be fixed!!! */ } break; case CTRL_STATUS_OUT: USB_OTG_BSP_uDelay(200); pdev->host.hc[ctl_req->hc_num_out].toggle_out ^= 1; USBH_CtlSendData(pdev, 0, 0, ctl_req->hc_num_out); ctl_req->state = CTRL_STATUS_OUT_WAIT; break; case CTRL_STATUS_OUT_WAIT: URB_Status = HCD_GetURB_State(pdev, ctl_req->hc_num_out); ctl_req->status = URB_Status; if (URB_Status == URB_DONE) { ctl_req->state = CTRL_IDLE; _usb_control_complete(adapter); } else if (URB_Status == URB_NOTREADY) { ctl_req->state = CTRL_STATUS_OUT; } else if (URB_Status == URB_ERROR) { ctl_req->state = CTRL_ERROR; } break; case CTRL_ERROR: DBGPRINT(WHED_DEBUG_ERROR, "PANIC(%s - %d): %s - control urb failed(%d), bRequestType = 0x%x, bRequest = 0x%x, wValue = 0x%x, wIndex = 0x%x, wLength = 0x%x.\n", __FILE__, __LINE__, __FUNCTION__, ctl_req->status, ctl_req->ctrlreq.b.bmRequestType, ctl_req->ctrlreq.b.bRequest, ctl_req->ctrlreq.b.wValue.w, ctl_req->ctrlreq.b.wIndex.w, ctl_req->ctrlreq.b.wLength.w); if (ctl_req->retry) { ctl_req->retry--; /* Do the transmission again, starting from SETUP Packet. */ ctl_req->state = CTRL_SETUP; } else { ctl_req->state = CTRL_IDLE; _usb_control_complete(adapter); } break; default: break; } timeout = timeout; /* avoid compiler's warning */ return status; }