/** * @brief This function responsible for reception of data from the device * @param pdev: Selected device * @retval None */ static void CDC_ProcessReception(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { if(RX_Enabled == 1) { URB_STATE URB_StatusRx = HCD_GetURB_State(pdev , CDC_Machine.CDC_DataItf.hc_num_in); switch(CDC_RxParam.CDCState) { case CDC_IDLE: /*check the received length lesser then the remaining space available in the buffer */ if(CDC_RxParam.DataLength < (CDC_RxParam.BufferLen - CDC_Machine.CDC_DataItf.length)) { /*Receive the data */ USBH_BulkReceiveData(pdev, CDC_RxParam.pFillBuff, CDC_Machine.CDC_DataItf.length, CDC_Machine.CDC_DataItf.hc_num_in); /*change the cdc state to USBH_CDC_GET_DATA*/ CDC_RxParam.CDCState = CDC_GET_DATA; } break; case CDC_GET_DATA: /*Check the last state of the device is URB_DONE */ if(URB_StatusRx == URB_DONE) { /* Move the pointer as well as datalength */ CDC_RxParam.DataLength += pdev->host.hc[CDC_Machine.CDC_DataItf.hc_num_in].xfer_count ; CDC_RxParam.pFillBuff += pdev->host.hc[CDC_Machine.CDC_DataItf.hc_num_in].xfer_count ; /* Process the recived data */ CDC_ReceiveData(&CDC_RxParam); /*change the state od the CDC state*/ CDC_RxParam.CDCState = CDC_IDLE; } break; } } }
/** * @brief USBH_CtlReq * USBH_CtlReq sends a control request and provide the status after * completion of the request * @param pdev: Selected device * @param req: Setup Request Structure * @param buff: data buffer address to store the response * @param length: length of the response * @retval Status */ USBH_Status USBH_CtlReq (USB_OTG_CORE_HANDLE *pdev, USB_Setup_TypeDef *req, uint8_t *buff, uint16_t length) { USBH_Status status; URB_STATE URB_Status = URB_IDLE; URB_Status = HCD_GetURB_State(pdev); status = USBH_BUSY; switch (USBH_Machine.RequestState) { case CMD_SEND: /* Start a SETUP transfer */ USBH_SubmitSetupRequest(pdev, req, buff, length); USBH_Machine.RequestState = CMD_WAIT; status = USBH_BUSY; break; case CMD_WAIT: if (URB_Status == URB_DONE) { /* Commands successfully sent and Response Received */ USBH_Machine.RequestState = CMD_SEND; status = USBH_OK; } else if (URB_Status == URB_ERROR) { /* Failure Mode */ USBH_Machine.RequestState = CMD_SEND; status = USBH_FAIL; } else if (URB_Status == URB_STALL) { /* Commands successfully sent and Response Received */ USBH_Machine.RequestState = CMD_SEND; status = USBH_NOT_SUPPORTED; } break; default: break; } return status; }
/** * @brief USBH_CtlSendData * Sends a data Packet to the Device * @param pdev: Selected device * @param buff: Buffer pointer from which the Data will be sent to Device * @param length: Length of the data to be sent * @param hc_num: Host channel Number * @retval Status */ USBH_Status USBH_CtlSendData ( USB_OTG_CORE_HANDLE *pdev, uint8_t *buff, uint8_t length, uint8_t hc_num) { pdev->host.hc[hc_num].ep_is_in = 0; pdev->host.hc[hc_num].xfer_buff = buff; pdev->host.hc[hc_num].xfer_len = length; if(HCD_GetURB_State(pdev) == URB_DONE) { /* Toggle the Bit fore previous successful Transaction */ pdev->host.hc[hc_num].toggle_out ^= 1; } if ( length == 0 ) { /* For Status OUT stage, Length==0, Status Out PID = 1 */ pdev->host.hc[hc_num].toggle_out = 1; } /* Set the Data Toggle bit as per the Flag */ if ( pdev->host.hc[hc_num].toggle_out == 0) { /* Put the PID 0 */ pdev->host.hc[hc_num].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ pdev->host.hc[hc_num].data_pid = HC_PID_DATA1 ; } HCD_SubmitRequest (pdev , hc_num); return USBH_OK; }
/** * @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_MSC_HandleBOTXfer * This function manages the different states of BOT transfer and * updates the status to upper layer. * @param None * @retval None * */ void USBH_MSC_HandleBOTXfer(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { uint8_t xferDirection, index; static uint32_t remainingDataLength; static uint8_t *datapointer, *datapointer_prev; static uint8_t error_direction; USBH_Status status; URB_STATE URB_Status = URB_IDLE; if (HCD_IsDeviceConnected(pdev)) { switch (USBH_MSC_BOTXferParam.BOTState) { case USBH_MSC_SEND_CBW: /* send CBW */ USBH_BulkSendData(pdev, &USBH_MSC_CBWData.CBWArray[0], USBH_MSC_BOT_CBW_PACKET_LENGTH, MSC_Machine.hc_num_out); USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SEND_CBW; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SENT_CBW; break; case USBH_MSC_SENT_CBW: URB_Status = HCD_GetURB_State(pdev, MSC_Machine.hc_num_out); if (URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SENT_CBW; /* If the CBW Pkt is sent successful, then change the state */ xferDirection = (USBH_MSC_CBWData.field.CBWFlags & USB_REQ_DIR_MASK); if (USBH_MSC_CBWData.field.CBWTransferLength != 0) { remainingDataLength = USBH_MSC_CBWData.field.CBWTransferLength; datapointer = USBH_MSC_BOTXferParam.pRxTxBuff; datapointer_prev = datapointer; /* If there is Data Transfer Stage */ if (xferDirection == USB_D2H) { /* Data Direction is IN */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAIN_STATE; } else { /* Data Direction is OUT */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAOUT_STATE; } } else {/* If there is NO Data Transfer Stage */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } } else if (URB_Status == URB_NOTREADY) { USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } else if (URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_OUT; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; } break; case USBH_MSC_BOT_DATAIN_STATE: URB_Status = HCD_GetURB_State(pdev, MSC_Machine.hc_num_in); /* BOT DATA IN stage */ if ((URB_Status == URB_DONE) || (USBH_MSC_BOTXferParam.BOTStateBkp != USBH_MSC_BOT_DATAIN_STATE)) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAIN_STATE; if (remainingDataLength > MSC_Machine.MSBulkInEpSize) { USBH_BulkReceiveData(pdev, datapointer, MSC_Machine.MSBulkInEpSize, MSC_Machine.hc_num_in); remainingDataLength -= MSC_Machine.MSBulkInEpSize; datapointer = datapointer + MSC_Machine.MSBulkInEpSize; } else if (remainingDataLength == 0) { /* If value was 0, and successful transfer, then change the state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } else { USBH_BulkReceiveData(pdev, datapointer, remainingDataLength, MSC_Machine.hc_num_in); remainingDataLength = 0; /* Reset this value and keep in same state */ } } else if (URB_Status == URB_STALL) { /* This is Data Stage STALL Condition */ error_direction = USBH_MSC_DIR_IN; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_IN; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.2 Host expects to receive data from the device 3. On a STALL condition receiving data, then: The host shall accept the data received. The host shall clear the Bulk-In pipe. 4. The host shall attempt to receive a CSW. USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original state after the ClearFeature Command is issued. */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; } break; case USBH_MSC_BOT_DATAOUT_STATE: /* BOT DATA OUT stage */ URB_Status = HCD_GetURB_State(pdev, MSC_Machine.hc_num_out); if (URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAOUT_STATE; if (remainingDataLength > MSC_Machine.MSBulkOutEpSize) { USBH_BulkSendData(pdev, datapointer, MSC_Machine.MSBulkOutEpSize, MSC_Machine.hc_num_out); datapointer_prev = datapointer; datapointer = datapointer + MSC_Machine.MSBulkOutEpSize; remainingDataLength = remainingDataLength - MSC_Machine.MSBulkOutEpSize; } else if (remainingDataLength == 0) { /* If value was 0, and successful transfer, then change the state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } else { USBH_BulkSendData(pdev, datapointer, remainingDataLength, MSC_Machine.hc_num_out); remainingDataLength = 0; /* Reset this value and keep in same state */ } } else if (URB_Status == URB_NOTREADY) { if (datapointer != datapointer_prev) { USBH_BulkSendData(pdev, (datapointer - MSC_Machine.MSBulkOutEpSize), MSC_Machine.MSBulkOutEpSize, MSC_Machine.hc_num_out); } else { USBH_BulkSendData(pdev, datapointer, MSC_Machine.MSBulkOutEpSize, MSC_Machine.hc_num_out); } } else if (URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_OUT; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.3 Ho - Host expects to send data to the device 3. On a STALL condition sending data, then: " The host shall clear the Bulk-Out pipe. 4. The host shall attempt to receive a CSW. The Above statement will do the clear the Bulk-Out pipe. The Below statement will help in Getting the CSW. USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original state after the ClearFeature Command is issued. */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; } break; case USBH_MSC_RECEIVE_CSW_STATE: /* BOT CSW stage */ /* NOTE: We cannot reset the BOTStallErrorCount here as it may come from the clearFeature from previous command */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; USBH_MSC_BOTXferParam.pRxTxBuff = USBH_MSC_CSWData.CSWArray; USBH_MSC_BOTXferParam.DataLength = USBH_MSC_CSW_MAX_LENGTH; for (index = USBH_MSC_CSW_LENGTH; index != 0; index--) { USBH_MSC_CSWData.CSWArray[index] = 0; } USBH_MSC_CSWData.CSWArray[0] = 0; USBH_BulkReceiveData(pdev, USBH_MSC_BOTXferParam.pRxTxBuff, USBH_MSC_CSW_MAX_LENGTH, MSC_Machine.hc_num_in); USBH_MSC_BOTXferParam.BOTState = USBH_MSC_DECODE_CSW; break; case USBH_MSC_DECODE_CSW: URB_Status = HCD_GetURB_State(pdev, MSC_Machine.hc_num_in); /* Decode CSW */ if (URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateCurrent; USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_DecodeCSW(pdev, phost); } else if (URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_IN; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_IN; } break; case USBH_MSC_BOT_ERROR_IN: status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_IN); if (status == USBH_OK) { /* Check if the error was due in Both the directions */ if (error_direction == USBH_MSC_BOTH_DIR) {/* If Both directions are Needed, Switch to OUT Direction */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; } else { /* Switch Back to the Original State, In many cases this will be USBH_MSC_RECEIVE_CSW_STATE state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } } else if (status == USBH_UNRECOVERED_ERROR) { /* This means that there is a STALL Error limit, Do Reset Recovery */ USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR; } break; case USBH_MSC_BOT_ERROR_OUT: status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_OUT); if (status == USBH_OK) { /* Switch Back to the Original State */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } else if (status == USBH_UNRECOVERED_ERROR) { /* This means that there is a STALL Error limit, Do Reset Recovery */ USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR; } break; default: break; } } }
/** * This function will do bulk transfer in lowlevel, it will send request to the host controller * * @param pipe the bulk transfer pipe. * @param buffer the data buffer to save requested data * @param nbytes the size of buffer * * @return the error code, RT_EOK on successfully. */ static int susb_bulk_xfer(upipe_t pipe, void* buffer, int nbytes, int timeout) { rt_uint8_t channel; int left = nbytes; rt_uint8_t *ptr; URB_STATE state; RT_ASSERT(pipe != RT_NULL); RT_ASSERT(buffer != RT_NULL); if(!(root_hub.port_status[0] & PORT_CCS) || (root_hub.port_status[0] & PORT_CCSC)) return -1; ptr = (rt_uint8_t*)buffer; channel = (rt_uint32_t)pipe->user_data & 0xFF; rt_sem_take(&sem_lock, RT_WAITING_FOREVER); if(pipe->ep.bEndpointAddress & USB_DIR_IN) { while(left > pipe->ep.wMaxPacketSize) { USBH_BulkReceiveData(&USB_OTG_Core, ptr, pipe->ep.wMaxPacketSize, channel); while(1) { state = HCD_GetURB_State(&USB_OTG_Core , channel); if(state == URB_DONE) break; else if(state == URB_NOTREADY) rt_kprintf("not ready\n"); else if(state == URB_STALL) rt_kprintf("stall\n"); //else if(state == URB_IDLE) rt_kprintf("idle\n"); } ptr += pipe->ep.wMaxPacketSize; left -= pipe->ep.wMaxPacketSize; } USBH_BulkReceiveData(&USB_OTG_Core, ptr, left, channel); while(1) { state = HCD_GetURB_State(&USB_OTG_Core , channel); if(state == URB_DONE) break; else if(state == URB_NOTREADY) rt_kprintf("not ready\n"); else if(state == URB_STALL) rt_kprintf("stall\n"); //else if(state == URB_IDLE) rt_kprintf("idle\n"); } } else { send_data: while(left > pipe->ep.wMaxPacketSize) { USBH_BulkSendData(&USB_OTG_Core, ptr, pipe->ep.wMaxPacketSize, channel); while(1) { state = HCD_GetURB_State(&USB_OTG_Core, channel); if(state == URB_DONE) break; if(state == URB_NOTREADY) goto send_data; } ptr += pipe->ep.wMaxPacketSize; left -= pipe->ep.wMaxPacketSize; } USBH_BulkSendData(&USB_OTG_Core, ptr, left, channel); while(1) { state = HCD_GetURB_State(&USB_OTG_Core , channel); if(state == URB_DONE) break; if(state == URB_NOTREADY) goto send_data; } } rt_sem_release(&sem_lock); return nbytes; }
/** * @brief USBH_HID_Handle * The function is for managing state machine for HID data transfers * @param pdev: Selected device * @param hdev: Selected device property * @retval USBH_Status */ static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev , void *phost) { USBH_HOST *pphost = phost; USBH_Status status = USBH_OK; switch (HID_Machine.state) { case HID_IDLE: HID_Machine.cb->Init(); HID_Machine.state = HID_SYNC; case HID_SYNC: /* Sync with start of Even Frame */ if(USB_OTG_IsEvenFrame(pdev) == TRUE) { HID_Machine.state = HID_GET_DATA; } break; case HID_GET_DATA: USBH_InterruptReceiveData(pdev, HID_Machine.buff, HID_Machine.length, HID_Machine.hc_num_in); start_toggle = 1; HID_Machine.state = HID_POLL; HID_Machine.timer = HCD_GetCurrentFrame(pdev); break; case HID_POLL: if(( HCD_GetCurrentFrame(pdev) - HID_Machine.timer) >= HID_Machine.poll) { HID_Machine.state = HID_GET_DATA; } else if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE) { if(start_toggle == 1) /* handle data once */ { start_toggle = 0; HID_Machine.cb->Decode(HID_Machine.buff); } } else if(HCD_GetURB_State(pdev, HID_Machine.hc_num_in) == URB_STALL) /* IN Endpoint Stalled */ { /* Issue Clear Feature on interrupt IN endpoint */ if( (USBH_ClrFeature(pdev, pphost, HID_Machine.ep_addr, HID_Machine.hc_num_in)) == USBH_OK) { /* Change state to issue next IN token */ HID_Machine.state = HID_GET_DATA; } } break; default: break; } return status; }
/** * @brief USBH_HID_Handle * The function is for managing state machine for HID data transfers * @param pdev: Selected device * @param hdev: Selected device property * @retval USBH_Status */ static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev , void *phost) { USBH_HOST *pphost = phost; HID_Machine_TypeDef *HID_Machine = &HID_Machines[pdev->cfg.coreID]; USBH_Status status = USBH_OK; switch (HID_Machine->state) { case HID_IDLE: HID_Machine->cb->Init(pdev->cfg.coreID,pphost->device_prop.Dev_Desc.idVendor,pphost->device_prop.Dev_Desc.idProduct); HID_Machine->state = HID_SYNC; case HID_SYNC: /* Sync with start of Even Frame */ if(USB_OTG_IsEvenFrame(pdev) == TRUE) { HID_Machine->state = HID_GET_DATA; } break; case HID_GET_DATA: USBH_InterruptReceiveData(pdev, HID_Machine->buff, HID_Machine->length, HID_Machine->hc_num_in); start_toggles[pdev->cfg.coreID] = 1; HID_Machine->state = HID_POLL; HID_Machine->timer = HCD_GetCurrentFrame(pdev); break; case HID_POLL: if(( HCD_GetCurrentFrame(pdev) - HID_Machine->timer) >= HID_Machine->poll) { HID_Machine->state = HID_GET_DATA; } else if(HCD_GetURB_State(pdev , HID_Machine->hc_num_in) == URB_DONE) { if(start_toggles[pdev->cfg.coreID] == 1) /* handle data once */ { start_toggles[pdev->cfg.coreID] = 0; HID_Machine->cb->Decode(pdev->cfg.coreID,HID_Machine->buff); } } else if(HCD_GetURB_State(pdev, HID_Machine->hc_num_in) == URB_STALL) /* IN Endpoint Stalled */ { /* Issue Clear Feature on interrupt IN endpoint */ if( (USBH_ClrFeature(pdev, pphost, HID_Machine->ep_addr, HID_Machine->hc_num_in)) == USBH_OK) { /* Change state to issue next IN token */ HID_Machine->state = HID_GET_DATA; } } break; default: break; } return status; }
void USBPT_Work() { if (USBPT_Has_Dev == 0) { if (HCD_IsDeviceConnected(&USB_OTG_Core_host) != 0) { USBPT_printf("USBPT Device Connecting \r\n"); if (USBH_Open_Channel( &USB_OTG_Core_host, &(USBPT_Dev->Control.hc_num_in), 0x80, USBPT_Dev->device_prop.address, // still 0 at this point USBPT_Dev->device_prop.speed, EP_TYPE_CTRL, USBPT_Dev->Control.ep0size) == HC_OK && USBH_Open_Channel( &USB_OTG_Core_host, &(USBPT_Dev->Control.hc_num_out), 0x00, USBPT_Dev->device_prop.address, // still 0 at this point USBPT_Dev->device_prop.speed, EP_TYPE_CTRL, USBPT_Dev->Control.ep0size) == HC_OK ) { DCD_DevConnect(&USB_OTG_Core_dev); USBPT_Has_Dev = 1; } else { dbg_printf(DBGMODE_ERR, "USBPT Unable to allocate control EP HC \r\n"); } } else { return; } } else { if (HCD_IsDeviceConnected(&USB_OTG_Core_host) == 0) { USBPT_printf("USBPT Device Disconnecting \r\n"); USBD_DeInit(&USB_OTG_Core_dev); DCD_DevDisconnect(&USB_OTG_Core_dev); USBPT_Has_Dev = 0; for (uint8_t i = 0; i < USBPTH_MAX_LISTENERS; i++) { USBH_Free_Channel(&USB_OTG_Core_host, &(USBPTH_Listeners[i].hc)); } USBH_Free_Channel(&USB_OTG_Core_host, &(USBPT_Dev->Control.hc_num_out)); USBH_Free_Channel(&USB_OTG_Core_host, &(USBPT_Dev->Control.hc_num_in)); } } for (uint8_t i = 0; i < USBPTH_MAX_LISTENERS; i++) { USBPTH_HC_EP_t* pl = &USBPTH_Listeners[i]; int8_t hc = USBPTH_Listeners[i].hc; if (hc >= 0) // if listener is actually allocated { USBH_EpDesc_TypeDef* epDesc = pl->epDesc; uint8_t epnum = epDesc->bEndpointAddress; uint8_t epType = 0; USBPT_GeneralInDataLen = epDesc->wMaxPacketSize; // try to send read tokens only on even frames if (USB_OTG_IsEvenFrame(&USB_OTG_Core_host) == 0) continue; dbg_trace(); // attempt to start the read, check the read type first if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; USBH_InterruptReceiveData(&USB_OTG_Core_host, USBPT_GeneralInData, USBPT_GeneralInDataLen, hc); } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; USBH_BulkReceiveData(&USB_OTG_Core_host, USBPT_GeneralInData, USBPT_GeneralInDataLen, hc); } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; USBH_IsocReceiveData(&USB_OTG_Core_host, USBPT_GeneralInData, USBPT_GeneralInDataLen, hc); } // now we wait for a reply, or maybe there isn't one USBH_Status status; char sent = 0; delay_1ms_cnt = 100; do { URB_STATE us = HCD_GetURB_State(&USB_OTG_Core_host, hc); if (us == URB_DONE) { // data was indeed received // print it to the serial port for monitoring USBPT_printf("USBPT:IN:EP0x%02X:", epnum); for (uint16_t c = 0; c < USBPT_GeneralInDataLen; c++) { USBPT_printf(" 0x%02X", USBPT_GeneralInData[c]); } USBPT_printf("\r\n"); // relay the data to the host DCD_EP_Tx(&USB_OTG_Core_dev, epnum, USBPT_GeneralInData, USBPT_GeneralInDataLen); sent = 1; break; } else if (us == URB_ERROR) { dbg_printf(DBGMODE_ERR, "DataIn Error on EP 0x%02X \r\n", epnum); break; } else if (us == URB_STALL) { dbg_printf(DBGMODE_ERR, "DataIn Stalled EP 0x%02X \r\n", epnum); break; } else if (us == URB_NOTREADY) { // NAK, no data break; } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { dbg_printf(DBGMODE_ERR, "DataIn Read Timed Out EP 0x%02X \r\n", epnum); } } } }
uint8_t USBPTD_DataOut (void *pcore , uint8_t epnum) { USB_OTG_CORE_HANDLE* pcore_ = (USB_OTG_CORE_HANDLE*)pcore; DCD_DEV* pdev = &(pcore_->dev); uint8_t* data; uint16_t wLength; if (epnum == 0x00) { // CTRL REQ wLength = USBPT_CtrlDataLen; data = USBPT_CtrlData; } else { wLength = pdev->out_ep[epnum].xfer_count; data = pdev->out_ep[epnum].xfer_buff; } // print to monitor USBPT_printf("USBPT:OUT:EP0x%02X:", epnum); for (uint16_t i = 0; i < wLength; i++) { USBPT_printf(" 0x%02X", data[i]); } USBPT_printf("\r\n"); if (epnum == 0x00) { // CTRL REQ USBH_Status status; delay_1ms_cnt = 100; // wait for transfer complete 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) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut timed out while sending to device, status: 0x%04X \r\n", status); USBD_CtlError(pcore , 0); return USBD_FAIL; } else if (status != USBH_OK) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut failed to send to device, status: 0x%04X \r\n", status); USBD_CtlError(pcore , 0); return USBD_FAIL; } else { // everything is OK USBD_CtlSendStatus(pcore); return USBD_OK; } } else { wLength = pdev->out_ep[epnum].xfer_count; data = pdev->out_ep[epnum].xfer_buff; // allocate memory needed if (USBPT_GeneralOutData != 0) free(USBPT_GeneralOutData); USBPT_GeneralOutDataLen = wLength; USBPT_GeneralOutData = malloc(wLength); memcpy(USBPT_GeneralOutData, data, USBPT_GeneralOutDataLen); USBH_EpDesc_TypeDef* epDesc = 0; for (uint8_t i = 0; i < USBPTH_OutEPCnt; i++) { // look for appropriate EP if (USBPTH_OutEP[i]->bEndpointAddress == epnum) { epDesc = USBPTH_OutEP[i]; break; } } if (epDesc != 0) // EP found { uint8_t epType = 0; int8_t hc = -1; 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; } // dynamically allocate host channel for use if (USBH_Open_Channel( &USB_OTG_Core_host, &hc, epnum, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, epDesc->wMaxPacketSize) == HC_OK) { // try to only send on even frame volatile uint32_t syncTries = 0x7FFFFFFF; while (USB_OTG_IsEvenFrame(&USB_OTG_Core_host) == 0 && syncTries--) __NOP(); // send using appropriate method switch (epType) { case EP_TYPE_INTR: USBH_InterruptSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; case EP_TYPE_BULK: USBH_BulkSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; case EP_TYPE_ISOC: USBH_IsocSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; default: break; } // wait until done sending USBH_Status status; delay_1ms_cnt = 100; do { URB_STATE us = HCD_GetURB_State(&USB_OTG_Core_host, hc); if (us == URB_DONE) { break; } else if (us == URB_ERROR) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Send Error on EP 0x%02X \r\n", epnum); DCD_EP_Stall(pcore, epnum); break; } else if (us == URB_STALL) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Stalled EP 0x%02X \r\n", epnum); DCD_EP_Stall(pcore, epnum); break; } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Send Timed Out EP 0x%02X \r\n", epnum); } // free the channel to be used by something else later USBH_Free_Channel(&USB_OTG_Core_host, &hc); } else { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Failed to Alloc HC for EP 0x%02X \r\n", epnum); } } else { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut No Such EP 0x%02X \r\n", epnum); } return USBD_OK; } return USBD_OK; }
/* 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 USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) { uint8_t rcode = hrSUCCESS, retry_count; uint8_t *data_p = data; //local copy of the data pointer uint16_t bytes_tosend, nak_count; uint16_t bytes_left = nbytes, last_bytesleft = nbytes; USB_OTG_CORE_HANDLE *pdev = coreConfig; uint32_t hcnum = pep->hcNumOut; uint8_t maxpktsize = pep->maxPktSize; if (maxpktsize < 1 || maxpktsize > 64) return USB_ERROR_INVALID_MAX_PKT_SIZE; if(maxpktsize != pdev->host.hc[hcnum].max_packet) pdev->host.hc[hcnum].max_packet = maxpktsize; #if 0 pdev->host.hc[hcnum].ep_is_in = 0; pdev->host.hc[hcnum].xfer_buff = data; //buff; pdev->host.hc[hcnum].xfer_len = nbytes; //length; if(nbytes == 0) { /* For Status OUT stage, Length==0, Status Out PID = 1 */ pdev->host.hc[hcnum].toggle_out = 1; } /* Set the Data Toggle bit as per the Flag */ if ( pdev->host.hc[hcnum].toggle_out == 0) { /* Put the PID 0 */ pdev->host.hc[hcnum].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ pdev->host.hc[hcnum].data_pid = HC_PID_DATA1 ; } HCD_SubmitRequest (pdev, hcnum); #else unsigned long timeout = millis() + USB_XFER_TIMEOUT; //regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value pdev->host.hc[hcnum].ep_is_in = 0; pdev->host.hc[hcnum].xfer_buff = data; //buff; pdev->host.hc[hcnum].xfer_len = nbytes; //length; if(nbytes == 0) { /* For Status OUT stage, Length==0, Status Out PID = 1 */ pdev->host.hc[hcnum].toggle_out = 1; } /* Set the Data Toggle bit as per the Flag */ if ( pdev->host.hc[hcnum].toggle_out == 0) { /* Put the PID 0 */ pdev->host.hc[hcnum].data_pid = HC_PID_DATA0; } else { /* Put the PID 1 */ pdev->host.hc[hcnum].data_pid = HC_PID_DATA1 ; } retry_count = 0; nak_count = 0; while (bytes_left) { // we send all data at once due to large fifo //bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; //bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO //regWr(rSNDBC, bytes_tosend); //set number of bytes //regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet HCD_SubmitRequest(pdev, hcnum); PollStatus: rcode = USB_ERROR_TRANSFER_TIMEOUT; while (timeout > millis()) //while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ { rcode = HCD_GetURB_State(pdev, hcnum); //regRd(rHIRQ); if (rcode != URB_IDLE) { //& bmHXFRDNIRQ) { //regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ rcode = 0x00; break; } } if(rcode != 0x00) return rcode; // todo: return for what rcode = HCD_GetHCState(pdev, hcnum); //(regRd(rHRSL) & 0x0f); //while (rcode && (timeout > millis())) { // we don't need pulling here because we already did it above switch (rcode) { case hrNAK: nak_count++; //maybe a NOT_READY happens if (nak_limit && (nak_count == nak_limit)) goto breakout; /* else if (URB_NOTREADY == HCD_GetURB_State(pdev, hcnum)) { USB_OTG_HCCHAR_TypeDef hcchar; hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hcnum]->HCCHAR); if(hcchar.b.eptype == EP_TYPE_BULK) { pdev->host.URB_State[hcnum] = URB_IDLE; // re-activate the channel hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hcnum]->HCCHAR, hcchar.d32); STM_EVAL_LEDToggle(LED1); goto PollStatus; //return ( rcode); } }*/ break; case hrTIMEOUT: retry_count++; if (retry_count == USB_RETRY_LIMIT) goto breakout; //return ( rcode); break; case hrTOGERR: // yes, we flip it wrong here so that next time it is actually correct! //pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1; //regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value printf("\nOutTransfer - togerr"); //break; default: goto breakout; }//switch( rcode /* process NAK according to Host out NAK bug */ /* uint32_t *addr; uint32_t i; for(addr = (uint32_t *)0x50000000, i = 0; i < 0x12; addr++, i++) { printf("\naddr(%x) = %x", addr, *addr); }*/ USB_OTG_HCTSIZn_TypeDef hctsiz; hctsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hcnum]->HCTSIZ); bytes_left = hctsiz.b.pktcnt << 6; if(last_bytesleft != bytes_left) { last_bytesleft = bytes_left; pdev->host.hc[hcnum].xfer_buff = data + nbytes - bytes_left; pdev->host.hc[hcnum].xfer_len = bytes_left; if(((nbytes - bytes_left) >> 6) & 0x1) { // if sent odd times packets pdev->host.hc[hcnum].toggle_out ^= 0x1; pdev->host.hc[hcnum].data_pid = (pdev->host.hc[hcnum].toggle_out) ? HC_PID_DATA1 : HC_PID_DATA0; } pdev->host.hc[hcnum].isEvenTimesToggle = 0; // will be re-calculate in HCD_SubmitRequest retry_count = 0; nak_count = 0; } //regWr(rSNDBC, 0); //regWr(rSNDFIFO, *data_p); //regWr(rSNDBC, bytes_tosend); //regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet //while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ //regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ //rcode = (regRd(rHRSL) & 0x0f); //}//while( rcode && .... // bytes_left seems never decreasing to 0 //bytes_left -= bytes_tosend; //data_p += bytes_tosend; }//while( bytes_left...
/** * @brief The function is responsible for sending data to the device * @param pdev: Selected device * @retval None */ void CDC_ProcessTransmission(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { static uint32_t len ; URB_STATE URB_StatusTx = URB_IDLE; URB_StatusTx = HCD_GetURB_State(pdev , CDC_Machine.CDC_DataItf.hc_num_out); switch(CDC_TxParam.CDCState) { case CDC_IDLE: break; case CDC_SEND_DATA: if(( URB_StatusTx == URB_DONE ) || (URB_StatusTx == URB_IDLE)) { /*Check the data length is more then the CDC_Machine.CDC_DataItf.CDC_DataItf.length */ if(CDC_TxParam.DataLength > CDC_Machine.CDC_DataItf.length) { len = CDC_Machine.CDC_DataItf.length ; /*Send the data */ USBH_BulkSendData (pdev, CDC_TxParam.pRxTxBuff, len , CDC_Machine.CDC_DataItf.hc_num_out); } else { len = CDC_TxParam.DataLength ; /*Send the remaining data */ USBH_BulkSendData (pdev, CDC_TxParam.pRxTxBuff, len, CDC_Machine.CDC_DataItf.hc_num_out); } CDC_TxParam.CDCState = CDC_DATA_SENT; } break; case CDC_DATA_SENT: /*Check the status done for transmssion*/ if(URB_StatusTx == URB_DONE ) { /*Point to next chunc of data*/ CDC_TxParam.pRxTxBuff += len ; /*decrease the data length*/ CDC_TxParam.DataLength -= len; if(CDC_TxParam.DataLength == 0) { CDC_TxParam.CDCState = CDC_IDLE; } else { CDC_TxParam.CDCState = CDC_SEND_DATA; } } else if( URB_StatusTx == URB_NOTREADY ) { /*Send the same data */ USBH_BulkSendData (pdev, (CDC_TxParam.pRxTxBuff), len, CDC_Machine.CDC_DataItf.hc_num_out); } break; } }
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; }
static int _usb_bulkin_request_handle(USB_OTG_CORE_HANDLE * pdev , USBH_HOST * phost, wifi_usb_adapter_t *adapter) { wifi_usb_bulkin_request_t *rx_req = &adapter->usb_rx_req; static unsigned short timeout = 0; URB_STATE URB_Status = URB_IDLE; unsigned int actual_len = 0; int status = 1; switch (rx_req->state) { case USB_BULK_STATE_IDLE: status = 0; /* indicate the state machine could be blocked */ break; case USB_BULK_STATE_REQUEST: rx_req->packet_buffer = &rx_req->buffer[0]; rx_req->packet_len = pdev->host.hc[adapter->hc_num_in].max_packet; USBH_BulkReceiveData(pdev, rx_req->packet_buffer, rx_req->packet_len, adapter->hc_num_in); rx_req->retry = 3; rx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ rx_req->timer = HCD_GetCurrentFrame(pdev); break; case USB_BULK_STATE_REQUEST_WAIT: URB_Status = HCD_GetURB_State(pdev , adapter->hc_num_in); rx_req->status = URB_Status; if (URB_Status == URB_DONE) { rx_req->state = USB_BULK_STATE_IDLE; actual_len = pdev->host.hc[adapter->hc_num_in].xfer_count; rx_req->len += actual_len; rx_req->packet_buffer = (unsigned char *)(rx_req->packet_buffer) + actual_len; if (actual_len < pdev->host.hc[adapter->hc_num_in].max_packet) { _usb_bulkin_complete(adapter); } else { if ((rx_req->len + pdev->host.hc[adapter->hc_num_in].max_packet) <= NOSWIFI_USB_RX_BUFFER_MAX_LEN) { rx_req->packet_len = pdev->host.hc[adapter->hc_num_in].max_packet; USBH_BulkReceiveData(pdev, rx_req->packet_buffer, rx_req->packet_len, adapter->hc_num_in); rx_req->retry = 3; rx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ rx_req->timer = HCD_GetCurrentFrame(pdev); } else { rx_req->len = 0; _usb_bulkin_complete(adapter); } } } else if (URB_Status == URB_ERROR) { rx_req->state = USB_BULK_STATE_ERROR; } else if (URB_Status == URB_STALL) { rx_req->state = USB_BULK_STATE_ERROR; } break; case USB_BULK_STATE_ERROR: DBGPRINT(WHED_DEBUG_ERROR, "PANIC(%s - %d): %s - rx urb failed(%d).\n", __FILE__, __LINE__, __FUNCTION__, rx_req->status); if (rx_req->retry) { USB_OTG_BSP_uDelay(600); rx_req->retry--; rx_req->state = USB_BULK_STATE_REQUEST; } else { rx_req->state = USB_BULK_STATE_REQUEST; rx_req->state = USB_BULK_STATE_IDLE; rx_req->len = 0; _usb_bulkin_complete(adapter); } break; default: break; } timeout = timeout; /* avoid compiler's warning */ return status; }
static int _usb_bulkout_request_handle(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost, wifi_usb_adapter_t *adapter) { wifi_usb_bulkout_request_t *tx_req = &adapter->usb_tx_req; static unsigned short timeout = 0; URB_STATE URB_Status = URB_IDLE; int status = 1; switch (tx_req->state) { case USB_BULK_STATE_IDLE: status = 0; /* indicate the state machine could be blocked */ break; case USB_BULK_STATE_REQUEST: tx_req->packet_buffer = &tx_req->buffer[0]; if (tx_req->len > pdev->host.hc[adapter->hc_num_out].max_packet) { tx_req->packet_len = pdev->host.hc[adapter->hc_num_out].max_packet; } else { tx_req->packet_len = tx_req->len; } USBH_BulkSendData(pdev, tx_req->packet_buffer, tx_req->packet_len, adapter->hc_num_out); tx_req->retry = 3; tx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ tx_req->timer = HCD_GetCurrentFrame(pdev); break; case USB_BULK_STATE_REQUEST_WAIT: URB_Status = HCD_GetURB_State(pdev , adapter->hc_num_out); tx_req->status = URB_Status; if (URB_Status == URB_DONE) { tx_req->len -= tx_req->packet_len; tx_req->packet_buffer = (unsigned char *)(tx_req->packet_buffer) + tx_req->packet_len; if (tx_req->len == 0) { tx_req->state = USB_BULK_STATE_IDLE; _usb_bulkout_complete(adapter); } else { if (tx_req->len > pdev->host.hc[adapter->hc_num_out].max_packet) { tx_req->packet_len = pdev->host.hc[adapter->hc_num_out].max_packet; } else { tx_req->packet_len = tx_req->len; } USBH_BulkSendData(pdev, tx_req->packet_buffer, tx_req->packet_len, adapter->hc_num_out); tx_req->retry = 10; tx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ tx_req->timer = HCD_GetCurrentFrame(pdev); } } else if (URB_Status == URB_ERROR) { tx_req->state = USB_BULK_STATE_ERROR; } else if (URB_Status == URB_STALL) { tx_req->state = USB_BULK_STATE_ERROR; } else if (URB_Status == URB_NOTREADY) { USBH_BulkSendData(pdev, tx_req->packet_buffer, tx_req->packet_len, adapter->hc_num_out); tx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ tx_req->timer = HCD_GetCurrentFrame(pdev); } break; case USB_BULK_STATE_ERROR: DBGPRINT(WHED_DEBUG_ERROR, "PANIC(%s - %d): %s - tx urb failed(%d).\n", __FILE__, __LINE__, __FUNCTION__, tx_req->status); if (tx_req->retry) { tx_req->retry--; //USB_OTG_BSP_uDelay(600); USBH_BulkSendData(pdev, tx_req->packet_buffer, tx_req->packet_len, adapter->hc_num_out); tx_req->state = USB_BULK_STATE_REQUEST_WAIT; status = 0; /* indicate the state machine could be blocked */ timeout = BULK_DATA_STAGE_TIMEOUT; /* Set the delay timer to enable timeout for data stage completion. */ tx_req->timer = HCD_GetCurrentFrame(pdev); } else { tx_req->state = USB_BULK_STATE_REQUEST; tx_req->state = USB_BULK_STATE_IDLE; _usb_bulkout_complete(adapter); } break; default: break; } timeout = timeout; /* avoid compiler's warning */ return status; }