cdcacm: support polling mode in order to work normally in interrupt

Signed-off-by: yangsong8 <yangsong8@xiaomi.com>
This commit is contained in:
yangsong8 2024-08-02 12:02:45 +08:00 committed by Xiang Xiao
parent 7d570182be
commit 6c71276359

View file

@ -103,7 +103,7 @@ struct cdcacm_dev_s
bool upper; /* True: RX buffer is (nearly) full */ bool upper; /* True: RX buffer is (nearly) full */
#endif #endif
bool rxenabled; /* true: UART RX "interrupts" enabled */ bool rxenabled; /* true: UART RX "interrupts" enabled */
bool issending; bool ispolling;
struct cdc_linecoding_s linecoding; /* Buffered line status */ struct cdc_linecoding_s linecoding; /* Buffered line status */
cdcacm_callback_t callback; /* Serial event callback function */ cdcacm_callback_t callback; /* Serial event callback function */
@ -293,6 +293,14 @@ static const struct uart_ops_s g_uartops =
static bool cdcuart_txready(FAR struct uart_dev_s *dev) static bool cdcuart_txready(FAR struct uart_dev_s *dev)
{ {
FAR struct cdcacm_dev_s *priv = dev->priv; FAR struct cdcacm_dev_s *priv = dev->priv;
FAR struct usbdev_ep_s *ep = priv->epbulkin;
if (sq_empty(&priv->txfree))
{
priv->ispolling = true;
EP_POLL(ep);
priv->ispolling = false;
}
return !sq_empty(&priv->txfree); return !sq_empty(&priv->txfree);
} }
@ -337,7 +345,9 @@ static ssize_t cdcuart_sendbuf(FAR struct uart_dev_s *dev,
req->len = nbytes; req->len = nbytes;
req->priv = wrcontainer; req->priv = wrcontainer;
req->flags = USBDEV_REQFLAGS_NULLPKT; req->flags = USBDEV_REQFLAGS_NULLPKT;
priv->ispolling = true;
ret = EP_SUBMIT(ep, req); ret = EP_SUBMIT(ep, req);
priv->ispolling = false;
if (ret < 0) if (ret < 0)
{ {
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL),
@ -372,14 +382,10 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
#endif #endif
flags = enter_critical_section(); flags = enter_critical_section();
if (priv->issending) if (priv->ispolling)
{ {
goto out; goto out;
} }
else
{
priv->issending = true;
}
uinfo("head=%d tail=%d nwrq=%d empty=%d\n", uinfo("head=%d tail=%d nwrq=%d empty=%d\n",
priv->serdev.xmit.head, priv->serdev.xmit.tail, priv->serdev.xmit.head, priv->serdev.xmit.tail,
@ -390,8 +396,6 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
uart_xmitchars_dma(&priv->serdev); uart_xmitchars_dma(&priv->serdev);
} }
priv->issending = false;
out: out:
leave_critical_section(flags); leave_critical_section(flags);
return OK; return OK;
@ -408,6 +412,14 @@ out:
static bool cdcuart_rxavailable(FAR struct uart_dev_s *dev) static bool cdcuart_rxavailable(FAR struct uart_dev_s *dev)
{ {
FAR struct cdcacm_dev_s *priv = dev->priv; FAR struct cdcacm_dev_s *priv = dev->priv;
FAR struct usbdev_ep_s *ep = priv->epbulkout;
if (sq_empty(&priv->rxpending))
{
priv->ispolling = true;
EP_POLL(ep);
priv->ispolling = false;
}
return !sq_empty(&priv->rxpending); return !sq_empty(&priv->rxpending);
} }
@ -519,6 +531,11 @@ static int cdcacm_release_rxpending(FAR struct cdcacm_dev_s *priv)
flags = enter_critical_section(); flags = enter_critical_section();
if (priv->ispolling)
{
goto out;
}
/* Cancel any pending failsafe timer */ /* Cancel any pending failsafe timer */
wd_cancel(&priv->rxfailsafe); wd_cancel(&priv->rxfailsafe);
@ -568,6 +585,7 @@ static int cdcacm_release_rxpending(FAR struct cdcacm_dev_s *priv)
cdcacm_rxtimeout, (wdparm_t)priv); cdcacm_rxtimeout, (wdparm_t)priv);
} }
out:
leave_critical_section(flags); leave_critical_section(flags);
return ret; return ret;
} }
@ -2647,6 +2665,9 @@ static void cdcuart_txint(FAR struct uart_dev_s *dev, bool enable)
static bool cdcuart_txempty(FAR struct uart_dev_s *dev) static bool cdcuart_txempty(FAR struct uart_dev_s *dev)
{ {
FAR struct cdcacm_dev_s *priv = (FAR struct cdcacm_dev_s *)dev->priv; FAR struct cdcacm_dev_s *priv = (FAR struct cdcacm_dev_s *)dev->priv;
FAR struct usbdev_ep_s *ep = priv->epbulkin;
irqstate_t flags;
bool empty;
usbtrace(CDCACM_CLASSAPI_TXEMPTY, 0); usbtrace(CDCACM_CLASSAPI_TXEMPTY, 0);
@ -2658,11 +2679,19 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev)
} }
#endif #endif
flags = enter_critical_section();
priv->ispolling = true;
EP_POLL(ep);
priv->ispolling = false;
/* When all of the allocated write requests have been returned to the /* When all of the allocated write requests have been returned to the
* txfree, then there is no longer any TX data in flight. * txfree, then there is no longer any TX data in flight.
*/ */
return priv->nwrq >= CONFIG_CDCACM_NWRREQS; empty = priv->nwrq >= CONFIG_CDCACM_NWRREQS;
leave_critical_section(flags);
return empty;
} }
/**************************************************************************** /****************************************************************************