From fb25c2d95f2c2e9e5fdf372caa16398eafe3910d Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Sat, 22 Mar 2014 12:32:54 +0000
Subject: [PATCH] stmhal: USB CDC and MSC device work together.

---
 stmhal/Makefile                               |  16 +-
 stmhal/main.c                                 |   1 -
 stmhal/usb.c                                  |  19 +-
 stmhal/usbd_conf.c                            |   8 +-
 stmhal/usbd_desc_cdc_msc.c                    | 228 ++++++
 stmhal/usbd_msc_storage.c                     |   2 +-
 .../usbdev/class/cdc_msc/inc/usbd_cdc_msc.h   | 134 +++
 .../usbdev/class/cdc_msc/inc/usbd_msc_bot.h   | 151 ++++
 .../usbdev/class/cdc_msc/inc/usbd_msc_data.h  | 104 +++
 .../usbdev/class/cdc_msc/inc/usbd_msc_scsi.h  | 193 +++++
 .../usbdev/class/cdc_msc/src/usbd_cdc_msc.c   | 583 +++++++++++++
 stmhal/usbdev/class/cdc_msc/src/usbd_msc.c    | 609 ++++++++++++++
 .../usbdev/class/cdc_msc/src/usbd_msc_bot.c   | 407 +++++++++
 .../usbdev/class/cdc_msc/src/usbd_msc_data.c  | 134 +++
 .../usbdev/class/cdc_msc/src/usbd_msc_scsi.c  | 770 ++++++++++++++++++
 15 files changed, 3344 insertions(+), 15 deletions(-)
 create mode 100644 stmhal/usbd_desc_cdc_msc.c
 create mode 100644 stmhal/usbdev/class/cdc_msc/inc/usbd_cdc_msc.h
 create mode 100644 stmhal/usbdev/class/cdc_msc/inc/usbd_msc_bot.h
 create mode 100644 stmhal/usbdev/class/cdc_msc/inc/usbd_msc_data.h
 create mode 100644 stmhal/usbdev/class/cdc_msc/inc/usbd_msc_scsi.h
 create mode 100644 stmhal/usbdev/class/cdc_msc/src/usbd_cdc_msc.c
 create mode 100644 stmhal/usbdev/class/cdc_msc/src/usbd_msc.c
 create mode 100644 stmhal/usbdev/class/cdc_msc/src/usbd_msc_bot.c
 create mode 100644 stmhal/usbdev/class/cdc_msc/src/usbd_msc_data.c
 create mode 100644 stmhal/usbdev/class/cdc_msc/src/usbd_msc_scsi.c

diff --git a/stmhal/Makefile b/stmhal/Makefile
index 86791607a..6bb60ec89 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -21,7 +21,7 @@ INC += -I$(PY_SRC)
 INC += -I$(CMSIS_DIR)/inc
 INC += -I$(CMSIS_DIR)/devinc
 INC += -I$(HAL_DIR)/inc
-INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc/inc -I$(USBDEV_DIR)/class/msc/inc
+INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc_msc/inc
 #INC += -I$(USBHOST_DIR)
 INC += -I$(FATFS_DIR)/src
 #INC += -I$(CC3K_DIR)
@@ -56,9 +56,8 @@ SRC_C = \
 	stm32f4xx_it.c \
 	stm32f4xx_hal_msp.c \
 	usbd_conf.c \
-	usbd_desc_vcp.c \
+	usbd_desc_cdc_msc.c \
 	usbd_cdc_interface.c \
-	usbd_desc_msc.c \
 	usbd_msc_storage.c \
 	pendsv.c \
 	systick.c  \
@@ -124,13 +123,14 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
 	core/src/usbd_core.c \
 	core/src/usbd_ctlreq.c \
 	core/src/usbd_ioreq.c \
-	class/cdc/src/usbd_cdc.c \
-	class/msc/src/usbd_msc.c \
-	class/msc/src/usbd_msc_bot.c \
-	class/msc/src/usbd_msc_scsi.c \
-	class/msc/src/usbd_msc_data.c \
+	class/cdc_msc/src/usbd_cdc_msc.c \
+	class/cdc_msc/src/usbd_msc_bot.c \
+	class/cdc_msc/src/usbd_msc_scsi.c \
+	class/cdc_msc/src/usbd_msc_data.c \
 	)
 
+#	class/cdc/src/usbd_cdc.c \
+	class/msc/src/usbd_msc.c \
 #	usbd_core.c \
 	usbd_ioreq.c \
 	usbd_req.c \
diff --git a/stmhal/main.c b/stmhal/main.c
index d92ccdd5b..f07a5eef1 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -336,7 +336,6 @@ soft_reset:
         fno.lfname = NULL;
         fno.lfsize = 0;
 #endif
-        led_debug(0, 500);
         FRESULT res = f_stat("0:/boot.py", &fno);
         if (res == FR_OK) {
             if (fno.fattrib & AM_DIR) {
diff --git a/stmhal/usb.c b/stmhal/usb.c
index c14a5ad68..43fc6d7a8 100644
--- a/stmhal/usb.c
+++ b/stmhal/usb.c
@@ -2,9 +2,8 @@
 
 #include "usbd_core.h"
 #include "usbd_desc.h"
-#include "usbd_cdc.h"
+#include "usbd_cdc_msc.h"
 #include "usbd_cdc_interface.h"
-#include "usbd_msc.h"
 #include "usbd_msc_storage.h"
 
 #include "misc.h"
@@ -26,6 +25,7 @@ void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t
     if (!dev_is_enabled) {
         // only init USB once in the device's power-lifetime
         switch (device_kind) {
+                #if 0
             case USBD_DEVICE_CDC:
                 // XXX USBD_CDC_Init (called by one of these functions below) uses malloc,
                 // so the memory is invalid after a soft reset (which resets the GC).
@@ -48,6 +48,21 @@ void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t
                 }
                 USBD_Start(&hUSBDDevice);
                 break;
+                #endif
+
+            case USBD_DEVICE_CDC:
+            case USBD_DEVICE_MSC:
+                USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
+                USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC);
+                USBD_CDC_RegisterInterface(&hUSBDDevice, (USBD_CDC_ItfTypeDef*)&USBD_CDC_fops);
+                if (medium_kind == USBD_STORAGE_MEDIUM_FLASH) {
+                    USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
+                } else {
+                    USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops);
+                }
+                USBD_Start(&hUSBDDevice);
+                break;
+
 
             case USBD_DEVICE_HID:
                 //USBD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_PYB_HID_cb, &USR_cb);
diff --git a/stmhal/usbd_conf.c b/stmhal/usbd_conf.c
index 4a4414afe..9df3b673c 100644
--- a/stmhal/usbd_conf.c
+++ b/stmhal/usbd_conf.c
@@ -342,10 +342,12 @@ USBD_StatusTypeDef  USBD_LL_Init (USBD_HandleTypeDef *pdev)
   pdev->pData = &hpcd;
   /*Initialize LL Driver */
   HAL_PCD_Init(&hpcd);
-  
+
   HAL_PCD_SetRxFiFo(&hpcd, 0x80);
-  HAL_PCD_SetTxFiFo(&hpcd, 0, 0x40);
-  HAL_PCD_SetTxFiFo(&hpcd, 1, 0x80); 
+  HAL_PCD_SetTxFiFo(&hpcd, 0, 0x20);
+  HAL_PCD_SetTxFiFo(&hpcd, 1, 0x40);
+  HAL_PCD_SetTxFiFo(&hpcd, 2, 0x20);
+  HAL_PCD_SetTxFiFo(&hpcd, 3, 0x40);
 
 
 #endif 
diff --git a/stmhal/usbd_desc_cdc_msc.c b/stmhal/usbd_desc_cdc_msc.c
new file mode 100644
index 000000000..edcb4b343
--- /dev/null
+++ b/stmhal/usbd_desc_cdc_msc.c
@@ -0,0 +1,228 @@
+/**
+  ******************************************************************************
+  * @file    USB_Device/CDC_Standalone/Src/usbd_desc.c
+  * @author  MCD Application Team
+  * @version V1.0.1
+  * @date    26-February-2014
+  * @brief   This file provides the USBD descriptors and string formating method.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_conf.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+#define USBD_VID                      0x0483
+#define USBD_PID                      0x5740
+#define USBD_LANGID_STRING            0x409
+#define USBD_MANUFACTURER_STRING      "STMicroelectronics"
+#define USBD_PRODUCT_HS_STRING        "STM32 Virtual ComPort in HS Mode"
+#define USBD_SERIALNUMBER_HS_STRING   "00000000001A"
+#define USBD_PRODUCT_FS_STRING        "STM32 Virtual ComPort in FS Mode"
+#define USBD_SERIALNUMBER_FS_STRING   "00000000001B"
+#define USBD_CONFIGURATION_HS_STRING  "VCP Config"
+#define USBD_INTERFACE_HS_STRING      "VCP Interface"
+#define USBD_CONFIGURATION_FS_STRING  "VCP Config"
+#define USBD_INTERFACE_FS_STRING      "VCP Interface"
+
+/* Private macro -------------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+uint8_t *USBD_VCP_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_VCP_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+#ifdef USB_SUPPORT_USER_STRING_DESC
+uint8_t *USBD_VCP_USRStringDesc (USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);  
+#endif /* USB_SUPPORT_USER_STRING_DESC */  
+
+/* Private variables ---------------------------------------------------------*/
+USBD_DescriptorsTypeDef VCP_Desc = {
+  USBD_VCP_DeviceDescriptor,
+  USBD_VCP_LangIDStrDescriptor, 
+  USBD_VCP_ManufacturerStrDescriptor,
+  USBD_VCP_ProductStrDescriptor,
+  USBD_VCP_SerialStrDescriptor,
+  USBD_VCP_ConfigStrDescriptor,
+  USBD_VCP_InterfaceStrDescriptor,  
+};
+
+/* USB Standard Device Descriptor */
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
+  0x12,                       /* bLength */
+  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
+  0x00,                       /* bcdUSB */
+  0x02,
+  0x00,                       /* bDeviceClass */
+  0x00,                       /* bDeviceSubClass */
+  0x00,                       /* bDeviceProtocol */
+  USB_MAX_EP0_SIZE,           /* bMaxPacketSize */
+  LOBYTE(USBD_VID),           /* idVendor */
+  HIBYTE(USBD_VID),           /* idVendor */
+  LOBYTE(USBD_PID),           /* idVendor */
+  HIBYTE(USBD_PID),           /* idVendor */
+  0x00,                       /* bcdDevice rel. 2.00 */
+  0x02,
+  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
+  USBD_IDX_PRODUCT_STR,       /* Index of product string */
+  USBD_IDX_SERIAL_STR,        /* Index of serial number string */
+  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
+}; /* USB_DeviceDescriptor */
+
+/* USB Standard Device Descriptor */
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
+  USB_LEN_LANGID_STR_DESC,         
+  USB_DESC_TYPE_STRING,       
+  LOBYTE(USBD_LANGID_STRING),
+  HIBYTE(USBD_LANGID_STRING), 
+};
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+
+/* Private functions ---------------------------------------------------------*/
+
+/**
+  * @brief  Returns the device descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  *length = sizeof(hUSBDDeviceDesc);
+  return hUSBDDeviceDesc;
+}
+
+/**
+  * @brief  Returns the LangID string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  *length = sizeof(USBD_LangIDDesc);  
+  return USBD_LangIDDesc;
+}
+
+/**
+  * @brief  Returns the product string descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {   
+    USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);    
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the manufacturer string descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the serial number string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == USBD_SPEED_HIGH)
+  {    
+    USBD_GetString((uint8_t *)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);    
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the configuration string descriptor.    
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == USBD_SPEED_HIGH)
+  {  
+    USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); 
+  }
+  return USBD_StrDesc;  
+}
+
+/**
+  * @brief  Returns the interface string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_VCP_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {
+    USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
+  }
+  return USBD_StrDesc;  
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c
index e5c75e27c..ce6d3a560 100644
--- a/stmhal/usbd_msc_storage.c
+++ b/stmhal/usbd_msc_storage.c
@@ -27,7 +27,7 @@
   ******************************************************************************
   */
 
-#include "usbd_msc.h"
+#include "usbd_cdc_msc.h"
 #include "usbd_msc_storage.h"
 
 #include "misc.h"
diff --git a/stmhal/usbdev/class/cdc_msc/inc/usbd_cdc_msc.h b/stmhal/usbdev/class/cdc_msc/inc/usbd_cdc_msc.h
new file mode 100644
index 000000000..6b738adde
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/inc/usbd_cdc_msc.h
@@ -0,0 +1,134 @@
+#ifndef _USB_CDC_MSC_CORE_H_
+#define _USB_CDC_MSC_CORE_H_
+
+#include  "usbd_msc_bot.h"
+#include  "usbd_msc_scsi.h"
+#include  "usbd_ioreq.h"
+
+// CDC endpoint parameters
+#define CDC_DATA_FS_MAX_PACKET_SIZE         64  // Endpoint IN & OUT Packet size
+#define CDC_CMD_PACKET_SIZE                  8  // Control Endpoint Packet size
+#define CDC_DATA_FS_IN_PACKET_SIZE                CDC_DATA_FS_MAX_PACKET_SIZE
+#define CDC_DATA_FS_OUT_PACKET_SIZE               CDC_DATA_FS_MAX_PACKET_SIZE
+
+#if 0
+// CDC
+#define USB_CDC_MSC_CONFIG_DESC_SIZ (75)
+#define NUM_INTERFACES (2)
+#define USE_CDC (1)
+#define USE_MSC (0)
+#define CDC_IN_EP                       0x81  /* EP1 for data IN */
+#define CDC_OUT_EP                      0x01  /* EP1 for data OUT */
+#define CDC_CMD_EP                      0x82  /* EP2 for CDC commands */
+#define MSC_IN_EP (0x83)
+#define MSC_OUT_EP (0x03)
+#elif 0
+// MSC
+#define USB_CDC_MSC_CONFIG_DESC_SIZ (32)
+#define NUM_INTERFACES (1)
+#define USE_CDC (0)
+#define USE_MSC (1)
+#define CDC_IN_EP                       0x81  /* EP1 for data IN */
+#define CDC_OUT_EP                      0x01  /* EP1 for data OUT */
+#define CDC_CMD_EP                      0x82  /* EP2 for CDC commands */
+#define MSC_IFACE_NUM (0)
+#define MSC_IN_EP (0x81)
+#define MSC_OUT_EP (0x01)
+#elif 0
+// CDC + MSC
+#define USB_CDC_MSC_CONFIG_DESC_SIZ (98)
+#define NUM_INTERFACES (3)
+#define USE_CDC (1)
+#define USE_MSC (1)
+#define CDC_IFACE_NUM (0)
+#define CDC_IN_EP                       0x81  /* EP1 for data IN */
+#define CDC_OUT_EP                      0x01  /* EP1 for data OUT */
+#define CDC_CMD_EP                      0x82  /* EP2 for CDC commands */
+#define MSC_IFACE_NUM (2)
+#define MSC_IN_EP (0x83)
+#define MSC_OUT_EP (0x03)
+#else
+// MSC + CDC
+#define USB_CDC_MSC_CONFIG_DESC_SIZ (98)
+#define NUM_INTERFACES (3)
+#define USE_CDC (1)
+#define USE_MSC (1)
+#define CDC_IFACE_NUM (1)
+#define CDC_IN_EP                       0x83  /* EP1 for data IN */
+#define CDC_OUT_EP                      0x03  /* EP1 for data OUT */
+#define CDC_CMD_EP                      0x82  /* EP2 for CDC commands */
+#define MSC_IFACE_NUM (0)
+#define MSC_IN_EP (0x81)
+#define MSC_OUT_EP (0x01)
+#endif
+
+typedef struct {
+  uint32_t bitrate;
+  uint8_t  format;
+  uint8_t  paritytype;
+  uint8_t  datatype;
+} USBD_CDC_LineCodingTypeDef;
+
+typedef struct _USBD_CDC_Itf {
+  int8_t (* Init)          (void);
+  int8_t (* DeInit)        (void);
+  int8_t (* Control)       (uint8_t, uint8_t * , uint16_t);   
+  int8_t (* Receive)       (uint8_t *, uint32_t *);  
+} USBD_CDC_ItfTypeDef;
+
+typedef struct {
+  uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4];      /* Force 32bits alignment */
+  uint8_t  CmdOpCode;
+  uint8_t  CmdLength;    
+  uint8_t  *RxBuffer;  
+  uint8_t  *TxBuffer;   
+  uint32_t RxLength;
+  uint32_t TxLength;    
+  
+  __IO uint32_t TxState;     
+  __IO uint32_t RxState;    
+} USBD_CDC_HandleTypeDef;
+
+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 {
+  uint32_t                 max_lun;   
+  uint32_t                 interface; 
+  uint8_t                  bot_state;
+  uint8_t                  bot_status;  
+  uint16_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;
+  
+  uint16_t                 scsi_blk_size;
+  uint32_t                 scsi_blk_nbr;
+  
+  uint32_t                 scsi_blk_addr;
+  uint32_t                 scsi_blk_len;
+} USBD_MSC_BOT_HandleTypeDef;
+
+extern USBD_ClassTypeDef USBD_CDC_MSC;
+
+uint8_t  USBD_CDC_RegisterInterface  (USBD_HandleTypeDef   *pdev, USBD_CDC_ItfTypeDef *fops);
+uint8_t  USBD_CDC_SetTxBuffer  (USBD_HandleTypeDef   *pdev, uint8_t  *pbuff, uint16_t length);
+uint8_t  USBD_CDC_SetRxBuffer        (USBD_HandleTypeDef   *pdev, uint8_t  *pbuff);
+uint8_t  USBD_CDC_ReceivePacket  (USBD_HandleTypeDef *pdev);
+uint8_t  USBD_CDC_TransmitPacket  (USBD_HandleTypeDef *pdev);
+
+uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops);
+
+#endif // _USB_CDC_MSC_CORE_H_
diff --git a/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_bot.h b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_bot.h
new file mode 100644
index 000000000..41f8ab5a5
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_bot.h
@@ -0,0 +1,151 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_bot.h
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   header for the usbd_msc_bot.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#include "usbd_core.h"
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_BOT_H
+#define __USBD_MSC_BOT_H
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @{
+  */
+  
+/** @defgroup MSC_BOT
+  * @brief This file is the Header file for usbd_bot.c
+  * @{
+  */ 
+
+
+/** @defgroup USBD_CORE_Exported_Defines
+  * @{
+  */ 
+#define USBD_BOT_IDLE                      0       /* Idle state */
+#define USBD_BOT_DATA_OUT                  1       /* Data Out state */
+#define USBD_BOT_DATA_IN                   2       /* Data In state */
+#define USBD_BOT_LAST_DATA_IN              3       /* Last Data In Last */
+#define USBD_BOT_SEND_DATA                 4       /* Send Immediate data */
+#define USBD_BOT_NO_DATA                   5       /* No data Stage */
+
+#define USBD_BOT_CBW_SIGNATURE             0x43425355
+#define USBD_BOT_CSW_SIGNATURE             0x53425355
+#define USBD_BOT_CBW_LENGTH                31
+#define USBD_BOT_CSW_LENGTH                13
+#define USBD_BOT_MAX_DATA                  256
+
+/* CSW Status Definitions */
+#define USBD_CSW_CMD_PASSED                0x00
+#define USBD_CSW_CMD_FAILED                0x01
+#define USBD_CSW_PHASE_ERROR               0x02
+
+/* BOT Status */
+#define USBD_BOT_STATUS_NORMAL             0
+#define USBD_BOT_STATUS_RECOVERY           1
+#define USBD_BOT_STATUS_ERROR              2
+
+
+#define USBD_DIR_IN                        0
+#define USBD_DIR_OUT                       1
+#define USBD_BOTH_DIR                      2
+
+/**
+  * @}
+  */ 
+
+/** @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);
+/**
+  * @}
+  */ 
+
+#endif /* __USBD_MSC_BOT_H */
+/**
+  * @}
+  */ 
+
+/**
+* @}
+*/ 
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_data.h b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_data.h
new file mode 100644
index 000000000..f468267f4
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_data.h
@@ -0,0 +1,104 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_data.h
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   header for the usbd_msc_data.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+
+#ifndef _USBD_MSC_DATA_H_
+#define _USBD_MSC_DATA_H_
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_conf.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @{
+  */
+  
+/** @defgroup USB_INFO
+  * @brief general defines for the usb device library file
+  * @{
+  */ 
+
+/** @defgroup USB_INFO_Exported_Defines
+  * @{
+  */ 
+#define MODE_SENSE6_LEN			 8
+#define MODE_SENSE10_LEN		 8
+#define LENGTH_INQUIRY_PAGE00		 7
+#define LENGTH_FORMAT_CAPACITIES    	20
+
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBD_INFO_Exported_TypesDefinitions
+  * @{
+  */
+/**
+  * @}
+  */ 
+
+
+
+/** @defgroup USBD_INFO_Exported_Macros
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+/** @defgroup USBD_INFO_Exported_Variables
+  * @{
+  */ 
+extern const uint8_t MSC_Page00_Inquiry_Data[];  
+extern const uint8_t MSC_Mode_Sense6_data[];
+extern const uint8_t MSC_Mode_Sense10_data[] ;
+
+/**
+  * @}
+  */ 
+
+/** @defgroup USBD_INFO_Exported_FunctionsPrototype
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+#endif /* _USBD_MSC_DATA_H_ */
+
+/**
+  * @}
+  */ 
+
+/**
+* @}
+*/ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_scsi.h b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_scsi.h
new file mode 100644
index 000000000..dea247bca
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/inc/usbd_msc_scsi.h
@@ -0,0 +1,193 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_scsi.h
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   header for the usbd_msc_scsi.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USBD_MSC_SCSI_H
+#define __USBD_MSC_SCSI_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @{
+  */
+  
+/** @defgroup USBD_SCSI
+  * @brief header file for the storage disk file
+  * @{
+  */ 
+
+/** @defgroup USBD_SCSI_Exported_Defines
+  * @{
+  */ 
+
+#define SENSE_LIST_DEEPTH                          4
+
+/* SCSI Commands */
+#define SCSI_FORMAT_UNIT                            0x04
+#define SCSI_INQUIRY                                0x12
+#define SCSI_MODE_SELECT6                           0x15
+#define SCSI_MODE_SELECT10                          0x55
+#define SCSI_MODE_SENSE6                            0x1A
+#define SCSI_MODE_SENSE10                           0x5A
+#define SCSI_ALLOW_MEDIUM_REMOVAL                   0x1E
+#define SCSI_READ6                                  0x08
+#define SCSI_READ10                                 0x28
+#define SCSI_READ12                                 0xA8
+#define SCSI_READ16                                 0x88
+
+#define SCSI_READ_CAPACITY10                        0x25
+#define SCSI_READ_CAPACITY16                        0x9E
+
+#define SCSI_REQUEST_SENSE                          0x03
+#define SCSI_START_STOP_UNIT                        0x1B
+#define SCSI_TEST_UNIT_READY                        0x00
+#define SCSI_WRITE6                                 0x0A
+#define SCSI_WRITE10                                0x2A
+#define SCSI_WRITE12                                0xAA
+#define SCSI_WRITE16                                0x8A
+
+#define SCSI_VERIFY10                               0x2F
+#define SCSI_VERIFY12                               0xAF
+#define SCSI_VERIFY16                               0x8F
+
+#define SCSI_SEND_DIAGNOSTIC                        0x1D
+#define SCSI_READ_FORMAT_CAPACITIES                 0x23
+
+#define NO_SENSE                                    0
+#define RECOVERED_ERROR                             1
+#define NOT_READY                                   2
+#define MEDIUM_ERROR                                3
+#define HARDWARE_ERROR                              4
+#define ILLEGAL_REQUEST                             5
+#define UNIT_ATTENTION                              6
+#define DATA_PROTECT                                7
+#define BLANK_CHECK                                 8
+#define VENDOR_SPECIFIC                             9
+#define COPY_ABORTED                               10
+#define ABORTED_COMMAND                            11
+#define VOLUME_OVERFLOW                            13
+#define MISCOMPARE                                 14
+
+
+#define INVALID_CDB                                 0x20
+#define INVALID_FIELED_IN_COMMAND                   0x24
+#define PARAMETER_LIST_LENGTH_ERROR                 0x1A
+#define INVALID_FIELD_IN_PARAMETER_LIST             0x26
+#define ADDRESS_OUT_OF_RANGE                        0x21
+#define MEDIUM_NOT_PRESENT                          0x3A
+#define MEDIUM_HAVE_CHANGED                         0x28
+#define WRITE_PROTECTED                             0x27 
+#define UNRECOVERED_READ_ERROR			    0x11
+#define WRITE_FAULT				    0x03 
+
+#define READ_FORMAT_CAPACITY_DATA_LEN               0x0C
+#define READ_CAPACITY10_DATA_LEN                    0x08
+#define MODE_SENSE10_DATA_LEN                       0x08
+#define MODE_SENSE6_DATA_LEN                        0x04
+#define REQUEST_SENSE_DATA_LEN                      0x12
+#define STANDARD_INQUIRY_DATA_LEN                   0x24
+#define BLKVFY                                      0x04
+
+extern  uint8_t Page00_Inquiry_Data[];
+extern  uint8_t Standard_Inquiry_Data[];
+extern  uint8_t Standard_Inquiry_Data2[];
+extern  uint8_t Mode_Sense6_data[];
+extern  uint8_t Mode_Sense10_data[];
+extern  uint8_t Scsi_Sense_Data[];
+extern  uint8_t ReadCapacity10_Data[];
+extern  uint8_t ReadFormatCapacity_Data [];
+/**
+  * @}
+  */ 
+
+
+/** @defgroup USBD_SCSI_Exported_TypesDefinitions
+  * @{
+  */
+
+typedef struct _SENSE_ITEM {                
+  char Skey;
+  union {
+    struct _ASCs {
+      char ASC;
+      char ASCQ;
+    }b;
+    unsigned int	ASC;
+    char *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);
+
+/**
+  * @}
+  */ 
+
+#endif /* __USBD_MSC_SCSI_H */
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */ 
+
+/**
+* @}
+*/ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/stmhal/usbdev/class/cdc_msc/src/usbd_cdc_msc.c b/stmhal/usbdev/class/cdc_msc/src/usbd_cdc_msc.c
new file mode 100644
index 000000000..8ebf33a10
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/src/usbd_cdc_msc.c
@@ -0,0 +1,583 @@
+#include "usbd_ioreq.h"
+#include "usbd_cdc_msc.h"
+
+#define USB_DESC_TYPE_ASSOCIATION (0x0b)
+
+/* currently unused
+#define CDC_SEND_ENCAPSULATED_COMMAND               0x00
+#define CDC_GET_ENCAPSULATED_RESPONSE               0x01
+#define CDC_SET_COMM_FEATURE                        0x02
+#define CDC_GET_COMM_FEATURE                        0x03
+#define CDC_CLEAR_COMM_FEATURE                      0x04
+#define CDC_SET_LINE_CODING                         0x20
+#define CDC_GET_LINE_CODING                         0x21
+#define CDC_SET_CONTROL_LINE_STATE                  0x22
+#define CDC_SEND_BREAK                              0x23
+*/
+
+#define BOT_GET_MAX_LUN              0xFE
+#define BOT_RESET                    0xFF
+#define USB_MSC_CONFIG_DESC_SIZ      32
+
+#define MSC_MAX_FS_PACKET            0x40
+
+static USBD_CDC_ItfTypeDef *CDC_fops;
+static USBD_StorageTypeDef *MSC_fops;
+
+static USBD_CDC_HandleTypeDef CDC_ClassData;
+static USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData;
+
+// I don't think we can make these descriptors constant because they are
+// modified (perhaps unnecessarily) by the USB driver.
+
+// USB Standard Device Descriptor
+__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = {
+    USB_LEN_DEV_QUALIFIER_DESC,
+    USB_DESC_TYPE_DEVICE_QUALIFIER,
+    0x00,
+    0x02,
+    0x00,
+    0x00,
+    0x00,
+    0x40, // same for CDC and MSC (latter being MSC_MAX_FS_PACKET)
+    0x01,
+    0x00,
+};
+
+// USB CDC MSC device Configuration Descriptor
+__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgFSDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] __ALIGN_END = {
+    //--------------------------------------------------------------------------
+    // Configuration Descriptor
+    0x09,   // bLength: Configuration Descriptor size
+    USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+    LOBYTE(USB_CDC_MSC_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes
+    HIBYTE(USB_CDC_MSC_CONFIG_DESC_SIZ),
+    NUM_INTERFACES, // bNumInterfaces: 3 interfaces
+    0x01,   // bConfigurationValue: Configuration value
+    0x00,   // iConfiguration: Index of string descriptor describing the configuration
+    0x80,   // bmAttributes: bus powered; 0xc0 for self powered
+    0xfa,   // bMaxPower: in units of 2mA
+
+#if USE_CDC
+    //==========================================================================
+    // Interface Association for CDC VCP
+    0x08,   // bLength: 8 bytes
+    USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD
+    CDC_IFACE_NUM, // bFirstInterface: first interface for this association
+    0x02,   // bInterfaceCount: nummber of interfaces for this association
+    0x00,   // bFunctionClass: ?
+    0x00,   // bFunctionSubClass: ?
+    0x00,   // bFunctionProtocol: ?
+    0x00,   // iFunction: index of string for this function
+
+    //--------------------------------------------------------------------------
+    // Interface Descriptor
+    0x09,   // bLength: Interface Descriptor size
+    USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface
+    CDC_IFACE_NUM, // bInterfaceNumber: Number of Interface
+    0x00,   // bAlternateSetting: Alternate setting
+    0x01,   // bNumEndpoints: One endpoints used
+    0x02,   // bInterfaceClass: Communication Interface Class
+    0x02,   // bInterfaceSubClass: Abstract Control Model
+    0x01,   // bInterfaceProtocol: Common AT commands
+    0x00,   // iInterface:
+
+    // Header Functional Descriptor
+    0x05,   // bLength: Endpoint Descriptor size
+    0x24,   // bDescriptorType: CS_INTERFACE
+    0x00,   // bDescriptorSubtype: Header Func Desc
+    0x10,   // bcdCDC: spec release number
+    0x01,   // ?
+
+    // Call Management Functional Descriptor
+    0x05,   // bFunctionLength
+    0x24,   // bDescriptorType: CS_INTERFACE
+    0x01,   // bDescriptorSubtype: Call Management Func Desc
+    0x00,   // bmCapabilities: D0+D1
+    CDC_IFACE_NUM + 1,   // bDataInterface: 1
+
+    // ACM Functional Descriptor
+    0x04,   // bFunctionLength
+    0x24,   // bDescriptorType: CS_INTERFACE
+    0x02,   // bDescriptorSubtype: Abstract Control Management desc
+    0x02,   // bmCapabilities
+
+    // Union Functional Descriptor
+    0x05,   // bFunctionLength
+    0x24,   // bDescriptorType: CS_INTERFACE
+    0x06,   // bDescriptorSubtype: Union func desc
+    CDC_IFACE_NUM + 0,   // bMasterInterface: Communication class interface
+    CDC_IFACE_NUM + 1,   // bSlaveInterface0: Data Class Interface
+
+    // Endpoint 2 Descriptor
+    0x07,                           // bLength: Endpoint Descriptor size
+    USB_DESC_TYPE_ENDPOINT,         // bDescriptorType: Endpoint
+    CDC_CMD_EP,                     // bEndpointAddress
+    0x03,                           // bmAttributes: Interrupt
+    LOBYTE(CDC_CMD_PACKET_SIZE),    // wMaxPacketSize:
+    HIBYTE(CDC_CMD_PACKET_SIZE),
+    0x20,                           // bInterval: polling interval in frames of 1ms
+
+    //--------------------------------------------------------------------------
+    // Data class interface descriptor
+    0x09,   // bLength: Endpoint Descriptor size
+    USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface
+    CDC_IFACE_NUM + 1,   // bInterfaceNumber: Number of Interface
+    0x00,   // bAlternateSetting: Alternate setting
+    0x02,   // bNumEndpoints: Two endpoints used
+    0x0A,   // bInterfaceClass: CDC
+    0x00,   // bInterfaceSubClass: ?
+    0x00,   // bInterfaceProtocol: ?
+    0x00,   // iInterface:
+
+    // Endpoint OUT Descriptor
+    0x07,                               // bLength: Endpoint Descriptor size
+    USB_DESC_TYPE_ENDPOINT,             // bDescriptorType: Endpoint
+    CDC_OUT_EP,                         // bEndpointAddress
+    0x02,                               // bmAttributes: Bulk
+    LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+    HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+    0x00,                               // bInterval: ignore for Bulk transfer
+
+    // Endpoint IN Descriptor
+    0x07,                               // bLength: Endpoint Descriptor size
+    USB_DESC_TYPE_ENDPOINT,             // bDescriptorType: Endpoint
+    CDC_IN_EP,                          // bEndpointAddress
+    0x02,                               // bmAttributes: Bulk
+    LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize:
+    HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
+    0x00,                               // bInterval: ignore for Bulk transfer
+#endif
+
+#if USE_MSC
+    //==========================================================================
+    // MSC only has 1 interface so doesn't need an IAD
+
+    //--------------------------------------------------------------------------
+    // Interface Descriptor
+    0x09,   // bLength: Interface Descriptor size
+    USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor
+    MSC_IFACE_NUM, // bInterfaceNumber: Number of Interface
+    0x00,   // bAlternateSetting: Alternate setting
+    0x02,   // bNumEndpoints
+    0x08,   // bInterfaceClass: MSC Class
+    0x06,   // bInterfaceSubClass : SCSI transparent
+    0x50,   // nInterfaceProtocol
+    0x00,   // iInterface:
+
+    // Endpoint IN descriptor
+    0x07,                           // bLength: Endpoint descriptor length
+    USB_DESC_TYPE_ENDPOINT,         // bDescriptorType: Endpoint descriptor type
+    MSC_IN_EP,                      // bEndpointAddress: IN, address 3
+    0x02,                           // bmAttributes: Bulk endpoint type
+    LOBYTE(MSC_MAX_FS_PACKET),      // wMaxPacketSize
+    HIBYTE(MSC_MAX_FS_PACKET),
+    0x00,                           // bInterval: ignore for Bulk transfer
+
+    // Endpoint OUT descriptor
+    0x07,                           // bLength: Endpoint descriptor length
+    USB_DESC_TYPE_ENDPOINT,         // bDescriptorType: Endpoint descriptor type
+    MSC_OUT_EP,                     // bEndpointAddress: OUT, address 3
+    0x02,                           // bmAttributes: Bulk endpoint type
+    LOBYTE(MSC_MAX_FS_PACKET),      // wMaxPacketSize
+    HIBYTE(MSC_MAX_FS_PACKET),
+    0x00,                           // bInterval: ignore for Bulk transfer
+#endif
+};
+
+static uint8_t USBD_CDC_MSC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+    if (pdev->dev_speed == USBD_SPEED_HIGH) {
+        // can't handle high speed
+        return 1;
+    }
+
+#if USE_CDC
+    //----------------------------------
+    // CDC VCP component
+
+    // Open EP IN
+    USBD_LL_OpenEP(pdev,
+                   CDC_IN_EP,
+                   USBD_EP_TYPE_BULK,
+                   CDC_DATA_FS_IN_PACKET_SIZE);
+
+    // Open EP OUT
+    USBD_LL_OpenEP(pdev,
+                   CDC_OUT_EP,
+                   USBD_EP_TYPE_BULK,
+                   CDC_DATA_FS_OUT_PACKET_SIZE);
+
+    // Open Command IN EP
+    USBD_LL_OpenEP(pdev,
+                   CDC_CMD_EP,
+                   USBD_EP_TYPE_INTR,
+                   CDC_CMD_PACKET_SIZE);
+
+    // Init physical Interface components
+    CDC_fops->Init();
+
+    // Init Xfer states
+    CDC_ClassData.TxState =0;
+    CDC_ClassData.RxState =0;
+
+    // Prepare Out endpoint to receive next packet
+    USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, CDC_ClassData.RxBuffer, CDC_DATA_FS_OUT_PACKET_SIZE);
+#endif
+
+#if USE_MSC
+    //----------------------------------
+    // MSC component
+
+    // Open EP OUT
+    USBD_LL_OpenEP(pdev,
+                   MSC_OUT_EP,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_FS_PACKET);
+
+    // Open EP IN
+    USBD_LL_OpenEP(pdev,
+                   MSC_IN_EP,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_FS_PACKET);
+
+    // MSC uses the pClassData pointer because SCSI and BOT reference it
+    pdev->pClassData = &MSC_BOT_ClassData;
+
+    // Init the BOT layer
+    MSC_BOT_Init(pdev);
+#endif
+
+    return 0;
+}
+
+static uint8_t USBD_CDC_MSC_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+#if USD_CDC
+    //----------------------------------
+    // CDC VCP component
+
+    // close endpoints
+    USBD_LL_CloseEP(pdev, CDC_IN_EP);
+    USBD_LL_CloseEP(pdev, CDC_OUT_EP);
+    USBD_LL_CloseEP(pdev, CDC_CMD_EP);
+
+    // DeInit physical Interface components
+    CDC_fops->DeInit();
+#endif
+
+#if USE_MSC
+    //----------------------------------
+    // MSC component
+
+    // close endpoints
+    USBD_LL_CloseEP(pdev, MSC_OUT_EP);
+    USBD_LL_CloseEP(pdev, MSC_IN_EP);
+
+    // DeInit the BOT layer
+    MSC_BOT_DeInit(pdev);
+
+    // clear the pointer
+    pdev->pClassData = NULL;
+#endif
+
+    return 0;
+}
+
+static uint8_t USBD_CDC_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
+
+    /*
+    printf("SU: %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex);
+    This is what we get when MSC is IFACE=0 and CDC is IFACE=1,2:
+        SU: 21 22 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
+        SU: 21 20 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_LINE_CODING
+        SU: a1 fe 0 0 -- 0x80 | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; BOT_GET_MAX_LUN; 0; 0
+        SU: 21 22 3 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
+    */
+
+    switch (req->bmRequest & USB_REQ_TYPE_MASK) {
+
+  /* Class request */
+  case USB_REQ_TYPE_CLASS :
+      // req->wIndex is the recipient interface number
+      if (0) {
+#if USE_CDC
+      } else if (req->wIndex == CDC_IFACE_NUM) {
+          // CDC component
+            if (req->wLength) {
+              if (req->bmRequest & 0x80)
+              {
+                CDC_fops->Control(req->bRequest, (uint8_t *)CDC_ClassData.data, req->wLength);
+                  USBD_CtlSendData (pdev, (uint8_t *)CDC_ClassData.data, req->wLength);
+              }
+              else
+              {
+                CDC_ClassData.CmdOpCode = req->bRequest;
+                CDC_ClassData.CmdLength = req->wLength;
+                USBD_CtlPrepareRx (pdev, (uint8_t *)CDC_ClassData.data, req->wLength);
+              }
+              break;
+            }
+#endif
+#if USE_MSC
+      } else if (req->wIndex == MSC_IFACE_NUM) {
+          // MSC component
+        switch (req->bRequest) {
+        case BOT_GET_MAX_LUN :
+
+          if((req->wValue  == 0) && 
+             (req->wLength == 1) &&
+             ((req->bmRequest & 0x80) == 0x80))
+          {
+            MSC_BOT_ClassData.max_lun = MSC_fops->GetMaxLun();
+            USBD_CtlSendData (pdev, (uint8_t *)&MSC_BOT_ClassData.max_lun, 1);
+          }
+          else
+          {
+             USBD_CtlError(pdev , req);
+             return USBD_FAIL; 
+          }
+          break;
+          
+        case BOT_RESET :
+          if((req->wValue  == 0) && 
+             (req->wLength == 0) &&
+            ((req->bmRequest & 0x80) != 0x80))
+          {      
+             MSC_BOT_Reset(pdev);
+          }
+          else
+          {
+             USBD_CtlError(pdev , req);
+             return USBD_FAIL; 
+          }
+          break;
+
+        default:
+           USBD_CtlError(pdev , req);
+           return USBD_FAIL; 
+        }
+    break;
+      }
+#endif
+      break;
+
+    /* Interface & Endpoint request */
+    case USB_REQ_TYPE_STANDARD:
+#if USE_MSC
+        // MSC only
+        switch (req->bRequest) {
+            case USB_REQ_GET_INTERFACE :
+                USBD_CtlSendData(pdev, (uint8_t *)&MSC_BOT_ClassData.interface, 1);
+                break;
+
+            case USB_REQ_SET_INTERFACE :
+                MSC_BOT_ClassData.interface = (uint8_t)(req->wValue);
+                break;
+
+            case USB_REQ_CLEAR_FEATURE:
+                /* Flush the FIFO and Clear the stall status */
+                USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
+
+                /* Re-activate the EP */
+                USBD_LL_CloseEP (pdev , (uint8_t)req->wIndex);
+                if((((uint8_t)req->wIndex) & 0x80) == 0x80) {
+                    /* Open EP IN */
+                    USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
+                } else {
+                    /* Open EP OUT */
+                    USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET);
+                }
+                /* Handle BOT error */
+                MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+                break;
+        }
+#endif
+        break;
+    }
+    return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_EP0_RxReady(USBD_HandleTypeDef *pdev) {
+  if((CDC_fops != NULL) && (CDC_ClassData.CmdOpCode != 0xFF)) {
+    CDC_fops->Control(CDC_ClassData.CmdOpCode,
+                                                      (uint8_t *)CDC_ClassData.data,
+                                                      CDC_ClassData.CmdLength);
+      CDC_ClassData.CmdOpCode = 0xFF; 
+      
+  }
+  return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+    switch (epnum) {
+#if USE_CDC
+        case (CDC_IN_EP & 0x7f):
+        case (CDC_CMD_EP & 0x7f):
+            CDC_ClassData.TxState = 0;
+            return USBD_OK;
+#endif
+
+        case (MSC_IN_EP & 0x7f):
+            MSC_BOT_DataIn(pdev, epnum);
+            return USBD_OK;
+    }
+
+    return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+    switch (epnum) {
+#if USE_CDC
+        case (CDC_OUT_EP & 0x7f):
+            /* Get the received data length */
+            CDC_ClassData.RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
+
+            /* USB data will be immediately processed, this allow next USB traffic being
+            NAKed till the end of the application Xfer */
+            CDC_fops->Receive(CDC_ClassData.RxBuffer, &CDC_ClassData.RxLength);
+
+            return USBD_OK;
+#endif
+
+        case (MSC_OUT_EP & 0x7f):
+            MSC_BOT_DataOut(pdev, epnum);
+            return USBD_OK;
+    }
+
+    return USBD_OK;
+}
+
+static uint8_t *USBD_CDC_MSC_GetFSCfgDesc(uint16_t *length) {
+    *length = sizeof(USBD_CDC_MSC_CfgFSDesc);
+    return USBD_CDC_MSC_CfgFSDesc;
+}
+
+static uint8_t *USBD_CDC_MSC_GetHSCfgDesc(uint16_t *length) {
+    *length = 0;
+    return USBD_CDC_MSC_CfgFSDesc; // need to return something because the USB driver writes bytes to the result
+}
+
+static uint8_t *USBD_CDC_MSC_GetOtherSpeedCfgDesc (uint16_t *length) {
+    *length = 0;
+    return USBD_CDC_MSC_CfgFSDesc; // need to return something because the USB driver writes bytes to the result
+}
+
+uint8_t *USBD_CDC_MSC_GetDeviceQualifierDescriptor (uint16_t *length) {
+    *length = sizeof(USBD_CDC_MSC_DeviceQualifierDesc);
+    return USBD_CDC_MSC_DeviceQualifierDesc;
+}
+
+uint8_t USBD_CDC_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_CDC_ItfTypeDef *fops) {
+    if (fops == NULL) {
+        return USBD_FAIL;
+    } else {
+        CDC_fops = fops;
+        return USBD_OK;
+    }
+}
+
+/**
+  * @brief  USBD_CDC_SetTxBuffer
+  * @param  pdev: device instance
+  * @param  pbuff: Tx Buffer
+  * @retval status
+  */
+uint8_t  USBD_CDC_SetTxBuffer  (USBD_HandleTypeDef   *pdev,
+                                uint8_t  *pbuff,
+                                uint16_t length)
+{
+  CDC_ClassData.TxBuffer = pbuff;
+  CDC_ClassData.TxLength = length;  
+  
+  return USBD_OK;  
+}
+
+
+/**
+  * @brief  USBD_CDC_SetRxBuffer
+  * @param  pdev: device instance
+  * @param  pbuff: Rx Buffer
+  * @retval status
+  */
+uint8_t  USBD_CDC_SetRxBuffer  (USBD_HandleTypeDef   *pdev,
+                                   uint8_t  *pbuff)
+{
+  CDC_ClassData.RxBuffer = pbuff;
+  
+  return USBD_OK;
+}
+
+/**
+  * @brief  USBD_CDC_DataOut
+  *         Data received on non-control Out endpoint
+  * @param  pdev: device instance
+  * @param  epnum: endpoint number
+  * @retval status
+  */
+uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev) {
+    if(CDC_ClassData.TxState == 0) {
+      
+      /* Transmit next packet */
+      USBD_LL_Transmit(pdev,
+                       CDC_IN_EP,
+                       CDC_ClassData.TxBuffer,
+                       CDC_ClassData.TxLength);
+      
+      /* Tx Transfer in progress */
+      CDC_ClassData.TxState = 1;
+      return USBD_OK;
+    }
+    else
+    {
+      return USBD_BUSY;
+    }
+}
+
+
+/**
+  * @brief  USBD_CDC_ReceivePacket
+  *         prepare OUT Endpoint for reception
+  * @param  pdev: device instance
+  * @retval status
+  */
+uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev) {
+    // Suspend or Resume USB Out process
+    if (pdev->dev_speed == USBD_SPEED_HIGH) {
+        return USBD_FAIL;
+    }
+
+    // Prepare Out endpoint to receive next packet */
+    USBD_LL_PrepareReceive(pdev,
+                           CDC_OUT_EP,
+                           CDC_ClassData.RxBuffer,
+                           CDC_DATA_FS_OUT_PACKET_SIZE);
+
+    return USBD_OK;
+}
+
+uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops) {
+    if (fops == NULL) {
+        return USBD_FAIL;
+    } else {
+        MSC_fops = fops;
+        pdev->pUserData = fops; // MSC uses pUserData because SCSI and BOT reference it
+        return USBD_OK;
+    }
+}
+
+// CDC + MSC interface class callbacks structure
+USBD_ClassTypeDef USBD_CDC_MSC = {
+    USBD_CDC_MSC_Init,
+    USBD_CDC_MSC_DeInit,
+    USBD_CDC_MSC_Setup,
+    NULL, // EP0_TxSent
+    USBD_CDC_MSC_EP0_RxReady,
+    USBD_CDC_MSC_DataIn,
+    USBD_CDC_MSC_DataOut,
+    NULL, // SOF
+    NULL,
+    NULL,
+    USBD_CDC_MSC_GetHSCfgDesc,
+    USBD_CDC_MSC_GetFSCfgDesc,
+    USBD_CDC_MSC_GetOtherSpeedCfgDesc,
+    USBD_CDC_MSC_GetDeviceQualifierDescriptor,
+};
diff --git a/stmhal/usbdev/class/cdc_msc/src/usbd_msc.c b/stmhal/usbdev/class/cdc_msc/src/usbd_msc.c
new file mode 100644
index 000000000..7817c98b1
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/src/usbd_msc.c
@@ -0,0 +1,609 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_core.c
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   This file provides all the MSC core functions.
+  *
+  * @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
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc.h"
+
+
+/** @addtogroup STM32_USB_OTG_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);
+
+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);
+
+
+/**
+  * @}
+  */ 
+
+
+/** @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,     
+  USBD_MSC_GetHSCfgDesc,
+  USBD_MSC_GetFSCfgDesc,  
+  USBD_MSC_GetOtherSpeedCfgDesc,
+  USBD_MSC_GetDeviceQualifierDescriptor,
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+__ALIGN_BEGIN uint8_t USBD_MSC_CfgHSDesc[USB_MSC_CONFIG_DESC_SIZ]  __ALIGN_END =
+{
+  
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
+  USB_MSC_CONFIG_DESC_SIZ,
+  
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 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_HS_PACKET),
+  HIBYTE(MSC_MAX_HS_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_HS_PACKET),
+  HIBYTE(MSC_MAX_HS_PACKET),
+  0x00     /*Polling interval in milliseconds*/
+};
+
+/* USB Mass storage device Configuration Descriptor */
+/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+uint8_t USBD_MSC_CfgFSDesc[USB_MSC_CONFIG_DESC_SIZ]  __ALIGN_END =
+{
+  
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
+  USB_MSC_CONFIG_DESC_SIZ,
+  
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 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*/
+};
+
+__ALIGN_BEGIN uint8_t USBD_MSC_OtherSpeedCfgDesc[USB_MSC_CONFIG_DESC_SIZ]   __ALIGN_END  =
+{
+  
+  0x09,   /* bLength: Configuation Descriptor size */
+  USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION,   
+  USB_MSC_CONFIG_DESC_SIZ,
+  
+  0x00,
+  0x01,   /* bNumInterfaces: 1 interface */
+  0x01,   /* bConfigurationValue: */
+  0x04,   /* iConfiguration: */
+  0xC0,   /* bmAttributes: */
+  0x32,   /* MaxPower 100 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 command set*/
+  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 */
+  0x40,
+  0x00,
+  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 */
+  0x40,
+  0x00,
+  0x00     /*Polling interval in milliseconds*/
+};
+
+/* USB Standard Device Descriptor */
+__ALIGN_BEGIN  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,
+};
+/**
+  * @}
+  */ 
+
+
+/** @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)
+{
+  int16_t ret = 0;
+   
+  if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
+  {
+    /* Open EP OUT */
+    USBD_LL_OpenEP(pdev,
+                   MSC_EPOUT_ADDR,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_HS_PACKET);
+    
+    /* Open EP IN */
+    USBD_LL_OpenEP(pdev,
+                   MSC_EPIN_ADDR,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_HS_PACKET);  
+  }
+  else
+  {
+    /* Open EP OUT */
+    USBD_LL_OpenEP(pdev,
+                   MSC_EPOUT_ADDR,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_FS_PACKET);
+    
+    /* Open EP IN */
+    USBD_LL_OpenEP(pdev,
+                   MSC_EPIN_ADDR,
+                   USBD_EP_TYPE_BULK,
+                   MSC_MAX_FS_PACKET);  
+  }
+  pdev->pClassData = USBD_malloc(sizeof (USBD_MSC_BOT_HandleTypeDef));
+  
+  if(pdev->pClassData == NULL)
+  {
+    ret = 1; 
+  }
+  else
+  {
+    /* Init the BOT  layer */
+    MSC_BOT_Init(pdev); 
+    ret = 0;
+  }
+  
+  return ret;
+}
+
+/**
+  * @brief  USBD_MSC_DeInit
+  *         DeInitilaize  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)
+{
+  /* Close MSC EPs */
+  USBD_LL_CloseEP(pdev,
+                  MSC_EPOUT_ADDR);
+  
+  /* Open EP IN */
+  USBD_LL_CloseEP(pdev,
+                  MSC_EPIN_ADDR);
+  
+  
+    /* D-Init the BOT layer */
+  MSC_BOT_DeInit(pdev);
+  
+  /* Free MSC Class Resources */
+  if(pdev->pClassData != NULL)
+  {
+    USBD_free(pdev->pClassData);
+    pdev->pClassData  = NULL; 
+  }
+  return 0;
+}
+/**
+* @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 = pdev->pClassData;
+  
+  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  == 0) && 
+         (req->wLength == 1) &&
+         ((req->bmRequest & 0x80) == 0x80))
+      {
+        hmsc->max_lun = ((USBD_StorageTypeDef *)pdev->pUserData)->GetMaxLun();
+        USBD_CtlSendData (pdev,
+                          (uint8_t *)&hmsc->max_lun,
+                          1);
+      }
+      else
+      {
+         USBD_CtlError(pdev , req);
+         return USBD_FAIL; 
+      }
+      break;
+      
+    case BOT_RESET :
+      if((req->wValue  == 0) && 
+         (req->wLength == 0) &&
+        ((req->bmRequest & 0x80) != 0x80))
+      {      
+         MSC_BOT_Reset(pdev);
+      }
+      else
+      {
+         USBD_CtlError(pdev , req);
+         return USBD_FAIL; 
+      }
+      break;
+
+    default:
+       USBD_CtlError(pdev , req);
+       return USBD_FAIL; 
+    }
+    break;
+  /* Interface & Endpoint request */
+  case USB_REQ_TYPE_STANDARD:
+    switch (req->bRequest)
+    {
+    case USB_REQ_GET_INTERFACE :
+      USBD_CtlSendData (pdev,
+                        (uint8_t *)&hmsc->interface,
+                        1);
+      break;
+      
+    case USB_REQ_SET_INTERFACE :
+      hmsc->interface = (uint8_t)(req->wValue);
+      break;
+    
+    case USB_REQ_CLEAR_FEATURE:  
+      
+      /* Flush the FIFO and Clear the stall status */    
+      USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex);
+      
+      /* Re-activate the EP */      
+      USBD_LL_CloseEP (pdev , (uint8_t)req->wIndex);
+      if((((uint8_t)req->wIndex) & 0x80) == 0x80)
+      {
+        if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
+        {
+          /* Open EP IN */
+          USBD_LL_OpenEP(pdev,
+                         MSC_EPIN_ADDR,
+                         USBD_EP_TYPE_BULK,
+                         MSC_MAX_HS_PACKET);  
+        }
+        else
+        {   
+          /* Open EP IN */
+          USBD_LL_OpenEP(pdev,
+                         MSC_EPIN_ADDR,
+                         USBD_EP_TYPE_BULK,
+                         MSC_MAX_FS_PACKET);  
+        }
+      }
+      else
+      {
+        if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
+        {
+          /* Open EP IN */
+          USBD_LL_OpenEP(pdev,
+                         MSC_EPOUT_ADDR,
+                         USBD_EP_TYPE_BULK,
+                         MSC_MAX_HS_PACKET);  
+        }
+        else
+        {   
+          /* Open EP IN */
+          USBD_LL_OpenEP(pdev,
+                         MSC_EPOUT_ADDR,
+                         USBD_EP_TYPE_BULK,
+                         MSC_MAX_FS_PACKET);  
+        }
+      }
+      
+      /* Handle BOT error */
+      MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+      break;
+      
+    }  
+    break;
+   
+  default:
+    break;
+  }
+  return 0;
+}
+
+/**
+* @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 0;
+}
+
+/**
+* @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 0;
+}
+
+/**
+* @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)
+{
+  *length = sizeof (USBD_MSC_CfgHSDesc);
+  return USBD_MSC_CfgHSDesc;
+}
+
+/**
+* @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)
+{
+  *length = sizeof (USBD_MSC_CfgFSDesc);
+  return USBD_MSC_CfgFSDesc;
+}
+
+/**
+* @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)
+{
+  *length = sizeof (USBD_MSC_OtherSpeedCfgDesc);
+  return USBD_MSC_OtherSpeedCfgDesc;
+}
+/**
+* @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 = sizeof (USBD_MSC_DeviceQualifierDesc);
+  return USBD_MSC_DeviceQualifierDesc;
+}
+
+/**
+* @brief  USBD_MSC_RegisterStorage
+* @param  fops: storage callback
+* @retval status
+*/
+uint8_t  USBD_MSC_RegisterStorage  (USBD_HandleTypeDef   *pdev, 
+                                    USBD_StorageTypeDef *fops)
+{
+  if(fops != NULL)
+  {
+    pdev->pUserData= fops;
+  }
+  return 0;
+}
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stmhal/usbdev/class/cdc_msc/src/usbd_msc_bot.c b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_bot.c
new file mode 100644
index 000000000..69c34a583
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_bot.c
@@ -0,0 +1,407 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_bot.c
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   This file provides all the BOT protocol core functions.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_cdc_msc.h"
+#include "usbd_ioreq.h"
+
+/** @addtogroup STM32_USB_OTG_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
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+
+/** @defgroup MSC_BOT_Private_FunctionPrototypes
+  * @{
+  */ 
+static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef  *pdev);
+
+static void MSC_BOT_SendData (USBD_HandleTypeDef  *pdev, 
+                              uint8_t* pbuf, 
+                              uint16_t len);
+
+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 = pdev->pClassData;
+    
+  hmsc->bot_state  = USBD_BOT_IDLE;
+  hmsc->bot_status = USBD_BOT_STATUS_NORMAL;
+  
+  hmsc->scsi_sense_tail = 0;
+  hmsc->scsi_sense_head = 0;
+  
+  ((USBD_StorageTypeDef *)pdev->pUserData)->Init(0);
+  
+  USBD_LL_FlushEP(pdev, MSC_OUT_EP);
+  USBD_LL_FlushEP(pdev, MSC_IN_EP);
+  
+  /* Prapare EP to Receive First BOT Cmd */
+  USBD_LL_PrepareReceive (pdev,
+                          MSC_OUT_EP,
+                          (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 = pdev->pClassData;
+    
+  hmsc->bot_state  = USBD_BOT_IDLE;
+  hmsc->bot_status = USBD_BOT_STATUS_RECOVERY;  
+  
+  /* Prapare EP to Receive First BOT Cmd */
+  USBD_LL_PrepareReceive (pdev,
+                          MSC_OUT_EP,
+                          (uint8_t *)&hmsc->cbw,
+                          USBD_BOT_CBW_LENGTH);   
+}
+
+/**
+* @brief  MSC_BOT_DeInit
+*         Uninitialize the BOT Machine
+* @param  pdev: device instance
+* @retval None
+*/
+void MSC_BOT_DeInit (USBD_HandleTypeDef  *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;  
+  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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;  
+  
+  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
+*         Proccess MSC OUT data
+* @param  pdev: device instance
+* @param  epnum: endpoint index
+* @retval None
+*/
+void MSC_BOT_DataOut (USBD_HandleTypeDef  *pdev, 
+                      uint8_t epnum)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;
+  
+  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 accordingtly  
+* @param  pdev: device instance
+* @retval None
+*/
+static void  MSC_BOT_CBW_Decode (USBD_HandleTypeDef  *pdev)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;  
+  
+  hmsc->csw.dTag = hmsc->cbw.dTag;
+  hmsc->csw.dDataResidue = hmsc->cbw.dDataLength;
+  
+  if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) ||
+      (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)||
+        (hmsc->cbw.bLUN > 1) || 
+          (hmsc->cbw.bCBLength < 1) || 
+            (hmsc->cbw.bCBLength > 16))
+  {
+    
+    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 > 0)
+      {
+        MSC_BOT_SendData(pdev,
+                         hmsc->bot_data, 
+                         hmsc->bot_data_length);
+      }
+      else if (hmsc->bot_data_length == 0) 
+      {
+        MSC_BOT_SendCSW (pdev,
+                         USBD_CSW_CMD_PASSED);
+      }
+    }
+  }
+}
+
+/**
+* @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* buf, 
+                              uint16_t len)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  len = MIN (hmsc->cbw.dDataLength, len);
+  hmsc->csw.dDataResidue -= len;
+  hmsc->csw.bStatus = USBD_CSW_CMD_PASSED;
+  hmsc->bot_state = USBD_BOT_SEND_DATA;
+  
+  USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len);  
+}
+
+/**
+* @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 = pdev->pClassData; 
+  
+  hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE;
+  hmsc->csw.bStatus = CSW_Status;
+  hmsc->bot_state = USBD_BOT_IDLE;
+  
+  USBD_LL_Transmit (pdev, 
+             MSC_IN_EP, 
+             (uint8_t *)&hmsc->csw, 
+             USBD_BOT_CSW_LENGTH);
+  
+  /* Prapare EP to Receive next Cmd */
+  USBD_LL_PrepareReceive (pdev,
+                    MSC_OUT_EP,
+                    (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 = pdev->pClassData; 
+  
+  if ((hmsc->cbw.bmFlags == 0) && 
+      (hmsc->cbw.dDataLength != 0) &&
+      (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) )
+  {
+    USBD_LL_StallEP(pdev, MSC_OUT_EP );
+  }
+  USBD_LL_StallEP(pdev, MSC_IN_EP);
+  
+  if(hmsc->bot_status == USBD_BOT_STATUS_ERROR)
+  {
+    USBD_LL_PrepareReceive (pdev,
+                      MSC_OUT_EP,
+                      (uint8_t *)&hmsc->cbw, 
+                      USBD_BOT_CBW_LENGTH);    
+  }
+}
+
+/**
+* @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 = pdev->pClassData; 
+  
+  if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */
+  {
+    USBD_LL_StallEP(pdev, MSC_IN_EP);
+    hmsc->bot_status = USBD_BOT_STATUS_NORMAL;    
+  }
+  else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY))
+  {
+    MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED);
+  }
+  
+}
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stmhal/usbdev/class/cdc_msc/src/usbd_msc_data.c b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_data.c
new file mode 100644
index 000000000..4d72bd5fc
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_data.c
@@ -0,0 +1,134 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_data.c
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   This file provides all the vital inquiry pages and sense data.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_data.h"
+
+
+/** @addtogroup STM32_USB_OTG_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 */
+const uint8_t  MSC_Page00_Inquiry_Data[] = {//7						
+	0x00,		
+	0x00, 
+	0x00, 
+	(LENGTH_INQUIRY_PAGE00 - 4),
+	0x00, 
+	0x80, 
+	0x83 
+};  
+/* USB Mass storage sense 6  Data */
+const uint8_t  MSC_Mode_Sense6_data[] = {
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00, 
+	0x00,
+	0x00
+};	
+/* USB Mass storage sense 10  Data */
+const uint8_t  MSC_Mode_Sense10_data[] = {
+	0x00,
+	0x06, 
+	0x00, 
+	0x00, 
+	0x00, 
+	0x00, 
+	0x00, 
+	0x00
+};
+/**
+  * @}
+  */ 
+
+
+/** @defgroup MSC_DATA_Private_FunctionPrototypes
+  * @{
+  */ 
+/**
+  * @}
+  */ 
+
+
+/** @defgroup MSC_DATA_Private_Functions
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stmhal/usbdev/class/cdc_msc/src/usbd_msc_scsi.c b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_scsi.c
new file mode 100644
index 000000000..dd3de90fe
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc/src/usbd_msc_scsi.c
@@ -0,0 +1,770 @@
+/**
+  ******************************************************************************
+  * @file    usbd_msc_scsi.c
+  * @author  MCD Application Team
+  * @version V2.0.0
+  * @date    18-February-2014
+  * @brief   This file provides all the USBD SCSI layer functions.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc_bot.h"
+#include "usbd_msc_scsi.h"
+#include "usbd_msc_data.h"
+#include "usbd_cdc_msc.h"
+
+
+
+/** @addtogroup STM32_USB_OTG_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
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+
+/** @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_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_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_Read10(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_CheckAddressRange (USBD_HandleTypeDef  *pdev, 
+                                      uint8_t lun , 
+                                      uint32_t blk_offset , 
+                                      uint16_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);
+/**
+  * @}
+  */ 
+
+
+/** @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 *params)
+{
+  
+  switch (params[0])
+  {
+  case SCSI_TEST_UNIT_READY:
+    return SCSI_TestUnitReady(pdev, lun, params);
+    
+  case SCSI_REQUEST_SENSE:
+    return SCSI_RequestSense (pdev, lun, params);
+  case SCSI_INQUIRY:
+    return SCSI_Inquiry(pdev, lun, params);
+    
+  case SCSI_START_STOP_UNIT:
+    return SCSI_StartStopUnit(pdev, lun, params);
+    
+  case SCSI_ALLOW_MEDIUM_REMOVAL:
+    return SCSI_StartStopUnit(pdev, lun, params);
+    
+  case SCSI_MODE_SENSE6:
+    return SCSI_ModeSense6 (pdev, lun, params);
+    
+  case SCSI_MODE_SENSE10:
+    return SCSI_ModeSense10 (pdev, lun, params);
+    
+  case SCSI_READ_FORMAT_CAPACITIES:
+    return SCSI_ReadFormatCapacity(pdev, lun, params);
+    
+  case SCSI_READ_CAPACITY10:
+    return SCSI_ReadCapacity10(pdev, lun, params);
+    
+  case SCSI_READ10:
+    return SCSI_Read10(pdev, lun, params); 
+    
+  case SCSI_WRITE10:
+    return SCSI_Write10(pdev, lun, params);
+    
+  case SCSI_VERIFY10:
+    return SCSI_Verify10(pdev, lun, params);
+    
+  default:
+    SCSI_SenseCode(pdev, 
+                   lun,
+                   ILLEGAL_REQUEST, 
+                   INVALID_CDB);    
+    return -1;
+  }
+}
+
+
+/**
+* @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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;  
+    
+  /* case 9 : Hi > D0 */
+  if (hmsc->cbw.dDataLength != 0)
+  {
+    SCSI_SenseCode(pdev,
+                   hmsc->cbw.bLUN, 
+                   ILLEGAL_REQUEST, 
+                   INVALID_CDB);
+    return -1;
+  }  
+  
+  if(((USBD_StorageTypeDef *)pdev->pUserData)->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 = 0;
+  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 = pdev->pClassData; 
+  
+  if (params[1] & 0x01)/*Evpd is set*/
+  {
+    pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
+    len = LENGTH_INQUIRY_PAGE00;
+  }
+  else
+  {
+    
+    pPage = (uint8_t *)&((USBD_StorageTypeDef *)pdev->pUserData)->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN];
+    len = pPage[4] + 5;
+    
+    if (params[4] <= len)
+    {
+      len = params[4];
+    }
+  }
+  hmsc->bot_data_length = len;
+  
+  while (len) 
+  {
+    len--;
+    hmsc->bot_data[len] = 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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
+  {
+    SCSI_SenseCode(pdev,
+                   lun,
+                   NOT_READY, 
+                   MEDIUM_NOT_PRESENT);
+    return -1;
+  } 
+  else
+  {
+    
+    hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
+    hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
+    hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >>  8);
+    hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
+    
+    hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
+    hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
+    hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
+    hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
+    
+    hmsc->bot_data_length = 8;
+    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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  uint16_t blk_size;
+  uint32_t blk_nbr;
+  uint16_t i;
+  
+  for(i=0 ; i < 12 ; i++) 
+  {
+    hmsc->bot_data[i] = 0;
+  }
+  
+  if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
+  {
+    SCSI_SenseCode(pdev,
+                   lun,
+                   NOT_READY, 
+                   MEDIUM_NOT_PRESENT);
+    return -1;
+  } 
+  else
+  {
+    hmsc->bot_data[3] = 0x08;
+    hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
+    hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
+    hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >>  8);
+    hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
+    
+    hmsc->bot_data[8] = 0x02;
+    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 = 12;
+    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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  uint16_t len = 8 ;
+  hmsc->bot_data_length = len;
+  
+  while (len) 
+  {
+    len--;
+    hmsc->bot_data[len] = 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)
+{
+  uint16_t len = 8;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  hmsc->bot_data_length = len;
+
+  while (len) 
+  {
+    len--;
+    hmsc->bot_data[len] = 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)
+{
+  uint8_t i;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) 
+  {
+    hmsc->bot_data[i] = 0;
+  }
+  
+  hmsc->bot_data[0]	= 0x70;		
+  hmsc->bot_data[7]	= REQUEST_SENSE_DATA_LEN - 6;	
+  
+  if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
+    
+    hmsc->bot_data[2]     = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;		
+    hmsc->bot_data[12]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;	
+    hmsc->bot_data[13]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;	
+    hmsc->scsi_sense_head++;
+    
+    if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
+    {
+      hmsc->scsi_sense_head = 0;
+    }
+  }
+  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 Key
+* @retval none
+
+*/
+void SCSI_SenseCode(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey  = sKey;
+  hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
+  hmsc->scsi_sense_tail++;
+  if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
+  {
+    hmsc->scsi_sense_tail = 0;
+  }
+}
+/**
+* @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)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData;   
+  hmsc->bot_data_length = 0;
+  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 = pdev->pClassData; 
+  
+  if(hmsc->bot_state == USBD_BOT_IDLE)  /* Idle */
+  {
+    
+    /* case 10 : Ho <> Di */
+    
+    if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
+    {
+      SCSI_SenseCode(pdev,
+                     hmsc->cbw.bLUN, 
+                     ILLEGAL_REQUEST, 
+                     INVALID_CDB);
+      return -1;
+    }    
+    
+    if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
+    {
+      SCSI_SenseCode(pdev,
+                     lun,
+                     NOT_READY, 
+                     MEDIUM_NOT_PRESENT);
+      return -1;
+    } 
+    
+    hmsc->scsi_blk_addr = (params[2] << 24) | \
+      (params[3] << 16) | \
+        (params[4] <<  8) | \
+          params[5];
+    
+    hmsc->scsi_blk_len =  (params[7] <<  8) | \
+      params[8];  
+    
+    
+    
+    if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
+    {
+      return -1; /* error */
+    }
+    
+    hmsc->bot_state = USBD_BOT_DATA_IN;
+    hmsc->scsi_blk_addr *= hmsc->scsi_blk_size;
+    hmsc->scsi_blk_len  *= hmsc->scsi_blk_size;
+    
+    /* cases 4,5 : Hi <> Dn */
+    if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
+    {
+      SCSI_SenseCode(pdev,
+                     hmsc->cbw.bLUN, 
+                     ILLEGAL_REQUEST, 
+                     INVALID_CDB);
+      return -1;
+    }
+  }
+  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 = pdev->pClassData; 
+  
+  if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
+  {
+    
+    /* case 8 : Hi <> Do */
+    
+    if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
+    {
+      SCSI_SenseCode(pdev,
+                     hmsc->cbw.bLUN, 
+                     ILLEGAL_REQUEST, 
+                     INVALID_CDB);
+      return -1;
+    }
+    
+    /* Check whether Media is ready */
+    if(((USBD_StorageTypeDef *)pdev->pUserData)->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)->IsWriteProtected(lun) !=0 )
+    {
+      SCSI_SenseCode(pdev,
+                     lun,
+                     NOT_READY, 
+                     WRITE_PROTECTED);
+      return -1;
+    } 
+    
+    
+    hmsc->scsi_blk_addr = (params[2] << 24) | \
+      (params[3] << 16) | \
+        (params[4] <<  8) | \
+          params[5];
+    hmsc->scsi_blk_len = (params[7] <<  8) | \
+      params[8];  
+    
+    /* check if LBA address is in the right range */
+    if(SCSI_CheckAddressRange(pdev,
+                              lun,
+                              hmsc->scsi_blk_addr,
+                              hmsc->scsi_blk_len) < 0)
+    {
+      return -1; /* error */      
+    }
+    
+    hmsc->scsi_blk_addr *= hmsc->scsi_blk_size;
+    hmsc->scsi_blk_len  *= hmsc->scsi_blk_size;
+    
+    /* cases 3,11,13 : Hn,Ho <> D0 */
+    if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len)
+    {
+      SCSI_SenseCode(pdev,
+                     hmsc->cbw.bLUN, 
+                     ILLEGAL_REQUEST, 
+                     INVALID_CDB);
+      return -1;
+    }
+    
+    /* Prepare EP to receive first data packet */
+    hmsc->bot_state = USBD_BOT_DATA_OUT;  
+    USBD_LL_PrepareReceive (pdev,
+                      MSC_OUT_EP,
+                      hmsc->bot_data, 
+                      MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET));  
+  }
+  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 = pdev->pClassData; 
+  
+  if ((params[1]& 0x02) == 0x02) 
+  {
+    SCSI_SenseCode (pdev,
+                    lun, 
+                    ILLEGAL_REQUEST, 
+                    INVALID_FIELED_IN_COMMAND);
+    return -1; /* Error, Verify Mode Not supported*/
+  }
+  
+  if(SCSI_CheckAddressRange(pdev,
+                            lun, 
+                            hmsc->scsi_blk_addr, 
+                            hmsc->scsi_blk_len) < 0)
+  {
+    return -1; /* error */      
+  }
+  hmsc->bot_data_length = 0;
+  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 , uint16_t blk_nbr)
+{
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  if ((blk_offset + blk_nbr) > hmsc->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 = pdev->pClassData;   
+  uint32_t len;
+  
+  len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); 
+  
+  if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
+                              hmsc->bot_data, 
+                              hmsc->scsi_blk_addr / hmsc->scsi_blk_size, 
+                              len / hmsc->scsi_blk_size) < 0)
+  {
+    
+    SCSI_SenseCode(pdev,
+                   lun, 
+                   HARDWARE_ERROR, 
+                   UNRECOVERED_READ_ERROR);
+    return -1; 
+  }
+  
+  
+  USBD_LL_Transmit (pdev, 
+             MSC_IN_EP,
+             hmsc->bot_data,
+             len);
+  
+  
+  hmsc->scsi_blk_addr   += len; 
+  hmsc->scsi_blk_len    -= len;  
+  
+  /* case 6 : Hi = Di */
+  hmsc->csw.dDataResidue -= len;
+  
+  if (hmsc->scsi_blk_len == 0)
+  {
+    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)
+{
+  uint32_t len;
+  USBD_MSC_BOT_HandleTypeDef  *hmsc = pdev->pClassData; 
+  
+  len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); 
+  
+  if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
+                              hmsc->bot_data, 
+                              hmsc->scsi_blk_addr / hmsc->scsi_blk_size, 
+                              len / hmsc->scsi_blk_size) < 0)
+  {
+    SCSI_SenseCode(pdev,
+                   lun, 
+                   HARDWARE_ERROR, 
+                   WRITE_FAULT);     
+    return -1; 
+  }
+  
+  
+  hmsc->scsi_blk_addr  += len; 
+  hmsc->scsi_blk_len   -= len; 
+  
+  /* case 12 : Ho = Do */
+  hmsc->csw.dDataResidue -= len;
+  
+  if (hmsc->scsi_blk_len == 0)
+  {
+    MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
+  }
+  else
+  {
+    /* Prapare EP to Receive next packet */
+    USBD_LL_PrepareReceive (pdev,
+                            MSC_OUT_EP,
+                            hmsc->bot_data, 
+                            MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); 
+  }
+  
+  return 0;
+}
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+
+/**
+  * @}
+  */ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-- 
GitLab