diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index ee7fc7e253..5d746b83f4 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -112,6 +112,9 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int uart_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int uart_unlink(FAR struct inode *inode); +#endif /**************************************************************************** * Public Function Prototypes @@ -129,15 +132,18 @@ int CONFIG_TTY_LAUNCH_ENTRYPOINT(int argc, char *argv[]); static const struct file_operations g_serialops = { - uart_open, /* open */ - uart_close, /* close */ - uart_read, /* read */ - uart_write, /* write */ - NULL, /* seek */ - uart_ioctl, /* ioctl */ - NULL, /* mmap */ - NULL, /* truncate */ - uart_poll /* poll */ + uart_open, /* open */ + uart_close, /* close */ + uart_read, /* read */ + uart_write, /* write */ + NULL, /* seek */ + uart_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + uart_poll /* poll */ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , uart_unlink /* unlink */ +#endif }; #ifdef CONFIG_TTY_LAUNCH @@ -725,6 +731,20 @@ static int uart_close(FAR struct file *filep) */ uart_reset_sem(dev); + + if (dev->unlinked) + { + nxmutex_unlock(&dev->closelock); + nxmutex_destroy(&dev->xmit.lock); + nxmutex_destroy(&dev->recv.lock); + nxmutex_destroy(&dev->closelock); + nxmutex_destroy(&dev->polllock); + nxsem_destroy(&dev->xmitsem); + nxsem_destroy(&dev->recvsem); + uart_release(dev); + return OK; + } + nxmutex_unlock(&dev->closelock); return OK; } @@ -1703,6 +1723,46 @@ errout: return ret; } +/**************************************************************************** + * Name: uart_unlink + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int uart_unlink(FAR struct inode *inode) +{ + FAR uart_dev_t *dev; + int ret; + + DEBUGASSERT(inode->i_private != NULL); + + dev = inode->i_private; + ret = nxmutex_lock(&dev->closelock); + if (ret < 0) + { + /* A signal received while waiting for the last close operation. */ + + return ret; + } + + if (dev->open_count <= 0) + { + nxmutex_unlock(&dev->closelock); + nxmutex_destroy(&dev->xmit.lock); + nxmutex_destroy(&dev->recv.lock); + nxmutex_destroy(&dev->closelock); + nxmutex_destroy(&dev->polllock); + nxsem_destroy(&dev->xmitsem); + nxsem_destroy(&dev->recvsem); + uart_release(dev); + return OK; + } + + dev->unlinked = true; + nxmutex_unlock(&dev->closelock); + return OK; +} +#endif + /**************************************************************************** * Name: uart_nxsched_foreach_cb ****************************************************************************/ diff --git a/drivers/usbdev/cdcacm.c b/drivers/usbdev/cdcacm.c index ea439d8ec7..dcf9cbf3ca 100644 --- a/drivers/usbdev/cdcacm.c +++ b/drivers/usbdev/cdcacm.c @@ -222,6 +222,7 @@ static bool cdcuart_rxflowcontrol(FAR struct uart_dev_s *dev, #endif static void cdcuart_txint(FAR struct uart_dev_s *dev, bool enable); static bool cdcuart_txempty(FAR struct uart_dev_s *dev); +static int cdcuart_release(FAR struct uart_dev_s *dev); /**************************************************************************** * Private Data @@ -272,7 +273,8 @@ static const struct uart_ops_s g_uartops = NULL, /* send */ cdcuart_txint, /* txinit */ NULL, /* txready */ - cdcuart_txempty /* txempty */ + cdcuart_txempty, /* txempty */ + cdcuart_release /* release */ }; /**************************************************************************** @@ -2800,6 +2802,28 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev) return priv->nwrq >= CONFIG_CDCACM_NWRREQS; } +/**************************************************************************** + * Name: cdcuart_release + * + * Description: + * This is called to release some resource about the device when device + * was close and unregistered. + * + ****************************************************************************/ + +static int cdcuart_release(FAR struct uart_dev_s *dev) +{ + FAR struct cdcacm_dev_s *priv = (FAR struct cdcacm_dev_s *)dev->priv; + + usbtrace(CDCACM_CLASSAPI_RELEASE, 0); + + /* And free the memory resources. */ + + wd_cancel(&priv->rxfailsafe); + kmm_free(priv); + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/usbdev/cdcacm.h b/drivers/usbdev/cdcacm.h index 6e97148ef8..00dfe6b581 100644 --- a/drivers/usbdev/cdcacm.h +++ b/drivers/usbdev/cdcacm.h @@ -181,6 +181,7 @@ #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) +#define CDCACM_CLASSAPI_RELEASE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RELEASE) /**************************************************************************** * Public Types diff --git a/include/nuttx/serial/serial.h b/include/nuttx/serial/serial.h index aa7f7ff4de..13e5fc28c3 100644 --- a/include/nuttx/serial/serial.h +++ b/include/nuttx/serial/serial.h @@ -88,6 +88,9 @@ #define uart_send(dev,ch) dev->ops->send(dev,ch) #define uart_receive(dev,s) dev->ops->receive(dev,s) +#define uart_release(dev) \ + ((dev)->ops->release ? (dev)->ops->release(dev) : -ENOSYS) + #ifdef CONFIG_SERIAL_TXDMA #define uart_dmasend(dev) \ ((dev)->ops->dmasend ? (dev)->ops->dmasend(dev) : -ENOSYS) @@ -254,6 +257,12 @@ struct uart_ops_s */ CODE bool (*txempty)(FAR struct uart_dev_s *dev); + + /* Call to release some resource about the device when device was close + * and unregistered. + */ + + CODE int (*release)(FAR struct uart_dev_s *dev); }; /* This is the device structure used by the driver. The caller of @@ -276,6 +285,7 @@ struct uart_dev_s volatile bool disconnected; /* true: Removable device is not connected */ #endif bool isconsole; /* true: This is the serial console */ + bool unlinked; /* true: This device driver has been unlinked. */ #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) || \ defined(CONFIG_TTY_FORCE_PANIC) || defined(CONFIG_TTY_LAUNCH) diff --git a/include/nuttx/usb/usbdev_trace.h b/include/nuttx/usb/usbdev_trace.h index 9246c44963..0993af5a0d 100644 --- a/include/nuttx/usb/usbdev_trace.h +++ b/include/nuttx/usb/usbdev_trace.h @@ -187,6 +187,7 @@ #define USBSER_TRACECLASSAPI_TXREADY 0x000b #define USBSER_TRACECLASSAPI_TXEMPTY 0x000c #define USBSER_TRACECLASSAPI_FLOWCONTROL 0x000d +#define USBSER_TRACECLASSAPI_RELEASE 0x000e /* Values of the class error ID used by the USB serial driver */