Sfoglia il codice sorgente

host msc: call read_capacity as part of enumeration

- add tuh_msc_get_block_count(), tuh_msc_get_block_size()
- rename tuh_msc_mounted_cb/tuh_msc_unmounted_cb to
tuh_msc_mount_cb/tuh_msc_unmount_cb to match device stack naming
- change tuh_msc_is_busy() to tuh_msc_ready()
- add CFG_TUH_MSC_MAXLUN (default to 4) to hold lun capacities
- add host msc configured to for state check.
hathach 5 anni fa
parent
commit
5108d76136

+ 8 - 38
examples/host/cdc_msc_hid/src/msc_app.c

@@ -31,31 +31,6 @@
 // MACRO TYPEDEF CONSTANT ENUM DECLARATION
 //--------------------------------------------------------------------+
 static scsi_inquiry_resp_t inquiry_resp;
-static scsi_read_capacity10_resp_t capacity_resp;
-
-uint32_t block_size;
-uint32_t block_count;
-
-bool capacity_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
-{
-  (void) dev_addr;
-  (void) cbw;
-
-  if (csw->status != 0)
-  {
-    printf("Read Capacity (10) failed\r\n");
-    return false;
-  }
-
-  // Capacity response field: Block size and Last LBA are both Big-Endian
-  block_count = tu_ntohl(capacity_resp.last_lba) + 1;
-  block_size = tu_ntohl(capacity_resp.block_size);
-
-  printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
-  printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
-
-  return true;
-}
 
 bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
 {
@@ -68,19 +43,21 @@ bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const
   // Print out Vendor ID, Product ID and Rev
   printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
 
-  // Read capacity of device
-  tuh_msc_read_capacity(dev_addr, cbw->lun, &capacity_resp, capacity_complete_cb);
+  // Get capacity of device
+  uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
+  uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
+
+  printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
+  printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
 
   return true;
 }
 
 //------------- IMPLEMENTATION -------------//
-void tuh_msc_mounted_cb(uint8_t dev_addr)
+void tuh_msc_mount_cb(uint8_t dev_addr)
 {
   printf("A MassStorage device is mounted\r\n");
 
-  block_size = block_count = 0;
-
   uint8_t const lun = 0;
   tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb);
 //
@@ -110,7 +87,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr)
 //  }
 }
 
-void tuh_msc_unmounted_cb(uint8_t dev_addr)
+void tuh_msc_unmount_cb(uint8_t dev_addr)
 {
   (void) dev_addr;
   printf("A MassStorage device is unmounted\r\n");
@@ -133,11 +110,4 @@ void tuh_msc_unmounted_cb(uint8_t dev_addr)
 //  }
 }
 
-//void tuh_msc_scsi_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
-//{
-//  (void) dev_addr;
-//  (void) cbw;
-//  (void) csw;
-//}
-
 #endif

+ 2 - 2
examples/obsolete/host/src/msc_host_app.c

@@ -48,7 +48,7 @@ CFG_TUSB_MEM_SECTION static FATFS fatfs[CFG_TUSB_HOST_DEVICE_MAX];
 //--------------------------------------------------------------------+
 // tinyusb callbacks
 //--------------------------------------------------------------------+
-void tuh_msc_mounted_cb(uint8_t dev_addr)
+void tuh_msc_mount_cb(uint8_t dev_addr)
 {
   puts("\na MassStorage device is mounted");
 
@@ -94,7 +94,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr)
   }
 }
 
-void tuh_msc_unmounted_cb(uint8_t dev_addr)
+void tuh_msc_unmount_cb(uint8_t dev_addr)
 {
   puts("\na MassStorage device is unmounted");
 

+ 1 - 1
lib/fatfs/diskio.c

@@ -48,7 +48,7 @@ static DSTATUS disk_state[CFG_TUSB_HOST_DEVICE_MAX];
 static DRESULT wait_for_io_complete(uint8_t usb_addr)
 {
   // TODO with RTOS, this should use semaphore instead of blocking
-  while ( tuh_msc_is_busy(usb_addr) )
+  while ( !tuh_msc_ready(usb_addr) )
   {
     // TODO should have timeout here
     #if CFG_TUSB_OS != OPT_OS_NONE

+ 89 - 44
src/class/msc/msc_host.c

@@ -47,14 +47,21 @@ enum
 
 typedef struct
 {
-  uint8_t  itf_num;
-  uint8_t  ep_in;
-  uint8_t  ep_out;
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
 
-  uint8_t  max_lun;
+  uint8_t max_lun;
 
-  volatile bool mounted;
+  volatile bool configured; // Receive SET_CONFIGURE
+  volatile bool mounted;    // Enumeration is complete
 
+  struct {
+    uint32_t block_size;
+    uint32_t block_count;
+  } capacity[CFG_TUH_MSC_MAXLUN];
+
+  //------------- SCSI -------------//
   uint8_t stage;
   void*   buffer;
   tuh_msc_complete_cb_t complete_cb;
@@ -63,14 +70,15 @@ typedef struct
   msc_csw_t csw;
 }msch_interface_t;
 
-CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX];
+CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUSB_HOST_DEVICE_MAX];
 
-// buffer used to read scsi information when mounted, largest response data currently is inquiry
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_t)];
+// buffer used to read scsi information when mounted
+// largest response data currently is inquiry TODO Inquiry is not part of enum anymore
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
 
 static inline msch_interface_t* get_itf(uint8_t dev_addr)
 {
-  return &msch_data[dev_addr-1];
+  return &_msch_itf[dev_addr-1];
 }
 
 //--------------------------------------------------------------------+
@@ -82,18 +90,28 @@ uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
   return p_msc->max_lun;
 }
 
-bool tuh_msc_mounted(uint8_t dev_addr)
+uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
 {
   msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->capacity[lun].block_count;
+}
 
-  // is configured can be omitted
-  return tuh_device_is_configured(dev_addr) && p_msc->mounted;
+uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->capacity[lun].block_size;
+}
+
+bool tuh_msc_mounted(uint8_t dev_addr)
+{
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  return p_msc->mounted;
 }
 
-bool tuh_msc_is_busy(uint8_t dev_addr)
+bool tuh_msc_ready(uint8_t dev_addr)
 {
   msch_interface_t* p_msc = get_itf(dev_addr);
-  return p_msc->mounted && hcd_edpt_busy(dev_addr, p_msc->ep_in);
+  return p_msc->mounted && !hcd_edpt_busy(dev_addr, p_msc->ep_in);
 }
 
 //--------------------------------------------------------------------+
@@ -110,7 +128,7 @@ static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
 bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb)
 {
   msch_interface_t* p_msc = get_itf(dev_addr);
-  // TU_VERIFY(p_msc->mounted); // TODO part of the enumeration also use scsi command
+  TU_VERIFY(p_msc->configured);
 
   // TODO claim endpoint
 
@@ -126,8 +144,8 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu
 
 bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb)
 {
-  msch_interface_t* p_msc = get_itf(dev_addr);
-  TU_VERIFY(p_msc->mounted);
+   msch_interface_t* p_msc = get_itf(dev_addr);
+   TU_VERIFY(p_msc->configured);
 
   msc_cbw_t cbw;
   cbw_init(&cbw, lun);
@@ -142,6 +160,9 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
 
 bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb)
 {
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->mounted);
+
   msc_cbw_t cbw;
   cbw_init(&cbw, lun);
 
@@ -161,14 +182,17 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons
 
 bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb)
 {
+  msch_interface_t* p_msc = get_itf(dev_addr);
+  TU_VERIFY(p_msc->configured);
+
   msc_cbw_t cbw;
   cbw_init(&cbw, lun);
 
-  cbw.total_bytes = 0; // Number of bytes
-  cbw.dir        = TUSB_DIR_OUT;
-  cbw.cmd_len    = sizeof(scsi_test_unit_ready_t);
-  cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
-  cbw.command[1] = lun; // according to wiki TODO need verification
+  cbw.total_bytes = 0;
+  cbw.dir         = TUSB_DIR_OUT;
+  cbw.cmd_len     = sizeof(scsi_test_unit_ready_t);
+  cbw.command[0]  = SCSI_CMD_TEST_UNIT_READY;
+  cbw.command[1]  = lun; // according to wiki TODO need verification
 
   return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb);
 }
@@ -179,8 +203,8 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms
   cbw_init(&cbw, lun);
 
   cbw.total_bytes = 18; // TODO sense response
-  cbw.dir        = TUSB_DIR_IN_MASK;
-  cbw.cmd_len    = sizeof(scsi_request_sense_t);
+  cbw.dir         = TUSB_DIR_IN_MASK;
+  cbw.cmd_len     = sizeof(scsi_request_sense_t);
 
   scsi_request_sense_t const cmd_request_sense =
   {
@@ -201,11 +225,11 @@ bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba,
   msc_cbw_t cbw;
   cbw_init(&cbw, lun);
  
-  cbw.total_bytes = 512*block_count; // Number of bytes TODO get block size from READ CAPACITY 10
-  cbw.dir        = TUSB_DIR_IN_MASK;
-  cbw.cmd_len    = sizeof(scsi_read10_t);
+  cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
+  cbw.dir         = TUSB_DIR_IN_MASK;
+  cbw.cmd_len     = sizeof(scsi_read10_t);
  
-  scsi_read10_t cmd_read10 =
+  scsi_read10_t const cmd_read10 =
   {
     .cmd_code    = SCSI_CMD_READ_10,
     .lba         = tu_htonl(lba),
@@ -225,11 +249,11 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_
   msc_cbw_t cbw;
   cbw_init(&cbw, lun);
 
-  cbw.total_bytes = 512*block_count; // Number of bytes TODO get block size from READ CAPACITY 10
-  cbw.dir        = TUSB_DIR_OUT;
-  cbw.cmd_len    = sizeof(scsi_write10_t);
+  cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
+  cbw.dir         = TUSB_DIR_OUT;
+  cbw.cmd_len     = sizeof(scsi_write10_t);
 
-  scsi_write10_t cmd_write10 =
+  scsi_write10_t const cmd_write10 =
   {
     .cmd_code    = SCSI_CMD_WRITE_10,
     .lba         = tu_htonl(lba),
@@ -267,14 +291,14 @@ bool tuh_msc_reset(uint8_t dev_addr)
 //--------------------------------------------------------------------+
 void msch_init(void)
 {
-  tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
+  tu_memclr(_msch_itf, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
 }
 
 void msch_close(uint8_t dev_addr)
 {
   msch_interface_t* p_msc = get_itf(dev_addr);
   tu_memclr(p_msc, sizeof(msch_interface_t));
-  tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback
+  tuh_msc_unmount_cb(dev_addr); // invoke Application Callback
 }
 
 bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
@@ -331,6 +355,7 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
 static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
 static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
+static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 
 bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
 {
@@ -369,6 +394,8 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
   msch_interface_t* p_msc = get_itf(dev_addr);
   TU_ASSERT(p_msc->itf_num == itf_num);
 
+  p_msc->configured = true;
+
   //------------- Get Max Lun -------------//
   TU_LOG2("MSC Get Max Lun\r\n");
   tusb_control_request_t request =
@@ -396,12 +423,13 @@ static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t
   msch_interface_t* p_msc = get_itf(dev_addr);
 
   // STALL means zero
-  p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? msch_buffer[0] : 0;
+  p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? _msch_buffer[0] : 0;
   p_msc->max_lun++; // MAX LUN is minus 1 by specs
 
   // TODO multiple LUN support
   TU_LOG2("SCSI Test Unit Ready\r\n");
-  tuh_msc_test_unit_ready(dev_addr, 0, config_test_unit_ready_complete);
+  uint8_t const lun = 0;
+  tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete);
 
   return true;
 }
@@ -410,19 +438,16 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
 {
   if (csw->status == 0)
   {
-    msch_interface_t* p_msc = get_itf(dev_addr);
-
-    usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
-
-    // Unit is ready, Enumeration is complete
-    p_msc->mounted = true;
-    tuh_msc_mounted_cb(dev_addr);
+    // Unit is ready, read its capacity
+    TU_LOG2("SCSI Read Capacity\r\n");
+    tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) _msch_buffer, config_read_capacity_complete);
   }else
   {
     // Note: During enumeration, some device fails Test Unit Ready and require a few retries
     // with Request Sense to start working !!
     // TODO limit number of retries
-    TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, msch_buffer, config_request_sense_complete));
+    TU_LOG2("SCSI Request Sense\r\n");
+    TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete));
   }
 
   return true;
@@ -435,4 +460,24 @@ static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw
   return true;
 }
 
+static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+{
+  TU_ASSERT(csw->status == 0);
+
+  msch_interface_t* p_msc = get_itf(dev_addr);
+
+  // Capacity response field: Block size and Last LBA are both Big-Endian
+  scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) _msch_buffer;
+  p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
+  p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
+
+  // Mark enumeration is complete
+  p_msc->mounted = true;
+  tuh_msc_mount_cb(dev_addr);
+
+  usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
+
+  return true;
+}
+
 #endif

+ 25 - 8
src/class/msc/msc_host.h

@@ -35,6 +35,15 @@
  extern "C" {
 #endif
 
+//--------------------------------------------------------------------+
+// Class Driver Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUH_MSC_MAXLUN
+#define CFG_TUH_MSC_MAXLUN  4
+#endif
+
+
 /** \addtogroup ClassDriver_MSC
  *  @{
  * \defgroup MSC_Host Host
@@ -51,12 +60,18 @@ typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, ms
 // This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb()
 bool tuh_msc_mounted(uint8_t dev_addr);
 
-// Check if the interface is currently busy transferring data
-bool tuh_msc_is_busy(uint8_t dev_addr);
+// Check if the interface is currently ready or busy transferring data
+bool tuh_msc_ready(uint8_t dev_addr);
 
 // Get Max Lun
 uint8_t tuh_msc_get_maxlun(uint8_t dev_addr);
 
+// Get number of block
+uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun);
+
+// Get block size in bytes
+uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
+
 // Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
 // Complete callback is invoked when SCSI op is complete.
 // return true if success, false if there is already pending operation.
@@ -74,10 +89,6 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
 // Complete callback is invoked when SCSI op is complete.
 bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb);
 
-// Perform SCSI Read Capacity 10 command
-// Complete callback is invoked when SCSI op is complete.
-bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb);
-
 // Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer
 // Complete callback is invoked when SCSI op is complete.
 bool  tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
@@ -86,13 +97,19 @@ bool  tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba,
 // Complete callback is invoked when SCSI op is complete.
 bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb);
 
+// Perform SCSI Read Capacity 10 command
+// Complete callback is invoked when SCSI op is complete.
+// Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by
+// simply call tuh_msc_get_block_count() and tuh_msc_get_block_size()
+bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb);
+
 //------------- Application Callback -------------//
 
 // Invoked when a device with MassStorage interface is mounted
-void tuh_msc_mounted_cb(uint8_t dev_addr);
+void tuh_msc_mount_cb(uint8_t dev_addr);
 
 // Invoked when a device with MassStorage interface is unmounted
-void tuh_msc_unmounted_cb(uint8_t dev_addr);
+void tuh_msc_unmount_cb(uint8_t dev_addr);
 
 //--------------------------------------------------------------------+
 // Internal Class Driver API