drivers: can: provide default callback to can_send() if NULL
Provide a default, internal callback to CAN controller drivers
implementation of can_send() if no callback was provided by the caller.
This allows for simplifying the CAN driver implementations of can_send() as
these no longer need special handling for callback/no callback operation.
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
diff --git a/drivers/can/can_common.c b/drivers/can/can_common.c
index f34b22a..4eafb0f 100644
--- a/drivers/can/can_common.c
+++ b/drivers/can/can_common.c
@@ -17,6 +17,44 @@
/* CAN sync segment is always one time quantum */
#define CAN_SYNC_SEG 1
+struct can_tx_default_cb_ctx {
+ struct k_sem done;
+ int status;
+};
+
+static void can_tx_default_cb(const struct device *dev, int error, void *user_data)
+{
+ struct can_tx_default_cb_ctx *ctx = user_data;
+
+ ctx->status = error;
+ k_sem_give(&ctx->done);
+}
+
+int z_impl_can_send(const struct device *dev, const struct can_frame *frame,
+ k_timeout_t timeout, can_tx_callback_t callback,
+ void *user_data)
+{
+ const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
+
+ if (callback == NULL) {
+ struct can_tx_default_cb_ctx ctx;
+ int err;
+
+ k_sem_init(&ctx.done, 0, 1);
+
+ err = api->send(dev, frame, timeout, can_tx_default_cb, &ctx);
+ if (err != 0) {
+ return err;
+ }
+
+ k_sem_take(&ctx.done, K_FOREVER);
+
+ return ctx.status;
+ }
+
+ return api->send(dev, frame, timeout, callback, user_data);
+}
+
static void can_msgq_put(const struct device *dev, struct can_frame *frame, void *user_data)
{
struct k_msgq *msgq = (struct k_msgq *)user_data;
diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h
index 3f64bb6..419b720 100644
--- a/include/zephyr/drivers/can.h
+++ b/include/zephyr/drivers/can.h
@@ -348,6 +348,9 @@
/**
* @brief Callback API upon sending a CAN frame
* See @a can_send() for argument description
+ *
+ * @note From a driver perspective `callback` will never be `NULL` as a default callback will be
+ * provided if none is provided by the caller. This allows for simplifying the driver handling.
*/
typedef int (*can_send_t)(const struct device *dev,
const struct can_frame *frame,
@@ -1095,15 +1098,6 @@
k_timeout_t timeout, can_tx_callback_t callback,
void *user_data);
-static inline int z_impl_can_send(const struct device *dev, const struct can_frame *frame,
- k_timeout_t timeout, can_tx_callback_t callback,
- void *user_data)
-{
- const struct can_driver_api *api = (const struct can_driver_api *)dev->api;
-
- return api->send(dev, frame, timeout, callback, user_data);
-}
-
/** @} */
/**