RISC_v update

master
Ivan Olenichev 3 years ago
parent 6185c52b56
commit 6800a95abe

@ -0,0 +1,25 @@
/*
* build_config.h
*
* Created on: 23 окт. 2021 г.
* Author: ivan
*/
#ifndef INCLUDE_BUILD_CONFIG_H_
#define INCLUDE_BUILD_CONFIG_H_
#define CONFIG_MASS_STORAGE_ENABLED
#define CONFIG_MASS_STORAGE_WRITES_PERMITTED
#define CONFIG_KEYBOARD_ENABLED
#define CONFIG_MOUSE_ENABLED
#define CONFIG_READ_FLASH_TIME_MS 3000 //Enable read LED flashes for the specified length of time
#define CONFIG_USB_ID_ENABLED
//#define CONFIG_FLASH_RDP_ENABLE
#endif /* INCLUDE_BUILD_CONFIG_H_ */

@ -0,0 +1,77 @@
/*
* downstream_interface_def.h
*
* Created on: 24/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/.
*/
#ifndef INC_DOWNSTREAM_INTERFACE_DEF_H_
#define INC_DOWNSTREAM_INTERFACE_DEF_H_
//***************
// Attention!
// Keep this file synchronised with upstream_interface_def.h
// in the Upstream project.
//***************
#define COMMAND_CLASS_DATA_FLAG 0x80
#define COMMAND_CLASS_MASK ((uint8_t)(~COMMAND_CLASS_DATA_FLAG))
typedef enum
{
COMMAND_CLASS_INTERFACE,
COMMAND_CLASS_MASS_STORAGE,
COMMAND_CLASS_HID_MOUSE,
COMMAND_CLASS_HID_KEYBOARD,
//...
COMMAND_CLASS_ERROR
}
InterfaceCommandClassTypeDef;
typedef enum
{
COMMAND_INTERFACE_ECHO, //Returns echo packet including all data
COMMAND_INTERFACE_NOTIFY_DEVICE //Returns COMMAND_CLASS_*** byte when downstream USB device is connected
}
InterfaceCommandInterfaceTypeDef;
typedef enum
{
COMMAND_MSC_TEST_UNIT_READY, //Returns HAL_StatusTypeDef result
COMMAND_MSC_GET_CAPACITY, //Returns uint32_t blk_nbr, uint32_t blk_size
COMMAND_MSC_READ, //Returns data stream or error packet
COMMAND_MSC_WRITE, //Waits for data stream or returns error packet
COMMAND_MSC_DISCONNECT, //Returns same packet after sending Stop command to device
COMMAND_MSC_POLL_DISCONNECT //Returns same packet if device is still connected
}
InterfaceCommandMscTypeDef;
typedef enum
{
COMMAND_HID_GET_REPORT, //Returns HID report from device
COMMAND_HID_SET_REPORT //Sends HID report to device. Simple ack packet contains no data.
}
InterfaceCommandHidTypeDef;
typedef enum
{
COMMAND_ERROR_GENERIC, //Something went wrong, time to FREAKOUT
COMMAND_ERROR_DEVICE_DISCONNECTED, //Device unexpectedly disconnected
}
InterfaceCommandErrorTypeDef;
#endif /* INC_DOWNSTREAM_INTERFACE_DEF_H_ */

@ -0,0 +1,27 @@
#ifndef INC_DOWNSTREAM_MSC_H_
#define INC_DOWNSTREAM_MSC_H_
#include "downstream_interface_def.h"
#include "downstream_spi.h"
#define MSC_SUPPORTED_BLOCK_SIZE 512
#define MSC_FIXED_LUN 0
typedef void (*DownstreamMSCCallbackPacketTypeDef)(DownstreamPacketTypeDef* receivedPacket,
uint16_t dataLength8);
InterfaceCommandClassTypeDef Downstream_MSC_ApproveConnectedDevice(void);
void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
StatusTypeDef Downstream_MSC_PutStreamDataPacket(DownstreamPacketTypeDef* packetToSend,
uint32_t dataLength8);
StatusTypeDef Downstream_MSC_GetStreamDataPacket(DownstreamMSCCallbackPacketTypeDef callback);
#endif /* INC_DOWNSTREAM_MSC_H_ */

@ -0,0 +1,84 @@
/*
* downstream_spi.h
*
* Created on: 24/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/.
*/
#ifndef INC_DOWNSTREAM_SPI_H_
#define INC_DOWNSTREAM_SPI_H_
#include "usbh_conf.h"
#define DOWNSTREAM_PACKET_HEADER_LEN (2) //Min length = CommandClass & Command bytes
#define DOWNSTREAM_PACKET_LEN (DOWNSTREAM_PACKET_HEADER_LEN + BOT_PAGE_LENGTH)
#define DOWNSTREAM_PACKET_LEN_MIN (DOWNSTREAM_PACKET_HEADER_LEN)
#define DOWNSTREAM_PACKET_HEADER_LEN_16 (DOWNSTREAM_PACKET_HEADER_LEN / 2)
#define DOWNSTREAM_PACKET_LEN_16 (DOWNSTREAM_PACKET_LEN / 2)
#define DOWNSTREAM_PACKET_LEN_MIN_16 (DOWNSTREAM_PACKET_LEN_MIN / 2)
#define DOWNSTREAM_SPI_FREAKOUT \
do { \
Downstream_PacketProcessor_FreakOut(); \
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_ERROR; \
while (1); \
} while (0);
typedef enum
{
DOWNSTREAM_INTERFACE_IDLE,
DOWNSTREAM_INTERFACE_RX_SIZE_WAIT,
DOWNSTREAM_INTERFACE_RX_PACKET_WAIT,
DOWNSTREAM_INTERFACE_TX_SIZE_WAIT,
DOWNSTREAM_INTERFACE_TX_PACKET_WAIT,
DOWNSTREAM_INTERFACE_ERROR
}
InterfaceStateTypeDef;
typedef enum
{
NOT_BUSY,
BUSY
}
PacketBusyTypeDef;
typedef struct
{
PacketBusyTypeDef Busy; //Everything after Busy should be word-aligned
uint16_t Length16 __attribute__ ((aligned (4))); //Packet length includes CommandClass, Command, and Data
uint8_t CommandClass;
uint8_t Command;
uint8_t Data[BOT_PAGE_LENGTH]; //Should (must?) be word-aligned, for USB copy routine
}
DownstreamPacketTypeDef;
typedef void (*FreePacketCallbackTypeDef)(DownstreamPacketTypeDef* freePacket);
typedef void (*SpiPacketReceivedCallbackTypeDef)(DownstreamPacketTypeDef* receivedPacket);
void Downstream_InitSPI(void);
StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback);
DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void);
void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease);
StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback);
StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite);
void Downstream_SPIProcess(void);
void DMA_SPI_TxRxCpltCallback(void);
//void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
#endif /* INC_DOWNSTREAM_SPI_H_ */

@ -0,0 +1,54 @@
/*
* downstream_statemachine.h
*
* Created on: 2/08/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/.
*/
#ifndef INC_DOWNSTREAM_STATEMACHINE_H_
#define INC_DOWNSTREAM_STATEMACHINE_H_
#include "usb_host.h"
#include "usbh_core.h"
#include "downstream_spi.h"
typedef enum
{
STATE_DEVICE_NOT_READY,
STATE_DEVICE_READY, //Go here if HOST_USER_CLASS_ACTIVE callback arrives first
STATE_WAIT_DEVICE_READY, //Go here if COMMAND_INTERFACE_NOTIFY_DEVICE message arrives first
STATE_ACTIVE,
STATE_ERROR
} DownstreamStateTypeDef;
#define DOWNSTREAM_STATEMACHINE_FREAKOUT \
do { \
USB_Host_Disconnect(); \
/*LED_SetState(LED_STATUS_FLASH_ERROR);*/ \
/*DownstreamState = STATE_ERROR; */ \
while (1); \
} while (0);
void Downstream_InitStateMachine(void);
void Downstream_HostUserCallback(usbh_host *phost, uint8_t id);
void Downstream_PacketProcessor(DownstreamPacketTypeDef* receivedPacket);
void Downstream_PacketProcessor_GenericErrorReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_PacketProcessor_ClassReply(DownstreamPacketTypeDef* replyPacket);
void Downstream_PacketProcessor_NotifyDisconnectReplyRequired(void);
void Downstream_PacketProcessor_CheckNotifyDisconnectReply(void);
void Downstream_PacketProcessor_SetErrorState(void);
void Downstream_PacketProcessor_FreakOut(void);
#endif /* INC_DOWNSTREAM_STATEMACHINE_H_ */

@ -0,0 +1,18 @@
/*
* interrupts.h
*
* Created on: 23 окт. 2021 г.
* Author: ivan
*/
#ifndef INCLUDE_INTERRUPTS_H_
#define INCLUDE_INTERRUPTS_H_
#include "gd32vf103.h"
/* function declarations */
/* DMA0_Channel0 handle function */
void DMA0_Channel1_IRQHandler(void);
void DMA0_Channel2_IRQHandler(void);
#endif /* INCLUDE_INTERRUPTS_H_ */

@ -0,0 +1,16 @@
/*
* usb_host.h
*
* Created on: 23 окт. 2021 г.
* Author: ivan
*/
#ifndef INCLUDE_USB_HOST_H_
#define INCLUDE_USB_HOST_H_
void USB_Host_Init(void);
void USB_Host_Process(void);
void USB_Host_Disconnect(void);
#endif /* INCLUDE_USB_HOST_H_ */

@ -39,4 +39,14 @@ OF SUCH DAMAGE.
#define USBH_MAX_INTERFACES_NUM 2 #define USBH_MAX_INTERFACES_NUM 2
#define USBH_MSC_MPS_SIZE 0x200 #define USBH_MSC_MPS_SIZE 0x200
#define BOT_PAGE_LENGTH 512
typedef enum
{
STATUS_OK = 0x00,
STATUS_ERROR = 0x01,
STATUS_BUSY = 0x02,
STATUS_TIMEOUT = 0x03
} StatusTypeDef;
#endif /* __USBH_CONF_H */ #endif /* __USBH_CONF_H */

@ -0,0 +1,358 @@
/*
* downstream_msc.c
*
* Created on: 8/08/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 "downstream_msc.h"
#include "downstream_interface_def.h"
#include "downstream_statemachine.h"
#include "downstream_spi.h"
//#include "usbh_msc.h"
#include "usbh_msc_core.h"
#include "build_config.h"
#ifdef CONFIG_MASS_STORAGE_ENABLED
extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c
//Stuff we need to save for our callbacks to use:
DownstreamMSCCallbackPacketTypeDef GetStreamDataCallback;
uint32_t ByteCount;
DownstreamPacketTypeDef* ReadStreamPacket;
uint8_t ReadStreamBusy;
static void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_StatusTypeDef result);
static void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_BeginWrite(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_RdWrCompleteCallback(USBH_StatusTypeDef result);
static void Downstream_MSC_GetStreamDataPacketCallback(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_Disconnect(DownstreamPacketTypeDef* receivedPacket);
static void Downstream_MSC_PacketProcessor_DisconnectCallback(USBH_StatusTypeDef result);
//High-level checks on the connected device. We don't want some weirdly
//configured device to bomb our USB stack, accidentally or otherwise.
InterfaceCommandClassTypeDef Downstream_MSC_ApproveConnectedDevice(void)
{
MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
if (MSC_Handle->unit[MSC_FIXED_LUN].error != MSC_OK)
{
return COMMAND_CLASS_INTERFACE; //fail
}
if ((MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr == 0) ||
(MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr == UINT32_MAX))
{
return COMMAND_CLASS_INTERFACE; //fail
}
if (MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size != MSC_SUPPORTED_BLOCK_SIZE)
{
return COMMAND_CLASS_INTERFACE; //fail
}
return COMMAND_CLASS_MASS_STORAGE; //success!
}
void Downstream_MSC_PacketProcessor(DownstreamPacketTypeDef* receivedPacket)
{
switch (receivedPacket->Command)
{
case COMMAND_MSC_TEST_UNIT_READY:
Downstream_MSC_PacketProcessor_TestUnitReady(receivedPacket);
break;
case COMMAND_MSC_GET_CAPACITY:
Downstream_MSC_PacketProcessor_GetCapacity(receivedPacket);
break;
case COMMAND_MSC_READ:
Downstream_MSC_PacketProcessor_BeginRead(receivedPacket);
break;
#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
case COMMAND_MSC_WRITE:
Downstream_MSC_PacketProcessor_BeginWrite(receivedPacket);
break;
#endif
case COMMAND_MSC_DISCONNECT:
Downstream_MSC_PacketProcessor_Disconnect(receivedPacket);
break;
case COMMAND_MSC_POLL_DISCONNECT:
Downstream_PacketProcessor_ClassReply(receivedPacket); //Device is still connected, so send the packet straight back
break;
default:
Downstream_PacketProcessor_FreakOut();
}
}
static void Downstream_MSC_PacketProcessor_TestUnitReady(DownstreamPacketTypeDef* receivedPacket)
{
Downstream_ReleasePacket(receivedPacket);
if (USBH_MSC_UnitIsReady(&hUsbHostFS,
MSC_FIXED_LUN,
Downstream_MSC_PacketProcessor_TestUnitReadyCallback) != USBH_BUSY)
{
Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_FAIL);
}
}
static void Downstream_MSC_PacketProcessor_TestUnitReadyCallback(USBH_StatusTypeDef result)
{
DownstreamPacketTypeDef* freePacket;
freePacket = Downstream_GetFreePacketImmediately();
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_TEST_UNIT_READY;
freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
if (result == USBH_OK)
{
freePacket->Data[0] = HAL_OK;
}
else
{
freePacket->Data[0] = HAL_ERROR;
}
Downstream_PacketProcessor_ClassReply(freePacket);
}
static void Downstream_MSC_PacketProcessor_GetCapacity(DownstreamPacketTypeDef* receivedPacket)
{
MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + (8 / 2);
*(uint32_t*)&(receivedPacket->Data[0]) = MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr;
*(uint32_t*)&(receivedPacket->Data[4]) = (uint32_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
Downstream_PacketProcessor_ClassReply(receivedPacket);
}
static void Downstream_MSC_PacketProcessor_BeginRead(DownstreamPacketTypeDef* receivedPacket)
{
uint64_t readBlockAddress;
uint32_t readBlockCount;
uint64_t readByteCount;
MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
if (receivedPacket->Length16 != (DOWNSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2)))
{
Downstream_PacketProcessor_FreakOut();
return;
}
LED_SetState(LED_STATUS_FLASH_READWRITE);
readBlockAddress = *(uint64_t*)&(receivedPacket->Data[0]);
readBlockCount = *(uint32_t*)&(receivedPacket->Data[8]);
readByteCount = readBlockCount * MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
if ((readBlockAddress >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
((readBlockAddress + readBlockCount - 1) >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
(readByteCount > UINT32_MAX))
{
Downstream_PacketProcessor_FreakOut();
return;
}
receivedPacket->Data[0] = HAL_ERROR;
receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
if (USBH_MSC_Read(&hUsbHostFS,
MSC_FIXED_LUN,
(uint32_t)readBlockAddress,
readBlockCount,
Downstream_MSC_PacketProcessor_RdWrCompleteCallback) == USBH_BUSY)
{
Downstream_ReleasePacket(receivedPacket);
return;
}
//Fail:
Downstream_PacketProcessor_ClassReply(receivedPacket);
}
static void Downstream_MSC_PacketProcessor_RdWrCompleteCallback(USBH_StatusTypeDef result)
{
if (result != USBH_OK)
{
Downstream_GetFreePacket(Downstream_PacketProcessor_GenericErrorReply);
return;
}
Downstream_ReceivePacket(Downstream_PacketProcessor);
}
#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
static void Downstream_MSC_PacketProcessor_BeginWrite(DownstreamPacketTypeDef* receivedPacket)
{
uint64_t writeBlockAddress;
uint32_t writeBlockCount;
uint64_t writeByteCount;
MSC_HandleTypeDef* MSC_Handle = (MSC_HandleTypeDef*)hUsbHostFS.pActiveClass->pData;
if (receivedPacket->Length16 != (DOWNSTREAM_PACKET_HEADER_LEN_16 + ((4 * 3) / 2)))
{
Downstream_PacketProcessor_FreakOut();
return;
}
writeBlockAddress = *(uint64_t*)&(receivedPacket->Data[0]);
writeBlockCount = *(uint32_t*)&(receivedPacket->Data[8]);
writeByteCount = writeBlockCount * MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_size;
if ((writeBlockAddress >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
((writeBlockAddress + writeBlockCount - 1) >= (uint64_t)MSC_Handle->unit[MSC_FIXED_LUN].capacity.block_nbr) ||
(writeByteCount > UINT32_MAX))
{
Downstream_PacketProcessor_FreakOut();
return;
}
ReadStreamPacket = NULL; //Prepare for GetStreamDataPacket's use
ReadStreamBusy = 0;
ByteCount = (uint32_t)writeByteCount;
receivedPacket->Data[0] = HAL_ERROR;
receivedPacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16 + 1;
//Our host stack has no way to detect if write-protection is enabled.
//So currently we can't return HAL_BUSY to Upstream in this situation.
if (USBH_MSC_Write(&hUsbHostFS,
MSC_FIXED_LUN,
(uint32_t)writeBlockAddress,
writeBlockCount,
Downstream_MSC_PacketProcessor_RdWrCompleteCallback) == USBH_BUSY)
{
Downstream_ReleasePacket(receivedPacket);
return;
}
//Fail:
Downstream_PacketProcessor_ClassReply(receivedPacket);
}
#endif
//Used by USB MSC host driver
StatusTypeDef Downstream_MSC_PutStreamDataPacket(DownstreamPacketTypeDef* packetToSend,
uint32_t dataLength8)
{
if ((dataLength8 % 2) != 0)
{
return HAL_ERROR;
}
packetToSend->Length16 = (dataLength8 / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16;
packetToSend->CommandClass = COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG;
packetToSend->Command = COMMAND_MSC_READ;
return Downstream_TransmitPacket(packetToSend);
}
#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
//Used by USB MSC host driver
StatusTypeDef Downstream_MSC_GetStreamDataPacket(DownstreamMSCCallbackPacketTypeDef callback)
{
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?
{
Downstream_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 Downstream_ReceivePacket(Downstream_MSC_GetStreamDataPacketCallback);
}
void Downstream_MSC_GetStreamDataPacketCallback(DownstreamPacketTypeDef* receivedPacket)
{
uint16_t dataLength8;
ReadStreamBusy = 0;
if (GetStreamDataCallback == NULL)
{
ReadStreamPacket = receivedPacket; //We used up our callback already, so save this one for later.
return;
}
dataLength8 = (receivedPacket->Length16 - DOWNSTREAM_PACKET_HEADER_LEN_16) * 2;
if ((receivedPacket->CommandClass != (COMMAND_CLASS_MASS_STORAGE | COMMAND_CLASS_DATA_FLAG)) || //Must be MSC command with data flag set
(receivedPacket->Command != COMMAND_MSC_WRITE) || //Must be write command
(receivedPacket->Length16 <= DOWNSTREAM_PACKET_HEADER_LEN_16) || //Should be at least one data byte in the packet.
(dataLength8 > ByteCount))
{
Downstream_PacketProcessor_FreakOut();
return;
}
ByteCount -= dataLength8;
GetStreamDataCallback(receivedPacket, dataLength8); //usb_msc_scsi will use this packet, so don't release now
if (ByteCount > 0)
{
Downstream_MSC_GetStreamDataPacket(NULL); //Try to get the next packet now, before USB asks for it
}
}
#endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED
static void Downstream_MSC_PacketProcessor_Disconnect(DownstreamPacketTypeDef* receivedPacket)
{
Downstream_ReleasePacket(receivedPacket);
USBH_MSC_StartStopUnit(&hUsbHostFS,
MSC_FIXED_LUN,
MSC_START_STOP_EJECT_FLAG,
Downstream_MSC_PacketProcessor_DisconnectCallback);
}
static void Downstream_MSC_PacketProcessor_DisconnectCallback(USBH_StatusTypeDef result)
{
DownstreamPacketTypeDef* freePacket;
if (result == USBH_OK)
{
freePacket = Downstream_GetFreePacketImmediately();
freePacket->CommandClass = COMMAND_CLASS_MASS_STORAGE;
freePacket->Command = COMMAND_MSC_DISCONNECT;
freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16;
Downstream_PacketProcessor_ClassReply(freePacket);
}
}
#endif //#ifdef CONFIG_MASS_STORAGE_ENABLED

@ -0,0 +1,475 @@
/*
* upstream_spi.c
*
* Created on: 24/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 "downstream_interface_def.h"
#include "downstream_spi.h"
#include "downstream_statemachine.h"
#include "gd32vf103.h"
#include "gd32vf103v_eval.h"
//SPI_HandleTypeDef Hspi1;
DownstreamPacketTypeDef DownstreamPacket0;
DownstreamPacketTypeDef DownstreamPacket1;
DownstreamPacketTypeDef* CurrentWorkingPacket;
DownstreamPacketTypeDef* NextTxPacket = NULL;
InterfaceStateTypeDef DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
FreePacketCallbackTypeDef PendingFreePacketCallback = NULL; //Indicates someone is waiting for a packet buffer to become available
SpiPacketReceivedCallbackTypeDef ReceivePacketCallback = NULL; //Indicates someone is waiting for a received packet
uint32_t TemporaryIncomingPacketLength = 0;
uint8_t SpiInterruptCompleted = 0;
StatusTypeDef Downstream_CheckPreparePacketReception(void);
void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket);
void Downstream_InitSPI(void)
{
DownstreamPacket0.Busy = NOT_BUSY;
DownstreamPacket1.Busy = NOT_BUSY;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(RCU_DMA0);
rcu_periph_clock_enable(RCU_SPI0);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 |GPIO_PIN_6| GPIO_PIN_7);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
dma_parameter_struct dma_init_struct;
/* SPI0 transmit dma config:DMA0-DMA_CH2 */
dma_deinit(DMA0, DMA_CH2);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);
dma_init_struct.memory_addr = (uint32_t)spi0_send_array;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_LOW;
dma_init_struct.number = ARRAYSIZE;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init(DMA0, DMA_CH2, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH2);
dma_memory_to_memory_disable(DMA0, DMA_CH2);
dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);
/* SPI0 receive dma config:DMA0-DMA_CH1 */
dma_deinit(DMA0, DMA_CH1);
dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);
dma_init_struct.memory_addr = (uint32_t)spi0_receive_array;
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init(DMA0, DMA_CH1, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH1);
dma_memory_to_memory_disable(DMA0, DMA_CH1);
dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);
spi_parameter_struct spi_init_struct;
/* deinitilize SPI and the parameters */
spi_i2s_deinit(SPI0);
spi_struct_para_init(&spi_init_struct);
/* SPI0 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_SLAVE;
spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_2;
spi_init_struct.endian = SPI_ENDIAN_LSB;
spi_init(SPI0, &spi_init_struct);
spi_crc_polynomial_set(SPI0,7);
spi_enable(SPI0);
/* DMA channel enable */
dma_channel_enable(DMA0, DMA_CH1);
dma_channel_enable(DMA0, DMA_CH2);
/* SPI DMA enable */
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
eclic_irq_enable(DMA1_Channel0_IRQn,1,0);
spi_i2s_interrupt_enable(SPI0, SPI_I2S_INT_TBE);
}
//Used by downstream state machine and USB host classes.
StatusTypeDef Downstream_GetFreePacket(FreePacketCallbackTypeDef callback)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return STATUS_ERROR;
}
//Do we already have a queued callback?
if (PendingFreePacketCallback != NULL)
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
//Check if there is a free buffer now
if (DownstreamPacket0.Busy == NOT_BUSY)
{
DownstreamPacket0.Busy = BUSY;
callback(&DownstreamPacket0);
return STATUS_OK;
}
if (DownstreamPacket1.Busy == NOT_BUSY)
{
DownstreamPacket1.Busy = BUSY;
callback(&DownstreamPacket1);
return STATUS_OK;
}
//Otherwise save requested address for when a buffer becomes free in the future
PendingFreePacketCallback = callback;
return STATUS_OK;
}
DownstreamPacketTypeDef* Downstream_GetFreePacketImmediately(void)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return NULL;
}
//We are expecting a free buffer now
if (DownstreamPacket0.Busy == NOT_BUSY)
{
DownstreamPacket0.Busy = BUSY;
return &DownstreamPacket0;
}
if (DownstreamPacket1.Busy == NOT_BUSY)
{
DownstreamPacket1.Busy = BUSY;
return &DownstreamPacket1;
}
//Should not happen:
DOWNSTREAM_SPI_FREAKOUT;
return NULL;
}
//Used by Downstream state machine and USB host classes.
void Downstream_ReleasePacket(DownstreamPacketTypeDef* packetToRelease)
{
FreePacketCallbackTypeDef tempCallback;
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return;
}
if ((packetToRelease != &DownstreamPacket0) &&
(packetToRelease != &DownstreamPacket1))
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
if (PendingFreePacketCallback != NULL)
{
tempCallback = PendingFreePacketCallback; //In extreme situations, running this callback can trigger another request for a free packet,
PendingFreePacketCallback = NULL; //thereby causing GetFreePacket to freak out. So we need to clear the callback indicator first.
tempCallback(packetToRelease);
}
else
{
packetToRelease->Busy = NOT_BUSY;
}
}
//Used by Downstream state machine and USB classes.
//Ok to call when idle or transmitting.
//Not OK to call when receiving or awaiting reception.
StatusTypeDef Downstream_ReceivePacket(SpiPacketReceivedCallbackTypeDef callback)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return STATUS_ERROR;
}
if ((DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT) ||
(DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT) ||
(ReceivePacketCallback != NULL))
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
ReceivePacketCallback = callback;
return Downstream_CheckPreparePacketReception();
}
//Internal use only
StatusTypeDef Downstream_CheckPreparePacketReception(void)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return STATUS_ERROR;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_IDLE)
{
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_SIZE_WAIT;
return Downstream_GetFreePacket(Downstream_PrepareReceivePacketSize);
}
return STATUS_OK;
}
//Internal use only
void Downstream_PrepareReceivePacketSize(DownstreamPacketTypeDef* freePacket)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return;
}
if (DownstreamInterfaceState != DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
CurrentWorkingPacket = freePacket;
CurrentWorkingPacket->Length16 = 0;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length16,
(uint8_t*)&CurrentWorkingPacket->Length16,
2) != HAL_OK) //We only need to read one word, but the peripheral library freaks out...
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
UPSTREAM_TX_REQUEST_ASSERT;
}
//Used by Downstream state machine and USB classes.
//Call when idle or transmitting.
//It doesn't make sense to call when receiving or awaiting reception.
StatusTypeDef Downstream_TransmitPacket(DownstreamPacketTypeDef* packetToWrite)
{
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return STATUS_ERROR;
}
//Sanity checks
if ((packetToWrite != &DownstreamPacket0) &&
(packetToWrite != &DownstreamPacket1))
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
if ((packetToWrite->Busy != BUSY) ||
(packetToWrite->Length16 < DOWNSTREAM_PACKET_LEN_MIN_16) ||
(packetToWrite->Length16 > DOWNSTREAM_PACKET_LEN_16))
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
if (NextTxPacket != NULL)
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
switch (DownstreamInterfaceState)
{
case DOWNSTREAM_INTERFACE_TX_SIZE_WAIT:
case DOWNSTREAM_INTERFACE_TX_PACKET_WAIT:
NextTxPacket = packetToWrite;
break;
case DOWNSTREAM_INTERFACE_IDLE:
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = packetToWrite;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length16,
(uint8_t*)&TemporaryIncomingPacketLength,
2) != HAL_OK) //We only need to write one word, but the peripheral library freaks out...
{
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
UPSTREAM_TX_REQUEST_ASSERT;
break;
default:
DOWNSTREAM_SPI_FREAKOUT;
return STATUS_ERROR;
}
return STATUS_OK;
}
//Do stuff at main loop priority after SPI transaction is complete
void Downstream_SPIProcess(void)
{
SpiPacketReceivedCallbackTypeDef tempPacketCallback;
if (SpiInterruptCompleted == 0)
{
return;
}
SpiInterruptCompleted = 0;
if (DownstreamInterfaceState >= DOWNSTREAM_INTERFACE_ERROR)
{
return;
}
//Finished transmitting packet size
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_TX_SIZE_WAIT)
{
if ((uint16_t)TemporaryIncomingPacketLength != 0)
{
//Currently we just freak out if Upstream sends us an unexpected command.
//Theoretically we could reset our downstream state machine and accept the new command...
DOWNSTREAM_SPI_FREAKOUT;
return;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_PACKET_WAIT;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
&CurrentWorkingPacket->CommandClass,
((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
UPSTREAM_TX_REQUEST_ASSERT;
return;
}
//Finished transmitting packet body
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_TX_PACKET_WAIT)
{
Downstream_ReleasePacket(CurrentWorkingPacket);
if (NextTxPacket != NULL)
{
//NextTxPacket has already passed the checks in Downstream_TransmitPacket.
//So we just need to pass it to HAL_SPI_Transmit_DMA.
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_TX_SIZE_WAIT;
CurrentWorkingPacket = NextTxPacket;
NextTxPacket = NULL;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
(uint8_t*)&CurrentWorkingPacket->Length16,
(uint8_t*)&TemporaryIncomingPacketLength,
2) != HAL_OK) //We only need to write one word, but the peripheral library freaks out...
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
UPSTREAM_TX_REQUEST_ASSERT;
return;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback != NULL)
{
Downstream_CheckPreparePacketReception();
}
return;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_SIZE_WAIT)
{
if ((CurrentWorkingPacket->Length16 < DOWNSTREAM_PACKET_LEN_MIN_16) ||
(CurrentWorkingPacket->Length16 > DOWNSTREAM_PACKET_LEN_16))
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_RX_PACKET_WAIT;
if (HAL_SPI_TransmitReceive_DMA(&Hspi1,
&CurrentWorkingPacket->CommandClass,
&CurrentWorkingPacket->CommandClass,
((CurrentWorkingPacket->Length16 < 2) ? 2 : CurrentWorkingPacket->Length16)) != HAL_OK)
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
UPSTREAM_TX_REQUEST_ASSERT;
return;
}
if (DownstreamInterfaceState == DOWNSTREAM_INTERFACE_RX_PACKET_WAIT)
{
DownstreamInterfaceState = DOWNSTREAM_INTERFACE_IDLE;
if (ReceivePacketCallback == NULL)
{
DOWNSTREAM_SPI_FREAKOUT;
return;
}
//Packet processor may want to receive another packet immediately,
//so clear ReceivePacketCallback before the call.
//It is the callback's responsibility to release the packet buffer we are passing to it!
tempPacketCallback = ReceivePacketCallback;
ReceivePacketCallback = NULL;
tempPacketCallback(CurrentWorkingPacket);
return;
}
//case default:
DOWNSTREAM_SPI_FREAKOUT;
}
//Called at the end of the SPI TxRx DMA transfer,
//at DMA2 interrupt priority. Assume *hspi points to our hspi1.
//We use TxRx to send our reply packet to check if Upstream was trying
//to send us a packet at the same time.
//We also TxRx our packet body because the SPI silicon is buggy at the end of
//a transmit-only DMA transfer with CRC! (it does not clear RXNE flag on request)
void DMA_SPI_TxRxCpltCallback(void)
{
UPSTREAM_TX_REQUEST_DEASSERT;
SpiInterruptCompleted = 1;
}
//Something bad happened! Possibly CRC error...
/*void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
DOWNSTREAM_SPI_FREAKOUT;
}*/

@ -0,0 +1,23 @@
/*
* interrupts.c
*
* Created on: 23 окт. 2021 г.
* Author: ivan
*/
#include "interrupts.h"
#include "downstream_spi.h"
/* DMA0_Channel0 handle function */
//receive
void DMA0_Channel1_IRQHandler(void){
if(dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)){
DMA_SPI_TxRxCpltCallback();
dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_G);
}
}
//transmit
void DMA0_Channel2_IRQHandler(void){
}

@ -36,25 +36,27 @@ OF SUCH DAMAGE.
#include "drv_usb_core.h" #include "drv_usb_core.h"
#include "usbh_usr.h" #include "usbh_usr.h"
#include "usbh_msc_core.h" #include "usbh_msc_core.h"
#include "gd32vf103v_eval.h"
#include "usb_host.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
usb_core_driver usbh_msc_core; /*usb_core_driver usbh_msc_core;
void Downstream_HostUserCallback(usbh_host *phost, uint8_t id){
//dummy
return;
}
usbh_host usb_host = { usbh_host usb_host = {
.class_cb = &usbh_msc_cb, .class_cb = &usbh_msc_cb,
.usr_cb = &user_callback_funs, .usr_cb = &user_callback_funs,
.pUser=&Downstream_HostUserCallback
}; };
usbh_host hUsbHostFS; usbh_host hUsbHostFS;*/
void Downstream_HostUserCallback(usbh_host *phost, uint8_t id){
//dummy
return;
}
/** /**
* @brief Main routine for HID mouse / keyboard class application * @brief Main routine for HID mouse / keyboard class application
@ -68,20 +70,22 @@ int main(void)
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL2_PRIO2); eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL2_PRIO2);
usb_rcu_config(); // usb_rcu_config();
usb_timer_init(); // usb_timer_init();
/* configure GPIO pin used for switching VBUS power and charge pump I/O */ /* configure GPIO pin used for switching VBUS power and charge pump I/O */
// usb_vbus_config(); // usb_vbus_config();
usbh_init (&usbh_msc_core, USB_CORE_ENUM_FS, &usb_host,Downstream_HostUserCallback); // usbh_init (&usbh_msc_core, USB_CORE_ENUM_FS, &usb_host);
/* enable interrupts */ /* enable interrupts */
usb_intr_config(); // usb_intr_config();
USB_Host_Init();
while (1) { while (1) {
/* Host state handler */ /* Host state handler */
usbh_core_task (&usbh_msc_core, &usb_host); // usbh_core_task (&usbh_msc_core, &usb_host);
USB_Host_Process();
} }
} }

@ -0,0 +1,36 @@
/*
* usb_host.c
*
* Created on: 23 окт. 2021 г.
* Author: ivan
*/
#include "drv_usb_hw.h"
#include "drv_usb_core.h"
#include "usbh_usr.h"
#include "usbh_msc_core.h"
#include "gd32vf103v_eval.h"
#include "downstream_statemachine.h"
usb_core_driver usbh_msc_core;
usbh_host usb_host = {
.class_cb = &usbh_msc_cb,
.usr_cb = &user_callback_funs,
.pUser=&Downstream_HostUserCallback
};
usbh_host hUsbHostFS;
void USB_Host_Init(void){
usb_rcu_config();
usb_timer_init();
usbh_init(&usbh_msc_core, USB_CORE_ENUM_FS, &usb_host);
usb_intr_config();
}
void USB_Host_Process(void){
usbh_core_task (&usbh_msc_core, &usb_host);
}
void USB_Host_Disconnect(void){
usbh_deinit(&usbh_msc_core, &usb_host);
}
Loading…
Cancel
Save