//! 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;
}
Пример #2
0
/** 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;
}