/******************************************************************************* * 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; }
/*! * @brief USB configure endpoint function. * * This function configure endpoint status. * * @param handle The USB device handle. * @param ep Endpoint address. * @param status A flag to indicate whether to stall the endpoint. 1: stall, 0: unstall. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status) { if (status) { return USB_DeviceStallEndpoint(handle, ep); } else { return USB_DeviceUnstallEndpoint(handle, ep); } }
/*! * @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 Handle set or clear device feature request. * * This function is used to handle set or clear device feature request. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param setup The pointer of the setup packet. * @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. * * @retval kStatus_USB_Success The requst is handled successfully. * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, * or, the request is unsupported. */ static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_common_class_struct_t *classHandle, usb_setup_struct_t *setup, uint8_t **buffer, uint32_t *length) { usb_status_t error = kStatus_USB_InvalidRequest; uint8_t state; uint8_t isSet = 0U; USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) { return error; } /* Identify the request is set or clear the feature. */ if (USB_REQUEST_STANDARD_SET_FEATURE == setup->bRequest) { isSet = 1U; } if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) { /* Set or Clear the device featrue. */ if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP == setup->wValue) { /* Set or Clear the device remote wakeup featrue. */ error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetRemoteWakeup, &isSet); } #if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ (defined(USB_DEVICE_CONFIG_EHCI_TEST_MODE) && (USB_DEVICE_CONFIG_EHCI_TEST_MODE > 0U)) else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE == setup->wValue) { state = kUSB_DeviceStateTestMode; error = USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); } #endif else { } } else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) { /* Set or Clear the endpoint featrue. */ if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT == setup->wValue) { if (USB_CONTROL_ENDPOINT == (setup->wIndex & USB_ENDPOINT_NUMBER_MASK)) { /* Set or Clear the control endpoint status(halt or not). */ if (isSet) { USB_DeviceStallEndpoint(classHandle->handle, (uint8_t)setup->wIndex); } else { USB_DeviceUnstallEndpoint(classHandle->handle, (uint8_t)setup->wIndex); } } /* Set or Clear the endpoint status featrue. */ if (isSet) { error = USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetEndpointHalt, &setup->wIndex); } else { error = USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventClearEndpointHalt, &setup->wIndex); } } else { } } else { } return error; }
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; }