diff options
Diffstat (limited to 'Middlewares/ST/STM32_USB_Device_Library/Class')
8 files changed, 3121 insertions, 0 deletions
diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h new file mode 100755 index 0000000..c9c26cb --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h @@ -0,0 +1,137 @@ +/** + ****************************************************************************** + * @file usbd_msc.h + * @author MCD Application Team + * @brief Header for the usbd_msc.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_H +#define __USBD_MSC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_ioreq.h" + +/** @addtogroup USBD_MSC_BOT + * @{ + */ + +/** @defgroup USBD_MSC + * @brief This file is the Header file for usbd_msc.c + * @{ + */ + + +/** @defgroup USBD_BOT_Exported_Defines + * @{ + */ +/* MSC Class Config */ +#ifndef MSC_MEDIA_PACKET +#define MSC_MEDIA_PACKET 512U +#endif /* MSC_MEDIA_PACKET */ + +#define MSC_MAX_FS_PACKET 0x40U +#define MSC_MAX_HS_PACKET 0x200U + +#define BOT_GET_MAX_LUN 0xFE +#define BOT_RESET 0xFF +#define USB_MSC_CONFIG_DESC_SIZ 32 + +#ifndef MSC_EPIN_ADDR +#define MSC_EPIN_ADDR 0x81U +#endif /* MSC_EPIN_ADDR */ + +#ifndef MSC_EPOUT_ADDR +#define MSC_EPOUT_ADDR 0x01U +#endif /* MSC_EPOUT_ADDR */ + +#ifndef MSC_BOT_MAX_LUN +#define MSC_BOT_MAX_LUN 0x2U +#endif /* MSC_BOT_MAX_LUN */ + +/** + * @} + */ + +/** @defgroup USB_CORE_Exported_Types + * @{ + */ +typedef struct _USBD_STORAGE +{ + int8_t (* Init)(uint8_t lun); + int8_t (* GetCapacity)(uint8_t lun, uint32_t *block_num, uint16_t *block_size); + int8_t (* IsReady)(uint8_t lun); + int8_t (* IsWriteProtected)(uint8_t lun); + int8_t (* Read)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); + int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); + int8_t (* GetMaxLun)(void); + int8_t *pInquiry; + +} USBD_StorageTypeDef; + +typedef struct +{ + uint16_t size; + uint32_t nbr; + uint32_t addr; + uint32_t len; +} USBD_MSC_BOT_LUN_TypeDef; + +typedef struct +{ + uint32_t max_lun; + uint32_t interface; + uint8_t bot_state; + uint8_t bot_status; + uint32_t bot_data_length; + uint8_t bot_data[MSC_MEDIA_PACKET]; + USBD_MSC_BOT_CBWTypeDef cbw; + USBD_MSC_BOT_CSWTypeDef csw; + + USBD_SCSI_SenseTypeDef scsi_sense [SENSE_LIST_DEEPTH]; + uint8_t scsi_sense_head; + uint8_t scsi_sense_tail; + uint8_t scsi_medium_state; + + USBD_MSC_BOT_LUN_TypeDef scsi_blk[MSC_BOT_MAX_LUN]; +} USBD_MSC_BOT_HandleTypeDef; + +/* Structure for MSC process */ +extern USBD_ClassTypeDef USBD_MSC; +#define USBD_MSC_CLASS &USBD_MSC + +uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, + USBD_StorageTypeDef *fops); +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_MSC_H */ +/** + * @} + */ diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_bot.h b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_bot.h new file mode 100755 index 0000000..8550a39 --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_bot.h @@ -0,0 +1,146 @@ +/** + ****************************************************************************** + * @file usbd_msc_bot.h + * @author MCD Application Team + * @brief Header for the usbd_msc_bot.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_BOT_H +#define __USBD_MSC_BOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup MSC_BOT + * @brief This file is the Header file for usbd_msc_bot.c + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ +#define USBD_BOT_IDLE 0U /* Idle state */ +#define USBD_BOT_DATA_OUT 1U /* Data Out state */ +#define USBD_BOT_DATA_IN 2U /* Data In state */ +#define USBD_BOT_LAST_DATA_IN 3U /* Last Data In Last */ +#define USBD_BOT_SEND_DATA 4U /* Send Immediate data */ +#define USBD_BOT_NO_DATA 5U /* No data Stage */ + +#define USBD_BOT_CBW_SIGNATURE 0x43425355U +#define USBD_BOT_CSW_SIGNATURE 0x53425355U +#define USBD_BOT_CBW_LENGTH 31U +#define USBD_BOT_CSW_LENGTH 13U +#define USBD_BOT_MAX_DATA 256U + +/* CSW Status Definitions */ +#define USBD_CSW_CMD_PASSED 0x00U +#define USBD_CSW_CMD_FAILED 0x01U +#define USBD_CSW_PHASE_ERROR 0x02U + +/* BOT Status */ +#define USBD_BOT_STATUS_NORMAL 0U +#define USBD_BOT_STATUS_RECOVERY 1U +#define USBD_BOT_STATUS_ERROR 2U + + +#define USBD_DIR_IN 0U +#define USBD_DIR_OUT 1U +#define USBD_BOTH_DIR 2U + +/** + * @} + */ + +/** @defgroup MSC_CORE_Private_TypesDefinitions + * @{ + */ + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataLength; + uint8_t bmFlags; + uint8_t bLUN; + uint8_t bCBLength; + uint8_t CB[16]; + uint8_t ReservedForAlign; +} USBD_MSC_BOT_CBWTypeDef; + + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataResidue; + uint8_t bStatus; + uint8_t ReservedForAlign[3]; +} USBD_MSC_BOT_CSWTypeDef; + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_Types + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_CORE_Exported_FunctionsPrototypes + * @{ + */ +void MSC_BOT_Init(USBD_HandleTypeDef *pdev); +void MSC_BOT_Reset(USBD_HandleTypeDef *pdev); +void MSC_BOT_DeInit(USBD_HandleTypeDef *pdev); +void MSC_BOT_DataIn(USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_DataOut(USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_SendCSW(USBD_HandleTypeDef *pdev, + uint8_t CSW_Status); + +void MSC_BOT_CplClrFeature(USBD_HandleTypeDef *pdev, + uint8_t epnum); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_MSC_BOT_H */ +/** + * @} + */ + +/** + * @} + */ + diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_data.h b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_data.h new file mode 100755 index 0000000..a321c91 --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_data.h @@ -0,0 +1,106 @@ +/** + ****************************************************************************** + * @file usbd_msc_data.h + * @author MCD Application Team + * @brief Header for the usbd_msc_data.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_DATA_H +#define __USBD_MSC_DATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_INFO + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_INFO_Exported_Defines + * @{ + */ +#define MODE_SENSE6_LEN 0x04U +#define MODE_SENSE10_LEN 0x08U +#define LENGTH_INQUIRY_PAGE00 0x06U +#define LENGTH_INQUIRY_PAGE80 0x08U +#define LENGTH_FORMAT_CAPACITIES 0x14U +#define DIAGNOSTIC_DATA_LEN 0x08U +#define LOG_PAGE_DATA_LEN 0x10U + +/** + * @} + */ + + +/** @defgroup USBD_INFO_Exported_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_INFO_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_Variables + * @{ + */ +extern uint8_t MSC_Page00_Inquiry_Data[LENGTH_INQUIRY_PAGE00]; +extern uint8_t MSC_Page80_Inquiry_Data[LENGTH_INQUIRY_PAGE80]; +extern uint8_t MSC_Mode_Sense6_data[MODE_SENSE6_LEN]; +extern uint8_t MSC_Mode_Sense10_data[MODE_SENSE10_LEN]; +extern uint8_t MSC_Diagnostic_Data[DIAGNOSTIC_DATA_LEN]; +extern uint8_t MSC_Log_Page_Data[LOG_PAGE_DATA_LEN]; + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_MSC_DATA_H */ + +/** + * @} + */ + +/** + * @} + */ diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h new file mode 100755 index 0000000..6000c2b --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h @@ -0,0 +1,183 @@ +/** + ****************************************************************************** + * @file usbd_msc_scsi.h + * @author MCD Application Team + * @brief Header for the usbd_msc_scsi.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_SCSI_H +#define __USBD_MSC_SCSI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_SCSI + * @brief header file for the storage disk file + * @{ + */ + +/** @defgroup USBD_SCSI_Exported_Defines + * @{ + */ + +#define SENSE_LIST_DEEPTH 4U + +/* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04U +#define SCSI_INQUIRY 0x12U +#define SCSI_MODE_SELECT6 0x15U +#define SCSI_MODE_SELECT10 0x55U +#define SCSI_MODE_SENSE6 0x1AU +#define SCSI_MODE_SENSE10 0x5AU +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1EU +#define SCSI_READ6 0x08U +#define SCSI_READ10 0x28U +#define SCSI_READ12 0xA8U +#define SCSI_READ16 0x88U + +#define SCSI_READ_CAPACITY10 0x25U +#define SCSI_READ_CAPACITY16 0x9EU + +#define SCSI_REQUEST_SENSE 0x03U +#define SCSI_START_STOP_UNIT 0x1BU +#define SCSI_TEST_UNIT_READY 0x00U +#define SCSI_WRITE6 0x0AU +#define SCSI_WRITE10 0x2AU +#define SCSI_WRITE12 0xAAU +#define SCSI_WRITE16 0x8AU + +#define SCSI_VERIFY10 0x2FU +#define SCSI_VERIFY12 0xAFU +#define SCSI_VERIFY16 0x8FU + +#define SCSI_READ_FORMAT_CAPACITIES 0x23U +#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS 0x1CU +#define SCSI_SEND_DIAGNOSTIC 0x1DU +#define SCSI_REPORT_LUNS 0xA0U + +#define NO_SENSE 0U +#define RECOVERED_ERROR 1U +#define NOT_READY 2U +#define MEDIUM_ERROR 3U +#define HARDWARE_ERROR 4U +#define ILLEGAL_REQUEST 5U +#define UNIT_ATTENTION 6U +#define DATA_PROTECT 7U +#define BLANK_CHECK 8U +#define MSC_VENDOR_SPECIFIC 9U +#define COPY_ABORTED 10U +#define ABORTED_COMMAND 11U +#define VOLUME_OVERFLOW 13U +#define MISCOMPARE 14U + +#define INVALID_CDB 0x20U +#define INVALID_FIELD_IN_COMMAND 0x24U +#define PARAMETER_LIST_LENGTH_ERROR 0x1AU +#define INVALID_FIELD_IN_PARAMETER_LIST 0x26U +#define ADDRESS_OUT_OF_RANGE 0x21U +#define MEDIUM_NOT_PRESENT 0x3AU +#define MEDIUM_HAVE_CHANGED 0x28U +#define WRITE_PROTECTED 0x27U +#define UNRECOVERED_READ_ERROR 0x11U +#define WRITE_FAULT 0x03U + +#define READ_FORMAT_CAPACITY_DATA_LEN 0x0CU +#define READ_CAPACITY10_DATA_LEN 0x08U +#define REQUEST_SENSE_DATA_LEN 0x12U +#define STANDARD_INQUIRY_DATA_LEN 0x24U +#define BLKVFY 0x04U + +#define SCSI_MEDIUM_UNLOCKED 0x00U +#define SCSI_MEDIUM_LOCKED 0x01U +#define SCSI_MEDIUM_EJECTED 0x02U +/** + * @} + */ + + +/** @defgroup USBD_SCSI_Exported_TypesDefinitions + * @{ + */ + +typedef struct _SENSE_ITEM +{ + uint8_t Skey; + union + { + struct _ASCs + { + uint8_t ASC; + uint8_t ASCQ; + } b; + uint8_t ASC; + uint8_t *pData; + } w; +} USBD_SCSI_SenseTypeDef; +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Variables + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_SCSI_Exported_FunctionsPrototype + * @{ + */ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd); + +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, + uint8_t ASC); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __USBD_MSC_SCSI_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c new file mode 100755 index 0000000..eafb8ba --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c @@ -0,0 +1,584 @@ +/** + ****************************************************************************** + * @file usbd_msc.c + * @author MCD Application Team + * @brief This file provides all the MSC core functions. + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + * @verbatim + * + * =================================================================== + * 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 + * + ****************************************************************************** + */ + +/* BSPDependencies +- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" +- "stm32xxxxx_{eval}{discovery}_io.c" +- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c" +EndBSPDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc.h" + + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_CORE + * @brief Mass storage core module + * @{ + */ + +/** @defgroup MSC_CORE_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_CORE_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_CORE_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_CORE_Private_FunctionPrototypes + * @{ + */ +uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum); +uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum); + +#ifndef USE_USBD_COMPOSITE +uint8_t *USBD_MSC_GetHSCfgDesc(uint16_t *length); +uint8_t *USBD_MSC_GetFSCfgDesc(uint16_t *length); +uint8_t *USBD_MSC_GetOtherSpeedCfgDesc(uint16_t *length); +uint8_t *USBD_MSC_GetDeviceQualifierDescriptor(uint16_t *length); +#endif /* USE_USBD_COMPOSITE */ +/** + * @} + */ + + +/** @defgroup MSC_CORE_Private_Variables + * @{ + */ + + +USBD_ClassTypeDef USBD_MSC = +{ + USBD_MSC_Init, + USBD_MSC_DeInit, + USBD_MSC_Setup, + NULL, /*EP0_TxSent*/ + NULL, /*EP0_RxReady*/ + USBD_MSC_DataIn, + USBD_MSC_DataOut, + NULL, /*SOF */ + NULL, + NULL, +#ifdef USE_USBD_COMPOSITE + NULL, + NULL, + NULL, + NULL, +#else + USBD_MSC_GetHSCfgDesc, + USBD_MSC_GetFSCfgDesc, + USBD_MSC_GetOtherSpeedCfgDesc, + USBD_MSC_GetDeviceQualifierDescriptor, +#endif /* USE_USBD_COMPOSITE */ +#if (USBD_SUPPORT_USER_STRING_DESC == 1U) + NULL, +#endif /* USBD_SUPPORT_USER_STRING_DESC */ +}; + +/* USB Mass storage device Configuration Descriptor */ +#ifndef USE_USBD_COMPOSITE +/* USB Mass storage device Configuration Descriptor */ +/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ +__ALIGN_BEGIN static uint8_t USBD_MSC_CfgDesc[USB_MSC_CONFIG_DESC_SIZ] __ALIGN_END = +{ + 0x09, /* bLength: Configuration Descriptor size */ + USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ + USB_MSC_CONFIG_DESC_SIZ, + + 0x00, + 0x01, /* bNumInterfaces: 1 interface */ + 0x01, /* bConfigurationValue */ + 0x04, /* iConfiguration */ +#if (USBD_SELF_POWERED == 1U) + 0xC0, /* bmAttributes: Bus Powered according to user configuration */ +#else + 0x80, /* bmAttributes: Bus Powered according to user configuration */ +#endif /* USBD_SELF_POWERED */ + USBD_MAX_POWER, /* MaxPower (mA) */ + + /******************** Mass Storage interface ********************/ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints */ + 0x08, /* bInterfaceClass: MSC Class */ + 0x06, /* bInterfaceSubClass : SCSI transparent*/ + 0x50, /* nInterfaceProtocol */ + 0x05, /* iInterface: */ + /******************** Mass Storage Endpoints ********************/ + 0x07, /* Endpoint descriptor length = 7 */ + 0x05, /* Endpoint descriptor type */ + MSC_EPIN_ADDR, /* Endpoint address (IN, address 1) */ + 0x02, /* Bulk endpoint type */ + LOBYTE(MSC_MAX_FS_PACKET), + HIBYTE(MSC_MAX_FS_PACKET), + 0x00, /* Polling interval in milliseconds */ + + 0x07, /* Endpoint descriptor length = 7 */ + 0x05, /* Endpoint descriptor type */ + MSC_EPOUT_ADDR, /* Endpoint address (OUT, address 1) */ + 0x02, /* Bulk endpoint type */ + LOBYTE(MSC_MAX_FS_PACKET), + HIBYTE(MSC_MAX_FS_PACKET), + 0x00 /* Polling interval in milliseconds */ +}; + +/* USB Standard Device Descriptor */ +__ALIGN_BEGIN static uint8_t USBD_MSC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = +{ + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + MSC_MAX_FS_PACKET, + 0x01, + 0x00, +}; +#endif /* USE_USBD_COMPOSITE */ + +uint8_t MSCInEpAdd = MSC_EPIN_ADDR; +uint8_t MSCOutEpAdd = MSC_EPOUT_ADDR; + +/** + * @} + */ + + +/** @defgroup MSC_CORE_Private_Functions + * @{ + */ + +/** + * @brief USBD_MSC_Init + * Initialize the mass storage configuration + * @param pdev: device instance + * @param cfgidx: configuration index + * @retval status + */ +uint8_t USBD_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + UNUSED(cfgidx); + USBD_MSC_BOT_HandleTypeDef *hmsc; + + hmsc = (USBD_MSC_BOT_HandleTypeDef *)USBD_malloc(sizeof(USBD_MSC_BOT_HandleTypeDef)); + + if (hmsc == NULL) + { + pdev->pClassDataCmsit[pdev->classId] = NULL; + return (uint8_t)USBD_EMEM; + } + + pdev->pClassDataCmsit[pdev->classId] = (void *)hmsc; + pdev->pClassData = pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (pdev->dev_speed == USBD_SPEED_HIGH) + { + /* Open EP OUT */ + (void)USBD_LL_OpenEP(pdev, MSCOutEpAdd, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET); + pdev->ep_out[MSCOutEpAdd & 0xFU].is_used = 1U; + + /* Open EP IN */ + (void)USBD_LL_OpenEP(pdev, MSCInEpAdd, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET); + pdev->ep_in[MSCInEpAdd & 0xFU].is_used = 1U; + } + else + { + /* Open EP OUT */ + (void)USBD_LL_OpenEP(pdev, MSCOutEpAdd, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET); + pdev->ep_out[MSCOutEpAdd & 0xFU].is_used = 1U; + + /* Open EP IN */ + (void)USBD_LL_OpenEP(pdev, MSCInEpAdd, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET); + pdev->ep_in[MSCInEpAdd & 0xFU].is_used = 1U; + } + + /* Init the BOT layer */ + MSC_BOT_Init(pdev); + + return (uint8_t)USBD_OK; +} + +/** + * @brief USBD_MSC_DeInit + * DeInitialize the mass storage configuration + * @param pdev: device instance + * @param cfgidx: configuration index + * @retval status + */ +uint8_t USBD_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + UNUSED(cfgidx); + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + /* Close MSC EPs */ + (void)USBD_LL_CloseEP(pdev, MSCOutEpAdd); + pdev->ep_out[MSCOutEpAdd & 0xFU].is_used = 0U; + + /* Close EP IN */ + (void)USBD_LL_CloseEP(pdev, MSCInEpAdd); + pdev->ep_in[MSCInEpAdd & 0xFU].is_used = 0U; + + /* Free MSC Class Resources */ + if (pdev->pClassDataCmsit[pdev->classId] != NULL) + { + /* De-Init the BOT layer */ + MSC_BOT_DeInit(pdev); + + (void)USBD_free(pdev->pClassDataCmsit[pdev->classId]); + pdev->pClassDataCmsit[pdev->classId] = NULL; + pdev->pClassData = NULL; + } + + return (uint8_t)USBD_OK; +} +/** + * @brief USBD_MSC_Setup + * Handle the MSC specific requests + * @param pdev: device instance + * @param req: USB request + * @retval status + */ +uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_StatusTypeDef ret = USBD_OK; + uint32_t max_lun; + uint16_t status_info = 0U; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return (uint8_t)USBD_FAIL; + } + + switch (req->bmRequest & USB_REQ_TYPE_MASK) + { + /* Class request */ + case USB_REQ_TYPE_CLASS: + switch (req->bRequest) + { + case BOT_GET_MAX_LUN: + if ((req->wValue == 0U) && (req->wLength == 1U) && + ((req->bmRequest & 0x80U) == 0x80U)) + { + max_lun = (uint32_t)((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->GetMaxLun(); + hmsc->max_lun = (max_lun > MSC_BOT_MAX_LUN) ? MSC_BOT_MAX_LUN : max_lun; + (void)USBD_CtlSendData(pdev, (uint8_t *)&hmsc->max_lun, 1U); + } + else + { + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + } + break; + + case BOT_RESET : + if ((req->wValue == 0U) && (req->wLength == 0U) && + ((req->bmRequest & 0x80U) != 0x80U)) + { + MSC_BOT_Reset(pdev); + } + else + { + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + } + break; + + default: + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + break; + } + break; + /* Interface & Endpoint request */ + case USB_REQ_TYPE_STANDARD: + switch (req->bRequest) + { + case USB_REQ_GET_STATUS: + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + (void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U); + } + else + { + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + } + break; + + case USB_REQ_GET_INTERFACE: + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + (void)USBD_CtlSendData(pdev, (uint8_t *)&hmsc->interface, 1U); + } + else + { + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + } + break; + + case USB_REQ_SET_INTERFACE: + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + hmsc->interface = (uint8_t)(req->wValue); + } + else + { + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + } + break; + + case USB_REQ_CLEAR_FEATURE: + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + if (req->wValue == USB_FEATURE_EP_HALT) + { + /* Flush the FIFO */ + (void)USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex); + + /* Handle BOT error */ + MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); + } + } + break; + + default: + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + break; + } + break; + + default: + USBD_CtlError(pdev, req); + ret = USBD_FAIL; + break; + } + + return (uint8_t)ret; +} + +/** + * @brief USBD_MSC_DataIn + * handle data IN Stage + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +uint8_t USBD_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + MSC_BOT_DataIn(pdev, epnum); + + return (uint8_t)USBD_OK; +} + +/** + * @brief USBD_MSC_DataOut + * handle data OUT Stage + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +uint8_t USBD_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + MSC_BOT_DataOut(pdev, epnum); + + return (uint8_t)USBD_OK; +} +#ifndef USE_USBD_COMPOSITE +/** + * @brief USBD_MSC_GetHSCfgDesc + * return configuration descriptor + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +uint8_t *USBD_MSC_GetHSCfgDesc(uint16_t *length) +{ + USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPIN_ADDR); + USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPOUT_ADDR); + + if (pEpInDesc != NULL) + { + pEpInDesc->wMaxPacketSize = MSC_MAX_HS_PACKET; + } + + if (pEpOutDesc != NULL) + { + pEpOutDesc->wMaxPacketSize = MSC_MAX_HS_PACKET; + } + + *length = (uint16_t)sizeof(USBD_MSC_CfgDesc); + return USBD_MSC_CfgDesc; +} + +/** + * @brief USBD_MSC_GetFSCfgDesc + * return configuration descriptor + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +uint8_t *USBD_MSC_GetFSCfgDesc(uint16_t *length) +{ + USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPIN_ADDR); + USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPOUT_ADDR); + + if (pEpInDesc != NULL) + { + pEpInDesc->wMaxPacketSize = MSC_MAX_FS_PACKET; + } + + if (pEpOutDesc != NULL) + { + pEpOutDesc->wMaxPacketSize = MSC_MAX_FS_PACKET; + } + + *length = (uint16_t)sizeof(USBD_MSC_CfgDesc); + return USBD_MSC_CfgDesc; +} + +/** + * @brief USBD_MSC_GetOtherSpeedCfgDesc + * return other speed configuration descriptor + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +uint8_t *USBD_MSC_GetOtherSpeedCfgDesc(uint16_t *length) +{ + USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPIN_ADDR); + USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_MSC_CfgDesc, MSC_EPOUT_ADDR); + + if (pEpInDesc != NULL) + { + pEpInDesc->wMaxPacketSize = MSC_MAX_FS_PACKET; + } + + if (pEpOutDesc != NULL) + { + pEpOutDesc->wMaxPacketSize = MSC_MAX_FS_PACKET; + } + + *length = (uint16_t)sizeof(USBD_MSC_CfgDesc); + return USBD_MSC_CfgDesc; +} +/** + * @brief DeviceQualifierDescriptor + * return Device Qualifier descriptor + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +uint8_t *USBD_MSC_GetDeviceQualifierDescriptor(uint16_t *length) +{ + *length = (uint16_t)sizeof(USBD_MSC_DeviceQualifierDesc); + + return USBD_MSC_DeviceQualifierDesc; +} +#endif /* USE_USBD_COMPOSITE */ +/** + * @brief USBD_MSC_RegisterStorage + * @param fops: storage callback + * @retval status + */ +uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops) +{ + if (fops == NULL) + { + return (uint8_t)USBD_FAIL; + } + + pdev->pUserData[pdev->classId] = fops; + + return (uint8_t)USBD_OK; +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c new file mode 100755 index 0000000..e1cb63c --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c @@ -0,0 +1,478 @@ +/** + ****************************************************************************** + * @file usbd_msc_bot.c + * @author MCD Application Team + * @brief This file provides all the BOT protocol core functions. + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* BSPDependencies +- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" +- "stm32xxxxx_{eval}{discovery}_io.c" +- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c" +EndBSPDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc.h" +#include "usbd_msc_scsi.h" +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_BOT + * @brief BOT protocol module + * @{ + */ + +/** @defgroup MSC_BOT_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Variables + * @{ + */ +extern uint8_t MSCInEpAdd; +extern uint8_t MSCOutEpAdd; +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_FunctionPrototypes + * @{ + */ +static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, uint8_t *pbuf, uint32_t len); +static void MSC_BOT_CBW_Decode(USBD_HandleTypeDef *pdev); +static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev); +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Functions + * @{ + */ + + +/** + * @brief MSC_BOT_Init + * Initialize the BOT Process + * @param pdev: device instance + * @retval None + */ +void MSC_BOT_Init(USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_NORMAL; + + hmsc->scsi_sense_tail = 0U; + hmsc->scsi_sense_head = 0U; + hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED; + + ((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->Init(0U); + + (void)USBD_LL_FlushEP(pdev, MSCOutEpAdd); + (void)USBD_LL_FlushEP(pdev, MSCInEpAdd); + + /* Prepare EP to Receive First BOT Cmd */ + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** + * @brief MSC_BOT_Reset + * Reset the BOT Machine + * @param pdev: device instance + * @retval None + */ +void MSC_BOT_Reset(USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_RECOVERY; + + (void)USBD_LL_ClearStallEP(pdev, MSCInEpAdd); + (void)USBD_LL_ClearStallEP(pdev, MSCOutEpAdd); + + /* Prepare EP to Receive First BOT Cmd */ + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** + * @brief MSC_BOT_DeInit + * DeInitialize the BOT Machine + * @param pdev: device instance + * @retval None + */ +void MSC_BOT_DeInit(USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc != NULL) + { + hmsc->bot_state = USBD_BOT_IDLE; + } +} + +/** + * @brief MSC_BOT_DataIn + * Handle BOT IN data stage + * @param pdev: device instance + * @param epnum: endpoint index + * @retval None + */ +void MSC_BOT_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + UNUSED(epnum); + + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return; + } + + switch (hmsc->bot_state) + { + case USBD_BOT_DATA_IN: + if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED); + } + break; + + case USBD_BOT_SEND_DATA: + case USBD_BOT_LAST_DATA_IN: + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED); + break; + + default: + break; + } +} +/** + * @brief MSC_BOT_DataOut + * Process MSC OUT data + * @param pdev: device instance + * @param epnum: endpoint index + * @retval None + */ +void MSC_BOT_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + UNUSED(epnum); + + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return; + } + + switch (hmsc->bot_state) + { + case USBD_BOT_IDLE: + MSC_BOT_CBW_Decode(pdev); + break; + + case USBD_BOT_DATA_OUT: + if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED); + } + break; + + default: + break; + } +} + +/** + * @brief MSC_BOT_CBW_Decode + * Decode the CBW command and set the BOT state machine accordingly + * @param pdev: device instance + * @retval None + */ +static void MSC_BOT_CBW_Decode(USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + hmsc->csw.dTag = hmsc->cbw.dTag; + hmsc->csw.dDataResidue = hmsc->cbw.dDataLength; + + if ((USBD_LL_GetRxDataSize(pdev, MSCOutEpAdd) != USBD_BOT_CBW_LENGTH) || + (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE) || + (hmsc->cbw.bLUN > hmsc->max_lun) || (hmsc->cbw.bCBLength < 1U) || + (hmsc->cbw.bCBLength > 16U)) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + + hmsc->bot_status = USBD_BOT_STATUS_ERROR; + MSC_BOT_Abort(pdev); + } + else + { + if (SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0]) < 0) + { + if (hmsc->bot_state == USBD_BOT_NO_DATA) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED); + } + else + { + MSC_BOT_Abort(pdev); + } + } + /* Burst xfer handled internally */ + else if ((hmsc->bot_state != USBD_BOT_DATA_IN) && + (hmsc->bot_state != USBD_BOT_DATA_OUT) && + (hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) + { + if (hmsc->bot_data_length > 0U) + { + MSC_BOT_SendData(pdev, hmsc->bot_data, hmsc->bot_data_length); + } + else if (hmsc->bot_data_length == 0U) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED); + } + else + { + MSC_BOT_Abort(pdev); + } + } + else + { + return; + } + } +} + +/** + * @brief MSC_BOT_SendData + * Send the requested data + * @param pdev: device instance + * @param buf: pointer to data buffer + * @param len: Data Length + * @retval None + */ +static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, uint8_t *pbuf, uint32_t len) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + uint32_t length; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + length = MIN(hmsc->cbw.dDataLength, len); + + hmsc->csw.dDataResidue -= len; + hmsc->csw.bStatus = USBD_CSW_CMD_PASSED; + hmsc->bot_state = USBD_BOT_SEND_DATA; + + (void)USBD_LL_Transmit(pdev, MSCInEpAdd, pbuf, length); +} + +/** + * @brief MSC_BOT_SendCSW + * Send the Command Status Wrapper + * @param pdev: device instance + * @param status : CSW status + * @retval None + */ +void MSC_BOT_SendCSW(USBD_HandleTypeDef *pdev, uint8_t CSW_Status) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE; + hmsc->csw.bStatus = CSW_Status; + hmsc->bot_state = USBD_BOT_IDLE; + + (void)USBD_LL_Transmit(pdev, MSCInEpAdd, (uint8_t *)&hmsc->csw, + USBD_BOT_CSW_LENGTH); + + /* Prepare EP to Receive next Cmd */ + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** + * @brief MSC_BOT_Abort + * Abort the current transfer + * @param pdev: device instance + * @retval status + */ + +static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + if ((hmsc->cbw.bmFlags == 0U) && + (hmsc->cbw.dDataLength != 0U) && + (hmsc->bot_status == USBD_BOT_STATUS_NORMAL)) + { + (void)USBD_LL_StallEP(pdev, MSCOutEpAdd); + } + + (void)USBD_LL_StallEP(pdev, MSCInEpAdd); + + if (hmsc->bot_status == USBD_BOT_STATUS_ERROR) + { + (void)USBD_LL_StallEP(pdev, MSCInEpAdd); + (void)USBD_LL_StallEP(pdev, MSCOutEpAdd); + } +} + +/** + * @brief MSC_BOT_CplClrFeature + * Complete the clear feature request + * @param pdev: device instance + * @param epnum: endpoint index + * @retval None + */ + +void MSC_BOT_CplClrFeature(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc == NULL) + { + return; + } + + if (hmsc->bot_status == USBD_BOT_STATUS_ERROR) /* Bad CBW Signature */ + { + (void)USBD_LL_StallEP(pdev, MSCInEpAdd); + (void)USBD_LL_StallEP(pdev, MSCOutEpAdd); + } + else if (((epnum & 0x80U) == 0x80U) && (hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_FAILED); + } + else + { + return; + } +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c new file mode 100755 index 0000000..333a87a --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c @@ -0,0 +1,164 @@ +/** + ****************************************************************************** + * @file usbd_msc_data.c + * @author MCD Application Team + * @brief This file provides all the vital inquiry pages and sense data. + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* BSPDependencies +- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" +- "stm32xxxxx_{eval}{discovery}_io.c" +- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c" +EndBSPDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_data.h" + + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_DATA + * @brief Mass storage info/data module + * @{ + */ + +/** @defgroup MSC_DATA_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Variables + * @{ + */ + +/* USB Mass storage Page 0 Inquiry Data */ +uint8_t MSC_Page00_Inquiry_Data[LENGTH_INQUIRY_PAGE00] = +{ + 0x00, + 0x00, + 0x00, + (LENGTH_INQUIRY_PAGE00 - 4U), + 0x00, + 0x80 +}; + +/* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */ +uint8_t MSC_Page80_Inquiry_Data[LENGTH_INQUIRY_PAGE80] = +{ + 0x00, + 0x80, + 0x00, + LENGTH_INQUIRY_PAGE80, + 0x20, /* Put Product Serial number */ + 0x20, + 0x20, + 0x20 +}; + +/* USB Mass storage sense 6 Data */ +uint8_t MSC_Mode_Sense6_data[MODE_SENSE6_LEN] = +{ + 0x03, /* MODE DATA LENGTH. The number of bytes that follow. */ + 0x00, /* MEDIUM TYPE. 00h for SBC devices. */ + 0x00, /* DEVICE-SPECIFIC PARAMETER. For SBC devices: + * bit 7: WP. Set to 1 if the media is write-protected. + * bits 6..5: reserved + * bit 4: DPOFUA. Set to 1 if the device supports the DPO and FUA bits + * bits 3..0: reserved */ + 0x00 /* BLOCK DESCRIPTOR LENGTH */ +}; + + +/* USB Mass storage sense 10 Data */ +uint8_t MSC_Mode_Sense10_data[MODE_SENSE10_LEN] = +{ + 0x00, /* MODE DATA LENGTH MSB. */ + 0x06, /* MODE DATA LENGTH LSB. The number of bytes that follow. */ + 0x00, /* MEDIUM TYPE. 00h for SBC devices. */ + 0x00, /* DEVICE-SPECIFIC PARAMETER. For SBC devices: + * bit 7: WP. Set to 1 if the media is write-protected. + * bits 6..5: reserved + * bit 4: DPOFUA. Set to 1 if the device supports the DPO and FUA bits + * bits 3..0: reserved */ + 0x00, /* LONGLBA Set to zero */ + 0x00, /* Reserved */ + 0x00, /* BLOCK DESCRIPTOR LENGTH MSB. */ + 0x00 /* BLOCK DESCRIPTOR LENGTH LSB. */ +}; + +uint8_t MSC_Diagnostic_Data[DIAGNOSTIC_DATA_LEN] = +{ + 0x00, /* Byte 0: ADDITIONAL LENGTH (MSB) */ + 0x00, /* Byte 1: ADDITIONAL LENGTH (LSB) */ + 0x00, /* Byte 2: FRU CODE (most probable) */ + 0x00, /* Byte 3: FRU CODE */ + 0x00, /* Byte 4: FRU CODE */ + 0x00, /* Byte 5: FRU CODE (least probable) */ + 0x00, /* Byte 6: ERROR CODE (MSB) */ + 0x00, /* Byte 7: ERROR CODE (LSB) */ +}; + +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Functions + * @{ + */ + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + diff --git a/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c new file mode 100755 index 0000000..25f9423 --- /dev/null +++ b/Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c @@ -0,0 +1,1323 @@ +/** + ****************************************************************************** + * @file usbd_msc_scsi.c + * @author MCD Application Team + * @brief This file provides all the USBD SCSI layer functions. + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* BSPDependencies +- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" +- "stm32xxxxx_{eval}{discovery}_io.c" +- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c" +EndBSPDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_msc.h" +#include "usbd_msc_data.h" + + +/** @addtogroup STM32_USB_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_SCSI + * @brief Mass storage SCSI layer module + * @{ + */ + +/** @defgroup MSC_SCSI_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Variables + * @{ + */ +extern uint8_t MSCInEpAdd; +extern uint8_t MSCOutEpAdd; +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_FunctionPrototypes + * @{ + */ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReportLuns(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReceiveDiagnosticResults(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun, + uint32_t blk_offset, uint32_t blk_nbr); + +static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun); +static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun); + +static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc, + uint8_t *pBuff, uint16_t length); +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Functions + * @{ + */ + + +/** + * @brief SCSI_ProcessCmd + * Process SCSI commands + * @param pdev: device instance + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd) +{ + int8_t ret; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + switch (cmd[0]) + { + case SCSI_TEST_UNIT_READY: + ret = SCSI_TestUnitReady(pdev, lun, cmd); + break; + + case SCSI_REQUEST_SENSE: + ret = SCSI_RequestSense(pdev, lun, cmd); + break; + + case SCSI_INQUIRY: + ret = SCSI_Inquiry(pdev, lun, cmd); + break; + + case SCSI_START_STOP_UNIT: + ret = SCSI_StartStopUnit(pdev, lun, cmd); + break; + + case SCSI_ALLOW_MEDIUM_REMOVAL: + ret = SCSI_AllowPreventRemovable(pdev, lun, cmd); + break; + + case SCSI_MODE_SENSE6: + ret = SCSI_ModeSense6(pdev, lun, cmd); + break; + + case SCSI_MODE_SENSE10: + ret = SCSI_ModeSense10(pdev, lun, cmd); + break; + + case SCSI_READ_FORMAT_CAPACITIES: + ret = SCSI_ReadFormatCapacity(pdev, lun, cmd); + break; + + case SCSI_READ_CAPACITY10: + ret = SCSI_ReadCapacity10(pdev, lun, cmd); + break; + + case SCSI_READ_CAPACITY16: + ret = SCSI_ReadCapacity16(pdev, lun, cmd); + break; + + case SCSI_READ10: + ret = SCSI_Read10(pdev, lun, cmd); + break; + + case SCSI_READ12: + ret = SCSI_Read12(pdev, lun, cmd); + break; + + case SCSI_WRITE10: + ret = SCSI_Write10(pdev, lun, cmd); + break; + + case SCSI_WRITE12: + ret = SCSI_Write12(pdev, lun, cmd); + break; + + case SCSI_VERIFY10: + ret = SCSI_Verify10(pdev, lun, cmd); + break; + + case SCSI_REPORT_LUNS: + ret = SCSI_ReportLuns(pdev, lun, cmd); + break; + + case SCSI_RECEIVE_DIAGNOSTIC_RESULTS: + ret = SCSI_ReceiveDiagnosticResults(pdev, lun, cmd); + break; + + default: + SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB); + ret = -1; + break; + } + + return ret; +} + + +/** + * @brief SCSI_TestUnitReady + * Process SCSI Test Unit Ready Command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(params); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + /* case 9 : Hi > D0 */ + if (hmsc->cbw.dDataLength != 0U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + + return -1; + } + + if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + hmsc->bot_state = USBD_BOT_NO_DATA; + return -1; + } + + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsReady(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + hmsc->bot_state = USBD_BOT_NO_DATA; + + return -1; + } + hmsc->bot_data_length = 0U; + + return 0; +} + + +/** + * @brief SCSI_Inquiry + * Process Inquiry command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint8_t *pPage; + uint16_t len; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + if (hmsc->cbw.dDataLength == 0U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + if ((params[1] & 0x01U) != 0U) /* Evpd is set */ + { + if (params[2] == 0U) /* Request for Supported Vital Product Data Pages*/ + { + (void)SCSI_UpdateBotData(hmsc, MSC_Page00_Inquiry_Data, LENGTH_INQUIRY_PAGE00); + } + else if (params[2] == 0x80U) /* Request for VPD page 0x80 Unit Serial Number */ + { + (void)SCSI_UpdateBotData(hmsc, MSC_Page80_Inquiry_Data, LENGTH_INQUIRY_PAGE80); + } + else /* Request Not supported */ + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, + INVALID_FIELD_IN_COMMAND); + + return -1; + } + } + else + { + + pPage = (uint8_t *) & ((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId]) \ + ->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN]; + len = (uint16_t)pPage[4] + 5U; + + if (params[4] <= len) + { + len = params[4]; + } + + (void)SCSI_UpdateBotData(hmsc, pPage, len); + } + + return 0; +} + + +/** + * @brief SCSI_ReadCapacity10 + * Process Read Capacity 10 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(params); + int8_t ret; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + ret = ((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->GetCapacity(lun, &p_scsi_blk->nbr, + &p_scsi_blk->size); + + if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + hmsc->bot_data[0] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 24); + hmsc->bot_data[1] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 16); + hmsc->bot_data[2] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 8); + hmsc->bot_data[3] = (uint8_t)(p_scsi_blk->nbr - 1U); + + hmsc->bot_data[4] = (uint8_t)(p_scsi_blk->size >> 24); + hmsc->bot_data[5] = (uint8_t)(p_scsi_blk->size >> 16); + hmsc->bot_data[6] = (uint8_t)(p_scsi_blk->size >> 8); + hmsc->bot_data[7] = (uint8_t)(p_scsi_blk->size); + + hmsc->bot_data_length = 8U; + + return 0; +} + + +/** + * @brief SCSI_ReadCapacity16 + * Process Read Capacity 16 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(params); + uint32_t idx; + int8_t ret; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + ret = ((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->GetCapacity(lun, &p_scsi_blk->nbr, + &p_scsi_blk->size); + + if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + hmsc->bot_data_length = ((uint32_t)params[10] << 24) | + ((uint32_t)params[11] << 16) | + ((uint32_t)params[12] << 8) | + (uint32_t)params[13]; + + for (idx = 0U; idx < hmsc->bot_data_length; idx++) + { + hmsc->bot_data[idx] = 0U; + } + + hmsc->bot_data[4] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 24); + hmsc->bot_data[5] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 16); + hmsc->bot_data[6] = (uint8_t)((p_scsi_blk->nbr - 1U) >> 8); + hmsc->bot_data[7] = (uint8_t)(p_scsi_blk->nbr - 1U); + + hmsc->bot_data[8] = (uint8_t)(p_scsi_blk->size >> 24); + hmsc->bot_data[9] = (uint8_t)(p_scsi_blk->size >> 16); + hmsc->bot_data[10] = (uint8_t)(p_scsi_blk->size >> 8); + hmsc->bot_data[11] = (uint8_t)(p_scsi_blk->size); + + hmsc->bot_data_length = ((uint32_t)params[10] << 24) | + ((uint32_t)params[11] << 16) | + ((uint32_t)params[12] << 8) | + (uint32_t)params[13]; + + return 0; +} + + +/** + * @brief SCSI_ReadFormatCapacity + * Process Read Format Capacity command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(params); + uint16_t blk_size; + uint32_t blk_nbr; + uint16_t i; + int8_t ret; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + ret = ((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->GetCapacity(lun, &blk_nbr, &blk_size); + + if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED)) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + for (i = 0U; i < 12U ; i++) + { + hmsc->bot_data[i] = 0U; + } + + hmsc->bot_data[3] = 0x08U; + hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1U) >> 24); + hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1U) >> 16); + hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1U) >> 8); + hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1U); + + hmsc->bot_data[8] = 0x02U; + hmsc->bot_data[9] = (uint8_t)(blk_size >> 16); + hmsc->bot_data[10] = (uint8_t)(blk_size >> 8); + hmsc->bot_data[11] = (uint8_t)(blk_size); + + hmsc->bot_data_length = 12U; + + return 0; +} + + +/** + * @brief SCSI_ModeSense6 + * Process Mode Sense6 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + uint16_t len = MODE_SENSE6_LEN; + + if (hmsc == NULL) + { + return -1; + } + + /* Check If media is write-protected */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsWriteProtected(lun) != 0) + { + MSC_Mode_Sense6_data[2] |= (0x1U << 7); /* Set the WP (write protection) bit */ + } + else + { + MSC_Mode_Sense10_data[2] &= ~(0x1U << 7); /* Clear the WP (write protection) bit */ + } + + if (params[4] <= len) + { + len = params[4]; + } + + (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense6_data, len); + + return 0; +} + + +/** + * @brief SCSI_ModeSense10 + * Process Mode Sense10 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + uint16_t len = MODE_SENSE10_LEN; + + if (hmsc == NULL) + { + return -1; + } + + /* Check If media is write-protected */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsWriteProtected(lun) != 0) + { + MSC_Mode_Sense10_data[3] |= (0x1U << 7); /* Set the WP (write protection) bit */ + } + else + { + MSC_Mode_Sense10_data[3] &= ~(0x1U << 7); /* Clear the WP (write protection) bit */ + } + + if (params[8] <= len) + { + len = params[8]; + } + + (void)SCSI_UpdateBotData(hmsc, MSC_Mode_Sense10_data, len); + + return 0; +} + + +/** + * @brief SCSI_RequestSense + * Process Request Sense command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_RequestSense(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + uint8_t i; + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + if (hmsc->cbw.dDataLength == 0U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) + { + hmsc->bot_data[i] = 0U; + } + + hmsc->bot_data[0] = 0x70U; + hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6U; + + if ((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) + { + hmsc->bot_data[2] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].Skey; + hmsc->bot_data[12] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC; + hmsc->bot_data[13] = (uint8_t)hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ; + hmsc->scsi_sense_head++; + + if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_head = 0U; + } + } + + hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN; + + if (params[4] <= REQUEST_SENSE_DATA_LEN) + { + hmsc->bot_data_length = params[4]; + } + + return 0; +} + + +/** + * @brief SCSI_SenseCode + * Load the last error code in the error list + * @param lun: Logical unit number + * @param sKey: Sense Key + * @param ASC: Additional Sense Code + * @retval none + + */ +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return; + } + + hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey; + hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASC = ASC; + hmsc->scsi_sense[hmsc->scsi_sense_tail].w.b.ASCQ = 0U; + hmsc->scsi_sense_tail++; + + if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_tail = 0U; + } +} + + +/** + * @brief SCSI_StartStopUnit + * Process Start Stop Unit command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + if ((hmsc->scsi_medium_state == SCSI_MEDIUM_LOCKED) && ((params[4] & 0x3U) == 2U)) + { + SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELD_IN_COMMAND); + + return -1; + } + + if ((params[4] & 0x3U) == 0x1U) /* START=1 */ + { + hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED; + } + else if ((params[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */ + { + hmsc->scsi_medium_state = SCSI_MEDIUM_EJECTED; + } + else if ((params[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */ + { + hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED; + } + else + { + /* .. */ + } + hmsc->bot_data_length = 0U; + + return 0; +} + + +/** + * @brief SCSI_AllowPreventRemovable + * Process Allow Prevent Removable medium command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + if (params[4] == 0U) + { + hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED; + } + else + { + hmsc->scsi_medium_state = SCSI_MEDIUM_LOCKED; + } + + hmsc->bot_data_length = 0U; + + return 0; +} + + +/** + * @brief SCSI_Read10 + * Process Read10 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + /* case 10 : Ho <> Di */ + if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + + return -1; + } + + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsReady(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + p_scsi_blk->addr = ((uint32_t)params[2] << 24) | + ((uint32_t)params[3] << 16) | + ((uint32_t)params[4] << 8) | + (uint32_t)params[5]; + + p_scsi_blk->len = ((uint32_t)params[7] << 8) | (uint32_t)params[8]; + + if (SCSI_CheckAddressRange(pdev, lun, p_scsi_blk->addr, p_scsi_blk->len) < 0) + { + return -1; /* error */ + } + + /* cases 4,5 : Hi <> Dn */ + if (hmsc->cbw.dDataLength != (p_scsi_blk->len * p_scsi_blk->size)) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + hmsc->bot_state = USBD_BOT_DATA_IN; + } + hmsc->bot_data_length = MSC_MEDIA_PACKET; + + return SCSI_ProcessRead(pdev, lun); +} + + +/** + * @brief SCSI_Read12 + * Process Read12 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + /* case 10 : Ho <> Di */ + if ((hmsc->cbw.bmFlags & 0x80U) != 0x80U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + if (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsReady(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + p_scsi_blk->addr = ((uint32_t)params[2] << 24) | + ((uint32_t)params[3] << 16) | + ((uint32_t)params[4] << 8) | + (uint32_t)params[5]; + + p_scsi_blk->len = ((uint32_t)params[6] << 24) | + ((uint32_t)params[7] << 16) | + ((uint32_t)params[8] << 8) | + (uint32_t)params[9]; + + if (SCSI_CheckAddressRange(pdev, lun, p_scsi_blk->addr, p_scsi_blk->len) < 0) + { + return -1; /* error */ + } + + /* cases 4,5 : Hi <> Dn */ + if (hmsc->cbw.dDataLength != (p_scsi_blk->len * p_scsi_blk->size)) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + hmsc->bot_state = USBD_BOT_DATA_IN; + } + hmsc->bot_data_length = MSC_MEDIA_PACKET; + + return SCSI_ProcessRead(pdev, lun); +} + + +/** + * @brief SCSI_Write10 + * Process Write10 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + uint32_t len; + + if (hmsc == NULL) + { + return -1; + } + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + if (hmsc->cbw.dDataLength == 0U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + /* case 8 : Hi <> Do */ + if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + /* Check whether Media is ready */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsReady(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + return -1; + } + + /* Check If media is write-protected */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsWriteProtected(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED); + return -1; + } + + p_scsi_blk->addr = ((uint32_t)params[2] << 24) | + ((uint32_t)params[3] << 16) | + ((uint32_t)params[4] << 8) | + (uint32_t)params[5]; + + p_scsi_blk->len = ((uint32_t)params[7] << 8) | + (uint32_t)params[8]; + + /* check if LBA address is in the right range */ + if (SCSI_CheckAddressRange(pdev, lun, p_scsi_blk->addr, p_scsi_blk->len) < 0) + { + return -1; /* error */ + } + + len = p_scsi_blk->len * p_scsi_blk->size; + + /* cases 3,11,13 : Hn,Ho <> D0 */ + if (hmsc->cbw.dDataLength != len) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + len = MIN(len, MSC_MEDIA_PACKET); + + /* Prepare EP to receive first data packet */ + hmsc->bot_state = USBD_BOT_DATA_OUT; + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, hmsc->bot_data, len); + } + else /* Write Process ongoing */ + { + return SCSI_ProcessWrite(pdev, lun); + } + + return 0; +} + + +/** + * @brief SCSI_Write12 + * Process Write12 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + uint32_t len; + + if (hmsc == NULL) + { + return -1; + } +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + if (hmsc->cbw.dDataLength == 0U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + /* case 8 : Hi <> Do */ + if ((hmsc->cbw.bmFlags & 0x80U) == 0x80U) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + /* Check whether Media is ready */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsReady(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT); + hmsc->bot_state = USBD_BOT_NO_DATA; + return -1; + } + + /* Check If media is write-protected */ + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->IsWriteProtected(lun) != 0) + { + SCSI_SenseCode(pdev, lun, NOT_READY, WRITE_PROTECTED); + hmsc->bot_state = USBD_BOT_NO_DATA; + return -1; + } + + p_scsi_blk->addr = ((uint32_t)params[2] << 24) | + ((uint32_t)params[3] << 16) | + ((uint32_t)params[4] << 8) | + (uint32_t)params[5]; + + p_scsi_blk->len = ((uint32_t)params[6] << 24) | + ((uint32_t)params[7] << 16) | + ((uint32_t)params[8] << 8) | + (uint32_t)params[9]; + + /* check if LBA address is in the right range */ + if (SCSI_CheckAddressRange(pdev, lun, p_scsi_blk->addr, p_scsi_blk->len) < 0) + { + return -1; /* error */ + } + + len = p_scsi_blk->len * p_scsi_blk->size; + + /* cases 3,11,13 : Hn,Ho <> D0 */ + if (hmsc->cbw.dDataLength != len) + { + SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); + return -1; + } + + len = MIN(len, MSC_MEDIA_PACKET); + + /* Prepare EP to receive first data packet */ + hmsc->bot_state = USBD_BOT_DATA_OUT; + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, hmsc->bot_data, len); + } + else /* Write Process ongoing */ + { + return SCSI_ProcessWrite(pdev, lun); + } + + return 0; +} + + +/** + * @brief SCSI_Verify10 + * Process Verify10 command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + if ((params[1] & 0x02U) == 0x02U) + { + SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_FIELD_IN_COMMAND); + return -1; /* Error, Verify Mode Not supported*/ + } + + if (SCSI_CheckAddressRange(pdev, lun, p_scsi_blk->addr, p_scsi_blk->len) < 0) + { + return -1; /* error */ + } + + hmsc->bot_data_length = 0U; + + return 0; +} + +/** + * @brief SCSI_ReportLuns12 + * Process ReportLuns command + * @retval status + */ +static int8_t SCSI_ReportLuns(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc; + uint32_t lun_list_length; + uint32_t total_length; + uint8_t lun_idx; + + UNUSED(lun); + UNUSED(params); + + /* Define the report LUNs buffer Each LUN entry is 8 bytes */ + static uint8_t lun_report[8U * (MSC_BOT_MAX_LUN + 1U)]; + + hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + + if (hmsc == NULL) + { + return -1; + } + + /* Initialize the report LUNs buffer */ + (void)USBD_memset(lun_report, 0, sizeof(lun_report)); + + /* Set the LUN list length in the first 4 bytes */ + lun_list_length = 8U * (hmsc->max_lun + 1U); + lun_report[0] = (uint8_t)(lun_list_length >> 24); + lun_report[1] = (uint8_t)(lun_list_length >> 16); + lun_report[2] = (uint8_t)(lun_list_length >> 8); + lun_report[3] = (uint8_t)(lun_list_length & 0xFFU); + + /* Update the LUN list */ + for (lun_idx = 0U; lun_idx <= hmsc->max_lun; lun_idx++) + { + /* LUN identifier is placed at the second byte of each 8-byte entry */ + lun_report[(8U * (lun_idx + 1U)) + 1U] = lun_idx; + } + + /* Calculate the total length of the report LUNs buffer */ + total_length = lun_list_length + 8U; + + /* Update the BOT data with the report LUNs buffer */ + (void)SCSI_UpdateBotData(hmsc, lun_report, (uint16_t)total_length); + + return 0; +} + +/** + * @brief SCSI_ReceiveDiagnosticResults + * Process SCSI_Receive Diagnostic Results command + * @param lun: Logical unit number + * @param params: Command parameters + * @retval status + */ +static int8_t SCSI_ReceiveDiagnosticResults(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + UNUSED(lun); + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + uint16_t allocation_length; + + /* Extract the allocation length from the CDB */ + allocation_length = (((uint16_t)params[3] << 8) | (uint16_t)params[4]); + + if (allocation_length == 0U) + { + return 0; + } + + /* Ensure the allocation length does not exceed the diagnostic data length */ + if (allocation_length > DIAGNOSTIC_DATA_LEN) + { + allocation_length = DIAGNOSTIC_DATA_LEN; + } + + /* Send the diagnostic data to the host */ + (void)SCSI_UpdateBotData(hmsc, MSC_Diagnostic_Data, allocation_length); + + return 0; +} + +/** + * @brief SCSI_CheckAddressRange + * Check address range + * @param lun: Logical unit number + * @param blk_offset: first block address + * @param blk_nbr: number of block to be processed + * @retval status + */ +static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun, + uint32_t blk_offset, uint32_t blk_nbr) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + + if (hmsc == NULL) + { + return -1; + } + + if ((blk_offset + blk_nbr) > p_scsi_blk->nbr) + { + SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE); + return -1; + } + + return 0; +} + +/** + * @brief SCSI_ProcessRead + * Handle Read Process + * @param lun: Logical unit number + * @retval status + */ +static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + uint32_t len; + + if (hmsc == NULL) + { + return -1; + } + + len = p_scsi_blk->len * p_scsi_blk->size; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + len = MIN(len, MSC_MEDIA_PACKET); + + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->Read(lun, hmsc->bot_data, + p_scsi_blk->addr, + (len / p_scsi_blk->size)) < 0) + { + SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR); + return -1; + } + + (void)USBD_LL_Transmit(pdev, MSCInEpAdd, hmsc->bot_data, len); + + p_scsi_blk->addr += (len / p_scsi_blk->size); + p_scsi_blk->len -= (len / p_scsi_blk->size); + + /* case 6 : Hi = Di */ + hmsc->csw.dDataResidue -= len; + + if (p_scsi_blk->len == 0U) + { + hmsc->bot_state = USBD_BOT_LAST_DATA_IN; + } + + return 0; +} + +/** + * @brief SCSI_ProcessWrite + * Handle Write Process + * @param lun: Logical unit number + * @retval status + */ +static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; + USBD_MSC_BOT_LUN_TypeDef *p_scsi_blk = &hmsc->scsi_blk[lun]; + uint32_t len; + + if (hmsc == NULL) + { + return -1; + } + + len = p_scsi_blk->len * p_scsi_blk->size; + +#ifdef USE_USBD_COMPOSITE + /* Get the Endpoints addresses allocated for this class instance */ + MSCOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId); +#endif /* USE_USBD_COMPOSITE */ + + len = MIN(len, MSC_MEDIA_PACKET); + + if (((USBD_StorageTypeDef *)pdev->pUserData[pdev->classId])->Write(lun, hmsc->bot_data, p_scsi_blk->addr, + (len / p_scsi_blk->size)) < 0) + { + SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT); + return -1; + } + + p_scsi_blk->addr += (len / p_scsi_blk->size); + p_scsi_blk->len -= (len / p_scsi_blk->size); + + /* case 12 : Ho = Do */ + hmsc->csw.dDataResidue -= len; + + if (p_scsi_blk->len == 0U) + { + MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED); + } + else + { + len = MIN((p_scsi_blk->len * p_scsi_blk->size), MSC_MEDIA_PACKET); + + /* Prepare EP to Receive next packet */ + (void)USBD_LL_PrepareReceive(pdev, MSCOutEpAdd, hmsc->bot_data, len); + } + + return 0; +} + + +/** + * @brief SCSI_UpdateBotData + * fill the requested Data to transmit buffer + * @param hmsc handler + * @param pBuff: Data buffer + * @param length: Data length + * @retval status + */ +static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc, + uint8_t *pBuff, uint16_t length) +{ + uint16_t len = length; + + if (hmsc == NULL) + { + return -1; + } + + hmsc->bot_data_length = len; + + while (len != 0U) + { + len--; + hmsc->bot_data[len] = pBuff[len]; + } + + return 0; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + |
