Skip to content

Commit

Permalink
host msc: call read_capacity as part of enumeration
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
hathach committed Feb 23, 2021
1 parent 386a386 commit 5108d76
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 93 deletions.
46 changes: 8 additions & 38 deletions examples/host/cdc_msc_hid/src/msc_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
//
Expand Down Expand Up @@ -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");
Expand All @@ -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
4 changes: 2 additions & 2 deletions examples/obsolete/host/src/msc_host_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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");

Expand Down
2 changes: 1 addition & 1 deletion lib/fatfs/diskio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
133 changes: 89 additions & 44 deletions src/class/msc/msc_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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];
}

//--------------------------------------------------------------------+
Expand All @@ -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);
}

//--------------------------------------------------------------------+
Expand All @@ -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

Expand All @@ -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);
Expand All @@ -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);

Expand All @@ -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);
}
Expand All @@ -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 =
{
Expand All @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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
Loading

0 comments on commit 5108d76

Please sign in to comment.