summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2021-08-30 17:31:50 +0700
committerGitHub <[email protected]>2021-08-30 17:31:50 +0700
commit38f5aee9c31299874dcda1758cb98e4404c6ad9d (patch)
tree3d29d52b6305d32e4c7960ad358a3cfe289b5ec8 /src
parent36dc25a22d05cf9826944e363dd9ca4eb3416661 (diff)
parentfdf1ff545f41c23f63e86d6debaa852e731d7644 (diff)
Merge pull request #1058 from hathach/usbcv-compliant-test
nrf5x USB Compliance Verification Test suite
Diffstat (limited to 'src')
-rw-r--r--src/class/hid/hid_device.h20
-rw-r--r--src/class/msc/msc_device.c546
-rw-r--r--src/class/msc/msc_device.h2
-rw-r--r--src/common/tusb_common.h7
-rw-r--r--src/device/dcd.h5
-rw-r--r--src/device/usbd.c81
-rw-r--r--src/portable/dialog/da146xx/dcd_da146xx.c6
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c6
-rw-r--r--src/portable/microchip/samd/dcd_samd.c6
-rw-r--r--src/portable/microchip/samg/dcd_samg.c6
-rw-r--r--src/portable/microchip/samx7x/dcd_samx7x.c6
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c6
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c77
-rw-r--r--src/portable/nuvoton/nuc120/dcd_nuc120.c6
-rw-r--r--src/portable/nuvoton/nuc121/dcd_nuc121.c6
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c6
-rw-r--r--src/portable/nxp/khci/dcd_khci.c6
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c6
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c6
-rw-r--r--src/portable/nxp/transdimension/dcd_transdimension.c6
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c6
-rw-r--r--src/portable/renesas/usba/dcd_usba.c6
-rw-r--r--src/portable/silabs/efm32/dcd_efm32.c6
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c6
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c6
-rw-r--r--src/portable/st/synopsys/dcd_synopsys.c6
-rw-r--r--src/portable/template/dcd_template.c5
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c6
-rw-r--r--src/portable/valentyusb/eptri/dcd_eptri.c6
29 files changed, 655 insertions, 214 deletions
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index e2c950dd1..5cf4b3060 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -195,16 +195,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_REPORT_COUNT ( 1 ) ,\
HID_REPORT_SIZE ( 8 ) ,\
HID_INPUT ( HID_CONSTANT ) ,\
- /* 6-byte Keycodes */ \
- HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
- HID_USAGE_MIN ( 0 ) ,\
- HID_USAGE_MAX_N ( 255, 2 ) ,\
- HID_LOGICAL_MIN ( 0 ) ,\
- HID_LOGICAL_MAX_N( 255, 2 ) ,\
- HID_REPORT_COUNT ( 6 ) ,\
- HID_REPORT_SIZE ( 8 ) ,\
- HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
- /* 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \
+ /* Output 5-bit LED Indicator Kana | Compose | ScrollLock | CapsLock | NumLock */ \
HID_USAGE_PAGE ( HID_USAGE_PAGE_LED ) ,\
HID_USAGE_MIN ( 1 ) ,\
HID_USAGE_MAX ( 5 ) ,\
@@ -215,6 +206,15 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_REPORT_COUNT ( 1 ) ,\
HID_REPORT_SIZE ( 3 ) ,\
HID_OUTPUT ( HID_CONSTANT ) ,\
+ /* 6-byte Keycodes */ \
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
+ HID_USAGE_MIN ( 0 ) ,\
+ HID_USAGE_MAX_N ( 255, 2 ) ,\
+ HID_LOGICAL_MIN ( 0 ) ,\
+ HID_LOGICAL_MAX_N( 255, 2 ) ,\
+ HID_REPORT_COUNT ( 6 ) ,\
+ HID_REPORT_SIZE ( 8 ) ,\
+ HID_INPUT ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
HID_COLLECTION_END \
// Mouse Report Descriptor Template
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 014e8b69e..7dcd4983e 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -46,7 +46,8 @@ enum
MSC_STAGE_CMD = 0,
MSC_STAGE_DATA,
MSC_STAGE_STATUS,
- MSC_STAGE_STATUS_SENT
+ MSC_STAGE_STATUS_SENT,
+ MSC_STAGE_NEED_RESET,
};
typedef struct
@@ -61,7 +62,7 @@ typedef struct
// Bulk Only Transfer (BOT) Protocol
uint8_t stage;
- uint32_t total_len;
+ uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw
uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
// Sense Response Data
@@ -78,7 +79,55 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_EP_
//--------------------------------------------------------------------+
static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize);
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
+
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
+static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes);
+
+TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir)
+{
+ return tu_bit_test(dir, 7);
+}
+
+static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc)
+{
+ // Data residue is always = host expect - actual transferred
+ p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
+
+ p_msc->stage = MSC_STAGE_STATUS_SENT;
+ return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t));
+}
+
+static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc)
+{
+ p_msc->stage = MSC_STAGE_CMD;
+ return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t));
+}
+
+static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status)
+{
+ msc_cbw_t const * p_cbw = &p_msc->cbw;
+ msc_csw_t * p_csw = &p_msc->csw;
+
+ p_csw->status = status;
+ p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
+ p_msc->stage = MSC_STAGE_STATUS;
+
+ // failed but sense key is not set: default to Illegal Request
+ if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+ // If there is data stage and not yet complete, stall it
+ if ( p_cbw->total_bytes && p_csw->data_residue )
+ {
+ if ( is_data_in(p_cbw->dir) )
+ {
+ usbd_edpt_stall(rhport, p_msc->ep_in);
+ }
+ else
+ {
+ usbd_edpt_stall(rhport, p_msc->ep_out);
+ }
+ }
+}
static inline uint32_t rdwr10_get_lba(uint8_t const command[])
{
@@ -89,15 +138,60 @@ static inline uint32_t rdwr10_get_lba(uint8_t const command[])
return tu_ntohl(lba);
}
-static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
+static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw)
{
- // use offsetof to avoid pointer to the odd/misaligned address
- uint16_t const block_count = tu_unaligned_read16(command + offsetof(scsi_write10_t, block_count));
-
- // block count is in Big Endian
+ uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count));
return tu_ntohs(block_count);
}
+static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw)
+{
+ // first extract block count in the command
+ uint16_t const block_count = rdwr10_get_blockcount(cbw);
+
+ // invalid block count
+ if (block_count == 0) return 0;
+
+ return cbw->total_bytes / block_count;
+}
+
+uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw)
+{
+ uint8_t status = MSC_CSW_STATUS_PASSED;
+ uint16_t const block_count = rdwr10_get_blockcount(cbw);
+
+ if ( cbw->total_bytes == 0 )
+ {
+ if ( block_count )
+ {
+ TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
+ status = MSC_CSW_STATUS_PHASE_ERROR;
+ }else
+ {
+ // no data transfer, only exist in complaint test suite
+ }
+ }else
+ {
+ if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) )
+ {
+ TU_LOG(MSC_DEBUG, " SCSI case 10 (Ho <> Di)\r\n");
+ status = MSC_CSW_STATUS_PHASE_ERROR;
+ }
+ else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) )
+ {
+ TU_LOG(MSC_DEBUG, " SCSI case 8 (Hi <> Do)\r\n");
+ status = MSC_CSW_STATUS_PHASE_ERROR;
+ }
+ else if ( !block_count )
+ {
+ TU_LOG(MSC_DEBUG, " SCSI case 4 Hi > Dn\r\n");
+ status = MSC_CSW_STATUS_FAILED;
+ }
+ }
+
+ return status;
+}
+
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
@@ -174,35 +268,89 @@ uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0 );
// Prepare for Command Block Wrapper
- if ( !usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) )
- {
- TU_LOG_FAILED();
- TU_BREAKPOINT();
- }
+ TU_ASSERT( prepare_cbw(rhport, p_msc), drv_len);
return drv_len;
}
+static void proc_bot_reset(mscd_interface_t* p_msc)
+{
+ p_msc->stage = MSC_STAGE_CMD;
+ p_msc->total_len = 0;
+ p_msc->xferred_len = 0;
+
+ p_msc->sense_key = 0;
+ p_msc->add_sense_code = 0;
+ p_msc->add_sense_qualifier = 0;
+}
+
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
-bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request)
+bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
// nothing to do with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP) return true;
- // Handle class request only
- TU_VERIFY(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+ mscd_interface_t* p_msc = &_mscd_itf;
- switch ( p_request->bRequest )
+ // Clear Endpoint Feature (stall) for recovery
+ if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
+ TUSB_REQ_RCPT_ENDPOINT == request->bmRequestType_bit.recipient &&
+ TUSB_REQ_CLEAR_FEATURE == request->bRequest &&
+ TUSB_REQ_FEATURE_EDPT_HALT == request->wValue )
+ {
+ uint8_t const ep_addr = tu_u16_low(request->wIndex);
+
+ if ( p_msc->stage == MSC_STAGE_NEED_RESET )
+ {
+ // reset recovery is required to recover from this stage
+ // Clear Stall request cannot resolve this -> continue to stall endpoint
+ usbd_edpt_stall(rhport, ep_addr);
+ }
+ else
+ {
+ if ( ep_addr == p_msc->ep_in )
+ {
+ if ( p_msc->stage == MSC_STAGE_STATUS )
+ {
+ // resume sending SCSI status if we are in this stage previously before stalled
+ TU_ASSERT( send_csw(rhport, p_msc) );
+ }
+ }
+ else if ( ep_addr == p_msc->ep_out )
+ {
+ if ( p_msc->stage == MSC_STAGE_CMD )
+ {
+ // part of reset recovery (probably due to invalid CBW) -> prepare for new command
+ TU_ASSERT( prepare_cbw(rhport, p_msc) );
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // From this point only handle class request only
+ TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+ switch ( request->bRequest )
{
case MSC_REQ_RESET:
- // TODO: Actually reset interface.
- tud_control_status(rhport, p_request);
+ TU_LOG(MSC_DEBUG, " MSC BOT Reset\r\n");
+ TU_VERIFY(request->wValue == 0 && request->wLength == 0);
+
+ // driver state reset
+ proc_bot_reset(p_msc);
+
+ tud_control_status(rhport, request);
break;
case MSC_REQ_GET_MAX_LUN:
{
+ TU_LOG(MSC_DEBUG, " MSC Get Max Lun\r\n");
+ TU_VERIFY(request->wValue == 0 && request->wLength == 1);
+
uint8_t maxlun = 1;
if (tud_msc_get_maxlun_cb) maxlun = tud_msc_get_maxlun_cb();
TU_VERIFY(maxlun);
@@ -210,7 +358,7 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
// MAX LUN is minus 1 by specs
maxlun--;
- tud_control_xfer(rhport, p_request, &maxlun, 1);
+ tud_control_xfer(rhport, request, &maxlun, 1);
}
break;
@@ -222,6 +370,8 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
{
+ (void) event;
+
mscd_interface_t* p_msc = &_mscd_itf;
msc_cbw_t const * p_cbw = &p_msc->cbw;
msc_csw_t * p_csw = &p_msc->csw;
@@ -233,46 +383,79 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
if(ep_addr != p_msc->ep_out) return true;
- TU_ASSERT( event == XFER_RESULT_SUCCESS &&
- xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE );
+ if ( !(xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE) )
+ {
+ TU_LOG(MSC_DEBUG, " SCSI CBW is not valid\r\n");
+
+ // BOT 6.6.1 If CBW is not valid stall both endpoints until reset recovery
+ p_msc->stage = MSC_STAGE_NEED_RESET;
+
+ // invalid CBW stall both endpoints
+ usbd_edpt_stall(rhport, p_msc->ep_in);
+ usbd_edpt_stall(rhport, p_msc->ep_out);
+
+ return false;
+ }
TU_LOG(MSC_DEBUG, " SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
- // TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
+ //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
p_csw->signature = MSC_CSW_SIGNATURE;
p_csw->tag = p_cbw->tag;
p_csw->data_residue = 0;
+ p_csw->status = MSC_CSW_STATUS_PASSED;
/*------------- Parse command and prepare DATA -------------*/
p_msc->stage = MSC_STAGE_DATA;
p_msc->total_len = p_cbw->total_bytes;
p_msc->xferred_len = 0;
- if (SCSI_CMD_READ_10 == p_cbw->command[0])
+ // Read10 or Write10
+ if ( (SCSI_CMD_READ_10 == p_cbw->command[0]) || (SCSI_CMD_WRITE_10 == p_cbw->command[0]) )
{
- proc_read10_cmd(rhport, p_msc);
- }
- else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
- {
- proc_write10_cmd(rhport, p_msc);
+ uint8_t const status = rdwr10_validate_cmd(p_cbw);
+
+ if ( status != MSC_CSW_STATUS_PASSED)
+ {
+ fail_scsi_op(rhport, p_msc, status);
+ }else if ( p_cbw->total_bytes )
+ {
+ if (SCSI_CMD_READ_10 == p_cbw->command[0])
+ {
+ proc_read10_cmd(rhport, p_msc);
+ }else
+ {
+ proc_write10_cmd(rhport, p_msc);
+ }
+ }else
+ {
+ // no data transfer, only exist in complaint test suite
+ p_msc->stage = MSC_STAGE_STATUS;
+ }
}
else
{
// For other SCSI commands
// 1. OUT : queue transfer (invoke app callback after done)
// 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
- if ( (p_cbw->total_bytes > 0 ) && !tu_bit_test(p_cbw->dir, 7) )
+ if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) )
{
- // queue transfer
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
+ if (p_cbw->total_bytes > sizeof(_mscd_buf))
+ {
+ TU_LOG(MSC_DEBUG, " SCSI reject non READ10/WRITE10 with large data\r\n");
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ }else
+ {
+ // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
+ // but it is OK to just receive data then responded with failed status
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
+ }
}else
{
- int32_t resplen;
-
// First process if it is a built-in commands
- resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf));
+ int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf));
- // Not built-in, invoke user callback
+ // Invoke user callback if not built-in
if ( (resplen < 0) && (p_msc->sense_key == 0) )
{
resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
@@ -280,30 +463,37 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ( resplen < 0 )
{
- p_msc->total_len = 0;
- p_csw->status = MSC_CSW_STATUS_FAILED;
- p_msc->stage = MSC_STAGE_STATUS;
-
- // failed but senskey is not set: default to Illegal Request
- if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
-
- // Stall bulk In if needed
- if (p_cbw->total_bytes) usbd_edpt_stall(rhport, p_msc->ep_in);
+ // unsupported command
+ TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n");
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}
- else
+ else if (resplen == 0)
{
- p_msc->total_len = (uint32_t) resplen;
- p_csw->status = MSC_CSW_STATUS_PASSED;
-
- if (p_msc->total_len)
+ if (p_cbw->total_bytes)
{
- TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+ // 6.7 The 13 Cases: case 4 (Hi > Dn)
+ TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes);
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}else
{
+ // case 1 Hn = Dn: all good
p_msc->stage = MSC_STAGE_STATUS;
}
}
+ else
+ {
+ if ( p_cbw->total_bytes == 0 )
+ {
+ // 6.7 The 13 Cases: case 2 (Hn < Di)
+ TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes);
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ }else
+ {
+ // cannot return more than host expect
+ p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes);
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+ }
+ }
}
}
break;
@@ -312,87 +502,51 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_LOG(MSC_DEBUG, " SCSI Data\r\n");
//TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
- // OUT transfer, invoke callback if needed
- if ( !tu_bit_test(p_cbw->dir, 7) )
+ if (SCSI_CMD_READ_10 == p_cbw->command[0])
{
- if ( SCSI_CMD_WRITE_10 != p_cbw->command[0] )
- {
- int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+ p_msc->xferred_len += xferred_bytes;
- if ( cb_result < 0 )
- {
- p_csw->status = MSC_CSW_STATUS_FAILED;
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
- }else
- {
- p_csw->status = MSC_CSW_STATUS_PASSED;
- }
- }
- else
+ if ( p_msc->xferred_len >= p_msc->total_len )
{
- uint16_t const block_sz = p_cbw->total_bytes / rdwr10_get_blockcount(p_cbw->command);
-
- // Adjust lba with transferred bytes
- uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
+ // Data Stage is complete
+ p_msc->stage = MSC_STAGE_STATUS;
+ }else
+ {
+ proc_read10_cmd(rhport, p_msc);
+ }
+ }
+ else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
+ {
+ proc_write10_new_data(rhport, p_msc, xferred_bytes);
+ }
+ else
+ {
+ p_msc->xferred_len += xferred_bytes;
- // Application can consume smaller bytes
- int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, p_msc->xferred_len % block_sz, _mscd_buf, xferred_bytes);
+ // OUT transfer, invoke callback if needed
+ if ( !is_data_in(p_cbw->dir) )
+ {
+ int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
- if ( nbytes < 0 )
+ if ( cb_result < 0 )
{
- // negative means error -> skip to status phase, status in CSW set to failed
- p_csw->data_residue = p_cbw->total_bytes - p_msc->xferred_len;
- p_csw->status = MSC_CSW_STATUS_FAILED;
- p_msc->stage = MSC_STAGE_STATUS;
-
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
- break;
+ // unsupported command
+ TU_LOG(MSC_DEBUG, " SCSI unsupported command\r\n");
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}else
{
- // Application consume less than what we got (including zero)
- if ( nbytes < (int32_t) xferred_bytes )
- {
- if ( nbytes > 0 )
- {
- p_msc->xferred_len += nbytes;
- memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
- }
-
- // simulate an transfer complete with adjusted parameters --> this driver callback will fired again
- dcd_event_xfer_complete(rhport, p_msc->ep_out, xferred_bytes-nbytes, XFER_RESULT_SUCCESS, false);
-
- return true; // skip the rest
- }
- else
- {
- // Application consume all bytes in our buffer. Nothing to do, process with normal flow
- }
+ // TODO haven't implement this scenario any further yet
}
}
- }
-
- // Accumulate data so far
- p_msc->xferred_len += xferred_bytes;
- if ( p_msc->xferred_len >= p_msc->total_len )
- {
- // Data Stage is complete
- p_msc->stage = MSC_STAGE_STATUS;
- }
- else
- {
- // READ10 & WRITE10 Can be executed with large bulk of data e.g write 8K bytes (several flash write)
- // We break it into multiple smaller command whose data size is up to CFG_TUD_MSC_EP_BUFSIZE
- if (SCSI_CMD_READ_10 == p_cbw->command[0])
+ if ( p_msc->xferred_len >= p_msc->total_len )
{
- proc_read10_cmd(rhport, p_msc);
+ // Data Stage is complete
+ p_msc->stage = MSC_STAGE_STATUS;
}
- else if (SCSI_CMD_WRITE_10 == p_cbw->command[0])
- {
- proc_write10_cmd(rhport, p_msc);
- }else
+ else
{
- // No other command take more than one transfer yet -> unlikely error
+ // This scenario with command that take more than one transfer is already rejected at Command stage
TU_BREAKPOINT();
}
}
@@ -406,7 +560,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Wait for the Status phase to complete
if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
{
- TU_LOG(MSC_DEBUG, " SCSI Status: %u\r\n", p_csw->status);
+ TU_LOG(MSC_DEBUG, " SCSI Status = %u\r\n", p_csw->status);
// TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
// Invoke complete callback if defined
@@ -427,11 +581,11 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
}
- // Move to default CMD stage
- p_msc->stage = MSC_STAGE_CMD;
-
- // Queue for the next CBW
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
+ TU_ASSERT( prepare_cbw(rhport, p_msc) );
+ }else
+ {
+ // Any xfer ended here is consider unknown error, ignore it
+ TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n");
}
break;
@@ -440,21 +594,18 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ( p_msc->stage == MSC_STAGE_STATUS )
{
- // Either endpoints is stalled, need to wait until it is cleared by host
- if ( usbd_edpt_stalled(rhport, p_msc->ep_in) || usbd_edpt_stalled(rhport, p_msc->ep_out) )
- {
- // simulate an transfer complete with adjusted parameters --> this driver callback will fired again
- // and response with status phase after halted endpoints are cleared.
- // note: use ep_out to prevent confusing with STATUS complete
- dcd_event_xfer_complete(rhport, p_msc->ep_out, 0, XFER_RESULT_SUCCESS, false);
- }
- else
+ // skip status if epin is currently stalled, will do it when received Clear Stall request
+ if ( !usbd_edpt_stalled(rhport, p_msc->ep_in) )
{
- // Move to Status Sent stage
- p_msc->stage = MSC_STAGE_STATUS_SENT;
-
- // Send SCSI Status
- TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
+ if ( (p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir) )
+ {
+ // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
+ TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
+ usbd_edpt_stall(rhport, p_msc->ep_in);
+ }else
+ {
+ TU_ASSERT( send_csw(rhport, p_msc) );
+ }
}
}
@@ -472,6 +623,8 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
(void) bufsize; // TODO refractor later
int32_t resplen;
+ mscd_interface_t* p_msc = &_mscd_itf;
+
switch ( scsi_cmd[0] )
{
case SCSI_CMD_TEST_UNIT_READY:
@@ -482,7 +635,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
resplen = - 1;
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
}
break;
@@ -498,7 +651,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
resplen = - 1;
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
}
}
break;
@@ -519,7 +672,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
resplen = -1;
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
}else
{
scsi_read_capacity10_resp_t read_capa10;
@@ -555,7 +708,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
resplen = -1;
// If sense key is not set by callback, default to Logical Unit Not Ready, Cause Not Reportable
- if ( _mscd_itf.sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
+ if ( p_msc->sense_key == 0 ) tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x04, 0x00);
}else
{
read_fmt_capa.block_num = tu_htonl(block_count);
@@ -600,9 +753,11 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
};
bool writable = true;
- if (tud_msc_is_writable_cb) {
- writable = tud_msc_is_writable_cb(lun);
+ if ( tud_msc_is_writable_cb )
+ {
+ writable = tud_msc_is_writable_cb(lun);
}
+
mode_resp.write_protected = !writable;
resplen = sizeof(mode_resp);
@@ -620,9 +775,9 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
- sense_rsp.sense_key = _mscd_itf.sense_key;
- sense_rsp.add_sense_code = _mscd_itf.add_sense_code;
- sense_rsp.add_sense_qualifier = _mscd_itf.add_sense_qualifier;
+ sense_rsp.sense_key = p_msc->sense_key;
+ sense_rsp.add_sense_code = p_msc->add_sense_code;
+ sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier;
resplen = sizeof(sense_rsp);
memcpy(buffer, &sense_rsp, resplen);
@@ -641,13 +796,9 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
{
msc_cbw_t const * p_cbw = &p_msc->cbw;
- msc_csw_t * p_csw = &p_msc->csw;
- uint16_t const block_cnt = rdwr10_get_blockcount(p_cbw->command);
- TU_ASSERT(block_cnt, ); // prevent div by zero
-
- uint16_t const block_sz = p_cbw->total_bytes / block_cnt;
- TU_ASSERT(block_sz, ); // prevent div by zero
+ // block size already verified not zero
+ uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
// Adjust lba with transferred bytes
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
@@ -656,16 +807,18 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
// Application can consume smaller bytes
- nbytes = tud_msc_read10_cb(p_cbw->lun, lba, p_msc->xferred_len % block_sz, _mscd_buf, (uint32_t) nbytes);
+ uint32_t const offset = p_msc->xferred_len % block_sz;
+ nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes);
if ( nbytes < 0 )
{
- // negative means error -> pipe is stalled & status in CSW set to failed
- p_csw->data_residue = p_cbw->total_bytes - p_msc->xferred_len;
- p_csw->status = MSC_CSW_STATUS_FAILED;
+ // negative means error -> endpoint is stalled & status in CSW set to failed
+ TU_LOG(MSC_DEBUG, " tud_msc_read10_cb() return -1\r\n");
+
+ // Sense = Flash not ready for access
+ tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // Sense = Invalid Command Operation
- usbd_edpt_stall(rhport, p_msc->ep_in);
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
}
else if ( nbytes == 0 )
{
@@ -682,16 +835,18 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
{
msc_cbw_t const * p_cbw = &p_msc->cbw;
bool writable = true;
- if (tud_msc_is_writable_cb) {
+
+ if ( tud_msc_is_writable_cb )
+ {
writable = tud_msc_is_writable_cb(p_cbw->lun);
}
- if (!writable) {
- msc_csw_t* p_csw = &p_msc->csw;
- p_csw->data_residue = p_cbw->total_bytes;
- p_csw->status = MSC_CSW_STATUS_FAILED;
- tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); // Sense = Write protected
- usbd_edpt_stall(rhport, p_msc->ep_out);
+ if ( !writable )
+ {
+ // Not writable, complete this SCSI op with error
+ // Sense = Write protected
+ tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00);
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
return;
}
@@ -702,4 +857,63 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
}
+// process new data arrived from WRITE10
+static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes)
+{
+ msc_cbw_t const * p_cbw = &p_msc->cbw;
+
+ // block size already verified not zero
+ uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
+
+ // Adjust lba with transferred bytes
+ uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
+
+ // Invoke callback to consume new data
+ uint32_t const offset = p_msc->xferred_len % block_sz;
+ int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes);
+
+ if ( nbytes < 0 )
+ {
+ // negative means error -> failed this scsi op
+ TU_LOG(MSC_DEBUG, " tud_msc_write10_cb() return -1\r\n");
+
+ // update actual byte before failed
+ p_msc->xferred_len += xferred_bytes;
+
+ // Sense = Flash not ready for access
+ tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_MEDIUM_ERROR, 0x33, 0x00);
+
+ fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ }else
+ {
+ // Application consume less than what we got (including zero)
+ if ( (uint32_t) nbytes < xferred_bytes )
+ {
+ if ( nbytes > 0 )
+ {
+ p_msc->xferred_len += nbytes;
+ memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
+ }
+
+ // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter
+ dcd_event_xfer_complete(rhport, p_msc->ep_out, xferred_bytes-nbytes, XFER_RESULT_SUCCESS, false);
+ }
+ else
+ {
+ // Application consume all bytes in our buffer
+ p_msc->xferred_len += xferred_bytes;
+
+ if ( p_msc->xferred_len >= p_msc->total_len )
+ {
+ // Data Stage is complete
+ p_msc->stage = MSC_STAGE_STATUS;
+ }else
+ {
+ // prepare to receive more data from host
+ proc_write10_cmd(rhport, p_msc);
+ }
+ }
+ }
+}
+
#endif
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index 8f90ef4ad..d32694340 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -140,7 +140,7 @@ TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
// Invoked when command in tud_msc_scsi_cb is complete
TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
-// Hook to make a mass storage device read-only. TODO remove
+// Invoked to check if device is writable as part of SCSI WRITE10
TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
//--------------------------------------------------------------------+
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index c2356ffee..1452e0105 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -369,12 +369,17 @@ typedef struct
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
{
+ static char not_found[10];
+
for(uint16_t i=0; i<p_table->count; i++)
{
if (p_table->items[i].key == key) return p_table->items[i].data;
}
- return NULL;
+ // not found return the key value in hex
+ sprintf(not_found, "0x%08lX", key);
+
+ return not_found;
}
#endif // CFG_TUSB_DEBUG
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 66767c1fe..8d042bbde 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -137,6 +137,11 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
// Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
+// Close all non-control endpoints, cancel all pending transfers if any.
+// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore
+// required for multiple configuration support.
+void dcd_edpt_close_all (uint8_t rhport);
+
// Close an endpoint.
// Since it is weak, caller must TU_ASSERT this function's existence before calling it.
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
diff --git a/src/device/usbd.c b/src/device/usbd.c
index e12dafcfd..7cd8fad42 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -38,7 +38,7 @@
//--------------------------------------------------------------------+
// Debug level of USBD
-#define USBD_DBG_LVL 2
+#define USBD_DBG 2
#ifndef CFG_TUD_TASK_QUEUE_SZ
#define CFG_TUD_TASK_QUEUE_SZ 16
@@ -432,19 +432,22 @@ bool tud_init (uint8_t rhport)
return true;
}
-static void usbd_reset(uint8_t rhport)
+static void configuration_reset(uint8_t rhport)
{
- tu_varclr(&_usbd_dev);
+ for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
+ {
+ get_driver(i)->reset(rhport);
+ }
+ tu_varclr(&_usbd_dev);
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
+}
+static void usbd_reset(uint8_t rhport)
+{
+ configuration_reset(rhport);
usbd_control_reset();
-
- for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
- {
- get_driver(i)->reset(rhport);
- }
}
bool tud_task_event_ready(void)
@@ -686,9 +689,29 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
{
uint8_t const cfg_num = (uint8_t) p_request->wValue;
- if ( !_usbd_dev.cfg_num && cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
- _usbd_dev.cfg_num = cfg_num;
+ // Only process if new configure is different
+ if (_usbd_dev.cfg_num != cfg_num)
+ {
+ if ( _usbd_dev.cfg_num )
+ {
+ // already configured: need to clear all endpoints and driver first
+ TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
+ // close all non-control endpoints, cancel all pending transfers if any
+ dcd_edpt_close_all(rhport);
+
+ // close all drivers and current configured state except bus speed
+ uint8_t const speed = _usbd_dev.speed;
+ configuration_reset(rhport);
+
+ _usbd_dev.speed = speed; // restore speed
+ }
+
+ // switch to new configuration if not zero
+ if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
+ }
+
+ _usbd_dev.cfg_num = cfg_num;
tud_control_status(rhport, p_request);
}
break;
@@ -701,7 +724,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Only support remote wakeup for device feature
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
- TU_LOG(USBD_DBG_LVL, " Enable Remote Wakeup\r\n");
+ TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n");
// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
@@ -712,7 +735,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Only support remote wakeup for device feature
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
- TU_LOG(USBD_DBG_LVL, " Disable Remote Wakeup\r\n");
+ TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n");
// Host may disable remote wake up after resuming
_usbd_dev.remote_wakeup_en = false;
@@ -751,16 +774,24 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// driver doesn't use alternate settings or implement this
TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
- if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+ switch(p_request->bRequest)
{
- uint8_t alternate = 0;
- tud_control_xfer(rhport, p_request, &alternate, 1);
- }else if (TUSB_REQ_SET_INTERFACE == p_request->bRequest)
- {
- tud_control_status(rhport, p_request);
- } else
- {
- return false;
+ case TUSB_REQ_GET_INTERFACE:
+ case TUSB_REQ_SET_INTERFACE:
+ // Clear complete callback if driver set since it can also stall the request.
+ usbd_control_set_complete_callback(NULL);
+
+ if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+ {
+ uint8_t alternate = 0;
+ tud_control_xfer(rhport, p_request, &alternate, 1);
+ }else
+ {
+ tud_control_status(rhport, p_request);
+ }
+ break;
+
+ default: return false;
}
}
}
@@ -843,7 +874,8 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// This function parse configuration descriptor & open drivers accordingly
static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
{
- tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1); // index is cfg_num-1
+ // index is cfg_num-1
+ tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1);
TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
// Parse configuration descriptor
@@ -1301,7 +1333,7 @@ bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
- TU_LOG(USBD_DBG_LVL, " Stall EP %02X", ep_addr);
+ TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -1313,12 +1345,11 @@ void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
- TU_LOG(USBD_DBG_LVL, " Clear Stall EP %02X", ep_addr);
+ TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
-
dcd_edpt_clear_stall(rhport, ep_addr);
_usbd_dev.ep_status[epnum][dir].stalled = false;
_usbd_dev.ep_status[epnum][dir].busy = false;
diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c
index 5fcf3bc5b..7b0d8f86c 100644
--- a/src/portable/dialog/da146xx/dcd_da146xx.c
+++ b/src/portable/dialog/da146xx/dcd_da146xx.c
@@ -847,6 +847,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index d728487c2..a5ada0da8 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -312,6 +312,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
return true;
}
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void)rhport;
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 577bd0e05..54e8e62d9 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -240,6 +240,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index d50621ce4..81779c56b 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -269,6 +269,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c
index 0d9e184f6..032547e47 100644
--- a/src/portable/microchip/samx7x/dcd_samx7x.c
+++ b/src/portable/microchip/samx7x/dcd_samx7x.c
@@ -544,6 +544,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
}
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index 59a40dc68..c472f2175 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -339,6 +339,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index f6b64c986..f40ba2d4f 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -206,7 +206,8 @@ static void xact_out_dma(uint8_t epnum)
}
else
{
- xact_len = (uint8_t)NRF_USBD->SIZE.EPOUT[epnum];
+ // limit xact len to remaining length
+ xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
@@ -306,8 +307,9 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+ uint8_t const ep_addr = desc_edpt->bEndpointAddress;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
_dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size;
@@ -359,11 +361,48 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
}
}
+
+ // clear stall and reset DataToggle
+ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+ NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+
__ISB(); __DSB();
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ // disable interrupt to prevent race condition
+ dcd_int_disable(rhport);
+
+ // disable all non-control (bulk + interrupt) endpoints
+ for ( uint8_t ep = 1; ep < EP_CBI_COUNT; ep++ )
+ {
+ NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + ep) | TU_BIT(USBD_INTEN_ENDEPIN0_Pos + ep);
+
+ NRF_USBD->TASKS_STARTEPIN[ep] = 0;
+ NRF_USBD->TASKS_STARTEPOUT[ep] = 0;
+
+ tu_memclr(_dcd.xfer[ep], 2*sizeof(xfer_td_t));
+ }
+
+ // disable both ISO
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk | USBD_INTENCLR_ENDISOOUT_Msk | USBD_INTENCLR_ENDISOIN_Msk;
+ NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
+
+ NRF_USBD->TASKS_STARTISOIN = 0;
+ NRF_USBD->TASKS_STARTISOOUT = 0;
+
+ tu_memclr(_dcd.xfer[EP_ISO_NUM], 2*sizeof(xfer_td_t));
+
+ // de-activate all non-control
+ NRF_USBD->EPOUTEN = 1UL;
+ NRF_USBD->EPINEN = 1UL;
+
+ dcd_int_enable(rhport);
+}
+
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
@@ -442,10 +481,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
{
if ( xfer->data_received )
{
- // Data may already be received previously
- xfer->data_received = false;
-
+ // Data is already received previously
// start DMA to copy to SRAM
+ xfer->data_received = false;
xact_out_dma(epnum);
}
else
@@ -467,7 +505,11 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
+
uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_td_t* xfer = get_td(epnum, dir);
if ( epnum == 0 )
{
@@ -475,6 +517,15 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
}else if (epnum != EP_ISO_NUM)
{
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
+ // Note: nRF can auto ACK packet OUT before get stalled.
+ // There maybe data in endpoint fifo already, we need to pull it out
+ if ( (dir == TUSB_DIR_OUT) && xfer->data_received )
+ {
+ TU_LOG_LOCATION();
+ xfer->data_received = false;
+ xact_out_dma(epnum);
+ }
}
__ISB(); __DSB();
@@ -488,14 +539,16 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
if ( epnum != 0 && epnum != EP_ISO_NUM )
{
- // clear stall
- NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
-
// reset data toggle to DATA0
+ // First write this register with VALUE=Nop to select the endpoint, then either read it to get the status from
+ // VALUE, or write it again with VALUE=Data0 or Data1
+ NRF_USBD->DTOGGLE = ep_addr;
NRF_USBD->DTOGGLE = (USBD_DTOGGLE_VALUE_Data0 << USBD_DTOGGLE_VALUE_Pos) | ep_addr;
+ // clear stall
+ NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
+
// Write any value to SIZE register will allow nRF to ACK/accept data
- // Drop any pending data
if (dir == TUSB_DIR_OUT) NRF_USBD->SIZE.EPOUT[epnum] = 0;
__ISB(); __DSB();
@@ -508,7 +561,9 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
void bus_reset(void)
{
// 6.35.6 USB controller automatically disabled all endpoints (except control)
- // i.e EPOUTEN and EPINEN and reset USBADDR to 0
+ NRF_USBD->EPOUTEN = 1UL;
+ NRF_USBD->EPINEN = 1UL;
+
for(int i=0; i<8; i++)
{
NRF_USBD->TASKS_STARTEPIN[i] = 0;
diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c
index 57cc76e81..7618f288d 100644
--- a/src/portable/nuvoton/nuc120/dcd_nuc120.c
+++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c
@@ -273,6 +273,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c
index a776e46f5..7edafe5d3 100644
--- a/src/portable/nuvoton/nuc121/dcd_nuc121.c
+++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c
@@ -289,6 +289,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index 4e633086d..ea5a8bea5 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -353,6 +353,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index dce464fd2..1f5f4e5e1 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -347,6 +347,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index 519d09151..2eae6d0f7 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -326,6 +326,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 4392d1882..1bdf72d6d 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -323,6 +323,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
static void prepare_setup_packet(uint8_t rhport)
{
if (_dcd_controller[rhport].max_speed == TUSB_SPEED_FULL )
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
index eeab3f487..42047ef92 100644
--- a/src/portable/nxp/transdimension/dcd_transdimension.c
+++ b/src/portable/nxp/transdimension/dcd_transdimension.c
@@ -366,6 +366,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 49284e92e..e81681d4f 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -428,6 +428,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
assert(rhport == 0);
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
index 095dcc136..a837b5724 100644
--- a/src/portable/renesas/usba/dcd_usba.c
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -733,6 +733,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
diff --git a/src/portable/silabs/efm32/dcd_efm32.c b/src/portable/silabs/efm32/dcd_efm32.c
index bd1f32e6b..3bef83408 100644
--- a/src/portable/silabs/efm32/dcd_efm32.c
+++ b/src/portable/silabs/efm32/dcd_efm32.c
@@ -434,6 +434,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
{
(void)rhport;
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index 834976468..cfd74330f 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -312,6 +312,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index eeba7204f..ccffa42d7 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -800,6 +800,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
/**
* Close an endpoint.
*
diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c
index 8a998aa3a..fe165e830 100644
--- a/src/portable/st/synopsys/dcd_synopsys.c
+++ b/src/portable/st/synopsys/dcd_synopsys.c
@@ -670,6 +670,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
uint8_t const epnum = tu_edpt_number(ep_addr);
diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c
index 12b9144bf..977369300 100644
--- a/src/portable/template/dcd_template.c
+++ b/src/portable/template/dcd_template.c
@@ -94,6 +94,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
return false;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+}
+
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 027ed26c9..ee85f0a77 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -298,6 +298,12 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c
index b68f04faa..89bc7a1ab 100644
--- a/src/portable/valentyusb/eptri/dcd_eptri.c
+++ b/src/portable/valentyusb/eptri/dcd_eptri.c
@@ -429,6 +429,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
return true;
}
+void dcd_edpt_close_all (uint8_t rhport)
+{
+ (void) rhport;
+ // TODO implement dcd_edpt_close_all()
+}
+
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;