Parcourir la source

improve scsi: support non read10, write10 out data

hathach il y a 8 ans
Parent
commit
6280c50ad7
2 fichiers modifiés avec 38 ajouts et 28 suppressions
  1. 37 27
      tinyusb/class/msc/msc_device.c
  2. 1 1
      tinyusb/class/msc/msc_device.h

+ 37 - 27
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]) )
-      {
-        // Can be executed several times e.g write 8K bytes (several flash write)
-        read10_write10_data_xfer(rhport, p_msc);
-      }else
+      // Data Stage is complete
+      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;
   }
 

+ 1 - 1
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.