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 <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2022-08-18 11:19:46 -07:00 committed by Fabio Baltieri
commit 9f02eeadf8
10 changed files with 106 additions and 0 deletions

View file

@ -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 without interrupting the MCU at all. However, the setup is more complex
than the other methods. 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 Configuration Options
********************* *********************

View file

@ -76,6 +76,21 @@ config UART_INTERRUPT_DRIVEN
This option enables interrupt support for UART allowing console This option enables interrupt support for UART allowing console
input and other UART based drivers. 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 config UART_LINE_CTRL
bool "Serial Line Control API" bool "Serial Line Control API"
help help

View file

@ -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 = cb;
data->irq_cb_data = cb_data; 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 */ #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.cb = callback;
data->async.user_data = user_data; 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; return 0;
} }

View file

@ -279,6 +279,11 @@ static void mcux_flexcomm_irq_callback_set(const struct device *dev,
data->irq_callback = cb; data->irq_callback = cb;
data->irq_cb_data = cb_data; 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 */ #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_callback = callback;
data->async_cb_data = user_data; 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; return 0;
} }

View file

@ -370,6 +370,11 @@ static void mcux_lpuart_irq_callback_set(const struct device *dev,
data->callback = cb; data->callback = cb;
data->cb_data = cb_data; 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 */ #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_callback = callback;
data->async.user_data = user_data; data->async.user_data = user_data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
data->callback = NULL;
data->cb_data = NULL;
#endif
return 0; return 0;
} }

View file

@ -405,6 +405,11 @@ static int uart_nrfx_callback_set(const struct device *dev,
uart0_cb.callback = callback; uart0_cb.callback = callback;
uart0_cb.user_data = user_data; uart0_cb.user_data = user_data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
irq_callback = NULL;
irq_cb_data = NULL;
#endif
return 0; return 0;
} }
@ -923,6 +928,11 @@ static void uart_nrfx_irq_callback_set(const struct device *dev,
(void)dev; (void)dev;
irq_callback = cb; irq_callback = cb;
irq_cb_data = cb_data; irq_cb_data = cb_data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
uart0_cb.callback = NULL;
uart0_cb.user_data = NULL;
#endif
} }
/** /**

View file

@ -937,6 +937,11 @@ static int uarte_nrfx_callback_set(const struct device *dev,
data->async->user_callback = callback; data->async->user_callback = callback;
data->async->user_data = user_data; 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; 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 = cb;
data->int_driven->cb_data = cb_data; 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 */ #endif /* UARTE_INTERRUPT_DRIVEN */

View file

@ -935,6 +935,11 @@ static void uart_sam0_irq_callback_set(const struct device *dev,
dev_data->cb = cb; dev_data->cb = cb;
dev_data->cb_data = cb_data; 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 #endif
@ -949,6 +954,11 @@ static int uart_sam0_callback_set(const struct device *dev,
dev_data->async_cb = callback; dev_data->async_cb = callback;
dev_data->async_cb_data = user_data; 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; return 0;
} }

View file

@ -904,6 +904,11 @@ static void uart_stm32_irq_callback_set(const struct device *dev,
data->user_cb = cb; data->user_cb = cb;
data->user_data = cb_data; 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 */ #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_cb = callback;
data->async_user_data = user_data; data->async_user_data = user_data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
data->user_cb = NULL;
data->user_data = NULL;
#endif
return 0; return 0;
} }

View file

@ -360,6 +360,11 @@ static void uart_xmc4xxx_irq_callback_set(const struct device *dev,
data->user_cb = cb; data->user_cb = cb;
data->user_data = user_data; 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 #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_cb = callback;
data->async_user_data = user_data; data->async_user_data = user_data;
#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS)
data->user_cb = NULL;
data->user_data = NULL;
#endif
return 0; return 0;
} }