From e24b0879183ed1351545fe6d395e35ec44219d07 Mon Sep 17 00:00:00 2001 From: Alexander Wachter Date: Sun, 16 Jan 2022 14:35:07 +0100 Subject: [PATCH] drivers: can: socketCAN: Move socket code to own file Move the code for socket instanciation from each driver to a generic driver, that makes an instance of a socketCAN net device for the chosen node. Signed-off-by: Alexander Wachter --- drivers/can/CMakeLists.txt | 1 + drivers/can/Kconfig | 15 +-- drivers/can/can_loopback.c | 38 -------- drivers/can/can_mcp2515.c | 35 ------- drivers/can/can_mcux_flexcan.c | 31 ------ drivers/can/can_socketcan.c | 161 +++++++++++++++++++++++++++++++ drivers/can/can_stm32.c | 70 -------------- drivers/can/socket_can_generic.h | 161 ------------------------------- 8 files changed, 171 insertions(+), 341 deletions(-) create mode 100644 drivers/can/can_socketcan.c delete mode 100644 drivers/can/socket_can_generic.h diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index ce0dddf4dcb..5160611bec4 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -16,5 +16,6 @@ zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c) zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) +zephyr_library_sources_ifdef(CONFIG_NET_SOCKETS_CAN can_socketcan.c) add_subdirectory(transceiver) diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index 5b96f876a83..e88e7cd321f 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -18,7 +18,7 @@ module-str = CAN source "subsys/logging/Kconfig.template.log_config" config CAN_INIT_PRIORITY - int "CAN init priority" + int "CAN driver init priority" default KERNEL_INIT_PRIORITY_DEVICE help CAN driver device initialization priority. @@ -66,14 +66,17 @@ config CANFD_MAX_DLC optimize memory consumption. endif # CAN_FD_MODE -config CAN_INIT_PRIORITY - int "CAN driver init priority" - default 80 +config CAN_SOCKETCAN_INIT_PRIORITY + int "socketCAN net device init priority" + default 81 + depends on NET_SOCKETS_CAN help - CAN device driver initialization priority. + socketCAN net device initialization priority. Do not mess with it unless you know what you are doing. Note that the priority needs to be lower than the net stack - so that it can start before the networking sub-system. + so that it can start before the networking sub-system, + and higher than the CAN driver so that it can use the underlaying + driver when starting. config CAN_RX_TIMESTAMP bool "Receiving timestamps" diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 0575925a6e2..36707219067 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -332,41 +332,3 @@ static int can_loopback_init(const struct device *dev) &can_loopback_driver_api); DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT) - -#if defined(CONFIG_NET_SOCKETS_CAN) -#include "socket_can_generic.h" - -#define CAN_LOOPBACK_SOCKET_CAN(inst) \ - static struct socket_can_context socket_can_context_##inst; \ - \ - static int socket_can_init_##inst(const struct device *dev) \ - { \ - const struct device *can_dev = DEVICE_DT_INST_GET(inst); \ - struct socket_can_context *socket_context = dev->data; \ - \ - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \ - dev, dev->name, can_dev, can_dev->name); \ - \ - socket_context->can_dev = can_dev; \ - socket_context->msgq = &socket_can_msgq; \ - \ - socket_context->rx_tid = \ - k_thread_create(&socket_context->rx_thread_data, \ - rx_thread_stack, \ - K_KERNEL_STACK_SIZEOF(rx_thread_stack), \ - rx_thread, socket_context, NULL, NULL, \ - RX_THREAD_PRIORITY, 0, K_NO_WAIT); \ - \ - return 0; \ - } \ - \ - NET_DEVICE_INIT(socket_can_loopback_##inst, SOCKET_CAN_NAME_##inst, \ - socket_can_init_##inst, NULL, \ - &socket_can_context_##inst, NULL, \ - CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \ - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \ - CAN_MTU); - -DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_SOCKET_CAN) - -#endif /* CONFIG_NET_SOCKETS_CAN */ diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index e5a59192c54..19f80f3638a 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -993,39 +993,4 @@ DEVICE_DT_INST_DEFINE(0, &mcp2515_init, NULL, &mcp2515_data_1, &mcp2515_config_1, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, &can_api_funcs); -#if defined(CONFIG_NET_SOCKETS_CAN) - -#include "socket_can_generic.h" - -static struct socket_can_context socket_can_context_1; - -static int socket_can_init(const struct device *dev) -{ - const struct device *can_dev = DEVICE_DT_INST_GET(1); - struct socket_can_context *socket_context = dev->data; - - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", - dev, dev->name, can_dev, can_dev->name); - - socket_context->can_dev = can_dev; - socket_context->msgq = &socket_can_msgq; - - socket_context->rx_tid = - k_thread_create(&socket_context->rx_thread_data, - rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, socket_context, NULL, NULL, - RX_THREAD_PRIORITY, 0, K_NO_WAIT); - - return 0; -} - -NET_DEVICE_INIT(socket_can_mcp2515_1, SOCKET_CAN_NAME_1, socket_can_init, - NULL, &socket_can_context_1, NULL, - CONFIG_CAN_INIT_PRIORITY, - &socket_can_api, - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); - -#endif - #endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */ diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 2914606e95a..23fe4916105 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -869,34 +869,3 @@ static const struct can_driver_api mcux_flexcan_driver_api = { } DT_INST_FOREACH_STATUS_OKAY(FLEXCAN_DEVICE_INIT_MCUX) - -#if defined(CONFIG_NET_SOCKETS_CAN) -#include "socket_can_generic.h" -#define FLEXCAN_DEVICE_SOCKET_CAN(id) \ - static struct socket_can_context socket_can_context_##id; \ - static int socket_can_init_##id(const struct device *dev) \ - { \ - const struct device *can_dev = DEVICE_DT_INST_GET(id); \ - struct socket_can_context *socket_context = dev->data; \ - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \ - dev, dev->name, can_dev, can_dev->name); \ - socket_context->can_dev = can_dev; \ - socket_context->msgq = &socket_can_msgq; \ - socket_context->rx_tid = \ - k_thread_create(&socket_context->rx_thread_data, \ - rx_thread_stack, \ - K_KERNEL_STACK_SIZEOF(rx_thread_stack), \ - rx_thread, socket_context, NULL, NULL, \ - RX_THREAD_PRIORITY, 0, K_NO_WAIT); \ - return 0; \ - } \ - \ - NET_DEVICE_INIT(socket_can_flexcan_##id, SOCKET_CAN_NAME_##id, \ - socket_can_init_##id, NULL, \ - &socket_can_context_##id, NULL, \ - CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \ - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \ - CAN_MTU); \ - -DT_INST_FOREACH_STATUS_OKAY(FLEXCAN_DEVICE_SOCKET_CAN) -#endif diff --git a/drivers/can/can_socketcan.c b/drivers/can/can_socketcan.c new file mode 100644 index 00000000000..25ab1197839 --- /dev/null +++ b/drivers/can/can_socketcan.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2019 Intel Corporation. + * Copyright (c) 2022 Alexander Wachter + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(can_socketcan, CONFIG_CAN_LOG_LEVEL); + +#define SEND_TIMEOUT K_MSEC(100) + +struct socketcan_context { + struct net_if *iface; +}; + +struct socketcan_config { + const struct device *can_dev; +}; + +static void socketcan_recv(const struct device *dev, struct zcan_frame *frame, void *arg) +{ + struct socketcan_context *ctx = (struct socketcan_context *)arg; + struct net_pkt *pkt; + int ret; + + ARG_UNUSED(dev); + + LOG_DBG("pkt on interface %p", ctx->iface); + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, sizeof(struct zcan_frame), + AF_CAN, 0, K_NO_WAIT); + if (pkt == NULL) { + LOG_ERR("Failed to obtain net_pkt"); + return; + } + + if (net_pkt_write(pkt, frame, sizeof(struct zcan_frame))) { + LOG_ERR("Failed to append RX data"); + net_pkt_unref(pkt); + return; + } + + ret = net_recv_data(ctx->iface, pkt); + if (ret < 0) { + LOG_DBG("net_recv_data failed [%d]", ret); + net_pkt_unref(pkt); + } +} + +static int socketcan_setsockopt(const struct device *dev, void *obj, int level, + int optname, const void *optval, socklen_t optlen) +{ + const struct socketcan_config *cfg = dev->config; + struct socketcan_context *socket_context = dev->data; + struct net_context *ctx = obj; + int ret; + + if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { + errno = EINVAL; + return -1; + } + + __ASSERT_NO_MSG(optlen == sizeof(struct zcan_filter)); + + ret = can_add_rx_filter(cfg->can_dev, socketcan_recv, socket_context, optval); + if (ret == -ENOSPC) { + errno = ENOSPC; + return -1; + } + + net_context_set_filter_id(ctx, ret); + + return 0; +} + +static void socketcan_close(const struct device *dev, int filter_id) +{ + const struct socketcan_config *cfg = dev->config; + + can_remove_rx_filter(cfg->can_dev, filter_id); +} + +static void socketcan_send_tx_callback(const struct device *dev, int error, void *arg) +{ + ARG_UNUSED(dev); + ARG_UNUSED(arg); + + if (error != 0) { + LOG_DBG("socket CAN TX error [%d]", error); + } +} + +static int socketcan_send(const struct device *dev, struct net_pkt *pkt) +{ + const struct socketcan_config *cfg = dev->config; + int ret; + + if (net_pkt_family(pkt) != AF_CAN) { + return -EPFNOSUPPORT; + } + + ret = can_send(cfg->can_dev, (struct zcan_frame *)pkt->frags->data, + SEND_TIMEOUT, socketcan_send_tx_callback, NULL); + + if (ret == 0) { + net_pkt_unref(pkt); + } else { + LOG_DBG("Cannot send socket CAN msg (%d)", ret); + } + + /* If something went wrong, then we need to return negative value to + * net_if.c:net_if_tx() so that the net_pkt will get released. + */ + return ret; +} + +static void socketcan_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct socketcan_context *socket_context = dev->data; + + socket_context->iface = iface; + + LOG_DBG("Init CAN interface %p dev %p", iface, dev); +} + +static int socketcan_init(const struct device *dev) +{ + const struct socketcan_config *cfg = dev->config; + + if (!device_is_ready(cfg->can_dev)) { + LOG_ERR("CAN device not ready"); + return -ENODEV; + } + + return 0; +} + +static struct canbus_api socketcan_api = { + .iface_api.init = socketcan_iface_init, + .send = socketcan_send, + .close = socketcan_close, + .setsockopt = socketcan_setsockopt, +}; + +static struct socketcan_context socketcan_ctx; + +static const struct socketcan_config socketcan_cfg = { + .can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)) +}; + +NET_DEVICE_INIT(socket_can, "SOCKET_CAN", socketcan_init, NULL, &socketcan_ctx, &socketcan_cfg, + CONFIG_CAN_SOCKETCAN_INIT_PRIORITY, &socketcan_api, CANBUS_RAW_L2, + NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); diff --git a/drivers/can/can_stm32.c b/drivers/can/can_stm32.c index c1567a083e6..724c9aede2b 100644 --- a/drivers/can/can_stm32.c +++ b/drivers/can/can_stm32.c @@ -1239,41 +1239,6 @@ static void config_can_1_irq(CAN_TypeDef *can) #endif /* CONFIG_CAN_STATS */ } -#if defined(CONFIG_NET_SOCKETS_CAN) - -#include "socket_can_generic.h" - -static struct socket_can_context socket_can_context_1; - -static int socket_can_init_1(const struct device *dev) -{ - const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(can1)); - struct socket_can_context *socket_context = dev->data; - - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", - dev, dev->name, can_dev, can_dev->name); - - socket_context->can_dev = can_dev; - socket_context->msgq = &socket_can_msgq; - - socket_context->rx_tid = - k_thread_create(&socket_context->rx_thread_data, - rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, socket_context, NULL, NULL, - RX_THREAD_PRIORITY, 0, K_NO_WAIT); - - return 0; -} - -NET_DEVICE_INIT(socket_can_stm32_1, SOCKET_CAN_NAME_1, socket_can_init_1, - NULL, &socket_can_context_1, NULL, - CONFIG_CAN_INIT_PRIORITY, - &socket_can_api, - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); - -#endif /* CONFIG_NET_SOCKETS_CAN */ - #endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) */ #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can2), st_stm32_can, okay) @@ -1335,39 +1300,4 @@ static void config_can_2_irq(CAN_TypeDef *can) #endif /* CONFIG_CAN_STATS */ } -#if defined(CONFIG_NET_SOCKETS_CAN) - -#include "socket_can_generic.h" - -static struct socket_can_context socket_can_context_2; - -static int socket_can_init_2(const struct device *dev) -{ - const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(can2)); - struct socket_can_context *socket_context = dev->data; - - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", - dev, dev->name, can_dev, can_dev->name); - - socket_context->can_dev = can_dev; - socket_context->msgq = &socket_can_msgq; - - socket_context->rx_tid = - k_thread_create(&socket_context->rx_thread_data, - rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, socket_context, NULL, NULL, - RX_THREAD_PRIORITY, 0, K_NO_WAIT); - - return 0; -} - -NET_DEVICE_INIT(socket_can_stm32_2, SOCKET_CAN_NAME_2, socket_can_init_2, - NULL, &socket_can_context_2, NULL, - CONFIG_CAN_INIT_PRIORITY, - &socket_can_api, - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); - -#endif /* CONFIG_NET_SOCKETS_CAN */ - #endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay) */ diff --git a/drivers/can/socket_can_generic.h b/drivers/can/socket_can_generic.h deleted file mode 100644 index c9c8dc1760c..00000000000 --- a/drivers/can/socket_can_generic.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -/* CANBUS related functions that are generic in all the drivers. */ - -#include -#include - -#ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ -#define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ - -#define SOCKET_CAN_NAME_0 "SOCKET_CAN_0" -#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1" -#define SOCKET_CAN_NAME_2 "SOCKET_CAN_2" -#define SEND_TIMEOUT K_MSEC(100) -#define RX_THREAD_STACK_SIZE 512 -#define RX_THREAD_PRIORITY 2 -#define BUF_ALLOC_TIMEOUT K_MSEC(50) - -/* TODO: make msgq size configurable */ -CAN_MSGQ_DEFINE(socket_can_msgq, 5); -K_KERNEL_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE); - -struct socket_can_context { - const struct device *can_dev; - struct net_if *iface; - struct k_msgq *msgq; - - /* TODO: remove the thread and push data to net directly from rx isr */ - k_tid_t rx_tid; - struct k_thread rx_thread_data; -}; - -static inline void socket_can_iface_init(struct net_if *iface) -{ - const struct device *dev = net_if_get_device(iface); - struct socket_can_context *socket_context = dev->data; - - socket_context->iface = iface; - - LOG_DBG("Init CAN interface %p dev %p", iface, dev); -} - -static inline void tx_irq_callback(const struct device *dev, int error, void *arg) -{ - char *caller_str = (char *)arg; - - ARG_UNUSED(dev); - - if (error != 0) { - LOG_DBG("TX error from %s! error-code: %d", - caller_str, error); - } -} - -/* This is called by net_if.c when packet is about to be sent */ -static inline int socket_can_send(const struct device *dev, - struct net_pkt *pkt) -{ - struct socket_can_context *socket_context = dev->data; - int ret; - - if (net_pkt_family(pkt) != AF_CAN) { - return -EPFNOSUPPORT; - } - - ret = can_send(socket_context->can_dev, - (struct zcan_frame *)pkt->frags->data, - SEND_TIMEOUT, tx_irq_callback, "socket_can_send"); - if (ret) { - LOG_DBG("Cannot send socket CAN msg (%d)", ret); - } - - /* If something went wrong, then we need to return negative value to - * net_if.c:net_if_tx() so that the net_pkt will get released. - */ - return -ret; -} - -static inline int socket_can_setsockopt(const struct device *dev, void *obj, - int level, int optname, - const void *optval, socklen_t optlen) -{ - struct socket_can_context *socket_context = dev->data; - struct net_context *ctx = obj; - int ret; - - if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { - errno = EINVAL; - return -1; - } - - __ASSERT_NO_MSG(optlen == sizeof(struct zcan_filter)); - - ret = can_add_rx_filter_msgq(socket_context->can_dev, socket_context->msgq, - optval); - if (ret == -ENOSPC) { - errno = ENOSPC; - return -1; - } - - net_context_set_filter_id(ctx, ret); - - return 0; -} - -static inline void socket_can_close(const struct device *dev, int filter_id) -{ - struct socket_can_context *socket_context = dev->data; - - can_remove_rx_filter(socket_context->can_dev, filter_id); -} - -static struct canbus_api socket_can_api = { - .iface_api.init = socket_can_iface_init, - .send = socket_can_send, - .close = socket_can_close, - .setsockopt = socket_can_setsockopt, -}; - -static inline void rx_thread(void *ctx, void *unused1, void *unused2) -{ - struct socket_can_context *socket_context = ctx; - struct net_pkt *pkt; - struct zcan_frame frame; - int ret; - - ARG_UNUSED(unused1); - ARG_UNUSED(unused2); - - while (1) { - k_msgq_get((struct k_msgq *)socket_context->msgq, &frame, - K_FOREVER); - - pkt = net_pkt_rx_alloc_with_buffer(socket_context->iface, - sizeof(frame), - AF_CAN, 0, - BUF_ALLOC_TIMEOUT); - if (!pkt) { - LOG_ERR("Failed to obtain RX buffer"); - continue; - } - - if (net_pkt_write(pkt, (void *)&frame, sizeof(frame))) { - LOG_ERR("Failed to append RX data"); - net_pkt_unref(pkt); - continue; - } - - ret = net_recv_data(socket_context->iface, pkt); - if (ret < 0) { - net_pkt_unref(pkt); - } - } -} - -#endif /* ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ */