driver/serial/cdcacm: config to enable or disable rxbuf

To be compatible with the previous method, add a buf between cdcacm
and serial. Because when using usbreqbuf directly as the buf of serial,
the amount of data received may be insufficient due to the limit of the
number of reqs. For example, when the number of reqs is 4, the number
of data received through cdcacm is 5, and each data is a separate USB
packet, which should require 5 reqs, resulting in the last number not
being received. If the application always waits for 5 numbers before
performing an operation, this will cause problems.

Signed-off-by: yangsong8 <yangsong8@xiaomi.com>
This commit is contained in:
yangsong8
2025-03-27 11:55:44 +08:00
committed by Lup Yuen Lee
parent 9206abc28a
commit f0b52a8b2d
2 changed files with 124 additions and 4 deletions
+23
View File
@@ -432,6 +432,7 @@ menuconfig CDCACM
bool "USB Modem (CDC/ACM) support"
default n
select SERIAL_REMOVABLE
select SERIAL_RXDMA if !CDCACM_DISABLE_RXBUF
---help---
Enables USB Modem (CDC/ACM) support
@@ -680,6 +681,28 @@ config CDCACM_BULKIN_REQLEN
than CDCACM_TXBUFSIZE-1, since a request larger than the TX
buffer can never be sent.
config CDCACM_DISABLE_RXBUF
bool "CDC/ACM use usb rx req buf directly"
default n
---help---
The interaction between cdcacm and serial uses usb req buf
directly instead of using a separate buffer.
if !CDCACM_DISABLE_RXBUF
config CDCACM_RXBUFSIZE
int "Receive buffer size"
default 513 if USBDEV_DUALSPEED
default 257 if !USBDEV_DUALSPEED
---help---
Size of the serial receive buffers. The actual amount of data that
can be held in the buffer is this number minus one due to the way
that the circular buffer is managed. So an RX buffer size of 257
will hold four full-speed, 64 byte packets; a buffer size of 513
will hold one high-speed, 512 byte packet.
endif # !CDCACM_DISABLE_RXBUF
if !CDCACM_COMPOSITE
# In a composite device the Vendor- and Product-ID is given by the composite
+101 -4
View File
@@ -130,7 +130,11 @@ struct cdcacm_dev_s
/* Serial I/O req container */
#ifdef CONFIG_CDCACM_DISABLE_RXBUF
FAR struct cdcacm_rdreq_s *rdcontainer;
#else
char rxbuffer[CONFIG_CDCACM_RXBUFSIZE];
#endif
FAR struct cdcacm_wrreq_s *wrcontainer;
};
@@ -157,7 +161,9 @@ struct cdcacm_alloc_s
/* Transfer helpers *********************************************************/
static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv);
#ifdef CONFIG_CDCACM_DISABLE_RXBUF
static void cdcacm_rcvpacket(FAR struct cdcacm_dev_s *priv);
#endif
static int cdcacm_requeue_rdrequest(FAR struct cdcacm_dev_s *priv,
FAR struct cdcacm_rdreq_s *rdcontainer);
static int cdcacm_release_rxpending(FAR struct cdcacm_dev_s *priv);
@@ -229,6 +235,9 @@ static ssize_t cdcuart_recvbuf(FAR struct uart_dev_s *dev,
static bool cdcuart_txready(FAR struct uart_dev_s *dev);
static ssize_t cdcuart_sendbuf(FAR struct uart_dev_s *dev,
FAR const void *buf, size_t len);
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
static void cdcuart_dmareceive(FAR struct uart_dev_s *dev);
#endif
/****************************************************************************
* Private Data
@@ -274,7 +283,11 @@ static const struct uart_ops_s g_uartops =
NULL, /* dmasend */
#endif
#ifdef CONFIG_SERIAL_RXDMA
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
cdcuart_dmareceive, /* dmareceive */
#else
NULL, /* dmareceive */
#endif
NULL, /* dmarxfree */
#endif
#ifdef CONFIG_SERIAL_TXDMA
@@ -607,7 +620,14 @@ static int cdcacm_release_rxpending(FAR struct cdcacm_dev_s *priv)
ret = OK;
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
if (!sq_empty(&priv->rxpending))
{
uart_recvchars_dma(&priv->serdev);
}
#else
cdcacm_rcvpacket(priv);
#endif
}
/* Restart the RX failsafe timer if there are RX packets in
@@ -2138,6 +2158,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
switch (cmd)
{
#ifdef CONFIG_CDCACM_DISABLE_RXBUF
/* Get the number of bytes that may be read from the RX buffer
* (without waiting)
*/
@@ -2165,6 +2186,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
*(FAR int *)((uintptr_t)arg) = count;
}
break;
#endif
/* Get the number of bytes that have been written to the TX
* buffer.
@@ -2237,13 +2259,17 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
case TCFLSH:
{
ret = -ENOTTY;
/* Empty the tx/rx buffers */
irqstate_t flags = enter_critical_section();
#ifdef CONFIG_CDCACM_DISABLE_RXBUF
if (arg == TCIFLUSH || arg == TCIOFLUSH)
{
FAR struct cdcacm_rdreq_s *rdcontainer;
ret = OK;
irqstate_t flags = enter_critical_section();
if (priv->rdcontainer)
{
@@ -2267,10 +2293,15 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
uart_rxflowcontrol(serdev, 0, false);
#endif
leave_critical_section(flags);
}
#endif
if (arg == TCOFLUSH || arg == TCIOFLUSH)
{
irqstate_t flags = enter_critical_section();
ret = OK;
if (priv->wrcontainer)
{
serdev->xmit.head = 0;
@@ -2296,9 +2327,9 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
ret = -EBUSY;
}
}
leave_critical_section(flags);
leave_critical_section(flags);
}
}
break;
@@ -2872,6 +2903,66 @@ static int cdcuart_release(FAR struct uart_dev_s *dev)
return OK;
}
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
/****************************************************************************
* Name: cdcuart_dmareceive
*
* Description:
* Set up to receive bytes into the RX circular buffer.
*
****************************************************************************/
static void cdcuart_dmareceive(FAR struct uart_dev_s *dev)
{
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
FAR struct cdcacm_dev_s *priv = dev->priv;
FAR struct cdcacm_rdreq_s *rdcontainer;
FAR struct usbdev_req_s *req;
FAR uint8_t *reqbuf;
size_t nbytes = 0;
size_t reqlen;
/* Process each packet in the priv->rxpending list */
rdcontainer = (FAR struct cdcacm_rdreq_s *)
sq_peek(&priv->rxpending);
DEBUGASSERT(rdcontainer != NULL);
req = rdcontainer->req;
DEBUGASSERT(req != NULL);
reqbuf = &req->buf[rdcontainer->offset];
reqlen = req->xfrd - rdcontainer->offset;
nbytes = MIN(reqlen, xfer->length);
memcpy(xfer->buffer, reqbuf, nbytes);
rdcontainer->offset += nbytes;
xfer->nbytes = nbytes;
if (xfer->nbuffer)
{
nbytes = MIN(reqlen - nbytes, xfer->nlength);
memcpy(xfer->nbuffer, reqbuf + xfer->nbytes, nbytes);
rdcontainer->offset += nbytes;
xfer->nbytes += nbytes;
}
uart_recvchars_done(dev);
/* The entire packet was processed and may be removed from the
* pending RX list.
*/
if (rdcontainer->offset >= rdcontainer->req->xfrd)
{
sq_remfirst(&priv->rxpending);
cdcacm_requeue_rdrequest(priv, rdcontainer);
}
}
#else
/****************************************************************************
* Name: cdcacm_rcvpacket
*
@@ -2916,6 +3007,8 @@ static void cdcacm_rcvpacket(FAR struct cdcacm_dev_s *priv)
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -3071,6 +3164,10 @@ int cdcacm_classobject(int minor, FAR struct usbdev_devinfo_s *devinfo,
#ifdef CONFIG_SERIAL_REMOVABLE
priv->serdev.disconnected = true;
#endif
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
priv->serdev.recv.size = CONFIG_CDCACM_RXBUFSIZE;
priv->serdev.recv.buffer = priv->rxbuffer;
#endif
priv->serdev.ops = &g_uartops;
priv->serdev.priv = priv;