From 038df4318362325b5b6b77f7582fb6373a240f3c Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Sun, 30 Mar 2014 00:00:15 +0000
Subject: [PATCH] stmhal: Implement selector for USB device mode; improve boot
 up.

Can now choose at boot up whether the USB device is CDC+MSC or CDC+HID.
Choice is made by an option in boot.py, with default being CDC+MSC.
HID+MSC is not currently supported, but should be easy to implement.

Boot up now has ability to change the reset mode: hold down USR switch
while booting and LEDs will count from 1 to 7 to indicate the boot mode.
Release USR when correct mode is selected.  Current modes are 1 (normal
boot), 2 (safe mode), 3 (reset FS mode).
---
 stmhal/Makefile                               |  10 +-
 stmhal/led.c                                  |   2 +-
 stmhal/main.c                                 | 169 ++--
 stmhal/modpyb.c                               |   2 +
 stmhal/qstrdefsport.h                         |   1 +
 stmhal/stm32f4xx_hal_msp.c                    |   2 +-
 stmhal/stm32f4xx_it.c                         |   2 +-
 stmhal/usb.c                                  |  34 +-
 stmhal/usb.h                                  |  14 +-
 stmhal/usbd_cdc_interface.c                   |   2 +-
 .../class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h  |  97 ++
 .../class/cdc_msc_hid/inc/usbd_msc_bot.h      | 151 +++
 .../class/cdc_msc_hid/inc/usbd_msc_data.h     | 104 ++
 .../class/cdc_msc_hid/inc/usbd_msc_scsi.h     | 193 ++++
 .../class/cdc_msc_hid/src/usbd_cdc_msc_hid.c  | 911 ++++++++++++++++++
 .../usbdev/class/cdc_msc_hid/src/usbd_msc.c   | 609 ++++++++++++
 .../class/cdc_msc_hid/src/usbd_msc_bot.c      | 407 ++++++++
 .../class/cdc_msc_hid/src/usbd_msc_data.c     | 134 +++
 .../class/cdc_msc_hid/src/usbd_msc_scsi.c     | 770 +++++++++++++++
 stmhal/usrsw.c                                |  11 +
 stmhal/usrsw.h                                |   1 +
 21 files changed, 3513 insertions(+), 113 deletions(-)
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_bot.h
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_data.h
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_scsi.h
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc.c
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_bot.c
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_data.c
 create mode 100644 stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c

diff --git a/stmhal/Makefile b/stmhal/Makefile
index b4169e3d6..67c1ebcb4 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_msc/inc
+INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc_msc_hid/inc
 #INC += -I$(USBHOST_DIR)
 INC += -I$(FATFS_DIR)/src
 #INC += -I$(CC3K_DIR)
@@ -135,10 +135,10 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
 	core/src/usbd_core.c \
 	core/src/usbd_ctlreq.c \
 	core/src/usbd_ioreq.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_msc_hid/src/usbd_cdc_msc_hid.c \
+	class/cdc_msc_hid/src/usbd_msc_bot.c \
+	class/cdc_msc_hid/src/usbd_msc_scsi.c \
+	class/cdc_msc_hid/src/usbd_msc_data.c \
 	)
 
 #	class/cdc/src/usbd_cdc.c \
diff --git a/stmhal/led.c b/stmhal/led.c
index 557f54538..5ff50fbb8 100644
--- a/stmhal/led.c
+++ b/stmhal/led.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <stm32f4xx_hal.h>
-#include "usbd_cdc_msc.h"
+#include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 
 #include "nlr.h"
diff --git a/stmhal/main.c b/stmhal/main.c
index e40026efd..9efaaec76 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -75,6 +75,7 @@ void __fatal_error(const char *msg) {
 
 STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
 STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
+STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL;
 
 STATIC mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
     if (MP_OBJ_IS_STR(source_dir)) {
@@ -94,6 +95,15 @@ STATIC mp_obj_t pyb_main(mp_obj_t main) {
 
 MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
 
+STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) {
+    if (MP_OBJ_IS_STR(usb_mode)) {
+        pyb_config_usb_mode = usb_mode;
+    }
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_mode_obj, pyb_usb_mode);
+
 void fatality(void) {
     led_state(PYB_LED_R1, 1);
     led_state(PYB_LED_G1, 1);
@@ -109,12 +119,9 @@ static const char fresh_boot_py[] =
 "# can run arbitrary Python, but best to keep it minimal\n"
 "\n"
 "import pyb\n"
-"pyb.source_dir('/src')\n"
-"pyb.main('main.py')\n"
-"#pyb.usb_usr('VCP')\n"
-"#pyb.usb_msd(True, 'dual partition')\n"
-"#pyb.flush_cache(False)\n"
-"#pyb.error_log('error.txt')\n"
+"#pyb.source_dir('/src')\n"
+"#pyb.main('main.py')\n"
+"#pyb.usb_mode('CDC+MSC') # one of: 'CDC+MSC', 'CDC+HID'\n"
 ;
 
 static const char fresh_main_py[] =
@@ -171,23 +178,64 @@ int main(void) {
     // basic sub-system init
     pendsv_init();
     led_init();
+    switch_init0();
 
-    // turn on LED to indicate bootup
-    led_state(PYB_LED_GREEN, 1);
+    int first_soft_reset = true;
+    uint reset_mode;
+
+soft_reset:
+
+    // check if user switch held to select the reset mode
+    reset_mode = 1;
+    led_state(1, 0);
+    led_state(2, 1);
+    led_state(3, 0);
+    led_state(4, 0);
+
+#if MICROPY_HW_HAS_SWITCH
+    if (switch_get()) {
+        for (uint i = 0; i < 3000; i++) {
+            if (!switch_get()) {
+                break;
+            }
+            HAL_Delay(20);
+            if (i % 30 == 29) {
+                reset_mode = (reset_mode + 1) & 7;
+                led_state(2, reset_mode & 1);
+                led_state(3, reset_mode & 2);
+                led_state(4, reset_mode & 4);
+            }
+        }
+        // flash the selected reset mode
+        for (uint i = 0; i < 6; i++) {
+            led_state(2, 0);
+            led_state(3, 0);
+            led_state(4, 0);
+            HAL_Delay(50);
+            led_state(2, reset_mode & 1);
+            led_state(3, reset_mode & 2);
+            led_state(4, reset_mode & 4);
+            HAL_Delay(50);
+        }
+        HAL_Delay(400);
+    }
+#endif
 
 #if MICROPY_HW_ENABLE_RTC
-    rtc_init();
+    if (first_soft_reset) {
+        rtc_init();
+    }
 #endif
 
     // more sub-system init
 #if MICROPY_HW_HAS_SDCARD
-    sdcard_init();
+    if (first_soft_reset) {
+        sdcard_init();
+    }
 #endif
-    storage_init();
-
-    int first_soft_reset = true;
-
-soft_reset:
+    if (first_soft_reset) {
+        storage_init();
+    }
 
     // GC init
     gc_init(&_heap_start, &_heap_end);
@@ -215,6 +263,7 @@ soft_reset:
     exti_init();
 
 #if MICROPY_HW_HAS_SWITCH
+    // must come after exti_init
     switch_init();
 #endif
 
@@ -225,29 +274,12 @@ soft_reset:
 
     pin_map_init();
 
-    // check if user switch held (initiates reset of filesystem)
-    bool reset_filesystem = false;
-#if MICROPY_HW_HAS_SWITCH
-    if (switch_get()) {
-        reset_filesystem = true;
-        for (int i = 0; i < 50; i++) {
-            if (!switch_get()) {
-                reset_filesystem = false;
-                break;
-            }
-            HAL_Delay(10);
-        }
-    }
-#endif
     // local filesystem init
     {
         // try to mount the flash
         FRESULT res = f_mount(&fatfs0, "0:", 1);
-        if (!reset_filesystem && res == FR_OK) {
-            // mount sucessful
-        } else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
-            // no filesystem, so create a fresh one
-            // TODO doesn't seem to work correctly when reset_filesystem is true...
+        if (reset_mode == 3 || res == FR_NO_FILESYSTEM) {
+            // no filesystem, or asked to reset it, so create a fresh one
 
             // LED on to indicate creation of LFS
             led_state(PYB_LED_R2, 1);
@@ -275,6 +307,8 @@ soft_reset:
             // keep LED on for at least 200ms
             sys_tick_wait_at_least(start_tick, 200);
             led_state(PYB_LED_R2, 0);
+        } else if (res == FR_OK) {
+            // mount sucessful
         } else {
             __fatal_error("could not access LFS");
         }
@@ -317,20 +351,24 @@ soft_reset:
     }
 
     // run /boot.py
-    if (!pyexec_file("0:/boot.py")) {
-        flash_error(4);
+    if (reset_mode == 1) {
+        if (!pyexec_file("0:/boot.py")) {
+            flash_error(4);
+        }
     }
 
-    // turn boot-up LED off
-    led_state(PYB_LED_GREEN, 0);
+    // turn boot-up LEDs off
+    led_state(2, 0);
+    led_state(3, 0);
+    led_state(4, 0);
 
 #if defined(USE_DEVICE_MODE)
-    usbd_storage_medium_kind_t usbd_medium_kind = USBD_STORAGE_MEDIUM_FLASH;
+    usb_storage_medium_t usb_medium = USB_STORAGE_MEDIUM_FLASH;
 #endif
 
 #if MICROPY_HW_HAS_SDCARD
     // if an SD card is present then mount it on 1:/
-    if (sdcard_is_present()) {
+    if (reset_mode == 1 && sdcard_is_present()) {
         FRESULT res = f_mount(&fatfs1, "1:", 1);
         if (res != FR_OK) {
             printf("[SD] could not mount SD card\n");
@@ -338,7 +376,7 @@ soft_reset:
             if (first_soft_reset) {
                 // use SD card as medium for the USB MSD
 #if defined(USE_DEVICE_MODE)
-                usbd_medium_kind = USBD_STORAGE_MEDIUM_SDCARD;
+                usb_medium = USB_STORAGE_MEDIUM_SDCARD;
 #endif
             }
         }
@@ -353,7 +391,17 @@ soft_reset:
     pyb_usb_host_init();
 #elif defined(USE_DEVICE_MODE)
     // USB device
-    pyb_usb_dev_init(USBD_DEVICE_CDC_MSC, usbd_medium_kind);
+    if (reset_mode == 1) {
+        usb_device_mode_t usb_mode = USB_DEVICE_MODE_CDC_MSC;
+        if (pyb_config_usb_mode != MP_OBJ_NULL) {
+            if (strcmp(mp_obj_str_get_str(pyb_config_usb_mode), "CDC+HID") == 0) {
+                usb_mode = USB_DEVICE_MODE_CDC_HID;
+            }
+        }
+        pyb_usb_dev_init(usb_mode, usb_medium);
+    } else {
+        pyb_usb_dev_init(USB_DEVICE_MODE_CDC_MSC, usb_medium);
+    }
 #endif
 
 #if MICROPY_HW_ENABLE_RNG
@@ -387,7 +435,7 @@ soft_reset:
 #endif
 
     // run main script
-    {
+    if (reset_mode == 1) {
         vstr_t *vstr = vstr_new();
         vstr_add_str(vstr, "0:/");
         if (pyb_config_source_dir == MP_OBJ_NULL) {
@@ -408,41 +456,6 @@ soft_reset:
     }
 
 #if 0
-#if MICROPY_HW_HAS_MMA7660
-    // HID example
-    if (0) {
-        uint8_t data[4];
-        data[0] = 0;
-        data[1] = 1;
-        data[2] = -2;
-        data[3] = 0;
-        for (;;) {
-        #if MICROPY_HW_HAS_SWITCH
-            if (switch_get()) {
-                data[0] = 0x01; // 0x04 is middle, 0x02 is right
-            } else {
-                data[0] = 0x00;
-            }
-        #else
-            data[0] = 0x00;
-        #endif
-            accel_start(0x4c /* ACCEL_ADDR */, 1);
-            accel_send_byte(0);
-            accel_restart(0x4c /* ACCEL_ADDR */, 0);
-            for (int i = 0; i <= 1; i++) {
-                int v = accel_read_ack() & 0x3f;
-                if (v & 0x20) {
-                    v |= ~0x1f;
-                }
-                data[1 + i] = v;
-            }
-            accel_read_nack();
-            usb_hid_send_report(data);
-            HAL_Delay(15);
-        }
-    }
-#endif
-
 #if MICROPY_HW_HAS_WLAN
     // wifi
     pyb_wlan_init();
diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c
index 6bdb2db84..87fab706d 100644
--- a/stmhal/modpyb.c
+++ b/stmhal/modpyb.c
@@ -208,6 +208,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_input_obj, pyb_input);
 
 MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c
 MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
+MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); // defined in main.c
 
 STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
@@ -220,6 +221,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj },
     { MP_OBJ_NEW_QSTR(MP_QSTR_source_dir), (mp_obj_t)&pyb_source_dir_obj },
     { MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_usb_mode), (mp_obj_t)&pyb_usb_mode_obj },
 
     { MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
     { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index 29d97bafa..0a7fe821d 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -10,6 +10,7 @@ Q(stop)
 Q(standby)
 Q(source_dir)
 Q(main)
+Q(usb_mode)
 Q(sync)
 Q(gc)
 Q(repl_info)
diff --git a/stmhal/stm32f4xx_hal_msp.c b/stmhal/stm32f4xx_hal_msp.c
index 15dca5651..1cf78336f 100644
--- a/stmhal/stm32f4xx_hal_msp.c
+++ b/stmhal/stm32f4xx_hal_msp.c
@@ -38,7 +38,7 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "stm32f4xx_hal.h"
-#include "usbd_cdc_msc.h"
+#include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 
 #include "misc.h"
diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c
index bd324a030..e74b1c6c7 100644
--- a/stmhal/stm32f4xx_it.c
+++ b/stmhal/stm32f4xx_it.c
@@ -42,7 +42,7 @@
 
 #include "stm32f4xx_it.h"
 #include "stm32f4xx_hal.h"
-#include "usbd_cdc_msc.h"
+#include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 
 #include "misc.h"
diff --git a/stmhal/usb.c b/stmhal/usb.c
index 79f9b85f3..3d795f182 100644
--- a/stmhal/usb.c
+++ b/stmhal/usb.c
@@ -2,7 +2,7 @@
 
 #include "usbd_core.h"
 #include "usbd_desc.h"
-#include "usbd_cdc_msc.h"
+#include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 #include "usbd_msc_storage.h"
 
@@ -19,28 +19,24 @@ USBD_HandleTypeDef hUSBDDevice;
 static int dev_is_enabled = 0;
 mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
 
-void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t medium_kind) {
+void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium) {
 #ifdef USE_DEVICE_MODE
     if (!dev_is_enabled) {
         // only init USB once in the device's power-lifetime
-        switch (device_kind) {
-            case USBD_DEVICE_CDC_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);
-                // TODO
-                break;
+        if (mode == USB_DEVICE_MODE_CDC_MSC) {
+            USBD_SelectMode(USBD_MODE_CDC_MSC);
+        } else {
+            USBD_SelectMode(USBD_MODE_CDC_HID);
         }
+        USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
+        USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC_HID);
+        USBD_CDC_RegisterInterface(&hUSBDDevice, (USBD_CDC_ItfTypeDef*)&USBD_CDC_fops);
+        if (medium == USB_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);
     }
     dev_is_enabled = 1;
 
diff --git a/stmhal/usb.h b/stmhal/usb.h
index e30b1364f..014b51eef 100644
--- a/stmhal/usb.h
+++ b/stmhal/usb.h
@@ -5,16 +5,16 @@
 #define VCP_CHAR_CTRL_D (4)
 
 typedef enum {
-    USBD_DEVICE_CDC_MSC,
-    USBD_DEVICE_HID,
-} usbd_device_kind_t;
+    USB_DEVICE_MODE_CDC_MSC,
+    USB_DEVICE_MODE_CDC_HID,
+} usb_device_mode_t;
 
 typedef enum {
-    USBD_STORAGE_MEDIUM_FLASH,
-    USBD_STORAGE_MEDIUM_SDCARD,
-} usbd_storage_medium_kind_t;
+    USB_STORAGE_MEDIUM_FLASH,
+    USB_STORAGE_MEDIUM_SDCARD,
+} usb_storage_medium_t;
 
-void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t medium_kind);
+void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium);
 bool usb_vcp_is_enabled(void);
 bool usb_vcp_is_connected(void);
 void usb_vcp_set_interrupt_char(int c);
diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c
index c441e9c61..693f51b7c 100644
--- a/stmhal/usbd_cdc_interface.c
+++ b/stmhal/usbd_cdc_interface.c
@@ -28,7 +28,7 @@
 /* Includes ------------------------------------------------------------------*/
 #include <stdbool.h>
 #include "stm32f4xx_hal.h"
-#include "usbd_cdc_msc.h"
+#include "usbd_cdc_msc_hid.h"
 #include "usbd_cdc_interface.h"
 #include "pendsv.h"
 #include "usb.h"
diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
new file mode 100644
index 000000000..8423ad775
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
@@ -0,0 +1,97 @@
+#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 and MSC packet sizes
+#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
+#define MSC_MEDIA_PACKET            (2048) // was 8192; how low can it go whilst still working?
+
+// Need to define here for BOT and SCSI layers
+#define MSC_IN_EP     (0x81)
+#define MSC_OUT_EP    (0x01)
+
+// only CDC_MSC and CDC_HID are available
+#define USBD_MODE_CDC (0x01)
+#define USBD_MODE_MSC (0x02)
+#define USBD_MODE_HID (0x04)
+#define USBD_MODE_CDC_MSC (USBD_MODE_CDC | USBD_MODE_MSC)
+#define USBD_MODE_CDC_HID (USBD_MODE_CDC | USBD_MODE_HID)
+#define USBD_MODE_MSC_HID (USBD_MODE_MSC | USBD_MODE_HID)
+
+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_HID;
+
+void USBD_SelectMode(uint32_t mode);
+
+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);
+
+uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);
+
+#endif // _USB_CDC_MSC_CORE_H_
diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_bot.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_bot.h
new file mode 100644
index 000000000..41f8ab5a5
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid/inc/usbd_msc_data.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_data.h
new file mode 100644
index 000000000..f468267f4
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid/inc/usbd_msc_scsi.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_msc_scsi.h
new file mode 100644
index 000000000..dea247bca
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
new file mode 100644
index 000000000..6cb15ba21
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
@@ -0,0 +1,911 @@
+#include "usbd_ioreq.h"
+#include "usbd_cdc_msc_hid.h"
+
+#define USB_CDC_MSC_CONFIG_DESC_SIZ (98)
+#define USB_CDC_HID_CONFIG_DESC_SIZ (100)
+#define CDC_IFACE_NUM (1)
+#define CDC_IN_EP     (0x83)
+#define CDC_OUT_EP    (0x03)
+#define CDC_CMD_EP    (0x82)
+#define MSC_IFACE_NUM (0)
+#define HID_IFACE_NUM_WITH_CDC (0)
+#define HID_IFACE_NUM_WITH_MSC (1)
+#define HID_IN_EP_WITH_CDC (0x81)
+#define HID_IN_EP_WITH_MSC (0x83)
+
+#define USB_DESC_TYPE_ASSOCIATION (0x0b)
+
+#define CDC_CMD_PACKET_SIZE                  8  // Control Endpoint Packet size
+#define CDC_DATA_IN_PACKET_SIZE                CDC_DATA_FS_MAX_PACKET_SIZE
+#define CDC_DATA_OUT_PACKET_SIZE               CDC_DATA_FS_MAX_PACKET_SIZE
+
+#define MSC_MAX_PACKET            0x40
+#define USB_MSC_CONFIG_DESC_SIZ      32
+#define BOT_GET_MAX_LUN              0xFE
+#define BOT_RESET                    0xFF
+
+#define HID_MAX_PACKET             0x04
+#define USB_HID_DESC_SIZ              9
+#define HID_MOUSE_REPORT_DESC_SIZE    74
+#define HID_KEYBOARD_REPORT_DESC_SIZE 63
+#define HID_DESCRIPTOR_TYPE           0x21
+#define HID_REPORT_DESC               0x22
+#define HID_REQ_SET_PROTOCOL          0x0B
+#define HID_REQ_GET_PROTOCOL          0x03
+#define HID_REQ_SET_IDLE              0x0A
+#define HID_REQ_GET_IDLE              0x02
+
+typedef enum {
+  HID_IDLE = 0,
+  HID_BUSY,
+} HID_StateTypeDef;
+
+typedef struct {
+  uint32_t             Protocol;
+  uint32_t             IdleState;
+  uint32_t             AltSetting;
+  HID_StateTypeDef     state;
+} USBD_HID_HandleTypeDef;
+
+static uint8_t usbd_mode;
+static uint8_t hid_in_ep;
+static uint8_t hid_iface_num;
+
+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;
+static USBD_HID_HandleTypeDef HID_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_HID_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_PACKET), HID is 0x04
+    0x01,
+    0x00,
+};
+
+// USB CDC MSC device Configuration Descriptor
+__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgDesc[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),
+    0x03,   // 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
+
+    //==========================================================================
+    // 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
+
+    //==========================================================================
+    // 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_PACKET),         // wMaxPacketSize
+    HIBYTE(MSC_MAX_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_PACKET),         // wMaxPacketSize
+    HIBYTE(MSC_MAX_PACKET),
+    0x00,                           // bInterval: ignore for Bulk transfer
+};
+
+// USB CDC HID device Configuration Descriptor
+__ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] __ALIGN_END = {
+    //--------------------------------------------------------------------------
+    // Configuration Descriptor
+    0x09,   // bLength: Configuration Descriptor size
+    USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration
+    LOBYTE(USB_CDC_HID_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes
+    HIBYTE(USB_CDC_HID_CONFIG_DESC_SIZ),
+    0x03,   // 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
+
+    //==========================================================================
+    // 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
+
+    //==========================================================================
+    // HID only has 1 interface so doesn't need an IAD
+
+    //--------------------------------------------------------------------------
+    // Interface Descriptor
+    0x09,   // bLength: Interface Descriptor size
+    USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor
+    HID_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface
+    0x00,   // bAlternateSetting: Alternate setting
+    0x01,   // bNumEndpoints
+    0x03,   // bInterfaceClass: HID Class
+    0x01,   // bInterfaceSubClass: 1=BOOT, 0=no boot
+    0x01,   // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse
+    0x00,   // iInterface:
+
+    // HID descriptor
+    0x09,                   // bLength: HID Descriptor size
+    HID_DESCRIPTOR_TYPE,    // bDescriptorType: HID
+    0x11,                   // bcdHID: HID Class Spec release number
+    0x01,
+    0x00,                   // bCountryCode: Hardware target country
+    0x01,                   // bNumDescriptors: Number of HID class descriptors to follow
+    0x22,                   // bDescriptorType
+    HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor
+    0x00,
+
+    // Endpoint IN descriptor
+    0x07,                           // bLength: Endpoint descriptor length
+    USB_DESC_TYPE_ENDPOINT,         // bDescriptorType: Endpoint descriptor type
+    HID_IN_EP_WITH_CDC,             // bEndpointAddress: IN
+    0x03,                           // bmAttributes: Interrupt endpoint type
+    LOBYTE(HID_MAX_PACKET),         // wMaxPacketSize
+    HIBYTE(HID_MAX_PACKET),
+    0x08,                           // bInterval: Polling interval
+};
+
+/* USB HID device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END = {
+  0x09,         /*bLength: HID Descriptor size*/
+  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
+  0x11,         /*bcdHID: HID Class Spec release number*/
+  0x01,
+  0x00,         /*bCountryCode: Hardware target country*/
+  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
+  0x22,         /*bDescriptorType*/
+  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
+  0x00,
+};
+
+__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = {
+  0x05,   0x01,
+  0x09,   0x02,
+  0xA1,   0x01,
+  0x09,   0x01,
+
+  0xA1,   0x00,
+  0x05,   0x09,
+  0x19,   0x01,
+  0x29,   0x03,
+
+  0x15,   0x00,
+  0x25,   0x01,
+  0x95,   0x03,
+  0x75,   0x01,
+
+  0x81,   0x02,
+  0x95,   0x01,
+  0x75,   0x05,
+  0x81,   0x01,
+
+  0x05,   0x01,
+  0x09,   0x30,
+  0x09,   0x31,
+  0x09,   0x38,
+
+  0x15,   0x81,
+  0x25,   0x7F,
+  0x75,   0x08,
+  0x95,   0x03,
+
+  0x81,   0x06,
+  0xC0,   0x09,
+  0x3c,   0x05,
+  0xff,   0x09,
+
+  0x01,   0x15,
+  0x00,   0x25,
+  0x01,   0x75,
+  0x01,   0x95,
+
+  0x02,   0xb1,
+  0x22,   0x75,
+  0x06,   0x95,
+  0x01,   0xb1,
+
+  0x01,   0xc0
+};
+
+#if 0
+__ALIGN_BEGIN static const uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = {
+    // From p69 of http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+    0x05, 0x01,     // Usage Page (Generic Desktop),
+    0x09, 0x06,     // Usage (Keyboard),
+    0xA1, 0x01,     // Collection (Application),
+    0x05, 0x07,         // Usage Page (Key Codes);
+    0x19, 0xE0,         // Usage Minimum (224),
+    0x29, 0xE7,         // Usage Maximum (231),
+    0x15, 0x00,         // Logical Minimum (0),
+    0x25, 0x01,         // Logical Maximum (1),
+    0x75, 0x01,         // Report Size (1),
+    0x95, 0x08,         // Report Count (8),
+    0x81, 0x02,         // Input (Data, Variable, Absolute), ;Modifier byte
+    0x95, 0x01,         // Report Count (1),
+    0x75, 0x08,         // Report Size (8),
+    0x81, 0x01,         // Input (Constant), ;Reserved byte
+    0x95, 0x05,         // Report Count (5),
+    0x75, 0x01,         // Report Size (1),
+    0x05, 0x08,         // Usage Page (Page# for LEDs),
+    0x19, 0x01,         // Usage Minimum (1),
+    0x29, 0x05,         // Usage Maximum (5),
+    0x91, 0x02,         // Output (Data, Variable, Absolute), ;LED report
+    0x95, 0x01,         // Report Count (1),
+    0x75, 0x03,         // Report Size (3),
+    0x91, 0x01,         // Output (Constant), ;LED report padding
+    0x95, 0x06,         // Report Count (6),
+    0x75, 0x08,         // Report Size (8),
+    0x15, 0x00,         // Logical Minimum (0),
+    0x25, 0x65,         // Logical Maximum(101),
+    0x05, 0x07,         // Usage Page (Key Codes),
+    0x19, 0x00,         // Usage Minimum (0),
+    0x29, 0x65,         // Usage Maximum (101),
+    0x81, 0x00,         // Input (Data, Array), ;Key arrays (6 bytes)
+    0xC0            // End Collection
+};
+#endif
+
+void USBD_SelectMode(uint32_t mode) {
+    // save mode
+    usbd_mode = mode;
+
+    // set up HID parameters if HID is selected
+    if (mode & USBD_MODE_HID) {
+        if (mode & USBD_MODE_CDC) {
+            hid_in_ep = HID_IN_EP_WITH_CDC;
+            hid_iface_num = HID_IFACE_NUM_WITH_CDC;
+        } else if (mode & USBD_MODE_MSC) {
+            hid_in_ep = HID_IN_EP_WITH_MSC;
+            hid_iface_num = HID_IFACE_NUM_WITH_MSC;
+        }
+    }
+}
+
+static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+    if (pdev->dev_speed == USBD_SPEED_HIGH) {
+        // can't handle high speed
+        return 1;
+    }
+
+    if (usbd_mode & USBD_MODE_CDC) {
+        // CDC VCP component
+
+        // Open EP IN
+        USBD_LL_OpenEP(pdev,
+                       CDC_IN_EP,
+                       USBD_EP_TYPE_BULK,
+                       CDC_DATA_IN_PACKET_SIZE);
+
+        // Open EP OUT
+        USBD_LL_OpenEP(pdev,
+                       CDC_OUT_EP,
+                       USBD_EP_TYPE_BULK,
+                       CDC_DATA_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_OUT_PACKET_SIZE);
+    }
+
+    if (usbd_mode & USBD_MODE_MSC) {
+        // MSC component
+
+        // Open EP OUT
+        USBD_LL_OpenEP(pdev,
+                       MSC_OUT_EP,
+                       USBD_EP_TYPE_BULK,
+                       MSC_MAX_PACKET);
+
+        // Open EP IN
+        USBD_LL_OpenEP(pdev,
+                       MSC_IN_EP,
+                       USBD_EP_TYPE_BULK,
+                       MSC_MAX_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);
+    }
+
+    if (usbd_mode & USBD_MODE_HID) {
+        // HID component
+
+        // Open EP IN
+        USBD_LL_OpenEP(pdev,
+                       hid_in_ep,
+                       USBD_EP_TYPE_INTR,
+                       HID_MAX_PACKET);
+
+        HID_ClassData.state = HID_IDLE;
+    }
+
+    return 0;
+}
+
+static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
+    if (usbd_mode & USBD_MODE_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();
+    }
+
+    if (usbd_mode & USBD_MODE_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;
+    }
+
+    if (usbd_mode & USBD_MODE_HID) {
+        // HID component
+
+        // close endpoints
+        USBD_LL_CloseEP(pdev, hid_in_ep);
+    }
+
+    return 0;
+}
+
+static uint8_t USBD_CDC_MSC_HID_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 ((usbd_mode & USBD_MODE_CDC) && req->wIndex == CDC_IFACE_NUM) {
+                // CDC component
+                if (req->wLength) {
+                    if (req->bmRequest & 0x80) {
+                        // device-to-host request
+                        CDC_fops->Control(req->bRequest, (uint8_t*)CDC_ClassData.data, req->wLength);
+                        USBD_CtlSendData(pdev, (uint8_t*)CDC_ClassData.data, req->wLength);
+                    } else {
+                        // host-to-device request
+                        CDC_ClassData.CmdOpCode = req->bRequest;
+                        CDC_ClassData.CmdLength = req->wLength;
+                        USBD_CtlPrepareRx(pdev, (uint8_t*)CDC_ClassData.data, req->wLength);
+                    }
+                } else {
+                    // Not a Data request
+                    // Transfer the command to the interface layer
+                    return CDC_fops->Control(req->bRequest, NULL, req->wValue);
+                }
+            } else if ((usbd_mode & USBD_MODE_MSC) && 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; 
+                }
+            } else if ((usbd_mode & USBD_MODE_HID) && req->wIndex == hid_iface_num) {
+                switch (req->bRequest) {
+                    case HID_REQ_SET_PROTOCOL:
+                        HID_ClassData.Protocol = (uint8_t)(req->wValue);
+                        break;
+
+                    case HID_REQ_GET_PROTOCOL:
+                        USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.Protocol, 1);
+                        break;
+
+                    case HID_REQ_SET_IDLE:
+                        HID_ClassData.IdleState = (uint8_t)(req->wValue >> 8);
+                        break;
+
+                    case HID_REQ_GET_IDLE:
+                        USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.IdleState, 1);
+                        break;
+
+                    default:
+                        USBD_CtlError(pdev, req);
+                        return USBD_FAIL;
+                }
+            }
+            break;
+
+        // Interface & Endpoint request
+        case USB_REQ_TYPE_STANDARD:
+            if ((usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM) {
+                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_PACKET);
+                        } else {
+                            /* Open EP OUT */
+                            USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET);
+                        }
+                        /* Handle BOT error */
+                        MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+                        break;
+                }
+            } else if ((usbd_mode & USBD_MODE_HID) && req->wIndex == hid_iface_num) {
+                switch (req->bRequest) {
+                    case USB_REQ_GET_DESCRIPTOR: {
+                      uint16_t len = 0;
+                      const uint8_t *pbuf = NULL;
+                      if (req->wValue >> 8 == HID_REPORT_DESC) {
+                        len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength);
+                        pbuf = HID_MOUSE_ReportDesc;
+                      } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) {
+                        len = MIN(USB_HID_DESC_SIZ , req->wLength);
+                        pbuf = USBD_HID_Desc;
+                      }
+                      USBD_CtlSendData(pdev, (uint8_t*)pbuf, len);
+                      break;
+                     }
+
+                    case USB_REQ_GET_INTERFACE:
+                      USBD_CtlSendData (pdev, (uint8_t *)&HID_ClassData.AltSetting, 1);
+                      break;
+
+                    case USB_REQ_SET_INTERFACE:
+                      HID_ClassData.AltSetting = (uint8_t)(req->wValue);
+                      break;
+                }
+            }
+            break;
+    }
+    return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_HID_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_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+    if ((usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) {
+        CDC_ClassData.TxState = 0;
+        return USBD_OK;
+    } else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) {
+        MSC_BOT_DataIn(pdev, epnum);
+        return USBD_OK;
+    } else if ((usbd_mode & USBD_MODE_HID) && epnum == (hid_in_ep & 0x7f)) {
+        /* Ensure that the FIFO is empty before a new transfer, this condition could
+        be caused by  a new transfer before the end of the previous transfer */
+        HID_ClassData.state = HID_IDLE;
+        return USBD_OK;
+    }
+
+    return USBD_OK;
+}
+
+static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
+    if ((usbd_mode & USBD_MODE_CDC) && epnum == (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;
+    } else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
+        MSC_BOT_DataOut(pdev, epnum);
+        return USBD_OK;
+    }
+
+    return USBD_OK;
+}
+
+static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(uint16_t *length) {
+    switch (usbd_mode) {
+        case USBD_MODE_CDC_MSC:
+            *length = sizeof(USBD_CDC_MSC_CfgDesc);
+            return USBD_CDC_MSC_CfgDesc;
+
+        case USBD_MODE_CDC_HID:
+        default:
+            *length = sizeof(USBD_CDC_HID_CfgDesc);
+            return USBD_CDC_HID_CfgDesc;
+    }
+}
+
+uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor (uint16_t *length) {
+    *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc);
+    return USBD_CDC_MSC_HID_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_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;
+    }
+}
+
+uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len) {
+    if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+        if (HID_ClassData.state == HID_IDLE) {
+            HID_ClassData.state = HID_BUSY;
+            USBD_LL_Transmit(pdev, hid_in_ep, report, len);
+        }
+    }
+    return USBD_OK;
+}
+
+// CDC + MSC interface class callbacks structure
+USBD_ClassTypeDef USBD_CDC_MSC_HID = {
+    USBD_CDC_MSC_HID_Init,
+    USBD_CDC_MSC_HID_DeInit,
+    USBD_CDC_MSC_HID_Setup,
+    NULL, // EP0_TxSent
+    USBD_CDC_MSC_HID_EP0_RxReady,
+    USBD_CDC_MSC_HID_DataIn,
+    USBD_CDC_MSC_HID_DataOut,
+    NULL, // SOF
+    NULL,
+    NULL,
+    USBD_CDC_MSC_HID_GetCfgDesc,
+    USBD_CDC_MSC_HID_GetCfgDesc,
+    USBD_CDC_MSC_HID_GetCfgDesc,
+    USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor,
+};
diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc.c
new file mode 100644
index 000000000..7817c98b1
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid/src/usbd_msc_bot.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_bot.c
new file mode 100644
index 000000000..3c06f3cf6
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid.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_hid/src/usbd_msc_data.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_data.c
new file mode 100644
index 000000000..4d72bd5fc
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid/src/usbd_msc_scsi.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c
new file mode 100644
index 000000000..af3818d37
--- /dev/null
+++ b/stmhal/usbdev/class/cdc_msc_hid/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_hid.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****/
diff --git a/stmhal/usrsw.c b/stmhal/usrsw.c
index 69a03b2cc..60032c4ec 100644
--- a/stmhal/usrsw.c
+++ b/stmhal/usrsw.c
@@ -39,6 +39,17 @@ static mp_obj_t switch_callback(mp_obj_t line) {
 }
 static MP_DEFINE_CONST_FUN_OBJ_1(switch_callback_obj, switch_callback);
 
+// this function inits the switch GPIO so that it can be used
+void switch_init0(void) {
+    GPIO_InitTypeDef init;
+    init.Pin = USRSW_PIN.pin_mask;
+    init.Mode = GPIO_MODE_INPUT;
+    init.Pull = USRSW_PULL;
+    init.Speed = GPIO_SPEED_FAST;
+    HAL_GPIO_Init(USRSW_PIN.gpio, &init);
+}
+
+// this function inits the callback and EXTI function of the switch
 void switch_init(void) {
     switch_user_callback_obj = mp_const_none;
     exti_register((mp_obj_t)&USRSW_PIN,
diff --git a/stmhal/usrsw.h b/stmhal/usrsw.h
index 2da8f069b..b1b838653 100644
--- a/stmhal/usrsw.h
+++ b/stmhal/usrsw.h
@@ -1,3 +1,4 @@
+void switch_init0(void);
 void switch_init(void);
 int switch_get(void);
 
-- 
GitLab