drivers/usbdev: Add support for RX flow control to the CDC/ACM driver.
This commit is contained in:
parent
1604ae7ca7
commit
5e38ad28f4
@ -309,11 +309,18 @@ config CDCACM_CONSOLE
|
||||
config CDCACM_IFLOWCONTROL
|
||||
bool "CDC/ACM RTS flow control"
|
||||
default n
|
||||
depends on EXPERIMENTAL
|
||||
select SERIAL_IFLOWCONTROL
|
||||
---help---
|
||||
Enable CDC/ACM RTS flow control
|
||||
|
||||
config CDCACM_OFLOWCONTROL
|
||||
bool "CDC/ACM CTS flow control"
|
||||
default n
|
||||
depends on EXPERIMENTAL
|
||||
select SERIAL_OFLOWCONTROL
|
||||
---help---
|
||||
Enable CDC/ACM CTS flow control
|
||||
|
||||
menuconfig CDCACM_COMPOSITE
|
||||
bool "CDC/ACM composite support"
|
||||
default n
|
||||
|
@ -92,6 +92,9 @@ struct cdcacm_dev_s
|
||||
uint8_t nwrq; /* Number of queue write requests (in reqlist) */
|
||||
uint8_t nrdq; /* Number of queue read requests (in epbulkout) */
|
||||
uint8_t minor; /* The device minor number */
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
uint8_t serialstate; /* State of the DSR/DCD */
|
||||
#endif
|
||||
bool rxenabled; /* true: UART RX "interrupts" enabled */
|
||||
int16_t rxhead; /* Working head; used when rx int disabled */
|
||||
|
||||
@ -156,6 +159,12 @@ static struct usbdev_req_s *cdcacm_allocreq(FAR struct usbdev_ep_s *ep,
|
||||
static void cdcacm_freereq(FAR struct usbdev_ep_s *ep,
|
||||
FAR struct usbdev_req_s *req);
|
||||
|
||||
/* Flow Control ************************************************************/
|
||||
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
static int cdcacm_serialstate(FAR struct cdcacm_dev_s *priv);
|
||||
#endif
|
||||
|
||||
/* Configuration ***********************************************************/
|
||||
|
||||
static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv);
|
||||
@ -355,13 +364,13 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv)
|
||||
if (priv == NULL)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return -ENODEV;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Use our IN endpoint for the transfer */
|
||||
/* Use our bulk IN endpoint for the transfer */
|
||||
|
||||
ep = priv->epbulkin;
|
||||
|
||||
@ -588,6 +597,104 @@ static void cdcacm_freereq(FAR struct usbdev_ep_s *ep,
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cdcacm_serialstate
|
||||
*
|
||||
* Description:
|
||||
* Send the serial state message.
|
||||
*
|
||||
* 1. Format and send a request header with:
|
||||
*
|
||||
* bmRequestType:
|
||||
* USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
|
||||
* USB_REQ_RECIPIENT_INTERFACE
|
||||
* bRequest: ACM_SERIAL_STATE
|
||||
* wValue: 0
|
||||
* wIndex: 0
|
||||
* wLength: Length of data = 2
|
||||
*
|
||||
* 2. Followed by the notification data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
static int cdcacm_serialstate(FAR struct cdcacm_dev_s *priv)
|
||||
{
|
||||
FAR struct usbdev_ep_s *ep;
|
||||
FAR struct usbdev_req_s *req;
|
||||
FAR struct cdcacm_req_s *reqcontainer;
|
||||
FAR struct cdc_notification_s *notify;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
usbtrace(CDCACM_CLASSAPI_FLOWCONTROL, (uint16_t)priv->serialstate);
|
||||
|
||||
DEBUGASSERT(priv != NULL && priv->epintin != NULL);
|
||||
#ifdef CONFIG_DEBUG_FEATURES
|
||||
if (priv == NULL || priv->epintin == NULL)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Use our interrupt IN endpoint for the transfer */
|
||||
|
||||
ep = priv->epintin;
|
||||
|
||||
/* Remove the next container from the request list */
|
||||
|
||||
reqcontainer = (FAR struct cdcacm_req_s *)sq_remfirst(&priv->reqlist);
|
||||
if (reqcontainer == NULL)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_flags;
|
||||
}
|
||||
|
||||
/* Decrement the count of write requests */
|
||||
|
||||
priv->nwrq--;
|
||||
|
||||
/* Format the SerialState notifcation */
|
||||
|
||||
DEBUGASSERT(reqcontainer->req != NULL);
|
||||
req = reqcontainer->req;
|
||||
|
||||
DEBUGASSERT(req->buf != NULL);
|
||||
notify = (FAR struct cdc_notification_s *)req->buf;
|
||||
|
||||
notify->type = (USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
|
||||
USB_REQ_RECIPIENT_INTERFACE);
|
||||
notify->notification = ACM_SERIAL_STATE;
|
||||
notify->value[0] = 0;
|
||||
notify->value[1] = 0;
|
||||
notify->index[0] = 0;
|
||||
notify->index[1] = 0;
|
||||
notify->len[0] = 2;
|
||||
notify->len[1] = 0;
|
||||
notify->data[0] = priv->serialstate;
|
||||
notify->data[1] = 0;
|
||||
|
||||
/* Then submit the request to the endpoint */
|
||||
|
||||
req->len = SIZEOF_NOTIFICATION_S(2);
|
||||
req->priv = reqcontainer;
|
||||
req->flags = USBDEV_REQFLAGS_NULLPKT;
|
||||
ret = EP_SUBMIT(ep, req);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16_t)-ret);
|
||||
}
|
||||
|
||||
errout_with_flags:
|
||||
leave_critical_section(flags);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cdcacm_resetconfig
|
||||
*
|
||||
@ -661,7 +768,7 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config)
|
||||
if (priv == NULL)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return -EIO;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1274,7 +1381,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver,
|
||||
if (!driver || !dev || !ctrl)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return -EIO;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1805,7 +1912,7 @@ static int cdcuart_setup(FAR struct uart_dev_s *dev)
|
||||
if (!dev || !dev->priv)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return -EIO;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1941,7 +2048,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
case CAIOC_GETCTRLLINE:
|
||||
{
|
||||
FAR int *ptr = (FAR int *)((uintptr_t)arg);
|
||||
if (ptr)
|
||||
if (ptr != NULL)
|
||||
{
|
||||
*ptr = priv->ctrlline;
|
||||
}
|
||||
@ -1952,6 +2059,7 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
/* CAIOC_NOTIFY
|
||||
* Send a serial state to the host via the Interrupt IN endpoint.
|
||||
* Argument: int. This includes the current state of the carrier
|
||||
@ -1961,27 +2069,13 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
|
||||
case CAIOC_NOTIFY:
|
||||
{
|
||||
/* Not yet implemented. I probably won't bother to implement until
|
||||
* I comr up with a usage model that needs it.
|
||||
*
|
||||
* Here is what the needs to be done:
|
||||
*
|
||||
* 1. Format and send a request header with:
|
||||
*
|
||||
* bmRequestType:
|
||||
* USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
|
||||
* USB_REQ_RECIPIENT_INTERFACE
|
||||
* bRequest: ACM_SERIAL_STATE
|
||||
* wValue: 0
|
||||
* wIndex: 0
|
||||
* wLength: Length of data
|
||||
*
|
||||
* 2. Followed by the notification data (in a separate packet)
|
||||
*/
|
||||
DEBUGASSERT(arg < UINT8_MAX);
|
||||
|
||||
ret = -ENOSYS;
|
||||
priv->serialstate = (uint8_t)arg;
|
||||
ret = cdcacm_serialstate(priv);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_TERMIOS
|
||||
case TCGETS:
|
||||
@ -2231,13 +2325,48 @@ static bool cdcuart_rxflowcontrol(FAR struct uart_dev_s *dev,
|
||||
unsigned int nbuffered, bool upper)
|
||||
{
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
/* Allocate a request */
|
||||
/* Format the SerialState notification */
|
||||
/* Submit the request on the Interrupt IN endpoint */
|
||||
# warning Missing logic
|
||||
FAR struct cdcacm_dev_s *priv;
|
||||
int ret;
|
||||
|
||||
/* Sanity check */
|
||||
|
||||
#ifdef CONFIG_DEBUG_FEATURES
|
||||
if (dev == NULL || dev->priv == NULL)
|
||||
{
|
||||
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Extract reference to private data */
|
||||
|
||||
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
|
||||
* upper water mark has been crossed.
|
||||
*/
|
||||
|
||||
if (upper)
|
||||
{
|
||||
priv->serialstate &= ~CDCACM_UART_DSR;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->serialstate |= CDCACM_UART_DSR;
|
||||
}
|
||||
|
||||
/* Set DCD in any event */
|
||||
|
||||
priv->serialstate |= CDCACM_UART_DCD;
|
||||
|
||||
/* And send the SerialState message */
|
||||
|
||||
ret = cdcacm_serialstate(priv);
|
||||
return (ret >= 0 && upper);
|
||||
#else
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2376,22 +2505,28 @@ int cdcacm_classobject(int minor, FAR struct usbdev_devinfo_s *devinfo,
|
||||
memset(priv, 0, sizeof(struct cdcacm_dev_s));
|
||||
sq_init(&priv->reqlist);
|
||||
|
||||
priv->minor = minor;
|
||||
priv->minor = minor;
|
||||
|
||||
/* Save the caller provided device description (composite only) */
|
||||
|
||||
memcpy(&priv->devinfo, devinfo,
|
||||
sizeof(struct usbdev_devinfo_s));
|
||||
|
||||
#ifdef CONFIG_CDCACM_IFLOWCONTROL
|
||||
/* SerialState */
|
||||
|
||||
priv->serialstate = (CDCACM_UART_DCD | CDCACM_UART_DSR);
|
||||
#endif
|
||||
|
||||
/* Fake line status */
|
||||
|
||||
priv->linecoding.baud[0] = (115200) & 0xff; /* Baud=115200 */
|
||||
priv->linecoding.baud[1] = (115200 >> 8) & 0xff;
|
||||
priv->linecoding.baud[2] = (115200 >> 16) & 0xff;
|
||||
priv->linecoding.baud[3] = (115200 >> 24) & 0xff;
|
||||
priv->linecoding.stop = CDC_CHFMT_STOP1; /* One stop bit */
|
||||
priv->linecoding.parity = CDC_PARITY_NONE; /* No parity */
|
||||
priv->linecoding.nbits = 8; /* 8 data bits */
|
||||
priv->linecoding.baud[0] = (115200) & 0xff; /* Baud=115200 */
|
||||
priv->linecoding.baud[1] = (115200 >> 8) & 0xff;
|
||||
priv->linecoding.baud[2] = (115200 >> 16) & 0xff;
|
||||
priv->linecoding.baud[3] = (115200 >> 24) & 0xff;
|
||||
priv->linecoding.stop = CDC_CHFMT_STOP1; /* One stop bit */
|
||||
priv->linecoding.parity = CDC_PARITY_NONE; /* No parity */
|
||||
priv->linecoding.nbits = 8; /* 8 data bits */
|
||||
|
||||
/* Initialize the serial driver sub-structure */
|
||||
|
||||
|
@ -157,7 +157,6 @@
|
||||
#define CDCACM_LASTSTRID CDCACM_DATAIFSTRID
|
||||
#define CDCACM_NSTRIDS (CDCACM_LASTSTRID - CDCACM_STRBASE)
|
||||
|
||||
|
||||
/* Endpoint configuration ****************************************************/
|
||||
|
||||
#define CDCACM_MKEPINTIN(desc) (USB_DIR_IN | (desc)->epno[CDCACM_EP_INTIN_IDX])
|
||||
@ -202,6 +201,7 @@
|
||||
#define CDCACM_CLASSAPI_TXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXINT)
|
||||
#define CDCACM_CLASSAPI_TXREADY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXREADY)
|
||||
#define CDCACM_CLASSAPI_TXEMPTY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXEMPTY)
|
||||
#define CDCACM_CLASSAPI_FLOWCONTROL TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_FLOWCONTROL)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* drivers/usbdev/usbdev_strings.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2013, 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -68,6 +68,9 @@ const struct trace_msg_t g_usb_trace_strings_clsapi[] =
|
||||
TRACE_STR(USBSER_TRACECLASSAPI_TXINT),
|
||||
TRACE_STR(USBSER_TRACECLASSAPI_TXREADY),
|
||||
TRACE_STR(USBSER_TRACECLASSAPI_TXEMPTY),
|
||||
#if defined(CONFIG_CDCACM_IFLOWCONTROL)
|
||||
TRACE_STR(USBSER_TRACECLASSAPI_FLOWCONTROL),
|
||||
#endif
|
||||
#endif
|
||||
TRACE_STR_END
|
||||
};
|
||||
|
@ -84,6 +84,7 @@ static FAR const char *get_trstring(FAR const struct trace_msg_t *array,
|
||||
{
|
||||
return p->str;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
|
@ -419,6 +419,9 @@
|
||||
* 105 and RS-232 signal RTS.
|
||||
*/
|
||||
|
||||
#define CDCACM_UART_DTR CDC_DTE_PRESENT
|
||||
#define CDCACM_UART_RTS CDC_ACTIVATE_CARRIER
|
||||
|
||||
/* Table 58: Call State Value Definitions */
|
||||
|
||||
#define CDC_CALLST_IDLE 0x00 /* Call is idle */
|
||||
@ -543,6 +546,10 @@
|
||||
#define CDC_UART_OVERRUN (1 << 6) /* bOverRun Received data has been discarded due to
|
||||
* overrun in the device.
|
||||
*/
|
||||
|
||||
#define CDCACM_UART_DCD CDC_UART_RXCARRIER
|
||||
#define CDCACM_UART_DSR CDC_UART_TXCARRIER
|
||||
|
||||
/* Table 70: Call State Change Value Definitions */
|
||||
|
||||
#define CDC_CALLST_IDLE 0x01 /* Call has become idle */
|
||||
@ -871,6 +878,7 @@ struct cdc_notification_s
|
||||
uint8_t len[2]; /* wLength - length of variable data */
|
||||
uint8_t data[1]; /* Variable length data begins here */
|
||||
};
|
||||
#define SIZEOF_NOTIFICATION_S(n) (sizeof(struct cdc_notification_s) + (n) - 1)
|
||||
|
||||
/* Table 60: Unit Parameter Structure */
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/usb/usbdev_trace.h
|
||||
*
|
||||
* Copyright (C) 2008, 2009-2010, 2012-2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2008, 2009-2010, 2012-2013, 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -198,6 +198,7 @@
|
||||
#define USBSER_TRACECLASSAPI_TXINT 0x000a
|
||||
#define USBSER_TRACECLASSAPI_TXREADY 0x000b
|
||||
#define USBSER_TRACECLASSAPI_TXEMPTY 0x000c
|
||||
#define USBSER_TRACECLASSAPI_FLOWCONTROL 0x000d
|
||||
|
||||
/* Values of the class error ID used by the USB serial driver */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user