//! This function transfers the data between memory and USB MSC interface //! //! @param addr Sector address to start read //! @param nb_sector Number of sectors to transfer (sector=512 bytes) //! @param b_read Memory to USB, if true //! //! @return Ctrl_status //! It is ready -> CTRL_GOOD //! Memory unplug -> CTRL_NO_PRESENT //! Not initialized or changed -> CTRL_BUSY //! An error occurred -> CTRL_FAIL //! static Ctrl_status virtual_usb_trans(uint32_t addr, uint16_t nb_sector, bool b_read) { if ((addr > VMEM_NB_SECTOR) || (addr + nb_sector > VMEM_NB_SECTOR)) { return CTRL_FAIL; } for (uint16_t i = 0; i < nb_sector; i++) { if (b_read) { VirtualFAT_ReadBlock(addr + i); if (!udi_msc_trans_block(b_read, BlockBuffer, VMEM_SECTOR_SIZE, NULL)) { return CTRL_FAIL; // transfer aborted } } else { if (!udi_msc_trans_block(b_read, BlockBuffer, VMEM_SECTOR_SIZE, NULL)) { return CTRL_FAIL; // transfer aborted } VirtualFAT_WriteBlock(addr + i); } } return CTRL_GOOD; }
/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address * and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual * reading and writing of the data. * * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE) * * \return Boolean \c true if the command completed successfully, \c false otherwise. */ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo, const bool IsDataRead) { uint16_t BlockAddress; uint16_t TotalBlocks; /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */ BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]); /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */ TotalBlocks = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]); /* Check if the block address is outside the maximum allowable value for the LUN */ if (BlockAddress >= LUN_MEDIA_BLOCKS) { /* Block address is invalid, update SENSE key and return command fail */ SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); return false; } /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */ for (uint16_t i = 0; i < TotalBlocks; i++) { if (IsDataRead == DATA_READ) VirtualFAT_ReadBlock(BlockAddress + i); else VirtualFAT_WriteBlock(BlockAddress + i); } /* Update the bytes transferred counter and succeed the command */ MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * SECTOR_SIZE_BYTES); return true; }