Skip to content

Commit 08299fd

Browse files
committed
update tinyusb with better msc inquiry, test_unit_ready support
1 parent f6f791c commit 08299fd

File tree

3 files changed

+99
-101
lines changed

3 files changed

+99
-101
lines changed

cores/nRF5/Adafruit_TinyUSB_Core/tinyusb/src/class/msc/msc_device.c

Lines changed: 80 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
159159
case MSC_REQ_GET_MAX_LUN:
160160
{
161161
uint8_t maxlun = 1;
162-
if (tud_msc_maxlun_cb) maxlun = tud_msc_maxlun_cb();
162+
if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb();
163163
TU_VERIFY(maxlun);
164164

165165
// MAX LUN is minus 1 by specs
@@ -186,14 +186,37 @@ bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const
186186
return true;
187187
}
188188

189-
// return length of response (copied to buffer), -1 if it is not an built-in commands
190-
int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t bufsize)
189+
// return response's length (copied to buffer). Negative if it is not an built-in command or indicate Failed status (CSW)
190+
// In case of a failed status, sense key must be set for reason of failure
191+
int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize)
191192
{
192193
(void) bufsize; // TODO refractor later
193-
int32_t ret;
194+
int32_t resplen;
194195

195-
switch ( p_cbw->command[0] )
196+
switch ( scsi_cmd[0] )
196197
{
198+
case SCSI_CMD_TEST_UNIT_READY:
199+
resplen = 0;
200+
if ( !tud_msc_test_unit_ready_cb(lun) )
201+
{
202+
// not ready response with Failed status and sense key = not ready
203+
resplen = - 1;
204+
205+
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
206+
if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
207+
}
208+
break;
209+
210+
case SCSI_CMD_START_STOP_UNIT:
211+
resplen = 0;
212+
213+
if (tud_msc_start_stop_cb)
214+
{
215+
scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
216+
tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject);
217+
}
218+
break;
219+
197220
case SCSI_CMD_READ_CAPACITY_10:
198221
{
199222
scsi_read_capacity10_resp_t read_capa10;
@@ -202,14 +225,14 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
202225
uint32_t block_size;
203226
uint16_t block_size_u16;
204227

205-
tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size_u16);
228+
tud_msc_capacity_cb(lun, &block_count, &block_size_u16);
206229
block_size = (uint32_t) block_size_u16;
207230

208231
read_capa10.last_lba = ENDIAN_BE(block_count-1);
209232
read_capa10.block_size = ENDIAN_BE(block_size);
210233

211-
ret = sizeof(read_capa10);
212-
memcpy(buffer, &read_capa10, ret);
234+
resplen = sizeof(read_capa10);
235+
memcpy(buffer, &read_capa10, resplen);
213236
}
214237
break;
215238

@@ -226,12 +249,12 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
226249
uint32_t block_count;
227250
uint16_t block_size;
228251

229-
tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size);
252+
tud_msc_capacity_cb(lun, &block_count, &block_size);
230253
read_fmt_capa.block_num = ENDIAN_BE(block_count);
231254
read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
232255

233-
ret = sizeof(read_fmt_capa);
234-
memcpy(buffer, &read_fmt_capa, ret);
256+
resplen = sizeof(read_fmt_capa);
257+
memcpy(buffer, &read_fmt_capa, resplen);
235258
}
236259
break;
237260

@@ -242,23 +265,17 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
242265
.is_removable = 1,
243266
.version = 2,
244267
.response_data_format = 2,
245-
// vendor_id, product_id, product_rev is space padded string
246-
.vendor_id = "",
247-
.product_id = "",
248-
.product_rev = "",
249268
};
250269

251-
memset(inquiry_rsp.vendor_id, ' ', sizeof(inquiry_rsp.vendor_id));
252-
memcpy(inquiry_rsp.vendor_id, CFG_TUD_MSC_VENDOR, tu_min32(strlen(CFG_TUD_MSC_VENDOR), sizeof(inquiry_rsp.vendor_id)));
253-
254-
memset(inquiry_rsp.product_id, ' ', sizeof(inquiry_rsp.product_id));
255-
memcpy(inquiry_rsp.product_id, CFG_TUD_MSC_PRODUCT, tu_min32(strlen(CFG_TUD_MSC_PRODUCT), sizeof(inquiry_rsp.product_id)));
256-
270+
// vendor_id, product_id, product_rev is space padded string
271+
memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id));
272+
memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id));
257273
memset(inquiry_rsp.product_rev, ' ', sizeof(inquiry_rsp.product_rev));
258-
memcpy(inquiry_rsp.product_rev, CFG_TUD_MSC_PRODUCT_REV, tu_min32(strlen(CFG_TUD_MSC_PRODUCT_REV), sizeof(inquiry_rsp.product_rev)));
259274

260-
ret = sizeof(inquiry_rsp);
261-
memcpy(buffer, &inquiry_rsp, ret);
275+
tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev);
276+
277+
resplen = sizeof(inquiry_rsp);
278+
memcpy(buffer, &inquiry_rsp, resplen);
262279
}
263280
break;
264281

@@ -275,12 +292,12 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
275292

276293
bool writable = true;
277294
if (tud_msc_is_writable_cb) {
278-
writable = tud_msc_is_writable_cb(p_cbw->lun);
295+
writable = tud_msc_is_writable_cb(lun);
279296
}
280297
mode_resp.write_protected = !writable;
281298

282-
ret = sizeof(mode_resp);
283-
memcpy(buffer, &mode_resp, ret);
299+
resplen = sizeof(mode_resp);
300+
memcpy(buffer, &mode_resp, resplen);
284301
}
285302
break;
286303

@@ -298,18 +315,18 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
298315
sense_rsp.add_sense_code = _mscd_itf.add_sense_code;
299316
sense_rsp.add_sense_qualifier = _mscd_itf.add_sense_qualifier;
300317

301-
ret = sizeof(sense_rsp);
302-
memcpy(buffer, &sense_rsp, ret);
318+
resplen = sizeof(sense_rsp);
319+
memcpy(buffer, &sense_rsp, resplen);
303320

304321
// Clear sense data after copy
305-
tud_msc_set_sense(p_cbw->lun, 0, 0, 0);
322+
tud_msc_set_sense(lun, 0, 0, 0);
306323
}
307324
break;
308325

309-
default: ret = -1; break;
326+
default: resplen = -1; break;
310327
}
311328

312-
return ret;
329+
return resplen;
313330
}
314331

315332
bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
@@ -348,60 +365,50 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
348365
else
349366
{
350367
// For other SCSI commands
351-
// 1. Zero : Invoke app callback, skip DATA and move to STATUS stage
352-
// 2. OUT : queue transfer (invoke app callback after done)
353-
// 3. IN : invoke app callback to get response
354-
if ( p_cbw->total_bytes == 0)
355-
{
356-
int32_t const cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, NULL, 0);
357-
358-
p_msc->total_len = 0;
359-
p_msc->stage = MSC_STAGE_STATUS;
360-
361-
if ( cb_result < 0 )
362-
{
363-
p_csw->status = MSC_CSW_STATUS_FAILED;
364-
tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
365-
}
366-
else
367-
{
368-
p_csw->status = MSC_CSW_STATUS_PASSED;
369-
}
370-
}
371-
else if ( !TU_BIT_TEST(p_cbw->dir, 7) )
368+
// 1. OUT : queue transfer (invoke app callback after done)
369+
// 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
370+
if ( (p_cbw->total_bytes > 0 ) && !TU_BIT_TEST(p_cbw->dir, 7) )
372371
{
373-
// OUT transfer
372+
// queue transfer
374373
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
375-
}
376-
else
374+
}else
377375
{
378-
// IN Transfer
379-
int32_t cb_result;
376+
int32_t resplen;
380377

381-
// first process if it is a built-in commands
382-
cb_result = proc_builtin_scsi(p_cbw, _mscd_buf, sizeof(_mscd_buf));
378+
// First process if it is a built-in commands
379+
resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf));
383380

384-
// Not an built-in command, invoke user callback
385-
if ( cb_result < 0 )
381+
// Not built-in, invoke user callback
382+
if ( (resplen < 0) && (p_msc->sense_key == 0) )
386383
{
387-
cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
384+
resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
388385
}
389386

390-
if ( cb_result > 0 )
391-
{
392-
p_msc->total_len = (uint32_t) cb_result;
393-
p_csw->status = MSC_CSW_STATUS_PASSED;
394-
395-
TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
396-
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
397-
}else
387+
if ( resplen < 0 )
398388
{
399389
p_msc->total_len = 0;
400390
p_csw->status = MSC_CSW_STATUS_FAILED;
401391
p_msc->stage = MSC_STAGE_STATUS;
402392

403-
tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
404-
usbd_edpt_stall(rhport, p_msc->ep_in);
393+
// failed but senskey is not set: default to Illegal Request
394+
if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
395+
396+
/// Stall bulk In if needed
397+
if (p_cbw->total_bytes) usbd_edpt_stall(rhport, p_msc->ep_in);
398+
}
399+
else
400+
{
401+
p_msc->total_len = (uint32_t) resplen;
402+
p_csw->status = MSC_CSW_STATUS_PASSED;
403+
404+
if (p_msc->total_len)
405+
{
406+
TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
407+
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
408+
}else
409+
{
410+
p_msc->stage = MSC_STAGE_STATUS;
411+
}
405412
}
406413
}
407414
}

cores/nRF5/Adafruit_TinyUSB_Core/tinyusb/src/class/msc/msc_device.h

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
4444
#error CFG_TUD_MSC_BUFSIZE must be defined, value of a block size should work well, the more the better
4545
#endif
4646

47-
#ifndef CFG_TUD_MSC_VENDOR
48-
#error CFG_TUD_MSC_VENDOR 8-byte name must be defined
49-
#endif
50-
51-
#ifndef CFG_TUD_MSC_PRODUCT
52-
#error CFG_TUD_MSC_PRODUCT 16-byte name must be defined
53-
#endif
54-
55-
#ifndef CFG_TUD_MSC_PRODUCT_REV
56-
#error CFG_TUD_MSC_PRODUCT_REV 4-byte string must be defined
57-
#endif
58-
5947
/** \addtogroup ClassDriver_MSC
6048
* @{
6149
* \defgroup MSC_Device Device
@@ -105,12 +93,23 @@ ATTR_WEAK int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset,
10593
*/
10694
ATTR_WEAK int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
10795

96+
// Invoked when received SCSI_CMD_INQUIRY
97+
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
98+
ATTR_WEAK void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]);
99+
100+
// Invoked when received Test Unit Ready command.
101+
// return true allowing host to read/write this LUN e.g SD card inserted
102+
ATTR_WEAK bool tud_msc_test_unit_ready_cb(uint8_t lun);
103+
108104
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
109105
// Application update block count and block size
110106
ATTR_WEAK void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size);
111107

112108
/**
113-
* Callback invoked when received an SCSI command not in built-in list below.
109+
* Invoked when received an SCSI command not in built-in list below.
110+
* - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, PREVENT_ALLOW_MEDIUM_REMOVE, MODE_SENSE6, REQUEST_SENSE
111+
* - READ10 and WRITE10 has their own callbacks
112+
*
114113
* \param[in] lun Logical unit number
115114
* \param[in] scsi_cmd SCSI command contents which application must examine to response accordingly
116115
* \param[out] buffer Buffer for SCSI Data Stage.
@@ -121,17 +120,18 @@ ATTR_WEAK void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t*
121120
* \return Actual bytes processed, can be zero for no-data command.
122121
* \retval negative Indicate error e.g unsupported command, tinyusb will \b STALL the corresponding
123122
* endpoint and return failed status in command status wrapper phase.
124-
*
125-
* \note Following command is automatically handled by tinyusb stack, callback should not be worried:
126-
* - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
127-
* - READ10 and WRITE10 has their own callbacks
128123
*/
129124
ATTR_WEAK int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
130125

131126
/*------------- Optional callbacks -------------*/
132127

133-
// Invoked when received GET_MAX_LUN request
134-
ATTR_WEAK uint8_t tud_msc_maxlun_cb(void);
128+
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
129+
ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
130+
131+
// Invoked when received Start Stop Unit command
132+
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
133+
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
134+
ATTR_WEAK void tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
135135

136136
// Invoked when Read10 command is complete
137137
ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);

cores/nRF5/Adafruit_TinyUSB_Core/tusb_config.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,6 @@
7171
// Buffer size of Device Mass storage
7272
#define CFG_TUD_MSC_BUFSIZE 512
7373

74-
// Vendor name included in Inquiry response, max 8 bytes
75-
#define CFG_TUD_MSC_VENDOR "Adafruit"
76-
77-
// Product name included in Inquiry response, max 16 bytes
78-
#define CFG_TUD_MSC_PRODUCT "Bluefruit nRF52"
79-
80-
// Product revision string included in Inquiry response, max 4 bytes
81-
#define CFG_TUD_MSC_PRODUCT_REV "1.0"
82-
8374
//------------- HID -------------//
8475

8576
// Should be sufficient to hold ID (if any) + Data

0 commit comments

Comments
 (0)