You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
12 KiB
404 lines
12 KiB
/*
|
|
* upstream_msc.c
|
|
*
|
|
* Created on: 4/07/2015
|
|
* Author: Robert Fisk
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
|
|
#include "upstream_interface_def.h"
|
|
#include "upstream_msc.h"
|
|
#include "upstream_spi.h"
|
|
#include "upstream_statemachine.h"
|
|
#include "stm32f4xx_hal.h"
|
|
#include "build_config.h"
|
|
|
|
|
|
#ifdef CONFIG_MASS_STORAGE_ENABLED
|
|
|
|
|
|
//Stuff we need to save for our callbacks to use:
|
|
UpstreamMSCCallbackTypeDef TestReadyCallback;
|
|
UpstreamMSCCallbackTypeDef BeginReadCallback;
|
|
UpstreamMSCCallbackTypeDef BeginWriteCallback;
|
|
UpstreamMSCCallbackTypeDef DisconnectCallback;
|
|
UpstreamMSCCallbackUintPacketTypeDef GetCapacityCallback;
|
|
UpstreamMSCCallbackPacketTypeDef GetStreamDataCallback;
|
|
uint64_t BlockStart;
|
|
uint32_t BlockCount;
|
|
uint32_t ByteCount;
|
|
|
|
UpstreamPacketTypeDef* ReadStreamPacket;
|
|
uint8_t ReadStreamBusy;
|
|
|
|
|
|
static void Upstream_MSC_TestReadyFreePacketCallback(UpstreamPacketTypeDef* freePacket);
|
|
static void Upstream_MSC_TestReadyReplyCallback(UpstreamPacketTypeDef* replyPacket);
|
|
static void Upstream_MSC_GetCapacityFreePacketCallback(UpstreamPacketTypeDef* freePacket);
|
|
static void Upstream_MSC_GetCapacityReplyCallback(UpstreamPacketTypeDef* replyPacket);
|
|
static void Upstream_MSC_GetStreamDataPacketCallback(UpstreamPacketTypeDef* replyPacket);
|
|
static void Upstream_MSC_BeginReadFreePacketCallback(UpstreamPacketTypeDef* freePacket);
|
|
static void Upstream_MSC_BeginWriteFreePacketCallback(UpstreamPacketTypeDef* freePacket);
|
|
static void Upstream_MSC_RequestDisconnectFreePacketCallback(UpstreamPacketTypeDef* freePacket);
|
|
static void Upstream_MSC_RequestDisconnectReplyCallback(UpstreamPacketTypeDef* replyPacket);
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_TestReady(UpstreamMSCCallbackTypeDef callback)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
//UPSTREAM_STATEMACHINE_FREAKOUT;
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
TestReadyCallback = callback;
|
|
return Upstream_GetFreePacket(Upstream_MSC_TestReadyFreePacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_TestReadyFreePacketCallback(UpstreamPacketTypeDef* freePacket)
|
|
{
|
|
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
|
|
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
|
|
freePacket->Command = COMMAND_MSC_TEST_UNIT_READY;
|
|
|
|
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
|
|
{
|
|
//Upstream_PacketManager will free the packet when the transfer is done
|
|
if (Upstream_ReceivePacket(Upstream_MSC_TestReadyReplyCallback) != HAL_OK)
|
|
{
|
|
TestReadyCallback(HAL_ERROR);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//else:
|
|
Upstream_ReleasePacket(freePacket);
|
|
TestReadyCallback(HAL_ERROR);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_TestReadyReplyCallback(UpstreamPacketTypeDef* replyPacket)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (replyPacket == NULL)
|
|
{
|
|
TestReadyCallback(HAL_ERROR);
|
|
return;
|
|
}
|
|
|
|
if ((replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + 1)) ||
|
|
(replyPacket->Data[0] != HAL_OK))
|
|
{
|
|
Upstream_ReleasePacket(replyPacket);
|
|
TestReadyCallback(HAL_ERROR);
|
|
return;
|
|
}
|
|
|
|
Upstream_ReleasePacket(replyPacket);
|
|
TestReadyCallback(HAL_OK);
|
|
}
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_GetCapacity(UpstreamMSCCallbackUintPacketTypeDef callback)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
GetCapacityCallback = callback;
|
|
return Upstream_GetFreePacket(Upstream_MSC_GetCapacityFreePacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_GetCapacityFreePacketCallback(UpstreamPacketTypeDef* freePacket)
|
|
{
|
|
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
|
|
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
|
|
freePacket->Command = COMMAND_MSC_GET_CAPACITY;
|
|
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
|
|
{
|
|
if (Upstream_ReceivePacket(Upstream_MSC_GetCapacityReplyCallback) != HAL_OK)
|
|
{
|
|
GetCapacityCallback(NULL, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//else:
|
|
Upstream_ReleasePacket(freePacket);
|
|
GetCapacityCallback(NULL, 0, 0);
|
|
}
|
|
|
|
|
|
static void Upstream_MSC_GetCapacityReplyCallback(UpstreamPacketTypeDef* replyPacket)
|
|
{
|
|
uint32_t block_count;
|
|
uint32_t block_size;
|
|
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (replyPacket == NULL)
|
|
{
|
|
GetCapacityCallback(NULL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
if (replyPacket->Length16 != (UPSTREAM_PACKET_HEADER_LEN_16 + (8 / 2)))
|
|
{
|
|
Upstream_ReleasePacket(replyPacket);
|
|
GetCapacityCallback(NULL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
block_count = *(uint32_t*)&(replyPacket->Data[0]);
|
|
block_size = *(uint32_t*)&(replyPacket->Data[4]);
|
|
|
|
if ((block_count < MSC_MINIMUM_BLOCK_COUNT) ||
|
|
(block_size != MSC_SUPPORTED_BLOCK_SIZE))
|
|
{
|
|
Upstream_ReleasePacket(replyPacket);
|
|
GetCapacityCallback(NULL, 0, 0);
|
|
return;
|
|
}
|
|
GetCapacityCallback(replyPacket, block_count, block_size); //usb_msc_scsi will use this packet, so don't release now
|
|
}
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_BeginRead(UpstreamMSCCallbackTypeDef callback,
|
|
uint64_t readBlockStart,
|
|
uint32_t readBlockCount,
|
|
uint32_t readByteCount)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
BlockStart = readBlockStart;
|
|
BlockCount = readBlockCount;
|
|
ByteCount = readByteCount;
|
|
ReadStreamPacket = NULL; //Prepare for GetStreamDataPacket's use
|
|
ReadStreamBusy = 0;
|
|
|
|
BeginReadCallback = callback;
|
|
return Upstream_GetFreePacket(Upstream_MSC_BeginReadFreePacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_BeginReadFreePacketCallback(UpstreamPacketTypeDef* freePacket)
|
|
{
|
|
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2);
|
|
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
|
|
freePacket->Command = COMMAND_MSC_READ;
|
|
*(uint64_t*)&(freePacket->Data[0]) = BlockStart;
|
|
*(uint32_t*)&(freePacket->Data[8]) = BlockCount;
|
|
|
|
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
|
|
{
|
|
BeginReadCallback(HAL_OK);
|
|
return;
|
|
}
|
|
|
|
//else:
|
|
Upstream_ReleasePacket(freePacket);
|
|
BeginReadCallback(HAL_ERROR);
|
|
}
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_GetStreamDataPacket(UpstreamMSCCallbackPacketTypeDef callback)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
GetStreamDataCallback = callback;
|
|
|
|
if (ReadStreamBusy != 0)
|
|
{
|
|
return HAL_OK;
|
|
}
|
|
ReadStreamBusy = 1;
|
|
|
|
if (ReadStreamPacket && GetStreamDataCallback) //Do we have a stored packet and an address to send it?
|
|
{
|
|
Upstream_MSC_GetStreamDataPacketCallback(ReadStreamPacket); //Send it now!
|
|
ReadStreamPacket = NULL;
|
|
return HAL_OK; //Our callback will call us again, so we don't need to get a packet in this case.
|
|
}
|
|
return Upstream_ReceivePacket(Upstream_MSC_GetStreamDataPacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_GetStreamDataPacketCallback(UpstreamPacketTypeDef* replyPacket)
|
|
{
|
|
uint32_t dataLength8;
|
|
|
|
ReadStreamBusy = 0;
|
|
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GetStreamDataCallback == NULL)
|
|
{
|
|
ReadStreamPacket = replyPacket; //We used up our callback already, so save this one for later.
|
|
return;
|
|
}
|
|
|
|
if (replyPacket == NULL)
|
|
{
|
|
GetStreamDataCallback(NULL, 0);
|
|
return;
|
|
}
|
|
|
|
dataLength8 = (replyPacket->Length16 - UPSTREAM_PACKET_HEADER_LEN_16) * 2;
|
|
|
|
if (((replyPacket->CommandClass & COMMAND_CLASS_DATA_FLAG) == 0) || //Any 'command' reply (as opposed to 'data' reply) is an automatic fail here
|
|
(dataLength8 != MSC_MINIMUM_DATA_UNIT) || //Should only receive integer units of MSC block size
|
|
(dataLength8 > ByteCount)) //No more data than expected transfer length
|
|
{
|
|
GetStreamDataCallback(NULL, 0);
|
|
return;
|
|
}
|
|
|
|
ByteCount -= dataLength8;
|
|
GetStreamDataCallback(replyPacket, dataLength8); //usb_msc_scsi will use this packet, so don't release now
|
|
if (ByteCount > 0)
|
|
{
|
|
Upstream_MSC_GetStreamDataPacket(NULL); //Try to get the next packet now, before USB asks for it
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
|
|
HAL_StatusTypeDef Upstream_MSC_BeginWrite(UpstreamMSCCallbackTypeDef callback,
|
|
uint64_t writeBlockStart,
|
|
uint32_t writeBlockCount)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
LED_SetState(LED_STATUS_FLASH_READWRITE);
|
|
BlockStart = writeBlockStart;
|
|
BlockCount = writeBlockCount;
|
|
BeginWriteCallback = callback;
|
|
return Upstream_GetFreePacket(Upstream_MSC_BeginWriteFreePacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_BeginWriteFreePacketCallback(UpstreamPacketTypeDef* freePacket)
|
|
{
|
|
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2);
|
|
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
|
|
freePacket->Command = COMMAND_MSC_WRITE;
|
|
*(uint64_t*)&(freePacket->Data[0]) = BlockStart;
|
|
*(uint32_t*)&(freePacket->Data[8]) = BlockCount;
|
|
|
|
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
|
|
{
|
|
BeginWriteCallback(HAL_OK);
|
|
return;
|
|
}
|
|
|
|
//else:
|
|
Upstream_ReleasePacket(freePacket);
|
|
BeginWriteCallback(HAL_ERROR);
|
|
}
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_PutStreamDataPacket(UpstreamPacketTypeDef* packetToSend,
|
|
uint32_t dataLength8)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if ((dataLength8 % 2) != 0)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
packetToSend->Length16 = (dataLength8 / 2) + UPSTREAM_PACKET_HEADER_LEN_16;
|
|
packetToSend->CommandClass = COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG;
|
|
packetToSend->Command = COMMAND_MSC_WRITE;
|
|
return Upstream_TransmitPacket(packetToSend);
|
|
}
|
|
#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
|
|
|
|
|
|
|
|
HAL_StatusTypeDef Upstream_MSC_RequestDisconnect(UpstreamMSCCallbackTypeDef callback)
|
|
{
|
|
if (Upstream_StateMachine_CheckActiveClass() != COMMAND_CLASS_MASS_STORAGE) return HAL_ERROR;
|
|
|
|
DisconnectCallback = callback;
|
|
return Upstream_GetFreePacket(Upstream_MSC_RequestDisconnectFreePacketCallback);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_RequestDisconnectFreePacketCallback(UpstreamPacketTypeDef* freePacket)
|
|
{
|
|
freePacket->Length16 = UPSTREAM_PACKET_HEADER_LEN_16;
|
|
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
|
|
freePacket->Command = COMMAND_MSC_DISCONNECT;
|
|
|
|
if (Upstream_TransmitPacket(freePacket) == HAL_OK)
|
|
{
|
|
//Upstream_PacketManager will free the packet when the transfer is done
|
|
if (Upstream_ReceivePacket(Upstream_MSC_RequestDisconnectReplyCallback) != HAL_OK)
|
|
{
|
|
DisconnectCallback(HAL_ERROR);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//else:
|
|
Upstream_ReleasePacket(freePacket);
|
|
DisconnectCallback(HAL_ERROR);
|
|
}
|
|
|
|
|
|
|
|
static void Upstream_MSC_RequestDisconnectReplyCallback(UpstreamPacketTypeDef* replyPacket)
|
|
{
|
|
//Acknowledge the SCSI Stop command to host now.
|
|
//We will disconnect from host when Downstream replies with COMMAND_ERROR_DEVICE_DISCONNECTED.
|
|
|
|
Upstream_ReleasePacket(replyPacket);
|
|
DisconnectCallback(HAL_OK);
|
|
}
|
|
|
|
|
|
|
|
#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED
|
|
|