diff options
| author | hathach <[email protected]> | 2021-02-23 19:41:11 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2021-02-23 19:41:11 +0700 |
| commit | 5108d7613600449c50af9e8ce373571d56bed3cc (patch) | |
| tree | 8306eb6d37d17666528cbfce24d6e6b260b68a7c /src | |
| parent | 386a386345fbaa1a9c63a4346c2d946fe015da72 (diff) | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/class/msc/msc_host.c | 133 | ||||
| -rw-r--r-- | src/class/msc/msc_host.h | 33 |
2 files changed, 114 insertions, 52 deletions
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 943dc541f..34dbec2e3 100644 --- a/src/class/msc/msc_host.c +++ b/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 diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index b6ead28c5..8116e729f 100644 --- a/src/class/msc/msc_host.h +++ b/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 |
