/* * Stall all endpoints and set a flag indicating any current transfers * should be aborted. IO loops will see this flag in TimerWorker(). */ void SetAbortState() { uint8_t origEndpoint = Endpoint_GetCurrentEndpoint(); doDeviceReset = true; Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT); Endpoint_StallTransaction(); Endpoint_SelectEndpoint(XUM_BULK_IN_ENDPOINT); Endpoint_StallTransaction(); Endpoint_SelectEndpoint(origEndpoint); }
/** Function to read in a command block from the host, via the bulk data OUT endpoint. This function reads in the next command block * if one has been issued, and performs validation to ensure that the block command is valid. * * \return Boolean true if a valid command block has been read in from the endpoint, false otherwise */ static bool ReadInCommandBlock(void) { uint16_t BytesTransferred; /* Select the Data Out endpoint */ Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPADDR); /* Abort if no command has been sent from the host */ if (!(Endpoint_IsOUTReceived())) return false; /* Read in command block header */ BytesTransferred = 0; while (Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)), &BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer) { /* Check if the current command is being aborted by the host */ if (IsMassStoreReset) return false; } /* Verify the command block - abort if invalid */ if ((CommandBlock.Signature != MS_CBW_SIGNATURE) || (CommandBlock.LUN >= TOTAL_LUNS) || (CommandBlock.Flags & 0x1F) || (CommandBlock.SCSICommandLength == 0) || (CommandBlock.SCSICommandLength > sizeof(CommandBlock.SCSICommandData))) { /* Stall both data pipes until reset by host */ Endpoint_StallTransaction(); Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPADDR); Endpoint_StallTransaction(); return false; } /* Read in command block command data */ BytesTransferred = 0; while (Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData, CommandBlock.SCSICommandLength, &BytesTransferred) == ENDPOINT_RWSTREAM_IncompleteTransfer) { /* Check if the current command is being aborted by the host */ if (IsMassStoreReset) return false; } /* Finalize the stream transfer to send the last packet */ Endpoint_ClearOUT(); return true; }
static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { uint16_t BytesProcessed; Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber); BytesProcessed = 0; while (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock, (sizeof(MS_CommandBlockWrapper_t) - 16), &BytesProcessed) == ENDPOINT_RWSTREAM_IncompleteTransfer) { #if !defined(INTERRUPT_CONTROL_ENDPOINT) USB_USBTask(); #endif if (MSInterfaceInfo->State.IsMassStoreReset) return false; } if ((MSInterfaceInfo->State.CommandBlock.Signature != CPU_TO_LE32(MS_CBW_SIGNATURE)) || (MSInterfaceInfo->State.CommandBlock.LUN >= MSInterfaceInfo->Config.TotalLUNs) || (MSInterfaceInfo->State.CommandBlock.Flags & 0x1F) || (MSInterfaceInfo->State.CommandBlock.SCSICommandLength == 0) || (MSInterfaceInfo->State.CommandBlock.SCSICommandLength > 16)) { Endpoint_StallTransaction(); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_StallTransaction(); return false; } BytesProcessed = 0; while (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock.SCSICommandData, MSInterfaceInfo->State.CommandBlock.SCSICommandLength, &BytesProcessed) == ENDPOINT_RWSTREAM_IncompleteTransfer) { #if !defined(INTERRUPT_CONTROL_ENDPOINT) USB_USBTask(); #endif if (MSInterfaceInfo->State.IsMassStoreReset) return false; } Endpoint_ClearOUT(); return true; }
uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, void* Buffer, uint16_t* const PacketLength) { if ((USB_DeviceState != DEVICE_STATE_Configured) || (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) { return ENDPOINT_RWSTREAM_DeviceDisconnected; } Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpoint.Address); *PacketLength = 0; if (!(Endpoint_IsOUTReceived())) return ENDPOINT_RWSTREAM_NoError; RNDIS_Packet_Message_t RNDISPacketHeader; Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); if (le32_to_cpu(RNDISPacketHeader.DataLength) > ETHERNET_FRAME_SIZE_MAX) { Endpoint_StallTransaction(); return RNDIS_ERROR_LOGICAL_CMD_FAILED; } *PacketLength = (uint16_t)le32_to_cpu(RNDISPacketHeader.DataLength); Endpoint_Read_Stream_LE(Buffer, *PacketLength, NULL); Endpoint_ClearOUT(); return ENDPOINT_RWSTREAM_NoError; }
/** Function to manage TMC data transmission and reception to and from the host. */ void TMC_Task(void) { /* Device must be connected and configured for the task to run */ if (USB_DeviceState != DEVICE_STATE_Configured) return; TMC_MessageHeader_t MessageHeader; uint8_t MessagePayload[128]; /* Try to read in a TMC message from the interface, process if one is available */ if (ReadTMCHeader(&MessageHeader)) { /* Indicate busy */ LEDs_SetAllLEDs(LEDMASK_USB_BUSY); switch (MessageHeader.MessageID) { case TMC_MESSAGEID_DEV_DEP_MSG_OUT: LastTransferLength = 0; while (Endpoint_Read_Stream_LE(MessagePayload, MIN(MessageHeader.TransferSize, sizeof(MessagePayload)), &LastTransferLength) == ENDPOINT_RWSTREAM_IncompleteTransfer) { if (IsTMCBulkOUTReset) break; } Endpoint_ClearOUT(); ProcessSentMessage(MessagePayload, LastTransferLength); break; case TMC_MESSAGEID_DEV_DEP_MSG_IN: Endpoint_ClearOUT(); MessageHeader.TransferSize = GetNextMessage(MessagePayload); MessageHeader.MessageIDSpecific.DeviceOUT.LastMessageTransaction = true; WriteTMCHeader(&MessageHeader); LastTransferLength = 0; while (Endpoint_Write_Stream_LE(MessagePayload, MessageHeader.TransferSize, &LastTransferLength) == ENDPOINT_RWSTREAM_IncompleteTransfer) { if (IsTMCBulkINReset) break; } Endpoint_ClearIN(); break; default: Endpoint_StallTransaction(); break; } LEDs_SetAllLEDs(LEDMASK_USB_READY); } /* All pending data has been processed - reset the data abort flags */ IsTMCBulkINReset = false; IsTMCBulkOUTReset = false; }
/** Function to read in a command block from the host, via the bulk data OUT endpoint. This function reads in the next command block * if one has been issued, and performs validation to ensure that the block command is valid. * * \return Boolean true if a valid command block has been read in from the endpoint, false otherwise */ static bool ReadInCommandBlock(void) { /* Select the Data Out endpoint */ Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); /* Abort if no command has been sent from the host */ if (!(Endpoint_IsOUTReceived())) return false; /* Read in command block header */ Endpoint_Read_Stream_LE(&CommandBlock, (sizeof(CommandBlock) - sizeof(CommandBlock.SCSICommandData)), StreamCallback_AbortOnMassStoreReset); /* Check if the current command is being aborted by the host */ if (IsMassStoreReset) return false; /* Verify the command block - abort if invalid */ if ((CommandBlock.Signature != CBW_SIGNATURE) || (CommandBlock.LUN >= TOTAL_LUNS) || (CommandBlock.Flags & 0x1F) || (CommandBlock.SCSICommandLength == 0) || (CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH)) { /* Stall both data pipes until reset by host */ Endpoint_StallTransaction(); Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); Endpoint_StallTransaction(); return false; } /* Read in command block command data */ Endpoint_Read_Stream_LE(&CommandBlock.SCSICommandData, CommandBlock.SCSICommandLength, StreamCallback_AbortOnMassStoreReset); /* Check if the current command is being aborted by the host */ if (IsMassStoreReset) return false; /* Finalize the stream transfer to send the last packet */ Endpoint_ClearOUT(); return true; }
void EVENT_USB_Device_ControlRequest(void){ void* buffer = NULL; uint16_t length = 0; if(change != NULL) { usb_set_device(change, 1); Endpoint_ClearSETUP(); Endpoint_ClearIN(); Endpoint_ClearOUT(); } else { Endpoint_ClearSETUP(); } uart_print("Type: %x, req: %x, val: %x, idx: %x, len: %d\n", USB_ControlRequest.bmRequestType, USB_ControlRequest.bRequest, USB_ControlRequest.wValue, USB_ControlRequest.wIndex, USB_ControlRequest.wLength); device->handle_configuration( device, USB_ControlRequest.bmRequestType, USB_ControlRequest.bRequest, USB_ControlRequest.wValue, USB_ControlRequest.wIndex, USB_ControlRequest.wLength, &buffer, &length); if(buffer) { if(length == 0xFFFF) { return; } if(length) { if(length & CONST_PTR) { Endpoint_Write_Control_PStream_LE(buffer, length & ~CONST_PTR); } else { Endpoint_Write_Control_Stream_LE(buffer, length); } } Endpoint_ClearStatusStage(); if(deferred_addr >= 0) { _usb_set_addr(deferred_addr); uart_print("Setting addr to %d\n", deferred_addr); deferred_addr = -1; } } else { Endpoint_StallTransaction(); uart_print("STALLED!\n"); } }
/** Task to manage the Mass Storage interface, reading in Command Block Wrappers from the host, processing the SCSI commands they * contain, and returning Command Status Wrappers back to the host to indicate the success or failure of the last issued command. */ void MassStorage_Task(void) { /* Device must be connected and configured for the task to run */ if (USB_DeviceState != DEVICE_STATE_Configured) return; /* Process sent command block from the host if one has been sent */ if (ReadInCommandBlock()) { /* Indicate busy */ LEDs_SetAllLEDs(LEDMASK_USB_BUSY); /* Check direction of command, select Data IN endpoint if data is from the device */ if (CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN) Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); /* Decode the received SCSI command, set returned status code */ CommandStatus.Status = SCSI_DecodeSCSICommand() ? Command_Pass : Command_Fail; /* Load in the CBW tag into the CSW to link them together */ CommandStatus.Tag = CommandBlock.Tag; /* Load in the data residue counter into the CSW */ CommandStatus.DataTransferResidue = CommandBlock.DataTransferLength; /* Stall the selected data pipe if command failed (if data is still to be transferred) */ if ((CommandStatus.Status == Command_Fail) && (CommandStatus.DataTransferResidue)) Endpoint_StallTransaction(); /* Return command status block to the host */ ReturnCommandStatus(); /* Indicate ready */ LEDs_SetAllLEDs(LEDMASK_USB_READY); } /* Check if a Mass Storage Reset occurred */ if (IsMassStoreReset) { /* Reset the data endpoint banks */ Endpoint_ResetFIFO(MASS_STORAGE_OUT_EPNUM); Endpoint_ResetFIFO(MASS_STORAGE_IN_EPNUM); Endpoint_SelectEndpoint(MASS_STORAGE_OUT_EPNUM); Endpoint_ClearStall(); Endpoint_ResetDataToggle(); Endpoint_SelectEndpoint(MASS_STORAGE_IN_EPNUM); Endpoint_ClearStall(); Endpoint_ResetDataToggle(); /* Clear the abort transfer flag */ IsMassStoreReset = false; } }
static void USB_Device_ClearSetFeature(void) { switch (USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) { #if !defined(NO_DEVICE_REMOTE_WAKEUP) case REQREC_DEVICE: if ((uint8_t)USB_ControlRequest.wValue == FEATURE_SEL_DeviceRemoteWakeup) USB_Device_RemoteWakeupEnabled = (USB_ControlRequest.bRequest == REQ_SetFeature); else return; break; #endif #if !defined(CONTROL_ONLY_DEVICE) case REQREC_ENDPOINT: if ((uint8_t)USB_ControlRequest.wValue == FEATURE_SEL_EndpointHalt) { uint8_t EndpointIndex = ((uint8_t)USB_ControlRequest.wIndex & ENDPOINT_EPNUM_MASK); if (EndpointIndex == ENDPOINT_CONTROLEP) return; Endpoint_SelectEndpoint(EndpointIndex); if (Endpoint_IsEnabled()) { if (USB_ControlRequest.bRequest == REQ_SetFeature) { Endpoint_StallTransaction(); } else { Endpoint_ClearStall(); Endpoint_ResetEndpoint(EndpointIndex); Endpoint_ResetDataToggle(); } } } break; #endif default: return; } Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP); Endpoint_ClearSETUP(); Endpoint_ClearStatusStage(); }
static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber); CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset; if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock, (sizeof(MS_CommandBlockWrapper_t) - 16), StreamCallback_MS_Device_AbortOnMassStoreReset)) { return false; } if ((MSInterfaceInfo->State.CommandBlock.Signature != MS_CBW_SIGNATURE) || (MSInterfaceInfo->State.CommandBlock.LUN >= MSInterfaceInfo->Config.TotalLUNs) || (MSInterfaceInfo->State.CommandBlock.Flags & 0x1F) || (MSInterfaceInfo->State.CommandBlock.SCSICommandLength == 0) || (MSInterfaceInfo->State.CommandBlock.SCSICommandLength > 16)) { Endpoint_StallTransaction(); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_StallTransaction(); return false; } CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset; if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock.SCSICommandData, MSInterfaceInfo->State.CommandBlock.SCSICommandLength, StreamCallback_MS_Device_AbortOnMassStoreReset)) { return false; } Endpoint_ClearOUT(); return true; }
void MS_Device_USBTask(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { if (USB_DeviceState[MSInterfaceInfo->Config.PortNumber] != DEVICE_STATE_Configured) return; Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataOUTEndpointNumber); if (Endpoint_IsReadWriteAllowed(MSInterfaceInfo->Config.PortNumber)) { if (MS_Device_ReadInCommandBlock(MSInterfaceInfo)) { if (MSInterfaceInfo->State.CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN) Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataINEndpointNumber); bool SCSICommandResult = CALLBACK_MS_Device_SCSICommandReceived(MSInterfaceInfo); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataOUTEndpointNumber);// for streaming Endpoint_ClearOUT(MSInterfaceInfo->Config.PortNumber); if (MSInterfaceInfo->State.CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN) Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataINEndpointNumber); MSInterfaceInfo->State.CommandStatus.Status = (SCSICommandResult) ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail; MSInterfaceInfo->State.CommandStatus.Signature = CPU_TO_LE32(MS_CSW_SIGNATURE); MSInterfaceInfo->State.CommandStatus.Tag = MSInterfaceInfo->State.CommandBlock.Tag; MSInterfaceInfo->State.CommandStatus.DataTransferResidue = MSInterfaceInfo->State.CommandBlock.DataTransferLength; if (!(SCSICommandResult) && (le32_to_cpu(MSInterfaceInfo->State.CommandStatus.DataTransferResidue))) Endpoint_StallTransaction(MSInterfaceInfo->Config.PortNumber); MS_Device_ReturnCommandStatus(MSInterfaceInfo); } } if (MSInterfaceInfo->State.IsMassStoreReset) { Endpoint_ResetEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber); Endpoint_ResetEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataOUTEndpointNumber); Endpoint_ClearStall(MSInterfaceInfo->Config.PortNumber); Endpoint_ResetDataToggle(MSInterfaceInfo->Config.PortNumber); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.PortNumber, MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_ClearStall(MSInterfaceInfo->Config.PortNumber); Endpoint_ResetDataToggle(MSInterfaceInfo->Config.PortNumber); MSInterfaceInfo->State.IsMassStoreReset = false; } }
void MS_Device_USBTask(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) { if (USB_DeviceState != DEVICE_STATE_Configured) return; Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber); if (Endpoint_IsReadWriteAllowed()) { if (MS_Device_ReadInCommandBlock(MSInterfaceInfo)) { if (MSInterfaceInfo->State.CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN) Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber); MSInterfaceInfo->State.CommandStatus.Status = CALLBACK_MS_Device_SCSICommandReceived(MSInterfaceInfo) ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail; MSInterfaceInfo->State.CommandStatus.Signature = MS_CSW_SIGNATURE; MSInterfaceInfo->State.CommandStatus.Tag = MSInterfaceInfo->State.CommandBlock.Tag; MSInterfaceInfo->State.CommandStatus.DataTransferResidue = MSInterfaceInfo->State.CommandBlock.DataTransferLength; if ((MSInterfaceInfo->State.CommandStatus.Status == MS_SCSI_COMMAND_Fail) && (MSInterfaceInfo->State.CommandStatus.DataTransferResidue)) { Endpoint_StallTransaction(); } MS_Device_ReturnCommandStatus(MSInterfaceInfo); } } if (MSInterfaceInfo->State.IsMassStoreReset) { Endpoint_ResetFIFO(MSInterfaceInfo->Config.DataOUTEndpointNumber); Endpoint_ResetFIFO(MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber); Endpoint_ClearStall(); Endpoint_ResetDataToggle(); Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber); Endpoint_ClearStall(); Endpoint_ResetDataToggle(); MSInterfaceInfo->State.IsMassStoreReset = false; } }
/** Function to manage TMC data transmission and reception to and from the host. */ void TMC_Task(void) { /* Device must be connected and configured for the task to run */ if (USB_DeviceState != DEVICE_STATE_Configured) return; TMC_MessageHeader_t MessageHeader; /* Try to read in a TMC message from the interface, process if one is available */ if (ReadTMCHeader(&MessageHeader)) { /* Indicate busy */ LEDs_SetAllLEDs(LEDMASK_USB_BUSY); switch (MessageHeader.MessageID) { case TMC_MESSAGEID_DEV_DEP_MSG_OUT: Endpoint_Discard_Stream(MessageHeader.TransferSize, StreamCallback_AbortOUTOnRequest); Endpoint_ClearOUT(); break; case TMC_MESSAGEID_DEV_DEP_MSG_IN: Endpoint_ClearOUT(); MessageHeader.TransferSize = 3; WriteTMCHeader(&MessageHeader); Endpoint_Write_Stream_LE("TMC", 3, StreamCallback_AbortINOnRequest); Endpoint_ClearIN(); break; default: Endpoint_StallTransaction(); break; } LEDs_SetAllLEDs(LEDMASK_USB_READY); } /* All pending data has been processed - reset the data abort flags */ IsTMCBulkINReset = false; IsTMCBulkOUTReset = false; }
void USB_Device_ProcessControlRequest(void) { uint8_t* RequestHeader = (uint8_t*)&USB_ControlRequest; for (uint8_t RequestHeaderByte = 0; RequestHeaderByte < sizeof(USB_Request_Header_t); RequestHeaderByte++) *(RequestHeader++) = Endpoint_Read_Byte(); EVENT_USB_Device_ControlRequest(); if (Endpoint_IsSETUPReceived()) { uint8_t bmRequestType = USB_ControlRequest.bmRequestType; switch (USB_ControlRequest.bRequest) { case REQ_GetStatus: if ((bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_ENDPOINT))) { USB_Device_GetStatus(); } break; case REQ_ClearFeature: case REQ_SetFeature: if ((bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT))) { USB_Device_ClearSetFeature(); } break; case REQ_SetAddress: if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_SetAddress(); break; case REQ_GetDescriptor: if ((bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE))) { USB_Device_GetDescriptor(); } break; case REQ_GetConfiguration: if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_GetConfiguration(); break; case REQ_SetConfiguration: if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_SetConfiguration(); break; } } if (Endpoint_IsSETUPReceived()) { Endpoint_StallTransaction(); Endpoint_ClearSETUP(); } }
static bool USB_BulkWorker() { uint8_t cmdBuf[XUM_CMDBUF_SIZE], statusBuf[XUM_STATUSBUF_SIZE]; int8_t status; /* * If we are not connected to the host or a command has not yet * been sent, no more processing is required. */ if (USB_DeviceState != DEVICE_STATE_Configured) return false; Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT); if (!Endpoint_IsReadWriteAllowed()) return false; #ifdef DEBUG // Dump the status of both endpoints before getting the command Endpoint_SelectEndpoint(XUM_BULK_IN_ENDPOINT); DEBUGF(DBG_INFO, "bsti %x %x %x %x %x %x %x %x\n", Endpoint_GetCurrentEndpoint(), Endpoint_BytesInEndpoint(), Endpoint_IsEnabled(), Endpoint_IsReadWriteAllowed(), Endpoint_IsConfigured(), Endpoint_IsINReady(), Endpoint_IsOUTReceived(), Endpoint_IsStalled()); Endpoint_SelectEndpoint(XUM_BULK_OUT_ENDPOINT); DEBUGF(DBG_INFO, "bsto %x %x %x %x %x %x %x %x\n", Endpoint_GetCurrentEndpoint(), Endpoint_BytesInEndpoint(), Endpoint_IsEnabled(), Endpoint_IsReadWriteAllowed(), Endpoint_IsConfigured(), Endpoint_IsINReady(), Endpoint_IsOUTReceived(), Endpoint_IsStalled()); #endif // Read in the command from the host now that one is ready. if (!USB_ReadBlock(cmdBuf, sizeof(cmdBuf))) { board_set_status(STATUS_ERROR); return false; } // Allow commands to leave the extended status untouched memset(statusBuf, 0, sizeof(statusBuf)); /* * Decode and process the command. * usbHandleBulk() stores its extended result in the output buffer, * up to XUM_STATUSBUF_SIZE. * * Return values: * >0: completed ok, send the return value and extended status * 0: completed ok, don't send any status * -1: error, no status */ status = usbHandleBulk(cmdBuf, statusBuf); if (status > 0) { statusBuf[0] = status; USB_WriteBlock(statusBuf, sizeof(statusBuf)); } else if (status < 0) { DEBUGF(DBG_ERROR, "usbblk err\n"); board_set_status(STATUS_ERROR); Endpoint_StallTransaction(); return false; } return true; }
void USB_Device_ProcessControlRequest(void) { // USB_ControlRequest.bmRequestType = Endpoint_Read_8(); // USB_ControlRequest.bRequest = Endpoint_Read_8(); // USB_ControlRequest.wValue = Endpoint_Read_16_LE(); // USB_ControlRequest.wIndex = Endpoint_Read_16_LE(); // USB_ControlRequest.wLength = Endpoint_Read_16_LE(); Endpoint_GetSetupPackage( (uint8_t*) &USB_ControlRequest); EVENT_USB_Device_ControlRequest(); if (Endpoint_IsSETUPReceived()) { uint8_t bmRequestType = USB_ControlRequest.bmRequestType; switch (USB_ControlRequest.bRequest) { case REQ_GetStatus: if ((bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_ENDPOINT))) { USB_Device_GetStatus(); } break; case REQ_ClearFeature: case REQ_SetFeature: if ((bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT))) { USB_Device_ClearSetFeature(); } break; case REQ_SetAddress: if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_SetAddress(); break; case REQ_GetDescriptor: if ((bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) || (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE))) { USB_Device_GetDescriptor(); } break; case REQ_GetConfiguration: if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_GetConfiguration(); break; case REQ_SetConfiguration: if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE)) USB_Device_SetConfiguration(); break; } } if (Endpoint_IsSETUPReceived()) { Endpoint_ClearSETUP(); Endpoint_StallTransaction(); } }
void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) { if (USB_DeviceState != DEVICE_STATE_Configured) return; RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber); if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady) { USB_Request_Header_t Notification = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = NOTIF_ResponseAvailable, .wValue = 0, .wIndex = 0, .wLength = 0, }; Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); Endpoint_ClearIN(); RNDISInterfaceInfo->State.ResponseReady = false; } if ((RNDISInterfaceInfo->State.CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) { RNDIS_Packet_Message_t RNDISPacketHeader; Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber); if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->State.FrameIN.FrameInBuffer)) { Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK); if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) { Endpoint_StallTransaction(); return; } Endpoint_Read_Stream_LE(RNDISInterfaceInfo->State.FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); Endpoint_ClearOUT(); RNDISInterfaceInfo->State.FrameIN.FrameLength = RNDISPacketHeader.DataLength; RNDISInterfaceInfo->State.FrameIN.FrameInBuffer = true; } Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber); if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer) { memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t)); RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG; RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + RNDISInterfaceInfo->State.FrameOUT.FrameLength); RNDISPacketHeader.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)); RNDISPacketHeader.DataLength = RNDISInterfaceInfo->State.FrameOUT.FrameLength; Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK); Endpoint_Write_Stream_LE(RNDISInterfaceInfo->State.FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); Endpoint_ClearIN(); RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer = false; } } }
/** Task to manage the sending and receiving of encapsulated RNDIS data and notifications. This removes the RNDIS * wrapper from received Ethernet frames and places them in the FrameIN global buffer, or adds the RNDIS wrapper * to a frame in the FrameOUT global before sending the buffer contents to the host. */ void RNDIS_Task(void) { /* Select the notification endpoint */ Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPADDR); /* Check if a message response is ready for the host */ if (Endpoint_IsINReady() && ResponseReady) { USB_Request_Header_t Notification = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), .bRequest = RNDIS_NOTIF_ResponseAvailable, .wValue = 0, .wIndex = 0, .wLength = 0, }; /* Indicate that a message response is ready for the host */ Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NULL); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); /* Indicate a response is no longer ready */ ResponseReady = false; } /* Don't process the data endpoints until the system is in the data initialized state, and the buffer is free */ if ((CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) { /* Create a new packet header for reading/writing */ RNDIS_Packet_Message_t RNDISPacketHeader; /* Select the data OUT endpoint */ Endpoint_SelectEndpoint(CDC_RX_EPADDR); /* Check if the data OUT endpoint contains data, and that the IN buffer is empty */ if (Endpoint_IsOUTReceived() && !(FrameIN.FrameLength)) { /* Read in the packet message header */ Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); /* Stall the request if the data is too large */ if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) { Endpoint_StallTransaction(); return; } /* Read in the Ethernet frame into the buffer */ Endpoint_Read_Stream_LE(FrameIN.FrameData, RNDISPacketHeader.DataLength, NULL); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearOUT(); /* Store the size of the Ethernet frame */ FrameIN.FrameLength = RNDISPacketHeader.DataLength; } /* Select the data IN endpoint */ Endpoint_SelectEndpoint(CDC_TX_EPADDR); /* Check if the data IN endpoint is ready for more data, and that the IN buffer is full */ if (Endpoint_IsINReady() && FrameOUT.FrameLength) { /* Clear the packet header with all 0s so that the relevant fields can be filled */ memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t)); /* Construct the required packet header fields in the buffer */ RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG; RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + FrameOUT.FrameLength); RNDISPacketHeader.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)); RNDISPacketHeader.DataLength = FrameOUT.FrameLength; /* Send the packet header to the host */ Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); /* Send the Ethernet frame data to the host */ Endpoint_Write_Stream_LE(FrameOUT.FrameData, RNDISPacketHeader.DataLength, NULL); /* Finalize the stream transfer to send the last packet */ Endpoint_ClearIN(); /* Indicate Ethernet OUT buffer no longer full */ FrameOUT.FrameLength = 0; } } }