|
|
@@ -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
|