mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-04 09:05:35 +00:00
Merge remote-tracking branch 'tinyusb/master' into bsp_h7_tm4c
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -315,7 +315,7 @@ jobs:
|
|||||||
run: python3 tools/get_deps.py $BUILD_ARGS
|
run: python3 tools/get_deps.py $BUILD_ARGS
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: python3 tools/build.py -j 4 --toolchain iar $BUILD_ARGS
|
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
|
||||||
|
|
||||||
- name: Test on actual hardware (hardware in the loop)
|
- name: Test on actual hardware (hardware in the loop)
|
||||||
run: python3 test/hil/hil_test.py hfp.json
|
run: python3 test/hil/hil_test.py hfp.json
|
||||||
|
|||||||
3
.github/workflows/ci_set_matrix.py
vendored
3
.github/workflows/ci_set_matrix.py
vendored
@ -38,7 +38,8 @@ family_list = {
|
|||||||
"stm32h7": ["arm-gcc", "arm-clang", "arm-iar"],
|
"stm32h7": ["arm-gcc", "arm-clang", "arm-iar"],
|
||||||
"stm32h7rs stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
|
"stm32h7rs stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
|
||||||
"stm32n6": ["arm-gcc"],
|
"stm32n6": ["arm-gcc"],
|
||||||
"stm32u0 stm32u5 stm32wb stm32wba": ["arm-gcc", "arm-clang", "arm-iar"],
|
"stm32u0 stm32wb stm32wba": ["arm-gcc", "arm-clang", "arm-iar"],
|
||||||
|
"stm32u5": ["arm-gcc", "arm-clang", "arm-iar"],
|
||||||
"-bespressif_s2_devkitc": ["esp-idf"],
|
"-bespressif_s2_devkitc": ["esp-idf"],
|
||||||
# S3, P4 will be built by hil test
|
# S3, P4 will be built by hil test
|
||||||
# "-bespressif_s3_devkitm": ["esp-idf"],
|
# "-bespressif_s3_devkitm": ["esp-idf"],
|
||||||
|
|||||||
@ -557,7 +557,7 @@ static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) {
|
|||||||
return MTP_RESP_INVALID_STORAGE_ID;
|
return MTP_RESP_INVALID_STORAGE_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj_info->parent_object != 0) { // not root
|
if (obj_info->parent_object != 0 && obj_info->parent_object != 0xFFFFFFFFu) { // not root
|
||||||
fs_file_t* parent = fs_get_file(obj_info->parent_object);
|
fs_file_t* parent = fs_get_file(obj_info->parent_object);
|
||||||
if (parent == NULL || 0u == parent->association_type) {
|
if (parent == NULL || 0u == parent->association_type) {
|
||||||
return MTP_RESP_INVALID_PARENT_OBJECT;
|
return MTP_RESP_INVALID_PARENT_OBJECT;
|
||||||
|
|||||||
@ -251,6 +251,7 @@ function(family_configure_target TARGET RTOS)
|
|||||||
family_flash_jlink(${TARGET})
|
family_flash_jlink(${TARGET})
|
||||||
|
|
||||||
# Generate linkermap target and post build. LINKERMAP_OPTION can be set with -D to change default options
|
# Generate linkermap target and post build. LINKERMAP_OPTION can be set with -D to change default options
|
||||||
|
family_add_bloaty(${TARGET})
|
||||||
family_add_linkermap(${TARGET})
|
family_add_linkermap(${TARGET})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|||||||
@ -92,8 +92,9 @@ typedef struct {
|
|||||||
uint8_t itf_num;
|
uint8_t itf_num;
|
||||||
uint8_t ep_in;
|
uint8_t ep_in;
|
||||||
uint8_t ep_out;
|
uint8_t ep_out;
|
||||||
uint8_t ep_event;
|
|
||||||
|
|
||||||
|
uint8_t ep_event;
|
||||||
|
uint8_t ep_sz_fs;
|
||||||
// Bulk Only Transfer (BOT) Protocol
|
// Bulk Only Transfer (BOT) Protocol
|
||||||
uint8_t phase;
|
uint8_t phase;
|
||||||
|
|
||||||
@ -194,42 +195,47 @@ static bool prepare_new_command(mtpd_interface_t* p_mtp) {
|
|||||||
return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, CFG_TUD_MTP_EP_BUFSIZE, false);
|
return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, CFG_TUD_MTP_EP_BUFSIZE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
|
bool tud_mtp_data_send(mtp_container_info_t *p_container) {
|
||||||
mtpd_interface_t* p_mtp = &_mtpd_itf;
|
mtpd_interface_t *p_mtp = &_mtpd_itf;
|
||||||
if (p_mtp->phase == MTP_PHASE_COMMAND) {
|
if (p_mtp->phase == MTP_PHASE_COMMAND) {
|
||||||
// 1st data block: header + payload
|
// 1st data block: header + payload
|
||||||
p_mtp->phase = MTP_PHASE_DATA;
|
p_mtp->phase = MTP_PHASE_DATA;
|
||||||
p_mtp->xferred_len = 0;
|
p_mtp->xferred_len = 0;
|
||||||
|
p_mtp->total_len = p_container->header->len;
|
||||||
|
|
||||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
|
||||||
p_mtp->total_len = p_container->header->len;
|
p_container->header->transaction_id = p_mtp->command.header.transaction_id;
|
||||||
p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
|
p_mtp->io_header = *p_container->header; // save header for subsequent data
|
||||||
p_container->header->transaction_id = p_mtp->command.header.transaction_id;
|
|
||||||
p_mtp->io_header = *p_container->header; // save header for subsequent data
|
|
||||||
} else {
|
|
||||||
// OUT transfer: total length is at least max packet size
|
|
||||||
p_mtp->total_len = tu_max32(p_container->header->len, CFG_TUD_MTP_EP_BUFSIZE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// subsequent data block: payload only
|
|
||||||
TU_ASSERT(p_mtp->phase == MTP_PHASE_DATA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t xact_len = (uint16_t) tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE);
|
const uint16_t xact_len = (uint16_t)tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE);
|
||||||
|
|
||||||
|
TU_LOG_DRV(" MTP Data IN: xferred_len/total_len=%lu/%lu, xact_len=%u\r\n", p_mtp->xferred_len, p_mtp->total_len,
|
||||||
|
xact_len);
|
||||||
if (xact_len) {
|
if (xact_len) {
|
||||||
// already transferred all bytes in header's length. Application make an unnecessary extra call
|
TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_in));
|
||||||
TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
|
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, xact_len, false));
|
||||||
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len, false));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_mtp_data_send(mtp_container_info_t* p_container) {
|
bool tud_mtp_data_receive(mtp_container_info_t *p_container) {
|
||||||
return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
|
mtpd_interface_t *p_mtp = &_mtpd_itf;
|
||||||
}
|
if (p_mtp->phase == MTP_PHASE_COMMAND) {
|
||||||
|
// 1st data block: header + payload
|
||||||
|
p_mtp->phase = MTP_PHASE_DATA;
|
||||||
|
p_mtp->xferred_len = 0;
|
||||||
|
p_mtp->total_len = p_container->header->len;
|
||||||
|
}
|
||||||
|
|
||||||
bool tud_mtp_data_receive(mtp_container_info_t* p_container) {
|
// up to buffer size since 1st packet (with header) may also contain payload
|
||||||
return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
|
const uint16_t xact_len = CFG_TUD_MTP_EP_BUFSIZE;
|
||||||
|
|
||||||
|
TU_LOG_DRV(" MTP Data OUT: xferred_len/total_len=%lu/%lu, xact_len=%u\r\n", p_mtp->xferred_len, p_mtp->total_len,
|
||||||
|
xact_len);
|
||||||
|
TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_out));
|
||||||
|
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, xact_len, false));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_mtp_response_send(mtp_container_info_t* p_container) {
|
bool tud_mtp_response_send(mtp_container_info_t* p_container) {
|
||||||
@ -287,15 +293,20 @@ uint16_t mtpd_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16
|
|||||||
p_mtp->itf_num = itf_desc->bInterfaceNumber;
|
p_mtp->itf_num = itf_desc->bInterfaceNumber;
|
||||||
|
|
||||||
// Open interrupt IN endpoint
|
// Open interrupt IN endpoint
|
||||||
const tusb_desc_endpoint_t* ep_desc = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
|
const tusb_desc_endpoint_t* ep_desc_int = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
|
||||||
TU_ASSERT(ep_desc->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0);
|
TU_ASSERT(ep_desc_int->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc_int->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0);
|
||||||
TU_ASSERT(usbd_edpt_open(rhport, ep_desc), 0);
|
TU_ASSERT(usbd_edpt_open(rhport, ep_desc_int), 0);
|
||||||
p_mtp->ep_event = ep_desc->bEndpointAddress;
|
p_mtp->ep_event = ep_desc_int->bEndpointAddress;
|
||||||
|
|
||||||
// Open endpoint pair
|
// Open endpoint pair
|
||||||
TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(ep_desc), 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0);
|
const tusb_desc_endpoint_t* ep_desc_bulk = (const tusb_desc_endpoint_t*) tu_desc_next(ep_desc_int);
|
||||||
|
TU_ASSERT(usbd_open_edpt_pair(rhport, (const uint8_t*)ep_desc_bulk, 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0);
|
||||||
TU_ASSERT(prepare_new_command(p_mtp), 0);
|
TU_ASSERT(prepare_new_command(p_mtp), 0);
|
||||||
|
|
||||||
|
if (tud_speed_get() == TUSB_SPEED_FULL) {
|
||||||
|
p_mtp->ep_sz_fs = (uint8_t)tu_edpt_packet_size(ep_desc_bulk);
|
||||||
|
}
|
||||||
|
|
||||||
return mtpd_itf_size;
|
return mtpd_itf_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,8 +388,8 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
|||||||
mtp_generic_container_t* p_container = (mtp_generic_container_t*) _mtpd_epbuf.buf;
|
mtp_generic_container_t* p_container = (mtp_generic_container_t*) _mtpd_epbuf.buf;
|
||||||
|
|
||||||
#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
|
#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
|
||||||
tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code);
|
const uint16_t code = (p_mtp->phase == MTP_PHASE_COMMAND) ? p_container->header.code : p_mtp->command.header.code;
|
||||||
TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code),
|
TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, code),
|
||||||
_mtp_phase_str[p_mtp->phase]);
|
_mtp_phase_str[p_mtp->phase]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -417,19 +428,35 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MTP_PHASE_DATA: {
|
case MTP_PHASE_DATA: {
|
||||||
const uint16_t bulk_mps = (tud_speed_get() == TUSB_SPEED_HIGH) ? 512 : 64;
|
|
||||||
p_mtp->xferred_len += xferred_bytes;
|
p_mtp->xferred_len += xferred_bytes;
|
||||||
cb_data.total_xferred_bytes = p_mtp->xferred_len;
|
cb_data.total_xferred_bytes = p_mtp->xferred_len;
|
||||||
|
|
||||||
bool is_complete = false;
|
const bool is_data_in = (ep_addr == p_mtp->ep_in);
|
||||||
// complete if ZLP or short packet or total length reached
|
// For IN endpoint, threshold is bulk max packet size
|
||||||
if (xferred_bytes == 0 || // ZLP
|
// For OUT endpoint, threshold is endpoint buffer size, since we always queue fixed size
|
||||||
(xferred_bytes & (bulk_mps - 1)) || // short packet
|
uint16_t threshold;
|
||||||
p_mtp->xferred_len >= p_mtp->total_len) { // total length reached
|
if (is_data_in) {
|
||||||
is_complete = true;
|
threshold = (p_mtp->ep_sz_fs > 0) ? p_mtp->ep_sz_fs : 512; // full speed bulk if set
|
||||||
|
} else {
|
||||||
|
threshold = CFG_TUD_MTP_EP_BUFSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep_addr == p_mtp->ep_in) {
|
// Check completion: ZLP, short packet, or total length reached
|
||||||
|
const bool is_complete =
|
||||||
|
(xferred_bytes == 0 || xferred_bytes < threshold || p_mtp->xferred_len >= p_mtp->total_len);
|
||||||
|
|
||||||
|
TU_LOG_DRV(" MTP Data %s CB: xferred_bytes=%lu, xferred_len/total_len=%lu/%lu, is_complete=%d\r\n",
|
||||||
|
is_data_in ? "IN" : "OUT", xferred_bytes, p_mtp->xferred_len, p_mtp->total_len, is_complete ? 1 : 0);
|
||||||
|
|
||||||
|
// Send/queue ZLP if packet is full-sized but transfer is complete
|
||||||
|
if (is_complete && xferred_bytes > 0 && !(xferred_bytes & (threshold - 1))) {
|
||||||
|
TU_LOG_DRV(" queue ZLP\r\n");
|
||||||
|
TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
|
||||||
|
TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, NULL, 0, false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_data_in) {
|
||||||
// Data In
|
// Data In
|
||||||
if (is_complete) {
|
if (is_complete) {
|
||||||
cb_data.io_container.header->len = sizeof(mtp_container_header_t);
|
cb_data.io_container.header->len = sizeof(mtp_container_header_t);
|
||||||
|
|||||||
266
src/class/vendor/vendor_device.c
vendored
266
src/class/vendor/vendor_device.c
vendored
@ -40,36 +40,33 @@ typedef struct {
|
|||||||
uint8_t rhport;
|
uint8_t rhport;
|
||||||
uint8_t itf_num;
|
uint8_t itf_num;
|
||||||
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||||
struct {
|
tu_edpt_stream_t tx_stream;
|
||||||
tu_edpt_stream_t tx;
|
tu_edpt_stream_t rx_stream;
|
||||||
tu_edpt_stream_t rx;
|
uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||||
|
uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
#else
|
||||||
uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
uint8_t ep_in;
|
||||||
|
uint8_t ep_out;
|
||||||
|
uint16_t ep_in_mps;
|
||||||
|
uint16_t ep_out_mps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
|
||||||
uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
|
|
||||||
#endif
|
|
||||||
} stream;
|
|
||||||
} vendord_interface_t;
|
} vendord_interface_t;
|
||||||
|
|
||||||
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + TU_FIELD_SIZE(vendord_interface_t, itf_num))
|
||||||
|
#else
|
||||||
|
#define ITF_MEM_RESET_SIZE sizeof(vendord_interface_t)
|
||||||
|
#endif
|
||||||
|
|
||||||
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||||
|
|
||||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
// Skip local EP buffer if dedicated hw FIFO is supported or no fifo mode
|
||||||
|
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || !CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Skip local EP buffer if dedicated hw FIFO is supported
|
|
||||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
|
||||||
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
|
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Skip local EP buffer if dedicated hw FIFO is supported
|
|
||||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0
|
|
||||||
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
|
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
|
||||||
#endif
|
|
||||||
} vendord_epbuf_t;
|
} vendord_epbuf_t;
|
||||||
|
|
||||||
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
||||||
@ -78,7 +75,6 @@ CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Weak stubs: invoked if no strong implementation is available
|
// Weak stubs: invoked if no strong implementation is available
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
|
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
|
||||||
(void)idx;
|
(void)idx;
|
||||||
(void)buffer;
|
(void)buffer;
|
||||||
@ -93,40 +89,44 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
|
|||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// Application API
|
// Application API
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
bool tud_vendor_n_mounted(uint8_t idx) {
|
bool tud_vendor_n_mounted(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return p_itf->stream.rx.ep_addr || p_itf->stream.tx.ep_addr;
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
return (p_itf->rx_stream.ep_addr != 0) || (p_itf->tx_stream.ep_addr != 0);
|
||||||
|
#else
|
||||||
|
return (p_itf->ep_out != 0) || (p_itf->ep_in != 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Read API
|
// Read API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
uint32_t tud_vendor_n_available(uint8_t idx) {
|
uint32_t tud_vendor_n_available(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_read_available(&p_itf->stream.rx);
|
return tu_edpt_stream_read_available(&p_itf->rx_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_vendor_n_peek(uint8_t idx, uint8_t *u8) {
|
bool tud_vendor_n_peek(uint8_t idx, uint8_t *u8) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_peek(&p_itf->stream.rx, u8);
|
return tu_edpt_stream_peek(&p_itf->rx_stream, u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize) {
|
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_read(&p_itf->stream.rx, buffer, bufsize);
|
return tu_edpt_stream_read(&p_itf->rx_stream, buffer, bufsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tud_vendor_n_read_flush(uint8_t idx) {
|
void tud_vendor_n_read_flush(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, );
|
TU_VERIFY(idx < CFG_TUD_VENDOR, );
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
tu_edpt_stream_clear(&p_itf->stream.rx);
|
tu_edpt_stream_clear(&p_itf->rx_stream);
|
||||||
tu_edpt_stream_read_xfer(&p_itf->stream.rx);
|
tu_edpt_stream_read_xfer(&p_itf->rx_stream);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -134,9 +134,17 @@ void tud_vendor_n_read_flush(uint8_t idx) {
|
|||||||
bool tud_vendor_n_read_xfer(uint8_t idx) {
|
bool tud_vendor_n_read_xfer(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_read_xfer(&p_itf->stream.rx);
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
return tu_edpt_stream_read_xfer(&p_itf->rx_stream);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Non-FIFO mode
|
||||||
|
TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_out));
|
||||||
|
return usbd_edpt_xfer(p_itf->rhport, p_itf->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@ -145,26 +153,45 @@ bool tud_vendor_n_read_xfer(uint8_t idx) {
|
|||||||
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) {
|
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_write(&p_itf->stream.tx, buffer, (uint16_t)bufsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
uint32_t tud_vendor_n_write_flush(uint8_t idx) {
|
return tu_edpt_stream_write(&p_itf->tx_stream, buffer, (uint16_t)bufsize);
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
#else
|
||||||
return tu_edpt_stream_write_xfer(&p_itf->stream.tx);
|
// non-fifo mode: direct transfer
|
||||||
|
TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_in), 0);
|
||||||
|
const uint32_t xact_len = tu_min32(bufsize, CFG_TUD_VENDOR_EPSIZE);
|
||||||
|
memcpy(_vendord_epbuf[idx].epin, buffer, xact_len);
|
||||||
|
TU_ASSERT(usbd_edpt_xfer(p_itf->rhport, p_itf->ep_in, _vendord_epbuf[idx].epin, (uint16_t)xact_len, false), 0);
|
||||||
|
return xact_len;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tud_vendor_n_write_available(uint8_t idx) {
|
uint32_t tud_vendor_n_write_available(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
return tu_edpt_stream_write_available(&p_itf->stream.tx);
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
return tu_edpt_stream_write_available(&p_itf->tx_stream);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Non-FIFO mode
|
||||||
|
TU_VERIFY(p_itf->ep_in > 0, 0); // must be opened
|
||||||
|
return usbd_edpt_busy(p_itf->rhport, p_itf->ep_in) ? 0 : CFG_TUD_VENDOR_EPSIZE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
uint32_t tud_vendor_n_write_flush(uint8_t idx) {
|
||||||
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
|
return tu_edpt_stream_write_xfer(&p_itf->tx_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tud_vendor_n_write_clear(uint8_t idx) {
|
bool tud_vendor_n_write_clear(uint8_t idx) {
|
||||||
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
|
||||||
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
vendord_interface_t *p_itf = &_vendord_itf[idx];
|
||||||
tu_edpt_stream_clear(&p_itf->stream.tx);
|
tu_edpt_stream_clear(&p_itf->tx_stream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -175,48 +202,37 @@ bool tud_vendor_n_write_clear(uint8_t idx) {
|
|||||||
void vendord_init(void) {
|
void vendord_init(void) {
|
||||||
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
|
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
|
||||||
|
|
||||||
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
|
||||||
|
vendord_interface_t *p_itf = &_vendord_itf[i];
|
||||||
|
|
||||||
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
|
#if CFG_TUD_EDPT_DEDICATED_HWFIFO
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0 // non-fifo rx still need ep buffer
|
|
||||||
uint8_t *epout_buf = _vendord_epbuf[i].epout;
|
|
||||||
#else
|
|
||||||
uint8_t *epout_buf = NULL;
|
uint8_t *epout_buf = NULL;
|
||||||
#endif
|
uint8_t *epin_buf = NULL;
|
||||||
|
#else
|
||||||
uint8_t *epin_buf = NULL;
|
|
||||||
#else
|
|
||||||
uint8_t *epout_buf = _vendord_epbuf[i].epout;
|
uint8_t *epout_buf = _vendord_epbuf[i].epout;
|
||||||
uint8_t *epin_buf = _vendord_epbuf[i].epin;
|
uint8_t *epin_buf = _vendord_epbuf[i].epin;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
uint8_t *rx_ff_buf = p_itf->rx_ff_buf;
|
||||||
uint8_t *rx_ff_buf = p_itf->stream.rx_ff_buf;
|
tu_edpt_stream_init(&p_itf->rx_stream, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
|
||||||
#else
|
|
||||||
uint8_t *rx_ff_buf = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tu_edpt_stream_init(&p_itf->stream.rx, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
|
|
||||||
CFG_TUD_VENDOR_EPSIZE);
|
CFG_TUD_VENDOR_EPSIZE);
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
uint8_t *tx_ff_buf = p_itf->tx_ff_buf;
|
||||||
uint8_t *tx_ff_buf = p_itf->stream.tx_ff_buf;
|
tu_edpt_stream_init(&p_itf->tx_stream, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
|
||||||
#else
|
|
||||||
uint8_t *tx_ff_buf = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tu_edpt_stream_init(&p_itf->stream.tx, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
|
|
||||||
CFG_TUD_VENDOR_EPSIZE);
|
CFG_TUD_VENDOR_EPSIZE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vendord_deinit(void) {
|
bool vendord_deinit(void) {
|
||||||
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
|
||||||
tu_edpt_stream_deinit(&p_itf->stream.rx);
|
vendord_interface_t *p_itf = &_vendord_itf[i];
|
||||||
tu_edpt_stream_deinit(&p_itf->stream.tx);
|
tu_edpt_stream_deinit(&p_itf->rx_stream);
|
||||||
|
tu_edpt_stream_deinit(&p_itf->tx_stream);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,11 +243,12 @@ void vendord_reset(uint8_t rhport) {
|
|||||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
vendord_interface_t* p_itf = &_vendord_itf[i];
|
||||||
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
|
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
|
||||||
|
|
||||||
tu_edpt_stream_clear(&p_itf->stream.rx);
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
tu_edpt_stream_close(&p_itf->stream.rx);
|
tu_edpt_stream_clear(&p_itf->rx_stream);
|
||||||
|
tu_edpt_stream_close(&p_itf->rx_stream);
|
||||||
tu_edpt_stream_clear(&p_itf->stream.tx);
|
tu_edpt_stream_clear(&p_itf->tx_stream);
|
||||||
tu_edpt_stream_close(&p_itf->stream.tx);
|
tu_edpt_stream_close(&p_itf->tx_stream);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,13 +258,25 @@ static uint8_t find_vendor_itf(uint8_t ep_addr) {
|
|||||||
const vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
const vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
||||||
if (ep_addr == 0) {
|
if (ep_addr == 0) {
|
||||||
// find unused: require both ep == 0
|
// find unused: require both ep == 0
|
||||||
if (p_vendor->stream.rx.ep_addr == 0 && p_vendor->stream.tx.ep_addr == 0) {
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
if (p_vendor->rx_stream.ep_addr == 0 && p_vendor->tx_stream.ep_addr == 0) {
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
} else if (ep_addr == p_vendor->stream.rx.ep_addr || ep_addr == p_vendor->stream.tx.ep_addr) {
|
#else
|
||||||
return idx;
|
if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// nothing to do
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
if (ep_addr == p_vendor->rx_stream.ep_addr || ep_addr == p_vendor->tx_stream.ep_addr) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (ep_addr == p_vendor->ep_out || ep_addr == p_vendor->ep_in) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0xff;
|
return 0xff;
|
||||||
@ -273,28 +302,39 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uin
|
|||||||
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
|
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
|
||||||
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
|
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
|
||||||
|
|
||||||
// open endpoint stream, skip if already opened (multiple IN/OUT endpoints)
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
// open endpoint stream
|
||||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
|
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
|
||||||
tu_edpt_stream_t *stream_tx = &p_vendor->stream.tx;
|
tu_edpt_stream_t *tx_stream = &p_vendor->tx_stream;
|
||||||
if (stream_tx->ep_addr == 0) {
|
tu_edpt_stream_open(tx_stream, rhport, desc_ep);
|
||||||
tu_edpt_stream_open(stream_tx, rhport, desc_ep);
|
tu_edpt_stream_write_xfer(tx_stream); // flush pending data
|
||||||
tu_edpt_stream_write_xfer(stream_tx); // flush pending data
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tu_edpt_stream_t *stream_rx = &p_vendor->stream.rx;
|
tu_edpt_stream_t *rx_stream = &p_vendor->rx_stream;
|
||||||
if (stream_rx->ep_addr == 0) {
|
tu_edpt_stream_open(rx_stream, rhport, desc_ep);
|
||||||
tu_edpt_stream_open(stream_rx, rhport, desc_ep);
|
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
TU_ASSERT(tu_edpt_stream_read_xfer(rx_stream) > 0, 0); // prepare for incoming data
|
||||||
TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
|
#endif
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// Non-FIFO mode: store endpoint info
|
||||||
|
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
|
||||||
|
p_vendor->ep_in = desc_ep->bEndpointAddress;
|
||||||
|
p_vendor->ep_in_mps = tu_edpt_packet_size(desc_ep);
|
||||||
|
} else {
|
||||||
|
p_vendor->ep_out = desc_ep->bEndpointAddress;
|
||||||
|
p_vendor->ep_out_mps = tu_edpt_packet_size(desc_ep);
|
||||||
|
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||||
|
// Prepare for incoming data
|
||||||
|
TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false), 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
p_desc = tu_desc_next(p_desc);
|
p_desc = tu_desc_next(p_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf);
|
return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||||
@ -304,34 +344,36 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||||||
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
TU_VERIFY(idx < CFG_TUD_VENDOR);
|
||||||
vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
vendord_interface_t *p_vendor = &_vendord_itf[idx];
|
||||||
|
|
||||||
if (ep_addr == p_vendor->stream.rx.ep_addr) {
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE
|
if (ep_addr == p_vendor->rx_stream.ep_addr) {
|
||||||
// Received new data: put into stream's fifo
|
// Put received data to FIFO
|
||||||
tu_edpt_stream_read_xfer_complete(&p_vendor->stream.rx, xferred_bytes);
|
tu_edpt_stream_read_xfer_complete(&p_vendor->rx_stream, xferred_bytes);
|
||||||
#endif
|
|
||||||
|
|
||||||
// invoke callback
|
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE == 0
|
|
||||||
tud_vendor_rx_cb(idx, p_vendor->stream.rx.ep_buf, xferred_bytes);
|
|
||||||
#else
|
|
||||||
tud_vendor_rx_cb(idx, NULL, 0);
|
tud_vendor_rx_cb(idx, NULL, 0);
|
||||||
#endif
|
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||||
|
tu_edpt_stream_read_xfer(&p_vendor->rx_stream); // prepare next data
|
||||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
#endif
|
||||||
tu_edpt_stream_read_xfer(&p_vendor->stream.rx); // prepare next data
|
} else if (ep_addr == p_vendor->tx_stream.ep_addr) {
|
||||||
#endif
|
|
||||||
} else if (ep_addr == p_vendor->stream.tx.ep_addr) {
|
|
||||||
// Send complete
|
// Send complete
|
||||||
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
|
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
|
||||||
// try to send more if possible
|
// try to send more if possible
|
||||||
if (0 == tu_edpt_stream_write_xfer(&p_vendor->stream.tx)) {
|
if (0 == tu_edpt_stream_write_xfer(&p_vendor->tx_stream)) {
|
||||||
// If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero
|
// If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero
|
||||||
tu_edpt_stream_write_zlp_if_needed(&p_vendor->stream.tx, xferred_bytes);
|
tu_edpt_stream_write_zlp_if_needed(&p_vendor->tx_stream, xferred_bytes);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (ep_addr == p_vendor->ep_out) {
|
||||||
|
// Non-FIFO mode: invoke callback with buffer
|
||||||
|
tud_vendor_rx_cb(idx, _vendord_epbuf[idx].epout, xferred_bytes);
|
||||||
|
#if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
|
||||||
|
usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
|
||||||
|
#endif
|
||||||
|
} else if (ep_addr == p_vendor->ep_in) {
|
||||||
|
// Send complete
|
||||||
|
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/class/vendor/vendor_device.h
vendored
44
src/class/vendor/vendor_device.h
vendored
@ -50,8 +50,14 @@ extern "C" {
|
|||||||
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
|
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Vendor is buffered (FIFO mode) if both TX and RX buffers are configured
|
||||||
|
// If either is 0, vendor operates in non-buffered (direct transfer) mode
|
||||||
|
#ifndef CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
|
#define CFG_TUD_VENDOR_TXRX_BUFFERED ((CFG_TUD_VENDOR_RX_BUFSIZE > 0) && (CFG_TUD_VENDOR_TX_BUFSIZE > 0))
|
||||||
|
#endif
|
||||||
|
|
||||||
// Application will manually schedule RX transfer. This can be useful when using with non-fifo (buffered) mode
|
// Application will manually schedule RX transfer. This can be useful when using with non-fifo (buffered) mode
|
||||||
// i.e. CFG_TUD_VENDOR_RX_BUFSIZE = 0
|
// i.e. CFG_TUD_VENDOR_TXRX_BUFFERED = 0
|
||||||
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
|
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
|
||||||
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
|
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
|
||||||
#endif
|
#endif
|
||||||
@ -63,7 +69,8 @@ extern "C" {
|
|||||||
// Return whether the vendor interface is mounted
|
// Return whether the vendor interface is mounted
|
||||||
bool tud_vendor_n_mounted(uint8_t idx);
|
bool tud_vendor_n_mounted(uint8_t idx);
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
//------------- RX -------------//
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
// Return number of available bytes for reading
|
// Return number of available bytes for reading
|
||||||
uint32_t tud_vendor_n_available(uint8_t idx);
|
uint32_t tud_vendor_n_available(uint8_t idx);
|
||||||
|
|
||||||
@ -82,16 +89,17 @@ void tud_vendor_n_read_flush(uint8_t idx);
|
|||||||
bool tud_vendor_n_read_xfer(uint8_t idx);
|
bool tud_vendor_n_read_xfer(uint8_t idx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//------------- TX -------------//
|
||||||
// Write to TX FIFO. This can be buffered and not sent immediately unless buffered bytes >= USB endpoint size
|
// Write to TX FIFO. This can be buffered and not sent immediately unless buffered bytes >= USB endpoint size
|
||||||
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize);
|
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize);
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
// Return number of bytes available for writing in TX FIFO (or endpoint if non-buffered)
|
||||||
|
uint32_t tud_vendor_n_write_available(uint8_t idx);
|
||||||
|
|
||||||
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
// Force sending buffered data, return number of bytes sent
|
// Force sending buffered data, return number of bytes sent
|
||||||
uint32_t tud_vendor_n_write_flush(uint8_t idx);
|
uint32_t tud_vendor_n_write_flush(uint8_t idx);
|
||||||
|
|
||||||
// Return number of bytes available for writing in TX FIFO
|
|
||||||
uint32_t tud_vendor_n_write_available(uint8_t idx);
|
|
||||||
|
|
||||||
// Clear the transmit FIFO
|
// Clear the transmit FIFO
|
||||||
bool tud_vendor_n_write_clear(uint8_t idx);
|
bool tud_vendor_n_write_clear(uint8_t idx);
|
||||||
#endif
|
#endif
|
||||||
@ -111,7 +119,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) {
|
|||||||
return tud_vendor_n_mounted(0);
|
return tud_vendor_n_mounted(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
#if CFG_TUD_VENDOR_TXRX_BUFFERED
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) {
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) {
|
||||||
return tud_vendor_n_available(0);
|
return tud_vendor_n_available(0);
|
||||||
}
|
}
|
||||||
@ -127,6 +135,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void *buffer, uint3
|
|||||||
TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) {
|
TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) {
|
||||||
tud_vendor_n_read_flush(0);
|
tud_vendor_n_read_flush(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
|
||||||
|
return tud_vendor_n_write_flush(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
||||||
|
return tud_vendor_n_write_clear(0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
|
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
|
||||||
@ -143,20 +159,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(const char *st
|
|||||||
return tud_vendor_n_write_str(0, str);
|
return tud_vendor_n_write_str(0, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
|
|
||||||
return tud_vendor_n_write_flush(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
|
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
|
||||||
return tud_vendor_n_write_available(0);
|
return tud_vendor_n_write_available(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
|
||||||
return tud_vendor_n_write_clear(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// backward compatible
|
// backward compatible
|
||||||
#define tud_vendor_flush() tud_vendor_write_flush()
|
#define tud_vendor_flush() tud_vendor_write_flush()
|
||||||
|
|
||||||
@ -165,8 +171,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
// Invoked when received new data.
|
// Invoked when received new data.
|
||||||
// - CFG_TUD_VENDOR_RX_BUFSIZE > 0; buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
|
// - CFG_TUD_VENDOR_TXRX_BUFFERED = 1: buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
|
||||||
// - CFG_TUD_VENDOR_RX_BUFSIZE = 0: Buffer and bufsize are valid
|
// - CFG_TUD_VENDOR_TXRX_BUFFERED = 0: Buffer and bufsize are valid
|
||||||
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
|
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
|
||||||
|
|
||||||
// Invoked when tx transfer is finished
|
// Invoked when tx transfer is finished
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
// Suppress IAR warning
|
// Suppress IAR warning
|
||||||
// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
|
// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
|
||||||
#if defined(__ICCARM__)
|
#if defined(__ICCARM__)
|
||||||
#pragma diag_suppress = Pa082
|
#pragma diag_suppress = Pa082
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OSAL_MUTEX_REQUIRED
|
#if OSAL_MUTEX_REQUIRED
|
||||||
@ -110,8 +110,9 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Pull & Push
|
// Hardware FIFO API
|
||||||
// copy data to/from fifo without updating read/write pointers
|
// Support different data access width and address increment scheme
|
||||||
|
// Can support multiple i.e both 16 and 32-bit data access if needed
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_API
|
#if CFG_TUSB_FIFO_HWFIFO_API
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
|
#if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
|
||||||
@ -122,18 +123,31 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
|
|||||||
|
|
||||||
#define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
|
#define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
|
||||||
|
|
||||||
|
//------------- Write -------------//
|
||||||
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
|
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
|
||||||
static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
|
TU_ATTR_ALWAYS_INLINE static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
|
||||||
|
(void)data_stride; // possible unused
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
|
||||||
if (data_stride == 4) {
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
|
||||||
|
if (data_stride == 4)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
*((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
|
*((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
|
|
||||||
if (data_stride == 2) {
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
|
||||||
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
|
||||||
|
if (data_stride == 2)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
*((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
|
*((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
|
||||||
|
*((volatile uint8_t *)hwfifo) = *(const uint8_t *)src;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
|
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
|
||||||
@ -147,7 +161,8 @@ void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, co
|
|||||||
HWFIFO_ADDR_NEXT(hwfifo, );
|
HWFIFO_ADDR_NEXT(hwfifo, );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
|
||||||
|
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
|
||||||
// 16-bit access is allowed for odd bytes
|
// 16-bit access is allowed for odd bytes
|
||||||
if (len >= 2) {
|
if (len >= 2) {
|
||||||
*((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
|
*((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
|
||||||
@ -155,16 +170,16 @@ void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, co
|
|||||||
len -= 2;
|
len -= 2;
|
||||||
HWFIFO_ADDR_NEXT_N(hwfifo, , 2);
|
HWFIFO_ADDR_NEXT_N(hwfifo, , 2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
|
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
|
||||||
// 8-bit access is allowed for odd bytes
|
// 8-bit access is allowed for odd bytes
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
*((volatile uint8_t *)hwfifo) = *src++;
|
*((volatile uint8_t *)hwfifo) = *src++;
|
||||||
len--;
|
len--;
|
||||||
HWFIFO_ADDR_NEXT_N(hwfifo, , 1);
|
HWFIFO_ADDR_NEXT_N(hwfifo, , 1);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
|
// Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
@ -173,13 +188,16 @@ void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, co
|
|||||||
stride_write(hwfifo, &tmp, data_stride);
|
stride_write(hwfifo, &tmp, data_stride);
|
||||||
HWFIFO_ADDR_NEXT(hwfifo, );
|
HWFIFO_ADDR_NEXT(hwfifo, );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//------------- Read -------------//
|
||||||
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
|
#ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
|
||||||
static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) {
|
TU_ATTR_ALWAYS_INLINE static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) {
|
||||||
(void)data_stride; // possible unused
|
(void)data_stride; // possible unused
|
||||||
|
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
|
||||||
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
|
||||||
if (data_stride == 4)
|
if (data_stride == 4)
|
||||||
@ -197,6 +215,10 @@ static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t
|
|||||||
tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
|
tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
|
||||||
|
*(uint8_t *)dest = *((const volatile uint8_t *)hwfifo);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
|
void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
|
||||||
@ -209,7 +231,8 @@ void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, co
|
|||||||
HWFIFO_ADDR_NEXT(hwfifo, const);
|
HWFIFO_ADDR_NEXT(hwfifo, const);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
|
||||||
|
#ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
|
||||||
// 16-bit access is allowed for odd bytes
|
// 16-bit access is allowed for odd bytes
|
||||||
if (len >= 2) {
|
if (len >= 2) {
|
||||||
tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
|
tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
|
||||||
@ -235,6 +258,7 @@ void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, co
|
|||||||
HWFIFO_ADDR_NEXT(hwfifo, const);
|
HWFIFO_ADDR_NEXT(hwfifo, const);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -251,7 +275,11 @@ static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uin
|
|||||||
tu_hwfifo_read(hwfifo, ff_buf, n, access_mode);
|
tu_hwfifo_read(hwfifo, ff_buf, n, access_mode);
|
||||||
} else {
|
} else {
|
||||||
// Wrap around case
|
// Wrap around case
|
||||||
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
|
||||||
|
tu_hwfifo_read(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
|
||||||
|
HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_bytes);
|
||||||
|
tu_hwfifo_read(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
|
||||||
|
#else
|
||||||
// Write full words to linear part of buffer
|
// Write full words to linear part of buffer
|
||||||
const uint8_t data_stride = access_mode->data_stride;
|
const uint8_t data_stride = access_mode->data_stride;
|
||||||
const uint32_t odd_mask = data_stride - 1;
|
const uint32_t odd_mask = data_stride - 1;
|
||||||
@ -286,6 +314,7 @@ static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uin
|
|||||||
if (wrap_bytes > 0) {
|
if (wrap_bytes > 0) {
|
||||||
tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
|
tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,11 +332,15 @@ static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t
|
|||||||
tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
|
tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
|
||||||
} else {
|
} else {
|
||||||
// Wrap around case
|
// Wrap around case
|
||||||
|
#if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
|
||||||
|
tu_hwfifo_write(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
|
||||||
|
HWFIFO_ADDR_NEXT_N(hwfifo, , lin_bytes);
|
||||||
|
tu_hwfifo_write(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
|
||||||
|
#else
|
||||||
// Read full words from linear part
|
// Read full words from linear part
|
||||||
const uint8_t data_stride = access_mode->data_stride;
|
const uint8_t data_stride = access_mode->data_stride;
|
||||||
const uint32_t odd_mask = data_stride - 1;
|
const uint32_t odd_mask = data_stride - 1;
|
||||||
uint16_t lin_even = lin_bytes & ~odd_mask;
|
uint16_t lin_even = lin_bytes & ~odd_mask;
|
||||||
tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
|
tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
|
||||||
HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even);
|
HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even);
|
||||||
ff_buf += lin_even;
|
ff_buf += lin_even;
|
||||||
@ -338,10 +371,15 @@ static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t
|
|||||||
if (wrap_bytes > 0) {
|
if (wrap_bytes > 0) {
|
||||||
tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode);
|
tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Pull & Push
|
||||||
|
// copy data to/from fifo without updating read/write pointers
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
// send n items to fifo WITHOUT updating write pointer
|
// send n items to fifo WITHOUT updating write pointer
|
||||||
static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
|
static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
|
||||||
uint16_t lin_bytes = f->depth - wr_ptr;
|
uint16_t lin_bytes = f->depth - wr_ptr;
|
||||||
@ -787,6 +825,6 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) {
|
|||||||
} else {
|
} else {
|
||||||
info->linear.len = f->depth - wr_ptr;
|
info->linear.len = f->depth - wr_ptr;
|
||||||
info->wrapped.len = remain - info->linear.len; // Remaining length - n already was limited to remain or FIFO depth
|
info->wrapped.len = remain - info->linear.len; // Remaining length - n already was limited to remain or FIFO depth
|
||||||
info->wrapped.ptr = f->buffer; // Always start of buffer
|
info->wrapped.ptr = f->buffer; // Always start of buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,14 +37,6 @@
|
|||||||
// Configuration
|
// Configuration
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
#if CFG_TUD_ENABLED && CFG_TUD_VENDOR && (CFG_TUD_VENDOR_TX_BUFSIZE == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0)
|
|
||||||
#define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
|
||||||
#define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TUP_USBIP_CONTROLLER_NUM 2
|
#define TUP_USBIP_CONTROLLER_NUM 2
|
||||||
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
|
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
|
||||||
|
|
||||||
|
|||||||
@ -554,7 +554,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) {
|
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) {
|
||||||
return (uint8_t) (num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0u));
|
return (uint8_t) (num | (dir == (uint8_t)TUSB_DIR_IN ? (uint8_t)TUSB_DIR_IN_MASK : 0u));
|
||||||
}
|
}
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) {
|
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) {
|
||||||
|
|||||||
@ -74,7 +74,6 @@ static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPa
|
|||||||
ep->ep_addr = ep_addr;
|
ep->ep_addr = ep_addr;
|
||||||
ep->next_pid = 0u;
|
ep->next_pid = 0u;
|
||||||
ep->wMaxPacketSize = wMaxPacketSize;
|
ep->wMaxPacketSize = wMaxPacketSize;
|
||||||
ep->transfer_type = transfer_type;
|
|
||||||
|
|
||||||
// Clear existing buffer control state
|
// Clear existing buffer control state
|
||||||
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
|
||||||
@ -502,7 +501,15 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
|
|||||||
(void)rhport;
|
(void)rhport;
|
||||||
(void)is_isr;
|
(void)is_isr;
|
||||||
hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
|
hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
hw_endpoint_xfer_start(ep, buffer, total_bytes);
|
hw_endpoint_xfer_start(ep, buffer, NULL, total_bytes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
|
||||||
|
(void)rhport;
|
||||||
|
(void)is_isr;
|
||||||
|
hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
|
hw_endpoint_xfer_start(ep, NULL, ff, total_bytes);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -511,7 +511,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
|||||||
// sie ctrl registers. Otherwise, interrupt ep registers should
|
// sie ctrl registers. Otherwise, interrupt ep registers should
|
||||||
// already be configured
|
// already be configured
|
||||||
if (ep == &epx) {
|
if (ep == &epx) {
|
||||||
hw_endpoint_xfer_start(ep, buffer, buflen);
|
hw_endpoint_xfer_start(ep, buffer, NULL, buflen);
|
||||||
|
|
||||||
// That has set up buffer control, endpoint control etc
|
// That has set up buffer control, endpoint control etc
|
||||||
// for host we have to initiate the transfer
|
// for host we have to initiate the transfer
|
||||||
@ -527,7 +527,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
|||||||
busy_wait_at_least_cycles(12);
|
busy_wait_at_least_cycles(12);
|
||||||
usb_hw->sie_ctrl = flags;
|
usb_hw->sie_ctrl = flags;
|
||||||
} else {
|
} else {
|
||||||
hw_endpoint_xfer_start(ep, buffer, buflen);
|
hw_endpoint_xfer_start(ep, buffer, NULL, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF PROTOTYPE
|
// MACRO CONSTANT TYPEDEF PROTOTYPE
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
static void hwep_xfer_sync(hw_endpoint_t *ep);
|
static void sync_xfer(hw_endpoint_t *ep);
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
|
static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
|
||||||
@ -47,14 +47,22 @@ static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
|
|||||||
// Implementation
|
// Implementation
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Provide own byte by byte memcpy as not all copies are aligned
|
// Provide own byte by byte memcpy as not all copies are aligned
|
||||||
static void unaligned_memcpy(void *dst, const void *src, size_t n) {
|
static void unaligned_memcpy(uint8_t *dst, const uint8_t *src, size_t n) {
|
||||||
uint8_t *dst_byte = (uint8_t*)dst;
|
|
||||||
const uint8_t *src_byte = (const uint8_t*)src;
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
*dst_byte++ = *src_byte++;
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
|
||||||
|
(void)access_mode;
|
||||||
|
unaligned_memcpy((uint8_t *)(uintptr_t)hwfifo, src, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
|
||||||
|
(void)access_mode;
|
||||||
|
unaligned_memcpy(dest, (const uint8_t *)(uintptr_t)hwfifo, len);
|
||||||
|
}
|
||||||
|
|
||||||
void rp2usb_init(void) {
|
void rp2usb_init(void) {
|
||||||
// Reset usb controller
|
// Reset usb controller
|
||||||
reset_block(RESETS_RESET_USBCTRL_BITS);
|
reset_block(RESETS_RESET_USBCTRL_BITS);
|
||||||
@ -127,9 +135,17 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep,
|
|||||||
ep->next_pid ^= 1u;
|
ep->next_pid ^= 1u;
|
||||||
|
|
||||||
if (!is_rx) {
|
if (!is_rx) {
|
||||||
// Copy data from user buffer to hw buffer
|
if (buflen) {
|
||||||
unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
|
// Copy data from user buffer/fifo to hw buffer
|
||||||
ep->user_buf += buflen;
|
uint8_t *hw_buf = ep->hw_data_buf + buf_id * 64;
|
||||||
|
if (ep->is_xfer_fifo) {
|
||||||
|
// not in sram, may mess up timing with E15 workaround
|
||||||
|
tu_hwfifo_write_from_fifo(hw_buf, ep->user_fifo, buflen, NULL);
|
||||||
|
} else {
|
||||||
|
unaligned_memcpy(hw_buf, ep->user_buf, buflen);
|
||||||
|
ep->user_buf += buflen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mark as full
|
// Mark as full
|
||||||
buf_ctrl |= USB_BUF_CTRL_FULL;
|
buf_ctrl |= USB_BUF_CTRL_FULL;
|
||||||
@ -152,7 +168,6 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep,
|
|||||||
// Prepare buffer control register value
|
// Prepare buffer control register value
|
||||||
void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
|
void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
|
||||||
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
||||||
|
|
||||||
bool is_rx;
|
bool is_rx;
|
||||||
bool is_host = false;
|
bool is_host = false;
|
||||||
io_rw_32 *ep_ctrl_reg;
|
io_rw_32 *ep_ctrl_reg;
|
||||||
@ -211,7 +226,7 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep)
|
|||||||
hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
|
hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
|
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len) {
|
||||||
hw_endpoint_lock_update(ep, 1);
|
hw_endpoint_lock_update(ep, 1);
|
||||||
|
|
||||||
if (ep->active) {
|
if (ep->active) {
|
||||||
@ -224,7 +239,14 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to
|
|||||||
ep->remaining_len = total_len;
|
ep->remaining_len = total_len;
|
||||||
ep->xferred_len = 0;
|
ep->xferred_len = 0;
|
||||||
ep->active = true;
|
ep->active = true;
|
||||||
ep->user_buf = buffer;
|
|
||||||
|
if (ff != NULL) {
|
||||||
|
ep->user_fifo = ff;
|
||||||
|
ep->is_xfer_fifo = true;
|
||||||
|
} else {
|
||||||
|
ep->user_buf = buffer;
|
||||||
|
ep->is_xfer_fifo = false;
|
||||||
|
}
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
if (ep->e15_bulk_in) {
|
if (ep->e15_bulk_in) {
|
||||||
@ -256,17 +278,21 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(hw_endpoint_t *ep, io_rw_32
|
|||||||
// We are continuing a transfer here. If we are TX, we have successfully
|
// We are continuing a transfer here. If we are TX, we have successfully
|
||||||
// sent some data can increase the length we have sent
|
// sent some data can increase the length we have sent
|
||||||
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
|
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
|
||||||
|
|
||||||
ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
|
|
||||||
} else {
|
} else {
|
||||||
// If we have received some data, so can increase the length
|
// If we have received some data, so can increase the length
|
||||||
// we have received AFTER we have copied it to the user buffer at the appropriate offset
|
// we have received AFTER we have copied it to the user buffer at the appropriate offset
|
||||||
assert(buf_ctrl & USB_BUF_CTRL_FULL);
|
assert(buf_ctrl & USB_BUF_CTRL_FULL);
|
||||||
|
|
||||||
unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
|
uint8_t *hw_buf = ep->hw_data_buf + buf_id * 64;
|
||||||
ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
|
if (ep->is_xfer_fifo) {
|
||||||
ep->user_buf += xferred_bytes;
|
// not in sram, may mess up timing with E15 workaround
|
||||||
|
tu_hwfifo_read_to_fifo(hw_buf, ep->user_fifo, xferred_bytes, NULL);
|
||||||
|
} else {
|
||||||
|
unaligned_memcpy(ep->user_buf, hw_buf, xferred_bytes);
|
||||||
|
ep->user_buf += xferred_bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ep->xferred_len += xferred_bytes;
|
||||||
|
|
||||||
// Short packet
|
// Short packet
|
||||||
if (xferred_bytes < ep->wMaxPacketSize) {
|
if (xferred_bytes < ep->wMaxPacketSize) {
|
||||||
@ -278,7 +304,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(hw_endpoint_t *ep, io_rw_32
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update hw endpoint struct with info from hardware after a buff status interrupt
|
// Update hw endpoint struct with info from hardware after a buff status interrupt
|
||||||
static void __tusb_irq_path_func(hwep_xfer_sync)(hw_endpoint_t *ep) {
|
static void __tusb_irq_path_func(sync_xfer)(hw_endpoint_t *ep) {
|
||||||
// const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
|
// const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
|
||||||
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
|
||||||
|
|
||||||
@ -350,8 +376,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
|
|||||||
panic("Can't continue xfer on inactive ep %02X", ep->ep_addr);
|
panic("Can't continue xfer on inactive ep %02X", ep->ep_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update EP struct from hardware state
|
sync_xfer(ep); // Update EP struct from hardware state
|
||||||
hwep_xfer_sync(ep);
|
|
||||||
|
|
||||||
// Now we have synced our state with the hardware. Is there more data to transfer?
|
// Now we have synced our state with the hardware. Is there more data to transfer?
|
||||||
// If we are done then notify tinyusb
|
// If we are done then notify tinyusb
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
#ifndef RP2040_COMMON_H_
|
#ifndef RP2040_COMMON_H_
|
||||||
#define RP2040_COMMON_H_
|
#define RP2040_COMMON_H_
|
||||||
|
|
||||||
#include "common/tusb_common.h"
|
|
||||||
|
|
||||||
#include "pico.h"
|
#include "pico.h"
|
||||||
#include "hardware/structs/usb.h"
|
#include "hardware/structs/usb.h"
|
||||||
#include "hardware/irq.h"
|
#include "hardware/irq.h"
|
||||||
#include "hardware/resets.h"
|
#include "hardware/resets.h"
|
||||||
#include "hardware/timer.h"
|
#include "hardware/timer.h"
|
||||||
|
|
||||||
|
#include "common/tusb_common.h"
|
||||||
|
#include "osal/osal.h"
|
||||||
|
#include "common/tusb_fifo.h"
|
||||||
|
|
||||||
#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
|
#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
|
||||||
#error TinyUSB device and host mode not supported at the same time
|
#error TinyUSB device and host mode not supported at the same time
|
||||||
#endif
|
#endif
|
||||||
@ -62,33 +64,31 @@
|
|||||||
typedef struct hw_endpoint {
|
typedef struct hw_endpoint {
|
||||||
uint8_t ep_addr;
|
uint8_t ep_addr;
|
||||||
uint8_t next_pid;
|
uint8_t next_pid;
|
||||||
uint8_t transfer_type;
|
bool active; // transferring data
|
||||||
|
bool is_xfer_fifo; // transfer using fifo
|
||||||
bool active; // transferring data
|
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
bool e15_bulk_in; // Errata15 device bulk in
|
bool e15_bulk_in; // Errata15 device bulk in
|
||||||
uint8_t pending; // Transfer scheduled but not active
|
uint8_t pending; // Transfer scheduled but not active
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUH_ENABLED
|
||||||
|
bool configured; // Is this a valid struct
|
||||||
|
uint8_t dev_addr;
|
||||||
|
uint8_t interrupt_num; // for host interrupt endpoints
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16_t wMaxPacketSize;
|
uint16_t wMaxPacketSize;
|
||||||
uint8_t *hw_data_buf; // Buffer pointer in usb dpram
|
uint8_t *hw_data_buf; // Buffer pointer in usb dpram
|
||||||
|
|
||||||
// Current transfer information
|
// transfer info
|
||||||
uint8_t *user_buf; // User buffer in main memory
|
union {
|
||||||
|
uint8_t *user_buf; // User buffer in main memory
|
||||||
|
tu_fifo_t *user_fifo;
|
||||||
|
};
|
||||||
uint16_t remaining_len;
|
uint16_t remaining_len;
|
||||||
uint16_t xferred_len;
|
uint16_t xferred_len;
|
||||||
|
|
||||||
#if CFG_TUH_ENABLED
|
|
||||||
// Is this a valid struct
|
|
||||||
bool configured;
|
|
||||||
|
|
||||||
// Only needed for host
|
|
||||||
uint8_t dev_addr;
|
|
||||||
|
|
||||||
// If interrupt endpoint
|
|
||||||
uint8_t interrupt_num;
|
|
||||||
#endif
|
|
||||||
} hw_endpoint_t;
|
} hw_endpoint_t;
|
||||||
|
|
||||||
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||||
@ -102,7 +102,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) {
|
|||||||
return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
|
return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
|
void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len);
|
||||||
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
|
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
|
||||||
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
|
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
|
||||||
void hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
|
void hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
|
||||||
|
|||||||
99
src/tusb.c
99
src/tusb.c
@ -309,11 +309,9 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove
|
|||||||
uint16_t ff_bufsize, uint8_t *ep_buf, uint16_t ep_bufsize) {
|
uint16_t ff_bufsize, uint8_t *ep_buf, uint16_t ep_bufsize) {
|
||||||
(void) is_tx;
|
(void) is_tx;
|
||||||
|
|
||||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED == 0 // FIFO is required
|
|
||||||
if (ff_buf == NULL || ff_bufsize == 0) {
|
if (ff_buf == NULL || ff_bufsize == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
s->is_host = is_host;
|
s->is_host = is_host;
|
||||||
tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
|
tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
|
||||||
@ -411,90 +409,45 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tu_edpt_stream_write(tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize) {
|
uint32_t tu_edpt_stream_write(tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize) {
|
||||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
TU_VERIFY(bufsize > 0);
|
||||||
if (0 == tu_fifo_depth(&s->ff)) {
|
const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
|
||||||
// non-fifo mode: TX need ep buffer
|
|
||||||
TU_VERIFY(s->ep_buf != NULL, 0);
|
|
||||||
TU_VERIFY(stream_claim(s), 0);
|
|
||||||
uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize);
|
|
||||||
memcpy(s->ep_buf, buffer, xact_len);
|
|
||||||
TU_ASSERT(stream_xfer(s, (uint16_t) xact_len), 0);
|
|
||||||
return xact_len;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
TU_VERIFY(bufsize > 0);
|
|
||||||
const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
|
|
||||||
|
|
||||||
// flush if fifo has more than packet size or
|
// flush if fifo has more than packet size or
|
||||||
// in rare case: fifo depth is configured too small (which never reach packet size)
|
// in rare case: fifo depth is configured too small (which never reach packet size)
|
||||||
if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
|
if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
|
||||||
tu_edpt_stream_write_xfer(s);
|
tu_edpt_stream_write_xfer(s);
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t *s) {
|
uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t *s) {
|
||||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
return (uint32_t)tu_fifo_remaining(&s->ff);
|
||||||
if (0 == tu_fifo_depth(&s->ff)) {
|
|
||||||
// non-fifo mode
|
|
||||||
TU_VERIFY(s->ep_addr > 0); // must be opened
|
|
||||||
bool is_busy = true;
|
|
||||||
if (s->is_host) {
|
|
||||||
#if CFG_TUH_ENABLED
|
|
||||||
is_busy = usbh_edpt_busy(s->hwid, s->ep_addr);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#if CFG_TUD_ENABLED
|
|
||||||
is_busy = usbd_edpt_busy(s->hwid, s->ep_addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return is_busy ? 0 : s->ep_bufsize;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
return (uint32_t)tu_fifo_remaining(&s->ff);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Stream Read
|
// Stream Read
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t *s) {
|
uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t *s) {
|
||||||
#if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
|
uint16_t available = tu_fifo_remaining(&s->ff);
|
||||||
if (0 == tu_fifo_depth(&s->ff)) {
|
|
||||||
// non-fifo mode: RX need ep buffer
|
|
||||||
TU_VERIFY(s->ep_buf != NULL, 0);
|
|
||||||
TU_VERIFY(stream_claim(s), 0);
|
|
||||||
TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0);
|
|
||||||
return s->ep_bufsize;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
uint16_t available = tu_fifo_remaining(&s->ff);
|
|
||||||
|
|
||||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||||
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
||||||
// and slowly move it to the FIFO when read().
|
// and slowly move it to the FIFO when read().
|
||||||
// This pre-check reduces endpoint claiming
|
// This pre-check reduces endpoint claiming
|
||||||
TU_VERIFY(available >= s->mps);
|
TU_VERIFY(available >= s->mps);
|
||||||
TU_VERIFY(stream_claim(s), 0);
|
TU_VERIFY(stream_claim(s), 0);
|
||||||
available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
|
available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
|
||||||
|
|
||||||
if (available >= s->mps) {
|
if (available >= s->mps) {
|
||||||
// multiple of packet size limit by ep bufsize
|
// multiple of packet size limit by ep bufsize
|
||||||
uint16_t count = (uint16_t) (available & ~(s->mps - 1));
|
uint16_t count = (uint16_t) (available & ~(s->mps - 1));
|
||||||
if (s->ep_buf != NULL) {
|
count = tu_min16(count, s->ep_bufsize);
|
||||||
count = tu_min16(count, s->ep_bufsize);
|
TU_ASSERT(stream_xfer(s, count), 0);
|
||||||
}
|
return count;
|
||||||
TU_ASSERT(stream_xfer(s, count), 0);
|
} else {
|
||||||
return count;
|
// Release endpoint since we don't make any transfer
|
||||||
} else {
|
stream_release(s);
|
||||||
// Release endpoint since we don't make any transfer
|
return 0;
|
||||||
stream_release(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -272,6 +272,25 @@
|
|||||||
// USBIP
|
// USBIP
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
//------------- ChipIdea -------------//
|
||||||
|
// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is
|
||||||
|
// insufficient).
|
||||||
|
#ifndef CFG_TUD_CI_HS_VBUS_CHARGE
|
||||||
|
#ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
|
||||||
|
#define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0
|
||||||
|
#endif
|
||||||
|
#define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CI_HS support FIFO transfer if endpoint buffer is 4k aligned and size is multiple of 4k, also DCACHE is disabled
|
||||||
|
#ifndef CFG_TUD_CI_HS_EPBUF_4K_ALIGNED
|
||||||
|
#define CFG_TUD_CI_HS_EPBUF_4K_ALIGNED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUD_CI_HS_EPBUF_4K_ALIGNED && !CFG_TUD_MEM_DCACHE_ENABLE
|
||||||
|
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
//------------- DWC2 -------------//
|
//------------- DWC2 -------------//
|
||||||
// DMA mode for device
|
// DMA mode for device
|
||||||
#ifndef CFG_TUD_DWC2_DMA_ENABLE
|
#ifndef CFG_TUD_DWC2_DMA_ENABLE
|
||||||
@ -317,41 +336,6 @@
|
|||||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address
|
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------- ChipIdea -------------//
|
|
||||||
// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is
|
|
||||||
// insufficient).
|
|
||||||
#ifndef CFG_TUD_CI_HS_VBUS_CHARGE
|
|
||||||
#ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
|
|
||||||
#define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0
|
|
||||||
#endif
|
|
||||||
#define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// CI_HS support FIFO transfer if endpoint buffer is 4k aligned and size is multiple of 4k, also DCACHE is disabled
|
|
||||||
#ifndef CFG_TUD_CI_HS_EPBUF_4K_ALIGNED
|
|
||||||
#define CFG_TUD_CI_HS_EPBUF_4K_ALIGNED 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CFG_TUD_CI_HS_EPBUF_4K_ALIGNED && !CFG_TUD_MEM_DCACHE_ENABLE
|
|
||||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------- Raspberry Pi -------------//
|
|
||||||
// Enable PIO-USB software host controller
|
|
||||||
#ifndef CFG_TUH_RPI_PIO_USB
|
|
||||||
#define CFG_TUH_RPI_PIO_USB 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CFG_TUD_RPI_PIO_USB
|
|
||||||
#define CFG_TUD_RPI_PIO_USB 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------ MAX3421 -------------//
|
|
||||||
// Enable MAX3421 USB host controller
|
|
||||||
#ifndef CFG_TUH_MAX3421
|
|
||||||
#define CFG_TUH_MAX3421 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//------------ FSDEV --------------//
|
//------------ FSDEV --------------//
|
||||||
#if defined(TUP_USBIP_FSDEV)
|
#if defined(TUP_USBIP_FSDEV)
|
||||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||||
@ -368,6 +352,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//------------ MAX3421 -------------//
|
||||||
|
// Enable MAX3421 USB host controller
|
||||||
|
#ifndef CFG_TUH_MAX3421
|
||||||
|
#define CFG_TUH_MAX3421 0
|
||||||
|
#endif
|
||||||
|
|
||||||
//------------ MUSB --------------//
|
//------------ MUSB --------------//
|
||||||
#if defined(TUP_USBIP_MUSB)
|
#if defined(TUP_USBIP_MUSB)
|
||||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||||
@ -375,13 +365,30 @@
|
|||||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
|
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
|
||||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
|
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
|
||||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
|
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------- Raspberry Pi -------------//
|
||||||
|
// Enable PIO-USB software host controller
|
||||||
|
#ifndef CFG_TUH_RPI_PIO_USB
|
||||||
|
#define CFG_TUH_RPI_PIO_USB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_RPI_PIO_USB
|
||||||
|
#define CFG_TUD_RPI_PIO_USB 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
|
||||||
|
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||||
|
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 1
|
||||||
|
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 1
|
||||||
|
#define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
|
||||||
|
#define CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------ RUSB2 --------------//
|
//------------ RUSB2 --------------//
|
||||||
#if defined(TUP_USBIP_RUSB2)
|
#if defined(TUP_USBIP_RUSB2)
|
||||||
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
|
||||||
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit data if highspeed
|
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit if highspeed
|
||||||
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
|
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
|
||||||
#define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write
|
#define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write
|
||||||
// odd byte with byte access
|
// odd byte with byte access
|
||||||
|
|||||||
@ -151,7 +151,7 @@ def read_disk_file(uid, lun, fname):
|
|||||||
def open_mtp_dev(uid):
|
def open_mtp_dev(uid):
|
||||||
mtp = MTP()
|
mtp = MTP()
|
||||||
# MTP seems to take a while to enumerate
|
# MTP seems to take a while to enumerate
|
||||||
timeout = 2*ENUM_TIMEOUT
|
timeout = 2 * ENUM_TIMEOUT
|
||||||
while timeout > 0:
|
while timeout > 0:
|
||||||
# run_cmd(f"gio mount -u mtp://TinyUsb_TinyUsb_Device_{uid}/")
|
# run_cmd(f"gio mount -u mtp://TinyUsb_TinyUsb_Device_{uid}/")
|
||||||
for raw in mtp.detect_devices():
|
for raw in mtp.detect_devices():
|
||||||
@ -410,22 +410,22 @@ def test_device_cdc_dual_ports(board):
|
|||||||
sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
|
sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
|
||||||
|
|
||||||
def write_and_check(writer, payload):
|
def write_and_check(writer, payload):
|
||||||
size = len(payload)
|
payload_len = len(payload)
|
||||||
for s in ser:
|
for s in ser:
|
||||||
s.reset_input_buffer()
|
s.reset_input_buffer()
|
||||||
rd0 = b''
|
rd0 = b''
|
||||||
rd1 = b''
|
rd1 = b''
|
||||||
offset = 0
|
offset = 0
|
||||||
# Write in chunks of random 1-64 bytes (device has 64-byte buffer)
|
# Write in chunks of random 1-64 bytes (device has 64-byte buffer)
|
||||||
while offset < size:
|
while offset < payload_len:
|
||||||
chunk_size = min(random.randint(1, 64), size - offset)
|
chunk_size = min(random.randint(1, 64), payload_len - offset)
|
||||||
ser[writer].write(payload[offset:offset + chunk_size])
|
ser[writer].write(payload[offset:offset + chunk_size])
|
||||||
ser[writer].flush()
|
ser[writer].flush()
|
||||||
rd0 += ser[0].read(chunk_size)
|
rd0 += ser[0].read(chunk_size)
|
||||||
rd1 += ser[1].read(chunk_size)
|
rd1 += ser[1].read(chunk_size)
|
||||||
offset += chunk_size
|
offset += chunk_size
|
||||||
assert rd0 == payload.lower(), f'Port0 wrong data ({size}): expected {payload.lower()[:16]}... was {rd0[:16]}'
|
assert rd0 == payload.lower(), f'Port0 wrong data ({payload_len}): expected {payload.lower()}... was {rd0}'
|
||||||
assert rd1 == payload.upper(), f'Port1 wrong data ({size}): expected {payload.upper()[:16]}... was {rd1[:16]}'
|
assert rd1 == payload.upper(), f'Port1 wrong data ({payload_len}): expected {payload.upper()}... was {rd1}'
|
||||||
|
|
||||||
for size in sizes:
|
for size in sizes:
|
||||||
payload0 = rand_ascii(size)
|
payload0 = rand_ascii(size)
|
||||||
|
|||||||
Reference in New Issue
Block a user