summaryrefslogtreecommitdiff
path: root/src/class
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2026-03-01 15:36:21 +0100
committerHiFiPhile <[email protected]>2026-03-01 15:36:21 +0100
commit7da7d0725b4b791eaeda6b6a344932ec8c07feb1 (patch)
tree4573f70051e02d1a684e42df36ea533d2c68257c /src/class
parentbb944729f2ad39f2e497505e4562e0fd1e836f23 (diff)
parentbd1e79bc6cefbbbe981691c3a55e24cf25537301 (diff)
Merge remote-tracking branch 'tinyusb/master' into ncm_restart
Diffstat (limited to 'src/class')
-rw-r--r--src/class/audio/audio_device.c12
-rw-r--r--src/class/cdc/cdc_host.c169
-rw-r--r--src/class/msc/msc_device.c6
-rw-r--r--src/class/mtp/mtp_device.c105
-rw-r--r--src/class/mtp/mtp_device.h2
-rw-r--r--src/class/vendor/vendor_device.c262
-rw-r--r--src/class/vendor/vendor_device.h44
-rw-r--r--src/class/video/video_device.h3
8 files changed, 342 insertions, 261 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 55eba81dd..be0224811 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -674,17 +674,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, true);
break;
#endif
}
@@ -716,17 +716,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, true);
break;
#endif
}
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index f19c4a327..8f6dd7200 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -127,7 +127,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_
static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST};
static uint16_t ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
-static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static bool ftdi_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
static void ftdi_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
@@ -216,82 +216,84 @@ typedef struct {
#define DRIVER_NAME_DECLARE(_str)
#endif
+// clang-format off
// Note driver list must be in the same order as SERIAL_DRIVER enum
static const cdch_serial_driver_t serial_drivers[] = {
{
- .vid_pid_list = NULL,
- .vid_pid_count = 0,
- .open = acm_open,
- .process_set_config = acm_process_set_config,
- .request_complete = acm_internal_control_complete,
- .set_control_line_state = acm_set_control_line_state,
- .set_baudrate = acm_set_line_coding,
- .set_data_format = acm_set_line_coding,
- .set_line_coding = acm_set_line_coding,
- DRIVER_NAME_DECLARE("ACM")
+ .vid_pid_list = NULL,
+ .vid_pid_count = 0,
+ .open = acm_open,
+ .process_set_config = acm_process_set_config,
+ .request_complete = acm_internal_control_complete,
+ .set_control_line_state = acm_set_control_line_state,
+ .set_baudrate = acm_set_line_coding,
+ .set_data_format = acm_set_line_coding,
+ .set_line_coding = acm_set_line_coding,
+ DRIVER_NAME_DECLARE("ACM")
},
#if CFG_TUH_CDC_FTDI
{
- .vid_pid_list = ftdi_vid_pid_list,
- .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list),
- .open = ftdi_open,
- .process_set_config = ftdi_proccess_set_config,
- .request_complete = ftdi_internal_control_complete,
- .set_control_line_state = ftdi_set_modem_ctrl,
- .set_baudrate = ftdi_set_baudrate,
- .set_data_format = ftdi_set_data_format,
- .set_line_coding = NULL, // 2 stage set line coding
- DRIVER_NAME_DECLARE("FTDI")
+ .vid_pid_list = ftdi_vid_pid_list,
+ .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list),
+ .open = ftdi_open,
+ .process_set_config = ftdi_process_set_config,
+ .request_complete = ftdi_internal_control_complete,
+ .set_control_line_state = ftdi_set_modem_ctrl,
+ .set_baudrate = ftdi_set_baudrate,
+ .set_data_format = ftdi_set_data_format,
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("FTDI")
},
#endif
#if CFG_TUH_CDC_CP210X
{
- .vid_pid_list = cp210x_vid_pid_list,
- .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list),
- .open = cp210x_open,
- .process_set_config = cp210x_process_set_config,
- .request_complete = cp210x_internal_control_complete,
- .set_control_line_state = cp210x_set_modem_ctrl,
- .set_baudrate = cp210x_set_baudrate,
- .set_data_format = cp210x_set_data_format,
- .set_line_coding = NULL, // 2 stage set line coding
- DRIVER_NAME_DECLARE("CP210x")
+ .vid_pid_list = cp210x_vid_pid_list,
+ .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list),
+ .open = cp210x_open,
+ .process_set_config = cp210x_process_set_config,
+ .request_complete = cp210x_internal_control_complete,
+ .set_control_line_state = cp210x_set_modem_ctrl,
+ .set_baudrate = cp210x_set_baudrate,
+ .set_data_format = cp210x_set_data_format,
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("CP210x")
},
#endif
#if CFG_TUH_CDC_CH34X
{
- .vid_pid_list = ch34x_vid_pid_list,
- .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list),
- .open = ch34x_open,
- .process_set_config = ch34x_process_set_config,
- .request_complete = ch34x_internal_control_complete,
+ .vid_pid_list = ch34x_vid_pid_list,
+ .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list),
+ .open = ch34x_open,
+ .process_set_config = ch34x_process_set_config,
+ .request_complete = ch34x_internal_control_complete,
- .set_control_line_state = ch34x_set_modem_ctrl,
- .set_baudrate = ch34x_set_baudrate,
- .set_data_format = ch34x_set_data_format,
- .set_line_coding = NULL, // 2 stage set line coding
- DRIVER_NAME_DECLARE("CH34x")
+ .set_control_line_state = ch34x_set_modem_ctrl,
+ .set_baudrate = ch34x_set_baudrate,
+ .set_data_format = ch34x_set_data_format,
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("CH34x")
},
#endif
#if CFG_TUH_CDC_PL2303
{
- .vid_pid_list = pl2303_vid_pid_list,
- .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list),
- .open = pl2303_open,
- .process_set_config = pl2303_process_set_config,
- .request_complete = pl2303_internal_control_complete,
- .set_control_line_state = pl2303_set_modem_ctrl,
- .set_baudrate = pl2303_set_line_coding,
- .set_data_format = pl2303_set_line_coding,
- .set_line_coding = pl2303_set_line_coding,
- DRIVER_NAME_DECLARE("PL2303")
+ .vid_pid_list = pl2303_vid_pid_list,
+ .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list),
+ .open = pl2303_open,
+ .process_set_config = pl2303_process_set_config,
+ .request_complete = pl2303_internal_control_complete,
+ .set_control_line_state = pl2303_set_modem_ctrl,
+ .set_baudrate = pl2303_set_line_coding,
+ .set_data_format = pl2303_set_line_coding,
+ .set_line_coding = pl2303_set_line_coding,
+ DRIVER_NAME_DECLARE("PL2303")
}
#endif
};
+// clang-format on
TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch");
@@ -761,7 +763,8 @@ uint16_t cdch_open(uint8_t rhport, uint8_t daddr, const tusb_desc_interface_t *i
for (size_t i = 0; i < driver->vid_pid_count; i++) {
if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) {
const uint16_t drv_len = driver->open(daddr, itf_desc, max_len);
- TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, drv_len > 0 ? "OK" : "FAILED");
+ TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name,
+ drv_len > 0 ? "OK" : "FAILED");
return drv_len;
}
}
@@ -773,35 +776,16 @@ uint16_t cdch_open(uint8_t rhport, uint8_t daddr, const tusb_desc_interface_t *i
return 0;
}
-bool cdch_set_config(uint8_t daddr, uint8_t itf_num) {
- tusb_control_request_t request;
- request.wIndex = tu_htole16((uint16_t) itf_num);
- uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
- cdch_interface_t *p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
- TU_LOG_CDC(p_cdc, "set config");
-
- // fake transfer to kick-off process_set_config()
- tuh_xfer_t xfer;
- xfer.daddr = daddr;
- xfer.result = XFER_RESULT_SUCCESS;
- xfer.setup = &request;
- xfer.user_data = 0; // initial state 0
- cdch_process_set_config(&xfer);
-
- return true;
-}
-
static void set_config_complete(cdch_interface_t *p_cdc, bool success) {
if (success) {
const uint8_t idx = get_idx_by_ptr(p_cdc);
- p_cdc->mounted = true;
+ p_cdc->mounted = true;
tuh_cdc_mount_cb(idx);
// Prepare for incoming data
tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
} else {
// clear the interface entry
- p_cdc->daddr = 0;
+ p_cdc->daddr = 0;
p_cdc->bInterfaceNumber = 0;
}
@@ -810,6 +794,33 @@ static void set_config_complete(cdch_interface_t *p_cdc, bool success) {
usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset);
}
+bool cdch_set_config(uint8_t daddr, uint8_t itf_num) {
+ const uint8_t idx = tuh_cdc_itf_get_index(daddr, itf_num);
+ cdch_interface_t *p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
+ TU_LOG_CDC(p_cdc, "set config");
+
+ // fake transfer to kick-off process_set_config()
+ tusb_control_request_t request;
+ request.wIndex = tu_htole16((uint16_t)itf_num);
+
+ tuh_xfer_t xfer;
+ xfer.daddr = daddr;
+ xfer.ep_addr = 0;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.setup = &request;
+ xfer.complete_cb = NULL;
+ xfer.buffer = NULL;
+ xfer.user_data = 0; // initial state 0
+
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
+ if (!driver->process_set_config(p_cdc, &xfer)) {
+ set_config_complete(p_cdc, false);
+ }
+
+ return true;
+}
+
static void cdch_process_set_config(tuh_xfer_t *xfer) {
cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
@@ -1215,22 +1226,14 @@ static uint16_t ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc,
return drv_len;
}
-static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+static bool ftdi_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS);
const uintptr_t state = xfer->user_data;
switch (state) {
// from here sequence overtaken from Linux Kernel function ftdi_port_probe()
case CONFIG_FTDI_DETERMINE_TYPE:
// determine type
- if (p_cdc->bInterfaceNumber == 0) {
- TU_ASSERT(ftdi_determine_type(p_cdc));
- } else {
- // other interfaces have same type as interface 0
- uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0);
- cdch_interface_t const *p_cdc_itf0 = get_itf(idx_itf0);
- TU_ASSERT(p_cdc_itf0);
- p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type;
- }
+ TU_ASSERT(ftdi_determine_type(p_cdc));
TU_ATTR_FALLTHROUGH;
case CONFIG_FTDI_WRITE_LATENCY:
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 15bfafc35..3766e3a25 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -646,7 +646,11 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
}
- TU_ASSERT(prepare_cbw(p_msc));
+ if (!usbd_edpt_stalled(rhport, p_msc->ep_out)) {
+ TU_ASSERT(prepare_cbw(p_msc));
+ } else {
+ p_msc->stage = MSC_STAGE_CMD;
+ }
} else {
// Any xfer ended here is considered unknown error, ignore it
TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n");
diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c
index 4942a105a..59096e476 100644
--- a/src/class/mtp/mtp_device.c
+++ b/src/class/mtp/mtp_device.c
@@ -92,8 +92,9 @@ typedef struct {
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
- uint8_t ep_event;
+ uint8_t ep_event;
+ uint8_t ep_sz_fs;
// Bulk Only Transfer (BOT) Protocol
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);
}
-static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
- mtpd_interface_t* p_mtp = &_mtpd_itf;
+bool tud_mtp_data_send(mtp_container_info_t *p_container) {
+ 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;
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
- p_mtp->total_len = p_container->header->len;
- p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
- 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);
+ p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.header.transaction_id;
+ p_mtp->io_header = *p_container->header; // save header for subsequent 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) {
- // already transferred all bytes in header's length. Application make an unnecessary extra call
- TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
- TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len, false));
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_in));
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, xact_len, false));
}
return true;
}
-bool tud_mtp_data_send(mtp_container_info_t* p_container) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
-}
+bool tud_mtp_data_receive(mtp_container_info_t *p_container) {
+ 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) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
+ // up to buffer size since 1st packet (with header) may also contain payload
+ 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) {
@@ -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;
// Open interrupt IN endpoint
- const tusb_desc_endpoint_t* ep_desc = (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(usbd_edpt_open(rhport, ep_desc), 0);
- p_mtp->ep_event = ep_desc->bEndpointAddress;
+ const tusb_desc_endpoint_t* ep_desc_int = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
+ 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_int), 0);
+ p_mtp->ep_event = ep_desc_int->bEndpointAddress;
// 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);
+ 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;
}
@@ -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;
#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
- 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, 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, code),
_mtp_phase_str[p_mtp->phase]);
#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: {
- const uint16_t bulk_mps = (tud_speed_get() == TUSB_SPEED_HIGH) ? 512 : 64;
p_mtp->xferred_len += xferred_bytes;
cb_data.total_xferred_bytes = p_mtp->xferred_len;
- bool is_complete = false;
- // complete if ZLP or short packet or total length reached
- if (xferred_bytes == 0 || // ZLP
- (xferred_bytes & (bulk_mps - 1)) || // short packet
- p_mtp->xferred_len >= p_mtp->total_len) { // total length reached
- is_complete = true;
+ const bool is_data_in = (ep_addr == p_mtp->ep_in);
+ // For IN endpoint, threshold is bulk max packet size
+ // For OUT endpoint, threshold is endpoint buffer size, since we always queue fixed size
+ uint16_t threshold;
+ if (is_data_in) {
+ 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;
+ }
+
+ // 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 (ep_addr == p_mtp->ep_in) {
+ if (is_data_in) {
// Data In
if (is_complete) {
cb_data.io_container.header->len = sizeof(mtp_container_header_t);
diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h
index a33f1dc08..6cce7efbb 100644
--- a/src/class/mtp/mtp_device.h
+++ b/src/class/mtp/mtp_device.h
@@ -18,7 +18,7 @@
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN0
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index b8e6fec6f..b917c8dc7 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -40,36 +40,33 @@ typedef struct {
uint8_t rhport;
uint8_t itf_num;
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
/*------------- From this point, data is not cleared by bus reset -------------*/
- struct {
- tu_edpt_stream_t tx;
- tu_edpt_stream_t rx;
-
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
- uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
- #endif
-
- #if CFG_TUD_VENDOR_RX_BUFSIZE > 0
- uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+ tu_edpt_stream_t tx_stream;
+ tu_edpt_stream_t rx_stream;
+ uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
+ uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+ #else
+ uint8_t ep_in;
+ uint8_t ep_out;
+ uint16_t ep_in_mps;
+ uint16_t ep_out_mps;
#endif
- } stream;
} 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];
-#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 {
- // 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);
- #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);
- #endif
} vendord_epbuf_t;
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
//--------------------------------------------------------------------+
-
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
(void)idx;
(void)buffer;
@@ -93,40 +89,44 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
//--------------------------------------------------------------------
// Application API
//--------------------------------------------------------------------
-
bool tud_vendor_n_mounted(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
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
//--------------------------------------------------------------------+
-#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
uint32_t tud_vendor_n_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
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) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
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) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
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) {
TU_VERIFY(idx < CFG_TUD_VENDOR, );
vendord_interface_t *p_itf = &_vendord_itf[idx];
- tu_edpt_stream_clear(&p_itf->stream.rx);
- tu_edpt_stream_read_xfer(&p_itf->stream.rx);
+ tu_edpt_stream_clear(&p_itf->rx_stream);
+ tu_edpt_stream_read_xfer(&p_itf->rx_stream);
}
#endif
@@ -134,9 +134,17 @@ void tud_vendor_n_read_flush(uint8_t idx) {
bool tud_vendor_n_read_xfer(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
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) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
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_TXRX_BUFFERED
+ return tu_edpt_stream_write(&p_itf->tx_stream, buffer, (uint16_t)bufsize);
+
+ #else
+ // 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
}
-#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
-uint32_t tud_vendor_n_write_flush(uint8_t idx) {
+uint32_t tud_vendor_n_write_available(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->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
}
-uint32_t tud_vendor_n_write_available(uint8_t idx) {
+ #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_available(&p_itf->stream.tx);
+ return tu_edpt_stream_write_xfer(&p_itf->tx_stream);
}
bool tud_vendor_n_write_clear(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
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;
}
#endif
@@ -175,48 +202,37 @@ bool tud_vendor_n_write_clear(uint8_t idx) {
void vendord_init(void) {
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
- for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
- vendord_interface_t* p_itf = &_vendord_itf[i];
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ 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_VENDOR_RX_BUFSIZE == 0 // non-fifo rx still need ep buffer
- uint8_t *epout_buf = _vendord_epbuf[i].epout;
- #else
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
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 *epin_buf = _vendord_epbuf[i].epin;
- #endif
-
- #if CFG_TUD_VENDOR_RX_BUFSIZE > 0
- uint8_t *rx_ff_buf = p_itf->stream.rx_ff_buf;
- #else
- uint8_t *rx_ff_buf = NULL;
- #endif
+ #endif
- tu_edpt_stream_init(&p_itf->stream.rx, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
+ uint8_t *rx_ff_buf = p_itf->rx_ff_buf;
+ tu_edpt_stream_init(&p_itf->rx_stream, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
CFG_TUD_VENDOR_EPSIZE);
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
- uint8_t *tx_ff_buf = p_itf->stream.tx_ff_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,
+ uint8_t *tx_ff_buf = p_itf->tx_ff_buf;
+ tu_edpt_stream_init(&p_itf->tx_stream, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
CFG_TUD_VENDOR_EPSIZE);
}
+ #endif
}
bool vendord_deinit(void) {
- for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
- vendord_interface_t* p_itf = &_vendord_itf[i];
- tu_edpt_stream_deinit(&p_itf->stream.rx);
- tu_edpt_stream_deinit(&p_itf->stream.tx);
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
+ vendord_interface_t *p_itf = &_vendord_itf[i];
+ tu_edpt_stream_deinit(&p_itf->rx_stream);
+ tu_edpt_stream_deinit(&p_itf->tx_stream);
}
+ #endif
return true;
}
@@ -227,11 +243,12 @@ void vendord_reset(uint8_t rhport) {
vendord_interface_t* p_itf = &_vendord_itf[i];
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
- tu_edpt_stream_clear(&p_itf->stream.rx);
- tu_edpt_stream_close(&p_itf->stream.rx);
-
- tu_edpt_stream_clear(&p_itf->stream.tx);
- tu_edpt_stream_close(&p_itf->stream.tx);
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ tu_edpt_stream_clear(&p_itf->rx_stream);
+ tu_edpt_stream_close(&p_itf->rx_stream);
+ tu_edpt_stream_clear(&p_itf->tx_stream);
+ 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];
if (ep_addr == 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;
}
- } else if (ep_addr == p_vendor->stream.rx.ep_addr || ep_addr == p_vendor->stream.tx.ep_addr) {
- return idx;
+ #else
+ if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0) {
+ return idx;
+ }
+ #endif
} 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;
@@ -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;
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) {
- tu_edpt_stream_t *stream_tx = &p_vendor->stream.tx;
- if (stream_tx->ep_addr == 0) {
- tu_edpt_stream_open(stream_tx, rhport, desc_ep);
- tu_edpt_stream_write_xfer(stream_tx); // flush pending data
- }
+ tu_edpt_stream_t *tx_stream = &p_vendor->tx_stream;
+ tu_edpt_stream_open(tx_stream, rhport, desc_ep);
+ tu_edpt_stream_write_xfer(tx_stream); // flush pending data
} else {
- tu_edpt_stream_t *stream_rx = &p_vendor->stream.rx;
- if (stream_rx->ep_addr == 0) {
- tu_edpt_stream_open(stream_rx, rhport, desc_ep);
- #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
- TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
- #endif
- }
+ tu_edpt_stream_t *rx_stream = &p_vendor->rx_stream;
+ tu_edpt_stream_open(rx_stream, rhport, desc_ep);
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ TU_ASSERT(tu_edpt_stream_read_xfer(rx_stream) > 0, 0); // prepare for incoming data
+ #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);
}
- 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) {
@@ -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);
vendord_interface_t *p_vendor = &_vendord_itf[idx];
- if (ep_addr == p_vendor->stream.rx.ep_addr) {
- #if CFG_TUD_VENDOR_RX_BUFSIZE
- // Received new data: put into stream's fifo
- tu_edpt_stream_read_xfer_complete(&p_vendor->stream.rx, 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
+#if CFG_TUD_VENDOR_TXRX_BUFFERED
+ if (ep_addr == p_vendor->rx_stream.ep_addr) {
+ // Put received data to FIFO
+ tu_edpt_stream_read_xfer_complete(&p_vendor->rx_stream, xferred_bytes);
tud_vendor_rx_cb(idx, NULL, 0);
- #endif
-
- #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
- tu_edpt_stream_read_xfer(&p_vendor->stream.rx); // prepare next data
- #endif
- } else if (ep_addr == p_vendor->stream.tx.ep_addr) {
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ tu_edpt_stream_read_xfer(&p_vendor->rx_stream); // prepare next data
+ #endif
+ } else if (ep_addr == p_vendor->tx_stream.ep_addr) {
// Send complete
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
// 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
- 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;
}
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
index c3de4c49d..101765bb1 100644
--- a/src/class/vendor/vendor_device.h
+++ b/src/class/vendor/vendor_device.h
@@ -50,8 +50,14 @@ extern "C" {
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
#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
-// i.e. CFG_TUD_VENDOR_RX_BUFSIZE = 0
+// i.e. CFG_TUD_VENDOR_TXRX_BUFFERED = 0
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
#endif
@@ -63,7 +69,8 @@ extern "C" {
// Return whether the vendor interface is mounted
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
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);
#endif
+//------------- TX -------------//
// 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);
-#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
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
bool tud_vendor_n_write_clear(uint8_t idx);
#endif
@@ -111,7 +119,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) {
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) {
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) {
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
#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);
}
-#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) {
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
#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.
-// - 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_RX_BUFSIZE = 0: Buffer and bufsize are valid
+// - 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_TXRX_BUFFERED = 0: Buffer and bufsize are valid
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
// Invoked when tx transfer is finished
diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h
index f14555e4f..2750bb2fb 100644
--- a/src/class/video/video_device.h
+++ b/src/class/video/video_device.h
@@ -99,8 +99,7 @@ int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
* @param[in] stm_idx Destination streaming interface index
* @param[out] payload_buf Payload storage buffer (target buffer for requested data)
* @param[in] payload_size Size of payload_buf (requested data size)
- * @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize)
- * @return video_error_code_t */
+ * @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize) */
void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request);
//--------------------------------------------------------------------+