driver/serial/cdcacm: config to enable or disable txbuf
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 sent 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 send through cdcacm is 5, and each data is a separate USB packet, if the host does not read in time, resulting in blocking send. Signed-off-by: yangsong8 <yangsong8@xiaomi.com>
This commit is contained in:
parent
f0b52a8b2d
commit
e8f9570ffd
2 changed files with 123 additions and 2 deletions
|
|
@ -433,6 +433,7 @@ menuconfig CDCACM
|
|||
default n
|
||||
select SERIAL_REMOVABLE
|
||||
select SERIAL_RXDMA if !CDCACM_DISABLE_RXBUF
|
||||
select SERIAL_TXDMA if !CDCACM_DISABLE_TXBUF
|
||||
---help---
|
||||
Enables USB Modem (CDC/ACM) support
|
||||
|
||||
|
|
@ -703,6 +704,28 @@ config CDCACM_RXBUFSIZE
|
|||
|
||||
endif # !CDCACM_DISABLE_RXBUF
|
||||
|
||||
config CDCACM_DISABLE_TXBUF
|
||||
bool "CDC/ACM use usb tx 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_TXBUF
|
||||
|
||||
config CDCACM_TXBUFSIZE
|
||||
int "Transmit buffer size"
|
||||
default 769 if USBDEV_DUALSPEED
|
||||
default 193 if !USBDEV_DUALSPEED
|
||||
---help---
|
||||
Size of the serial transmit 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 a TX buffer size of 769
|
||||
will hold one request of size 768; a buffer size of 193 will hold
|
||||
two requests of size 96 bytes.
|
||||
|
||||
endif # !CDCACM_DISABLE_TXBUF
|
||||
|
||||
if !CDCACM_COMPOSITE
|
||||
|
||||
# In a composite device the Vendor- and Product-ID is given by the composite
|
||||
|
|
|
|||
|
|
@ -135,7 +135,11 @@ struct cdcacm_dev_s
|
|||
#else
|
||||
char rxbuffer[CONFIG_CDCACM_RXBUFSIZE];
|
||||
#endif
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
FAR struct cdcacm_wrreq_s *wrcontainer;
|
||||
#else
|
||||
char txbuffer[CONFIG_CDCACM_TXBUFSIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The internal version of the class driver */
|
||||
|
|
@ -235,6 +239,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_TXBUF
|
||||
static void cdcuart_dmasend(FAR struct uart_dev_s *dev);
|
||||
#endif
|
||||
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
|
||||
static void cdcuart_dmareceive(FAR struct uart_dev_s *dev);
|
||||
#endif
|
||||
|
|
@ -280,8 +287,12 @@ static const struct uart_ops_s g_uartops =
|
|||
cdcuart_rxflowcontrol, /* rxflowcontrol */
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_TXDMA
|
||||
#ifndef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
cdcuart_dmasend, /* dmasend */
|
||||
#else
|
||||
NULL, /* dmasend */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_RXDMA
|
||||
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
|
||||
cdcuart_dmareceive, /* dmareceive */
|
||||
|
|
@ -395,12 +406,15 @@ static ssize_t cdcuart_sendbuf(FAR struct uart_dev_s *dev,
|
|||
|
||||
static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
FAR struct usbdev_ep_s *ep = priv->epbulkin;
|
||||
FAR struct uart_dev_s *dev = &priv->serdev;
|
||||
FAR struct cdcacm_wrreq_s *wrcontainer;
|
||||
FAR struct usbdev_req_s *req;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
irqstate_t flags;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FEATURES
|
||||
if (priv == NULL)
|
||||
|
|
@ -420,6 +434,7 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
|
|||
priv->serdev.xmit.head, priv->serdev.xmit.tail,
|
||||
priv->nwrq, sq_empty(&priv->txfree));
|
||||
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
if (priv->wrcontainer)
|
||||
{
|
||||
wrcontainer = priv->wrcontainer;
|
||||
|
|
@ -454,6 +469,12 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
|
|||
dev->xmit.tail = 0;
|
||||
uart_datasent(dev);
|
||||
}
|
||||
#else
|
||||
if (!sq_empty(&priv->txfree))
|
||||
{
|
||||
uart_xmitchars_dma(&priv->serdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
leave_critical_section(flags);
|
||||
|
|
@ -1113,7 +1134,9 @@ static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep,
|
|||
case OK: /* Normal completion */
|
||||
{
|
||||
usbtrace(TRACE_CLASSWRCOMPLETE, priv->nwrq);
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
if (priv->wrcontainer == NULL)
|
||||
#endif
|
||||
{
|
||||
cdcacm_sndpacket(priv);
|
||||
}
|
||||
|
|
@ -1348,11 +1371,13 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver,
|
|||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
priv->wrcontainer = (FAR struct cdcacm_wrreq_s *)
|
||||
sq_remfirst(&priv->txfree);
|
||||
priv->serdev.xmit.buffer = (FAR char *)priv->wrcontainer->req->buf;
|
||||
priv->serdev.xmit.size = reqlen + 1;
|
||||
priv->nwrq--;
|
||||
#endif
|
||||
|
||||
/* Report if we are selfpowered (unless we are part of a
|
||||
* composite device)
|
||||
|
|
@ -2153,7 +2178,9 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct cdcacm_dev_s *priv = inode->i_private;
|
||||
#if defined(CONFIG_CDCACM_DISABLE_TXBUF) || defined(CONFIG_CDCACM_DISABLE_RXBUF)
|
||||
FAR struct uart_dev_s *serdev = &priv->serdev;
|
||||
#endif
|
||||
int ret = OK;
|
||||
|
||||
switch (cmd)
|
||||
|
|
@ -2188,6 +2215,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
/* Get the number of bytes that have been written to the TX
|
||||
* buffer.
|
||||
*/
|
||||
|
|
@ -2256,6 +2284,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
*(FAR int *)((uintptr_t)arg) = count;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TCFLSH:
|
||||
{
|
||||
|
|
@ -2297,6 +2326,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
if (arg == TCOFLUSH || arg == TCIOFLUSH)
|
||||
{
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
|
@ -2330,6 +2360,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2871,11 +2902,17 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev)
|
|||
|
||||
/* When all of the allocated write requests have been returned to the
|
||||
* txfree, then there is no longer any TX data in flight.
|
||||
* dev->xmit.buffer always take one req, so just compare
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
/* dev->xmit.buffer always take one req, so just compare
|
||||
* CONFIG_CDCACM_NWRREQS - 1.
|
||||
*/
|
||||
|
||||
empty = priv->nwrq >= (CONFIG_CDCACM_NWRREQS - 1);
|
||||
#else
|
||||
empty = priv->nwrq >= CONFIG_CDCACM_NWRREQS;
|
||||
#endif
|
||||
leave_critical_section(flags);
|
||||
|
||||
return empty;
|
||||
|
|
@ -2903,6 +2940,63 @@ static int cdcuart_release(FAR struct uart_dev_s *dev)
|
|||
return OK;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cdcuart_dmasend
|
||||
*
|
||||
* Description:
|
||||
* Set up to transfer bytes from the TX circular buffer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cdcuart_dmasend(FAR struct uart_dev_s *dev)
|
||||
{
|
||||
FAR struct uart_dmaxfer_s *xfer = &dev->dmatx;
|
||||
FAR struct cdcacm_dev_s *priv = dev->priv;
|
||||
FAR struct usbdev_ep_s *ep = priv->epbulkin;
|
||||
FAR struct cdcacm_wrreq_s *wrcontainer;
|
||||
FAR struct usbdev_req_s *req;
|
||||
size_t nbytes;
|
||||
size_t reqlen;
|
||||
int ret;
|
||||
|
||||
/* Get the maximum number of bytes that will fit into one bulk IN request */
|
||||
|
||||
reqlen = MIN(CONFIG_CDCACM_BULKIN_REQLEN, ep->maxpacket);
|
||||
|
||||
/* Peek at the request in the container at the head of the list */
|
||||
|
||||
wrcontainer = (FAR struct cdcacm_wrreq_s *)sq_remfirst(&priv->txfree);
|
||||
req = wrcontainer->req;
|
||||
priv->nwrq--;
|
||||
|
||||
/* Fill the request with serial TX data */
|
||||
|
||||
nbytes = MIN(reqlen, xfer->length);
|
||||
memcpy(req->buf, xfer->buffer, nbytes);
|
||||
req->len = nbytes;
|
||||
|
||||
nbytes = MIN(reqlen - nbytes, xfer->nlength);
|
||||
memcpy(req->buf + req->len, xfer->nbuffer, nbytes);
|
||||
req->len += nbytes;
|
||||
xfer->nbytes = req->len;
|
||||
|
||||
uart_xmitchars_done(dev);
|
||||
|
||||
/* Then submit the request to the endpoint */
|
||||
|
||||
req->priv = wrcontainer;
|
||||
req->flags = USBDEV_REQFLAGS_NULLPKT;
|
||||
ret = EP_SUBMIT(ep, req);
|
||||
if (ret < 0)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL),
|
||||
(uint16_t)-ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -3168,6 +3262,10 @@ int cdcacm_classobject(int minor, FAR struct usbdev_devinfo_s *devinfo,
|
|||
#ifndef CONFIG_CDCACM_DISABLE_RXBUF
|
||||
priv->serdev.recv.size = CONFIG_CDCACM_RXBUFSIZE;
|
||||
priv->serdev.recv.buffer = priv->rxbuffer;
|
||||
#endif
|
||||
#ifndef CONFIG_CDCACM_DISABLE_TXBUF
|
||||
priv->serdev.xmit.size = CONFIG_CDCACM_TXBUFSIZE;
|
||||
priv->serdev.xmit.buffer = priv->txbuffer;
|
||||
#endif
|
||||
priv->serdev.ops = &g_uartops;
|
||||
priv->serdev.priv = priv;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue