Skip to content

Commit d81bda4

Browse files
authored
Merge pull request arduino#109 from hathach/adafruit-tinyusb
fix tinyusb bug with clear stall and reset data toggle
2 parents cd0f54e + af90d98 commit d81bda4

File tree

13 files changed

+158
-127
lines changed

13 files changed

+158
-127
lines changed

cores/arduino/Adafruit_TinyUSB_Core/Adafruit_TinyUSB_Core.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* THE SOFTWARE.
2323
*/
2424

25-
#if defined(USE_TINYUSB) && defined(USBCON)
25+
#ifdef USE_TINYUSB
2626

2727
#include "Arduino.h"
2828
#include "Adafruit_TinyUSB_Core.h"
@@ -128,4 +128,4 @@ void Adafruit_TinyUSB_Core_init(void)
128128
tusb_init();
129129
}
130130

131-
#endif
131+
#endif // USE_TINYUSB

cores/arduino/Adafruit_TinyUSB_Core/Adafruit_TinyUSB_Core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#ifndef ADAFRUIT_TINYUSB_CORE_H_
2626
#define ADAFRUIT_TINYUSB_CORE_H_
2727

28+
#ifndef USE_TINYUSB
29+
#error TinyUSB is not selected, please select it in Tools->Menu->USB Stack
30+
#endif
31+
2832
#include "tusb.h"
2933

3034
#ifdef __cplusplus

cores/arduino/Adafruit_TinyUSB_Core/Adafruit_USBD_CDC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* THE SOFTWARE.
2323
*/
2424

25-
#if defined(USE_TINYUSB) && defined(USBCON)
25+
#ifdef USE_TINYUSB
2626

2727
#include "Arduino.h"
2828
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
@@ -139,4 +139,4 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
139139

140140
}
141141

142-
#endif // NRF52840_XXAA
142+
#endif // USE_TINYUSB

cores/arduino/Adafruit_TinyUSB_Core/Adafruit_USBD_Device.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* THE SOFTWARE.
2323
*/
2424

25-
#if defined(USE_TINYUSB) && defined(USBCON)
25+
#ifdef USE_TINYUSB
2626

2727
#include "Adafruit_USBD_Device.h"
2828

@@ -184,4 +184,4 @@ bool Adafruit_USBD_Device::begin(void)
184184
return true;
185185
}
186186

187-
#endif
187+
#endif // USE_TINYUSB

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

Lines changed: 109 additions & 79 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,30 +186,64 @@ 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
{
199-
scsi_read_capacity10_resp_t read_capa10;
200-
201222
uint32_t block_count;
202223
uint32_t block_size;
203224
uint16_t block_size_u16;
204225

205-
tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size_u16);
226+
tud_msc_capacity_cb(lun, &block_count, &block_size_u16);
206227
block_size = (uint32_t) block_size_u16;
207228

208-
read_capa10.last_lba = ENDIAN_BE(block_count-1);
209-
read_capa10.block_size = ENDIAN_BE(block_size);
229+
// Invalid block size/count from callback, possibly unit is not ready
230+
// stall this request, set sense key to NOT READY
231+
if (block_count == 0 || block_size == 0)
232+
{
233+
resplen = -1;
234+
235+
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
236+
if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
237+
}else
238+
{
239+
scsi_read_capacity10_resp_t read_capa10;
240+
241+
read_capa10.last_lba = ENDIAN_BE(block_count-1);
242+
read_capa10.block_size = ENDIAN_BE(block_size);
210243

211-
ret = sizeof(read_capa10);
212-
memcpy(buffer, &read_capa10, ret);
244+
resplen = sizeof(read_capa10);
245+
memcpy(buffer, &read_capa10, resplen);
246+
}
213247
}
214248
break;
215249

@@ -226,12 +260,24 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
226260
uint32_t block_count;
227261
uint16_t block_size;
228262

229-
tud_msc_capacity_cb(p_cbw->lun, &block_count, &block_size);
230-
read_fmt_capa.block_num = ENDIAN_BE(block_count);
231-
read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
263+
tud_msc_capacity_cb(lun, &block_count, &block_size);
264+
265+
// Invalid block size/count from callback, possibly unit is not ready
266+
// stall this request, set sense key to NOT READY
267+
if (block_count == 0 || block_size == 0)
268+
{
269+
resplen = -1;
232270

233-
ret = sizeof(read_fmt_capa);
234-
memcpy(buffer, &read_fmt_capa, ret);
271+
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
272+
if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
273+
}else
274+
{
275+
read_fmt_capa.block_num = ENDIAN_BE(block_count);
276+
read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
277+
278+
resplen = sizeof(read_fmt_capa);
279+
memcpy(buffer, &read_fmt_capa, resplen);
280+
}
235281
}
236282
break;
237283

@@ -242,23 +288,17 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
242288
.is_removable = 1,
243289
.version = 2,
244290
.response_data_format = 2,
245-
// vendor_id, product_id, product_rev is space padded string
246-
.vendor_id = "",
247-
.product_id = "",
248-
.product_rev = "",
249291
};
250292

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-
293+
// vendor_id, product_id, product_rev is space padded string
294+
memset(inquiry_rsp.vendor_id , ' ', sizeof(inquiry_rsp.vendor_id));
295+
memset(inquiry_rsp.product_id , ' ', sizeof(inquiry_rsp.product_id));
257296
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)));
259297

260-
ret = sizeof(inquiry_rsp);
261-
memcpy(buffer, &inquiry_rsp, ret);
298+
tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev);
299+
300+
resplen = sizeof(inquiry_rsp);
301+
memcpy(buffer, &inquiry_rsp, resplen);
262302
}
263303
break;
264304

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

276316
bool writable = true;
277317
if (tud_msc_is_writable_cb) {
278-
writable = tud_msc_is_writable_cb(p_cbw->lun);
318+
writable = tud_msc_is_writable_cb(lun);
279319
}
280320
mode_resp.write_protected = !writable;
281321

282-
ret = sizeof(mode_resp);
283-
memcpy(buffer, &mode_resp, ret);
322+
resplen = sizeof(mode_resp);
323+
memcpy(buffer, &mode_resp, resplen);
284324
}
285325
break;
286326

@@ -298,18 +338,18 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
298338
sense_rsp.add_sense_code = _mscd_itf.add_sense_code;
299339
sense_rsp.add_sense_qualifier = _mscd_itf.add_sense_qualifier;
300340

301-
ret = sizeof(sense_rsp);
302-
memcpy(buffer, &sense_rsp, ret);
341+
resplen = sizeof(sense_rsp);
342+
memcpy(buffer, &sense_rsp, resplen);
303343

304344
// Clear sense data after copy
305-
tud_msc_set_sense(p_cbw->lun, 0, 0, 0);
345+
tud_msc_set_sense(lun, 0, 0, 0);
306346
}
307347
break;
308348

309-
default: ret = -1; break;
349+
default: resplen = -1; break;
310350
}
311351

312-
return ret;
352+
return resplen;
313353
}
314354

315355
bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
@@ -348,60 +388,50 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
348388
else
349389
{
350390
// 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)
391+
// 1. OUT : queue transfer (invoke app callback after done)
392+
// 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
393+
if ( (p_cbw->total_bytes > 0 ) && !TU_BIT_TEST(p_cbw->dir, 7) )
355394
{
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) )
372-
{
373-
// OUT transfer
395+
// queue transfer
374396
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
375-
}
376-
else
397+
}else
377398
{
378-
// IN Transfer
379-
int32_t cb_result;
399+
int32_t resplen;
380400

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

384-
// Not an built-in command, invoke user callback
385-
if ( cb_result < 0 )
404+
// Not built-in, invoke user callback
405+
if ( (resplen < 0) && (p_msc->sense_key == 0) )
386406
{
387-
cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
407+
resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
388408
}
389409

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
410+
if ( resplen < 0 )
398411
{
399412
p_msc->total_len = 0;
400413
p_csw->status = MSC_CSW_STATUS_FAILED;
401414
p_msc->stage = MSC_STAGE_STATUS;
402415

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);
416+
// failed but senskey is not set: default to Illegal Request
417+
if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
418+
419+
/// Stall bulk In if needed
420+
if (p_cbw->total_bytes) usbd_edpt_stall(rhport, p_msc->ep_in);
421+
}
422+
else
423+
{
424+
p_msc->total_len = (uint32_t) resplen;
425+
p_csw->status = MSC_CSW_STATUS_PASSED;
426+
427+
if (p_msc->total_len)
428+
{
429+
TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
430+
TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
431+
}else
432+
{
433+
p_msc->stage = MSC_STAGE_STATUS;
434+
}
405435
}
406436
}
407437
}

0 commit comments

Comments
 (0)