aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/usbdev/cdcacm.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/usbdev/cdcacm.c')
-rw-r--r--nuttx/drivers/usbdev/cdcacm.c137
1 files changed, 127 insertions, 10 deletions
diff --git a/nuttx/drivers/usbdev/cdcacm.c b/nuttx/drivers/usbdev/cdcacm.c
index 97c9d7c77..cb8679976 100644
--- a/nuttx/drivers/usbdev/cdcacm.c
+++ b/nuttx/drivers/usbdev/cdcacm.c
@@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbdev/cdcacm.c
*
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -188,6 +188,12 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver,
size_t outlen);
static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev);
+#ifdef CONFIG_SERIAL_REMOVABLE
+static void cdcacm_suspend(FAR struct usbdevclass_driver_s *driver,
+ FAR struct usbdev_s *dev);
+static void cdcacm_resume(FAR struct usbdevclass_driver_s *driver,
+ FAR struct usbdev_s *dev);
+#endif
/* UART Operations **********************************************************/
@@ -211,8 +217,13 @@ static const struct usbdevclass_driverops_s g_driverops =
cdcacm_unbind, /* unbind */
cdcacm_setup, /* setup */
cdcacm_disconnect, /* disconnect */
+#ifdef CONFIG_SERIAL_REMOVABLE
+ cdcacm_suspend, /* suspend */
+ cdcacm_resume, /* resume */
+#else
NULL, /* suspend */
NULL, /* resume */
+#endif
};
/* Serial port **************************************************************/
@@ -570,6 +581,14 @@ static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv)
priv->config = CDCACM_CONFIGIDNONE;
+ /* Inform the "upper half" driver that there is no (functional) USB
+ * connection.
+ */
+
+#ifdef CONFIG_SERIAL_REMOVABLE
+ uart_connected(&priv->serdev, false);
+#endif
+
/* Disable endpoints. This should force completion of all pending
* transfers.
*/
@@ -731,10 +750,20 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config)
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-ret);
goto errout;
}
+
priv->nrdq++;
}
+ /* We are successfully configured */
+
priv->config = config;
+
+ /* Inform the "upper half" driver that we are "open for business" */
+
+#ifdef CONFIG_SERIAL_REMOVABLE
+ uart_connected(&priv->serdev, true);
+#endif
+
return OK;
errout:
@@ -823,6 +852,7 @@ static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep,
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-req->result);
}
+
irqrestore(flags);
}
@@ -932,6 +962,7 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver,
ret = -ENOMEM;
goto errout;
}
+
priv->ctrlreq->callback = cdcacm_ep0incomplete;
/* Pre-allocate all endpoints... the endpoints will not be functional
@@ -1575,12 +1606,20 @@ static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver,
}
#endif
- /* Reset the configuration */
+ /* Inform the "upper half serial driver that we have lost the USB serial
+ * connection.
+ */
flags = irqsave();
+#ifdef CONFIG_SERIAL_REMOVABLE
+ uart_connected(&priv->serdev, false);
+#endif
+
+ /* Reset the configuration */
+
cdcacm_resetconfig(priv);
- /* Clear out all data in the circular buffer */
+ /* Clear out all outgoing data in the circular buffer */
priv->serdev.xmit.head = 0;
priv->serdev.xmit.tail = 0;
@@ -1596,6 +1635,79 @@ static void cdcacm_disconnect(FAR struct usbdevclass_driver_s *driver,
}
/****************************************************************************
+ * Name: cdcacm_suspend
+ *
+ * Description:
+ * Handle the USB suspend event.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SERIAL_REMOVABLE
+static void cdcacm_suspend(FAR struct usbdevclass_driver_s *driver,
+ FAR struct usbdev_s *dev)
+{
+ FAR struct cdcacm_dev_s *priv;
+
+ usbtrace(TRACE_CLASSSUSPEND, 0);
+
+#ifdef CONFIG_DEBUG
+ if (!driver || !dev)
+ {
+ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+ return;
+ }
+#endif
+
+ /* Extract reference to private data */
+
+ priv = ((FAR struct cdcacm_driver_s*)driver)->dev;
+
+ /* And let the "upper half" driver now that we are suspended */
+
+ uart_connected(&priv->serdev, false);
+}
+#endif
+
+/****************************************************************************
+ * Name: cdcacm_resume
+ *
+ * Description:
+ * Handle the USB resume event.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SERIAL_REMOVABLE
+static void cdcacm_resume(FAR struct usbdevclass_driver_s *driver,
+ FAR struct usbdev_s *dev)
+{
+ FAR struct cdcacm_dev_s *priv;
+
+ usbtrace(TRACE_CLASSRESUME, 0);
+
+#ifdef CONFIG_DEBUG
+ if (!driver || !dev)
+ {
+ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
+ return;
+ }
+#endif
+
+ /* Extract reference to private data */
+
+ priv = ((FAR struct cdcacm_driver_s*)driver)->dev;
+
+ /* Are we still configured? */
+
+ if (priv->config != CDCACM_CONFIGIDNONE)
+ {
+ /* Yes.. let the "upper half" know that have resumed */
+
+ uart_connected(&priv->serdev, true);
+ }
+}
+#endif
+
+/****************************************************************************
* Serial Device Methods
****************************************************************************/
@@ -2045,12 +2157,17 @@ int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev)
/* Initialize the serial driver sub-structure */
- priv->serdev.recv.size = CONFIG_CDCACM_RXBUFSIZE;
- priv->serdev.recv.buffer = priv->rxbuffer;
- priv->serdev.xmit.size = CONFIG_CDCACM_TXBUFSIZE;
- priv->serdev.xmit.buffer = priv->txbuffer;
- priv->serdev.ops = &g_uartops;
- priv->serdev.priv = priv;
+ /* The initial state is disconnected */
+
+#ifdef CONFIG_SERIAL_REMOVABLE
+ priv->serdev.disconnected = true;
+#endif
+ priv->serdev.recv.size = CONFIG_CDCACM_RXBUFSIZE;
+ priv->serdev.recv.buffer = priv->rxbuffer;
+ priv->serdev.xmit.size = CONFIG_CDCACM_TXBUFSIZE;
+ priv->serdev.xmit.buffer = priv->txbuffer;
+ priv->serdev.ops = &g_uartops;
+ priv->serdev.priv = priv;
/* Initialize the USB class driver structure */
@@ -2148,7 +2265,7 @@ int cdcacm_initialize(int minor, FAR void **handle)
*
* Description:
* Un-initialize the USB storage class driver. This function is used
- * internally by the USB composite driver to unitialized the CDC/ACM
+ * internally by the USB composite driver to unitialize the CDC/ACM
* driver. This same interface is available (with an untyped input
* parameter) when the CDC/ACM driver is used standalone.
*