update example

This commit is contained in:
hathach
2025-07-01 20:15:16 +07:00
parent d22cbe4cb5
commit 216a35e59a
3 changed files with 55 additions and 74 deletions

View File

@@ -28,8 +28,13 @@
#if CFG_TUD_MSC #if CFG_TUD_MSC
#if CFG_EXAMPLE_MSC_ASYNC_IO // Use async IO in example or not
#define CFG_EXAMPLE_MSC_ASYNC_IO 1
// Simulate read/write operation delay
#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0
#if CFG_EXAMPLE_MSC_ASYNC_IO
#define IO_STACK_SIZE configMINIMAL_STACK_SIZE #define IO_STACK_SIZE configMINIMAL_STACK_SIZE
typedef struct { typedef struct {
@@ -66,8 +71,7 @@ static bool ejected = false;
If you find any bugs or get any questions, feel free to file an\r\n\ If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb" issue at github.com/hathach/tinyusb"
enum enum {
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512 DISK_BLOCK_SIZE = 512
}; };
@@ -162,18 +166,20 @@ static void io_task(void *params) {
io_ops_t io_ops; io_ops_t io_ops;
while (1) { while (1) {
if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) {
const uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset;
int32_t nbytes = io_ops.bufsize;
if (io_ops.is_read) { if (io_ops.is_read) {
uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset;
memcpy(io_ops.buffer, addr, io_ops.bufsize); memcpy(io_ops.buffer, addr, io_ops.bufsize);
} else { } else {
#ifndef CFG_EXAMPLE_MSC_READONLY #ifndef CFG_EXAMPLE_MSC_READONLY
uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize);
memcpy(addr, io_ops.buffer, io_ops.bufsize); #else
nbytes = -1; // failed to write
#endif #endif
} }
tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
tud_msc_async_io_done(io_ops.bufsize); tud_msc_async_io_done(nbytes, false);
} }
} }
} }
@@ -184,14 +190,11 @@ void msc_disk_init() {}
// Invoked when received SCSI_CMD_INQUIRY // Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
{
(void) lun; (void) lun;
const char vid[] = "TinyUSB"; const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage"; const char pid[] = "Mass Storage";
const char rev[] = "1.0"; const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid)); memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid)); memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev)); memcpy(product_rev, rev, strlen(rev));
@@ -199,8 +202,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
// Invoked when received Test Unit Ready command. // Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted // return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun) bool tud_msc_test_unit_ready_cb(uint8_t lun) {
{
(void) lun; (void) lun;
// RAM disk is ready until ejected // RAM disk is ready until ejected
@@ -215,10 +217,8 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun)
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size // Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
{
(void) lun; (void) lun;
*block_count = DISK_BLOCK_NUM; *block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE; *block_size = DISK_BLOCK_SIZE;
} }
@@ -226,18 +226,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
// Invoked when received Start Stop Unit command // Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
{
(void) lun; (void) lun;
(void) power_condition; (void) power_condition;
if ( load_eject ) if (load_eject) {
{ if (start) {
if (start)
{
// load disk storage // load disk storage
}else } else {
{
// unload disk storage // unload disk storage
ejected = true; ejected = true;
} }
@@ -248,116 +244,107 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
{
(void) lun; (void) lun;
// out of ramdisk // out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) { if (lba >= DISK_BLOCK_NUM) {
return TUD_MSC_RET_ERROR; return TUD_MSC_RET_ERROR;
} }
// Check for overflow of offset + bufsize // Check for overflow of offset + bufsize
if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
return TUD_MSC_RET_ERROR; return TUD_MSC_RET_ERROR;
} }
#if CFG_EXAMPLE_MSC_ASYNC_IO #if CFG_EXAMPLE_MSC_ASYNC_IO
io_ops_t io_ops = { .is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
// Send IO operation to IO task // Send IO operation to IO task
TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
return TUD_MSC_RET_ASYNC; return TUD_MSC_RET_ASYNC;
#else #else
uint8_t const* addr = msc_disk[lba] + offset; uint8_t const *addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
return bufsize; return bufsize;
#endif #endif
} }
bool tud_msc_is_writable_cb (uint8_t lun) bool tud_msc_is_writable_cb (uint8_t lun) {
{
(void) lun; (void) lun;
#ifdef CFG_EXAMPLE_MSC_READONLY #ifdef CFG_EXAMPLE_MSC_READONLY
return false; return false;
#else #else
return true; return true;
#endif #endif
} }
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes // Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
{
// out of ramdisk // out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) { if (lba >= DISK_BLOCK_NUM) {
return TUD_MSC_RET_ERROR; return TUD_MSC_RET_ERROR;
} }
// Check for overflow of offset + bufsize // Check for overflow of offset + bufsize
if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
return TUD_MSC_RET_ERROR; return TUD_MSC_RET_ERROR;
} }
#ifdef CFG_EXAMPLE_MSC_READONLY #ifdef CFG_EXAMPLE_MSC_READONLY
(void) lun; (void) buffer; (void) lun;
(void) buffer;
return bufsize; return bufsize;
#endif #endif
#if CFG_EXAMPLE_MSC_ASYNC_IO #if CFG_EXAMPLE_MSC_ASYNC_IO
io_ops_t io_ops = { .is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
// Send IO operation to IO task // Send IO operation to IO task
TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
return TUD_MSC_RET_ASYNC; return TUD_MSC_RET_ASYNC;
#else #else
uint8_t* addr = msc_disk[lba] + offset; uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize); memcpy(addr, buffer, bufsize);
tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
return bufsize; return bufsize;
#endif #endif
} }
// Callback invoked when received an SCSI command not in built-in list below // Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks // - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
{
// read10 & write10 has their own callback and MUST not be handled here // read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL; void const *response = NULL;
int32_t resplen = 0; int32_t resplen = 0;
// most scsi handled is input // most scsi handled is input
bool in_xfer = true; bool in_xfer = true;
switch (scsi_cmd[0]) switch (scsi_cmd[0]) {
{
default: default:
// Set Sense = Invalid Command Operation // Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status // negative means error -> tinyusb could stall and/or response with failed status
resplen = -1; resplen = -1;
break; break;
} }
// return resplen must not larger than bufsize // return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize; if (resplen > bufsize) { resplen = bufsize; }
if ( response && (resplen > 0) ) if (response && (resplen > 0)) {
{ if (in_xfer) {
if(in_xfer)
{
memcpy(buffer, response, (size_t) resplen); memcpy(buffer, response, (size_t) resplen);
}else } else {
{
// SCSI output // SCSI output
} }
} }

View File

@@ -114,12 +114,6 @@
// MSC Buffer size of Device Mass storage // MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512 #define CFG_TUD_MSC_EP_BUFSIZE 512
// Use async IO in example or not
#define CFG_EXAMPLE_MSC_ASYNC_IO 1
// Simulate read/write operation delay
#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -828,8 +828,8 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) {
static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
uint8_t rhport = p_msc->rhport; uint8_t rhport = p_msc->rhport;
if (nbytes < 0) { if (nbytes == TUD_MSC_RET_ERROR) {
// negative means error -> endpoint is stalled & status in CSW set to failed // error -> endpoint is stalled & status in CSW set to failed
TU_LOG_DRV(" IO read() failed\r\n"); TU_LOG_DRV(" IO read() failed\r\n");
// set sense // set sense
@@ -837,7 +837,7 @@ static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
set_sense_medium_not_present(p_cbw->lun); set_sense_medium_not_present(p_cbw->lun);
fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else if (nbytes == 0) { } else if (nbytes == TUD_MSC_RET_BUSY) {
// zero means not ready -> fake a transfer complete so that this driver callback will fire again // zero means not ready -> fake a transfer complete so that this driver callback will fire again
dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
} else { } else {