diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 0e529b3462be..d80d5f28894f 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -1767,6 +1767,14 @@
*/
//#define SDSUPPORT
+/**
+ * USB HOST MSC
+ *
+ * USB Flash mounted in MCU USB OTG Host port
+ * you need uncomment both SDSUPPORT and following option at the same time or it won't work.
+ */
+//#define USB_HOST_MSC_FLASH_SUPPORT
+
/**
* SD CARD: SPI SPEED
*
diff --git a/Marlin/src/HAL/STM32/inc/SanityCheck.h b/Marlin/src/HAL/STM32/inc/SanityCheck.h
index c51fecc7bdb9..e747433ed570 100644
--- a/Marlin/src/HAL/STM32/inc/SanityCheck.h
+++ b/Marlin/src/HAL/STM32/inc/SanityCheck.h
@@ -46,6 +46,10 @@
#error "FLASH_EEPROM_LEVELING is currently only supported on STM32F4 hardware."
#endif
+#if !defined(STM32F4xx) && ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+ #error "For now USB host MSC is only supported on STM32F4."
+#endif
+
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on this platform."
#elif ENABLED(SERIAL_STATS_DROPPED_RX)
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h
new file mode 100644
index 000000000000..55aeab65ea0b
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h
@@ -0,0 +1,216 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.h
+ * @author MCD Application Team
+ * @brief This file contains all the prototypes for the usbh_msc.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_H
+#define __USBH_MSC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../Core/Inc/usbh_core.h"
+#include "usbh_msc_bot.h"
+#include "usbh_msc_scsi.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_CORE
+ * @brief This file is the Header file for usbh_msc.c
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ MSC_INIT = 0,
+ MSC_IDLE,
+ MSC_TEST_UNIT_READY,
+ MSC_READ_CAPACITY10,
+ MSC_READ_INQUIRY,
+ MSC_REQUEST_SENSE,
+ MSC_READ,
+ MSC_WRITE,
+ MSC_UNRECOVERED_ERROR,
+ MSC_PERIODIC_CHECK,
+}
+MSC_StateTypeDef;
+
+typedef enum
+{
+ MSC_OK,
+ MSC_NOT_READY,
+ MSC_ERROR,
+
+}
+MSC_ErrorTypeDef;
+
+typedef enum
+{
+ MSC_REQ_IDLE = 0,
+ MSC_REQ_RESET,
+ MSC_REQ_GET_MAX_LUN,
+ MSC_REQ_ERROR,
+}
+MSC_ReqStateTypeDef;
+
+#ifndef MAX_SUPPORTED_LUN
+#define MAX_SUPPORTED_LUN 2U
+#endif
+
+
+/* Structure for LUN */
+typedef struct
+{
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ USBH_StatusTypeDef prev_ready_state;
+ SCSI_CapacityTypeDef capacity;
+ SCSI_SenseTypeDef sense;
+ SCSI_StdInquiryDataTypeDef inquiry;
+ uint8_t state_changed;
+
+}
+MSC_LUNTypeDef;
+
+/* Structure for MSC process */
+typedef struct _MSC_Process
+{
+ uint8_t max_lun;
+ uint8_t Reserved[3];
+ uint8_t InPipe;
+ uint8_t OutPipe;
+ uint8_t OutEp;
+ uint8_t InEp;
+ uint16_t OutEpSize;
+ uint16_t InEpSize;
+ MSC_StateTypeDef state;
+ MSC_ErrorTypeDef error;
+ MSC_ReqStateTypeDef req_state;
+ MSC_ReqStateTypeDef prev_req_state;
+ BOT_HandleTypeDef hbot;
+ MSC_LUNTypeDef unit[MAX_SUPPORTED_LUN];
+ uint16_t current_lun;
+ uint16_t rw_lun;
+ uint32_t timer;
+}
+MSC_HandleTypeDef;
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Defines
+ * @{
+ */
+
+#define USB_REQ_BOT_RESET 0xFFU
+#define USB_REQ_GET_MAX_LUN 0xFEU
+
+
+/* MSC Class Codes */
+#define USB_MSC_CLASS 0x08U
+
+/* Interface Descriptor field values for HID Boot Protocol */
+#define MSC_BOT 0x50U
+#define MSC_TRANSPARENT 0x06U
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+extern USBH_ClassTypeDef USBH_msc;
+#define USBH_MSC_CLASS &USBH_msc
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+uint8_t USBH_MSC_IsReady(USBH_HandleTypeDef *phost);
+uint8_t USBH_MSC_GetMaxLUN(USBH_HandleTypeDef *phost);
+uint8_t USBH_MSC_UnitIsReady(USBH_HandleTypeDef *phost, uint8_t lun);
+
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun,
+ MSC_LUNTypeDef *info);
+
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost, uint8_t lun,
+ uint32_t address, uint8_t *pbuf, uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost, uint8_t lun,
+ uint32_t address, uint8_t *pbuf, uint32_t length);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h
new file mode 100644
index 000000000000..731c6cfbfc28
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_bot.h
@@ -0,0 +1,232 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_msc_bot.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_BOT_H
+#define __USBH_MSC_BOT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../Core/Inc/usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_BOT
+ * @brief This file is the Header file for usbh_msc_bot.c
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ BOT_OK = 0,
+ BOT_FAIL = 1,
+ BOT_PHASE_ERROR = 2,
+ BOT_BUSY = 3
+}
+BOT_StatusTypeDef;
+
+typedef enum
+{
+ BOT_CMD_IDLE = 0,
+ BOT_CMD_SEND,
+ BOT_CMD_WAIT,
+}
+BOT_CMDStateTypeDef;
+
+/* CSW Status Definitions */
+typedef enum
+{
+
+ BOT_CSW_CMD_PASSED = 0x00,
+ BOT_CSW_CMD_FAILED = 0x01,
+ BOT_CSW_PHASE_ERROR = 0x02,
+}
+BOT_CSWStatusTypeDef;
+
+typedef enum
+{
+ BOT_SEND_CBW = 1,
+ BOT_SEND_CBW_WAIT,
+ BOT_DATA_IN,
+ BOT_DATA_IN_WAIT,
+ BOT_DATA_OUT,
+ BOT_DATA_OUT_WAIT,
+ BOT_RECEIVE_CSW,
+ BOT_RECEIVE_CSW_WAIT,
+ BOT_ERROR_IN,
+ BOT_ERROR_OUT,
+ BOT_UNRECOVERED_ERROR
+}
+BOT_StateTypeDef;
+
+typedef union
+{
+ struct __CBW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataTransferLength;
+ uint8_t Flags;
+ uint8_t LUN;
+ uint8_t CBLength;
+ uint8_t CB[16];
+ } field;
+ uint8_t data[31];
+}
+BOT_CBWTypeDef;
+
+typedef union
+{
+ struct __CSW
+ {
+ uint32_t Signature;
+ uint32_t Tag;
+ uint32_t DataResidue;
+ uint8_t Status;
+ } field;
+ uint8_t data[13];
+}
+BOT_CSWTypeDef;
+
+typedef struct
+{
+ uint32_t data[16];
+ BOT_StateTypeDef state;
+ BOT_StateTypeDef prev_state;
+ BOT_CMDStateTypeDef cmd_state;
+ BOT_CBWTypeDef cbw;
+ uint8_t Reserved1;
+ BOT_CSWTypeDef csw;
+ uint8_t Reserved2[3];
+ uint8_t *pbuf;
+}
+BOT_HandleTypeDef;
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Defines
+ * @{
+ */
+#define BOT_CBW_SIGNATURE 0x43425355U
+#define BOT_CBW_TAG 0x20304050U
+#define BOT_CSW_SIGNATURE 0x53425355U
+#define BOT_CBW_LENGTH 31U
+#define BOT_CSW_LENGTH 13U
+
+
+
+#define BOT_SEND_CSW_DISABLE 0U
+#define BOT_SEND_CSW_ENABLE 1U
+
+#define BOT_DIR_IN 0U
+#define BOT_DIR_OUT 1U
+#define BOT_DIR_BOTH 2U
+
+#define BOT_PAGE_LENGTH 512U
+
+
+#define BOT_CBW_CB_LENGTH 16U
+
+
+#define MAX_BULK_STALL_COUNT_LIMIT 0x04U /* If STALL is seen on Bulk
+ Endpoint continuously, this means
+ that device and Host has phase error
+ Hence a Reset is needed */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_BOT_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun);
+
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_MSC_BOT_Process(USBH_HandleTypeDef *phost, uint8_t lun);
+USBH_StatusTypeDef USBH_MSC_BOT_Error(USBH_HandleTypeDef *phost, uint8_t lun);
+
+
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_BOT_H__ */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h
new file mode 100644
index 000000000000..3f3e611df56d
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc_scsi.h
@@ -0,0 +1,218 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_msc_scsi.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_MSC_SCSI_H
+#define __USBH_MSC_SCSI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../Core/Inc/usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file is the Header file for usbh_msc_scsi.c
+ * @{
+ */
+
+
+/* Capacity data */
+typedef struct
+{
+ uint32_t block_nbr;
+ uint16_t block_size;
+} SCSI_CapacityTypeDef;
+
+
+/* Sense data */
+typedef struct
+{
+ uint8_t key;
+ uint8_t asc;
+ uint8_t ascq;
+} SCSI_SenseTypeDef;
+
+/* INQUIRY data */
+typedef struct
+{
+ uint8_t PeripheralQualifier;
+ uint8_t DeviceType;
+ uint8_t RemovableMedia;
+ uint8_t vendor_id[9];
+ uint8_t product_id[17];
+ uint8_t revision_id[5];
+} SCSI_StdInquiryDataTypeDef;
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define OPCODE_TEST_UNIT_READY 0x00U
+#define OPCODE_READ_CAPACITY10 0x25U
+#define OPCODE_READ10 0x28U
+#define OPCODE_WRITE10 0x2AU
+#define OPCODE_REQUEST_SENSE 0x03U
+#define OPCODE_INQUIRY 0x12U
+
+#define DATA_LEN_MODE_TEST_UNIT_READY 0U
+#define DATA_LEN_READ_CAPACITY10 8U
+#define DATA_LEN_INQUIRY 36U
+#define DATA_LEN_REQUEST_SENSE 14U
+
+#define CBW_CB_LENGTH 16U
+#define CBW_LENGTH 10U
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_SENSE_KEY_NO_SENSE 0x00U
+#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01U
+#define SCSI_SENSE_KEY_NOT_READY 0x02U
+#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03U
+#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04U
+#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05U
+#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06U
+#define SCSI_SENSE_KEY_DATA_PROTECT 0x07U
+#define SCSI_SENSE_KEY_BLANK_CHECK 0x08U
+#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09U
+#define SCSI_SENSE_KEY_COPY_ABORTED 0x0AU
+#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0BU
+#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0DU
+#define SCSI_SENSE_KEY_MISCOMPARE 0x0EU
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
+#define SCSI_ASC_LOGICAL_UNIT_NOT_READY 0x04
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_WRITE_PROTECTED 0x27
+#define SCSI_ASC_FORMAT_ERROR 0x31
+#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20
+#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Defines
+ * @{
+ */
+#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
+#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
+#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup _Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady(USBH_HandleTypeDef *phost,
+ uint8_t lun);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length);
+
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_MSC_SCSI_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.cpp
new file mode 100644
index 000000000000..90f1fa05ea01
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.cpp
@@ -0,0 +1,866 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc.c
+ * @author MCD Application Team
+ * @brief This file implements the MSC class driver functions
+ * ===================================================================
+ * MSC Class Description
+ * ===================================================================
+ * This module manages the MSC class V1.0 following the "Universal
+ * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0
+ * Sep. 31, 1999".
+ * This driver implements the following aspects of the specification:
+ * - Bulk-Only Transport protocol
+ * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3))
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c"
+- "stm32xxxxx_{eval}{discovery}_sdram.c"
+EndBSPDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_msc.h"
+#include "../Inc/usbh_msc_bot.h"
+#include "../Inc/usbh_msc_scsi.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_CORE
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes
+ * @{
+ */
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost);
+
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun);
+
+USBH_ClassTypeDef USBH_msc =
+{
+ "MSC",
+ USB_MSC_CLASS,
+ USBH_MSC_InterfaceInit,
+ USBH_MSC_InterfaceDeInit,
+ USBH_MSC_ClassRequest,
+ USBH_MSC_Process,
+ USBH_MSC_SOFProcess,
+ NULL,
+};
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_CORE_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_InterfaceInit
+ * The function init the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_InterfaceInit(USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef status;
+ uint8_t interface;
+ MSC_HandleTypeDef *MSC_Handle;
+
+ interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, MSC_TRANSPARENT, MSC_BOT);
+
+ if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) /* Not Valid Interface */
+ {
+ USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
+ return USBH_FAIL;
+ }
+
+ status = USBH_SelectInterface(phost, interface);
+
+ if (status != USBH_OK)
+ {
+ return USBH_FAIL;
+ }
+
+ phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc(sizeof(MSC_HandleTypeDef));
+ MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if (MSC_Handle == NULL)
+ {
+ USBH_DbgLog("Cannot allocate memory for MSC Handle");
+ return USBH_FAIL;
+ }
+
+ /* Initialize msc handler */
+ USBH_memset(MSC_Handle, 0, sizeof(MSC_HandleTypeDef));
+
+ if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
+ }
+
+ if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80U)
+ {
+ MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
+ }
+ else
+ {
+ MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress);
+ MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
+ }
+
+ MSC_Handle->state = MSC_INIT;
+ MSC_Handle->error = MSC_OK;
+ MSC_Handle->req_state = MSC_REQ_IDLE;
+ MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp);
+ MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp);
+
+ USBH_MSC_BOT_Init(phost);
+
+ /* Open the new channels */
+ USBH_OpenPipe(phost, MSC_Handle->OutPipe, MSC_Handle->OutEp,
+ phost->device.address, phost->device.speed,
+ USB_EP_TYPE_BULK, MSC_Handle->OutEpSize);
+
+ USBH_OpenPipe(phost, MSC_Handle->InPipe, MSC_Handle->InEp,
+ phost->device.address, phost->device.speed, USB_EP_TYPE_BULK,
+ MSC_Handle->InEpSize);
+
+ USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0U);
+ USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 0U);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_InterfaceDeInit
+ * The function DeInit the Pipes used for the MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if (MSC_Handle->OutPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->OutPipe);
+ USBH_FreePipe(phost, MSC_Handle->OutPipe);
+ MSC_Handle->OutPipe = 0U; /* Reset the Channel as Free */
+ }
+
+ if (MSC_Handle->InPipe)
+ {
+ USBH_ClosePipe(phost, MSC_Handle->InPipe);
+ USBH_FreePipe(phost, MSC_Handle->InPipe);
+ MSC_Handle->InPipe = 0U; /* Reset the Channel as Free */
+ }
+
+ if (phost->pActiveClass->pData)
+ {
+ USBH_free(phost->pActiveClass->pData);
+ phost->pActiveClass->pData = 0U;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_ClassRequest
+ * The function is responsible for handling Standard requests
+ * for MSC class.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ uint8_t i;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->req_state)
+ {
+ case MSC_REQ_IDLE:
+ case MSC_REQ_GET_MAX_LUN:
+ /* Issue GetMaxLUN request */
+ status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, &MSC_Handle->max_lun);
+
+ /* When devices do not support the GetMaxLun request, this should
+ be considred as only one logical unit is supported */
+ if (status == USBH_NOT_SUPPORTED)
+ {
+ MSC_Handle->max_lun = 0U;
+ status = USBH_OK;
+ }
+
+ if (status == USBH_OK)
+ {
+ MSC_Handle->max_lun = (MSC_Handle->max_lun > MAX_SUPPORTED_LUN) ? MAX_SUPPORTED_LUN : (MSC_Handle->max_lun + 1U);
+ USBH_UsrLog("Number of supported LUN: %d", MSC_Handle->max_lun);
+
+ for (i = 0U; i < MSC_Handle->max_lun; i++)
+ {
+ MSC_Handle->unit[i].prev_ready_state = USBH_FAIL;
+ MSC_Handle->unit[i].state_changed = 0U;
+ }
+ }
+ break;
+
+ case MSC_REQ_ERROR:
+ /* a Clear Feature should be issued here */
+ if (USBH_ClrFeature(phost, 0x00U) == USBH_OK)
+ {
+ MSC_Handle->req_state = MSC_Handle->prev_req_state;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_Process
+ * The function is for managing state machine for MSC data transfers
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY;
+ USBH_StatusTypeDef ready_status = USBH_BUSY;
+
+ switch (MSC_Handle->state)
+ {
+ case MSC_INIT:
+
+ if (MSC_Handle->current_lun < MSC_Handle->max_lun)
+ {
+
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[MSC_Handle->current_lun].state)
+ {
+ case MSC_INIT:
+ USBH_UsrLog("LUN #%d: ", MSC_Handle->current_lun);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY;
+ MSC_Handle->timer = phost->Timer;
+ break;
+
+ case MSC_READ_INQUIRY:
+ scsi_status = USBH_MSC_SCSI_Inquiry(phost, (uint8_t)MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry);
+
+ if (scsi_status == USBH_OK)
+ {
+ USBH_UsrLog("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id);
+ USBH_UsrLog("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id);
+ USBH_UsrLog("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ }
+ if (scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ }
+ break;
+
+ case MSC_TEST_UNIT_READY:
+ ready_status = USBH_MSC_SCSI_TestUnitReady(phost, (uint8_t)MSC_Handle->current_lun);
+
+ if (ready_status == USBH_OK)
+ {
+ if (MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1U;
+ USBH_UsrLog("MSC Device ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0U;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK;
+ }
+ if (ready_status == USBH_FAIL)
+ {
+ /* Media not ready, so try to check again during 10s */
+ if (MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1U;
+ USBH_UsrLog("MSC Device NOT ready");
+ }
+ else
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0U;
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY;
+ MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL;
+ }
+ else
+ {
+ if (ready_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ }
+ break;
+
+ case MSC_READ_CAPACITY10:
+ scsi_status = USBH_MSC_SCSI_ReadCapacity(phost, (uint8_t)MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ;
+
+ if (scsi_status == USBH_OK)
+ {
+ if (MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1U)
+ {
+ USBH_UsrLog("MSC Device capacity : %lu Bytes", \
+ (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
+ USBH_UsrLog("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr));
+ USBH_UsrLog("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size));
+ }
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK;
+ MSC_Handle->current_lun++;
+ }
+ else if (scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE;
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ }
+ break;
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, (uint8_t)MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense);
+
+ if (scsi_status == USBH_OK)
+ {
+ if ((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) ||
+ (MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY))
+ {
+
+ if ((phost->Timer - MSC_Handle->timer) < 10000U)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY;
+ break;
+ }
+ }
+
+ USBH_UsrLog("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key);
+ USBH_UsrLog("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc);
+ USBH_UsrLog("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq);
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->current_lun++;
+ }
+ if (scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog("MSC Device NOT ready");
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR;
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE;
+ MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR;
+ }
+ }
+ break;
+
+ case MSC_UNRECOVERED_ERROR:
+ MSC_Handle->current_lun++;
+ break;
+
+ default:
+ break;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ MSC_Handle->current_lun = 0U;
+ MSC_Handle->state = MSC_IDLE;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
+ }
+ break;
+
+ case MSC_IDLE:
+ error = USBH_OK;
+ break;
+
+ default:
+ break;
+ }
+ return error;
+}
+
+
+/**
+ * @brief USBH_MSC_SOFProcess
+ * The function is for SOF state
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(phost);
+
+ return USBH_OK;
+}
+/**
+ * @brief USBH_MSC_RdWrProcess
+ * The function is for managing state machine for MSC I/O Process
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ USBH_StatusTypeDef scsi_status = USBH_BUSY ;
+
+ /* Switch MSC REQ state machine */
+ switch (MSC_Handle->unit[lun].state)
+ {
+
+ case MSC_READ:
+ scsi_status = USBH_MSC_SCSI_Read(phost, lun, 0U, NULL, 0U);
+
+ if (scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if (scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case MSC_WRITE:
+ scsi_status = USBH_MSC_SCSI_Write(phost, lun, 0U, NULL, 0U);
+
+ if (scsi_status == USBH_OK)
+ {
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ error = USBH_OK;
+ }
+ else if (scsi_status == USBH_FAIL)
+ {
+ MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE;
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case MSC_REQUEST_SENSE:
+ scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense);
+
+ if (scsi_status == USBH_OK)
+ {
+ USBH_UsrLog("Sense Key : %x", MSC_Handle->unit[lun].sense.key);
+ USBH_UsrLog("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc);
+ USBH_UsrLog("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq);
+ MSC_Handle->unit[lun].state = MSC_IDLE;
+ MSC_Handle->unit[lun].error = MSC_ERROR;
+
+ error = USBH_FAIL;
+ }
+ if (scsi_status == USBH_FAIL)
+ {
+ USBH_UsrLog("MSC Device NOT ready");
+ }
+ else
+ {
+ if (scsi_status == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR;
+ error = USBH_FAIL;
+ }
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ default:
+ break;
+
+ }
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_IsReady
+ * The function check if the MSC function is ready
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+uint8_t USBH_MSC_IsReady(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ uint8_t res;
+
+ if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE))
+ {
+ res = 1U;
+ }
+ else
+ {
+ res = 0U;
+ }
+
+ return res;
+}
+
+/**
+ * @brief USBH_MSC_GetMaxLUN
+ * The function return the Max LUN supported
+ * @param phost: Host handle
+ * @retval logical Unit Number supported
+ */
+uint8_t USBH_MSC_GetMaxLUN(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE))
+ {
+ return (uint8_t)MSC_Handle->max_lun;
+ }
+
+ return 0xFFU;
+}
+
+/**
+ * @brief USBH_MSC_UnitIsReady
+ * The function check whether a LUN is ready
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval Lun status (0: not ready / 1: ready)
+ */
+uint8_t USBH_MSC_UnitIsReady(USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ uint8_t res;
+
+ if ((phost->gState == HOST_CLASS) && (MSC_Handle->unit[lun].error == MSC_OK))
+ {
+ res = 1U;
+ }
+ else
+ {
+ res = 0U;
+ }
+
+ return res;
+}
+
+/**
+ * @brief USBH_MSC_GetLUNInfo
+ * The function return a LUN information
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ if (phost->gState == HOST_CLASS)
+ {
+ USBH_memcpy(info, &MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef));
+ return USBH_OK;
+ }
+ else
+ {
+ return USBH_FAIL;
+ }
+}
+
+/**
+ * @brief USBH_MSC_Read
+ * The function performs a Read operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ uint32_t timeout;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0U) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_READ;
+ MSC_Handle->unit[lun].state = MSC_READ;
+ MSC_Handle->rw_lun = lun;
+
+ USBH_MSC_SCSI_Read(phost, lun, address, pbuf, length);
+
+ timeout = phost->Timer;
+
+ while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
+ {
+ if (((phost->Timer - timeout) > (10000U * length)) || (phost->device.is_connected == 0U))
+ {
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_FAIL;
+ }
+ }
+ MSC_Handle->state = MSC_IDLE;
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_MSC_Write
+ * The function performs a Write operation
+ * @param phost: Host handle
+ * @param lun: logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ uint32_t timeout;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ if ((phost->device.is_connected == 0U) ||
+ (phost->gState != HOST_CLASS) ||
+ (MSC_Handle->unit[lun].state != MSC_IDLE))
+ {
+ return USBH_FAIL;
+ }
+
+ MSC_Handle->state = MSC_WRITE;
+ MSC_Handle->unit[lun].state = MSC_WRITE;
+ MSC_Handle->rw_lun = lun;
+
+ USBH_MSC_SCSI_Write(phost, lun, address, pbuf, length);
+
+ timeout = phost->Timer;
+ while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY)
+ {
+ if (((phost->Timer - timeout) > (10000U * length)) || (phost->device.is_connected == 0U))
+ {
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_FAIL;
+ }
+ }
+ MSC_Handle->state = MSC_IDLE;
+ return USBH_OK;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.cpp
new file mode 100644
index 000000000000..42bef03b14dc
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.cpp
@@ -0,0 +1,706 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_bot.c
+ * @author MCD Application Team
+ * @brief This file includes the BOT protocol related functions
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c"
+- "stm32xxxxx_{eval}{discovery}_sdram.c"
+EndBSPDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_msc_bot.h"
+#include "../Inc/usbh_msc.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_CLASS
+* @{
+*/
+
+/** @addtogroup USBH_MSC_CLASS
+* @{
+*/
+
+/** @defgroup USBH_MSC_BOT
+* @brief This file includes the mass storage related functions
+* @{
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MSC_BOT_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_MSC_BOT_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_Variables
+* @{
+*/
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir);
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost);
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Exported_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_MSC_BOT_Private_Functions
+* @{
+*/
+
+/**
+ * @brief USBH_MSC_BOT_REQ_Reset
+ * The function the MSC BOT Reset request.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost)
+{
+
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS
+ | USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET;
+ phost->Control.setup.b.wValue.w = 0U;
+ phost->Control.setup.b.wIndex.w = 0U;
+ phost->Control.setup.b.wLength.w = 0U;
+
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+/**
+ * @brief USBH_MSC_BOT_REQ_GetMaxLUN
+ * The function the MSC BOT GetMaxLUN request.
+ * @param phost: Host handle
+ * @param Maxlun: pointer to Maxlun variable
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun)
+{
+ phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS
+ | USB_REQ_RECIPIENT_INTERFACE;
+
+ phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
+ phost->Control.setup.b.wValue.w = 0U;
+ phost->Control.setup.b.wIndex.w = 0U;
+ phost->Control.setup.b.wLength.w = 1U;
+
+ return USBH_CtlReq(phost, Maxlun, 1U);
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Init
+ * The function Initializes the BOT protocol.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost)
+{
+
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ MSC_Handle->hbot.cbw.field.Signature = BOT_CBW_SIGNATURE;
+ MSC_Handle->hbot.cbw.field.Tag = BOT_CBW_TAG;
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+
+ return USBH_OK;
+}
+
+
+
+/**
+ * @brief USBH_MSC_BOT_Process
+ * The function handle the BOT protocol.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_BOT_Process(USBH_HandleTypeDef *phost, uint8_t lun)
+{
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_StatusTypeDef error = USBH_BUSY;
+ BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ uint8_t toggle = 0U;
+
+ switch (MSC_Handle->hbot.state)
+ {
+ case BOT_SEND_CBW:
+ MSC_Handle->hbot.cbw.field.LUN = lun;
+ MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT;
+ USBH_BulkSendData(phost, MSC_Handle->hbot.cbw.data,
+ BOT_CBW_LENGTH, MSC_Handle->OutPipe, 1U);
+
+ break;
+
+ case BOT_SEND_CBW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength != 0U)
+ {
+ /* If there is Data Transfer Stage */
+ if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H)
+ {
+ /* Data Direction is IN */
+ MSC_Handle->hbot.state = BOT_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+ }
+ }
+
+ else
+ {
+ /* If there is NO Data Transfer Stage */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Re-send CBW */
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if (URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case BOT_DATA_IN:
+ /* Send first packet */
+ USBH_BulkReceiveData(phost, MSC_Handle->hbot.pbuf,
+ MSC_Handle->InEpSize, MSC_Handle->InPipe);
+
+ MSC_Handle->hbot.state = BOT_DATA_IN_WAIT;
+
+ break;
+
+ case BOT_DATA_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ /* Adjust Data pointer and data length */
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->InEpSize)
+ {
+ MSC_Handle->hbot.pbuf += MSC_Handle->InEpSize;
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->InEpSize;
+ }
+ else
+ {
+ MSC_Handle->hbot.cbw.field.DataTransferLength = 0U;
+ }
+
+ /* More Data To be Received */
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength > 0U)
+ {
+ /* Send next packet */
+ USBH_BulkReceiveData(phost, MSC_Handle->hbot.pbuf,
+ MSC_Handle->InEpSize, MSC_Handle->InPipe);
+ }
+ else
+ {
+ /* If value was 0, and successful transfer, then change the state */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ /* This is Data IN Stage STALL Condition */
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.2 Host expects to receive data from the device
+ 3. On a STALL condition receiving data, then:
+ The host shall accept the data received.
+ The host shall clear the Bulk-In pipe.
+ 4. The host shall attempt to receive a CSW.*/
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ }
+ break;
+
+ case BOT_DATA_OUT:
+
+ USBH_BulkSendData(phost, MSC_Handle->hbot.pbuf,
+ MSC_Handle->OutEpSize, MSC_Handle->OutPipe, 1U);
+
+ MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT;
+ break;
+
+ case BOT_DATA_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ /* Adjust Data pointer and data length */
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->OutEpSize)
+ {
+ MSC_Handle->hbot.pbuf += MSC_Handle->OutEpSize;
+ MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->OutEpSize;
+ }
+ else
+ {
+ MSC_Handle->hbot.cbw.field.DataTransferLength = 0U;
+ }
+
+ /* More Data To be Sent */
+ if (MSC_Handle->hbot.cbw.field.DataTransferLength > 0U)
+ {
+ USBH_BulkSendData(phost, MSC_Handle->hbot.pbuf,
+ MSC_Handle->OutEpSize, MSC_Handle->OutPipe, 1U);
+ }
+ else
+ {
+ /* If value was 0, and successful transfer, then change the state */
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Resend same data */
+ MSC_Handle->hbot.state = BOT_DATA_OUT;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_OUT;
+
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ 6.7.3 Ho - Host expects to send data to the device
+ 3. On a STALL condition sending data, then:
+ " The host shall clear the Bulk-Out pipe.
+ 4. The host shall attempt to receive a CSW.
+ */
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ }
+ break;
+
+ case BOT_RECEIVE_CSW:
+
+ USBH_BulkReceiveData(phost, MSC_Handle->hbot.csw.data,
+ BOT_CSW_LENGTH, MSC_Handle->InPipe);
+
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT;
+ break;
+
+ case BOT_RECEIVE_CSW_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe);
+
+ /* Decode CSW */
+ if (URB_Status == USBH_URB_DONE)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_SEND;
+ CSW_Status = USBH_MSC_DecodeCSW(phost);
+
+ if (CSW_Status == BOT_CSW_CMD_PASSED)
+ {
+ status = USBH_OK;
+ }
+ else
+ {
+ status = USBH_FAIL;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_URB_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ }
+ break;
+
+ case BOT_ERROR_IN:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN);
+
+ if (error == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_RECEIVE_CSW;
+ }
+ else if (error == USBH_UNRECOVERED_ERROR)
+ {
+ /* This means that there is a STALL Error limit, Do Reset Recovery */
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ else
+ {
+ }
+ break;
+
+ case BOT_ERROR_OUT:
+ error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT);
+
+ if (error == USBH_OK)
+ {
+
+ toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe);
+ USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1U - toggle);
+ USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0U);
+ MSC_Handle->hbot.state = BOT_ERROR_IN;
+ }
+ else
+ {
+ if (error == USBH_UNRECOVERED_ERROR)
+ {
+ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR;
+ }
+ }
+ break;
+
+
+ case BOT_UNRECOVERED_ERROR:
+ status = USBH_MSC_BOT_REQ_Reset(phost);
+ if (status == USBH_OK)
+ {
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_BOT_Abort
+ * The function handle the BOT Abort process.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param dir: direction (0: out / 1 : in)
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(lun);
+
+ USBH_StatusTypeDef status = USBH_FAIL;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (dir)
+ {
+ case BOT_DIR_IN :
+ /* send ClrFeture on Bulk IN endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->InEp);
+
+ break;
+
+ case BOT_DIR_OUT :
+ /*send ClrFeature on Bulk OUT endpoint */
+ status = USBH_ClrFeature(phost, MSC_Handle->OutEp);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+/**
+ * @brief USBH_MSC_BOT_DecodeCSW
+ * This function decodes the CSW received by the device and updates the
+ * same to upper layer.
+ * @param phost: Host handle
+ * @retval USBH Status
+ * @notes
+ * Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ * 6.3.1 Valid CSW Conditions :
+ * The host shall consider the CSW valid when:
+ * 1. dCSWSignature is equal to 53425355h
+ * 2. the CSW is 13 (Dh) bytes in length,
+ * 3. dCSWTag matches the dCBWTag from the corresponding CBW.
+ */
+
+static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost)
+{
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+ BOT_CSWStatusTypeDef status = BOT_CSW_CMD_FAILED;
+
+ /*Checking if the transfer length is different than 13*/
+ if (USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != BOT_CSW_LENGTH)
+ {
+ /*(4) Hi > Dn (Host expects to receive data from the device,
+ Device intends to transfer no data)
+ (5) Hi > Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (9) Ho > Dn (Host expects to send data to the device,
+ Device intends to transfer no data)
+ (11) Ho > Do (Host expects to send data to the device,
+ Device intends to receive data from the host)*/
+
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ else
+ {
+ /* CSW length is Correct */
+
+ /* Check validity of the CSW Signature and CSWStatus */
+ if (MSC_Handle->hbot.csw.field.Signature == BOT_CSW_SIGNATURE)
+ {
+ /* Check Condition 1. dCSWSignature is equal to 53425355h */
+
+ if (MSC_Handle->hbot.csw.field.Tag == MSC_Handle->hbot.cbw.field.Tag)
+ {
+ /* Check Condition 3. dCSWTag matches the dCBWTag from the
+ corresponding CBW */
+
+ if (MSC_Handle->hbot.csw.field.Status == 0U)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+
+ Hn Host expects no data transfers
+ Hi Host expects to receive data from the device
+ Ho Host expects to send data to the device
+
+ Dn Device intends to transfer no data
+ Di Device intends to send data to the host
+ Do Device intends to receive data from the host
+
+ Section 6.7
+ (1) Hn = Dn (Host expects no data transfers,
+ Device intends to transfer no data)
+ (6) Hi = Di (Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (12) Ho = Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+
+ */
+
+ status = BOT_CSW_CMD_PASSED;
+ }
+ else if (MSC_Handle->hbot.csw.field.Status == 1U)
+ {
+ status = BOT_CSW_CMD_FAILED;
+ }
+
+ else if (MSC_Handle->hbot.csw.field.Status == 2U)
+ {
+ /* Refer to USB Mass-Storage Class : BOT (www.usb.org)
+ Section 6.7
+ (2) Hn < Di ( Host expects no data transfers,
+ Device intends to send data to the host)
+ (3) Hn < Do ( Host expects no data transfers,
+ Device intends to receive data from the host)
+ (7) Hi < Di ( Host expects to receive data from the device,
+ Device intends to send data to the host)
+ (8) Hi <> Do ( Host expects to receive data from the device,
+ Device intends to receive data from the host)
+ (10) Ho <> Di (Host expects to send data to the device,
+ Di Device intends to send data to the host)
+ (13) Ho < Do (Host expects to send data to the device,
+ Device intends to receive data from the host)
+ */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ else
+ {
+ }
+ } /* CSW Tag Matching is Checked */
+ } /* CSW Signature Correct Checking */
+ else
+ {
+ /* If the CSW Signature is not valid, We sall return the Phase Error to
+ Upper Layers for Reset Recovery */
+
+ status = BOT_CSW_PHASE_ERROR;
+ }
+ } /* CSW Length Check*/
+
+ return status;
+}
+
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.cpp
new file mode 100644
index 000000000000..373d43a5c9a6
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.cpp
@@ -0,0 +1,472 @@
+/**
+ ******************************************************************************
+ * @file usbh_msc_scsi.c
+ * @author MCD Application Team
+ * @brief This file implements the SCSI commands
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* BSPDependencies
+- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+- "stm32xxxxx_{eval}{discovery}_io.c"
+- "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c"
+- "stm32xxxxx_{eval}{discovery}_sdram.c"
+EndBSPDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_msc.h"
+#include "../Inc/usbh_msc_scsi.h"
+#include "../Inc/usbh_msc_bot.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_CLASS
+ * @{
+ */
+
+/** @addtogroup USBH_MSC_CLASS
+ * @{
+ */
+
+/** @defgroup USBH_MSC_SCSI
+ * @brief This file includes the mass storage related functions
+ * @{
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_MSC_SCSI_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_MSC_SCSI_Private_Functions
+ * @{
+ */
+
+
+/**
+ * @brief USBH_MSC_SCSI_TestUnitReady
+ * Issue TestUnitReady command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady(USBH_HandleTypeDef *phost,
+ uint8_t lun)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_TEST_UNIT_READY;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_ReadCapacity
+ * Issue Read Capacity command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the capacity structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_CapacityTypeDef *capacity)
+{
+ USBH_StatusTypeDef error = USBH_BUSY ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ_CAPACITY10;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)(void *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if (error == USBH_OK)
+ {
+ /*assign the capacity*/
+ capacity->block_nbr = MSC_Handle->hbot.pbuf[3] | ((uint32_t)MSC_Handle->hbot.pbuf[2] << 8U) | \
+ ((uint32_t)MSC_Handle->hbot.pbuf[1] << 16U) | ((uint32_t)MSC_Handle->hbot.pbuf[0] << 24U);
+
+ /*assign the page length*/
+ capacity->block_size = (uint16_t)(MSC_Handle->hbot.pbuf[7] | ((uint32_t)MSC_Handle->hbot.pbuf[6] << 8U));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Inquiry
+ * Issue Inquiry command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the inquiry structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry(USBH_HandleTypeDef *phost, uint8_t lun,
+ SCSI_StdInquiryDataTypeDef *inquiry)
+{
+ USBH_StatusTypeDef error = USBH_FAIL;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_INQUIRY;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0U;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0U;
+ MSC_Handle->hbot.cbw.field.CB[4] = 0x24U;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0U;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)(void *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if (error == USBH_OK)
+ {
+ USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef));
+ /*assign Inquiry Data */
+ inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1FU;
+ inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5U;
+
+ if (((uint32_t)MSC_Handle->hbot.pbuf[1] & 0x80U) == 0x80U)
+ {
+ inquiry->RemovableMedia = 1U;
+ }
+ else
+ {
+ inquiry->RemovableMedia = 0U;
+ }
+
+ USBH_memcpy(inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8U);
+ USBH_memcpy(inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16U);
+ USBH_memcpy(inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4U);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_RequestSense
+ * Issue RequestSense command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param capacity: pointer to the sense data structure
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ SCSI_SenseTypeDef *sense_data)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5);
+ MSC_Handle->hbot.cbw.field.CB[2] = 0U;
+ MSC_Handle->hbot.cbw.field.CB[3] = 0U;
+ MSC_Handle->hbot.cbw.field.CB[4] = DATA_LEN_REQUEST_SENSE;
+ MSC_Handle->hbot.cbw.field.CB[5] = 0U;
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = (uint8_t *)(void *)MSC_Handle->hbot.data;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+
+ error = USBH_MSC_BOT_Process(phost, lun);
+
+ if (error == USBH_OK)
+ {
+ sense_data->key = MSC_Handle->hbot.pbuf[2] & 0x0FU;
+ sense_data->asc = MSC_Handle->hbot.pbuf[12];
+ sense_data->ascq = MSC_Handle->hbot.pbuf[13];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Write
+ * Issue write10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to write
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * MSC_Handle->unit[0].capacity.block_size;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_WRITE10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t *)(void *)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t *)(void *)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t *)(void *)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t *)(void *)&address)[0]);
+
+
+ /*Transfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)(void *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)(void *)&length)[0]) ;
+
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = pbuf;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+/**
+ * @brief USBH_MSC_SCSI_Read
+ * Issue Read10 command.
+ * @param phost: Host handle
+ * @param lun: Logical Unit Number
+ * @param address: sector address
+ * @param pbuf: pointer to data
+ * @param length: number of sector to read
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost,
+ uint8_t lun,
+ uint32_t address,
+ uint8_t *pbuf,
+ uint32_t length)
+{
+ USBH_StatusTypeDef error = USBH_FAIL ;
+ MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData;
+
+ switch (MSC_Handle->hbot.cmd_state)
+ {
+ case BOT_CMD_SEND:
+
+ /*Prepare the CBW and relevent field*/
+ MSC_Handle->hbot.cbw.field.DataTransferLength = length * MSC_Handle->unit[0].capacity.block_size;
+ MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN;
+ MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH;
+
+ USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH);
+ MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ10;
+
+ /*logical block address*/
+ MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t *)(void *)&address)[3]);
+ MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t *)(void *)&address)[2]);
+ MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t *)(void *)&address)[1]);
+ MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t *)(void *)&address)[0]);
+
+
+ /*Transfer length */
+ MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)(void *)&length)[1]) ;
+ MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)(void *)&length)[0]) ;
+
+
+ MSC_Handle->hbot.state = BOT_SEND_CBW;
+ MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT;
+ MSC_Handle->hbot.pbuf = pbuf;
+ error = USBH_BUSY;
+ break;
+
+ case BOT_CMD_WAIT:
+ error = USBH_MSC_BOT_Process(phost, lun);
+ break;
+
+ default:
+ break;
+ }
+
+ return error;
+}
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_core.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_core.h
new file mode 100644
index 000000000000..8f059de2bc1e
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_core.h
@@ -0,0 +1,192 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_core.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_CORE_H
+#define __USBH_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../usbh_conf.h"
+#include "usbh_def.h"
+#include "usbh_ioreq.h"
+#include "usbh_pipes.h"
+#include "usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CORE
+ * @brief This file is the Header file for usbh_core.c
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Exported_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+#define HOST_USER_SELECT_CONFIGURATION 0x01U
+#define HOST_USER_CLASS_ACTIVE 0x02U
+#define HOST_USER_CLASS_SELECTED 0x03U
+#define HOST_USER_CONNECTION 0x04U
+#define HOST_USER_DISCONNECTION 0x05U
+#define HOST_USER_UNRECOVERED_ERROR 0x06U
+
+
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_CORE_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Exported_FunctionsPrototype
+ * @{
+ */
+
+
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t id), uint8_t id);
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass);
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface);
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost,
+ uint8_t Class,
+ uint8_t SubClass,
+ uint8_t Protocol);
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost);
+
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost,
+ uint8_t interface_number,
+ uint8_t alt_settings);
+
+uint8_t USBH_IsPortEnabled(USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_Start(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Stop(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_ReEnumerate(USBH_HandleTypeDef *phost);
+
+/* USBH Low Level Driver */
+USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_DeInit(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Stop(USBH_HandleTypeDef *phost);
+
+USBH_StatusTypeDef USBH_LL_Connect(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_Disconnect(USBH_HandleTypeDef *phost);
+USBH_SpeedTypeDef USBH_LL_GetSpeed(USBH_HandleTypeDef *phost);
+USBH_StatusTypeDef USBH_LL_ResetPort(USBH_HandleTypeDef *phost);
+uint32_t USBH_LL_GetLastXferSize(USBH_HandleTypeDef *phost,
+ uint8_t pipe);
+
+USBH_StatusTypeDef USBH_LL_DriverVBUS(USBH_HandleTypeDef *phost,
+ uint8_t state);
+
+USBH_StatusTypeDef USBH_LL_OpenPipe(USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps);
+
+USBH_StatusTypeDef USBH_LL_ClosePipe(USBH_HandleTypeDef *phost,
+ uint8_t pipe);
+
+USBH_StatusTypeDef USBH_LL_SubmitURB(USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t direction,
+ uint8_t ep_type,
+ uint8_t token,
+ uint8_t *pbuff,
+ uint16_t length,
+ uint8_t do_ping);
+
+USBH_URBStateTypeDef USBH_LL_GetURBState(USBH_HandleTypeDef *phost,
+ uint8_t pipe);
+
+#if (USBH_USE_OS == 1U)
+USBH_StatusTypeDef USBH_LL_NotifyURBChange(USBH_HandleTypeDef *phost);
+#endif
+
+USBH_StatusTypeDef USBH_LL_SetToggle(USBH_HandleTypeDef *phost,
+ uint8_t pipe, uint8_t toggle);
+
+uint8_t USBH_LL_GetToggle(USBH_HandleTypeDef *phost, uint8_t pipe);
+
+void USBH_LL_PortDisabled(USBH_HandleTypeDef *phost);
+void USBH_LL_PortEnabled(USBH_HandleTypeDef *phost);
+
+/* USBH Time base */
+void USBH_LL_SetTimer(USBH_HandleTypeDef *phost, uint32_t time);
+void USBH_LL_IncTimer(USBH_HandleTypeDef *phost);
+
+void USBH_Delay(uint32_t Delay);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_CORE_H */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h
new file mode 100644
index 000000000000..5fef83f3c02d
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ctlreq.h
@@ -0,0 +1,141 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_ctlreq.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_CTLREQ_H
+#define __USBH_CTLREQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+ * @brief This file is the
+ * @{
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Defines
+ * @{
+ */
+/*Standard Feature Selector for clear feature command*/
+#define FEATURE_SELECTOR_ENDPOINT 0x00U
+#define FEATURE_SELECTOR_DEVICE 0x01U
+#define FEATURE_SELECTOR_REMOTEWAKEUP 0X01U
+
+
+#define INTERFACE_DESC_TYPE 0x04U
+#define ENDPOINT_DESC_TYPE 0x05U
+#define INTERFACE_DESC_SIZE 0x09U
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CTLREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_Variables
+ * @{
+ */
+extern uint8_t USBH_CfgDesc[512];
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CTLREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlReq(USBH_HandleTypeDef *phost, uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type, uint16_t value_idx,
+ uint8_t *buff, uint16_t length);
+
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length);
+
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index, uint8_t *buff,
+ uint16_t length);
+
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, uint16_t cfg_idx);
+
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost, uint16_t length);
+
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress);
+
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, uint8_t ep_num,
+ uint8_t altSetting);
+
+USBH_StatusTypeDef USBH_SetFeature(USBH_HandleTypeDef *phost, uint8_t wValue);
+
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, uint8_t ep_num);
+
+USBH_DescHeader_t *USBH_GetNextDesc(uint8_t *pbuf, uint16_t *ptr);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_CTLREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_def.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_def.h
new file mode 100644
index 000000000000..69b2b3567a98
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_def.h
@@ -0,0 +1,500 @@
+/**
+ ******************************************************************************
+ * @file usbh_def.h
+ * @author MCD Application Team
+ * @brief Definitions used in the USB host library
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef USBH_DEF_H
+#define USBH_DEF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../usbh_conf.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_DEF
+ * @brief This file is includes USB descriptors
+ * @{
+ */
+
+#ifndef NULL
+#define NULL 0U
+#endif
+
+#ifndef FALSE
+#define FALSE 0U
+#endif
+
+#ifndef TRUE
+#define TRUE 1U
+#endif
+
+#ifndef USBH_DEV_RESET_TIMEOUT
+#define USBH_DEV_RESET_TIMEOUT 1000U
+#endif
+
+#define ValBit(VAR,POS) (VAR & (1 << POS))
+#define SetBit(VAR,POS) (VAR |= (1 << POS))
+#define ClrBit(VAR,POS) (VAR &= ((1 << POS)^255))
+
+#define LE16(addr) (((uint16_t)(addr)[0]) | \
+ ((uint16_t)(((uint32_t)(addr)[1]) << 8)))
+
+#define LE24(addr) (((uint32_t)(addr)[0]) | \
+ (((uint32_t)(addr)[1]) << 8) | \
+ (((uint32_t)(addr)[2]) << 16))
+
+#define LE32(addr) (((uint32_t)(addr)[0]) | \
+ (((uint32_t)(addr)[1]) << 8) | \
+ (((uint32_t)(addr)[2]) << 16) | \
+ (((uint32_t)(addr)[3]) << 24))
+
+#define LE64(addr) (((uint64_t)(addr)[0]) | \
+ (((uint64_t)(addr)[1]) << 8) | \
+ (((uint64_t)(addr)[2]) << 16) | \
+ (((uint64_t)(addr)[3]) << 24) | \
+ (((uint64_t)(addr)[4]) << 32) | \
+ (((uint64_t)(addr)[5]) << 40) | \
+ (((uint64_t)(addr)[6]) << 48) | \
+ (((uint64_t)(addr)[7]) << 56))
+
+#define LE16S(addr) ((int16_t)(LE16((addr))))
+#define LE24S(addr) ((int32_t)(LE24((addr))))
+#define LE32S(addr) ((int32_t)(LE32((addr))))
+#define LE64S(addr) ((int64_t)(LE64((addr))))
+
+
+
+#define USB_LEN_DESC_HDR 0x02U
+#define USB_LEN_DEV_DESC 0x12U
+#define USB_LEN_CFG_DESC 0x09U
+#define USB_LEN_IF_DESC 0x09U
+#define USB_LEN_EP_DESC 0x07U
+#define USB_LEN_OTG_DESC 0x03U
+#define USB_LEN_SETUP_PKT 0x08U
+
+/* bmRequestType :D7 Data Phase Transfer Direction */
+#define USB_REQ_DIR_MASK 0x80U
+#define USB_H2D 0x00U
+#define USB_D2H 0x80U
+
+/* bmRequestType D6..5 Type */
+#define USB_REQ_TYPE_STANDARD 0x00U
+#define USB_REQ_TYPE_CLASS 0x20U
+#define USB_REQ_TYPE_VENDOR 0x40U
+#define USB_REQ_TYPE_RESERVED 0x60U
+
+/* bmRequestType D4..0 Recipient */
+#define USB_REQ_RECIPIENT_DEVICE 0x00U
+#define USB_REQ_RECIPIENT_INTERFACE 0x01U
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02U
+#define USB_REQ_RECIPIENT_OTHER 0x03U
+
+/* Table 9-4. Standard Request Codes */
+/* bRequest , Value */
+#define USB_REQ_GET_STATUS 0x00U
+#define USB_REQ_CLEAR_FEATURE 0x01U
+#define USB_REQ_SET_FEATURE 0x03U
+#define USB_REQ_SET_ADDRESS 0x05U
+#define USB_REQ_GET_DESCRIPTOR 0x06U
+#define USB_REQ_SET_DESCRIPTOR 0x07U
+#define USB_REQ_GET_CONFIGURATION 0x08U
+#define USB_REQ_SET_CONFIGURATION 0x09U
+#define USB_REQ_GET_INTERFACE 0x0AU
+#define USB_REQ_SET_INTERFACE 0x0BU
+#define USB_REQ_SYNCH_FRAME 0x0CU
+
+/* Table 9-5. Descriptor Types of USB Specifications */
+#define USB_DESC_TYPE_DEVICE 0x01U
+#define USB_DESC_TYPE_CONFIGURATION 0x02U
+#define USB_DESC_TYPE_STRING 0x03U
+#define USB_DESC_TYPE_INTERFACE 0x04U
+#define USB_DESC_TYPE_ENDPOINT 0x05U
+#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06U
+#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07U
+#define USB_DESC_TYPE_INTERFACE_POWER 0x08U
+#define USB_DESC_TYPE_HID 0x21U
+#define USB_DESC_TYPE_HID_REPORT 0x22U
+
+
+#define USB_DEVICE_DESC_SIZE 0x12U
+#define USB_CONFIGURATION_DESC_SIZE 0x09U
+#define USB_HID_DESC_SIZE 0x09U
+#define USB_INTERFACE_DESC_SIZE 0x09U
+#define USB_ENDPOINT_DESC_SIZE 0x07U
+
+/* Descriptor Type and Descriptor Index */
+/* Use the following values when calling the function USBH_GetDescriptor */
+#define USB_DESC_DEVICE ((USB_DESC_TYPE_DEVICE << 8) & 0xFF00U)
+#define USB_DESC_CONFIGURATION ((USB_DESC_TYPE_CONFIGURATION << 8) & 0xFF00U)
+#define USB_DESC_STRING ((USB_DESC_TYPE_STRING << 8) & 0xFF00U)
+#define USB_DESC_INTERFACE ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00U)
+#define USB_DESC_ENDPOINT ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00U)
+#define USB_DESC_DEVICE_QUALIFIER ((USB_DESC_TYPE_DEVICE_QUALIFIER << 8) & 0xFF00U)
+#define USB_DESC_OTHER_SPEED_CONFIGURATION ((USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION << 8) & 0xFF00U)
+#define USB_DESC_INTERFACE_POWER ((USB_DESC_TYPE_INTERFACE_POWER << 8) & 0xFF00U)
+#define USB_DESC_HID_REPORT ((USB_DESC_TYPE_HID_REPORT << 8) & 0xFF00U)
+#define USB_DESC_HID ((USB_DESC_TYPE_HID << 8) & 0xFF00U)
+
+
+#define USB_EP_TYPE_CTRL 0x00U
+#define USB_EP_TYPE_ISOC 0x01U
+#define USB_EP_TYPE_BULK 0x02U
+#define USB_EP_TYPE_INTR 0x03U
+
+#define USB_EP_DIR_OUT 0x00U
+#define USB_EP_DIR_IN 0x80U
+#define USB_EP_DIR_MSK 0x80U
+
+#ifndef USBH_MAX_PIPES_NBR
+#define USBH_MAX_PIPES_NBR 15U
+#endif /* USBH_MAX_PIPES_NBR */
+
+#define USBH_DEVICE_ADDRESS_DEFAULT 0x00U
+#define USBH_DEVICE_ADDRESS 0x01U
+
+#define USBH_MAX_ERROR_COUNT 0x02U
+
+#if (USBH_USE_OS == 1U)
+#define MSGQUEUE_OBJECTS 0x10U
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#define USBH_CONFIGURATION_DESCRIPTOR_SIZE (USB_CONFIGURATION_DESC_SIZE \
+ + USB_INTERFACE_DESC_SIZE\
+ + (USBH_MAX_NUM_ENDPOINTS * USB_ENDPOINT_DESC_SIZE))
+
+
+#define CONFIG_DESC_wTOTAL_LENGTH (ConfigurationDescriptorData.ConfigDescfield.\
+ ConfigurationDescriptor.wTotalLength)
+
+
+typedef union
+{
+ uint16_t w;
+ struct BW
+ {
+ uint8_t msb;
+ uint8_t lsb;
+ }
+ bw;
+}
+uint16_t_uint8_t;
+
+
+typedef union _USB_Setup
+{
+ uint32_t d8[2];
+
+ struct _SetupPkt_Struc
+ {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t_uint8_t wValue;
+ uint16_t_uint8_t wIndex;
+ uint16_t_uint8_t wLength;
+ } b;
+}
+USB_Setup_TypeDef;
+
+typedef struct _DescHeader
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+}
+USBH_DescHeader_t;
+
+typedef struct _DeviceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB; /* USB Specification Number which device complies too */
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ /* If equal to Zero, each interface specifies its own class
+ code if equal to 0xFF, the class code is vendor specified.
+ Otherwise field is valid Class Code.*/
+ uint8_t bMaxPacketSize;
+ uint16_t idVendor; /* Vendor ID (Assigned by USB Org) */
+ uint16_t idProduct; /* Product ID (Assigned by Manufacturer) */
+ uint16_t bcdDevice; /* Device Release Number */
+ uint8_t iManufacturer; /* Index of Manufacturer String Descriptor */
+ uint8_t iProduct; /* Index of Product String Descriptor */
+ uint8_t iSerialNumber; /* Index of Serial Number String Descriptor */
+ uint8_t bNumConfigurations; /* Number of Possible Configurations */
+}
+USBH_DevDescTypeDef;
+
+typedef struct _EndpointDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress; /* indicates what endpoint this descriptor is describing */
+ uint8_t bmAttributes; /* specifies the transfer type. */
+ uint16_t wMaxPacketSize; /* Maximum Packet Size this endpoint is capable of sending or receiving */
+ uint8_t bInterval; /* is used to specify the polling interval of certain transfers. */
+}
+USBH_EpDescTypeDef;
+
+typedef struct _InterfaceDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting; /* Value used to select alternative setting */
+ uint8_t bNumEndpoints; /* Number of Endpoints used for this interface */
+ uint8_t bInterfaceClass; /* Class Code (Assigned by USB Org) */
+ uint8_t bInterfaceSubClass; /* Subclass Code (Assigned by USB Org) */
+ uint8_t bInterfaceProtocol; /* Protocol Code */
+ uint8_t iInterface; /* Index of String Descriptor Describing this interface */
+ USBH_EpDescTypeDef Ep_Desc[USBH_MAX_NUM_ENDPOINTS];
+}
+USBH_InterfaceDescTypeDef;
+
+
+typedef struct _ConfigurationDescriptor
+{
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t wTotalLength; /* Total Length of Data Returned */
+ uint8_t bNumInterfaces; /* Number of Interfaces */
+ uint8_t bConfigurationValue; /* Value to use as an argument to select this configuration*/
+ uint8_t iConfiguration; /*Index of String Descriptor Describing this configuration */
+ uint8_t bmAttributes; /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/
+ uint8_t bMaxPower; /*Maximum Power Consumption */
+ USBH_InterfaceDescTypeDef Itf_Desc[USBH_MAX_NUM_INTERFACES];
+}
+USBH_CfgDescTypeDef;
+
+
+/* Following USB Host status */
+typedef enum
+{
+ USBH_OK = 0,
+ USBH_BUSY,
+ USBH_FAIL,
+ USBH_NOT_SUPPORTED,
+ USBH_UNRECOVERED_ERROR,
+ USBH_ERROR_SPEED_UNKNOWN,
+} USBH_StatusTypeDef;
+
+
+/** @defgroup USBH_CORE_Exported_Types
+ * @{
+ */
+
+typedef enum
+{
+ USBH_SPEED_HIGH = 0U,
+ USBH_SPEED_FULL = 1U,
+ USBH_SPEED_LOW = 2U,
+
+} USBH_SpeedTypeDef;
+
+/* Following states are used for gState */
+typedef enum
+{
+ HOST_IDLE = 0U,
+ HOST_DEV_WAIT_FOR_ATTACHMENT,
+ HOST_DEV_ATTACHED,
+ HOST_DEV_DISCONNECTED,
+ HOST_DETECT_DEVICE_SPEED,
+ HOST_ENUMERATION,
+ HOST_CLASS_REQUEST,
+ HOST_INPUT,
+ HOST_SET_CONFIGURATION,
+ HOST_SET_WAKEUP_FEATURE,
+ HOST_CHECK_CLASS,
+ HOST_CLASS,
+ HOST_SUSPENDED,
+ HOST_ABORT_STATE,
+} HOST_StateTypeDef;
+
+/* Following states are used for EnumerationState */
+typedef enum
+{
+ ENUM_IDLE = 0U,
+ ENUM_GET_FULL_DEV_DESC,
+ ENUM_SET_ADDR,
+ ENUM_GET_CFG_DESC,
+ ENUM_GET_FULL_CFG_DESC,
+ ENUM_GET_MFC_STRING_DESC,
+ ENUM_GET_PRODUCT_STRING_DESC,
+ ENUM_GET_SERIALNUM_STRING_DESC,
+} ENUM_StateTypeDef;
+
+/* Following states are used for CtrlXferStateMachine */
+typedef enum
+{
+ CTRL_IDLE = 0U,
+ CTRL_SETUP,
+ CTRL_SETUP_WAIT,
+ CTRL_DATA_IN,
+ CTRL_DATA_IN_WAIT,
+ CTRL_DATA_OUT,
+ CTRL_DATA_OUT_WAIT,
+ CTRL_STATUS_IN,
+ CTRL_STATUS_IN_WAIT,
+ CTRL_STATUS_OUT,
+ CTRL_STATUS_OUT_WAIT,
+ CTRL_ERROR,
+ CTRL_STALLED,
+ CTRL_COMPLETE
+} CTRL_StateTypeDef;
+
+
+/* Following states are used for RequestState */
+typedef enum
+{
+ CMD_IDLE = 0U,
+ CMD_SEND,
+ CMD_WAIT
+} CMD_StateTypeDef;
+
+typedef enum
+{
+ USBH_URB_IDLE = 0U,
+ USBH_URB_DONE,
+ USBH_URB_NOTREADY,
+ USBH_URB_NYET,
+ USBH_URB_ERROR,
+ USBH_URB_STALL
+} USBH_URBStateTypeDef;
+
+typedef enum
+{
+ USBH_PORT_EVENT = 1U,
+ USBH_URB_EVENT,
+ USBH_CONTROL_EVENT,
+ USBH_CLASS_EVENT,
+ USBH_STATE_CHANGED_EVENT,
+}
+USBH_OSEventTypeDef;
+
+/* Control request structure */
+typedef struct
+{
+ uint8_t pipe_in;
+ uint8_t pipe_out;
+ uint8_t pipe_size;
+ uint8_t *buff;
+ uint16_t length;
+ uint16_t timer;
+ USB_Setup_TypeDef setup;
+ CTRL_StateTypeDef state;
+ uint8_t errorcount;
+
+} USBH_CtrlTypeDef;
+
+/* Attached device structure */
+typedef struct
+{
+ uint8_t CfgDesc_Raw[USBH_MAX_SIZE_CONFIGURATION];
+ uint8_t Data[USBH_MAX_DATA_BUFFER];
+ uint8_t address;
+ uint8_t speed;
+ uint8_t EnumCnt;
+ uint8_t RstCnt;
+ __IO uint8_t is_connected;
+ __IO uint8_t is_disconnected;
+ __IO uint8_t is_ReEnumerated;
+ uint8_t PortEnabled;
+ uint8_t current_interface;
+ USBH_DevDescTypeDef DevDesc;
+ USBH_CfgDescTypeDef CfgDesc;
+} USBH_DeviceTypeDef;
+
+struct _USBH_HandleTypeDef;
+
+/* USB Host Class structure */
+typedef struct
+{
+ const char *Name;
+ uint8_t ClassCode;
+ USBH_StatusTypeDef(*Init)(struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef(*DeInit)(struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef(*Requests)(struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef(*BgndProcess)(struct _USBH_HandleTypeDef *phost);
+ USBH_StatusTypeDef(*SOFProcess)(struct _USBH_HandleTypeDef *phost);
+ void *pData;
+} USBH_ClassTypeDef;
+
+/* USB Host handle structure */
+typedef struct _USBH_HandleTypeDef
+{
+ __IO HOST_StateTypeDef gState; /* Host State Machine Value */
+ ENUM_StateTypeDef EnumState; /* Enumeration state Machine */
+ CMD_StateTypeDef RequestState;
+ USBH_CtrlTypeDef Control;
+ USBH_DeviceTypeDef device;
+ USBH_ClassTypeDef *pClass[USBH_MAX_NUM_SUPPORTED_CLASS];
+ USBH_ClassTypeDef *pActiveClass;
+ uint32_t ClassNumber;
+ uint32_t Pipes[16];
+ __IO uint32_t Timer;
+ uint32_t Timeout;
+ uint8_t id;
+ void *pData;
+ void (* pUser)(struct _USBH_HandleTypeDef *pHandle, uint8_t id);
+
+#if (USBH_USE_OS == 1U)
+#if osCMSIS < 0x20000
+ osMessageQId os_event;
+ osThreadId thread;
+#else
+ osMessageQueueId_t os_event;
+ osThreadId_t thread;
+#endif
+ uint32_t os_msg;
+#endif
+
+} USBH_HandleTypeDef;
+
+
+#if defined ( __GNUC__ )
+#ifndef __weak
+#define __weak __attribute__((weak))
+#endif /* __weak */
+#ifndef __packed
+#define __packed __attribute__((__packed__))
+#endif /* __packed */
+#endif /* __GNUC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_DEF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h
new file mode 100644
index 000000000000..307bb2b696ff
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_ioreq.h
@@ -0,0 +1,160 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_ioreq.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_IOREQ_H
+#define __USBH_IOREQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "../../../usbh_conf.h"
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file is the header file for usbh_ioreq.c
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Defines
+ * @{
+ */
+
+#define USBH_PID_SETUP 0U
+#define USBH_PID_DATA 1U
+
+#define USBH_EP_CONTROL 0U
+#define USBH_EP_ISO 1U
+#define USBH_EP_BULK 2U
+#define USBH_EP_INTERRUPT 3U
+
+#define USBH_SETUP_PKT_SIZE 8U
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_IOREQ_Exported_FunctionsPrototype
+ * @{
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t pipe_num);
+
+USBH_StatusTypeDef USBH_CtlSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping);
+
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num);
+
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num);
+
+USBH_StatusTypeDef USBH_BulkSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping);
+
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num);
+
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num);
+
+
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num);
+
+
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_IOREQ_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h
new file mode 100644
index 000000000000..a2b4c81b3d88
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Inc/usbh_pipes.h
@@ -0,0 +1,123 @@
+/**
+ ******************************************************************************
+ * @file usbh_pipes.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_pipes.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive ----------------------------------------------*/
+#ifndef __USBH_PIPES_H
+#define __USBH_PIPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_core.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file is the header file for usbh_pipes.c
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Exported_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Exported_FunctionsPrototype
+ * @{
+ */
+
+USBH_StatusTypeDef USBH_OpenPipe(USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps);
+
+USBH_StatusTypeDef USBH_ClosePipe(USBH_HandleTypeDef *phost,
+ uint8_t pipe_num);
+
+uint8_t USBH_AllocPipe(USBH_HandleTypeDef *phost,
+ uint8_t ep_addr);
+
+USBH_StatusTypeDef USBH_FreePipe(USBH_HandleTypeDef *phost,
+ uint8_t idx);
+
+
+
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBH_PIPES_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_core.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_core.cpp
new file mode 100644
index 000000000000..cc6f1b09db30
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_core.cpp
@@ -0,0 +1,1379 @@
+/**
+ ******************************************************************************
+ * @file usbh_core.c
+ * @author MCD Application Team
+ * @brief This file implements the functions for the core state machine process
+ * the enumeration and the control transfer process
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_core.h"
+
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+ * @{
+ */
+
+/** @defgroup USBH_CORE
+ * @brief This file handles the basic enumeration when a device is connected
+ * to the host.
+ * @{
+ */
+
+
+/** @defgroup USBH_CORE_Private_Defines
+ * @{
+ */
+#define USBH_ADDRESS_DEFAULT 0x00U
+#define USBH_ADDRESS_ASSIGNED 0x01U
+#define USBH_MPS_DEFAULT 0x40U
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CORE_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Variables
+ * @{
+ */
+#if (USBH_USE_OS == 1U)
+#if (osCMSIS >= 0x20000U)
+osThreadAttr_t USBH_Thread_Atrr;
+#endif
+#endif
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CORE_Private_Functions
+ * @{
+ */
+static USBH_StatusTypeDef USBH_HandleEnum(USBH_HandleTypeDef *phost);
+static void USBH_HandleSof(USBH_HandleTypeDef *phost);
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost);
+
+#if (USBH_USE_OS == 1U)
+#if (osCMSIS < 0x20000U)
+static void USBH_Process_OS(void const *argument);
+#else
+static void USBH_Process_OS(void *argument);
+#endif
+#endif
+
+
+/**
+ * @brief HCD_Init
+ * Initialize the HOST Core.
+ * @param phost: Host Handle
+ * @param pUsrFunc: User Callback
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost,
+ void (*pUsrFunc)(USBH_HandleTypeDef *phost,
+ uint8_t id), uint8_t id)
+{
+ /* Check whether the USB Host handle is valid */
+ if (phost == NULL)
+ {
+ USBH_ErrLog("Invalid Host handle");
+ return USBH_FAIL;
+ }
+
+ /* Set DRiver ID */
+ phost->id = id;
+
+ /* Unlink class*/
+ phost->pActiveClass = NULL;
+ phost->ClassNumber = 0U;
+
+ /* Restore default states and prepare EP0 */
+ DeInitStateMachine(phost);
+
+ /* Restore default Device connection states */
+ phost->device.PortEnabled = 0U;
+ phost->device.is_connected = 0U;
+ phost->device.is_disconnected = 0U;
+ phost->device.is_ReEnumerated = 0U;
+
+ /* Assign User process */
+ if (pUsrFunc != NULL)
+ {
+ phost->pUser = pUsrFunc;
+ }
+
+#if (USBH_USE_OS == 1U)
+#if (osCMSIS < 0x20000U)
+
+ /* Create USB Host Queue */
+ osMessageQDef(USBH_Queue, MSGQUEUE_OBJECTS, uint16_t);
+ phost->os_event = osMessageCreate(osMessageQ(USBH_Queue), NULL);
+
+ /* Create USB Host Task */
+#if defined (USBH_PROCESS_STACK_SIZE)
+ osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, USBH_PROCESS_STACK_SIZE);
+#else
+ osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0U, 8U * configMINIMAL_STACK_SIZE);
+#endif /* defined (USBH_PROCESS_STACK_SIZE) */
+
+ phost->thread = osThreadCreate(osThread(USBH_Thread), phost);
+
+#else
+
+ /* Create USB Host Queue */
+ phost->os_event = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(uint32_t), NULL);
+
+ /* Create USB Host Task */
+ USBH_Thread_Atrr.name = "USBH_Queue";
+
+#if defined (USBH_PROCESS_STACK_SIZE)
+ USBH_Thread_Atrr.stack_size = USBH_PROCESS_STACK_SIZE;
+#else
+ USBH_Thread_Atrr.stack_size = (8U * configMINIMAL_STACK_SIZE);
+#endif /* defined (USBH_PROCESS_STACK_SIZE) */
+
+ USBH_Thread_Atrr.priority = USBH_PROCESS_PRIO;
+ phost->thread = osThreadNew(USBH_Process_OS, phost, &USBH_Thread_Atrr);
+
+#endif /* (osCMSIS < 0x20000U) */
+#endif /* (USBH_USE_OS == 1U) */
+
+ /* Initialize low level driver */
+ USBH_LL_Init(phost);
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief HCD_Init
+ * De-Initialize the Host portion of the driver.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
+{
+ DeInitStateMachine(phost);
+
+ /* Restore default Device connection states */
+ phost->device.PortEnabled = 0U;
+ phost->device.is_connected = 0U;
+ phost->device.is_disconnected = 0U;
+ phost->device.is_ReEnumerated = 0U;
+ phost->device.RstCnt = 0U;
+ phost->device.EnumCnt = 0U;
+
+ if (phost->pData != NULL)
+ {
+ USBH_LL_Stop(phost);
+ }
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief DeInitStateMachine
+ * De-Initialize the Host state machine.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
+{
+ uint32_t i = 0U;
+
+ /* Clear Pipes flags*/
+ for (i = 0U; i < USBH_MAX_PIPES_NBR; i++)
+ {
+ phost->Pipes[i] = 0U;
+ }
+
+ for (i = 0U; i < USBH_MAX_DATA_BUFFER; i++)
+ {
+ phost->device.Data[i] = 0U;
+ }
+
+ phost->gState = HOST_IDLE;
+ phost->EnumState = ENUM_IDLE;
+ phost->RequestState = CMD_SEND;
+ phost->Timer = 0U;
+
+ phost->Control.state = CTRL_SETUP;
+ phost->Control.pipe_size = USBH_MPS_DEFAULT;
+ phost->Control.errorcount = 0U;
+
+ phost->device.address = USBH_ADDRESS_DEFAULT;
+ phost->device.speed = USBH_SPEED_FULL;
+ phost->device.RstCnt = 0U;
+ phost->device.EnumCnt = 0U;
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_RegisterClass
+ * Link class driver to Host Core.
+ * @param phost : Host Handle
+ * @param pclass: Class handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if (pclass != NULL)
+ {
+ if (phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS)
+ {
+ /* link the class to the USB Host handle */
+ phost->pClass[phost->ClassNumber++] = pclass;
+ status = USBH_OK;
+ }
+ else
+ {
+ USBH_ErrLog("Max Class Number reached");
+ status = USBH_FAIL;
+ }
+ }
+ else
+ {
+ USBH_ErrLog("Invalid Class handle");
+ status = USBH_FAIL;
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_SelectInterface
+ * Select current interface.
+ * @param phost: Host Handle
+ * @param interface: Interface number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface)
+{
+ USBH_StatusTypeDef status = USBH_OK;
+
+ if (interface < phost->device.CfgDesc.bNumInterfaces)
+ {
+ phost->device.current_interface = interface;
+ USBH_UsrLog("Switching to Interface (#%d)", interface);
+ USBH_UsrLog("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass);
+ USBH_UsrLog("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass);
+ USBH_UsrLog("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol);
+ }
+ else
+ {
+ USBH_ErrLog("Cannot Select This Interface.");
+ status = USBH_FAIL;
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_GetActiveClass
+ * Return Device Class.
+ * @param phost: Host Handle
+ * @param interface: Interface index
+ * @retval Class Code
+ */
+uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost)
+{
+ return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass);
+}
+
+
+/**
+ * @brief USBH_FindInterface
+ * Find the interface index for a specific class.
+ * @param phost: Host Handle
+ * @param Class: Class code
+ * @param SubClass: SubClass code
+ * @param Protocol: Protocol code
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol)
+{
+ USBH_InterfaceDescTypeDef *pif;
+ USBH_CfgDescTypeDef *pcfg;
+ uint8_t if_ix = 0U;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if (((pif->bInterfaceClass == Class) || (Class == 0xFFU)) &&
+ ((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFFU)) &&
+ ((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFFU)))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFFU;
+}
+
+
+/**
+ * @brief USBH_FindInterfaceIndex
+ * Find the interface index for a specific class interface and alternate setting number.
+ * @param phost: Host Handle
+ * @param interface_number: interface number
+ * @param alt_settings : alternate setting number
+ * @retval interface index in the configuration structure
+ * @note : (1)interface index 0xFF means interface index not found
+ */
+uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings)
+{
+ USBH_InterfaceDescTypeDef *pif;
+ USBH_CfgDescTypeDef *pcfg;
+ uint8_t if_ix = 0U;
+
+ pif = (USBH_InterfaceDescTypeDef *)0;
+ pcfg = &phost->device.CfgDesc;
+
+ while (if_ix < USBH_MAX_NUM_INTERFACES)
+ {
+ pif = &pcfg->Itf_Desc[if_ix];
+ if ((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings))
+ {
+ return if_ix;
+ }
+ if_ix++;
+ }
+ return 0xFFU;
+}
+
+
+/**
+ * @brief USBH_Start
+ * Start the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Start(USBH_HandleTypeDef *phost)
+{
+ /* Start the low level driver */
+ USBH_LL_Start(phost);
+
+ /* Activate VBUS on the port */
+ USBH_LL_DriverVBUS(phost, TRUE);
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_Stop
+ * Stop the USB Host Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Stop(USBH_HandleTypeDef *phost)
+{
+ /* DeActivate VBUS on the port */
+ USBH_LL_DriverVBUS(phost, FALSE);
+
+ /* Stop and cleanup the low level driver */
+ USBH_LL_Stop(phost);
+
+ /* Free Control Pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief HCD_ReEnumerate
+ * Perform a new Enumeration phase.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ReEnumerate(USBH_HandleTypeDef *phost)
+{
+ if (USBH_IsPortEnabled(phost))
+ {
+ phost->device.is_ReEnumerated = 1U;
+
+ /* Stop Host */
+ USBH_Stop(phost);
+
+ phost->device.is_disconnected = 1U;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_Process
+ * Background process of the USB Core.
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost)
+{
+ __IO USBH_StatusTypeDef status = USBH_FAIL;
+ uint8_t idx = 0U;
+
+ /* check for Host pending port disconnect event */
+ if (phost->device.is_disconnected == 1U)
+ {
+ phost->gState = HOST_DEV_DISCONNECTED;
+ }
+
+ switch (phost->gState)
+ {
+ case HOST_IDLE :
+
+ if (phost->device.is_connected)
+ {
+ USBH_UsrLog("USB Device Connected");
+
+ /* Wait for 200 ms after connection */
+ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
+ USBH_Delay(200U);
+ USBH_LL_ResetPort(phost);
+
+ /* Make sure to start with Default address */
+ phost->device.address = USBH_ADDRESS_DEFAULT;
+ phost->Timeout = 0U;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ break;
+
+ case HOST_DEV_WAIT_FOR_ATTACHMENT: /* Wait for Port Enabled */
+
+ if (phost->device.PortEnabled == 1U)
+ {
+ USBH_UsrLog("USB Device Reset Completed");
+ phost->device.RstCnt = 0U;
+ phost->gState = HOST_DEV_ATTACHED;
+ }
+ else
+ {
+ if (phost->Timeout > USBH_DEV_RESET_TIMEOUT)
+ {
+ phost->device.RstCnt++;
+ if (phost->device.RstCnt > 3U)
+ {
+ /* Buggy Device can't complete reset */
+ USBH_UsrLog("USB Reset Failed, Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ }
+ else
+ {
+ phost->gState = HOST_IDLE;
+ }
+ }
+ else
+ {
+ phost->Timeout += 10U;
+ USBH_Delay(10U);
+ }
+ }
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_DEV_ATTACHED :
+
+ if (phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_CONNECTION);
+ }
+
+ /* Wait for 100 ms after Reset */
+ USBH_Delay(100U);
+
+ phost->device.speed = USBH_LL_GetSpeed(phost);
+
+ phost->gState = HOST_ENUMERATION;
+
+ phost->Control.pipe_out = USBH_AllocPipe(phost, 0x00U);
+ phost->Control.pipe_in = USBH_AllocPipe(phost, 0x80U);
+
+ /* Open Control pipes */
+ USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U,
+ phost->device.address, phost->device.speed,
+ USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U,
+ phost->device.address, phost->device.speed,
+ USBH_EP_CONTROL, (uint16_t)phost->Control.pipe_size);
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_ENUMERATION:
+ /* Check for enumeration status */
+ status = USBH_HandleEnum(phost);
+ if (status == USBH_OK)
+ {
+ /* The function shall return USBH_OK when full enumeration is complete */
+ USBH_UsrLog("Enumeration done.");
+
+ phost->device.current_interface = 0U;
+
+ if (phost->device.DevDesc.bNumConfigurations == 1U)
+ {
+ USBH_UsrLog("This device has only 1 configuration.");
+ phost->gState = HOST_SET_CONFIGURATION;
+ }
+ else
+ {
+ phost->gState = HOST_INPUT;
+ }
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ break;
+
+ case HOST_INPUT:
+ {
+ /* user callback for end of device basic enumeration */
+ if (phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION);
+ phost->gState = HOST_SET_CONFIGURATION;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case HOST_SET_CONFIGURATION:
+ /* set configuration */
+ if (USBH_SetCfg(phost, (uint16_t)phost->device.CfgDesc.bConfigurationValue) == USBH_OK)
+ {
+ phost->gState = HOST_SET_WAKEUP_FEATURE;
+ USBH_UsrLog("Default configuration set.");
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_SET_WAKEUP_FEATURE:
+
+ if ((phost->device.CfgDesc.bmAttributes) & (1U << 5))
+ {
+ if (USBH_SetFeature(phost, FEATURE_SELECTOR_REMOTEWAKEUP) == USBH_OK)
+ {
+ USBH_UsrLog("Device remote wakeup enabled");
+ phost->gState = HOST_CHECK_CLASS;
+ }
+ }
+ else
+ {
+ phost->gState = HOST_CHECK_CLASS;
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_CHECK_CLASS:
+
+ if (phost->ClassNumber == 0U)
+ {
+ USBH_UsrLog("No Class has been registered.");
+ }
+ else
+ {
+ phost->pActiveClass = NULL;
+
+ for (idx = 0U; idx < USBH_MAX_NUM_SUPPORTED_CLASS; idx++)
+ {
+ if (phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass)
+ {
+ phost->pActiveClass = phost->pClass[idx];
+ break;
+ }
+ }
+
+ if (phost->pActiveClass != NULL)
+ {
+ if (phost->pActiveClass->Init(phost) == USBH_OK)
+ {
+ phost->gState = HOST_CLASS_REQUEST;
+ USBH_UsrLog("%s class started.", phost->pActiveClass->Name);
+
+ /* Inform user that a class has been activated */
+ phost->pUser(phost, HOST_USER_CLASS_SELECTED);
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog("Device not supporting %s class.", phost->pActiveClass->Name);
+ }
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_UsrLog("No registered class for this device.");
+ }
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_CLASS_REQUEST:
+ /* process class standard control requests state machine */
+ if (phost->pActiveClass != NULL)
+ {
+ status = phost->pActiveClass->Requests(phost);
+
+ if (status == USBH_OK)
+ {
+ phost->gState = HOST_CLASS;
+ }
+ else if (status == USBH_FAIL)
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_ErrLog("Device not responding Please Unplug.");
+ }
+ else
+ {
+ /* .. */
+ }
+ }
+ else
+ {
+ phost->gState = HOST_ABORT_STATE;
+ USBH_ErrLog("Invalid Class Driver.");
+ }
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_CLASS:
+ /* process class state machine */
+ if (phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->BgndProcess(phost);
+ }
+ break;
+
+ case HOST_DEV_DISCONNECTED :
+ phost->device.is_disconnected = 0U;
+
+ DeInitStateMachine(phost);
+
+ /* Re-Initilaize Host for new Enumeration */
+ if (phost->pActiveClass != NULL)
+ {
+ phost->pActiveClass->DeInit(phost);
+ phost->pActiveClass = NULL;
+ }
+
+ if (phost->pUser != NULL)
+ {
+ phost->pUser(phost, HOST_USER_DISCONNECTION);
+ }
+ USBH_UsrLog("USB Device disconnected");
+
+ if (phost->device.is_ReEnumerated == 1U)
+ {
+ phost->device.is_ReEnumerated = 0U;
+
+ /* Start the host and re-enable Vbus */
+ USBH_Start(phost);
+ }
+ else
+ {
+ /* Device Disconnection Completed, start USB Driver */
+ USBH_LL_Start(phost);
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case HOST_ABORT_STATE:
+ default :
+ break;
+ }
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_HandleEnum
+ * This function includes the complete enumeration process
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+static USBH_StatusTypeDef USBH_HandleEnum(USBH_HandleTypeDef *phost)
+{
+ USBH_StatusTypeDef Status = USBH_BUSY;
+ USBH_StatusTypeDef ReqStatus = USBH_BUSY;
+
+ switch (phost->EnumState)
+ {
+ case ENUM_IDLE:
+ /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
+ ReqStatus = USBH_Get_DevDesc(phost, 8U);
+ if (ReqStatus == USBH_OK)
+ {
+ phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
+
+ phost->EnumState = ENUM_GET_FULL_DEV_DESC;
+
+ /* modify control channels configuration for MaxPacket size */
+ USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U, phost->device.address,
+ phost->device.speed, USBH_EP_CONTROL,
+ (uint16_t)phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address,
+ phost->device.speed, USBH_EP_CONTROL,
+ (uint16_t)phost->Control.pipe_size);
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_ErrLog("Control error: Get Device Descriptor request failed");
+ phost->device.EnumCnt++;
+ if (phost->device.EnumCnt > 3U)
+ {
+ /* Buggy Device can't complete get device desc request */
+ USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ }
+ else
+ {
+ /* free control pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+
+ /* Reset the USB Device */
+ phost->gState = HOST_IDLE;
+ }
+ }
+ else
+ {
+ /* .. */
+ }
+ break;
+
+ case ENUM_GET_FULL_DEV_DESC:
+ /* Get FULL Device Desc */
+ ReqStatus = USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE);
+ if (ReqStatus == USBH_OK)
+ {
+ USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct);
+ USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor);
+
+ phost->EnumState = ENUM_SET_ADDR;
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_ErrLog("Control error: Get Full Device Descriptor request failed");
+ phost->device.EnumCnt++;
+ if (phost->device.EnumCnt > 3U)
+ {
+ /* Buggy Device can't complete get device desc request */
+ USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ }
+ else
+ {
+ /* Free control pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+
+ /* Reset the USB Device */
+ phost->EnumState = ENUM_IDLE;
+ phost->gState = HOST_IDLE;
+ }
+ }
+ else
+ {
+ /* .. */
+ }
+ break;
+
+ case ENUM_SET_ADDR:
+ /* set address */
+ ReqStatus = USBH_SetAddress(phost, USBH_DEVICE_ADDRESS);
+ if (ReqStatus == USBH_OK)
+ {
+ USBH_Delay(2U);
+ phost->device.address = USBH_DEVICE_ADDRESS;
+
+ /* user callback for device address assigned */
+ USBH_UsrLog("Address (#%d) assigned.", phost->device.address);
+ phost->EnumState = ENUM_GET_CFG_DESC;
+
+ /* modify control channels to update device address */
+ USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U, phost->device.address,
+ phost->device.speed, USBH_EP_CONTROL,
+ (uint16_t)phost->Control.pipe_size);
+
+ /* Open Control pipes */
+ USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address,
+ phost->device.speed, USBH_EP_CONTROL,
+ (uint16_t)phost->Control.pipe_size);
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_ErrLog("Control error: Device Set Address request failed");
+
+ /* Buggy Device can't complete get device desc request */
+ USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ phost->EnumState = ENUM_IDLE;
+ }
+ else
+ {
+ /* .. */
+ }
+ break;
+
+ case ENUM_GET_CFG_DESC:
+ /* get standard configuration descriptor */
+ ReqStatus = USBH_Get_CfgDesc(phost, USB_CONFIGURATION_DESC_SIZE);
+ if (ReqStatus == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_FULL_CFG_DESC;
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_ErrLog("Control error: Get Device configuration descriptor request failed");
+ phost->device.EnumCnt++;
+ if (phost->device.EnumCnt > 3U)
+ {
+ /* Buggy Device can't complete get device desc request */
+ USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ }
+ else
+ {
+ /* Free control pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+
+ /* Reset the USB Device */
+ phost->EnumState = ENUM_IDLE;
+ phost->gState = HOST_IDLE;
+ }
+ }
+ else
+ {
+ /* .. */
+ }
+ break;
+
+ case ENUM_GET_FULL_CFG_DESC:
+ /* get FULL config descriptor (config, interface, endpoints) */
+ ReqStatus = USBH_Get_CfgDesc(phost, phost->device.CfgDesc.wTotalLength);
+ if (ReqStatus == USBH_OK)
+ {
+ phost->EnumState = ENUM_GET_MFC_STRING_DESC;
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_ErrLog("Control error: Get Device configuration descriptor request failed");
+ phost->device.EnumCnt++;
+ if (phost->device.EnumCnt > 3U)
+ {
+ /* Buggy Device can't complete get device desc request */
+ USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
+ phost->gState = HOST_ABORT_STATE;
+ }
+ else
+ {
+ /* Free control pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+
+ /* Reset the USB Device */
+ phost->EnumState = ENUM_IDLE;
+ phost->gState = HOST_IDLE;
+ }
+ }
+ else
+ {
+ /* .. */
+ }
+ break;
+
+ case ENUM_GET_MFC_STRING_DESC:
+ if (phost->device.DevDesc.iManufacturer != 0U)
+ {
+ /* Check that Manufacturer String is available */
+ ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iManufacturer,
+ phost->device.Data, 0xFFU);
+ if (ReqStatus == USBH_OK)
+ {
+ /* User callback for Manufacturing string */
+ USBH_UsrLog("Manufacturer : %s", (char *)(void *)phost->device.Data);
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_UsrLog("Manufacturer : N/A");
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ /* .. */
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Manufacturer : N/A");
+ phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ break;
+
+ case ENUM_GET_PRODUCT_STRING_DESC:
+ if (phost->device.DevDesc.iProduct != 0U)
+ {
+ /* Check that Product string is available */
+ ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iProduct,
+ phost->device.Data, 0xFFU);
+ if (ReqStatus == USBH_OK)
+ {
+ /* User callback for Product string */
+ USBH_UsrLog("Product : %s", (char *)(void *)phost->device.Data);
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_UsrLog("Product : N/A");
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ /* .. */
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Product : N/A");
+ phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_STATE_CHANGED_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ break;
+
+ case ENUM_GET_SERIALNUM_STRING_DESC:
+ if (phost->device.DevDesc.iSerialNumber != 0U)
+ {
+ /* Check that Serial number string is available */
+ ReqStatus = USBH_Get_StringDesc(phost, phost->device.DevDesc.iSerialNumber,
+ phost->device.Data, 0xFFU);
+ if (ReqStatus == USBH_OK)
+ {
+ /* User callback for Serial number string */
+ USBH_UsrLog("Serial Number : %s", (char *)(void *)phost->device.Data);
+ Status = USBH_OK;
+ }
+ else if (ReqStatus == USBH_NOT_SUPPORTED)
+ {
+ USBH_UsrLog("Serial Number : N/A");
+ Status = USBH_OK;
+ }
+ else
+ {
+ /* .. */
+ }
+ }
+ else
+ {
+ USBH_UsrLog("Serial Number : N/A");
+ Status = USBH_OK;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return Status;
+}
+
+
+/**
+ * @brief USBH_LL_SetTimer
+ * Set the initial Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_SetTimer(USBH_HandleTypeDef *phost, uint32_t time)
+{
+ phost->Timer = time;
+}
+
+
+/**
+ * @brief USBH_LL_IncTimer
+ * Increment Host Timer tick
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_IncTimer(USBH_HandleTypeDef *phost)
+{
+ phost->Timer++;
+ USBH_HandleSof(phost);
+}
+
+
+/**
+ * @brief USBH_HandleSof
+ * Call SOF process
+ * @param phost: Host Handle
+ * @retval None
+ */
+static void USBH_HandleSof(USBH_HandleTypeDef *phost)
+{
+ if ((phost->gState == HOST_CLASS) && (phost->pActiveClass != NULL))
+ {
+ phost->pActiveClass->SOFProcess(phost);
+ }
+}
+
+
+/**
+ * @brief USBH_PortEnabled
+ * Port Enabled
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_PortEnabled(USBH_HandleTypeDef *phost)
+{
+ phost->device.PortEnabled = 1U;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+
+ return;
+}
+
+
+/**
+ * @brief USBH_LL_PortDisabled
+ * Port Disabled
+ * @param phost: Host Handle
+ * @retval None
+ */
+void USBH_LL_PortDisabled(USBH_HandleTypeDef *phost)
+{
+ phost->device.PortEnabled = 0U;
+
+ return;
+}
+
+
+/**
+ * @brief HCD_IsPortEnabled
+ * Is Port Enabled
+ * @param phost: Host Handle
+ * @retval None
+ */
+uint8_t USBH_IsPortEnabled(USBH_HandleTypeDef *phost)
+{
+ return (phost->device.PortEnabled);
+}
+
+
+/**
+ * @brief USBH_LL_Connect
+ * Handle USB Host connexion event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Connect(USBH_HandleTypeDef *phost)
+{
+ phost->device.is_connected = 1U;
+ phost->device.is_disconnected = 0U;
+ phost->device.is_ReEnumerated = 0U;
+
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_LL_Disconnect
+ * Handle USB Host disconnection event
+ * @param phost: Host Handle
+ * @retval USBH_Status
+ */
+USBH_StatusTypeDef USBH_LL_Disconnect(USBH_HandleTypeDef *phost)
+{
+ /* update device connection states */
+ phost->device.is_disconnected = 1U;
+ phost->device.is_connected = 0U;
+ phost->device.PortEnabled = 0U;
+
+ /* Stop Host */
+ USBH_LL_Stop(phost);
+
+ /* FRee Control Pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+
+ return USBH_OK;
+}
+
+
+#if (USBH_USE_OS == 1U)
+/**
+ * @brief USB Host Thread task
+ * @param pvParameters not used
+ * @retval None
+ */
+
+#if (osCMSIS < 0x20000U)
+static void USBH_Process_OS(void const *argument)
+{
+ osEvent event;
+
+ for (;;)
+ {
+ event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever);
+ if (event.status == osEventMessage)
+ {
+ USBH_Process((USBH_HandleTypeDef *)argument);
+ }
+ }
+}
+#else
+static void USBH_Process_OS(void *argument)
+{
+ osStatus_t status;
+
+ for (;;)
+ {
+ status = osMessageQueueGet(((USBH_HandleTypeDef *)argument)->os_event,
+ &((USBH_HandleTypeDef *)argument)->os_msg, NULL, osWaitForever);
+ if (status == osOK)
+ {
+ USBH_Process((USBH_HandleTypeDef *)argument);
+ }
+ }
+}
+#endif /* (osCMSIS < 0x20000U) */
+
+
+/**
+* @brief USBH_LL_NotifyURBChange
+* Notify URB state Change
+* @param phost: Host handle
+* @retval USBH Status
+*/
+USBH_StatusTypeDef USBH_LL_NotifyURBChange(USBH_HandleTypeDef *phost)
+{
+ phost->os_msg = (uint32_t)USBH_PORT_EVENT;
+
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+
+ return USBH_OK;
+}
+#endif
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.cpp
new file mode 100644
index 000000000000..6381e8d5426b
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.cpp
@@ -0,0 +1,1008 @@
+/**
+ ******************************************************************************
+ * @file usbh_ctlreq.c
+ * @author MCD Application Team
+ * @brief This file implements the control requests for device enumeration
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_ctlreq.h"
+
+/** @addtogroup USBH_LIB
+* @{
+*/
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_CTLREQ
+* @brief This file implements the standard requests for device enumeration
+* @{
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Defines
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_TypesDefinitions
+* @{
+*/
+/**
+* @}
+*/
+
+
+
+/** @defgroup USBH_CTLREQ_Private_Macros
+* @{
+*/
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Variables
+* @{
+*/
+/**
+* @}
+*/
+
+/** @defgroup USBH_CTLREQ_Private_FunctionPrototypes
+* @{
+*/
+static USBH_StatusTypeDef USBH_HandleControl(USBH_HandleTypeDef *phost);
+
+static void USBH_ParseDevDesc(USBH_DevDescTypeDef *dev_desc,
+ uint8_t *buf, uint16_t length);
+
+static void USBH_ParseCfgDesc(USBH_CfgDescTypeDef *cfg_desc,
+ uint8_t *buf, uint16_t length);
+
+static void USBH_ParseEPDesc(USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf);
+static void USBH_ParseStringDesc(uint8_t *psrc, uint8_t *pdest, uint16_t length);
+static void USBH_ParseInterfaceDesc(USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf);
+
+
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_CTLREQ_Private_Functions
+* @{
+*/
+
+
+/**
+ * @brief USBH_Get_DevDesc
+ * Issue Get Device Descriptor command to the device. Once the response
+ * received, it parses the device descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length)
+{
+ USBH_StatusTypeDef status;
+
+ if ((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_DEVICE, phost->device.Data,
+ (uint16_t)length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data,
+ (uint16_t)length);
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_Get_CfgDesc
+ * Issues Configuration Descriptor to the device. Once the response
+ * received, it parses the configuration descriptor and updates the
+ * status.
+ * @param phost: Host Handle
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
+ uint16_t length)
+
+{
+ USBH_StatusTypeDef status;
+ uint8_t *pData = phost->device.CfgDesc_Raw;;
+
+ if ((status = USBH_GetDescriptor(phost, (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD),
+ USB_DESC_CONFIGURATION, pData, length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseCfgDesc(&phost->device.CfgDesc, pData, length);
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_Get_StringDesc
+ * Issues string Descriptor command to the device. Once the response
+ * received, it parses the string descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param string_index: String index for the descriptor
+ * @param buff: Buffer address for the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
+ uint8_t string_index, uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+
+ if ((status = USBH_GetDescriptor(phost,
+ USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
+ USB_DESC_STRING | string_index,
+ phost->device.Data, length)) == USBH_OK)
+ {
+ /* Commands successfully sent and Response Received */
+ USBH_ParseStringDesc(phost->device.Data, buff, length);
+ }
+
+ return status;
+}
+
+
+/**
+ * @brief USBH_GetDescriptor
+ * Issues Descriptor command to the device. Once the response received,
+ * it parses the descriptor and updates the status.
+ * @param phost: Host Handle
+ * @param req_type: Descriptor type
+ * @param value_idx: Value for the GetDescriptr request
+ * @param buff: Buffer to store the descriptor
+ * @param length: Length of the descriptor
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
+ uint8_t req_type,
+ uint16_t value_idx,
+ uint8_t *buff,
+ uint16_t length)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
+ phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
+ phost->Control.setup.b.wValue.w = value_idx;
+
+ if ((value_idx & 0xff00U) == USB_DESC_STRING)
+ {
+ phost->Control.setup.b.wIndex.w = 0x0409U;
+ }
+ else
+ {
+ phost->Control.setup.b.wIndex.w = 0U;
+ }
+ phost->Control.setup.b.wLength.w = length;
+ }
+
+ return USBH_CtlReq(phost, buff, length);
+}
+
+
+/**
+ * @brief USBH_SetAddress
+ * This command sets the address to the connected device
+ * @param phost: Host Handle
+ * @param DeviceAddress: Device address to assign
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
+ uint8_t DeviceAddress)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
+ USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
+
+ phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
+ phost->Control.setup.b.wIndex.w = 0U;
+ phost->Control.setup.b.wLength.w = 0U;
+ }
+
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+
+/**
+ * @brief USBH_SetCfg
+ * The command sets the configuration value to the connected device
+ * @param phost: Host Handle
+ * @param cfg_idx: Configuration value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, uint16_t cfg_idx)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE
+ | USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
+ phost->Control.setup.b.wValue.w = cfg_idx;
+ phost->Control.setup.b.wIndex.w = 0U;
+ phost->Control.setup.b.wLength.w = 0U;
+ }
+
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+
+/**
+ * @brief USBH_SetInterface
+ * The command sets the Interface value to the connected device
+ * @param phost: Host Handle
+ * @param altSetting: Interface value
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, uint8_t ep_num,
+ uint8_t altSetting)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE
+ | USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE;
+ phost->Control.setup.b.wValue.w = altSetting;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0U;
+ }
+
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+
+/**
+ * @brief USBH_SetFeature
+ * The command sets the device features (remote wakeup feature,..)
+ * @param pdev: Selected device
+ * @param itf_idx
+ * @retval Status
+*/
+USBH_StatusTypeDef USBH_SetFeature(USBH_HandleTypeDef *phost, uint8_t wValue)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE
+ | USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_SET_FEATURE;
+ phost->Control.setup.b.wValue.w = wValue;
+ phost->Control.setup.b.wIndex.w = 0U;
+ phost->Control.setup.b.wLength.w = 0U;
+ }
+
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+
+/**
+ * @brief USBH_ClrFeature
+ * This request is used to clear or disable a specific feature.
+ * @param phost: Host Handle
+ * @param ep_num: endpoint number
+ * @param hc_num: Host channel number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, uint8_t ep_num)
+{
+ if (phost->RequestState == CMD_SEND)
+ {
+ phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT
+ | USB_REQ_TYPE_STANDARD;
+
+ phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
+ phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
+ phost->Control.setup.b.wIndex.w = ep_num;
+ phost->Control.setup.b.wLength.w = 0U;
+ }
+ return USBH_CtlReq(phost, 0U, 0U);
+}
+
+
+/**
+ * @brief USBH_ParseDevDesc
+ * This function Parses the device descriptor
+ * @param dev_desc: device_descriptor destination address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseDevDesc(USBH_DevDescTypeDef *dev_desc, uint8_t *buf,
+ uint16_t length)
+{
+ dev_desc->bLength = *(uint8_t *)(buf + 0);
+ dev_desc->bDescriptorType = *(uint8_t *)(buf + 1);
+ dev_desc->bcdUSB = LE16(buf + 2);
+ dev_desc->bDeviceClass = *(uint8_t *)(buf + 4);
+ dev_desc->bDeviceSubClass = *(uint8_t *)(buf + 5);
+ dev_desc->bDeviceProtocol = *(uint8_t *)(buf + 6);
+ dev_desc->bMaxPacketSize = *(uint8_t *)(buf + 7);
+
+ if (length > 8U)
+ {
+ /* For 1st time after device connection, Host may issue only 8 bytes for
+ Device Descriptor Length */
+ dev_desc->idVendor = LE16(buf + 8);
+ dev_desc->idProduct = LE16(buf + 10);
+ dev_desc->bcdDevice = LE16(buf + 12);
+ dev_desc->iManufacturer = *(uint8_t *)(buf + 14);
+ dev_desc->iProduct = *(uint8_t *)(buf + 15);
+ dev_desc->iSerialNumber = *(uint8_t *)(buf + 16);
+ dev_desc->bNumConfigurations = *(uint8_t *)(buf + 17);
+ }
+}
+
+
+/**
+ * @brief USBH_ParseCfgDesc
+ * This function Parses the configuration descriptor
+ * @param cfg_desc: Configuration Descriptor address
+ * @param buf: Buffer where the source descriptor is available
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseCfgDesc(USBH_CfgDescTypeDef *cfg_desc, uint8_t *buf,
+ uint16_t length)
+{
+ USBH_InterfaceDescTypeDef *pif ;
+ USBH_EpDescTypeDef *pep;
+ USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)(void *)buf;
+ uint16_t ptr;
+ uint8_t if_ix = 0U;
+ uint8_t ep_ix = 0U;
+
+ pdesc = (USBH_DescHeader_t *)(void *)buf;
+
+ /* Parse configuration descriptor */
+ cfg_desc->bLength = *(uint8_t *)(buf + 0);
+ cfg_desc->bDescriptorType = *(uint8_t *)(buf + 1);
+ cfg_desc->wTotalLength = LE16(buf + 2);
+ cfg_desc->bNumInterfaces = *(uint8_t *)(buf + 4);
+ cfg_desc->bConfigurationValue = *(uint8_t *)(buf + 5);
+ cfg_desc->iConfiguration = *(uint8_t *)(buf + 6);
+ cfg_desc->bmAttributes = *(uint8_t *)(buf + 7);
+ cfg_desc->bMaxPower = *(uint8_t *)(buf + 8);
+
+ if (length > USB_CONFIGURATION_DESC_SIZE)
+ {
+ ptr = USB_LEN_CFG_DESC;
+ pif = (USBH_InterfaceDescTypeDef *)0;
+
+ while ((if_ix < USBH_MAX_NUM_INTERFACES) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
+ {
+ pif = &cfg_desc->Itf_Desc[if_ix];
+ USBH_ParseInterfaceDesc(pif, (uint8_t *)(void *)pdesc);
+
+ ep_ix = 0U;
+ pep = (USBH_EpDescTypeDef *)0;
+ while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
+ {
+ pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
+ if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
+ {
+ pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
+ USBH_ParseEPDesc(pep, (uint8_t *)(void *)pdesc);
+ ep_ix++;
+ }
+ }
+ if_ix++;
+ }
+ }
+ }
+}
+
+
+/**
+ * @brief USBH_ParseInterfaceDesc
+ * This function Parses the interface descriptor
+ * @param if_descriptor : Interface descriptor destination
+ * @param buf: Buffer where the descriptor data is available
+ * @retval None
+ */
+static void USBH_ParseInterfaceDesc(USBH_InterfaceDescTypeDef *if_descriptor,
+ uint8_t *buf)
+{
+ if_descriptor->bLength = *(uint8_t *)(buf + 0);
+ if_descriptor->bDescriptorType = *(uint8_t *)(buf + 1);
+ if_descriptor->bInterfaceNumber = *(uint8_t *)(buf + 2);
+ if_descriptor->bAlternateSetting = *(uint8_t *)(buf + 3);
+ if_descriptor->bNumEndpoints = *(uint8_t *)(buf + 4);
+ if_descriptor->bInterfaceClass = *(uint8_t *)(buf + 5);
+ if_descriptor->bInterfaceSubClass = *(uint8_t *)(buf + 6);
+ if_descriptor->bInterfaceProtocol = *(uint8_t *)(buf + 7);
+ if_descriptor->iInterface = *(uint8_t *)(buf + 8);
+}
+
+
+/**
+ * @brief USBH_ParseEPDesc
+ * This function Parses the endpoint descriptor
+ * @param ep_descriptor: Endpoint descriptor destination address
+ * @param buf: Buffer where the parsed descriptor stored
+ * @retval None
+ */
+static void USBH_ParseEPDesc(USBH_EpDescTypeDef *ep_descriptor,
+ uint8_t *buf)
+{
+ ep_descriptor->bLength = *(uint8_t *)(buf + 0);
+ ep_descriptor->bDescriptorType = *(uint8_t *)(buf + 1);
+ ep_descriptor->bEndpointAddress = *(uint8_t *)(buf + 2);
+ ep_descriptor->bmAttributes = *(uint8_t *)(buf + 3);
+ ep_descriptor->wMaxPacketSize = LE16(buf + 4);
+ ep_descriptor->bInterval = *(uint8_t *)(buf + 6);
+}
+
+
+/**
+ * @brief USBH_ParseStringDesc
+ * This function Parses the string descriptor
+ * @param psrc: Source pointer containing the descriptor data
+ * @param pdest: Destination address pointer
+ * @param length: Length of the descriptor
+ * @retval None
+ */
+static void USBH_ParseStringDesc(uint8_t *psrc, uint8_t *pdest, uint16_t length)
+{
+ uint16_t strlength;
+ uint16_t idx;
+
+ /* The UNICODE string descriptor is not NULL-terminated. The string length is
+ computed by substracting two from the value of the first byte of the descriptor.
+ */
+
+ /* Check which is lower size, the Size of string or the length of bytes read
+ from the device */
+
+ if (psrc[1] == USB_DESC_TYPE_STRING)
+ {
+ /* Make sure the Descriptor is String Type */
+
+ /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
+ strlength = ((((uint16_t)psrc[0] - 2U) <= length) ? ((uint16_t)psrc[0] - 2U) : length);
+
+ /* Adjust the offset ignoring the String Len and Descriptor type */
+ psrc += 2U;
+
+ for (idx = 0U; idx < strlength; idx += 2U)
+ {
+ /* Copy Only the string and ignore the UNICODE ID, hence add the src */
+ *pdest = psrc[idx];
+ pdest++;
+ }
+ *pdest = 0U; /* mark end of string */
+ }
+}
+
+
+/**
+ * @brief USBH_GetNextDesc
+ * This function return the next descriptor header
+ * @param buf: Buffer where the cfg descriptor is available
+ * @param ptr: data pointer inside the cfg descriptor
+ * @retval next header
+ */
+USBH_DescHeader_t *USBH_GetNextDesc(uint8_t *pbuf, uint16_t *ptr)
+{
+ USBH_DescHeader_t *pnext;
+
+ *ptr += ((USBH_DescHeader_t *)(void *)pbuf)->bLength;
+ pnext = (USBH_DescHeader_t *)(void *)((uint8_t *)(void *)pbuf + \
+ ((USBH_DescHeader_t *)(void *)pbuf)->bLength);
+
+ return (pnext);
+}
+
+
+/**
+ * @brief USBH_CtlReq
+ * USBH_CtlReq sends a control request and provide the status after
+ * completion of the request
+ * @param phost: Host Handle
+ * @param req: Setup Request Structure
+ * @param buff: data buffer address to store the response
+ * @param length: length of the response
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlReq(USBH_HandleTypeDef *phost, uint8_t *buff,
+ uint16_t length)
+{
+ USBH_StatusTypeDef status;
+ status = USBH_BUSY;
+
+ switch (phost->RequestState)
+ {
+ case CMD_SEND:
+ /* Start a SETUP transfer */
+ phost->Control.buff = buff;
+ phost->Control.length = length;
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_WAIT;
+ status = USBH_BUSY;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ case CMD_WAIT:
+ status = USBH_HandleControl(phost);
+ if ((status == USBH_OK) || (status == USBH_NOT_SUPPORTED))
+ {
+ /* Transaction completed, move control state to idle */
+ phost->RequestState = CMD_SEND;
+ phost->Control.state = CTRL_IDLE;
+ }
+ else if (status == USBH_FAIL)
+ {
+ /* Failure Mode */
+ phost->RequestState = CMD_SEND;
+ }
+ else
+ {
+ /* .. */
+ }
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+
+/**
+ * @brief USBH_HandleControl
+ * Handles the USB control transfer state machine
+ * @param phost: Host Handle
+ * @retval USBH Status
+ */
+static USBH_StatusTypeDef USBH_HandleControl(USBH_HandleTypeDef *phost)
+{
+ uint8_t direction;
+ USBH_StatusTypeDef status = USBH_BUSY;
+ USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
+
+ switch (phost->Control.state)
+ {
+ case CTRL_SETUP:
+ /* send a SETUP packet */
+ USBH_CtlSendSetup(phost, (uint8_t *)(void *)phost->Control.setup.d8,
+ phost->Control.pipe_out);
+
+ phost->Control.state = CTRL_SETUP_WAIT;
+ break;
+
+ case CTRL_SETUP_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+ /* case SETUP packet sent successfully */
+ if (URB_Status == USBH_URB_DONE)
+ {
+ direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
+
+ /* check if there is a data stage */
+ if (phost->Control.setup.b.wLength.w != 0U)
+ {
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_DATA_IN;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_DATA_OUT;
+ }
+ }
+ /* No DATA stage */
+ else
+ {
+ /* If there is No Data Transfer Stage */
+ if (direction == USB_D2H)
+ {
+ /* Data Direction is IN */
+ phost->Control.state = CTRL_STATUS_OUT;
+ }
+ else
+ {
+ /* Data Direction is OUT */
+ phost->Control.state = CTRL_STATUS_IN;
+ }
+ }
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if ((URB_Status == USBH_URB_ERROR) || (URB_Status == USBH_URB_NOTREADY))
+ {
+ phost->Control.state = CTRL_ERROR;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case CTRL_DATA_IN:
+ /* Issue an IN token */
+ phost->Control.timer = (uint16_t)phost->Timer;
+ USBH_CtlReceiveData(phost, phost->Control.buff, phost->Control.length,
+ phost->Control.pipe_in);
+
+ phost->Control.state = CTRL_DATA_IN_WAIT;
+ break;
+
+ case CTRL_DATA_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_in);
+
+ /* check is DATA packet transferred successfully */
+ if (URB_Status == USBH_URB_DONE)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+
+ /* manage error cases*/
+ if (URB_Status == USBH_URB_STALL)
+ {
+ /* In stall case, return to previous machine state*/
+ status = USBH_NOT_SUPPORTED;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if (URB_Status == USBH_URB_ERROR)
+ {
+ /* Device error */
+ phost->Control.state = CTRL_ERROR;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case CTRL_DATA_OUT:
+
+ USBH_CtlSendData(phost, phost->Control.buff, phost->Control.length,
+ phost->Control.pipe_out, 1U);
+
+ phost->Control.timer = (uint16_t)phost->Timer;
+ phost->Control.state = CTRL_DATA_OUT_WAIT;
+ break;
+
+ case CTRL_DATA_OUT_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ /* If the Setup Pkt is sent successful, then change the state */
+ phost->Control.state = CTRL_STATUS_IN;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+
+ /* handle error cases */
+ else if (URB_Status == USBH_URB_STALL)
+ {
+ /* In stall case, return to previous machine state*/
+ phost->Control.state = CTRL_STALLED;
+ status = USBH_NOT_SUPPORTED;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ /* Nack received from device */
+ phost->Control.state = CTRL_DATA_OUT;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if (URB_Status == USBH_URB_ERROR)
+ {
+ /* device error */
+ phost->Control.state = CTRL_ERROR;
+ status = USBH_FAIL;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case CTRL_STATUS_IN:
+ /* Send 0 bytes out packet */
+ USBH_CtlReceiveData(phost, 0U, 0U, phost->Control.pipe_in);
+
+ phost->Control.timer = (uint16_t)phost->Timer;
+ phost->Control.state = CTRL_STATUS_IN_WAIT;
+
+ break;
+
+ case CTRL_STATUS_IN_WAIT:
+
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_in);
+
+ if (URB_Status == USBH_URB_DONE)
+ {
+ /* Control transfers completed, Exit the State Machine */
+ phost->Control.state = CTRL_COMPLETE;
+ status = USBH_OK;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if (URB_Status == USBH_URB_STALL)
+ {
+ /* Control transfers completed, Exit the State Machine */
+ status = USBH_NOT_SUPPORTED;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case CTRL_STATUS_OUT:
+ USBH_CtlSendData(phost, 0U, 0U, phost->Control.pipe_out, 1U);
+
+ phost->Control.timer = (uint16_t)phost->Timer;
+ phost->Control.state = CTRL_STATUS_OUT_WAIT;
+ break;
+
+ case CTRL_STATUS_OUT_WAIT:
+ URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
+ if (URB_Status == USBH_URB_DONE)
+ {
+ status = USBH_OK;
+ phost->Control.state = CTRL_COMPLETE;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else if (URB_Status == USBH_URB_NOTREADY)
+ {
+ phost->Control.state = CTRL_STATUS_OUT;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ else
+ {
+ if (URB_Status == USBH_URB_ERROR)
+ {
+ phost->Control.state = CTRL_ERROR;
+
+#if (USBH_USE_OS == 1U)
+ phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
+#if (osCMSIS < 0x20000U)
+ (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
+#else
+ (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
+#endif
+#endif
+ }
+ }
+ break;
+
+ case CTRL_ERROR:
+ /*
+ After a halt condition is encountered or an error is detected by the
+ host, a control endpoint is allowed to recover by accepting the next Setup
+ PID; i.e., recovery actions via some other pipe are not required for control
+ endpoints. For the Default Control Pipe, a device reset will ultimately be
+ required to clear the halt or error condition if the next Setup PID is not
+ accepted.
+ */
+ if (++phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
+ {
+ /* Do the transmission again, starting from SETUP Packet */
+ phost->Control.state = CTRL_SETUP;
+ phost->RequestState = CMD_SEND;
+ }
+ else
+ {
+ phost->pUser(phost, HOST_USER_UNRECOVERED_ERROR);
+ phost->Control.errorcount = 0U;
+ USBH_ErrLog("Control error: Device not responding");
+
+ /* Free control pipes */
+ USBH_FreePipe(phost, phost->Control.pipe_out);
+ USBH_FreePipe(phost, phost->Control.pipe_in);
+
+ phost->gState = HOST_IDLE;
+ status = USBH_FAIL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ioreq.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ioreq.cpp
new file mode 100644
index 000000000000..65fc89e15560
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_ioreq.cpp
@@ -0,0 +1,356 @@
+/**
+ ******************************************************************************
+ * @file usbh_ioreq.c
+ * @author MCD Application Team
+ * @brief This file handles the issuing of the USB transactions
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_ioreq.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_IOREQ
+ * @brief This file handles the standard protocol processing (USB v2.0)
+ * @{
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Defines
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+
+/** @defgroup USBH_IOREQ_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+/** @defgroup USBH_IOREQ_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_IOREQ_Private_Functions
+ * @{
+ */
+
+
+
+/**
+ * @brief USBH_CtlSendSetup
+ * Sends the Setup Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be send to Device
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendSetup(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t pipe_num)
+{
+
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0U, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_SETUP, /* Type setup */
+ buff, /* data buffer */
+ USBH_SETUP_PKT_SIZE, /* data length */
+ 0U);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlSendData
+ * Sends a data Packet to the Device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_CtlSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping)
+{
+ if (phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0U;
+ }
+
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0U, /* Direction : OUT */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_CtlReceiveData
+ * Receives the Device Response to the Setup Packet
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1U, /* Direction : IN */
+ USBH_EP_CONTROL, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0U);
+ return USBH_OK;
+
+}
+
+
+/**
+ * @brief USBH_BulkSendData
+ * Sends the Bulk Packet to the device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from which the Data will be sent to Device
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_BulkSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num,
+ uint8_t do_ping)
+{
+ if (phost->device.speed != USBH_SPEED_HIGH)
+ {
+ do_ping = 0U;
+ }
+
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0U, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ do_ping); /* do ping (HS Only)*/
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_BulkReceiveData
+ * Receives IN bulk packet from device
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the received data packet to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint16_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1U, /* Direction : IN */
+ USBH_EP_BULK, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ length, /* data length */
+ 0U);
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_InterruptReceiveData
+ * Receives the Device Response to the Interrupt IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1U, /* Direction : IN */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ (uint16_t)length, /* data length */
+ 0U);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_InterruptSendData
+ * Sends the data on Interrupt OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint8_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0U, /* Direction : OUT */
+ USBH_EP_INTERRUPT, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ (uint16_t)length, /* data length */
+ 0U);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocReceiveData
+ * Receives the Device Response to the Isochronous IN token
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer in which the response needs to be copied
+ * @param length: Length of the data to be received
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 1U, /* Direction : IN */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ (uint16_t)length, /* data length */
+ 0U);
+
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_IsocSendData
+ * Sends the data on Isochronous OUT Endpoint
+ * @param phost: Host Handle
+ * @param buff: Buffer pointer from where the data needs to be copied
+ * @param length: Length of the data to be sent
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status.
+ */
+USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost,
+ uint8_t *buff,
+ uint32_t length,
+ uint8_t pipe_num)
+{
+ USBH_LL_SubmitURB(phost, /* Driver handle */
+ pipe_num, /* Pipe index */
+ 0U, /* Direction : OUT */
+ USBH_EP_ISO, /* EP type */
+ USBH_PID_DATA, /* Type Data */
+ buff, /* data buffer */
+ (uint16_t)length, /* data length */
+ 0U);
+
+ return USBH_OK;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_pipes.cpp b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_pipes.cpp
new file mode 100644
index 000000000000..30f97f052610
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Core/Src/usbh_pipes.cpp
@@ -0,0 +1,195 @@
+/**
+ ******************************************************************************
+ * @file usbh_pipes.c
+ * @author MCD Application Team
+ * @brief This file implements functions for opening and closing Pipes
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+/* Includes ------------------------------------------------------------------*/
+#include "../Inc/usbh_pipes.h"
+
+/** @addtogroup USBH_LIB
+ * @{
+ */
+
+/** @addtogroup USBH_LIB_CORE
+* @{
+*/
+
+/** @defgroup USBH_PIPES
+ * @brief This file includes opening and closing Pipes
+ * @{
+ */
+
+/** @defgroup USBH_PIPES_Private_Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_PIPES_Private_TypesDefinitions
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_PIPES_Private_Functions
+ * @{
+ */
+static uint16_t USBH_GetFreePipe(USBH_HandleTypeDef *phost);
+
+
+/**
+ * @brief USBH_Open_Pipe
+ * Open a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @param dev_address: USB Device address allocated to attached device
+ * @param speed : USB device speed (Full/Low)
+ * @param ep_type: end point type (Bulk/int/ctl)
+ * @param mps: max pkt size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_OpenPipe(USBH_HandleTypeDef *phost, uint8_t pipe_num,
+ uint8_t epnum, uint8_t dev_address,
+ uint8_t speed, uint8_t ep_type, uint16_t mps)
+{
+ USBH_LL_OpenPipe(phost, pipe_num, epnum, dev_address, speed, ep_type, mps);
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_ClosePipe
+ * Close a pipe
+ * @param phost: Host Handle
+ * @param pipe_num: Pipe Number
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_ClosePipe(USBH_HandleTypeDef *phost, uint8_t pipe_num)
+{
+ USBH_LL_ClosePipe(phost, pipe_num);
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_Alloc_Pipe
+ * Allocate a new Pipe
+ * @param phost: Host Handle
+ * @param ep_addr: End point for which the Pipe to be allocated
+ * @retval Pipe number
+ */
+uint8_t USBH_AllocPipe(USBH_HandleTypeDef *phost, uint8_t ep_addr)
+{
+ uint16_t pipe;
+
+ pipe = USBH_GetFreePipe(phost);
+
+ if (pipe != 0xFFFFU)
+ {
+ phost->Pipes[pipe & 0xFU] = 0x8000U | ep_addr;
+ }
+
+ return (uint8_t)pipe;
+}
+
+
+/**
+ * @brief USBH_Free_Pipe
+ * Free the USB Pipe
+ * @param phost: Host Handle
+ * @param idx: Pipe number to be freed
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_FreePipe(USBH_HandleTypeDef *phost, uint8_t idx)
+{
+ if (idx < 11U)
+ {
+ phost->Pipes[idx] &= 0x7FFFU;
+ }
+
+ return USBH_OK;
+}
+
+
+/**
+ * @brief USBH_GetFreePipe
+ * @param phost: Host Handle
+ * Get a free Pipe number for allocation to a device endpoint
+ * @retval idx: Free Pipe number
+ */
+static uint16_t USBH_GetFreePipe(USBH_HandleTypeDef *phost)
+{
+ uint8_t idx = 0U;
+
+ for (idx = 0U ; idx < 11U ; idx++)
+ {
+ if ((phost->Pipes[idx] & 0x8000U) == 0U)
+ {
+ return (uint16_t)idx;
+ }
+ }
+
+ return 0xFFFFU;
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Release_Notes.html b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Release_Notes.html
new file mode 100644
index 000000000000..beaf93952316
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/STM32_USB_Host_Library/Release_Notes.html
@@ -0,0 +1,1235 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+Release Notes for STM32 USB Host Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back to Release page
+
+
+
+
+ Release Notes for STM32 USB Host Library
+ Copyright
+ 2015 STMicroelectronics
+
+
+
+
+
+
+
+
+ Update History V3.3.4 / 08-January-2020 Main Changes
Core driver: Improve enumeration phase and avoid silent responses. Add device reset trial mechanism during enumeration phase. MSC Class usbh_msc.c update max_lun field to be uint8_t instead of uint32_t. HID Class Get
+HID descriptor by parsing the device descriptor in order to improve
+interoperability with buggy devices that Stall host Get HID descriptor
+request. V3.3.3 / 29-April-2019 Main Changes
Fix misra-C 2012 high severity violations Core driver: usbh_core.c: Rework USB host Core process in order to improve Device connection / disconnection robustness MSC Class usbh_msc.c Update USBH_MSC_GetMaxLUN() to prevent corruption of supported LUNs HID Class prevent
+race between USB buffer and Application fifo buffer, this was ensured
+by allocating a dedicated buffer for received report Prevent overflow on USB buffer for devices that could have report size greater than 4bytes V3.3.2 / 24-January-2019 Main Changes
Core driver: usbh_core.c:
+fix on USBH_Deinit() API, prevent freeing pActiveClass->pData
+pointer during host Deinit, this is manged by the Class drivers. V3.3.1 / 09-July-2018 Main Changes
Fix interoperability issue with HP mouse Add compatibility with FreeRTOS CMSIS V2 API changesUpdate License section and add link to get copy of ST Ultimate Liberty license SLA0044 V3.3.0 / 23-january-2018
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Main Changes
Update license section to Ultimate Liberty Update some functions to be MISRA-C 2004 compliant Improve USB Core enumeration state machine Fix Device fast plug/unplug issue Improve interoperability with non compliant USB devices Add support of Host set remote wakeup enable feature Fix USB Host MSC set correct sector size MSC: Set correct LUN number if returned LUN number exceeds max supported value V3.2.2 / 07-July-2015
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Main
+Changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSC Class usbh_msc.c Fix MSC Get Ready Delay issue V3.2.1 / 26-June-2015
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Main
+Changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Core driver
+
+ usbh_def.h:
+update USBH_MAX_PIPES_NBR literal definition to be conditioned by
+#ifndef directive, to allow application code to change its value (i.e.
+in the compiler preprocessor)
+
+
+ MSC Class
+
+ usbh_msc.c
+
+ Update USBH_MSC_GetMaxLUN() to return the correct number of supported LUNs (was returning 0xFF)
+ Fix timeout calculation issue
+
+
+
+
+ usbh_msc.h:
+update MAX_SUPPORTED_LUN literal definition to be conditioned by
+#ifndef directive, to allow application code to change its value
+(i.e.in the compiler preprocessor)
+
+ HID Class
+
+ usbh_hid.h: fix HID's handle “timer” type to uint32_t instead of uint16_t
+ MTP Class
+
+ usbh_mtp.c : Fix timeout calculation issue
+
+
+
+
+
+
+ V3.2.0 / 04-November-2014
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Main
+Changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Update all drivers to be C++ compliant
+
+ Core driver
+
+ usbh_core.c: remove HOST_IDLE state in USBH_LL_Connect() function
+
+
+ MSC class
+
+ Update to manage correctly older USB Keys that do not support GetMaxLun request
+
+Miscellaneous source code comments update
+
+
+ V3.1.0 / 19-June-2014
+
+
+
+
+
+ Main
+Changes
+
+
+
+
+
+
+
+
+
+
+ Core driver
+
+ Add a new define USBH_PROCESS_STACK_SIZE in the usbh_conf.h
+file to change the default internal USB host process stack. Note that
+by omitting this define, the default stack size (2KB) is used
+
+ Add a user callback to handle unrecoverable error case in the application
+
+
+ Remove the wrong check on the interface descriptor index in the USBH_FindInterface() function
+
+
+ All classes
+
+Update class description in files comment by adding reference to the used USB class specification revision
+
+ Audio, CDC and MTP classes
+
+
+ Add full RTOS support by handling state transitions through OS messages
+
+
+ HID class
+
+ Add new API USBH_HID_GetPollInterval() to allow user to retrieve the needed poll time (interval between two USBD_HID_SendReport() )
+
+ Audio class
+
+ Add a new weak callback USBH_AUDIO_BufferEmptyCallback() to indicate the end of audio data processing on the user buffer
+
+ MSC class
+
+Return mass storage device capacity in Bytes in the user log message instead of MBytes
+
+
+
+
+
+ V3.0.0 / 18-February-2014
+
+
+
+ Main
+Changes
+
+
+
+
+
+
+
+
+ Major update
+based on STM32Cube specification: Library Core, Classes architecture and APIs
+modified vs. V2.1.0, and thus the 2 versions are not compatible.
+
+ This version has to be used only with STM32Cube based development
+
+V2.1.0 / 19-March-2012
+ Main
+Changes
+
+ Official support of STM32F4xx devicesAll source files: license disclaimer text update and add link to the License file on ST Internet Add ISR structure to link the low level driver to the Host library Change length parameter in the I/O operations to handle large amount of data Enhance the configuration descriptor parsing method to take into account multi interface devices HID class Remove blocking even frame synchronization loop MSC class Handle correctly the BOT transfer with length < max length Handle multi sector length data in the FAT FS interface Miscellaneous bug fix V2.0.0 / 22-July-2011 Main
+Changes
+Second official version supporting STM32F105/7 and STM32F2xx devices Add support for STM32F2xx devices Add multi interface feature Add dynamic configuration parsing Add
+USBH_DeAllocate_AllChannel function in the Host channel management
+layer to clean up channels allocation table when de-initializing the
+library Change the core layer to stop correctly the host core and free all allocated channels Add usbh_conf.h file in the application layer to customize some user parameters V1.0.0 - 11/29/2010
+License This
+software component is licensed by ST under Ultimate Liberty license
+SLA0044, the "License"; You may not use this component except in
+compliance with the License. You may obtain a copy of the License at:
http://www.st.com/SLA0044
+
+
+
+ For
+ complete documentation on STM32
+ Microcontrollers visit www.st.com/STM32
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.cpp b/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.cpp
new file mode 100644
index 000000000000..70ab4d76b0fe
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.cpp
@@ -0,0 +1,482 @@
+/**
+ ******************************************************************************
+ * @file usbh_conf.cpp
+ * @author MCD Application Team
+ * @brief This file implements the board support package for the USB host library
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+/* Includes ------------------------------------------------------------------*/
+
+#include "../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+#include "STM32_USB_Host_Library/Core/Inc/usbh_core.h"
+#include "usbh_pins.h"
+
+HCD_HandleTypeDef Marlinhcd;
+
+/**
+ * @brief SOF callback.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_LL_IncTimer((USBH_HandleTypeDef *)(hhcd->pData));
+}
+
+/**
+ * @brief Connection Event callback.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_DbgLog("Connected!\r\n");
+ USBH_LL_Connect((USBH_HandleTypeDef *)(hhcd->pData));
+}
+
+/**
+ * @brief Disconnection Event callback.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_DbgLog("Disconnected!\r\n");
+ USBH_LL_Disconnect((USBH_HandleTypeDef *)(hhcd->pData));
+}
+
+/**
+ * @brief Port Enabled Event callback.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_PortEnabled_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_DbgLog("Prot enabled!\r\n");
+ USBH_LL_PortEnabled((USBH_HandleTypeDef *)(hhcd->pData));
+}
+
+/**
+ * @brief Port Disabled Event callback.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_PortDisabled_Callback(HCD_HandleTypeDef *hhcd)
+{
+ USBH_DbgLog("Prot disabled!\r\n");
+ USBH_LL_PortDisabled((USBH_HandleTypeDef *)(hhcd->pData));
+}
+
+/**
+ * @brief Notify URB state change callback.
+ * @param hhcd HCD handle
+ * @param chnum Channel number.
+ * This parameter can be a value from 1 to 15
+ * @param urb_state:
+ * This parameter can be one of these values:
+ * URB_IDLE/
+ * URB_DONE/
+ * URB_NOTREADY/
+ * URB_NYET/
+ * URB_ERROR/
+ * URB_STALL/
+ * @retval None
+ */
+void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hhcd);
+ UNUSED(chnum);
+ UNUSED(urb_state);
+}
+
+/**
+ * @brief Initialize the HCD MSP.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_MspInit(HCD_HandleTypeDef *hhcd)
+{
+ if(hhcd->Instance==USB_OTG_FS)
+ {
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ __HAL_RCC_USB_OTG_FS_CLK_ENABLE();
+ HAL_NVIC_SetPriority(OTG_FS_IRQn, 1, 0);
+ HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+ }
+ else if (hhcd->Instance == USB_OTG_HS)
+ {
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15);
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+ __HAL_RCC_USB_OTG_HS_CLK_ENABLE();
+ HAL_NVIC_SetPriority(OTG_HS_IRQn, 1, 0);
+ HAL_NVIC_EnableIRQ(OTG_HS_IRQn);
+ }
+}
+
+/**
+ * @brief DeInitialize the HCD MSP.
+ * @param hhcd HCD handle
+ * @retval None
+ */
+void HAL_HCD_MspDeInit(HCD_HandleTypeDef *hhcd)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hhcd);
+}
+
+// OTG host IRQ
+extern "C" USB_OTG_ISR()
+{
+ HAL_HCD_IRQHandler(&Marlinhcd);
+}
+
+/**
+ * @brief USBH_LL_Init
+ * Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost)
+{
+ Marlinhcd.Instance = USB_OTG_INSTANCE;
+ Marlinhcd.Init.Host_channels = 12;
+ Marlinhcd.Init.dma_enable = DISABLE;
+ Marlinhcd.Init.low_power_enable = DISABLE;
+ Marlinhcd.Init.phy_itface = HCD_PHY_EMBEDDED;
+ Marlinhcd.Init.Sof_enable = DISABLE;
+ Marlinhcd.Init.speed = HCD_SPEED_FULL;
+ Marlinhcd.Init.vbus_sensing_enable = DISABLE;
+ Marlinhcd.Init.lpm_enable = DISABLE;
+
+ Marlinhcd.pData = phost;
+ phost->pData = &Marlinhcd;
+
+ HAL_HCD_Init(&Marlinhcd);
+
+ USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(&Marlinhcd));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_DeInit
+ * De-Initialize the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_DeInit(USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_DeInit((HCD_HandleTypeDef *)(phost->pData));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Start
+ * Start the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_Start((HCD_HandleTypeDef *)(phost->pData));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_Stop
+ * Stop the Low Level portion of the Host driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_Stop(USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_Stop((HCD_HandleTypeDef *)(phost->pData));
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetSpeed
+ * Return the USB Host Speed from the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Speeds
+ */
+USBH_SpeedTypeDef USBH_LL_GetSpeed(USBH_HandleTypeDef *phost)
+{
+ USBH_SpeedTypeDef speed;
+
+ switch (HAL_HCD_GetCurrentSpeed((HCD_HandleTypeDef *)(phost->pData)))
+ {
+ case 0:
+ speed = USBH_SPEED_HIGH;
+ USBH_DbgLog("USB Host [HS]\r\n");
+ break;
+
+ case 1:
+ speed = USBH_SPEED_FULL;
+ USBH_DbgLog("USB Host [FS]\r\n");
+ break;
+
+ case 2:
+ speed = USBH_SPEED_LOW;
+ USBH_DbgLog("USB Host [LS]\r\n");
+ break;
+
+ default:
+ speed = USBH_SPEED_FULL;
+ USBH_DbgLog("USB Host [FS]\r\n");
+ break;
+ }
+
+ return speed;
+}
+
+/**
+ * @brief USBH_LL_ResetPort
+ * Reset the Host Port of the Low Level Driver.
+ * @param phost: Host handle
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ResetPort(USBH_HandleTypeDef *phost)
+{
+ HAL_HCD_ResetPort((HCD_HandleTypeDef *)(phost->pData));
+ USBH_DbgLog("USB Reset Port\r\n");
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetLastXferSize
+ * Return the last transferred packet size.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval Packet Size
+ */
+uint32_t USBH_LL_GetLastXferSize(USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return HAL_HCD_HC_GetXferCount((HCD_HandleTypeDef *)(phost->pData), pipe);
+}
+
+/**
+ * @brief USBH_LL_OpenPipe
+ * Open a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @param epnum: Endpoint Number
+ * @param dev_address: Device USB address
+ * @param speed: Device Speed
+ * @param ep_type: Endpoint Type
+ * @param mps: Endpoint Max Packet Size
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_OpenPipe(USBH_HandleTypeDef *phost,
+ uint8_t pipe_num,
+ uint8_t epnum,
+ uint8_t dev_address,
+ uint8_t speed,
+ uint8_t ep_type,
+ uint16_t mps)
+{
+ HAL_HCD_HC_Init((HCD_HandleTypeDef *)(phost->pData), pipe_num, epnum, dev_address, speed, ep_type, mps);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_ClosePipe
+ * Close a pipe of the Low Level Driver.
+ * @param phost: Host handle
+ * @param pipe_num: Pipe index
+ * @retval USBH Status
+ */
+USBH_StatusTypeDef USBH_LL_ClosePipe(USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ HAL_HCD_HC_Halt((HCD_HandleTypeDef *)(phost->pData), pipe);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SubmitURB
+ * Submit a new URB to the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @param direction : Channel number
+ * This parameter can be one of the these values:
+ * 0 : Output
+ * 1 : Input
+ * @param ep_type : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg EP_TYPE_CTRL: Control type
+ * @arg EP_TYPE_ISOC: Isochronous type
+ * @arg EP_TYPE_BULK: Bulk type
+ * @arg EP_TYPE_INTR: Interrupt type
+ * @param token : Endpoint Type
+ * This parameter can be one of the these values:
+ * @arg 0: PID_SETUP
+ * @arg 1: PID_DATA
+ * @param pbuff : pointer to URB data
+ * @param length : Length of URB data
+ * @param do_ping : activate do ping protocol (for high speed only)
+ * This parameter can be one of the these values:
+ * 0 : do ping inactive
+ * 1 : do ping active
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_SubmitURB(USBH_HandleTypeDef *phost,
+ uint8_t pipe,
+ uint8_t direction,
+ uint8_t ep_type,
+ uint8_t token,
+ uint8_t *pbuff,
+ uint16_t length,
+ uint8_t do_ping)
+{
+ HAL_HCD_HC_SubmitRequest((HCD_HandleTypeDef *)(phost->pData), pipe, direction, ep_type, token, pbuff, length, do_ping);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetURBState
+ * Get a URB state from the low level driver.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * This parameter can be a value from 1 to 15
+ * @retval URB state
+ * This parameter can be one of the these values:
+ * @arg URB_IDLE
+ * @arg URB_DONE
+ * @arg URB_NOTREADY
+ * @arg URB_NYET
+ * @arg URB_ERROR
+ * @arg URB_STALL
+ */
+USBH_URBStateTypeDef USBH_LL_GetURBState(USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ return (USBH_URBStateTypeDef) HAL_HCD_HC_GetURBState((HCD_HandleTypeDef *)(phost->pData), pipe);
+}
+
+/**
+ * @brief USBH_LL_DriverVBUS
+ * Drive VBUS.
+ * @param phost: Host handle
+ * @param state : VBUS state
+ * This parameter can be one of the these values:
+ * 0 : VBUS Active
+ * 1 : VBUS Inactive
+ * @retval Status
+ */
+
+USBH_StatusTypeDef USBH_LL_DriverVBUS(USBH_HandleTypeDef *phost, uint8_t state)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(phost);
+ UNUSED(state);
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_SetToggle
+ * Set toggle for a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @param pipe_num: Pipe index
+ * @param toggle: toggle (0/1)
+ * @retval Status
+ */
+USBH_StatusTypeDef USBH_LL_SetToggle(USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
+{
+ if (Marlinhcd.hc[pipe].ep_is_in)
+ {
+ Marlinhcd.hc[pipe].toggle_in = toggle;
+ }
+ else
+ {
+ Marlinhcd.hc[pipe].toggle_out = toggle;
+ }
+
+ return USBH_OK;
+}
+
+/**
+ * @brief USBH_LL_GetToggle
+ * Return the current toggle of a pipe.
+ * @param phost: Host handle
+ * @param pipe: Pipe index
+ * @retval toggle (0/1)
+ */
+uint8_t USBH_LL_GetToggle(USBH_HandleTypeDef *phost, uint8_t pipe)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(phost);
+ UNUSED(pipe);
+
+ uint8_t toggle = 0U;
+
+ if (Marlinhcd.hc[pipe].ep_is_in)
+ {
+ toggle = Marlinhcd.hc[pipe].toggle_in;
+ }
+ else
+ {
+ toggle = Marlinhcd.hc[pipe].toggle_out;
+ }
+
+ return toggle;
+}
+/**
+ * @brief USBH_Delay
+ * Delay routine for the USB Host Library
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void USBH_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.h b/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.h
new file mode 100644
index 000000000000..e1f935e7e71f
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/usbh_conf.h
@@ -0,0 +1,149 @@
+/**
+ ******************************************************************************
+ * @file usbh_conf_template.h
+ * @author MCD Application Team
+ * @brief Header file for usbh_conf_template.c
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBH_CONF_H
+#define __USBH_CONF_H
+
+/* Includes ------------------------------------------------------------------*/
+// #include "stm32fxxx.h" /* replace 'stm32xxx' with your HAL driver header filename, ex: stm32f4xx.h */
+#ifdef STM32F4
+ #include "stm32f4xx_hal.h"
+#else
+ #error "For now USB host MSC is only supported on STM32F4."
+#endif
+#include
+#include
+#include
+
+/** @addtogroup STM32_USB_HOST_LIBRARY
+ * @{
+ */
+
+/** @defgroup USBH_CONF
+ * @brief usb host low level driver configuration file
+ * @{
+ */
+
+/** @defgroup USBH_CONF_Exported_Defines
+ * @{
+ */
+
+#define USBH_MAX_NUM_ENDPOINTS 2U
+#define USBH_MAX_NUM_INTERFACES 2U
+#define USBH_MAX_NUM_CONFIGURATION 1U
+#define USBH_KEEP_CFG_DESCRIPTOR 1U
+#define USBH_MAX_NUM_SUPPORTED_CLASS 1U
+#define USBH_MAX_SIZE_CONFIGURATION 0x200U
+#define USBH_MAX_DATA_BUFFER 0x200U
+#define USBH_DEBUG_LEVEL 0U
+#define USBH_USE_OS 0U
+
+/** @defgroup USBH_Exported_Macros
+ * @{
+ */
+
+/* Memory management macros */
+#define USBH_malloc malloc
+#define USBH_free free
+#define USBH_memset memset
+#define USBH_memcpy memcpy
+
+/* DEBUG macros */
+#if (USBH_DEBUG_LEVEL > 0U)
+#define USBH_UsrLog(...) do { \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+} while (0)
+#else
+#define USBH_UsrLog(...) do {} while (0)
+#endif
+
+#if (USBH_DEBUG_LEVEL > 1U)
+
+#define USBH_ErrLog(...) do { \
+ printf("ERROR: ") ; \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+} while (0)
+#else
+#define USBH_ErrLog(...) do {} while (0)
+#endif
+
+#if (USBH_DEBUG_LEVEL > 2U)
+#define USBH_DbgLog(...) do { \
+ printf("DEBUG : ") ; \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+} while (0)
+#else
+#define USBH_DbgLog(...) do {} while (0)
+#endif
+
+/**
+ * @}
+ */
+
+
+
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CONF_Exported_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+
+/** @defgroup USBH_CONF_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_Variables
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup USBH_CONF_Exported_FunctionsPrototype
+ * @{
+ */
+/**
+ * @}
+ */
+
+#endif /* __USBH_CONF_TEMPLATE_H */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/usbh_pins.h b/Marlin/src/HAL/STM32/usb_hostlib/usbh_pins.h
new file mode 100644
index 000000000000..7172a1173418
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/usbh_pins.h
@@ -0,0 +1,45 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+/**
+ * Define USB HOST Pins: OTG_DM, OTG_DP
+ */
+#ifndef USB_OTG_DM_PIN
+ #define USB_OTG_DM_PIN PA11
+#endif
+#ifndef USB_OTG_DP_PIN
+ #define USB_OTG_DP_PIN PA12
+#endif
+
+#if USB_OTG_DM_PIN == PA11 && USB_OTG_DP_PIN == PA12
+ #define USB_OTG_ID FS
+#elif USB_OTG_DM_PIN == PB14 && USB_OTG_DP_PIN == PB15
+ #define USB_OTG_ID HS // HS port used for FS function
+#else
+ #error "USB OTG pins error!"
+#endif
+
+#define __USB_OTG_ISR(n) void OTG_##n##_IRQHandler(void)
+#define _USB_OTG_ISR(n) __USB_OTG_ISR(n)
+#define USB_OTG_ISR() _USB_OTG_ISR(USB_OTG_ID)
+
+#define __USB_OTG_INSTANCE(n) USB_OTG_##n
+#define _USB_OTG_INSTANCE(n) __USB_OTG_INSTANCE(n)
+#define USB_OTG_INSTANCE _USB_OTG_INSTANCE(USB_OTG_ID)
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.cpp b/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.cpp
new file mode 100644
index 000000000000..14882ef8e203
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.cpp
@@ -0,0 +1,178 @@
+/**
+ ******************************************************************************
+ * @file usbh_usr.cpp
+ * @author MCD Application Team
+ * @brief This file implements the board support package for the USB host library
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2015 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+
+#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
+
+#include "../../../inc/MarlinConfig.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+#include "usbh_usr.h"
+#include "STM32_USB_Host_Library/Core/Inc/usbh_def.h"
+#include "STM32_USB_Host_Library/Class/MSC/Inc/usbh_msc.h"
+
+USBH_HandleTypeDef MarlinUSB_Host;
+
+uint8_t usbh_media_ready = 0;
+
+/*
+ * user callback definition
+ */
+static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
+{
+ /* USER CODE BEGIN CALL_BACK_1 */
+ switch(id)
+ {
+ case HOST_USER_CLASS_ACTIVE:
+ usbh_media_ready = 1;
+ break;
+
+ case HOST_USER_SELECT_CONFIGURATION:
+ case HOST_USER_DISCONNECTION:
+ case HOST_USER_CONNECTION:
+ default:
+ usbh_media_ready = 0;
+ break;
+ }
+ /* USER CODE END CALL_BACK_1 */
+}
+
+void USBH_HAL_Init(void)
+{
+ USBH_Init(&MarlinUSB_Host, USBH_UserProcess, 0);
+ USBH_RegisterClass(&MarlinUSB_Host, USBH_MSC_CLASS);
+ USBH_Start(&MarlinUSB_Host);
+}
+
+void USB_HAL_Loop(void)
+{
+ USBH_Process(&MarlinUSB_Host);
+}
+
+uint8_t USBH_IsConnected(void)
+{
+ return usbh_media_ready;
+}
+
+/**
+ * @brief Gets Disk Status
+ * @param lun : lun id
+ * @retval DSTATUS: Operation status, 0:ok 1:error
+ */
+uint8_t USBH_status(uint8_t lun)
+{
+ if(USBH_MSC_UnitIsReady(&MarlinUSB_Host, lun))
+ {
+ return 0; // Media ready
+ }
+ else
+ {
+ return 1; // Error
+ }
+}
+
+/**
+ * @brief Reads Sector(s)
+ * @param lun : lun id
+ * @param *buff: Data buffer to store read data
+ * @param sector: Sector address (LBA)
+ * @param count: Number of sectors to read (1..128)
+ * @retval DRESULT: Operation result, 0:ok 1:error
+ */
+uint8_t USBH_read(uint8_t lun, uint8_t *buff, uint32_t sector, uint32_t count)
+{
+ uint8_t res = 1;
+ MSC_LUNTypeDef info;
+
+ if(USBH_MSC_Read(&MarlinUSB_Host, lun, sector, buff, count) == USBH_OK)
+ {
+ res = 0; // Read successful
+ }
+ else
+ {
+ USBH_MSC_GetLUNInfo(&MarlinUSB_Host, lun, &info);
+
+ switch (info.sense.asc)
+ {
+ case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
+ case SCSI_ASC_MEDIUM_NOT_PRESENT:
+ case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
+ USBH_ErrLog ("USB Disk is not ready!");
+ res = 3; // Media not ready
+ break;
+
+ default:
+ res = 1; // Error
+ break;
+ }
+ }
+
+ return res;
+}
+
+/* USER CODE BEGIN beforeWriteSection */
+/* can be used to modify previous code / undefine following code / add new code */
+/* USER CODE END beforeWriteSection */
+
+/**
+ * @brief Writes Sector(s)
+ * @param lun : lun id
+ * @param *buff: Data to be written
+ * @param sector: Sector address (LBA)
+ * @param count: Number of sectors to write (1..128)
+ * @retval DRESULT: Operation result, 0:ok 1:error
+ */
+uint8_t USBH_write(uint8_t lun, const uint8_t *buff, uint32_t sector, uint32_t count)
+{
+ uint8_t res = 1;
+ MSC_LUNTypeDef info;
+
+ if(USBH_MSC_Write(&MarlinUSB_Host, lun, sector, (uint8_t *)buff, count) == USBH_OK)
+ {
+ res = 0; // Write successful
+ }
+ else
+ {
+ USBH_MSC_GetLUNInfo(&MarlinUSB_Host, lun, &info);
+
+ switch (info.sense.asc)
+ {
+ case SCSI_ASC_WRITE_PROTECTED:
+ USBH_ErrLog("USB Disk is Write protected!");
+ res = 2; // Write protected
+ break;
+
+ case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
+ case SCSI_ASC_MEDIUM_NOT_PRESENT:
+ case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
+ USBH_ErrLog("USB Disk is not ready!");
+ res = 3; // Media not ready
+ break;
+
+ default:
+ res = 1; // Error
+ break;
+ }
+ }
+
+ return res;
+}
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
+#endif // STM32
diff --git a/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.h b/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.h
new file mode 100644
index 000000000000..68a6414d12f1
--- /dev/null
+++ b/Marlin/src/HAL/STM32/usb_hostlib/usbh_usr.h
@@ -0,0 +1,28 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+#include
+
+void USBH_HAL_Init(void);
+void USB_HAL_Loop(void);
+
+uint8_t USBH_IsConnected(void);
+uint8_t USBH_read(uint8_t lun, uint8_t *buff, uint32_t sector, uint32_t count);
+uint8_t USBH_write(uint8_t lun, const uint8_t *buff, uint32_t sector, uint32_t count);
diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index b6282cb09835..8a3dbef1854a 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -740,7 +740,9 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
TERN_(SDSUPPORT, card.manage_media());
// Handle USB Flash Drive insert / remove
- TERN_(USB_FLASH_DRIVE_SUPPORT, Sd2Card::idle());
+ #if EITHER(USB_FLASH_DRIVE_SUPPORT, USB_HOST_MSC_FLASH_SUPPORT)
+ Sd2Card::idle();
+ #endif
// Announce Host Keepalive state (if any)
TERN_(HOST_KEEPALIVE_FEATURE, gcode.host_keepalive());
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
index bfa4007658db..2f664f81d48d 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_GTR_V1_0.h
@@ -29,6 +29,15 @@
#error "Marlin extruder/hotends limit! Increase MAX_E_STEPPERS to continue."
#endif
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+ #if ENABLED(USBCON)
+ #error "For USB host MSC make sure USBCON is not defined. Remove -DUSBCON if present."
+ #endif
+ #if SERIAL_PORT == -1 || SERIAL_PORT_2 == -1
+ #error "USB host MSC and USB emulated serial port can't be enabled on GTR V1.0 at the same time."
+ #endif
+#endif
+
#define BOARD_INFO_NAME "BTT GTR V1.0"
// Onboard I2C EEPROM
@@ -37,6 +46,12 @@
#define TP // Enable to define servo and probe pins
+//
+// USB OTG Host
+//
+#define USB_OTG_DM_PIN PA11
+#define USB_OTG_DP_PIN PA12
+
//
// Servos
//
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_1.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_1.h
index fb4b17b6fb22..71af9329f93f 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_1.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_1.h
@@ -25,6 +25,15 @@
#error "BIGTREE SKR Pro V1.1 supports up to 3 hotends / E-steppers."
#endif
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+ #if ENABLED(USBCON)
+ #error "For USB host MSC make sure USBCON is not defined. Remove -DUSBCON if present."
+ #endif
+ #if SERIAL_PORT == -1 || SERIAL_PORT_2 == -1
+ #error "USB host MSC and USB emulated serial port can't be enabled on BTT SKR Pro V1.1 at the same time."
+ #endif
+#endif
+
#define BOARD_INFO_NAME "BTT SKR Pro V1.1"
#include "pins_BTT_SKR_PRO_common.h"
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_2.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_2.h
index 615751b62d37..520461e6e3b7 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_2.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_V1_2.h
@@ -25,6 +25,15 @@
#error "BIGTREE SKR Pro V1.2 supports up to 3 hotends / E-steppers."
#endif
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+ #if ENABLED(USBCON)
+ #error "For USB host MSC make sure USBCON is not defined. Remove -DUSBCON if present."
+ #endif
+ #if SERIAL_PORT == -1 || SERIAL_PORT_2 == -1
+ #error "USB host MSC and USB emulated serial port can't be enabled on BTT SKR Pro V1.2 at the same time."
+ #endif
+#endif
+
#define BOARD_INFO_NAME "BTT SKR Pro V1.2"
#include "pins_BTT_SKR_PRO_common.h"
diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
index 235ed1edcc4c..aaa5a26b10ba 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
@@ -44,6 +44,12 @@
#define FLASH_EEPROM_LEVELING
#endif
+//
+// USB OTG Host
+//
+#define USB_OTG_DM_PIN PA11
+#define USB_OTG_DP_PIN PA12
+
//
// Servos
//
diff --git a/Marlin/src/sd/Sd2Card.cpp b/Marlin/src/sd/Sd2Card.cpp
index 491c0692c72f..47eb676e7c75 100644
--- a/Marlin/src/sd/Sd2Card.cpp
+++ b/Marlin/src/sd/Sd2Card.cpp
@@ -30,7 +30,7 @@
#include "../inc/MarlinConfig.h"
-#if ENABLED(SDSUPPORT) && NONE(USB_FLASH_DRIVE_SUPPORT, SDIO_SUPPORT)
+#if ENABLED(SDSUPPORT) && NONE(USB_FLASH_DRIVE_SUPPORT, USB_HOST_MSC_FLASH_SUPPORT, SDIO_SUPPORT)
/* Enable FAST CRC computations - You can trade speed for FLASH space if
* needed by disabling the following define */
diff --git a/Marlin/src/sd/SdVolume.h b/Marlin/src/sd/SdVolume.h
index 2d57c681c494..9a702c239f3f 100644
--- a/Marlin/src/sd/SdVolume.h
+++ b/Marlin/src/sd/SdVolume.h
@@ -36,6 +36,8 @@
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
#include "usb_flashdrive/Sd2Card_FlashDrive.h"
+#elif ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+ #include "usb_hostmsc/Sd2Card_usbhost_msc.h"
#elif ENABLED(SDIO_SUPPORT)
#include "Sd2Card_sdio.h"
#else
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
index bce84bbd3921..9c2bff55f349 100644
--- a/Marlin/src/sd/cardreader.cpp
+++ b/Marlin/src/sd/cardreader.cpp
@@ -394,7 +394,7 @@ void CardReader::mount() {
if (flag.mounted)
cdroot();
- #if ENABLED(USB_FLASH_DRIVE_SUPPORT) || PIN_EXISTS(SD_DETECT)
+ #if EITHER(USB_FLASH_DRIVE_SUPPORT, USB_HOST_MSC_FLASH_SUPPORT) || PIN_EXISTS(SD_DETECT)
else if (marlin_state != MF_INITIALIZING)
ui.set_status_P(GET_TEXT(MSG_SD_INIT_FAIL), -1);
#endif
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index dabbf719f92b..867cb0fd420f 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -281,7 +281,7 @@ class CardReader {
#endif
};
-#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+#if EITHER(USB_FLASH_DRIVE_SUPPORT, USB_HOST_MSC_FLASH_SUPPORT)
#define IS_SD_INSERTED() Sd2Card::isInserted()
#elif PIN_EXISTS(SD_DETECT)
#define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE)
diff --git a/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.cpp b/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.cpp
new file mode 100644
index 000000000000..93731c72417e
--- /dev/null
+++ b/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.cpp
@@ -0,0 +1,70 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_HOST_MSC_FLASH_SUPPORT)
+
+#include "Sd2Card_usbhost_msc.h"
+#include HAL_PATH(../../HAL, usb_hostlib/usbh_usr.h)
+
+#include "../../MarlinCore.h"
+#include "../../core/serial.h"
+#include "../../module/temperature.h"
+
+// idle() is always called in Marlin idle()
+void Sd2Card::idle() {
+
+ // Hareware IO init once time after startup
+ static uint8_t firstCall = 1;
+ if (firstCall) {
+ USBH_HAL_Init();
+ firstCall = 0;
+ }
+
+ USB_HAL_Loop();
+}
+
+// Marlin calls this function to check whether an USB drive is inserted.
+// This is equivalent to polling the SD_DETECT when using SD cards.
+bool Sd2Card::isInserted() {
+ return USBH_IsConnected();
+}
+
+// Marlin calls this to initialize an SD card once it is inserted.
+bool Sd2Card::init(const uint8_t, const pin_t) {
+ return isInserted();
+}
+
+bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
+ if (!isInserted()) return false;
+
+ return (USBH_read(0, dst, block, 1) == 0);
+}
+
+bool Sd2Card::writeBlock(uint32_t block, const uint8_t* src) {
+ if (!isInserted()) return false;
+
+ return (USBH_write(0, src, block, 1) == 0);
+}
+
+#endif // USB_HOST_MSC_FLASH_SUPPORT
diff --git a/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.h b/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.h
new file mode 100644
index 000000000000..443be4a61932
--- /dev/null
+++ b/Marlin/src/sd/usb_hostmsc/Sd2Card_usbhost_msc.h
@@ -0,0 +1,43 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#pragma once
+
+/**
+ * \file
+ * \brief Sd2Card class for V2 SD/SDHC cards
+ */
+
+#include "../SdFatConfig.h"
+#include "../SdInfo.h"
+
+class Sd2Card {
+ public:
+
+ bool init(const uint8_t sckRateID=0, const pin_t chipSelectPin=0);
+
+ static void idle();
+
+ bool readBlock(uint32_t block, uint8_t* dst);
+ bool writeBlock(uint32_t blockNumber, const uint8_t* src);
+
+ static bool isInserted();
+};
diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/ldscript.ld b/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/ldscript.ld
index 0c060d175180..f96475d465da 100644
--- a/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/BIGTREE_BTT002/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_GTR_V1/ldscript.ld b/buildroot/share/PlatformIO/variants/BIGTREE_GTR_V1/ldscript.ld
index 0c060d175180..f96475d465da 100644
--- a/buildroot/share/PlatformIO/variants/BIGTREE_GTR_V1/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/BIGTREE_GTR_V1/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h
index e0e8239aac08..afe6e308e7b8 100644
--- a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h
+++ b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/hal_conf_extra.h
@@ -13,6 +13,7 @@
#define HAL_TIM_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_HCD_MODULE_ENABLED // USB Host
//#define HAL_UART_MODULE_ENABLED // by default
//#define HAL_PCD_MODULE_ENABLED // Since STM32 v3.10700.191028 this is automatically added if any type of USB is enabled (as in Arduino IDE)
@@ -44,7 +45,6 @@
#undef HAL_IRDA_MODULE_ENABLED
#undef HAL_SMARTCARD_MODULE_ENABLED
#undef HAL_WWDG_MODULE_ENABLED
-#undef HAL_HCD_MODULE_ENABLED
#undef HAL_FMPI2C_MODULE_ENABLED
#undef HAL_SPDIFRX_MODULE_ENABLED
#undef HAL_DFSDM_MODULE_ENABLED
diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/ldscript.ld b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/ldscript.ld
index 0c060d175180..f96475d465da 100644
--- a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/FLY_F407ZG/ldscript.ld b/buildroot/share/PlatformIO/variants/FLY_F407ZG/ldscript.ld
index 40abfe19b574..35c0d3daffea 100644
--- a/buildroot/share/PlatformIO/variants/FLY_F407ZG/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/FLY_F407ZG/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F103Vx/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_F103Vx/ldscript.ld
index c9197c8b451a..7f1a34f45681 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_F103Vx/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/MARLIN_F103Vx/ldscript.ld
@@ -23,7 +23,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2019 STMicroelectronics
+** © COPYRIGHT(c) 2019 STMicroelectronics
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/hal_conf_custom.h b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/hal_conf_custom.h
index 014943f311ed..b14a6bd0969d 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/hal_conf_custom.h
+++ b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/hal_conf_custom.h
@@ -5,8 +5,8 @@
******************************************************************************
* @attention
*
- * © Copyright (c) 2017 STMicroelectronics.
- * All rights reserved.
+ * Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/ldscript.ld
index 09088b622c87..7b553e12439a 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/MARLIN_F103Zx/ldscript.ld
@@ -23,7 +23,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2019 STMicroelectronics
+** © COPYRIGHT(c) 2019 STMicroelectronics
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F407VE/hal_conf_custom.h b/buildroot/share/PlatformIO/variants/MARLIN_F407VE/hal_conf_custom.h
index 92e9fecb4d63..8a8930be667a 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_F407VE/hal_conf_custom.h
+++ b/buildroot/share/PlatformIO/variants/MARLIN_F407VE/hal_conf_custom.h
@@ -5,8 +5,8 @@
******************************************************************************
* @attention
*
- * © Copyright (c) 2017 STMicroelectronics.
- * All rights reserved.
+ * Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_F407VE/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_F407VE/ldscript.ld
index efe2db5cd472..c4da3ba1fad3 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_F407VE/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/MARLIN_F407VE/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld b/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld
index 2a61072cb17e..5dfe50afee19 100644
--- a/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/MARLIN_FYSETC_S6/ldscript.ld
@@ -21,7 +21,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
index 0c7781997fef..188be7b327e6 100644
--- a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
+++ b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/hal_conf_custom.h
@@ -5,8 +5,8 @@
******************************************************************************
* @attention
*
- * © Copyright (c) 2017 STMicroelectronics.
- * All rights reserved.
+ * Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
diff --git a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/ldscript.ld b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/ldscript.ld
index f20a047c6574..31d16fd30201 100644
--- a/buildroot/share/PlatformIO/variants/STEVAL_F401VE/ldscript.ld
+++ b/buildroot/share/PlatformIO/variants/STEVAL_F401VE/ldscript.ld
@@ -20,7 +20,7 @@
*****************************************************************************
** @attention
**
-** © COPYRIGHT(c) 2014 Ac6
+** © COPYRIGHT(c) 2014 Ac6
**
** Redistribution and use in source and binary forms, with or without modification,
** are permitted provided that the following conditions are met:
diff --git a/platformio.ini b/platformio.ini
index 52310e6b8198..47493f2d1be3 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -60,6 +60,7 @@ default_src_filter = + - - +
-
-
-
+ - -
-
-
-
@@ -273,6 +274,7 @@ TOUCH_UI_FTDI_EVE = src_filter=+
EXTUI_EXAMPLE = src_filter=+
MALYAN_LCD = src_filter=+
USB_FLASH_DRIVE_SUPPORT = src_filter=+
+USB_HOST_MSC_FLASH_SUPPORT = src_filter=+ +
AUTO_BED_LEVELING_BILINEAR = src_filter=+
AUTO_BED_LEVELING_(3POINT|(BI)?LINEAR) = src_filter=+
MESH_BED_LEVELING = src_filter=+ +