/*! * @brief Bulk in pipe callback function. * * This function serves as the callback function for bulk in pipe. * * @param handle The USB device handle. * @param message The endpoint callback message * @param callbackParam The parameter of the callback. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) { usb_status_t error = kStatus_USB_Error; if ((message->length != 0) && (!(message->length % s_usbBulkMaxPacketSize))) { /* If the last packet is the size of endpoint, then send also zero-ended packet, ** meaning that we want to inform the host that we do not have any additional ** data, so it can flush the output. */ USB_DeviceSendRequest(handle, USB_CDC_VCOM_BULK_IN_ENDPOINT, NULL, 0); } else if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) { if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0))) { /* User: add your own code for send complete event */ /* Schedule buffer for next receive event */ USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize); #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) s_waitForDataReceive = 1; USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK; #endif } } else { } return error; }
/******************************************************************************* * Code ******************************************************************************/ usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle) { usb_status_t error = kStatus_USB_Success; usb_device_lba_app_struct_t lba; lba.offset = mscHandle->currentOffset; /*bulkInBufferSize is the application buffer size, USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH is the max transfer length by the hardware, lba.size is the data pending for transfer ,select the minimum size to transfer ,the remaining will be transfer next time*/ lba.size = (mscHandle->bulkInBufferSize > USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH) ? USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH : mscHandle->bulkInBufferSize; lba.size = (mscHandle->transferRemaining > lba.size) ? lba.size : mscHandle->transferRemaining; /* whichever is smaller */ lba.buffer = g_deviceComposite->mscDisk.storageDisk + lba.offset; if (mscHandle->currentOffset < (mscHandle->totalLogicalBlockNumber * mscHandle->lengthOfEachLba)) { error = USB_DeviceSendRequest(g_deviceComposite->deviceHandle, mscHandle->bulkInEndpoint, lba.buffer, lba.size); } else { mscHandle->needInStallFlag = 0; mscHandle->inEndpointStallFlag = 1; mscHandle->dataInFlag = 0; mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA; USB_DeviceStallEndpoint(g_deviceComposite->deviceHandle, mscHandle->bulkInEndpoint); } return error; }
/*! * @brief Bulk IN endpoint callback function. * * This callback function is used to notify uplayer the tranfser result of a transfer. * This callback pointer is passed when the Bulk IN pipe initialized. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param event The result of the Bulk IN pipe transfer. * @param arg The paramter for this callback. It is same with * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the MSC class handle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscBulkIn(usb_device_handle deviceHandle, usb_device_endpoint_callback_message_struct_t *event, void *arg) { usb_device_msc_csw_t *csw; usb_status_t error = kStatus_USB_Error; usb_device_msc_struct_t *mscHandle; mscHandle = &(g_deviceComposite->mscDisk.handle); if (event->length == USB_UNINITIALIZED_VAL_32) { return error; } if (mscHandle->transferRemaining >= event->length) { mscHandle->transferRemaining -= event->length; } if (mscHandle->needInStallFlag == 1) { mscHandle->needInStallFlag = 0; mscHandle->inEndpointStallFlag = 1; mscHandle->dataInFlag = 0; USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkInEndpoint); return error; } if ((!mscHandle->dataInFlag) && (event->length == USB_DEVICE_MSC_CSW_LENGTH)) { csw = (usb_device_msc_csw_t *)(event->buffer); } if (mscHandle->dataInFlag) { if (mscHandle->transferRemaining) { mscHandle->currentOffset += event->length; error = USB_DeviceMscSend(mscHandle); } if (!mscHandle->transferRemaining) { mscHandle->dataInFlag = 0; /*data transfer has been done, send the csw to host */ USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)&mscHandle->g_mscCsw, USB_DEVICE_MSC_CSW_LENGTH); } } else if ((event->length == USB_DEVICE_MSC_CSW_LENGTH) && (csw->signature == USB_DEVICE_MSC_DCSWSIGNATURE)) { mscHandle->cbwValidFlag = 1; (void)USB_DeviceRecvRequest(deviceHandle, mscHandle->bulkOutEndpoint, (uint8_t *)&mscHandle->g_mscCbw, USB_DEVICE_MSC_CBW_LENGTH); mscHandle->cbwPrimeFlag = 1; } else { } return error; }
/* See virtual_com.h for documentation of this function. */ void USB_VcomWriteBlocking(usb_device_handle baseAddr, const uint8_t *buf, size_t count) { while ((s_cdcVcom.attach != 1) || (s_cdcVcom.startTransactions != 1)) { __NOP(); }; USB_DeviceSendRequest((usb_device_handle)baseAddr, USB_CDC_VCOM_BULK_IN_ENDPOINT, (uint8_t *)buf, count); while (!s_sendComplete) { __NOP(); }; s_sendComplete = 0; }
/*! * @brief Send the reponse to the host. * * This function is used to send the reponse to the host. * * There are two cases this function will be called. * Case one when a setup packet is received in control endpoint callback function: * 1. If there is not data phase in the setup transfer, the function will prime an IN transfer with the data * length is zero for status phase. * 2. If there is an IN data phase, the function will prime an OUT transfer with the actual length to need to * send for data phase. And then prime an IN transfer with the data length is zero for status phase. * 3. If there is an OUT data phase, the function will prime an IN transfer with the actual length to want to * receive for data phase. * * Case two when is not a setup packet received in control endpoint callback function: * 1. The function will prime an IN transfer with data length is zero for status phase. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param setup The pointer of the setup packet. * @param error The error code returned from the standard request fucntion. * @param stage The stage of the control transfer. * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. * @param length It is an out parameter, the data length. * * @return A USB error code or kStatus_USB_Success. */ static usb_status_t USB_DeviceControlCallbackFeedback(usb_device_handle handle, usb_setup_struct_t *setup, usb_status_t error, usb_device_control_read_write_sequence_t stage, uint8_t **buffer, uint32_t *length) { usb_status_t errorCode = kStatus_USB_Error; uint8_t direction = USB_IN; if (kStatus_USB_InvalidRequest == error) { /* Stall the control pipe when the request is unsupported. */ if ((!((setup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_STANDARD)) && ((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) && (setup->wLength) && (kUSB_DeviceControlPipeSetupStage == stage)) { direction = USB_OUT; } errorCode = USB_DeviceStallEndpoint( handle, (USB_CONTROL_ENDPOINT) | (uint8_t)((uint32_t)direction << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); } else { if (*length > setup->wLength) { *length = setup->wLength; } errorCode = USB_DeviceSendRequest(handle, (USB_CONTROL_ENDPOINT), *buffer, *length); if ((kStatus_USB_Success == errorCode) && (USB_REQUEST_TYPE_DIR_IN == (setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK))) { errorCode = USB_DeviceRecvRequest(handle, (USB_CONTROL_ENDPOINT), (uint8_t *)NULL, 0U); } } return errorCode; }
/*! * @brief CDC class specific callback function. * * This function handles the CDC class specific requests. * * @param handle The USB device handle. * @param setup The pointer to the setup packet. * @param length The pointer to the length of the data buffer. * @param buffer The pointer to the address of setup packet data buffer. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, usb_setup_struct_t *setup, uint32_t *length, uint8_t **buffer) { usb_status_t error = kStatus_USB_InvalidRequest; usb_cdc_acm_info_t *acmInfo = &s_usbCdcAcmInfo; uint32_t len; uint16_t *uartBitmap; if (setup->wIndex != USB_CDC_VCOM_COMM_INTERFACE_INDEX) { return error; } switch (setup->bRequest) { case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND: break; case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE: break; case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE: if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) { *buffer = s_abstractState; } else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) { *buffer = s_countryCode; } else { } error = kStatus_USB_Success; break; case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE: if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) { *buffer = s_abstractState; *length = COMM_FEATURE_DATA_SIZE; } else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) { *buffer = s_countryCode; *length = COMM_FEATURE_DATA_SIZE; } else { } error = kStatus_USB_Success; break; case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE: break; case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING: *buffer = s_lineCoding; *length = LINE_CODING_SIZE; error = kStatus_USB_Success; break; case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING: *buffer = s_lineCoding; error = kStatus_USB_Success; break; case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE: { acmInfo->dteStatus = setup->wValue; /* activate/deactivate Tx carrier */ if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) { acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER; } else { acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_TX_CARRIER; } /* activate carrier and DTE */ if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) { acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER; } else { acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_RX_CARRIER; } /* Indicates to DCE if DTE is present or not */ acmInfo->dtePresent = (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) ? true : false; /* Initialize the serial state buffer */ acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE; /* bmRequestType */ acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF; /* bNotification */ acmInfo->serialStateBuf[2] = 0x00; /* wValue */ acmInfo->serialStateBuf[3] = 0x00; acmInfo->serialStateBuf[4] = 0x00; /* wIndex */ acmInfo->serialStateBuf[5] = 0x00; acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; /* wLength */ acmInfo->serialStateBuf[7] = 0x00; /* Notifiy to host the line state */ acmInfo->serialStateBuf[4] = setup->wIndex; /* Lower byte of UART BITMAP */ uartBitmap = (uint16_t *)&acmInfo->serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE - 2]; *uartBitmap = acmInfo->uartState; len = (uint32_t)(NOTIF_PACKET_SIZE + UART_BITMAP_SIZE); error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT, acmInfo->serialStateBuf, len); /* Update status */ if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) { /* To do: CARRIER_ACTIVATED */ } else { /* To do: CARRIER_DEACTIVATED */ } if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) { /* DTE_ACTIVATED */ if (1 == s_cdcVcom.attach) { s_cdcVcom.startTransactions = 1; #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK; #endif } } else { /* DTE_DEACTIVATED */ if (1 == s_cdcVcom.attach) { s_cdcVcom.startTransactions = 0; } } } break; case USB_DEVICE_CDC_REQUEST_SEND_BREAK: break; default: break; } return error; }
/*! * @brief Application task function. * * This function runs the task for application. * * @return None. */ void APP_task(void) { usb_status_t error = kStatus_USB_Error; if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) { /* User Code */ if ((0 != s_recvSize) && (0xFFFFFFFFU != s_recvSize)) { int32_t i; /* Copy Buffer to Send Buff */ for (i = 0; i < s_recvSize; i++) { s_currSendBuf[s_sendSize++] = s_currRecvBuf[i]; } s_recvSize = 0; } if (s_sendSize) { uint32_t size = s_sendSize; s_sendSize = 0; error = USB_DeviceSendRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, s_currSendBuf, size); if (error != kStatus_USB_Success) { /* Failure to send Data Handling code here */ } } #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) if ((s_waitForDataReceive)) { if (s_comOpen == 1) { /* Wait for all the packets been sent during opening the com port. Otherwise these packets may * wake up the system. */ usb_echo("Waiting to enter lowpower ...\r\n"); for (uint32_t i = 0U; i < 16000000U; ++i) { __ASM("NOP"); /* delay */ } s_comOpen = 0; } usb_echo("Enter lowpower\r\n"); USB0->INTEN &= ~USB_INTEN_TOKDNEEN_MASK; SMC_SetPowerModeVlps(SMC); s_waitForDataReceive = 0; USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK; usb_echo("Exit lowpower\r\n"); } #endif } #if USB_DEVICE_CONFIG_USE_TASK USB_DeviceKhciTaskFunction(s_cdcVcom.deviceHandle); #endif }
usb_status_t USB_DeviceMscDiskConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status) { usb_status_t error = kStatus_USB_Error; usb_device_msc_struct_t *mscHandle; mscHandle = &(g_deviceComposite->mscDisk.handle); if (status) { if ((USB_MSC_DISK_BULK_IN_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) && (ep & 0x80U)) { if (mscHandle->inEndpointStallFlag == 0) { mscHandle->inEndpointStallFlag = 1; error = USB_DeviceStallEndpoint(handle, ep); } } else if ((USB_MSC_DISK_BULK_OUT_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) && (ep & 0x80U)) { if (mscHandle->outEndpointStallFlag == 0) { mscHandle->outEndpointStallFlag = 1; error = USB_DeviceStallEndpoint(handle, ep); } } else { } } else { if ((USB_MSC_DISK_BULK_IN_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) && (ep & 0x80U)) { if (mscHandle->inEndpointStallFlag == 1) { mscHandle->inEndpointStallFlag = 0; error = USB_DeviceUnstallEndpoint(handle, ep); } } else if ((USB_MSC_DISK_BULK_OUT_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) && (ep & 0x80U)) { if (mscHandle->outEndpointStallFlag == 1) { mscHandle->outEndpointStallFlag = 0; error = USB_DeviceUnstallEndpoint(handle, ep); } } else { } } if (((mscHandle->stallStatus == USB_DEVICE_MSC_STALL_IN_CSW) || (mscHandle->stallStatus == USB_DEVICE_MSC_STALL_IN_DATA)) && (mscHandle->performResetDoneFlag != 1)) { if (mscHandle->cswPrimeFlag == 1) { USB_DeviceCancel(handle, mscHandle->bulkInEndpoint); } USB_DeviceSendRequest(handle, mscHandle->bulkInEndpoint, (uint8_t *)&mscHandle->g_mscCsw, USB_DEVICE_MSC_CSW_LENGTH); mscHandle->cswPrimeFlag = 0; mscHandle->stallStatus = 0; } if ((mscHandle->performResetDoneFlag == 1) && (mscHandle->inEndpointStallFlag == 0) && (mscHandle->outEndpointStallFlag == 0)) { mscHandle->performResetDoneFlag = 0; if (mscHandle->cswPrimeFlag == 1) { USB_DeviceCancel(handle, mscHandle->bulkInEndpoint); } USB_DeviceRecvRequest(handle, mscHandle->bulkOutEndpoint, (uint8_t *)&mscHandle->g_mscCbw, USB_DEVICE_MSC_CBW_LENGTH); mscHandle->cswPrimeFlag = 0; mscHandle->stallStatus = 0; } return error; }
/*! * @brief Bulk OUT endpoint callback function. * * This callback function is used to notify uplayer the tranfser result of a transfer. * This callback pointer is passed when the Bulk OUT pipe initialized. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param message The result of the Bulk OUT pipe transfer. * @param callbackParam The paramter for this callback. It is same with * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the MSC class handle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscBulkOut(usb_device_handle deviceHandle, usb_device_endpoint_callback_message_struct_t *event, void *arg) { usb_status_t error = kStatus_USB_Success; usb_device_msc_struct_t *mscHandle; mscHandle = &(g_deviceComposite->mscDisk.handle); if (event->length == USB_UNINITIALIZED_VAL_32) { return error; } if (mscHandle->transferRemaining >= event->length) { mscHandle->transferRemaining -= event->length; } if (mscHandle->needOutStallFlag == 1) { mscHandle->needOutStallFlag = 0; mscHandle->outEndpointStallFlag = 1; mscHandle->dataOutFlag = 0; mscHandle->cbwPrimeFlag = 0; USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkOutEndpoint); return error; } if (mscHandle->dataOutFlag) { if (mscHandle->transferRemaining) { mscHandle->currentOffset += event->length; error = USB_DeviceMscRecv(mscHandle); } if (!mscHandle->transferRemaining) { mscHandle->dataOutFlag = 0; { USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)&mscHandle->g_mscCsw, USB_DEVICE_MSC_CSW_LENGTH); mscHandle->cswPrimeFlag = 1; } } } else if ((mscHandle->cbwValidFlag) && (event->length == USB_DEVICE_MSC_CBW_LENGTH) && (mscHandle->g_mscCbw.signature == USB_DEVICE_MSC_DCBWSIGNATURE) && (!((mscHandle->g_mscCbw.logicalUnitNumber & 0xF0U) || (mscHandle->g_mscCbw.cbLength & 0xE0U))) && (mscHandle->g_mscCbw.logicalUnitNumber < (mscHandle->logicalUnitNumber + 1)) && ((mscHandle->g_mscCbw.cbLength >= 0x01) && (mscHandle->g_mscCbw.cbLength <= 0x10))) { mscHandle->cbwPrimeFlag = 0; mscHandle->transferRemaining = 0; mscHandle->g_mscCsw.signature = USB_DEVICE_MSC_DCSWSIGNATURE; mscHandle->g_mscCsw.dataResidue = 0; mscHandle->g_mscCsw.tag = mscHandle->g_mscCbw.tag; mscHandle->cbwValidFlag = 0; mscHandle->g_mscCbw.dataTransferLength = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->g_mscCbw.dataTransferLength); mscHandle->dataOutFlag = (uint8_t)(((!(mscHandle->g_mscCbw.flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT)) && (mscHandle->g_mscCbw.dataTransferLength)) ? 1 : 0); mscHandle->dataInFlag = (uint8_t)(((mscHandle->g_mscCbw.flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT) && (mscHandle->g_mscCbw.dataTransferLength)) ? 1 : 0); if ((0 != mscHandle->dataInFlag) && (0 != mscHandle->inEndpointStallFlag)) { error = kStatus_USB_Error; return error; } error = USB_DeviceMscProcessUfiCommand(mscHandle); if (error == kStatus_USB_InvalidRequest) { if (mscHandle->dataOutFlag == 1) { if (mscHandle->outEndpointStallFlag == 0) { mscHandle->needOutStallFlag = 1; } mscHandle->dataOutFlag = 0; } else if (mscHandle->dataInFlag == 1) { if (mscHandle->inEndpointStallFlag == 0) { mscHandle->needInStallFlag = 1; } mscHandle->dataInFlag = 0; } else { } mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA; } if (!((mscHandle->dataOutFlag) || ((mscHandle->dataInFlag) || (mscHandle->needInStallFlag)))) { USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)&mscHandle->g_mscCsw, USB_DEVICE_MSC_CSW_LENGTH); mscHandle->cswPrimeFlag = 1; } } else { USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkOutEndpoint); USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkInEndpoint); mscHandle->cbwValidFlag = 0; mscHandle->outEndpointStallFlag = 1; mscHandle->inEndpointStallFlag = 1; mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_CBW; mscHandle->performResetRecover = 1; } return error; }
/* The device callback */ static usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param) { usb_status_t error = kStatus_USB_Success; uint8_t *temp8 = (uint8_t *)param; uint16_t *temp16 = (uint16_t *)param; switch (event) { case kUSB_DeviceEventBusReset: { /* The device BUS reset signal detected */ USB_DeviceVideoApplicationSetDefault(); #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U) if (kStatus_USB_Success == USB_DeviceGetStatus(g_UsbDeviceVideoVirtualCamera.deviceHandle, kUSB_DeviceStatusSpeed, &g_UsbDeviceVideoVirtualCamera.speed)) { USB_DeviceSetSpeed(g_UsbDeviceVideoVirtualCamera.deviceHandle, g_UsbDeviceVideoVirtualCamera.speed); } if (USB_SPEED_HIGH == g_UsbDeviceVideoVirtualCamera.speed) { g_UsbDeviceVideoVirtualCamera.currentMaxPacketSize = HS_STREAM_IN_PACKET_SIZE; } #endif } break; case kUSB_DeviceEventSetConfiguration: if (USB_VIDEO_VIRTUAL_CAMERA_CONFIGURE_INDEX == (*temp8)) { /* Set the configuration request */ g_UsbDeviceVideoVirtualCamera.attach = 1U; g_UsbDeviceVideoVirtualCamera.currentConfiguration = *temp8; } break; case kUSB_DeviceEventSetInterface: if ((g_UsbDeviceVideoVirtualCamera.attach) && param) { /* Set alternateSetting of the interface request */ uint8_t interface = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U); uint8_t alternateSetting = (uint8_t)(*temp16 & 0x00FFU); if (g_UsbDeviceVideoVirtualCamera.currentInterfaceAlternateSetting[interface] != alternateSetting) { if (!g_UsbDeviceVideoVirtualCamera.currentInterfaceAlternateSetting[interface]) { if (USB_VIDEO_VIRTUAL_CAMERA_STREAM_INTERFACE_INDEX == interface) { USB_DeviceVideoPrepareVideoData(); error = USB_DeviceSendRequest(g_UsbDeviceVideoVirtualCamera.deviceHandle, USB_VIDEO_VIRTUAL_CAMERA_STREAM_ENDPOINT_IN, g_UsbDeviceVideoVirtualCamera.imageBuffer, g_UsbDeviceVideoVirtualCamera.imageBufferLength); } } g_UsbDeviceVideoVirtualCamera.currentInterfaceAlternateSetting[interface] = alternateSetting; } } break; case kUSB_DeviceEventGetConfiguration: if (param) { /* Get the current configuration request */ *temp8 = g_UsbDeviceVideoVirtualCamera.currentConfiguration; error = kStatus_USB_Success; } break; case kUSB_DeviceEventGetInterface: if (param) { /* Set the alternateSetting of the interface request */ uint8_t interface = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U); if (interface < USB_VIDEO_VIRTUAL_CAMERA_INTERFACE_COUNT) { *temp16 = (*temp16 & 0xFF00U) | g_UsbDeviceVideoVirtualCamera.currentInterfaceAlternateSetting[interface]; error = kStatus_USB_Success; } else { error = kStatus_USB_InvalidRequest; } } break; case kUSB_DeviceEventGetDeviceDescriptor: if (param) { /* Get the device descriptor request */ error = USB_DeviceGetDeviceDescriptor(handle, (usb_device_get_device_descriptor_struct_t *)param); } break; case kUSB_DeviceEventGetConfigurationDescriptor: if (param) { /* Get the configuration descriptor request */ error = USB_DeviceGetConfigurationDescriptor(handle, (usb_device_get_configuration_descriptor_struct_t *)param); } break; case kUSB_DeviceEventGetStringDescriptor: if (param) { /* Get the string descriptor request */ error = USB_DeviceGetStringDescriptor(handle, (usb_device_get_string_descriptor_struct_t *)param); } break; default: break; }