From 34dea652d79fd8abc312bd5cf0d87c9f8888fb99 Mon Sep 17 00:00:00 2001 From: yangsong8 Date: Sat, 14 Sep 2024 14:39:43 +0800 Subject: [PATCH] driver/syslog: add cdcacm channel Use the CDCACM as a SYSLOG output device, send message to remote proc. If there are more than one CDCACM devices, then a device minor number may also need to be provided. Default: 0 Signed-off-by: yangsong8 --- drivers/syslog/Kconfig | 19 ++++++- drivers/syslog/syslog_channel.c | 58 ++++++++++++++++++++- drivers/usbdev/cdcacm.c | 89 +++++++++++++++++++++++++++++++++ include/nuttx/usb/cdcacm.h | 34 +++++++++++++ 4 files changed, 196 insertions(+), 4 deletions(-) diff --git a/drivers/syslog/Kconfig b/drivers/syslog/Kconfig index 7a5db1cee9a93..0c51edfab58db 100644 --- a/drivers/syslog/Kconfig +++ b/drivers/syslog/Kconfig @@ -259,6 +259,21 @@ config SYSLOG_RPMSG ---help--- Use the RPMSG as a SYSLOG output device, send message to remote proc. +config SYSLOG_CDCACM + bool "Log to CDCACM" + depends on CDCACM + default n + ---help--- + Use the CDCACM as a SYSLOG output device, send message to remote proc. + +config SYSLOG_CDCACM_MINOR + int "The syslog CDCACM minor number" + depends on SYSLOG_CDCACM + default 0 + ---help--- + If there are more than one CDCACM devices, then a device minor number + may also need to be provided. Default: 0 + config SYSLOG_STREAM bool "Log to stream" default n @@ -269,7 +284,7 @@ config SYSLOG_STREAM config SYSLOG_CONSOLE bool "Log to /dev/console" - default !ARCH_LOWPUTC && !SYSLOG_CHAR && !RAMLOG_SYSLOG && !SYSLOG_RPMSG && !SYSLOG_RTT + default !ARCH_LOWPUTC && !SYSLOG_CHAR && !RAMLOG_SYSLOG && !SYSLOG_RPMSG && !SYSLOG_RTT && !SYSLOG_CDCACM depends on DEV_CONSOLE select SYSLOG_REGISTER ---help--- @@ -277,7 +292,7 @@ config SYSLOG_CONSOLE config SYSLOG_DEFAULT bool "Default SYSLOG device" - default ARCH_LOWPUTC && !SYSLOG_CHAR && !RAMLOG_SYSLOG && !SYSLOG_RPMSG && !SYSLOG_RTT && !SYSLOG_CONSOLE + default ARCH_LOWPUTC && !SYSLOG_CHAR && !RAMLOG_SYSLOG && !SYSLOG_RPMSG && !SYSLOG_RTT && !SYSLOG_CDCACM && !SYSLOG_CONSOLE ---help--- syslog() interfaces will be present, but all output will go to the up_putc(ARCH_LOWPUTC == y) or bit-bucket(ARCH_LOWPUTC == n). diff --git a/drivers/syslog/syslog_channel.c b/drivers/syslog/syslog_channel.c index d3082a8ca9390..682039963ba0e 100644 --- a/drivers/syslog/syslog_channel.c +++ b/drivers/syslog/syslog_channel.c @@ -47,6 +47,10 @@ # include #endif +#ifdef CONFIG_SYSLOG_CDCACM +# include +#endif + #ifdef CONFIG_ARCH_LOWPUTC # include #endif @@ -57,13 +61,20 @@ * Private Function Prototypes ****************************************************************************/ -#if defined(CONFIG_SYSLOG_DEFAULT) +#ifdef CONFIG_SYSLOG_DEFAULT static int syslog_default_putc(FAR syslog_channel_t *channel, int ch); static ssize_t syslog_default_write(FAR syslog_channel_t *channel, FAR const char *buffer, size_t buflen); #endif +#ifdef CONFIG_SYSLOG_CDCACM +static int syslog_cdcacm_putc(FAR struct syslog_channel_s *channel, + int ch); +static ssize_t syslog_cdcacm_write(FAR struct syslog_channel_s *channel, + FAR const char *buffer, size_t buflen); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -133,6 +144,25 @@ static syslog_channel_t g_rtt_channel = }; #endif +#ifdef CONFIG_SYSLOG_CDCACM +static const struct syslog_channel_ops_s g_cdcacm_channel_ops = +{ + syslog_cdcacm_putc, + syslog_cdcacm_putc, + NULL, + syslog_cdcacm_write, + syslog_cdcacm_write +}; + +static struct syslog_channel_s g_cdcacm_channel = +{ + &g_cdcacm_channel_ops +# ifdef CONFIG_SYSLOG_IOCTL + , "cdcacm" +# endif +}; +#endif + #ifdef CONFIG_SYSLOG_DEFAULT static const struct syslog_channel_ops_s g_default_channel_ops = { @@ -206,7 +236,10 @@ g_syslog_channel[CONFIG_SYSLOG_MAX_CHANNELS] = &g_rpmsg_channel, #endif #ifdef CONFIG_SYSLOG_RTT - &g_rtt_channel + &g_rtt_channel, +#endif +#ifdef CONFIG_SYSLOG_CDCACM + &g_cdcacm_channel #endif }; @@ -296,6 +329,27 @@ static ssize_t syslog_default_write(FAR syslog_channel_t *channel, } #endif +#ifdef CONFIG_SYSLOG_CDCACM +static int syslog_cdcacm_putc(FAR struct syslog_channel_s *channel, int ch) +{ + char tmp; + + tmp = ch; + cdcacm_write(&tmp, 1); + + UNUSED(channel); + return ch; +} + +static ssize_t syslog_cdcacm_write(FAR struct syslog_channel_s *channel, + FAR const char *buffer, size_t buflen) +{ + UNUSED(channel); + + return cdcacm_write(buffer, buflen); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/drivers/usbdev/cdcacm.c b/drivers/usbdev/cdcacm.c index d3cc8a5ad383c..6042508bd9872 100644 --- a/drivers/usbdev/cdcacm.c +++ b/drivers/usbdev/cdcacm.c @@ -235,6 +235,10 @@ static void cdcuart_dmareceive(FAR struct uart_dev_s *dev); * Private Data ****************************************************************************/ +#ifdef CONFIG_SYSLOG_CDCACM +static FAR struct cdcacm_dev_s *g_syslog_cdcacm; +#endif + /* USB class device *********************************************************/ static const struct usbdevclass_driverops_s g_driverops = @@ -2775,6 +2779,76 @@ static void cdcuart_dmareceive(FAR struct uart_dev_s *dev) * Public Functions ****************************************************************************/ +#ifdef CONFIG_SYSLOG_CDCACM +/**************************************************************************** + * Name: cdcacm_write + * + * Description: + * This provides a cdcacm write method for syslog devices that support + * multiple byte writes + * + * Input Parameters: + * buffer - The buffer containing the data to be output + * buflen - The number of bytes in the buffer + * + * Returned Value: + * On success, the number of characters written is returned. A negated + * errno value is returned on any failure. + * + ****************************************************************************/ + +ssize_t cdcacm_write(FAR const char *buffer, size_t buflen) +{ + FAR struct cdcacm_dev_s *priv = g_syslog_cdcacm; + size_t len = 0; + + while (len < buflen) + { + irqstate_t flags; + + if (!priv || !priv->ctrlline) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + if (cdcuart_txready(&priv->serdev)) + { + ssize_t ret = cdcuart_sendbuf(&priv->serdev, + buffer + len, + buflen - len); + if (ret < 0) + { + leave_critical_section(flags); + return ret; + } + + len += ret; + } + + leave_critical_section(flags); + } + + return buflen; +} + +/**************************************************************************** + * Name: cdcacm_disable_syslog + * + * Description: + * Disable CDCACM syslog channel by clearing the globle pointer. + * This function is used in specific situation, such as must disable + * cdcacm log printing when usb re-enumeration. + * + ****************************************************************************/ + +void cdcacm_disable_syslog(void) +{ + g_syslog_cdcacm = NULL; +} +#endif + /**************************************************************************** * Name: cdcacm_classobject * @@ -2904,6 +2978,14 @@ int cdcacm_classobject(int minor, FAR struct usbdev_devinfo_s *devinfo, } *classdev = &drvr->drvr; + +#ifdef CONFIG_SYSLOG_CDCACM + if (minor == CONFIG_SYSLOG_CDCACM_MINOR) + { + g_syslog_cdcacm = priv; + } +#endif + return OK; errout_with_class: @@ -3019,6 +3101,13 @@ void cdcacm_uninitialize(FAR struct usbdevclass_driver_s *classdev) char devname[CDCACM_DEVNAME_SIZE]; int ret; +#ifdef CONFIG_SYSLOG_CDCACM + if (g_syslog_cdcacm == priv) + { + g_syslog_cdcacm = NULL; + } +#endif + /* Disconnect in case we are connected */ cdcacm_disconnect(classdev, priv->usbdev); diff --git a/include/nuttx/usb/cdcacm.h b/include/nuttx/usb/cdcacm.h index d703e146cab45..f495fc46e0884 100644 --- a/include/nuttx/usb/cdcacm.h +++ b/include/nuttx/usb/cdcacm.h @@ -423,6 +423,40 @@ struct composite_devdesc_s; void cdcacm_get_composite_devdesc(struct composite_devdesc_s *dev); #endif +/**************************************************************************** + * Name: cdcacm_write + * + * Description: + * This provides a cdcacm write method for syslog devices that support + * multiple byte writes. + * + * Input Parameters: + * buffer - The buffer containing the data to be output + * buflen - The number of bytes in the buffer + * + * Returned Value: + * On success, the number of characters written is returned. A negated + * errno value is returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SYSLOG_CDCACM +ssize_t cdcacm_write(FAR const char *buffer, size_t buflen); +#endif + +/**************************************************************************** + * Name: cdcacm_disable_syslog + * + * Description: + * Disable CDCACM syslog channel by clearing the globle pointer. + * This function is used in specific situation, such as must disable + * cdcacm log printing when usb re-enumeration. + * + ****************************************************************************/ +#ifdef CONFIG_SYSLOG_CDCACM +void cdcacm_disable_syslog(void); +#endif + #undef EXTERN #if defined(__cplusplus) }