Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/usb/msc/usbd_msc.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/usb/msc/usbd_msc.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,1216 @@ +/** + * @file usbd_msc.c + * @brief Mass Storage Class driver + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> + +#include "rl_usb.h" +#include "usb_for_lib.h" +#include "util.h" + +BOOL USBD_MSC_MediaReady = __FALSE; +BOOL USBD_MSC_ReadOnly = __FALSE; +U32 USBD_MSC_MemorySize; +U32 USBD_MSC_BlockSize; +U32 USBD_MSC_BlockGroup; +U32 USBD_MSC_BlockCount; +U8 *USBD_MSC_BlockBuf; + +MSC_CBW USBD_MSC_CBW; /* Command Block Wrapper */ +MSC_CSW USBD_MSC_CSW; /* Command Status Wrapper */ + +BOOL USBD_MSC_MediaReadyEx = __FALSE; /* Previous state of Media ready */ +BOOL MemOK; /* Memory OK */ + +U32 Block; /* R/W Block */ +U32 Offset; /* R/W Offset */ +U32 Length; /* R/W Length */ + +U8 BulkStage; /* Bulk Stage */ +U32 BulkLen; /* Bulk In/Out Length */ + + +/* Dummy Weak Functions that need to be provided by user */ +__weak void usbd_msc_init() +{ + +} +__weak void usbd_msc_read_sect(U32 block, U8 *buf, U32 num_of_blocks) +{ + +} +__weak void usbd_msc_write_sect(U32 block, U8 *buf, U32 num_of_blocks) +{ + +} +__weak void usbd_msc_start_stop(BOOL start) +{ + +} + + +/* + * Set Stall for USB Device MSC Endpoint + * Parameters: EPNum: USB Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_MSC_SetStallEP(U32 EPNum) /* set EP halt status according stall status */ +{ + USBD_SetStallEP(EPNum); + USBD_EndPointHalt |= (EPNum & 0x80) ? ((1 << 16) << (EPNum & 0x0F)) : (1 << EPNum); +} + + +/* + * Clear Stall for USB Device MSC Endpoint + * Parameters: EPNum: USB Device Endpoint Number + * EPNum.0..3: Address + * EPNum.7: Dir + * Return Value: None + */ + +void USBD_MSC_ClrStallEP(U32 EPNum) /* clear EP halt status according stall status */ +{ + U32 n, m; + n = USBD_SetupPacket.wIndexL & 0x8F; + m = (n & 0x80) ? ((1 << 16) << (n & 0x0F)) : (1 << n); + + if ((n == (usbd_msc_ep_bulkin | 0x80)) && ((USBD_EndPointHalt & m) != 0)) { + /* Compliance Test: rewrite CSW after unstall */ + if (USBD_MSC_CSW.dSignature == MSC_CSW_Signature) { + USBD_WriteEP((usbd_msc_ep_bulkin | 0x80), (U8 *)&USBD_MSC_CSW, sizeof(USBD_MSC_CSW)); + } + } +} + + +/* + * USB Device MSC Mass Storage Reset Request Callback + * Called automatically on USB Device Mass Storage Reset Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_MSC_Reset(void) +{ + USBD_EndPointStall = 0x00000000; /* EP must stay stalled */ + USBD_MSC_CSW.dSignature = 0; /* invalid signature */ + BulkStage = MSC_BS_RESET; + return (__TRUE); +} + + +/* + * USB Device MSC Get Max LUN Request Callback + * Called automatically on USB Device Get Max LUN Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_MSC_GetMaxLUN(void) +{ + USBD_EP0Buf[0] = 0; /* one LUN associated with this device */ + return (__TRUE); +} + + +/* + * USB Device Check Media Ready + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_MSC_CheckMedia(void) +{ + USBD_MSC_MediaReadyEx = USBD_MSC_MediaReady; + + if (!USBD_MSC_MediaReady) { + if (USBD_MSC_CBW.dDataLength) { + if ((USBD_MSC_CBW.bmFlags & 0x80) != 0) { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + } else { + if (USBD_MSC_CSW.dDataResidue != BulkLen) { + // Only stall if this isn't the last transfer + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + } + } + } + + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + return (__FALSE); + } + + return (__TRUE); +} + + +/* + * USB Device MSC Memory Read Callback + * Called automatically on USB Device Memory Read Event + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_MemoryRead(void) +{ + U32 n, m; + + if (Block >= USBD_MSC_BlockCount) { + n = 0; + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); + } else { + if (Length > usbd_msc_maxpacketsize[USBD_HighSpeed]) { + n = usbd_msc_maxpacketsize[USBD_HighSpeed]; + } else { + n = Length; + } + } + + if (!USBD_MSC_CheckMedia()) { + n = 0; + } + + if ((Offset == 0) && (n != 0)) { + m = (Length + (USBD_MSC_BlockSize - 1)) / USBD_MSC_BlockSize; + + if (m > USBD_MSC_BlockGroup) { + m = USBD_MSC_BlockGroup; + } + + usbd_msc_read_sect(Block, USBD_MSC_BlockBuf, m); + } + + if (n) { + USBD_WriteEP(usbd_msc_ep_bulkin | 0x80, &USBD_MSC_BlockBuf[Offset], n); + Offset += n; + Length -= n; + } + + if (Offset == USBD_MSC_BlockGroup * USBD_MSC_BlockSize) { + Offset = 0; + Block += USBD_MSC_BlockGroup; + } + + USBD_MSC_CSW.dDataResidue -= n; + + if (!n) { + return; + } + + if (Length == 0) { + BulkStage = MSC_BS_DATA_IN_LAST; + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + } +} + + +/* + * USB Device MSC Memory Write Callback + * Called automatically on USB Device Memory Write Event + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_MemoryWrite(void) +{ + U32 n; + + if (Block >= USBD_MSC_BlockCount) { + BulkLen = 0; + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); + } + + if (!USBD_MSC_CheckMedia()) { + BulkLen = 0; + } + + if (Offset + BulkLen > USBD_MSC_BlockSize) { + // This write would have overflowed USBD_MSC_BlockBuf + util_assert(0); + return; + } + + for (n = 0; n < BulkLen; n++) { + USBD_MSC_BlockBuf[Offset + n] = USBD_MSC_BulkBuf[n]; + } + + Offset += BulkLen; + Length -= BulkLen; + + if (BulkLen) { + if ((Length == 0) && (Offset != 0)) { + n = (Offset + (USBD_MSC_BlockSize - 1)) / USBD_MSC_BlockSize; + + if (n > USBD_MSC_BlockGroup) { + n = USBD_MSC_BlockGroup; + } + + usbd_msc_write_sect(Block, USBD_MSC_BlockBuf, n); + Offset = 0; + Block += n; + } else if (Offset == USBD_MSC_BlockGroup * USBD_MSC_BlockSize) { + usbd_msc_write_sect(Block, USBD_MSC_BlockBuf, USBD_MSC_BlockGroup); + Offset = 0; + Block += USBD_MSC_BlockGroup; + } + } + + USBD_MSC_CSW.dDataResidue -= BulkLen; + + if (!BulkLen) { + return; + } + + if ((Length == 0) || (BulkStage == MSC_BS_CSW)) { + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); + } +} + + +/* + * USB Device MSC Memory Verify Callback + * Called automatically on USB Device Memory Verify Event + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_MemoryVerify(void) +{ + U32 n; + + if (Block >= USBD_MSC_BlockCount) { + BulkLen = 0; + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); + } + + if (!USBD_MSC_CheckMedia()) { + BulkLen = 0; + } + + if (BulkLen) { + if ((Offset == 0) && (BulkLen != 0)) { + n = (Length + (USBD_MSC_BlockSize - 1)) / USBD_MSC_BlockSize; + + if (n > USBD_MSC_BlockGroup) { + n = USBD_MSC_BlockGroup; + } + + usbd_msc_read_sect(Block, USBD_MSC_BlockBuf, n); + } + + for (n = 0; n < BulkLen; n++) { + if (USBD_MSC_BlockBuf[Offset + n] != USBD_MSC_BulkBuf[n]) { + MemOK = __FALSE; + break; + } + } + } + + Offset += BulkLen; + Length -= BulkLen; + + if (Offset == USBD_MSC_BlockGroup * USBD_MSC_BlockSize) { + Offset = 0; + Block += USBD_MSC_BlockGroup; + } + + USBD_MSC_CSW.dDataResidue -= BulkLen; + + if (!BulkLen) { + return; + } + + if ((Length == 0) || (BulkStage == MSC_BS_CSW)) { + USBD_MSC_CSW.bStatus = (MemOK) ? CSW_CMD_PASSED : CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + } +} + + +/* + * USB Device MSC SCSI Read/Write Setup Callback + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_MSC_RWSetup(void) +{ + U32 n; + /* Logical Block Address of First Block */ + n = (USBD_MSC_CBW.CB[2] << 24) | + (USBD_MSC_CBW.CB[3] << 16) | + (USBD_MSC_CBW.CB[4] << 8) | + (USBD_MSC_CBW.CB[5] << 0); + Block = n; + Offset = 0; + + /* Number of Blocks to transfer */ + switch (USBD_MSC_CBW.CB[0]) { + case SCSI_WRITE10: + case SCSI_VERIFY10: + if (!USBD_MSC_CheckMedia()) { + return (__FALSE); + } + + case SCSI_READ10: + n = (USBD_MSC_CBW.CB[7] << 8) | + (USBD_MSC_CBW.CB[8] << 0); + break; + + case SCSI_WRITE12: + if (!USBD_MSC_CheckMedia()) { + return (__FALSE); + } + + case SCSI_READ12: + n = (USBD_MSC_CBW.CB[6] << 24) | + (USBD_MSC_CBW.CB[7] << 16) | + (USBD_MSC_CBW.CB[8] << 8) | + (USBD_MSC_CBW.CB[9] << 0); + break; + } + + Length = n * USBD_MSC_BlockSize; + + if (USBD_MSC_CBW.dDataLength == 0) { /* host requests no data */ + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + return (__FALSE); + } + + if (USBD_MSC_CBW.dDataLength != Length) { + if ((USBD_MSC_CBW.bmFlags & 0x80) != 0) { /* stall appropriate EP */ + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + } else { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + } + + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + return (__FALSE); + } + + return (__TRUE); +} + + +/* + * USB Device Check Data IN Format + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_MSC_DataInFormat(void) +{ + if (USBD_MSC_CBW.dDataLength == 0) { + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + return (__FALSE); + } + + if ((USBD_MSC_CBW.bmFlags & 0x80) == 0) { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + return (__FALSE); + } + + return (__TRUE); +} + + +/* + * USB Device Perform Data IN Transfer + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_DataInTransfer(void) +{ + if (BulkLen >= USBD_MSC_CBW.dDataLength) { + BulkLen = USBD_MSC_CBW.dDataLength; + BulkStage = MSC_BS_DATA_IN_LAST; + } else { + BulkStage = MSC_BS_DATA_IN_LAST_STALL; /* short or zero packet */ + } + + USBD_WriteEP(usbd_msc_ep_bulkin | 0x80, USBD_MSC_BulkBuf, BulkLen); + USBD_MSC_CSW.dDataResidue -= BulkLen; + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; +} + + +/* + * USB Device MSC SCSI Test Unit Ready Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_TestUnitReady(void) +{ + if (USBD_MSC_CBW.dDataLength != 0) { + if ((USBD_MSC_CBW.bmFlags & 0x80) != 0) { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + } else { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + } + + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + return; + } + + if (!USBD_MSC_CheckMedia()) { + return; + } + + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); +} + + +/* + * USB Device MSC SCSI Request Sense Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_RequestSense(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x70; /* Response Code */ + USBD_MSC_BulkBuf[ 1] = 0x00; + + if ((USBD_MSC_MediaReadyEx ^ USBD_MSC_MediaReady) & USBD_MSC_MediaReady) { /* If media state changed to ready */ + USBD_MSC_BulkBuf[ 2] = 0x06; /* UNIT ATTENTION */ + USBD_MSC_BulkBuf[12] = 0x28; /* Additional Sense Code: Not ready to ready transition */ + USBD_MSC_BulkBuf[13] = 0x00; /* Additional Sense Code Qualifier */ + USBD_MSC_MediaReadyEx = USBD_MSC_MediaReady; + } else if (!USBD_MSC_MediaReady) { + USBD_MSC_BulkBuf[ 2] = 0x02; /* NOT READY */ + USBD_MSC_BulkBuf[12] = 0x3A; /* Additional Sense Code: Medium not present */ + USBD_MSC_BulkBuf[13] = 0x00; /* Additional Sense Code Qualifier */ + } else { + if (USBD_MSC_CSW.bStatus == CSW_CMD_PASSED) { + USBD_MSC_BulkBuf[ 2] = 0x00; /* NO SENSE */ + USBD_MSC_BulkBuf[12] = 0x00; /* Additional Sense Code: No additional code */ + USBD_MSC_BulkBuf[13] = 0x00; /* Additional Sense Code Qualifier */ + } else { + USBD_MSC_BulkBuf[ 2] = 0x05; /* ILLEGAL REQUEST */ + USBD_MSC_BulkBuf[12] = 0x20; /* Additional Sense Code: Invalid command */ + USBD_MSC_BulkBuf[13] = 0x00; /* Additional Sense Code Qualifier */ + } + } + + USBD_MSC_BulkBuf[ 3] = 0x00; + USBD_MSC_BulkBuf[ 4] = 0x00; + USBD_MSC_BulkBuf[ 5] = 0x00; + USBD_MSC_BulkBuf[ 6] = 0x00; + USBD_MSC_BulkBuf[ 7] = 0x0A; /* Additional Length */ + USBD_MSC_BulkBuf[ 8] = 0x00; + USBD_MSC_BulkBuf[ 9] = 0x00; + USBD_MSC_BulkBuf[10] = 0x00; + USBD_MSC_BulkBuf[11] = 0x00; + USBD_MSC_BulkBuf[14] = 0x00; + USBD_MSC_BulkBuf[15] = 0x00; + USBD_MSC_BulkBuf[16] = 0x00; + USBD_MSC_BulkBuf[17] = 0x00; + BulkLen = 18; + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Inquiry Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_Inquiry(void) +{ + U8 i; + U8 *ptr_str; + + if (!USBD_MSC_DataInFormat()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x00; /* Direct Access Device */ + USBD_MSC_BulkBuf[ 1] = 0x80; /* RMB = 1: Removable Medium */ + USBD_MSC_BulkBuf[ 2] = 0x02; /* Version: ANSI X3.131: 1994 */ + USBD_MSC_BulkBuf[ 3] = 0x02; + USBD_MSC_BulkBuf[ 4] = 36 - 4; /* Additional Length */ + USBD_MSC_BulkBuf[ 5] = 0x00; /* SCCS = 0: No Storage Controller Component */ + USBD_MSC_BulkBuf[ 6] = 0x00; + USBD_MSC_BulkBuf[ 7] = 0x00; + ptr_str = (U8 *)usbd_msc_inquiry_data; + + for (i = 8; i < 36; i++) { /* Product Information + */ + if (*ptr_str) { /* Product Revision Level */ + USBD_MSC_BulkBuf[i] = *ptr_str++; + } else { + USBD_MSC_BulkBuf[i] = ' '; + } + } + + BulkLen = 36; + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Start Stop Unit Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_StartStopUnit(void) +{ + if (!USBD_MSC_CBW.CB[3]) { /* If power condition modifier is 0 */ + USBD_MSC_MediaReady = USBD_MSC_CBW.CB[4] & 0x01; /* Media ready = START bit value */ + usbd_msc_start_stop(USBD_MSC_MediaReady); + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; /* Start Stop Unit -> pass */ + USBD_MSC_SetCSW(); + return; + } + + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; /* Start Stop Unit -> fail */ + USBD_MSC_SetCSW(); +} + + +/* + * USB Device MSC SCSI Media Removal Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_MediaRemoval(void) +{ + if (USBD_MSC_CBW.CB[4] & 1) { /* If prevent */ + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; /* Prevent media removal -> fail */ + } else { /* If allow */ + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; /* Allow media removal -> pass */ + } + + USBD_MSC_SetCSW(); +} + + +/* + * USB Device MSC SCSI Mode Sense (6-Byte) Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_ModeSense6(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + if (!USBD_MSC_CheckMedia()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x03; + USBD_MSC_BulkBuf[ 1] = 0x00; + USBD_MSC_BulkBuf[ 2] = (USBD_MSC_ReadOnly << 7); + USBD_MSC_BulkBuf[ 3] = 0x00; + BulkLen = 4; + + /* Win host requests maximum number of bytes but as all we have is 4 bytes we have + to tell host back that it is all we have, that's why we correct residue */ + if (USBD_MSC_CSW.dDataResidue > BulkLen) { + USBD_MSC_CBW.dDataLength = BulkLen; + USBD_MSC_CSW.dDataResidue = BulkLen; + } + + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Mode Sense (10-Byte) Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_ModeSense10(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + if (!USBD_MSC_CheckMedia()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x00; + USBD_MSC_BulkBuf[ 1] = 0x06; + USBD_MSC_BulkBuf[ 2] = 0x00; + USBD_MSC_BulkBuf[ 3] = (USBD_MSC_ReadOnly << 7); + USBD_MSC_BulkBuf[ 4] = 0x00; + USBD_MSC_BulkBuf[ 5] = 0x00; + USBD_MSC_BulkBuf[ 6] = 0x00; + USBD_MSC_BulkBuf[ 7] = 0x00; + BulkLen = 8; + + /* Win host requests maximum number of bytes but as all we have is 8 bytes we have + to tell host back that it is all we have, that's why we correct residue */ + if (USBD_MSC_CSW.dDataResidue > BulkLen) { + USBD_MSC_CBW.dDataLength = BulkLen; + USBD_MSC_CSW.dDataResidue = BulkLen; + } + + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Read Capacity Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_ReadCapacity(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + if (!USBD_MSC_CheckMedia()) { + return; + } + + /* Last Logical Block */ + USBD_MSC_BulkBuf[ 0] = ((USBD_MSC_BlockCount - 1) >> 24) & 0xFF; + USBD_MSC_BulkBuf[ 1] = ((USBD_MSC_BlockCount - 1) >> 16) & 0xFF; + USBD_MSC_BulkBuf[ 2] = ((USBD_MSC_BlockCount - 1) >> 8) & 0xFF; + USBD_MSC_BulkBuf[ 3] = ((USBD_MSC_BlockCount - 1) >> 0) & 0xFF; + /* Block Length */ + USBD_MSC_BulkBuf[ 4] = (USBD_MSC_BlockSize >> 24) & 0xFF; + USBD_MSC_BulkBuf[ 5] = (USBD_MSC_BlockSize >> 16) & 0xFF; + USBD_MSC_BulkBuf[ 6] = (USBD_MSC_BlockSize >> 8) & 0xFF; + USBD_MSC_BulkBuf[ 7] = (USBD_MSC_BlockSize >> 0) & 0xFF; + BulkLen = 8; + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Read Format Capacity Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_ReadFormatCapacity(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + if (!USBD_MSC_CheckMedia()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x00; + USBD_MSC_BulkBuf[ 1] = 0x00; + USBD_MSC_BulkBuf[ 2] = 0x00; + USBD_MSC_BulkBuf[ 3] = 0x08; /* Capacity List Length */ + /* Block Count */ + USBD_MSC_BulkBuf[ 4] = (USBD_MSC_BlockCount >> 24) & 0xFF; + USBD_MSC_BulkBuf[ 5] = (USBD_MSC_BlockCount >> 16) & 0xFF; + USBD_MSC_BulkBuf[ 6] = (USBD_MSC_BlockCount >> 8) & 0xFF; + USBD_MSC_BulkBuf[ 7] = (USBD_MSC_BlockCount >> 0) & 0xFF; + /* Block Length */ + USBD_MSC_BulkBuf[ 8] = 0x02; /* Descriptor Code: Formatted Media */ + USBD_MSC_BulkBuf[ 9] = (USBD_MSC_BlockSize >> 16) & 0xFF; + USBD_MSC_BulkBuf[10] = (USBD_MSC_BlockSize >> 8) & 0xFF; + USBD_MSC_BulkBuf[11] = (USBD_MSC_BlockSize >> 0) & 0xFF; + BulkLen = 12; + + /* Win host requests maximum number of bytes but as all we have is 12 bytes we have + to tell host back that it is all we have, that's why we correct residue */ + if (USBD_MSC_CSW.dDataResidue > BulkLen) { + USBD_MSC_CBW.dDataLength = BulkLen; + USBD_MSC_CSW.dDataResidue = BulkLen; + } + + USBD_MSC_DataInTransfer(); +} + + +/* + * USB Device MSC SCSI Synchronize Cache (10/16-Byte) Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_SynchronizeCache(void) +{ + /* Synchronize check always passes as we always write data dirrectly + so cache is always synchronized */ + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); +} + + +/* + * USB Device MSC ATA Pass-Through Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_ATAPassThrough(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x02; + USBD_MSC_BulkBuf[ 1] = 0x02; + BulkLen = 2; + BulkStage = MSC_BS_DATA_IN_LAST; + + /* Win host requests maximum number of bytes but as all we have is 2 bytes we have + to tell host back that it is all we have, that's why we correct residue */ + if (USBD_MSC_CSW.dDataResidue > BulkLen) { + USBD_MSC_CBW.dDataLength = BulkLen; + USBD_MSC_CSW.dDataResidue = BulkLen; + } + + USBD_WriteEP(usbd_msc_ep_bulkin | 0x80, USBD_MSC_BulkBuf, BulkLen); + USBD_MSC_CSW.dDataResidue -= BulkLen; + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; +} + +/* + * USB Device MSC Service Action (16-Byte) Callback + * Parameters: None + * Return Value: None + */ + + +void USBD_MSC_ServiceActionIn16(void) +{ + if (!USBD_MSC_DataInFormat()) { + return; + } + + USBD_MSC_BulkBuf[ 0] = 0x20; + USBD_MSC_BulkBuf[ 1] = 0x00; + USBD_MSC_BulkBuf[31] = 0x00; + BulkLen = 32; + BulkStage = MSC_BS_DATA_IN_LAST; + USBD_WriteEP(usbd_msc_ep_bulkin | 0x80, USBD_MSC_BulkBuf, BulkLen); + USBD_MSC_CSW.dDataResidue -= BulkLen; + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; +} + + +/* + * USB Device MSC Get Command Block Wrapper Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_GetCBW(void) +{ + U32 n; + U32 copy_size; + copy_size = MIN(BulkLen, sizeof(USBD_MSC_CBW)); + + for (n = 0; n < copy_size; n++) { + *((U8 *)&USBD_MSC_CBW + n) = USBD_MSC_BulkBuf[n]; + } + + if ((BulkLen == sizeof(USBD_MSC_CBW)) && (USBD_MSC_CBW.dSignature == MSC_CBW_Signature)) { + /* Valid USBD_MSC_CBW */ + USBD_MSC_CSW.dTag = USBD_MSC_CBW.dTag; + USBD_MSC_CSW.dDataResidue = USBD_MSC_CBW.dDataLength; + + if ((USBD_MSC_CBW.bLUN > 0) || + (USBD_MSC_CBW.bCBLength < 1) || + (USBD_MSC_CBW.bCBLength > 16)) { +fail: + USBD_MSC_CSW.bStatus = CSW_CMD_FAILED; + USBD_MSC_SetCSW(); + } else { + switch (USBD_MSC_CBW.CB[0]) { + case SCSI_TEST_UNIT_READY: + USBD_MSC_TestUnitReady(); + break; + + case SCSI_REQUEST_SENSE: + USBD_MSC_RequestSense(); + break; + + case SCSI_FORMAT_UNIT: + goto fail; + + case SCSI_INQUIRY: + USBD_MSC_Inquiry(); + break; + + case SCSI_START_STOP_UNIT: + USBD_MSC_StartStopUnit(); + break; + + case SCSI_MEDIA_REMOVAL: + USBD_MSC_MediaRemoval(); + break; + + case SCSI_MODE_SELECT6: + goto fail; + + case SCSI_MODE_SENSE6: + USBD_MSC_ModeSense6(); + break; + + case SCSI_MODE_SELECT10: + goto fail; + + case SCSI_MODE_SENSE10: + USBD_MSC_ModeSense10(); + break; + + case SCSI_READ_FORMAT_CAPACITIES: + USBD_MSC_ReadFormatCapacity(); + break; + + case SCSI_READ_CAPACITY: + USBD_MSC_ReadCapacity(); + break; + + case SCSI_ATA_COMMAND_PASS_THROUGH12: + USBD_MSC_ATAPassThrough(); + break; + + case SCSI_SERVICE_ACTION_IN16: + USBD_MSC_ServiceActionIn16(); + break; + + case SCSI_READ10: + case SCSI_READ12: + if (USBD_MSC_RWSetup()) { + if ((USBD_MSC_CBW.bmFlags & 0x80) != 0) { + BulkStage = MSC_BS_DATA_IN; + USBD_MSC_MemoryRead(); + } else { /* direction mismatch */ + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + } + } + + break; + + case SCSI_WRITE10: + case SCSI_WRITE12: + if (USBD_MSC_RWSetup()) { + if ((USBD_MSC_CBW.bmFlags & 0x80) == 0) { + BulkStage = MSC_BS_DATA_OUT; + } else { /* direction mismatch */ + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + } + } + + break; + + case SCSI_VERIFY10: + if ((USBD_MSC_CBW.CB[1] & 0x02) == 0) { + // BYTCHK = 0 -> CRC Check (not implemented) + USBD_MSC_CSW.bStatus = CSW_CMD_PASSED; + USBD_MSC_SetCSW(); + break; + } + + if (USBD_MSC_RWSetup()) { + if ((USBD_MSC_CBW.bmFlags & 0x80) == 0) { + BulkStage = MSC_BS_DATA_OUT; + MemOK = __TRUE; + } else { + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + } + } + + break; + + case SCSI_SYNC_CACHE10: + case SCSI_SYNC_CACHE16: + USBD_MSC_SynchronizeCache(); + break; + + case SCSI_REPORT_ID_INFO: + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + goto fail; + + default: + goto fail; + } + } + } else { + /* Invalid USBD_MSC_CBW */ + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + /* set EP to stay stalled */ + USBD_EndPointStall |= ((1 << 16) << (usbd_msc_ep_bulkin & 0x0F)); + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + /* set EP to stay stalled */ + USBD_EndPointStall |= 1 << usbd_msc_ep_bulkout; + BulkStage = MSC_BS_ERROR; + } +} + + +/* + * USB Device MSC Set Command Status Wrapper Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_SetCSW(void) +{ + USBD_MSC_CSW.dSignature = MSC_CSW_Signature; + USBD_WriteEP(usbd_msc_ep_bulkin | 0x80, (U8 *)&USBD_MSC_CSW, sizeof(USBD_MSC_CSW)); + BulkStage = MSC_BS_CSW; +} + + +/* + * USB Device MSC Bulk In Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_BulkIn(void) +{ + switch (BulkStage) { + case MSC_BS_DATA_IN: + switch (USBD_MSC_CBW.CB[0]) { + case SCSI_READ10: + case SCSI_READ12: + USBD_MSC_MemoryRead(); + break; + } + + break; + + case MSC_BS_DATA_IN_LAST: + USBD_MSC_SetCSW(); + break; + + case MSC_BS_DATA_IN_LAST_STALL: + USBD_MSC_SetStallEP(usbd_msc_ep_bulkin | 0x80); + USBD_MSC_SetCSW(); + break; + + case MSC_BS_CSW: + BulkStage = MSC_BS_CBW; + break; + + default: + break; + } +} + + +/* + * USB Device MSC Bulk Out Callback + * Parameters: None + * Return Value: None + */ + +void USBD_MSC_BulkOut(void) +{ + switch (BulkStage) { + case MSC_BS_CBW: + USBD_MSC_GetCBW(); + break; + + case MSC_BS_DATA_OUT: + switch (USBD_MSC_CBW.CB[0]) { + case SCSI_WRITE10: + case SCSI_WRITE12: + USBD_MSC_MemoryWrite(); + break; + + case SCSI_VERIFY10: + USBD_MSC_MemoryVerify(); + break; + } + break; + + case MSC_BS_CSW: + // Previous transfer must be complete + // before the next transfer begins. + // + // If bulk out is stalled then just + // drop this packet and don't assert. + // This packet was left over from before + // the transfer aborted with a stall. + util_assert(USBD_EndPointHalt & (1 << usbd_msc_ep_bulkout)); + break; + + case MSC_BS_RESET: + // If Bulk-Only Mass Storage Reset command was received on + // Control Endpoint ignore next Bulk OUT transfer if it was not + // a CBW (as it means it was a unprocessed leftover from + // transfer before reset happened) + BulkStage = MSC_BS_CBW; + if (BulkLen == sizeof(USBD_MSC_CBW)) { + // If it is a CBW size packet go process it as CBW + USBD_MSC_GetCBW(); + } + break; + + default: + USBD_MSC_SetStallEP(usbd_msc_ep_bulkout); + USBD_MSC_CSW.bStatus = CSW_PHASE_ERROR; + USBD_MSC_SetCSW(); + break; + } +} + +/** \brief Handle Reset Events + + The function handles Reset events. + */ + +void USBD_MSC_Reset_Event(void) +{ + USBD_MSC_Reset(); +} + +/* + * USB Device MSC Bulk In Endpoint Event Callback + * Parameters: event: not used (just for compatibility) + * Return Value: None + */ + +void USBD_MSC_EP_BULKIN_Event(U32 event) +{ + USBD_MSC_BulkIn(); +} + + +/* + * USB Device MSC Bulk Out Endpoint Event Callback + * Parameters: event: not used (just for compatibility) + * Return Value: None + */ + +void USBD_MSC_EP_BULKOUT_Event(U32 event) +{ + BulkLen = USBD_ReadEP(usbd_msc_ep_bulkout, USBD_MSC_BulkBuf, USBD_MSC_BulkBufSize); + USBD_MSC_BulkOut(); +} + + +/* + * USB Device MSC Bulk In/Out Endpoint Event Callback + * Parameters: event: USB Device Event + * USBD_EVT_OUT: Output Event + * USBD_EVT_IN: Input Event + * Return Value: None + */ + +void USBD_MSC_EP_BULK_Event(U32 event) +{ + if (event & USBD_EVT_OUT) { + USBD_MSC_EP_BULKOUT_Event(0); + } + + if (event & USBD_EVT_IN) { + USBD_MSC_EP_BULKIN_Event(0); + } +} + + +#ifdef __RTX /* RTX tasks for handling events */ + +/* + * USB Device MSC Bulk In Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +__task void USBD_RTX_MSC_EP_BULKIN_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + + if (usbd_os_evt_get() & USBD_EVT_IN) { + USBD_MSC_EP_BULKIN_Event(0); + } + } +} + + +/* + * USB Device MSC Bulk Out Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +__task void USBD_RTX_MSC_EP_BULKOUT_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + + if (usbd_os_evt_get() & USBD_EVT_OUT) { + USBD_MSC_EP_BULKOUT_Event(0); + } + } +} + + +/* + * USB Device MSC Bulk In/Out Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +__task void USBD_RTX_MSC_EP_BULK_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + USBD_MSC_EP_BULK_Event(usbd_os_evt_get()); + } +} +#endif