From c7e924b4be6554c92dc87774c813dcf9573c18ba Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Apr 2018 16:10:52 +0700 Subject: [PATCH] finalize msc cb API with tud_msc_read10_cb and tud_msc_write10_cb --- .../obsolete/device/src/msc_device_ramdisk.c | 14 ++-- examples/obsolete/device/src/tusb_config.h | 7 ++ tinyusb/class/msc/msc_device.c | 82 +++++++++++-------- tinyusb/class/msc/msc_device.h | 4 +- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/examples/obsolete/device/src/msc_device_ramdisk.c b/examples/obsolete/device/src/msc_device_ramdisk.c index c16ee5ce1..fbcd04f57 100644 --- a/examples/obsolete/device/src/msc_device_ramdisk.c +++ b/examples/obsolete/device/src/msc_device_ramdisk.c @@ -91,17 +91,19 @@ uint8_t msc_device_ramdisk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = //--------------------------------------------------------------------+ // IMPLEMENTATION //--------------------------------------------------------------------+ -uint16_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint16_t block_count, void** pp_buffer) +uint32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { - (*pp_buffer) = msc_device_ramdisk[lba]; + uint8_t* addr = msc_device_ramdisk[lba] + offset; + memcpy(buffer, addr, bufsize); - return min16_of(block_count, DISK_BLOCK_NUM); + return bufsize; } -uint16_t tud_msc_write10_cb(uint8_t rhport, uint8_t lun, uint32_t lba, uint16_t block_count, void** pp_buffer) +uint32_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { - (*pp_buffer) = msc_device_ramdisk[lba]; + uint8_t* addr = msc_device_ramdisk[lba] + offset; + memcpy(addr, buffer, bufsize); - return min16_of(block_count, DISK_BLOCK_NUM); + return bufsize; } //--------------------------------------------------------------------+ diff --git a/examples/obsolete/device/src/tusb_config.h b/examples/obsolete/device/src/tusb_config.h index 9ed1ace9b..4db29baab 100644 --- a/examples/obsolete/device/src/tusb_config.h +++ b/examples/obsolete/device/src/tusb_config.h @@ -83,6 +83,13 @@ // If not enabled, application must call tud_cdc_flush() periodically #define CFG_TUD_CDC_FLUSH_ON_SOF 1 + +// Number of supported Logical Unit Number +#define CFG_TUD_MSC_MAXLUN 1 + + +#define CFG_TUD_MSC_BUFSIZE 512 + //--------------------------------------------------------------------+ // USB RAM PLACEMENT //--------------------------------------------------------------------+ diff --git a/tinyusb/class/msc/msc_device.c b/tinyusb/class/msc/msc_device.c index 0e5b8621e..73af4fd87 100644 --- a/tinyusb/class/msc/msc_device.c +++ b/tinyusb/class/msc/msc_device.c @@ -40,6 +40,10 @@ #if (MODE_DEVICE_SUPPORTED && CFG_TUD_MSC) +#if CFG_TUD_MSC_MAXLUN == 0 || CFG_TUD_MSC_MAXLUN > 16 +#error MSC Device: Incorrect setting of MAX LUN +#endif + #define _TINY_USB_SOURCE_FILE_ //--------------------------------------------------------------------+ // INCLUDE @@ -70,7 +74,6 @@ typedef struct { CFG_TUSB_MEM_ALIGN msc_csw_t csw; - uint8_t max_lun; uint8_t interface_num; uint8_t ep_in, ep_out; @@ -80,10 +83,12 @@ typedef struct { }mscd_interface_t; CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN STATIC_VAR mscd_interface_t mscd_data; +CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE]; + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static void read10_write10_data_xfer(uint8_t rhport, mscd_interface_t* p_msc); +static void proc_read10_write10(uint8_t rhport, mscd_interface_t* p_msc); //--------------------------------------------------------------------+ // USBD-CLASS API @@ -152,7 +157,8 @@ tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t cons else if (MSC_REQUEST_GET_MAX_LUN == p_request->bRequest) { // Note: lpc11/13u need xfer data's address to be aligned 64 -> make use of scsi_data instead of using max_lun directly - p_msc->scsi_data[0] = p_msc->max_lun; + // returned MAX LUN is minus 1 by specs + p_msc->scsi_data[0] = CFG_TUD_MSC_MAXLUN-1; usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, p_msc->scsi_data, 1); }else { @@ -172,8 +178,9 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u switch (p_msc->stage) { - //------------- new CBW received -------------// case MSC_STAGE_CMD: + //------------- new CBW received -------------// + // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it if(ep_addr != p_msc->ep_out) return TUSB_ERROR_NONE; @@ -191,14 +198,13 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) { - // Read10 & Write10 data len is same as CBW's xfer bytes - read10_write10_data_xfer(rhport, p_msc); + proc_read10_write10(rhport, p_msc); } else { // For other SCSI commands // 1. Zero : Invoke app callback, skip DATA and move to STATUS stage - // 2. OUT : queue transfer (invoke app callback there) + // 2. OUT : queue transfer (invoke app callback after done) // 3. IN : invoke app callback to get response if ( p_cbw->xfer_bytes == 0) @@ -234,31 +240,42 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u break; case MSC_STAGE_DATA: + // OUT transfer, invoke callback if needed + if ( !BIT_TEST_(p_cbw->dir, 7) ) + { + if ( SCSI_CMD_WRITE_10 == p_cbw->command[0] ) + { + scsi_read10_t* p_write10 = (scsi_read10_t*) &p_cbw->command; + uint32_t lba = __be2n(p_write10->lba); + + tud_msc_write10_cb(rhport, p_cbw->lun, lba, p_msc->xferred_len, _mscd_buf, xferred_bytes); + } + else + { + p_csw->status = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, p_msc->scsi_data, &p_msc->data_len) ? MSC_CSW_STATUS_PASSED : MSC_CSW_STATUS_FAILED; + } + } + + /*------------- Prepare for DATA transfer if not complete yet -------------*/ p_msc->xferred_len += xferred_bytes; - // Still transferring - if ( p_msc->xferred_len < p_msc->data_len ) + if ( p_msc->xferred_len >= p_msc->data_len ) + { + // Data Stage is complete + p_msc->stage = MSC_STAGE_STATUS; + } + else { if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) { // Can be executed several times e.g write 8K bytes (several flash write) - read10_write10_data_xfer(rhport, p_msc); + proc_read10_write10(rhport, p_msc); }else { - verify_breakpoint(); // unexpected error + // No other command take more than one transfer yet -> unlikely error + verify_breakpoint(); } } - // Data Stage is complete - else - { - // Invoke callback if it is not READ10, WRITE10 - if ( ! ((SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0])) ) - { - p_csw->status = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, p_msc->scsi_data, &p_msc->data_len) ? MSC_CSW_STATUS_PASSED : MSC_CSW_STATUS_FAILED; - } - - p_msc->stage = MSC_STAGE_STATUS; - } break; case MSC_STAGE_STATUS: break; // processed immediately after this switch @@ -291,7 +308,7 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u return TUSB_ERROR_NONE; } -static void read10_write10_data_xfer(uint8_t rhport, mscd_interface_t* p_msc) +static void proc_read10_write10(uint8_t rhport, mscd_interface_t* p_msc) { msc_cbw_t* const p_cbw = &p_msc->cbw; msc_csw_t* const p_csw = &p_msc->csw; @@ -302,29 +319,24 @@ static void read10_write10_data_xfer(uint8_t rhport, mscd_interface_t* p_msc) uint8_t const ep_data = BIT_TEST_(p_cbw->dir, 7) ? p_msc->ep_in : p_msc->ep_out; // LBA and Block count are in Big Endian + // FIXME Mis-aligned memory access with M0 !!! uint32_t lba = __be2n(p_readwrite->lba); uint16_t block_count = __be2n_16(p_readwrite->block_count); uint16_t const block_size = p_cbw->xfer_bytes / block_count; - // Adjust lba and block count according to byte transferred so far - lba += (p_msc->xferred_len / block_size); - block_count -= (p_msc->xferred_len / block_size); - - void *p_buffer = NULL; - uint16_t xfer_block; + uint32_t xfer_bytes = min32_of(sizeof(_mscd_buf), p_cbw->xfer_bytes-p_msc->xferred_len); if (SCSI_CMD_READ_10 == p_cbw->command[0]) { - xfer_block = tud_msc_read10_cb (rhport, p_cbw->lun, lba, block_count, &p_buffer); + xfer_bytes = tud_msc_read10_cb (rhport, p_cbw->lun, lba, p_msc->xferred_len, _mscd_buf, xfer_bytes); }else { - xfer_block = tud_msc_write10_cb(rhport, p_cbw->lun, lba, block_count, &p_buffer); + // call later after write transfer complete +// xfer_block = tud_msc_write10_cb(rhport, p_cbw->lun, lba, block_count, &p_buffer); } - xfer_block = min16_of(xfer_block, block_count); - - if ( 0 == xfer_block ) + if ( 0 == xfer_bytes ) { // xferred_block is zero will cause pipe is stalled & status in CSW set to failed p_csw->data_residue = p_cbw->xfer_bytes; @@ -333,7 +345,7 @@ static void read10_write10_data_xfer(uint8_t rhport, mscd_interface_t* p_msc) dcd_edpt_stall(rhport, ep_data); }else { - TU_ASSERT( dcd_edpt_xfer(rhport, ep_data, p_buffer, xfer_block * block_size) ); + TU_ASSERT( dcd_edpt_xfer(rhport, ep_data, _mscd_buf, xfer_bytes) ); } } diff --git a/tinyusb/class/msc/msc_device.h b/tinyusb/class/msc/msc_device.h index 246e7f16a..d3326ff6b 100644 --- a/tinyusb/class/msc/msc_device.h +++ b/tinyusb/class/msc/msc_device.h @@ -78,7 +78,7 @@ * \n\n Although this callback is called by tinyusb device task (non-isr context), however as all the classes share * the same task (to save resource), any delay in this callback will cause delay in response on other classes. */ -uint16_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint16_t block_count, void** pp_buffer); +uint32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); /** \brief Callback invoked when received \ref SCSI_CMD_WRITE_10 command * \param[in] rhport Root hub port @@ -98,7 +98,7 @@ uint16_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint16_t * \n\n Although this callback is called by tinyusb device task (non-isr context), however as all the classes share * the same task (to save resource), any delay in this callback will cause delay in response on other classes. */ -uint16_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint16_t block_count, void** pp_buffer); +uint32_t tud_msc_write10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); /** \brief Callback invoked when received an SCSI command other than \ref SCSI_CMD_WRITE_10 and \ref SCSI_CMD_READ_10