Skip to content

Commit 6cf2775

Browse files
jfischer-nofabiobaltieri
authored andcommitted
usb: device_next: align CDC ACM UART poll_out with legacy implementation
Apply changes in commit c152e09 ("usb: device: cdc_acm: block in uart_poll_out() routine") to the new CDC ACM UART poll_out implementation. Signed-off-by: Johann Fischer <[email protected]>
1 parent 1867e71 commit 6cf2775

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

subsys/usb/device_next/class/usbd_cdc_acm.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ struct cdc_acm_uart_data {
105105
struct k_work irq_cb_work;
106106
struct cdc_acm_uart_fifo rx_fifo;
107107
struct cdc_acm_uart_fifo tx_fifo;
108+
/* When flow_ctrl is set, poll out is blocked when the buffer is full,
109+
* roughly emulating flow control.
110+
*/
111+
bool flow_ctrl;
108112
/* USBD CDC ACM TX fifo work */
109113
struct k_work tx_fifo_work;
110114
/* USBD CDC ACM RX fifo work */
@@ -373,7 +377,8 @@ static void cdc_acm_update_uart_cfg(struct cdc_acm_uart_data *const data)
373377
break;
374378
};
375379

376-
cfg->flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
380+
cfg->flow_ctrl = data->flow_ctrl ? UART_CFG_FLOW_CTRL_RTS_CTS :
381+
UART_CFG_FLOW_CTRL_NONE;
377382
}
378383

379384
static void cdc_acm_update_linestate(struct cdc_acm_uart_data *const data)
@@ -884,24 +889,27 @@ static int cdc_acm_poll_in(const struct device *dev, unsigned char *const c)
884889
static void cdc_acm_poll_out(const struct device *dev, const unsigned char c)
885890
{
886891
struct cdc_acm_uart_data *const data = dev->data;
892+
uint32_t wrote;
887893

888894
if (atomic_test_and_set_bit(&data->state, CDC_ACM_LOCK)) {
889895
LOG_ERR("IRQ callback is used");
890896
return;
891897
}
892898

893-
if (ring_buf_put(data->tx_fifo.rb, &c, 1)) {
894-
goto poll_out_exit;
895-
}
899+
while (true) {
900+
wrote = ring_buf_put(data->tx_fifo.rb, &c, 1);
901+
if (wrote == 1) {
902+
break;
903+
}
896904

897-
LOG_DBG("Ring buffer full, drain buffer");
898-
if (!ring_buf_get(data->tx_fifo.rb, NULL, 1) ||
899-
!ring_buf_put(data->tx_fifo.rb, &c, 1)) {
900-
LOG_ERR("Failed to drain buffer");
901-
__ASSERT_NO_MSG(false);
905+
if (k_is_in_isr() || !data->flow_ctrl) {
906+
LOG_WRN_ONCE("Ring buffer full, discard data");
907+
break;
908+
}
909+
910+
k_msleep(1);
902911
}
903912

904-
poll_out_exit:
905913
atomic_clear_bit(&data->state, CDC_ACM_LOCK);
906914
cdc_acm_work_submit(&data->tx_fifo_work);
907915
}
@@ -976,17 +984,18 @@ static int cdc_acm_line_ctrl_get(const struct device *dev,
976984
static int cdc_acm_configure(const struct device *dev,
977985
const struct uart_config *const cfg)
978986
{
979-
ARG_UNUSED(dev);
980-
ARG_UNUSED(cfg);
981-
/*
982-
* We cannot implement configure API because there is
983-
* no notification of configuration changes provided
984-
* for the Abstract Control Model and the UART controller
985-
* is only emulated.
986-
* However, it allows us to use CDC ACM UART together with
987-
* subsystems like Modbus which require configure API for
988-
* real controllers.
989-
*/
987+
struct cdc_acm_uart_data *const data = dev->data;
988+
989+
switch (cfg->flow_ctrl) {
990+
case UART_CFG_FLOW_CTRL_NONE:
991+
data->flow_ctrl = false;
992+
break;
993+
case UART_CFG_FLOW_CTRL_RTS_CTS:
994+
data->flow_ctrl = true;
995+
break;
996+
default:
997+
return -ENOTSUP;
998+
}
990999

9911000
return 0;
9921001
}
@@ -1240,6 +1249,7 @@ const static struct usb_desc_header *cdc_acm_hs_desc_##n[] = { \
12401249
.c_data = &cdc_acm_##n, \
12411250
.rx_fifo.rb = &cdc_acm_rb_rx_##n, \
12421251
.tx_fifo.rb = &cdc_acm_rb_tx_##n, \
1252+
.flow_ctrl = DT_INST_PROP(n, hw_flow_control), \
12431253
.notif_sem = Z_SEM_INITIALIZER(uart_data_##n.notif_sem, 0, 1), \
12441254
.desc = &cdc_acm_desc_##n, \
12451255
.fs_desc = cdc_acm_fs_desc_##n, \

0 commit comments

Comments
 (0)