Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions sys/include/usb/usbus/cdc/acm.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
*/

#include <stdint.h>
#include <unistd.h>

#include "usb/cdc.h"
#include "usb/usbus.h"
#include "tsrb.h"
Expand Down Expand Up @@ -198,9 +200,10 @@ void usbus_cdc_acm_init(usbus_t *usbus, usbus_cdcacm_device_t *cdcacm,
* @param[in] buf buffer to submit
* @param[in] len length of the submitted buffer
*
* @return Number of bytes added to the CDC ACM ring buffer
* @retval -ECONNRESET Failed to submit data
* @retval >=0 Number of bytes added to the CDC ACM ring buffer
*/
size_t usbus_cdc_acm_submit(usbus_cdcacm_device_t *cdcacm,
ssize_t usbus_cdc_acm_submit(usbus_cdcacm_device_t *cdcacm,
const uint8_t *buf, size_t len);

/**
Expand Down
15 changes: 12 additions & 3 deletions sys/picolibc_syscalls_default/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,19 @@ static int picolibc_stdout_queued;

static void _picolibc_flush(void)
{
if (picolibc_stdout_queued) {
stdio_write(picolibc_stdout, picolibc_stdout_queued);
picolibc_stdout_queued = 0;
char *pos = picolibc_stdout;
char *end = pos + picolibc_stdout_queued;
while (pos < end) {
size_t left = (size_t)end - (size_t)pos;
ssize_t written = stdio_write(pos, left);
if (written < 0) {
/* failed to flush, drop data */
break;
}
pos += written;
Comment on lines +185 to +192
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this become an endless loop with high CPU load if stdio_write returns 0 (and does not write anything)? I'd have to look up if stdio_write could behave like that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning 0 is very much valid. If the stdio would have flow control (e.g. UART with flow control or some network protocol), it may not be able to send out any data right now.

There is an expectation towards the transport that returning 0 is a temporary thing that will sort itself out within reasonable time. The layer above cannot reasonably judge when stuff won't work, so it just has to trust that at some point the transport will either make progress or give up.

}

picolibc_stdout_queued = 0;
}

static int picolibc_put(char c, FILE *file)
Expand Down
7 changes: 4 additions & 3 deletions sys/usb/usbus/cdc/acm/cdc_acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define USB_H_USER_IS_RIOT_INTERNAL

#include <assert.h>
#include <errno.h>
#include <string.h>

#include "tsrb.h"
Expand Down Expand Up @@ -148,12 +149,12 @@ static size_t _gen_full_acm_descriptor(usbus_t *usbus, void *arg)
}

/* Submit (ACM interface in) */
size_t usbus_cdc_acm_submit(usbus_cdcacm_device_t *cdcacm, const uint8_t *buf, size_t len)
ssize_t usbus_cdc_acm_submit(usbus_cdcacm_device_t *cdcacm, const uint8_t *buf, size_t len)
{
size_t n;
ssize_t n;
unsigned old;
if (cdcacm->state == USBUS_CDC_ACM_LINE_STATE_DISCONNECTED) {
return len;
return -ECONNRESET;
}

old = irq_disable();
Expand Down
13 changes: 3 additions & 10 deletions sys/usb/usbus/cdc/acm/cdc_acm_stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include <stdio.h>
#include <sys/types.h>

#include "log.h"
#include "isrpipe.h"
#include "stdio_base.h"

Expand All @@ -36,15 +35,9 @@ static uint8_t _cdc_tx_buf_mem[CONFIG_USBUS_CDC_ACM_STDIO_BUF_SIZE];

static ssize_t _write(const void* buffer, size_t len)
{
const char *start = buffer;
while (len) {
size_t n = usbus_cdc_acm_submit(&cdcacm, buffer, len);
usbus_cdc_acm_flush(&cdcacm);
/* Use tsrb and flush */
buffer = (char *)buffer + n;
len -= n;
}
return (char *)buffer - start;
ssize_t retval = usbus_cdc_acm_submit(&cdcacm, buffer, len);
usbus_cdc_acm_flush(&cdcacm);
return retval;
Copy link
Contributor

@benpicco benpicco Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling the partial transfer in the upper layer won't work when stdio_dispatch is used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do the looping in stdio_dispatch for now and have the option to later improve, e.g. be asking the transports what amount of data they can handle right away and dispatching only the minimum of those values.

If we force all transports to be smart and handle all the special cases and IRQ themselves, we easily run into duplicates code and transport specific behaviour.

}

static void _cdc_acm_rx_pipe(usbus_cdcacm_device_t *cdcacm,
Expand Down
Loading