drivers/usbdev: Add support for flow control TERMIOs in CDC/ACM driver
This commit is contained in:
parent
b065b1f5df
commit
5d02baf205
@ -85,8 +85,8 @@ struct cdcacm_req_s
|
|||||||
|
|
||||||
struct cdcacm_dev_s
|
struct cdcacm_dev_s
|
||||||
{
|
{
|
||||||
FAR struct uart_dev_s serdev; /* Serial device structure */
|
FAR struct uart_dev_s serdev; /* Serial device structure */
|
||||||
FAR struct usbdev_s *usbdev; /* usbdev driver pointer */
|
FAR struct usbdev_s *usbdev; /* usbdev driver pointer */
|
||||||
|
|
||||||
uint8_t config; /* Configuration number */
|
uint8_t config; /* Configuration number */
|
||||||
uint8_t nwrq; /* Number of queue write requests (in reqlist) */
|
uint8_t nwrq; /* Number of queue write requests (in reqlist) */
|
||||||
@ -94,19 +94,21 @@ struct cdcacm_dev_s
|
|||||||
uint8_t minor; /* The device minor number */
|
uint8_t minor; /* The device minor number */
|
||||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||||
uint8_t serialstate; /* State of the DSR/DCD */
|
uint8_t serialstate; /* State of the DSR/DCD */
|
||||||
|
bool iflow; /* True: input flow control is enabled */
|
||||||
|
bool upper; /* True: RX buffer is (nearly) full */
|
||||||
#endif
|
#endif
|
||||||
bool rxenabled; /* true: UART RX "interrupts" enabled */
|
bool rxenabled; /* true: UART RX "interrupts" enabled */
|
||||||
int16_t rxhead; /* Working head; used when rx int disabled */
|
int16_t rxhead; /* Working head; used when rx int disabled */
|
||||||
|
|
||||||
uint8_t ctrlline; /* Buffered control line state */
|
uint8_t ctrlline; /* Buffered control line state */
|
||||||
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 */
|
||||||
|
|
||||||
FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */
|
FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */
|
||||||
FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */
|
FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */
|
||||||
FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */
|
FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */
|
||||||
FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */
|
FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */
|
||||||
struct sq_queue_s reqlist; /* List of write request containers */
|
struct sq_queue_s reqlist; /* List of write request containers */
|
||||||
|
|
||||||
struct usbdev_devinfo_s devinfo;
|
struct usbdev_devinfo_s devinfo;
|
||||||
|
|
||||||
@ -2106,12 +2108,26 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
termiosp->c_iflag = serdev->tc_iflag;
|
termiosp->c_iflag = serdev->tc_iflag;
|
||||||
termiosp->c_oflag = serdev->tc_oflag;
|
termiosp->c_oflag = serdev->tc_oflag;
|
||||||
termiosp->c_lflag = serdev->tc_lflag;
|
termiosp->c_lflag = serdev->tc_lflag;
|
||||||
|
termiosp->c_cflag = CS8;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CDCACM_OFLOWCONTROL
|
||||||
|
/* Report state of output flow control */
|
||||||
|
# warning Missing logic
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||||
|
/* Report state of input flow control */
|
||||||
|
|
||||||
|
termiosp->c_lflag = (priv->iflow) ? CRTS_IFLOW : 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCSETS:
|
case TCSETS:
|
||||||
{
|
{
|
||||||
struct termios *termiosp = (FAR struct termios *)arg;
|
struct termios *termiosp = (FAR struct termios *)arg;
|
||||||
|
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||||
|
bool iflow;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!termiosp)
|
if (!termiosp)
|
||||||
{
|
{
|
||||||
@ -2124,6 +2140,46 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
serdev->tc_iflag = termiosp->c_iflag;
|
serdev->tc_iflag = termiosp->c_iflag;
|
||||||
serdev->tc_oflag = termiosp->c_oflag;
|
serdev->tc_oflag = termiosp->c_oflag;
|
||||||
serdev->tc_lflag = termiosp->c_lflag;
|
serdev->tc_lflag = termiosp->c_lflag;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CDCACM_OFLOWCONTROL
|
||||||
|
/* Handle changes to output flow control */
|
||||||
|
# warning Missing logic
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||||
|
/* Handle changes to input flow control */
|
||||||
|
|
||||||
|
iflow = ((termiosp->c_cflag & CRTS_IFLOW) != 0);
|
||||||
|
if (iflow != priv->iflow)
|
||||||
|
{
|
||||||
|
/* The input flow control state has changed. Save the new
|
||||||
|
* flow control setting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
priv->iflow = iflow;
|
||||||
|
|
||||||
|
/* If flow control has been disabled, then we will need to
|
||||||
|
* make sure that DSR is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!iflow && (priv->serialstate & CDCACM_UART_DSR) == 0)
|
||||||
|
{
|
||||||
|
priv->serialstate |= (CDCACM_UART_DSR | CDCACM_UART_DCD);
|
||||||
|
ret = cdcacm_serialstate(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If flow control has been enabled and the RX buffer is already
|
||||||
|
* (nearly) full, the we need to make sure the DSR is clear.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (priv->upper)
|
||||||
|
{
|
||||||
|
priv->serialstate &= ~CDCACM_UART_DSR;
|
||||||
|
priv->serialstate |= CDCACM_UART_DCD;
|
||||||
|
ret = cdcacm_serialstate(priv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -2339,6 +2395,7 @@ static bool cdcuart_rxflowcontrol(FAR struct uart_dev_s *dev,
|
|||||||
{
|
{
|
||||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||||
FAR struct cdcacm_dev_s *priv;
|
FAR struct cdcacm_dev_s *priv;
|
||||||
|
uint8_t mask;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
@ -2355,27 +2412,55 @@ static bool cdcuart_rxflowcontrol(FAR struct uart_dev_s *dev,
|
|||||||
|
|
||||||
priv = (FAR struct cdcacm_dev_s *)dev->priv;
|
priv = (FAR struct cdcacm_dev_s *)dev->priv;
|
||||||
|
|
||||||
/* Set DSR (TX carrier) if the lower water mark has been crossed or clear it if the
|
/* Is input flow control enabled? */
|
||||||
* upper water mark has been crossed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (upper)
|
priv->upper = upper;
|
||||||
|
if (priv->iflow)
|
||||||
{
|
{
|
||||||
priv->serialstate &= ~CDCACM_UART_DSR;
|
/* Yes.. Set DSR (TX carrier) if the lower water mark has been crossed
|
||||||
|
* or clear it if the upper water mark has been crossed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mask = upper ? 0 : CDCACM_UART_DSR;
|
||||||
|
|
||||||
|
/* Don't do anything unless this results in a change in the setting of
|
||||||
|
* DSR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((priv->serialstate ^ mask) & CDCACM_UART_DSR) != 0)
|
||||||
|
{
|
||||||
|
/* Set or clear DSR (set DCD in any case). */
|
||||||
|
|
||||||
|
priv->serialstate &= ~CDCACM_UART_DSR;
|
||||||
|
priv->serialstate |= (mask | CDCACM_UART_DCD);
|
||||||
|
|
||||||
|
/* And send the SerialState message */
|
||||||
|
|
||||||
|
ret = cdcacm_serialstate(priv);
|
||||||
|
return (ret >= 0 && upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true of DSR is not set */
|
||||||
|
|
||||||
|
return ((priv->serialstate & CDCACM_UART_DSR) == 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
priv->serialstate |= CDCACM_UART_DSR;
|
/* Flow control is disabled ... DSR must be set */
|
||||||
|
|
||||||
|
if ((priv->serialstate & CDCACM_UART_DSR) == 0)
|
||||||
|
{
|
||||||
|
/* Set DSR and DCD */
|
||||||
|
|
||||||
|
priv->serialstate |= (CDCACM_UART_DSR | CDCACM_UART_DCD);
|
||||||
|
|
||||||
|
/* And send the SerialState message */
|
||||||
|
|
||||||
|
(void)cdcacm_serialstate(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set DCD in any event */
|
|
||||||
|
|
||||||
priv->serialstate |= CDCACM_UART_DCD;
|
|
||||||
|
|
||||||
/* And send the SerialState message */
|
|
||||||
|
|
||||||
ret = cdcacm_serialstate(priv);
|
|
||||||
return (ret >= 0 && upper);
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user