添加 USB 主机、BLE 和 Socket 数据端口驱动程序:
- 支持大容量存储类(MSC)的 USB 主机驱动程序 - BLE SPP(串行端口配置文件)客户端和服务器实现 - Socket(UDP/TCP)数据端口驱动程序 - 相关的 shell 接口用于配置和测试
This commit is contained in:
118
app/drivers/data_port/usb-host/msc/diskio_usb.c
Executable file
118
app/drivers/data_port/usb-host/msc/diskio_usb.c
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "diskio_impl.h"
|
||||
#include "ffconf.h"
|
||||
#include "ff.h"
|
||||
#include "esp_log.h"
|
||||
#include "private_include/diskio_usb.h"
|
||||
#include "private_include/msc_scsi_bot.h"
|
||||
#include "private_include/msc_common.h"
|
||||
#include "usb/usb_types_stack.h"
|
||||
|
||||
static usb_disk_t *s_disks[FF_VOLUMES] = { NULL };
|
||||
|
||||
static const char *TAG = "diskio_usb";
|
||||
|
||||
static DSTATUS usb_disk_initialize (BYTE pdrv)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
static DSTATUS usb_disk_status (BYTE pdrv)
|
||||
{
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
static DRESULT usb_disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
|
||||
{
|
||||
assert(pdrv < FF_VOLUMES);
|
||||
assert(s_disks[pdrv]);
|
||||
|
||||
esp_err_t err;
|
||||
usb_disk_t *disk = s_disks[pdrv];
|
||||
size_t sector_size = disk->block_size;
|
||||
msc_device_t *dev = __containerof(disk, msc_device_t, disk);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
err = scsi_cmd_read10(dev, &buff[i * sector_size], sector + i, 1, sector_size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "scsi_cmd_read10 failed (%d)", err);
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
static DRESULT usb_disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
|
||||
{
|
||||
assert(pdrv < FF_VOLUMES);
|
||||
assert(s_disks[pdrv]);
|
||||
|
||||
esp_err_t err;
|
||||
usb_disk_t *disk = s_disks[pdrv];
|
||||
size_t sector_size = disk->block_size;
|
||||
msc_device_t *dev = __containerof(disk, msc_device_t, disk);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
err = scsi_cmd_write10(dev, &buff[i * sector_size], sector + i, 1, sector_size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "scsi_cmd_write10 failed (%d)", err);
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
static DRESULT usb_disk_ioctl (BYTE pdrv, BYTE cmd, void *buff)
|
||||
{
|
||||
assert(pdrv < FF_VOLUMES);
|
||||
assert(s_disks[pdrv]);
|
||||
|
||||
usb_disk_t *disk = s_disks[pdrv];
|
||||
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
return RES_OK;
|
||||
case GET_SECTOR_COUNT:
|
||||
*((DWORD *) buff) = disk->block_count;
|
||||
return RES_OK;
|
||||
case GET_SECTOR_SIZE:
|
||||
*((WORD *) buff) = disk->block_size;
|
||||
return RES_OK;
|
||||
case GET_BLOCK_SIZE:
|
||||
return RES_ERROR;
|
||||
}
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
void ff_diskio_register_msc(BYTE pdrv, usb_disk_t *disk)
|
||||
{
|
||||
assert(pdrv < FF_VOLUMES);
|
||||
|
||||
static const ff_diskio_impl_t usb_disk_impl = {
|
||||
.init = &usb_disk_initialize,
|
||||
.status = &usb_disk_status,
|
||||
.read = &usb_disk_read,
|
||||
.write = &usb_disk_write,
|
||||
.ioctl = &usb_disk_ioctl
|
||||
};
|
||||
s_disks[pdrv] = disk;
|
||||
ff_diskio_register(pdrv, &usb_disk_impl);
|
||||
}
|
||||
|
||||
BYTE ff_diskio_get_pdrv_disk(const usb_disk_t *disk)
|
||||
{
|
||||
for (int i = 0; i < FF_VOLUMES; i++) {
|
||||
if (disk == s_disks[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
308
app/drivers/data_port/usb-host/msc/include/msc_host.h
Executable file
308
app/drivers/data_port/usb-host/msc/include/msc_host.h
Executable file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_ERR_MSC_HOST_BASE 0x1700 /*!< MSC host error code base */
|
||||
#define ESP_ERR_MSC_MOUNT_FAILED (ESP_ERR_MSC_HOST_BASE + 1) /*!< Failed to mount storage */
|
||||
#define ESP_ERR_MSC_FORMAT_FAILED (ESP_ERR_MSC_HOST_BASE + 2) /*!< Failed to format storage */
|
||||
#define ESP_ERR_MSC_INTERNAL (ESP_ERR_MSC_HOST_BASE + 3) /*!< MSC host internal error */
|
||||
|
||||
#define MSC_STR_DESC_SIZE 32
|
||||
|
||||
typedef struct msc_host_device *msc_host_device_handle_t; /**< Handle to a Mass Storage Device */
|
||||
|
||||
/**
|
||||
* @brief USB Mass Storage event containing event type and associated device handle.
|
||||
*/
|
||||
typedef struct {
|
||||
enum {
|
||||
MSC_DEVICE_CONNECTED, /**< MSC device has been connected to the system.*/
|
||||
MSC_DEVICE_DISCONNECTED, /**< MSC device has been disconnected from the system.*/
|
||||
|
||||
CDC_DEVICE_CONNECTED,
|
||||
CDC_DEVICE_DISCONNECTED,
|
||||
|
||||
DFU_DEVICE_CONNECTED,
|
||||
DFU_DEVICE_DISCONNECTED,
|
||||
} event;
|
||||
union {
|
||||
uint8_t address; /**< Address of connected MSC device.*/
|
||||
msc_host_device_handle_t handle; /**< MSC device handle to disconnected device.*/
|
||||
} device;
|
||||
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
} msc_host_event_t;
|
||||
|
||||
/**
|
||||
* @brief USB Mass Storage event callback.
|
||||
*
|
||||
* @param[in] event mass storage event
|
||||
*/
|
||||
typedef void (*msc_host_event_cb_t)(const msc_host_event_t *event, void *arg);
|
||||
|
||||
/**
|
||||
* @brief MSC configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
bool create_backround_task; /**< When set to true, background task handling usb events is created.
|
||||
Otherwise user has to periodically call msc_host_handle_events function */
|
||||
size_t task_priority; /**< Task priority of crated background task */
|
||||
size_t stack_size; /**< Stack size of crated background task */
|
||||
BaseType_t core_id; /**< Select core on which background task will run or tskNO_AFFINITY */
|
||||
msc_host_event_cb_t callback; /**< Callback invoked when MSC event occurs. Must not be NULL. */
|
||||
void *callback_arg; /**< User provided argument passed to callback */
|
||||
} msc_host_driver_config_t;
|
||||
|
||||
/**
|
||||
* @brief MSC device info.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t sector_count;
|
||||
uint32_t sector_size;
|
||||
uint16_t idProduct;
|
||||
uint16_t idVendor;
|
||||
wchar_t iManufacturer[MSC_STR_DESC_SIZE];
|
||||
wchar_t iProduct[MSC_STR_DESC_SIZE];
|
||||
wchar_t iSerialNumber[MSC_STR_DESC_SIZE];
|
||||
} msc_host_device_info_t;
|
||||
|
||||
//////cdc
|
||||
|
||||
typedef struct cdc_dev_s *cdc_acm_dev_hdl_t;
|
||||
|
||||
/**
|
||||
* @brief Line Coding structure
|
||||
* @see Table 17, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t dwDTERate; // in bits per second
|
||||
uint8_t bCharFormat; // 0: 1 stopbit, 1: 1.5 stopbits, 2: 2 stopbits
|
||||
uint8_t bParityType; // 0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
|
||||
uint8_t bDataBits; // 5, 6, 7, 8 or 16
|
||||
} __attribute__((packed)) cdc_acm_line_coding_t;
|
||||
|
||||
/**
|
||||
* @brief UART State Bitmap
|
||||
* @see Table 31, USB CDC-PSTN specification rev. 1.2
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t bRxCarrier : 1; // State of receiver carrier detection mechanism of device. This signal corresponds to V.24 signal 109 and RS-232 signal DCD.
|
||||
uint16_t bTxCarrier : 1; // State of transmission carrier. This signal corresponds to V.24 signal 106 and RS-232 signal DSR.
|
||||
uint16_t bBreak : 1; // State of break detection mechanism of the device.
|
||||
uint16_t bRingSignal : 1; // State of ring signal detection of the device.
|
||||
uint16_t bFraming : 1; // A framing error has occurred.
|
||||
uint16_t bParity : 1; // A parity error has occurred.
|
||||
uint16_t bOverRun : 1; // Received data has been discarded due to overrun in the device.
|
||||
uint16_t reserved : 9;
|
||||
};
|
||||
uint16_t val;
|
||||
} cdc_acm_uart_state_t;
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM Device Event types to upper layer
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
CDC_ACM_HOST_ERROR,
|
||||
CDC_ACM_HOST_SERIAL_STATE,
|
||||
CDC_ACM_HOST_NETWORK_CONNECTION,
|
||||
CDC_ACM_HOST_DEVICE_DISCONNECTED
|
||||
} cdc_acm_host_dev_event_t;
|
||||
|
||||
/**
|
||||
* @brief CDC-ACM Device Event data structure
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
cdc_acm_host_dev_event_t type;
|
||||
union {
|
||||
int error; // Error code from USB Host
|
||||
cdc_acm_uart_state_t serial_state; // Serial (UART) state
|
||||
bool network_connected; // Network connection event
|
||||
} data;
|
||||
} cdc_acm_host_dev_event_data_t;
|
||||
|
||||
/**
|
||||
* @brief Data receive callback type
|
||||
*/
|
||||
typedef void (*cdc_acm_data_callback_t)(uint8_t *data, size_t data_len, void *user_arg);
|
||||
|
||||
/**
|
||||
* @brief Device event callback type
|
||||
* @see cdc_acm_host_dev_event_t
|
||||
*/
|
||||
typedef void (*cdc_acm_host_dev_callback_t)(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_data_t *event, void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Configuration structure of USB Host CDC-ACM driver
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
size_t driver_task_stack_size; /**< Stack size of the driver's task */
|
||||
unsigned driver_task_priority; /**< Priority of the driver's task */
|
||||
int xCoreID; /**< Core affinity of the driver's task */
|
||||
} cdc_acm_host_driver_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configuration structure of CDC-ACM device
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t connection_timeout_ms; /**< Timeout for USB device connection in [ms] */
|
||||
size_t out_buffer_size; /**< Maximum size of USB bulk out transfer, set to 0 for read-only devices */
|
||||
cdc_acm_host_dev_callback_t event_cb; /**< Device's event callback function. Can be NULL */
|
||||
cdc_acm_data_callback_t data_cb; /**< Device's data RX callback function. Can be NULL for write-only devices */
|
||||
void *user_arg; /**< User's argument that will be passed to the callbacks */
|
||||
} cdc_acm_host_device_config_t;
|
||||
|
||||
/////end cdc
|
||||
|
||||
// stm32 dfu update
|
||||
|
||||
#define STM32_DFU_REQUEST_DETACH 0x00
|
||||
#define STM32_DFU_REQUEST_DNLOAD 0x01
|
||||
#define STM32_DFU_REQUEST_UPLOAD 0x02
|
||||
#define STM32_DFU_REQUEST_GETSTATUS 0x03
|
||||
#define STM32_DFU_REQUEST_CLRSTATUS 0x04
|
||||
#define STM32_DFU_REQUEST_GETSTATE 0x05
|
||||
#define STM32_DFU_REQUEST_ABORT 0x06
|
||||
|
||||
#define STM32_DFU_STATE_APP_IDLE 0
|
||||
#define STM32_DFU_STATE_APP_DETACH 1
|
||||
#define STM32_DFU_STATE_DFU_IDLE 2
|
||||
#define STM32_DFU_STATE_DNLOAD_SYNC 3
|
||||
#define STM32_DFU_STATE_DNBUSY 4
|
||||
#define STM32_DFU_STATE_DNLOAD_IDLE 5
|
||||
#define STM32_DFU_STATE_MAINFES_SYNC 6
|
||||
#define STM32_DFU_STATE_MAINFEST 7
|
||||
#define STM32_DFU_STATE_MAINFEST_WAIT_RESET 8
|
||||
#define STM32_DFU_STATE_UPLOAD_IDLE 9
|
||||
#define STM32_DFU_STATE_ERROR 10
|
||||
|
||||
////
|
||||
|
||||
/**
|
||||
* @brief Install USB Host Mass Storage Class driver
|
||||
*
|
||||
* @param[in] config configuration structure MSC to create
|
||||
* @return esp_err_r
|
||||
*/
|
||||
esp_err_t msc_host_install(const msc_host_driver_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Uninstall Mass Storage Class driver
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_uninstall(void);
|
||||
|
||||
/**
|
||||
* @brief Initialization of MSC device.
|
||||
*
|
||||
* @param[in] device_address Device address obtained from MSC callback provided upon connection and enumeration
|
||||
* @param[out] device Mass storage device handle to be used for subsequent calls.
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_install_device(uint8_t device_address, msc_host_device_handle_t *device);
|
||||
|
||||
/**
|
||||
* @brief Deinitialization of MSC device.
|
||||
*
|
||||
* @param[in] device Device handle obtained from msc_host_install_device function
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_uninstall_device(msc_host_device_handle_t device);
|
||||
|
||||
/**
|
||||
* @brief Helper function for reading sector from mass storage device.
|
||||
*
|
||||
* @warning This call is not thread safe and should not be combined
|
||||
* with accesses to storage through file system.
|
||||
*
|
||||
* @note Provided sector and size cannot exceed
|
||||
* sector_count and sector_size obtained from msc_host_device_info_t
|
||||
*
|
||||
* @param[in] device Device handle
|
||||
* @param[in] sector Number of sector to be read
|
||||
* @param[out] data Buffer into which data will be written
|
||||
* @param[in] size Number of bytes to be read
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_read_sector(msc_host_device_handle_t device, size_t sector, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Helper function for writing sector to mass storage device.
|
||||
*
|
||||
* @warning This call is not thread safe and should not be combined
|
||||
* with accesses to storare through file system.
|
||||
*
|
||||
* @note Provided sector and size cannot exceed
|
||||
* sector_count and sector_size obtained from msc_host_device_info_t
|
||||
*
|
||||
* @param[in] device Device handle
|
||||
* @param[in] sector Number of sector to be read
|
||||
* @param[in] data Data to be written to the sector
|
||||
* @param[in] size Number of bytes to be written
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_write_sector(msc_host_device_handle_t device, size_t sector, const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Handle MSC HOST events.
|
||||
*
|
||||
* @param[in] timeout_ms Timeout in miliseconds
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_handle_events(uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Gets devices information.
|
||||
*
|
||||
* @warning This call is not thread safe and should not be combined
|
||||
* with accesses to storare through file system.
|
||||
*
|
||||
* @param[in] device Handle to device
|
||||
* @param[out] info Structure to be populated with device info
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_device_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Print configuration descriptor.
|
||||
*
|
||||
* @param[in] device Handle of MSC device
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device);
|
||||
|
||||
esp_err_t cdc_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
|
||||
void cdc_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
void cdc_submit_transfer_in(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
int cdc_write_bytes(const uint8_t *buf, size_t length);
|
||||
esp_err_t cdc_host_close(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
|
||||
esp_err_t dfu_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
|
||||
esp_err_t dfu_host_close(cdc_acm_dev_hdl_t cdc_hdl);
|
||||
|
||||
esp_err_t usbh_stm32_get_status_ex(uint8_t *out_result_data /*[6]*/, uint16_t timeout);
|
||||
esp_err_t usbh_stm32_get_status(uint8_t *out_result_data /*[6]*/);
|
||||
void usbh_stm32_get_chipinfo(char *descriptors, uint8_t count, uint8_t *actual_desc_count);
|
||||
uint16_t usbh_stm32_get_transfer_block_size();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
44
app/drivers/data_port/usb-host/msc/include/msc_host_vfs.h
Executable file
44
app/drivers/data_port/usb-host/msc/include/msc_host_vfs.h
Executable file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "msc_host.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct msc_host_vfs *msc_host_vfs_handle_t; /**< VFS handle to attached Mass Storage device */
|
||||
|
||||
/**
|
||||
* @brief Register MSC device to Virtual filesystem.
|
||||
*
|
||||
* @param[in] device Device handle obtained from MSC callback provided upon initialization
|
||||
* @param[in] base_path Base VFS path to be used to access file storage
|
||||
* @param[in] mount_config Mount configuration.
|
||||
* @param[out] vfs_handle Handle to MSC device associated with registered VFS
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_vfs_register(msc_host_device_handle_t device,
|
||||
const char *base_path,
|
||||
const esp_vfs_fat_mount_config_t *mount_config,
|
||||
msc_host_vfs_handle_t *vfs_handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unregister MSC device from Virtual filesystem.
|
||||
*
|
||||
* @param[in] vfs_handle VFS handle obtained from MSC callback provided upon initialization
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t msc_host_vfs_unregister(msc_host_vfs_handle_t vfs_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
2701
app/drivers/data_port/usb-host/msc/msc_host.c
Executable file
2701
app/drivers/data_port/usb-host/msc/msc_host.c
Executable file
File diff suppressed because it is too large
Load Diff
125
app/drivers/data_port/usb-host/msc/msc_host_vfs.c
Executable file
125
app/drivers/data_port/usb-host/msc/msc_host_vfs.c
Executable file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "private_include/msc_common.h"
|
||||
#include "include/msc_host_vfs.h"
|
||||
#include "diskio_impl.h"
|
||||
#include "ffconf.h"
|
||||
#include "ff.h"
|
||||
#include "vfs_fat_internal.h"
|
||||
|
||||
#define DRIVE_STR_LEN 3
|
||||
|
||||
typedef struct msc_host_vfs {
|
||||
char drive[DRIVE_STR_LEN];
|
||||
char *base_path;
|
||||
uint8_t pdrv;
|
||||
} msc_host_vfs_t;
|
||||
|
||||
static const char *TAG = "MSC VFS";
|
||||
|
||||
static esp_err_t msc_format_storage(size_t block_size, size_t allocation_size, const char *drv, const esp_vfs_fat_mount_config_t *mount_config)
|
||||
{
|
||||
void *workbuf = NULL;
|
||||
const size_t workbuf_size = 4096;
|
||||
|
||||
MSC_RETURN_ON_FALSE( workbuf = ff_memalloc(workbuf_size), ESP_ERR_NO_MEM );
|
||||
|
||||
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, mount_config->allocation_unit_size);
|
||||
ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
|
||||
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, alloc_unit_size};
|
||||
FRESULT err = f_mkfs(drv, &opt, workbuf, workbuf_size);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Formatting failed with error: %d", err);
|
||||
free(workbuf);
|
||||
return ESP_ERR_MSC_FORMAT_FAILED;
|
||||
}
|
||||
|
||||
free(workbuf);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void dealloc_msc_vfs(msc_host_vfs_t *vfs)
|
||||
{
|
||||
free(vfs->base_path);
|
||||
free(vfs);
|
||||
}
|
||||
|
||||
esp_err_t msc_host_vfs_register(msc_host_device_handle_t device,
|
||||
const char *base_path,
|
||||
const esp_vfs_fat_mount_config_t *mount_config,
|
||||
msc_host_vfs_handle_t *vfs_handle)
|
||||
{
|
||||
MSC_RETURN_ON_INVALID_ARG(device);
|
||||
MSC_RETURN_ON_INVALID_ARG(base_path);
|
||||
MSC_RETURN_ON_INVALID_ARG(mount_config);
|
||||
MSC_RETURN_ON_INVALID_ARG(vfs_handle);
|
||||
|
||||
FATFS *fs = NULL;
|
||||
BYTE pdrv;
|
||||
bool diskio_registered = false;
|
||||
esp_err_t ret = ESP_ERR_MSC_MOUNT_FAILED;
|
||||
msc_device_t *dev = (msc_device_t *)device;
|
||||
size_t block_size = dev->disk.block_size;
|
||||
size_t alloc_size = mount_config->allocation_unit_size;
|
||||
|
||||
msc_host_vfs_t *vfs = calloc(1, sizeof(msc_host_vfs_t));
|
||||
MSC_RETURN_ON_FALSE(vfs != NULL, ESP_ERR_NO_MEM);
|
||||
|
||||
MSC_GOTO_ON_ERROR( ff_diskio_get_drive(&pdrv) );
|
||||
|
||||
ff_diskio_register_msc(pdrv, &dev->disk);
|
||||
char drive[DRIVE_STR_LEN] = {(char)('0' + pdrv), ':', 0};
|
||||
diskio_registered = true;
|
||||
|
||||
strncpy(vfs->drive, drive, DRIVE_STR_LEN);
|
||||
MSC_GOTO_ON_FALSE( vfs->base_path = strdup(base_path), ESP_ERR_NO_MEM );
|
||||
vfs->pdrv = pdrv;
|
||||
|
||||
MSC_GOTO_ON_ERROR( esp_vfs_fat_register(base_path, drive, mount_config->max_files, &fs) );
|
||||
|
||||
FRESULT fresult = f_mount(fs, drive, 1);
|
||||
|
||||
if ( fresult != FR_OK) {
|
||||
if (mount_config->format_if_mount_failed &&
|
||||
(fresult == FR_NO_FILESYSTEM || fresult == FR_INT_ERR)) {
|
||||
MSC_GOTO_ON_ERROR( msc_format_storage(block_size, alloc_size, drive, mount_config) );
|
||||
MSC_GOTO_ON_FALSE( f_mount(fs, drive, 0) == FR_OK, ESP_ERR_MSC_MOUNT_FAILED );
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
*vfs_handle = vfs;
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
if (diskio_registered) {
|
||||
ff_diskio_unregister(pdrv);
|
||||
}
|
||||
esp_vfs_fat_unregister_path(base_path);
|
||||
if(fs) {
|
||||
f_mount(NULL, drive, 0);
|
||||
}
|
||||
dealloc_msc_vfs(vfs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t msc_host_vfs_unregister(msc_host_vfs_handle_t vfs_handle)
|
||||
{
|
||||
MSC_RETURN_ON_INVALID_ARG(vfs_handle);
|
||||
msc_host_vfs_t *vfs = (msc_host_vfs_t *)vfs_handle;
|
||||
|
||||
f_mount(NULL, vfs->drive, 0);
|
||||
ff_diskio_unregister(vfs->pdrv);
|
||||
esp_vfs_fat_unregister_path(vfs->base_path);
|
||||
dealloc_msc_vfs(vfs);
|
||||
return ESP_OK;
|
||||
}
|
||||
434
app/drivers/data_port/usb-host/msc/msc_scsi_bot.c
Executable file
434
app/drivers/data_port/usb-host/msc/msc_scsi_bot.c
Executable file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_log.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "private_include/msc_common.h"
|
||||
#include "private_include/msc_scsi_bot.h"
|
||||
|
||||
#define TAG "USB_MSC_SCSI"
|
||||
|
||||
/* --------------------------- SCSI Definitions ----------------------------- */
|
||||
#define CMD_SENSE_VALID_BIT (1 << 7)
|
||||
#define SCSI_FLAG_DPO (1<<4)
|
||||
#define SCSI_FLAG_FUA (1<<3)
|
||||
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_MODE_SELECT 0x55
|
||||
#define SCSI_CMD_MODE_SENSE 0x5A
|
||||
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_CMD_READ10 0x28
|
||||
#define SCSI_CMD_READ12 0xA8
|
||||
#define SCSI_CMD_READ_CAPACITY 0x25
|
||||
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_REZERO 0x01
|
||||
#define SCSI_CMD_SEEK10 0x2B
|
||||
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
||||
#define SCSI_CMD_START_STOP Unit 0x1B
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_VERIFY 0x2F
|
||||
#define SCSI_CMD_WRITE10 0x2A
|
||||
#define SCSI_CMD_WRITE12 0xAA
|
||||
#define SCSI_CMD_WRITE_AND_VERIFY 0x2E
|
||||
|
||||
#define IN_DIR CWB_FLAG_DIRECTION_IN
|
||||
#define OUT_DIR 0
|
||||
|
||||
#define INQUIRY_VID_SIZE 8
|
||||
#define INQUIRY_PID_SIZE 16
|
||||
#define INQUIRY_REV_SIZE 4
|
||||
|
||||
#define CBW_CMD_SIZE(cmd) (sizeof(cmd) - sizeof(msc_cbw_t))
|
||||
|
||||
#define CBW_BASE_INIT(dir, cbw_len, data_len) \
|
||||
.base = { \
|
||||
.signature = 0x43425355, \
|
||||
.tag = ++cbw_tag, \
|
||||
.flags = dir, \
|
||||
.lun = 0, \
|
||||
.data_length = data_len, \
|
||||
.cbw_length = cbw_len, \
|
||||
}
|
||||
|
||||
#define FEATURE_SELECTOR_ENDPOINT 0
|
||||
#define CSW_SIGNATURE 0x53425355
|
||||
#define CBW_SIZE 31
|
||||
|
||||
#define USB_MASS_REQ_INIT_RESET(ctrl_req_ptr, intf_num) ({ \
|
||||
(ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \
|
||||
USB_BM_REQUEST_TYPE_TYPE_CLASS | \
|
||||
USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
|
||||
(ctrl_req_ptr)->bRequest = 0xFF; \
|
||||
(ctrl_req_ptr)->wValue = 0; \
|
||||
(ctrl_req_ptr)->wIndex = (intf_num); \
|
||||
(ctrl_req_ptr)->wLength = 0; \
|
||||
})
|
||||
|
||||
#define USB_MASS_REQ_INIT_GET_MAX_LUN(ctrl_req_ptr, intf_num) ({ \
|
||||
(ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | \
|
||||
USB_BM_REQUEST_TYPE_TYPE_CLASS | \
|
||||
USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
|
||||
(ctrl_req_ptr)->bRequest = 0xFE; \
|
||||
(ctrl_req_ptr)->wValue = 0; \
|
||||
(ctrl_req_ptr)->wIndex = (intf_num); \
|
||||
(ctrl_req_ptr)->wLength = 1; \
|
||||
})
|
||||
|
||||
#define USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP(ctrl_req_ptr, ep_num) ({ \
|
||||
(ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \
|
||||
USB_BM_REQUEST_TYPE_TYPE_STANDARD | \
|
||||
USB_BM_REQUEST_TYPE_RECIP_ENDPOINT; \
|
||||
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_CLEAR_FEATURE; \
|
||||
(ctrl_req_ptr)->wValue = FEATURE_SELECTOR_ENDPOINT; \
|
||||
(ctrl_req_ptr)->wIndex = (ep_num); \
|
||||
(ctrl_req_ptr)->wLength = 0; \
|
||||
})
|
||||
|
||||
#define CWB_FLAG_DIRECTION_IN (1<<7) // device -> host
|
||||
|
||||
/**
|
||||
* @brief Command Block Wrapper structure
|
||||
*/
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint32_t signature;
|
||||
uint32_t tag;
|
||||
uint32_t data_length;
|
||||
uint8_t flags;
|
||||
uint8_t lun;
|
||||
uint8_t cbw_length;
|
||||
} msc_cbw_t;
|
||||
|
||||
/**
|
||||
* @brief Command Status Wrapper structure
|
||||
*/
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint32_t signature;
|
||||
uint32_t tag;
|
||||
uint32_t dataResidue;
|
||||
uint8_t status;
|
||||
} msc_csw_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint32_t address;
|
||||
uint8_t reserved1;
|
||||
uint16_t length;
|
||||
uint8_t reserved2[3];
|
||||
} cbw_read10_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint32_t address;
|
||||
uint8_t reserved1;
|
||||
uint16_t length;
|
||||
uint8_t reserved2[1];
|
||||
} cbw_write10_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint32_t address;
|
||||
uint8_t reserved[6];
|
||||
} cbw_read_capacity_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint32_t block_count;
|
||||
uint32_t block_size;
|
||||
} cbw_read_capacity_response_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[10];
|
||||
} cbw_unit_ready_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t reserved_0[2];
|
||||
uint8_t allocation_length;
|
||||
uint8_t reserved_1[7];
|
||||
} cbw_sense_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint8_t error_code;
|
||||
uint8_t reserved_0;
|
||||
uint8_t sense_key;
|
||||
uint32_t info;
|
||||
uint8_t sense_len;
|
||||
uint32_t reserved_1;
|
||||
uint8_t sense_code;
|
||||
uint8_t sense_code_qualifier;
|
||||
uint32_t reserved_2;
|
||||
} cbw_sense_response_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t page_code;
|
||||
uint8_t reserved_0;
|
||||
uint8_t allocation_length;
|
||||
uint8_t reserved_1[7];
|
||||
} cbw_inquiry_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t pc_page_code;
|
||||
uint8_t reserved_1[4];
|
||||
uint16_t parameter_list_length;
|
||||
uint8_t reserved_2[3];
|
||||
} mode_sense_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint8_t data[8];
|
||||
} mode_sense_response_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
msc_cbw_t base;
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint8_t reserved_1[2];
|
||||
uint8_t prevent;
|
||||
uint8_t reserved_2[7];
|
||||
} prevent_allow_medium_removal_t;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint8_t data[36];
|
||||
} cbw_inquiry_response_t;
|
||||
|
||||
// Unique number based on which MSC protocol pairs request and response
|
||||
static uint32_t cbw_tag;
|
||||
|
||||
static esp_err_t check_csw(msc_csw_t *csw, uint32_t tag)
|
||||
{
|
||||
bool csw_ok = csw->signature == CSW_SIGNATURE && csw->tag == tag &&
|
||||
csw->dataResidue == 0 && csw->status == 0;
|
||||
|
||||
if (!csw_ok) {
|
||||
ESP_LOGD(TAG, "CSW failed: status %d", csw->status);
|
||||
}
|
||||
|
||||
return csw_ok ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t clear_feature(msc_device_t *device, uint8_t endpoint)
|
||||
{
|
||||
usb_device_handle_t dev = device->handle;
|
||||
usb_transfer_t *xfer = device->xfer;
|
||||
|
||||
MSC_RETURN_ON_ERROR( usb_host_endpoint_clear(dev, endpoint) );
|
||||
USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP((usb_setup_packet_t *)xfer->data_buffer, endpoint);
|
||||
MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE) );
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t msc_mass_reset(msc_device_t *device)
|
||||
{
|
||||
usb_transfer_t *xfer = device->xfer;
|
||||
|
||||
USB_MASS_REQ_INIT_RESET((usb_setup_packet_t *)xfer->data_buffer, 0);
|
||||
MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE) );
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t msc_get_max_lun(msc_device_t *device, uint8_t *lun)
|
||||
{
|
||||
usb_transfer_t *xfer = device->xfer;
|
||||
|
||||
USB_MASS_REQ_INIT_GET_MAX_LUN((usb_setup_packet_t *)xfer->data_buffer, 0);
|
||||
MSC_RETURN_ON_ERROR( msc_control_transfer(device, xfer, USB_SETUP_PACKET_SIZE + 1) );
|
||||
|
||||
*lun = xfer->data_buffer[USB_SETUP_PACKET_SIZE];
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t bot_execute_command(msc_device_t *device, msc_cbw_t *cbw, void *data, size_t size)
|
||||
{
|
||||
msc_csw_t csw;
|
||||
msc_endpoint_t ep = (cbw->flags & CWB_FLAG_DIRECTION_IN) ? MSC_EP_IN : MSC_EP_OUT;
|
||||
|
||||
MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)cbw, CBW_SIZE, MSC_EP_OUT) );
|
||||
|
||||
if (data) {
|
||||
MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)data, size, ep) );
|
||||
}
|
||||
|
||||
esp_err_t err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN);
|
||||
|
||||
if (err == ESP_FAIL && device->transfer_status == USB_TRANSFER_STATUS_STALL) {
|
||||
ESP_RETURN_ON_ERROR( clear_feature(device, MSC_EP_IN), TAG, "Clear feature failed" );
|
||||
// Try to read csw again after clearing feature
|
||||
err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN);
|
||||
if (err) {
|
||||
ESP_RETURN_ON_ERROR( clear_feature(device, MSC_EP_IN), TAG, "Clear feature failed" );
|
||||
ESP_RETURN_ON_ERROR( msc_mass_reset(device), TAG, "Mass reset failed" );
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
MSC_RETURN_ON_ERROR(err);
|
||||
|
||||
return check_csw(&csw, cbw->tag);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t scsi_cmd_read10(msc_device_t *device,
|
||||
uint8_t *data,
|
||||
uint32_t sector_address,
|
||||
uint32_t num_sectors,
|
||||
uint32_t sector_size)
|
||||
{
|
||||
cbw_read10_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read10_t), num_sectors * sector_size),
|
||||
.opcode = SCSI_CMD_READ10,
|
||||
.flags = 0, // lun
|
||||
.address = __builtin_bswap32(sector_address),
|
||||
.length = __builtin_bswap16(num_sectors),
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, data, num_sectors * sector_size);
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_write10(msc_device_t *device,
|
||||
const uint8_t *data,
|
||||
uint32_t sector_address,
|
||||
uint32_t num_sectors,
|
||||
uint32_t sector_size)
|
||||
{
|
||||
cbw_write10_t cbw = {
|
||||
CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(cbw_write10_t), num_sectors * sector_size),
|
||||
.opcode = SCSI_CMD_WRITE10,
|
||||
.address = __builtin_bswap32(sector_address),
|
||||
.length = __builtin_bswap16(num_sectors),
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, (void *)data, num_sectors * sector_size);
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_read_capacity(msc_device_t *device, uint32_t *block_size, uint32_t *block_count)
|
||||
{
|
||||
cbw_read_capacity_response_t response;
|
||||
|
||||
cbw_read_capacity_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read_capacity_t), sizeof(response)),
|
||||
.opcode = SCSI_CMD_READ_CAPACITY,
|
||||
};
|
||||
|
||||
MSC_RETURN_ON_ERROR( bot_execute_command(device, &cbw.base, &response, sizeof(response)) );
|
||||
|
||||
*block_count = __builtin_bswap32(response.block_count);
|
||||
*block_size = __builtin_bswap32(response.block_size);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_unit_ready(msc_device_t *device)
|
||||
{
|
||||
cbw_unit_ready_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_unit_ready_t), 0),
|
||||
.opcode = SCSI_CMD_TEST_UNIT_READY,
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, NULL, 0);
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_sense(msc_device_t *device, scsi_sense_data_t *sense)
|
||||
{
|
||||
cbw_sense_response_t response;
|
||||
|
||||
cbw_sense_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_sense_t), sizeof(response)),
|
||||
.opcode = SCSI_CMD_REQUEST_SENSE,
|
||||
.allocation_length = sizeof(response),
|
||||
};
|
||||
|
||||
MSC_RETURN_ON_ERROR( bot_execute_command(device, &cbw.base, &response, sizeof(response)) );
|
||||
|
||||
if (sense->key) {
|
||||
ESP_LOGD(TAG, "sense_key: 0x%02X, code: 0x%02X, qualifier: 0x%02X",
|
||||
response.sense_key, response.sense_code, response.sense_code_qualifier);
|
||||
}
|
||||
|
||||
sense->key = response.sense_key;
|
||||
sense->code = response.sense_code;
|
||||
sense->code_q = response.sense_code_qualifier;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_inquiry(msc_device_t *device)
|
||||
{
|
||||
cbw_inquiry_response_t response = { 0 };
|
||||
|
||||
cbw_inquiry_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_inquiry_t), sizeof(response)),
|
||||
.opcode = SCSI_CMD_INQUIRY,
|
||||
.allocation_length = sizeof(response),
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, &response, sizeof(response) );
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_mode_sense(msc_device_t *device)
|
||||
{
|
||||
mode_sense_response_t response = { 0 };
|
||||
|
||||
mode_sense_t cbw = {
|
||||
CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(mode_sense_t), sizeof(response)),
|
||||
.opcode = SCSI_CMD_MODE_SENSE,
|
||||
.pc_page_code = 0x3F,
|
||||
.parameter_list_length = sizeof(response),
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, &response, sizeof(response) );
|
||||
}
|
||||
|
||||
esp_err_t scsi_cmd_prevent_removal(msc_device_t *device, bool prevent)
|
||||
{
|
||||
prevent_allow_medium_removal_t cbw = {
|
||||
CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(prevent_allow_medium_removal_t), 0),
|
||||
.opcode = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
|
||||
.prevent = 1,
|
||||
};
|
||||
|
||||
return bot_execute_command(device, &cbw.base, NULL, 0);
|
||||
}
|
||||
39
app/drivers/data_port/usb-host/msc/private_include/diskio_usb.h
Executable file
39
app/drivers/data_port/usb-host/msc/private_include/diskio_usb.h
Executable file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Mass storage disk initialization structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; /**< Block size */
|
||||
uint32_t block_count; /**< Block count */
|
||||
} usb_disk_t;
|
||||
|
||||
/**
|
||||
* @brief Register mass storage disk to fat file system
|
||||
*
|
||||
* @param[in] pdrv Number of free drive obtained from ff_diskio_get_drive() function
|
||||
* @param[in] disk usb_disk_t structure
|
||||
*/
|
||||
void ff_diskio_register_msc(uint8_t pdrv, usb_disk_t *disk);
|
||||
|
||||
/**
|
||||
* @brief Obtains number of drive assigned to usb disk upon calling ff_diskio_register_msc()
|
||||
*
|
||||
* @param[in] disk usb_disk_t structure
|
||||
* @return Drive number
|
||||
*/
|
||||
uint8_t ff_diskio_get_pdrv_disk(const usb_disk_t *disk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
61
app/drivers/data_port/usb-host/msc/private_include/msc_common.h
Executable file
61
app/drivers/data_port/usb-host/msc/private_include/msc_common.h
Executable file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/queue.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "diskio_usb.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "usb/usb_types_stack.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MSC_EP_OUT,
|
||||
MSC_EP_IN
|
||||
} msc_endpoint_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t bulk_in_mps;
|
||||
uint8_t bulk_in_ep;
|
||||
uint8_t bulk_out_ep;
|
||||
uint8_t iface_num;
|
||||
} msc_config_t;
|
||||
|
||||
typedef struct msc_host_device {
|
||||
STAILQ_ENTRY(msc_host_device) tailq_entry;
|
||||
usb_transfer_status_t transfer_status;
|
||||
SemaphoreHandle_t transfer_done;
|
||||
usb_device_handle_t handle;
|
||||
usb_transfer_t *xfer;
|
||||
msc_config_t config;
|
||||
usb_disk_t disk;
|
||||
} msc_device_t;
|
||||
|
||||
esp_err_t msc_bulk_transfer(msc_device_t *device_handle, uint8_t *data, size_t size, msc_endpoint_t ep);
|
||||
|
||||
esp_err_t msc_control_transfer(msc_device_t *device_handle, usb_transfer_t *xfer, size_t len);
|
||||
|
||||
#define MSC_GOTO_ON_ERROR(exp) ESP_GOTO_ON_ERROR(exp, fail, TAG, "")
|
||||
|
||||
#define MSC_GOTO_ON_FALSE(exp, err) ESP_GOTO_ON_FALSE( (exp), err, fail, TAG, "" )
|
||||
|
||||
#define MSC_RETURN_ON_ERROR(exp) ESP_RETURN_ON_ERROR((exp), TAG, "")
|
||||
|
||||
#define MSC_RETURN_ON_FALSE(exp, err) ESP_RETURN_ON_FALSE( (exp), (err), TAG, "")
|
||||
|
||||
#define MSC_RETURN_ON_INVALID_ARG(exp) ESP_RETURN_ON_FALSE((exp) != NULL, ESP_ERR_INVALID_ARG, TAG, "")
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
56
app/drivers/data_port/usb-host/msc/private_include/msc_scsi_bot.h
Executable file
56
app/drivers/data_port/usb-host/msc/private_include/msc_scsi_bot.h
Executable file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "msc_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint8_t key;
|
||||
uint8_t code;
|
||||
uint8_t code_q;
|
||||
} scsi_sense_data_t;
|
||||
|
||||
esp_err_t scsi_cmd_read10(msc_device_t *device,
|
||||
uint8_t *data,
|
||||
uint32_t sector_address,
|
||||
uint32_t num_sectors,
|
||||
uint32_t sector_size);
|
||||
|
||||
esp_err_t scsi_cmd_write10(msc_device_t *device,
|
||||
const uint8_t *data,
|
||||
uint32_t sector_address,
|
||||
uint32_t num_sectors,
|
||||
uint32_t sector_size);
|
||||
|
||||
esp_err_t scsi_cmd_read_capacity(msc_device_t *device,
|
||||
uint32_t *block_size,
|
||||
uint32_t *block_count);
|
||||
|
||||
esp_err_t scsi_cmd_sense(msc_device_t *device, scsi_sense_data_t *sense);
|
||||
|
||||
esp_err_t scsi_cmd_unit_ready(msc_device_t *device);
|
||||
|
||||
esp_err_t scsi_cmd_inquiry(msc_device_t *device);
|
||||
|
||||
esp_err_t scsi_cmd_prevent_removal(msc_device_t *device, bool prevent);
|
||||
|
||||
esp_err_t scsi_cmd_mode_sense(msc_device_t *device);
|
||||
|
||||
esp_err_t msc_mass_reset(msc_device_t *device);
|
||||
|
||||
esp_err_t msc_get_max_lun(msc_device_t *device, uint8_t *lun);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user