From 6280c50ad71a225a12ac2a65bda8829f7914f348 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Apr 2018 13:46:05 +0700 Subject: [PATCH] improve scsi: support non read10, write10 out data --- tinyusb/class/msc/msc_device.c | 64 ++++++++++++++++++++-------------- tinyusb/class/msc/msc_device.h | 2 +- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/tinyusb/class/msc/msc_device.c b/tinyusb/class/msc/msc_device.c index 3c7cb9751..225a4fc35 100644 --- a/tinyusb/class/msc/msc_device.c +++ b/tinyusb/class/msc/msc_device.c @@ -199,37 +199,38 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u } else { - // If not read10 & write10, invoke application callback - void const *p_buffer = NULL; - - // TODO SCSI data out transfer is not yet supported - TU_ASSERT( !(p_cbw->xfer_bytes > 0 && !BIT_TEST_(p_cbw->dir, 7)), TUSB_ERROR_NOT_SUPPORTED_YET); - - // Invoke callback - p_csw->status = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, p_msc->scsi_data, &p_msc->data_len); + // For other SCSI commands + // 1. Zero : Invoke app callback, skip DATA and move to STATUS stage + // 2. OUT : queue transfer (invoke app callback there) + // 3. IN : invoke app callback to get response if ( p_cbw->xfer_bytes == 0) { - // There is no DATA, move to Status Stage - p_msc->stage = MSC_STAGE_STATUS; + p_csw->status = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, p_msc->scsi_data, &p_msc->data_len); + p_msc->stage = MSC_STAGE_STATUS; + } + else if ( !BIT_TEST_(p_cbw->dir, 7) ) + { + TU_ASSERT( sizeof(p_msc->scsi_data) >= p_msc->data_len, TUSB_ERROR_NOT_ENOUGH_MEMORY); // needs to increase size for scsi_data + TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, p_msc->scsi_data, p_msc->data_len), TUSB_ERROR_DCD_EDPT_XFER ); } else { - // Data Phase (non READ10, WRITE10) + p_csw->status = tud_msc_scsi_cb(rhport, p_cbw->lun, p_cbw->command, p_msc->scsi_data, &p_msc->data_len); + TU_ASSERT( p_cbw->xfer_bytes >= p_msc->data_len, TUSB_ERROR_INVALID_PARA ); // cannot return more than host expect TU_ASSERT( sizeof(p_msc->scsi_data) >= p_msc->data_len, TUSB_ERROR_NOT_ENOUGH_MEMORY); // needs to increase size for scsi_data - uint8_t const ep = BIT_TEST_(p_cbw->dir, 7) ? p_msc->ep_in : p_msc->ep_out; - if ( p_msc->data_len ) { - TU_ASSERT( dcd_edpt_xfer(rhport, ep, p_msc->scsi_data, p_msc->data_len), TUSB_ERROR_DCD_EDPT_XFER ); + TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, p_msc->scsi_data, p_msc->data_len), TUSB_ERROR_DCD_EDPT_XFER ); }else { // application does not provide data to response --> possibly unsupported SCSI command - dcd_edpt_stall(rhport, ep); + dcd_edpt_stall(rhport, p_msc->ep_in); + p_csw->status = MSC_CSW_STATUS_FAILED; - p_msc->stage = MSC_STAGE_STATUS; + p_msc->stage = MSC_STAGE_STATUS; } } } @@ -238,23 +239,32 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u case MSC_STAGE_DATA: p_msc->xferred_len += xferred_bytes; - // Data Stage is complete - if ( p_msc->xferred_len == p_msc->data_len ) + // Still transferring + if ( p_msc->xferred_len < p_msc->data_len ) { - p_msc->stage = MSC_STAGE_STATUS; + 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); + }else + { + verify_breakpoint(); // unexpected error + } } - else if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) ) + // Data Stage is complete + else { - // Can be executed several times e.g write 8K bytes (several flash write) - read10_write10_data_xfer(rhport, p_msc); - }else - { - // unlikely error - verify_breakpoint(); + // 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); + } + + p_msc->stage = MSC_STAGE_STATUS; } break; - case MSC_STAGE_STATUS: break; // is processed immediately + case MSC_STAGE_STATUS: break; // processed immediately after this switch default : break; } diff --git a/tinyusb/class/msc/msc_device.h b/tinyusb/class/msc/msc_device.h index a379d102a..6b44ece26 100644 --- a/tinyusb/class/msc/msc_device.h +++ b/tinyusb/class/msc/msc_device.h @@ -107,7 +107,7 @@ uint16_t tud_msc_write10_cb(uint8_t rhport, uint8_t lun, void** pp_buffer, uint3 * \param[in] scsi_cmd SCSI command contents, application should examine this command block to know which command host requested * \param[out] buffer Pointer to buffer which application need to update with the address to transfer data with host. * The buffer address can be anywhere since the stack will copy its contents to a internal USB-accessible buffer. - * \param[in] p_length Expected length from host, Application could update to actual data, but could not larger than original value. + * \param[in] p_len Expected length from host, Application could update to actual data, but could not larger than original value. * \retval non-zero Actual number of block that application can receive and must be less than or equal to \a \b block_count. * \retval zero Indicate error in retrieving data from application. Tinyusb device stack will \b STALL the corresponding * endpoint and return failed status in command status wrapper phase.