stm32/usbd_msc: Rework USBD MSC code to support multiple logical units.

SCSI can support multiple logical units over the one interface (in this
case over USBD MSC) and here the MSC code is reworked to support this
feature.  At this point only one LU is used and the behaviour is mostly
unchanged from before, except the INQUIRY result is different (it will
report "Flash" for both flash and SD card).
pull/4842/head
Damien George 2019-06-11 14:38:56 +10:00
rodzic 9d3031cc9d
commit 518aa571ab
5 zmienionych plików z 279 dodań i 315 usunięć

Wyświetl plik

@ -222,7 +222,7 @@ SRC_C = \
usbd_desc.c \
usbd_cdc_interface.c \
usbd_hid_interface.c \
usbd_msc_storage.c \
usbd_msc_interface.c \
mphalport.c \
mpthreadport.c \
irq.c \

Wyświetl plik

@ -31,7 +31,7 @@
#include "usbd_desc.h"
#include "usbd_cdc_msc_hid.h"
#include "usbd_cdc_interface.h"
#include "usbd_msc_storage.h"
#include "usbd_msc_interface.h"
#include "usbd_hid_interface.h"
#include "py/objstr.h"
@ -40,6 +40,8 @@
#include "py/mperrno.h"
#include "py/mphal.h"
#include "bufhelper.h"
#include "storage.h"
#include "sdcard.h"
#include "usb.h"
#if MICROPY_HW_ENABLE_USB
@ -143,16 +145,20 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, uint8_t mode, USBD_HID_ModeInf
return false;
}
// Configure the MSC interface
const void *lu[1];
switch (pyb_usb_storage_medium) {
#if MICROPY_HW_ENABLE_SDCARD
case PYB_USB_STORAGE_MEDIUM_SDCARD:
USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops);
lu[0] = &pyb_sdcard_type;
break;
#endif
default:
USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
lu[0] = &pyb_flash_type;
break;
}
usbd_msc_init_lu(1, lu);
USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&usbd_msc_fops);
// start the USB device
USBD_LL_Init(usbd, (mode & USBD_MODE_HIGH_SPEED) != 0);

Wyświetl plik

@ -0,0 +1,263 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include "usbd_cdc_msc_hid.h"
#include "usbd_msc_interface.h"
#include "extmod/vfs.h"
#include "storage.h"
#include "sdcard.h"
#define USBD_MSC_MAX_LUN (2)
// This flag is needed to support removal of the medium, so that the USB drive
// can be unmounted and won't be remounted automatically.
#define FLAGS_STARTED (0x01)
#define FLAGS_READONLY (0x02)
STATIC const void *usbd_msc_lu_data[USBD_MSC_MAX_LUN];
STATIC uint8_t usbd_msc_lu_num;
STATIC uint16_t usbd_msc_lu_flags;
static inline void lu_flag_set(uint8_t lun, uint8_t flag) {
usbd_msc_lu_flags |= flag << (lun * 2);
}
static inline void lu_flag_clr(uint8_t lun, uint8_t flag) {
usbd_msc_lu_flags &= ~(flag << (lun * 2));
}
static inline bool lu_flag_is_set(uint8_t lun, uint8_t flag) {
return usbd_msc_lu_flags & (flag << (lun * 2));
}
STATIC const int8_t usbd_msc_inquiry_data[36] = {
0x00, // peripheral qualifier; peripheral device type
0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
0x02, // version
0x02, // response data format
(STANDARD_INQUIRY_DATA_LEN - 5), // additional length
0x00, // various flags
0x00, // various flags
0x00, // various flags
'M', 'i', 'c', 'r', 'o', 'P', 'y', ' ', // Manufacturer : 8 bytes
'p', 'y', 'b', 'o', 'a', 'r', 'd', ' ', // Product : 16 Bytes
'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
'1', '.', '0' ,'0', // Version : 4 Bytes
};
// Set the logical units that will be exposed over MSC
void usbd_msc_init_lu(size_t lu_n, const void *lu_data) {
usbd_msc_lu_num = MIN(lu_n, USBD_MSC_MAX_LUN);
memcpy(usbd_msc_lu_data, lu_data, sizeof(void*) * usbd_msc_lu_num);
usbd_msc_lu_flags = 0;
}
// Helper function to perform an ioctl on a logical unit
STATIC int lu_ioctl(uint8_t lun, int op, uint32_t *data) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
const void *lu = usbd_msc_lu_data[lun];
if (lu == &pyb_flash_type) {
switch (op) {
case BP_IOCTL_INIT:
storage_init();
*data = 0;
return 0;
case BP_IOCTL_SYNC:
storage_flush();
return 0;
case BP_IOCTL_SEC_SIZE:
*data = storage_get_block_size();
return 0;
case BP_IOCTL_SEC_COUNT:
*data = storage_get_block_count();
return 0;
default:
return -1;
}
} else if (lu == &pyb_sdcard_type
#if MICROPY_HW_ENABLE_MMCARD
|| lu == &pyb_mmcard_type
#endif
) {
switch (op) {
case BP_IOCTL_INIT:
if (!sdcard_power_on()) {
return -1;
}
*data = 0;
return 0;
case BP_IOCTL_SYNC:
return 0;
case BP_IOCTL_SEC_SIZE:
*data = SDCARD_BLOCK_SIZE;
return 0;
case BP_IOCTL_SEC_COUNT:
*data = sdcard_get_capacity_in_bytes() / (uint64_t)SDCARD_BLOCK_SIZE;
return 0;
default:
return -1;
}
} else {
return -1;
}
}
// Initialise all logical units (it's only ever called once, with lun_in=0)
STATIC int8_t usbd_msc_Init(uint8_t lun_in) {
if (lun_in != 0) {
return 0;
}
for (int lun = 0; lun < usbd_msc_lu_num; ++lun) {
uint32_t data = 0;
int res = lu_ioctl(lun, BP_IOCTL_INIT, &data);
if (res != 0) {
lu_flag_clr(lun, FLAGS_STARTED);
} else {
lu_flag_set(lun, FLAGS_STARTED);
if (data) {
lu_flag_set(lun, FLAGS_READONLY);
}
}
}
return 0;
}
// Get storage capacity of a logical unit
STATIC int8_t usbd_msc_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
uint32_t block_size_u32 = 0;
int res = lu_ioctl(lun, BP_IOCTL_SEC_SIZE, &block_size_u32);
if (res != 0) {
return -1;
}
*block_size = block_size_u32;
return lu_ioctl(lun, BP_IOCTL_SEC_COUNT, block_num);
}
// Check if a logical unit is ready
STATIC int8_t usbd_msc_IsReady(uint8_t lun) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
return lu_flag_is_set(lun, FLAGS_STARTED) ? 0 : -1;
}
// Check if a logical unit is write protected
STATIC int8_t usbd_msc_IsWriteProtected(uint8_t lun) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
return lu_flag_is_set(lun, FLAGS_READONLY) ? 1 : 0;
}
// Start or stop a logical unit
STATIC int8_t usbd_msc_StartStopUnit(uint8_t lun, uint8_t started) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
if (started) {
lu_flag_set(lun, FLAGS_STARTED);
} else {
lu_flag_clr(lun, FLAGS_STARTED);
}
return 0;
}
// Prepare a logical unit for possible removal
STATIC int8_t usbd_msc_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
uint32_t dummy;
// Sync the logical unit so the device can be unplugged/turned off
return lu_ioctl(lun, BP_IOCTL_SYNC, &dummy);
}
// Read data from a logical unit
STATIC int8_t usbd_msc_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
const void *lu = usbd_msc_lu_data[lun];
if (lu == &pyb_flash_type) {
storage_read_blocks(buf, blk_addr, blk_len);
return 0;
} else if (lu == &pyb_sdcard_type
#if MICROPY_HW_ENABLE_MMCARD
|| lu == &pyb_mmcard_type
#endif
) {
if (sdcard_read_blocks(buf, blk_addr, blk_len) == 0) {
return 0;
}
}
return -1;
}
// Write data to a logical unit
STATIC int8_t usbd_msc_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
if (lun >= usbd_msc_lu_num) {
return -1;
}
const void *lu = usbd_msc_lu_data[lun];
if (lu == &pyb_flash_type) {
storage_write_blocks(buf, blk_addr, blk_len);
return 0;
} else if (lu == &pyb_sdcard_type
#if MICROPY_HW_ENABLE_MMCARD
|| lu == &pyb_mmcard_type
#endif
) {
if (sdcard_write_blocks(buf, blk_addr, blk_len) == 0) {
return 0;
}
}
return -1;
}
// Get the number of attached logical units
STATIC int8_t usbd_msc_GetMaxLun(void) {
return usbd_msc_lu_num - 1;
}
// Table of operations for the SCSI layer to call
const USBD_StorageTypeDef usbd_msc_fops = {
usbd_msc_Init,
usbd_msc_GetCapacity,
usbd_msc_IsReady,
usbd_msc_IsWriteProtected,
usbd_msc_StartStopUnit,
usbd_msc_PreventAllowMediumRemoval,
usbd_msc_Read,
usbd_msc_Write,
usbd_msc_GetMaxLun,
(int8_t *)usbd_msc_inquiry_data,
};

Wyświetl plik

@ -23,10 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H
#define MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H
extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops;
extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops;
extern const USBD_StorageTypeDef usbd_msc_fops;
#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H
void usbd_msc_init_lu(size_t lu_n, const void *lu_data);
#endif // MICROPY_INCLUDED_STM32_USBD_MSC_INTERFACE_H

Wyświetl plik

@ -1,306 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*/
/**
******************************************************************************
* @file usbd_storage_msd.c
* @author MCD application Team
* @version V1.1.0
* @date 19-March-2012
* @brief This file provides the disk operations functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Heavily modified by dpgeorge for MicroPython.
*
******************************************************************************
*/
#include <stdint.h>
#include "usbd_cdc_msc_hid.h"
#include "usbd_msc_storage.h"
#include "py/mpstate.h"
#include "storage.h"
#include "sdcard.h"
// These are needed to support removal of the medium, so that the USB drive
// can be unmounted, and won't be remounted automatically.
static uint8_t flash_started = 0;
#if MICROPY_HW_ENABLE_SDCARD
static uint8_t sdcard_started = 0;
#endif
/******************************************************************************/
// Callback functions for when the internal flash is the mass storage device
static const int8_t FLASH_STORAGE_Inquirydata[] = { // 36 bytes
// LUN 0
0x00,
0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes
'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
'1', '.', '0' ,'0', // Version : 4 Bytes
};
/**
* @brief Initialize the storage medium
* @param lun : logical unit number
* @retval Status
*/
int8_t FLASH_STORAGE_Init(uint8_t lun) {
storage_init();
flash_started = 1;
return 0;
}
/**
* @brief return medium capacity and block size
* @param lun : logical unit number
* @param block_num : number of physical block
* @param block_size : size of a physical block
* @retval Status
*/
int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
*block_size = storage_get_block_size();
*block_num = storage_get_block_count();
return 0;
}
/**
* @brief check whether the medium is ready
* @param lun : logical unit number
* @retval Status
*/
int8_t FLASH_STORAGE_IsReady(uint8_t lun) {
if (flash_started) {
return 0;
}
return -1;
}
/**
* @brief check whether the medium is write-protected
* @param lun : logical unit number
* @retval Status
*/
int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) {
return 0;
}
// Remove the lun
int8_t FLASH_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) {
flash_started = started;
return 0;
}
int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
// sync the flash so that the cache is cleared and the device can be unplugged/turned off
storage_flush();
return 0;
}
/**
* @brief Read data from the medium
* @param lun : logical unit number
* @param buf : Pointer to the buffer to save data
* @param blk_addr : address of 1st block to be read
* @param blk_len : nmber of blocks to be read
* @retval Status
*/
int8_t FLASH_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
storage_read_blocks(buf, blk_addr, blk_len);
return 0;
}
/**
* @brief Write data to the medium
* @param lun : logical unit number
* @param buf : Pointer to the buffer to write from
* @param blk_addr : address of 1st block to be written
* @param blk_len : nmber of blocks to be read
* @retval Status
*/
int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
storage_write_blocks(buf, blk_addr, blk_len);
return 0;
}
/**
* @brief Return number of supported logical unit
* @param None
* @retval number of logical unit
*/
int8_t FLASH_STORAGE_GetMaxLun(void) {
return 0;
}
const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = {
FLASH_STORAGE_Init,
FLASH_STORAGE_GetCapacity,
FLASH_STORAGE_IsReady,
FLASH_STORAGE_IsWriteProtected,
FLASH_STORAGE_StartStopUnit,
FLASH_STORAGE_PreventAllowMediumRemoval,
FLASH_STORAGE_Read,
FLASH_STORAGE_Write,
FLASH_STORAGE_GetMaxLun,
(int8_t *)FLASH_STORAGE_Inquirydata,
};
/******************************************************************************/
// Callback functions for when the SD card is the mass storage device
#if MICROPY_HW_ENABLE_SDCARD
static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes
// LUN 0
0x00,
0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes
'S', 'D', ' ', 'c', 'a', 'r', 'd', ' ',
'1', '.', '0' ,'0', // Version : 4 Bytes
};
/**
* @brief Initialize the storage medium
* @param lun : logical unit number
* @retval Status
*/
int8_t SDCARD_STORAGE_Init(uint8_t lun) {
if (!sdcard_power_on()) {
return -1;
}
sdcard_started = 1;
return 0;
}
/**
* @brief return medium capacity and block size
* @param lun : logical unit number
* @param block_num : number of physical block
* @param block_size : size of a physical block
* @retval Status
*/
int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
*block_size = SDCARD_BLOCK_SIZE;
*block_num = sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE;
return 0;
}
/**
* @brief check whether the medium is ready
* @param lun : logical unit number
* @retval Status
*/
int8_t SDCARD_STORAGE_IsReady(uint8_t lun) {
if (sdcard_started) {
return 0;
}
return -1;
}
/**
* @brief check whether the medium is write-protected
* @param lun : logical unit number
* @retval Status
*/
int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) {
return 0;
}
// Remove the lun
int8_t SDCARD_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) {
sdcard_started = started;
return 0;
}
int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
return 0;
}
/**
* @brief Read data from the medium
* @param lun : logical unit number
* @param buf : Pointer to the buffer to save data
* @param blk_addr : address of 1st block to be read
* @param blk_len : nmber of blocks to be read
* @retval Status
*/
int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
if (sdcard_read_blocks(buf, blk_addr, blk_len) != 0) {
return -1;
}
return 0;
}
/**
* @brief Write data to the medium
* @param lun : logical unit number
* @param buf : Pointer to the buffer to write from
* @param blk_addr : address of 1st block to be written
* @param blk_len : nmber of blocks to be read
* @retval Status
*/
int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
if (sdcard_write_blocks(buf, blk_addr, blk_len) != 0) {
return -1;
}
return 0;
}
/**
* @brief Return number of supported logical unit
* @param None
* @retval number of logical unit
*/
int8_t SDCARD_STORAGE_GetMaxLun(void) {
return 0;
}
const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = {
SDCARD_STORAGE_Init,
SDCARD_STORAGE_GetCapacity,
SDCARD_STORAGE_IsReady,
SDCARD_STORAGE_IsWriteProtected,
SDCARD_STORAGE_StartStopUnit,
SDCARD_STORAGE_PreventAllowMediumRemoval,
SDCARD_STORAGE_Read,
SDCARD_STORAGE_Write,
SDCARD_STORAGE_GetMaxLun,
(int8_t *)SDCARD_STORAGE_Inquirydata,
};
#endif // MICROPY_HW_ENABLE_SDCARD