From 9f02eeadf890c80047fea2bb50905ac5ea43183d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 18 Aug 2022 11:19:46 -0700 Subject: [PATCH] serial: allow callback setting to be exclusive Both the IRQ API and Asynchronous API support callback. However, since they are both interrupt driven, having callbacks on both API would interfere with each other in almost all cases. So this adds a kconfig to signal that the callbacks should be exclusive to each other. In other words, if one is set, the other should not be active. Drivers implementing both APIs have been updated to remove the callbacks from the other API. Though, this still leaves the option to disable the kconfig and allows both APIs to have callbacks if one desires. Fixes #48606 Signed-off-by: Daniel Leung --- doc/hardware/peripherals/uart.rst | 9 +++++++++ drivers/serial/Kconfig | 15 +++++++++++++++ drivers/serial/uart_esp32.c | 10 ++++++++++ drivers/serial/uart_mcux_flexcomm.c | 11 +++++++++++ drivers/serial/uart_mcux_lpuart.c | 10 ++++++++++ drivers/serial/uart_nrfx_uart.c | 10 ++++++++++ drivers/serial/uart_nrfx_uarte.c | 10 ++++++++++ drivers/serial/uart_sam0.c | 10 ++++++++++ drivers/serial/uart_stm32.c | 10 ++++++++++ drivers/serial/uart_xmc4xxx.c | 11 +++++++++++ 10 files changed, 106 insertions(+) diff --git a/doc/hardware/peripherals/uart.rst b/doc/hardware/peripherals/uart.rst index b190dcbeea0..42906bca6fa 100644 --- a/doc/hardware/peripherals/uart.rst +++ b/doc/hardware/peripherals/uart.rst @@ -28,6 +28,15 @@ The Asynchronous API allows to read and write data in the background using DMA without interrupting the MCU at all. However, the setup is more complex than the other methods. +.. warning:: + + Interrupt-driven API and the Asynchronous API should NOT be used at + the same time, since both APIs require hardware interrupts to function + properly, using the callbacks for both APIs would result in interference + between each other. :kconfig:option:`CONFIG_UART_EXCLUSIVE_API_CALLBACKS` + is enabled by default so that only the callbacks associated with one API + is active at a time. + Configuration Options ********************* diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 405fda7d074..a803c152919 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -76,6 +76,21 @@ config UART_INTERRUPT_DRIVEN This option enables interrupt support for UART allowing console input and other UART based drivers. +config UART_EXCLUSIVE_API_CALLBACKS + bool "Use exclusive callbacks for multiple APIs" + depends on UART_ASYNC_API && UART_INTERRUPT_DRIVEN + default y + help + When multiple set of APIs support callbacks, enabling this + option will result in only the callbacks of one set of API + being active at a time. Setting a new callback to one set of + API will remove callbacks to other set of APIs. For example, + calling uart_callback_set() would disable the callback + previously set via uart_irq_callback_set(). + + Says yes unless you are absolutely sure you know what you are + doing and promise not to file bug when things do not work out. + config UART_LINE_CTRL bool "Serial Line Control API" help diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 380226dcfe6..a1054ba7d85 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -435,6 +435,11 @@ static void uart_esp32_irq_callback_set(const struct device *dev, uart_irq_callb data->irq_cb = cb; data->irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async.cb = NULL; + data->async.user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -662,6 +667,11 @@ static int uart_esp32_async_callback_set(const struct device *dev, uart_callback data->async.cb = callback; data->async.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->irq_cb = NULL; + data->irq_cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_mcux_flexcomm.c b/drivers/serial/uart_mcux_flexcomm.c index 041f690317d..4332b20cb91 100644 --- a/drivers/serial/uart_mcux_flexcomm.c +++ b/drivers/serial/uart_mcux_flexcomm.c @@ -279,6 +279,11 @@ static void mcux_flexcomm_irq_callback_set(const struct device *dev, data->irq_callback = cb; data->irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_callback = NULL; + data->async_cb_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -400,6 +405,12 @@ static int mcux_flexcomm_uart_callback_set(const struct device *dev, data->async_callback = callback; data->async_cb_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->irq_callback = NULL; + data->irq_cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index cdafa42d585..e1fe23ea322 100644 --- a/drivers/serial/uart_mcux_lpuart.c +++ b/drivers/serial/uart_mcux_lpuart.c @@ -370,6 +370,11 @@ static void mcux_lpuart_irq_callback_set(const struct device *dev, data->callback = cb; data->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async.user_callback = NULL; + data->async.user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -661,6 +666,11 @@ static int mcux_lpuart_callback_set(const struct device *dev, uart_callback_t ca data->async.user_callback = callback; data->async.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->callback = NULL; + data->cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_nrfx_uart.c b/drivers/serial/uart_nrfx_uart.c index 77efdd0050a..96cb190a487 100644 --- a/drivers/serial/uart_nrfx_uart.c +++ b/drivers/serial/uart_nrfx_uart.c @@ -405,6 +405,11 @@ static int uart_nrfx_callback_set(const struct device *dev, uart0_cb.callback = callback; uart0_cb.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + irq_callback = NULL; + irq_cb_data = NULL; +#endif + return 0; } @@ -923,6 +928,11 @@ static void uart_nrfx_irq_callback_set(const struct device *dev, (void)dev; irq_callback = cb; irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + uart0_cb.callback = NULL; + uart0_cb.user_data = NULL; +#endif } /** diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 047405b84c0..16877328e5f 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -937,6 +937,11 @@ static int uarte_nrfx_callback_set(const struct device *dev, data->async->user_callback = callback; data->async->user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->int_driven->cb = NULL; + data->int_driven->cb_data = NULL; +#endif + return 0; } @@ -1675,6 +1680,11 @@ static void uarte_nrfx_irq_callback_set(const struct device *dev, data->int_driven->cb = cb; data->int_driven->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async->user_callback = NULL; + data->async->user_data = NULL; +#endif } #endif /* UARTE_INTERRUPT_DRIVEN */ diff --git a/drivers/serial/uart_sam0.c b/drivers/serial/uart_sam0.c index 82676b4f85b..4f4407bdca9 100644 --- a/drivers/serial/uart_sam0.c +++ b/drivers/serial/uart_sam0.c @@ -935,6 +935,11 @@ static void uart_sam0_irq_callback_set(const struct device *dev, dev_data->cb = cb; dev_data->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + dev_data->async_cb = NULL; + dev_data->async_cb_data = NULL; +#endif } #endif @@ -949,6 +954,11 @@ static int uart_sam0_callback_set(const struct device *dev, dev_data->async_cb = callback; dev_data->async_cb_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + dev_data->cb = NULL; + dev_data->cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 45a16e9e893..23be4a9138c 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -904,6 +904,11 @@ static void uart_stm32_irq_callback_set(const struct device *dev, data->user_cb = cb; data->user_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_cb = NULL; + data->async_user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -1125,6 +1130,11 @@ static int uart_stm32_async_callback_set(const struct device *dev, data->async_cb = callback; data->async_user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->user_cb = NULL; + data->user_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_xmc4xxx.c b/drivers/serial/uart_xmc4xxx.c index 278e7bcfb10..40e33b9fa45 100644 --- a/drivers/serial/uart_xmc4xxx.c +++ b/drivers/serial/uart_xmc4xxx.c @@ -360,6 +360,11 @@ static void uart_xmc4xxx_irq_callback_set(const struct device *dev, data->user_cb = cb; data->user_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_cb = NULL; + data->async_user_data = NULL; +#endif } #define NVIC_ISPR_BASE 0xe000e200u @@ -599,6 +604,12 @@ static int uart_xmc4xxx_async_callback_set(const struct device *dev, uart_callba data->async_cb = callback; data->async_user_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->user_cb = NULL; + data->user_data = NULL; +#endif + return 0; }