diff --git a/stmhal/Makefile b/stmhal/Makefile index b4169e3d63..67c1ebcb42 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 557f54538e..5ff50fbb88 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -1,6 +1,6 @@ #include #include -#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 e40026efdd..9efaaec764 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 6bdb2db846..87fab706d7 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 29d97bafaa..0a7fe821dd 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 15dca56517..1cf78336f8 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 bd324a030d..e74b1c6c75 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 79f9b85f35..3d795f1823 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 e30b1364f9..014b51eefa 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 c441e9c61c..693f51b7c8 100644 --- a/stmhal/usbd_cdc_interface.c +++ b/stmhal/usbd_cdc_interface.c @@ -28,7 +28,7 @@ /* Includes ------------------------------------------------------------------*/ #include #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 0000000000..8423ad7759 --- /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 0000000000..41f8ab5a53 --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..f468267f43 --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..dea247bca8 --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..6cb15ba210 --- /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 0000000000..7817c98b1c --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..3c06f3cf68 --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..4d72bd5fce --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 0000000000..af3818d373 --- /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 + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 69a03b2cc3..60032c4ecb 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 2da8f069ba..b1b838653f 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);