diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index 04f6637a9e1..266f3285b11 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -58,10 +58,6 @@ if(CONFIG_SENSING) zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) endif() -if(CONFIG_UART_MUX) - zephyr_iterable_section(NAME uart_mux GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN CONFIG_LINKER_ITERABLE_SUBALIGN) -endif() - if(CONFIG_USB_DEVICE_STACK) zephyr_linker_section(NAME usb_descriptor GROUP DATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} SUBALIGN 1) zephyr_linker_section_configure(SECTION usb_descriptor diff --git a/drivers/console/CMakeLists.txt b/drivers/console/CMakeLists.txt index 8e5e26aaabc..b31486dee42 100644 --- a/drivers/console/CMakeLists.txt +++ b/drivers/console/CMakeLists.txt @@ -1,13 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_syscall_header_ifdef( - CONFIG_UART_MUX - ${ZEPHYR_BASE}/include/zephyr/drivers/console/uart_mux.h -) - zephyr_library() -zephyr_library_sources_ifdef(CONFIG_GSM_MUX gsm_mux.c) zephyr_library_sources_ifdef(CONFIG_IPM_CONSOLE_RECEIVER ipm_console_receiver.c) zephyr_library_sources_ifdef(CONFIG_IPM_CONSOLE_SENDER ipm_console_sender.c) zephyr_library_sources_ifdef(CONFIG_IPM_CONSOLE ipm_console.c) @@ -18,7 +12,6 @@ zephyr_library_sources_ifdef(CONFIG_RTT_CONSOLE rtt_console.c) zephyr_library_sources_ifdef(CONFIG_SEMIHOST_CONSOLE semihost_console.c) zephyr_library_sources_ifdef(CONFIG_UART_CONSOLE uart_console.c) zephyr_library_sources_ifdef(CONFIG_UART_MCUMGR uart_mcumgr.c) -zephyr_library_sources_ifdef(CONFIG_UART_MUX uart_mux.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_SIM_CONSOLE xtensa_sim_console.c) zephyr_library_sources_ifdef(CONFIG_EFI_CONSOLE efi_console.c) zephyr_library_sources_ifdef(CONFIG_WINSTREAM_CONSOLE winstream_console.c) diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 28dcf9fbc16..6acef7a63dd 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -34,7 +34,6 @@ config CONSOLE_HANDLER config CONSOLE_INIT_PRIORITY int "Console init priority" - default 95 if UART_MUX default 60 if UART_CONSOLE || XTENSA_SIM_CONSOLE default KERNEL_INIT_PRIORITY_DEFAULT help @@ -254,84 +253,6 @@ module = UART_CONSOLE module-str = UART console source "subsys/logging/Kconfig.template.log_config" -source "drivers/console/Kconfig.gsm_mux" - -config UART_MUX - bool "[DEPRECATED] UART muxing (GSM 07.10) support [EXPERIMENTAL]" - depends on SERIAL_SUPPORT_INTERRUPT && GSM_MUX - select UART_INTERRUPT_DRIVEN - select EXPERIMENTAL - select DEPRECATED - help - Enable this option to create UART muxer that run over a physical - UART. The GSM 07.10 muxing protocol is used to separate the data - between these muxed UARTs. - -if UART_MUX - -config UART_MUX_DEVICE_NAME - string "UART mux device name template" - default "GSM" - help - Device name template for the UART mux Devices. First device would - have name $(UART_MUX_DEVICE_NAME)_0, etc. User will access muxed - UART using this name. - -config UART_MUX_RINGBUF_SIZE - int "UART mux ring buffer size" - default 256 - help - UART mux ring buffer size when passing data from RX ISR to worker - thread that will do the unmuxing. - -config UART_MUX_TEMP_BUF_SIZE - int "Size of the temp buffer when reading data from real UART" - default 32 - help - Size of the temporary RX buffer in receiving ISR. - -config UART_MUX_DEVICE_COUNT - int "Number of UART mux devices (DLCIs)" - default GSM_MUX_DLCI_MAX - range 1 64 - help - Number of instances of UART muxes. Default value is set by - maximum number of DLCIs (Data Link Connection Identifiers) - configured in the system. - -config UART_MUX_REAL_DEVICE_COUNT - int "Number of real UART devices" - default 1 - help - Tells how many real UART devices there are. Typically there is - only one UART and the muxed UARTs are run on top of that. If you have - two modems for example, then you would need to increase this to two. - -config UART_MUX_RX_STACK_SIZE - int "Size of the stack allocated for receiving data from UART" - default 512 - help - Sets the stack size which will be used by the PPP RX workqueue. - -config UART_MUX_RX_PRIORITY - int "RX workqueue thread priority" - default 7 - help - Sets the priority of the RX workqueue thread. - -module = UART_MUX -module-str = UART mux -source "subsys/logging/Kconfig.template.log_config" - -endif # UART_MUX - -config UART_MUX_VERBOSE_DEBUG - bool "Print hexdump of sent and received packets" - depends on UART_MUX_LOG_LEVEL_DBG - help - As there might be lot of debug output printed, only enable - this if really needed. - config EFI_CONSOLE bool "Use EFI console for console output" select CONSOLE_HAS_DRIVER diff --git a/drivers/console/Kconfig.gsm_mux b/drivers/console/Kconfig.gsm_mux deleted file mode 100644 index 100b5d54303..00000000000 --- a/drivers/console/Kconfig.gsm_mux +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (c) 2020 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config GSM_MUX - bool "[DEPRECATED] GSM 07.10 muxing protocol" - select CRC - select DEPRECATED - help - Enable GSM 07.10 muxing protocol defined in - https://www.etsi.org/deliver/etsi_ts/101300_101399/101369/07.01.00_60/ts_101369v070100p.pdf - The muxing protocol allows GSM modem to share the same UART for both - the PPP data and AT commands. - -config GSM_MUX_MAX - int "Max number of GSM mux instances" - default 1 - depends on GSM_MUX - help - Usually we only need one GSM mux instance. You need to increase - this if you have more than one GSM modems. - -config GSM_MUX_DLCI_MAX - int "Max number of GSM data link connection (DLC) instances" - default 3 - range 1 64 - depends on GSM_MUX - help - For our purposes we will manage with 3 DLCI (control, ppp, and AT - commands) so making it the default value. If GSM modem also provides - GNSS (location) services and you want to create a DLCI for it, then - you need to increase this to 4. - -config GSM_MUX_DLCI_AT - int "DLCI id of the AT commands channel" - default 2 if MODEM_GSM_SIMCOM - default 1 - range 1 63 - depends on GSM_MUX - help - Channel number for the AT commands to the modem. - -config GSM_MUX_DLCI_PPP - int "DLCI id of the PPP connection channel" - default 1 if MODEM_GSM_SIMCOM - default 2 - range 1 63 - depends on GSM_MUX - help - Channel number for the PPP connection to the modem. - SIMCOM modem has 16kb buffer for DLCI 1 so the manual recommends - it for PPP traffic. For other DLCIs in that modem, the buffer size - is only 1kb. - -config GSM_MUX_PENDING_CMD_MAX - int "Max number of pending GSM mux commands" - default 2 - range 1 8 - depends on GSM_MUX - help - How many pending GSM mux commands can exists. - -config GSM_MUX_MRU_DEFAULT_LEN - int "Default size of received user data (MRU)" - default 127 if MODEM_GSM_SIMCOM - default 127 if MODEM_GSM_QUECTEL - default 31 - range 1 1509 - depends on GSM_MUX - help - Default MRU (Maximum Receive Unit) data size. The default - value for Basic mode is 31 bytes. The 1509 limit comes from - ublox-sara modem and it means we can transfer full Ethernet sized - frame and muxing headers. - -config GSM_MUX_MRU_MAX_LEN - int "Max size of received user data (MRU)" - default 255 if MODEM_GSM_SIMCOM - default 128 - range 1 1509 - depends on GSM_MUX - help - Max MRU (Maximum Receive Unit) data size. The default max - value for Basic mode is 128 bytes. - -config GSM_MUX_INITIATOR - bool "Are we the initiator of the connection" - default y - depends on GSM_MUX - help - Default value when deciding whether we are the initiator of the - connection attempt. Normally this should be enabled. - -config GSM_MUX_T1_TIMEOUT - int "T1 timeout in ms" - default 0 - range 0 5000 - depends on GSM_MUX - help - T1 timeout is initial command timeout when establishing - the connection. The value is in milliseconds. Zero value - means that default (100 ms) specified in the code is used. - -if GSM_MUX - -module = GSM_MUX -module-dep = LOG -module-str = Log level for GSM 07.10 Mux driver -module-help = Sets log level for GSM 07.10 Mux Device Driver. -source "subsys/net/Kconfig.template.log_config.net" - -config GSM_MUX_VERBOSE_DEBUG - bool "Print hexdump of sent and received packets" - depends on GSM_MUX_LOG_LEVEL_DBG - help - As there might be lot of debug output printed, only enable - this if really needed. - -endif diff --git a/drivers/console/gsm_mux.c b/drivers/console/gsm_mux.c deleted file mode 100644 index c7e8793b6ae..00000000000 --- a/drivers/console/gsm_mux.c +++ /dev/null @@ -1,1535 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(gsm_mux, CONFIG_GSM_MUX_LOG_LEVEL); - -#include -#include -#include -#include -#include - -#include "uart_mux_internal.h" -#include "gsm_mux.h" - -/* Default values are from the specification 07.10 */ -#define T1_MSEC 100 /* 100 ms */ -#define T2_MSEC 340 /* 333 ms */ - -#define N1 256 /* default I frame size, GSM 07.10 ch 6.2.2.1 */ -#define N2 3 /* retry 3 times */ - -/* CRC8 is the reflected CRC8/ROHC algorithm */ -#define FCS_POLYNOMIAL 0xe0 /* reversed crc8 */ -#define FCS_INIT_VALUE 0xFF -#define FCS_GOOD_VALUE 0xCF - -#define GSM_EA 0x01 /* Extension bit */ -#define GSM_CR 0x02 /* Command / Response */ -#define GSM_PF 0x10 /* Poll / Final */ - -/* Frame types */ -#define FT_RR 0x01 /* Receive Ready */ -#define FT_UI 0x03 /* Unnumbered Information */ -#define FT_RNR 0x05 /* Receive Not Ready */ -#define FT_REJ 0x09 /* Reject */ -#define FT_DM 0x0F /* Disconnected Mode */ -#define FT_SABM 0x2F /* Set Asynchronous Balanced Mode */ -#define FT_DISC 0x43 /* Disconnect */ -#define FT_UA 0x63 /* Unnumbered Acknowledgement */ -#define FT_UIH 0xEF /* Unnumbered Information with Header check */ - -/* Control channel commands */ -#define CMD_NSC 0x08 /* Non Supported Command Response */ -#define CMD_TEST 0x10 /* Test Command */ -#define CMD_PSC 0x20 /* Power Saving Control */ -#define CMD_RLS 0x28 /* Remote Line Status Command */ -#define CMD_FCOFF 0x30 /* Flow Control Off Command */ -#define CMD_PN 0x40 /* DLC parameter negotiation */ -#define CMD_RPN 0x48 /* Remote Port Negotiation Command */ -#define CMD_FCON 0x50 /* Flow Control On Command */ -#define CMD_CLD 0x60 /* Multiplexer close down */ -#define CMD_SNC 0x68 /* Service Negotiation Command */ -#define CMD_MSC 0x70 /* Modem Status Command */ - -/* Flag sequence field between messages (start of frame) */ -#define SOF_MARKER 0xF9 - -/* Mux parsing states */ -enum gsm_mux_state { - GSM_MUX_SOF, /* Start of frame */ - GSM_MUX_ADDRESS, /* Address field */ - GSM_MUX_CONTROL, /* Control field */ - GSM_MUX_LEN_0, /* First length byte */ - GSM_MUX_LEN_1, /* Second length byte */ - GSM_MUX_DATA, /* Data */ - GSM_MUX_FCS, /* Frame Check Sequence */ - GSM_MUX_EOF /* End of frame */ -}; - -struct gsm_mux { - /* UART device to use. This device is the real UART, not the - * muxed one. - */ - const struct device *uart; - - /* Buf to use when TX mux packet (hdr + data). For RX it only contains - * the data (not hdr). - */ - struct net_buf *buf; - int mru; - - enum gsm_mux_state state; - - /* Control DLCI is not included in this list so -1 here */ - uint8_t dlci_to_create[CONFIG_GSM_MUX_DLCI_MAX - 1]; - - uint16_t msg_len; /* message length */ - uint16_t received; /* bytes so far received */ - - struct k_work_delayable t2_timer; - sys_slist_t pending_ctrls; - - uint16_t t1_timeout_value; /* T1 default value */ - uint16_t t2_timeout_value; /* T2 default value */ - - /* Information from currently read packet */ - uint8_t address; /* dlci address (only one byte address supported) */ - uint8_t control; /* type of the frame */ - uint8_t fcs; /* calculated frame check sequence */ - uint8_t received_fcs; /* packet fcs */ - uint8_t retries; /* N2 counter */ - - bool in_use : 1; - bool is_initiator : 1; /* Did we initiate the connection attempt */ - bool refuse_service : 1; /* Do not try to talk to this modem */ -}; - -/* DLCI states */ -enum gsm_dlci_state { - GSM_DLCI_CLOSED, - GSM_DLCI_OPENING, - GSM_DLCI_OPEN, - GSM_DLCI_CLOSING -}; - -enum gsm_dlci_mode { - GSM_DLCI_MODE_ABM = 0, /* Normal Asynchronous Balanced Mode */ - GSM_DLCI_MODE_ADM = 1, /* Asynchronous Disconnected Mode */ -}; - -typedef int (*dlci_process_msg_t)(struct gsm_dlci *dlci, bool cmd, - struct net_buf *buf); -typedef void (*dlci_command_cb_t)(struct gsm_dlci *dlci, bool connected); - -struct gsm_dlci { - sys_snode_t node; - struct k_sem disconnect_sem; - struct gsm_mux *mux; - dlci_process_msg_t handler; - dlci_command_cb_t command_cb; - gsm_mux_dlci_created_cb_t dlci_created_cb; - void *user_data; - const struct device *uart; - enum gsm_dlci_state state; - enum gsm_dlci_mode mode; - int num; - uint32_t req_start; - uint8_t retries; - bool refuse_service : 1; /* Do not try to talk to this channel */ - bool in_use : 1; -}; - -struct gsm_control_msg { - sys_snode_t node; - struct net_buf *buf; - uint32_t req_start; - uint8_t cmd; - bool finished : 1; -}; - -/* From 07.10, Maximum Frame Size [1 - 128] in Basic mode */ -#define MAX_MRU CONFIG_GSM_MUX_MRU_MAX_LEN - -/* Assume that there are 3 network buffers (one for RX and one for TX, and one - * extra when parsing data) going on at the same time. - */ -#define MIN_BUF_COUNT (CONFIG_GSM_MUX_MAX * 3) - -NET_BUF_POOL_DEFINE(gsm_mux_pool, MIN_BUF_COUNT, MAX_MRU, 0, NULL); - -#define BUF_ALLOC_TIMEOUT K_MSEC(50) - -static struct gsm_mux muxes[CONFIG_GSM_MUX_MAX]; - -static struct gsm_dlci dlcis[CONFIG_GSM_MUX_DLCI_MAX]; -static sys_slist_t dlci_free_entries; -static sys_slist_t dlci_active_t1_timers; -static struct k_work_delayable t1_timer; - -static struct gsm_control_msg ctrls[CONFIG_GSM_MUX_PENDING_CMD_MAX]; -static sys_slist_t ctrls_free_entries; - -static bool gsm_mux_init_done; - -static const char *get_frame_type_str(uint8_t frame_type) -{ - switch (frame_type) { - case FT_RR: - return "RR"; - case FT_UI: - return "UI"; - case FT_RNR: - return "RNR"; - case FT_REJ: - return "REJ"; - case FT_DM: - return "DM"; - case FT_SABM: - return "SABM"; - case FT_DISC: - return "DISC"; - case FT_UA: - return "UA"; - case FT_UIH: - return "UIH"; - } - - return NULL; -} - -static void hexdump_packet(const char *header, uint8_t address, bool cmd_rsp, - uint8_t control, const uint8_t *data, size_t len) -{ - const char *frame_type; - char out[128]; - int ret; - - if (!IS_ENABLED(CONFIG_GSM_MUX_LOG_LEVEL_DBG)) { - return; - } - - memset(out, 0, sizeof(out)); - - ret = snprintk(out, sizeof(out), "%s: DLCI %d %s ", - header, address, cmd_rsp ? "cmd" : "resp"); - if (ret >= sizeof(out)) { - LOG_DBG("%d: Too long msg (%ld)", __LINE__, (long)(ret - sizeof(out))); - goto print; - } - - frame_type = get_frame_type_str(control & ~GSM_PF); - if (frame_type) { - ret += snprintk(out + ret, sizeof(out) - ret, "%s ", - frame_type); - } else if (!(control & 0x01)) { - ret += snprintk(out + ret, sizeof(out) - ret, - "I N(S)%d N(R)%d ", - (control & 0x0E) >> 1, - (control & 0xE0) >> 5); - } else { - frame_type = get_frame_type_str(control & 0x0F); - if (frame_type) { - ret += snprintk(out + ret, sizeof(out) - ret, - "%s(%d) ", frame_type, - (control & 0xE0) >> 5); - } else { - ret += snprintk(out + ret, sizeof(out) - ret, - "[%02X] ", control); - } - } - - if (ret >= sizeof(out)) { - LOG_DBG("%d: Too long msg (%ld)", __LINE__, (long)(ret - sizeof(out))); - goto print; - } - - ret += snprintk(out + ret, sizeof(out) - ret, "%s", (control & GSM_PF) ? "(P)" : "(F)"); - if (ret >= sizeof(out)) { - LOG_DBG("%d: Too long msg (%ld)", __LINE__, (long)(ret - sizeof(out))); - goto print; - } - -print: - if (IS_ENABLED(CONFIG_GSM_MUX_VERBOSE_DEBUG)) { - if (len > 0) { - LOG_HEXDUMP_DBG(data, len, out); - } else { - LOG_DBG("%s", out); - } - } else { - LOG_DBG("%s", out); - } -} - -static uint8_t gsm_mux_fcs_add_buf(uint8_t fcs, const uint8_t *buf, size_t len) -{ - return crc8(buf, len, FCS_POLYNOMIAL, fcs, true); -} - -static uint8_t gsm_mux_fcs_add(uint8_t fcs, uint8_t recv_byte) -{ - return gsm_mux_fcs_add_buf(fcs, &recv_byte, 1); -} - -static bool gsm_mux_read_ea(int *value, uint8_t recv_byte) -{ - /* As the value can be larger than one byte, collect the read - * bytes to given variable. - */ - *value <<= 7; - *value |= recv_byte >> 1; - - /* When the address has been read fully, the EA bit is 1 */ - return recv_byte & GSM_EA; -} - -static bool gsm_mux_read_msg_len(struct gsm_mux *mux, uint8_t recv_byte) -{ - int value = mux->msg_len; - bool ret; - - ret = gsm_mux_read_ea(&value, recv_byte); - - mux->msg_len = value; - - return ret; -} - -static struct net_buf *gsm_mux_alloc_buf(k_timeout_t timeout, void *user_data) -{ - struct net_buf *buf; - - ARG_UNUSED(user_data); - - buf = net_buf_alloc(&gsm_mux_pool, timeout); - if (!buf) { - LOG_ERR("Cannot allocate buffer"); - } - - return buf; -} - -static void hexdump_buf(const char *header, struct net_buf *buf) -{ - if (IS_ENABLED(CONFIG_GSM_MUX_VERBOSE_DEBUG)) { - while (buf) { - LOG_HEXDUMP_DBG(buf->data, buf->len, header); - buf = buf->frags; - } - } -} - -static int gsm_dlci_process_data(struct gsm_dlci *dlci, bool cmd, - struct net_buf *buf) -{ - int len = 0; - - LOG_DBG("[%p] DLCI %d data %s", dlci->mux, dlci->num, - cmd ? "request" : "response"); - hexdump_buf("buf", buf); - - while (buf) { - uart_mux_recv(dlci->uart, dlci, buf->data, buf->len); - len += buf->len; - buf = buf->frags; - } - - return len; -} - -static struct gsm_dlci *gsm_dlci_get(struct gsm_mux *mux, uint8_t dlci_address) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dlcis); i++) { - if (dlcis[i].in_use && - dlcis[i].mux == mux && - dlcis[i].num == dlci_address) { - return &dlcis[i]; - } - } - - return NULL; -} - -static int gsm_mux_modem_send(struct gsm_mux *mux, const uint8_t *buf, size_t size) -{ - if (mux->uart == NULL) { - return -ENOENT; - } - - if (size == 0) { - return 0; - } - - return uart_mux_send(mux->uart, buf, size); -} - -static int gsm_mux_send_data_msg(struct gsm_mux *mux, bool cmd, - struct gsm_dlci *dlci, uint8_t frame_type, - const uint8_t *buf, size_t size) -{ - uint8_t hdr[7]; - int pos; - int ret; - - hdr[0] = SOF_MARKER; - hdr[1] = (dlci->num << 2) | ((uint8_t)cmd << 1) | GSM_EA; - hdr[2] = frame_type; - - if (size < 128) { - hdr[3] = (size << 1) | GSM_EA; - pos = 4; - } else { - hdr[3] = (size & 127) << 1; - hdr[4] = (size >> 7); - pos = 5; - } - - /* Write the header and data in smaller chunks in order to avoid - * allocating a big buffer. - */ - (void)gsm_mux_modem_send(mux, &hdr[0], pos); - - if (size > 0) { - (void)gsm_mux_modem_send(mux, buf, size); - } - - /* FSC is calculated only for address, type and length fields - * for UIH frames - */ - hdr[pos] = 0xFF - gsm_mux_fcs_add_buf(FCS_INIT_VALUE, &hdr[1], - pos - 1); - if ((frame_type & ~GSM_PF) != FT_UIH) { - hdr[pos] = gsm_mux_fcs_add_buf(hdr[pos], buf, size); - } - - hdr[pos + 1] = SOF_MARKER; - - ret = gsm_mux_modem_send(mux, &hdr[pos], 2); - - hexdump_packet("Sending", dlci->num, cmd, frame_type, - buf, size); - return ret; -} - -static int gsm_mux_send_control_msg(struct gsm_mux *mux, bool cmd, - uint8_t dlci_address, uint8_t frame_type) -{ - uint8_t buf[6]; - - buf[0] = SOF_MARKER; - buf[1] = (dlci_address << 2) | ((uint8_t)cmd << 1) | GSM_EA; - buf[2] = frame_type; - buf[3] = GSM_EA; - buf[4] = 0xFF - gsm_mux_fcs_add_buf(FCS_INIT_VALUE, buf + 1, 3); - buf[5] = SOF_MARKER; - - hexdump_packet("Sending", dlci_address, cmd, frame_type, - buf, sizeof(buf)); - - return gsm_mux_modem_send(mux, buf, sizeof(buf)); -} - -static int gsm_mux_send_command(struct gsm_mux *mux, uint8_t dlci_address, - uint8_t frame_type) -{ - return gsm_mux_send_control_msg(mux, true, dlci_address, frame_type); -} - -static int gsm_mux_send_response(struct gsm_mux *mux, uint8_t dlci_address, - uint8_t frame_type) -{ - return gsm_mux_send_control_msg(mux, false, dlci_address, frame_type); -} - -static void dlci_run_timer(uint32_t current_time) -{ - struct gsm_dlci *dlci, *next; - uint32_t new_timer = UINT_MAX; - - (void)k_work_cancel_delayable(&t1_timer); - - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dlci_active_t1_timers, - dlci, next, node) { - uint32_t current_timer = dlci->req_start + - dlci->mux->t1_timeout_value - current_time; - - new_timer = MIN(current_timer, new_timer); - } - - if (new_timer != UINT_MAX) { - k_work_reschedule(&t1_timer, K_MSEC(new_timer)); - } -} - -static void gsm_dlci_open(struct gsm_dlci *dlci) -{ - LOG_DBG("[%p/%d] DLCI id %d open", dlci, dlci->num, dlci->num); - dlci->state = GSM_DLCI_OPEN; - - /* Remove this DLCI from pending T1 timers */ - sys_slist_remove(&dlci_active_t1_timers, NULL, &dlci->node); - dlci_run_timer(k_uptime_get_32()); - - if (dlci->command_cb) { - dlci->command_cb(dlci, true); - } -} - -static void gsm_dlci_close(struct gsm_dlci *dlci) -{ - LOG_DBG("[%p/%d] DLCI id %d closed", dlci, dlci->num, dlci->num); - dlci->state = GSM_DLCI_CLOSED; - - k_sem_give(&dlci->disconnect_sem); - - /* Remove this DLCI from pending T1 timers */ - sys_slist_remove(&dlci_active_t1_timers, NULL, &dlci->node); - dlci_run_timer(k_uptime_get_32()); - - if (dlci->command_cb) { - dlci->command_cb(dlci, false); - } - - if (dlci->num == 0) { - dlci->mux->refuse_service = true; - } -} - -/* Return true if we need to retry, false otherwise */ -static bool handle_t1_timeout(struct gsm_dlci *dlci) -{ - LOG_DBG("[%p/%d] T1 timeout", dlci, dlci->num); - - if (dlci->state == GSM_DLCI_OPENING) { - dlci->retries--; - if (dlci->retries) { - dlci->req_start = k_uptime_get_32(); - (void)gsm_mux_send_command(dlci->mux, dlci->num, FT_SABM | GSM_PF); - return true; - } - - if (dlci->command_cb) { - dlci->command_cb(dlci, false); - } - - if (dlci->num == 0 && dlci->mux->control == (FT_DM | GSM_PF)) { - LOG_DBG("DLCI %d -> ADM mode", dlci->num); - dlci->mode = GSM_DLCI_MODE_ADM; - gsm_dlci_open(dlci); - } else { - gsm_dlci_close(dlci); - } - } else if (dlci->state == GSM_DLCI_CLOSING) { - dlci->retries--; - if (dlci->retries) { - (void)gsm_mux_send_command(dlci->mux, dlci->num, FT_DISC | GSM_PF); - return true; - } - - gsm_dlci_close(dlci); - } - - return false; -} - -static void dlci_t1_timeout(struct k_work *work) -{ - uint32_t current_time = k_uptime_get_32(); - struct gsm_dlci *entry, *next; - sys_snode_t *prev_node = NULL; - - ARG_UNUSED(work); - - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dlci_active_t1_timers, - entry, next, node) { - if ((int32_t)(entry->req_start + - entry->mux->t1_timeout_value - current_time) > 0) { - prev_node = &entry->node; - break; - } - - if (!handle_t1_timeout(entry)) { - sys_slist_remove(&dlci_active_t1_timers, prev_node, - &entry->node); - } - } - - dlci_run_timer(current_time); -} - -static struct gsm_control_msg *gsm_ctrl_msg_get_free(void) -{ - sys_snode_t *node; - - node = sys_slist_peek_head(&ctrls_free_entries); - if (!node) { - return NULL; - } - - sys_slist_remove(&ctrls_free_entries, NULL, node); - - return CONTAINER_OF(node, struct gsm_control_msg, node); -} - -static struct gsm_control_msg *gsm_mux_alloc_control_msg(struct net_buf *buf, - uint8_t cmd) -{ - struct gsm_control_msg *msg; - - msg = gsm_ctrl_msg_get_free(); - if (!msg) { - return NULL; - } - - msg->buf = buf; - msg->cmd = cmd; - - return msg; -} - -static void ctrl_msg_cleanup(struct gsm_control_msg *entry, bool pending) -{ - if (pending) { - LOG_DBG("Releasing pending buf %p (ref %d)", - entry->buf, entry->buf->ref - 1); - net_buf_unref(entry->buf); - entry->buf = NULL; - } -} - -/* T2 timeout is for control message retransmits */ -static void gsm_mux_t2_timeout(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct gsm_mux *mux = CONTAINER_OF(dwork, struct gsm_mux, t2_timer); - uint32_t current_time = k_uptime_get_32(); - struct gsm_control_msg *entry, *next; - - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&mux->pending_ctrls, entry, next, - node) { - if ((int32_t)(entry->req_start + T2_MSEC - current_time) > 0) { - break; - } - - ctrl_msg_cleanup(entry, true); - - sys_slist_remove(&mux->pending_ctrls, NULL, &entry->node); - sys_slist_append(&ctrls_free_entries, &entry->node); - - entry = NULL; - } - - if (entry) { - k_work_reschedule( - &mux->t2_timer, - K_MSEC(entry->req_start + T2_MSEC - current_time)); - } -} - -static int gsm_mux_send_control_message(struct gsm_mux *mux, uint8_t dlci_address, - int cmd, uint8_t *data, size_t data_len) -{ - struct gsm_control_msg *ctrl; - struct net_buf *buf; - - /* We create a net_buf for the control message so that we can - * resend it easily if needed. - */ - buf = gsm_mux_alloc_buf(BUF_ALLOC_TIMEOUT, NULL); - if (!buf) { - LOG_ERR("[%p] Cannot allocate header", mux); - return -ENOMEM; - } - - if (data && data_len > 0) { - size_t added; - - added = net_buf_append_bytes(buf, data_len, data, - BUF_ALLOC_TIMEOUT, - gsm_mux_alloc_buf, NULL); - if (added != data_len) { - net_buf_unref(buf); - return -ENOMEM; - } - } - - ctrl = gsm_mux_alloc_control_msg(buf, cmd); - if (!ctrl) { - net_buf_unref(buf); - return -ENOMEM; - } - - sys_slist_append(&mux->pending_ctrls, &ctrl->node); - ctrl->req_start = k_uptime_get_32(); - - /* Let's start the timer if necessary */ - if (!k_work_delayable_remaining_get(&mux->t2_timer)) { - k_work_reschedule(&mux->t2_timer, K_MSEC(T2_MSEC)); - } - - return gsm_mux_modem_send(mux, buf->data, buf->len); -} - -static int gsm_dlci_opening_or_closing(struct gsm_dlci *dlci, - enum gsm_dlci_state state, - int command, - dlci_command_cb_t cb) -{ - dlci->retries = dlci->mux->retries; - dlci->req_start = k_uptime_get_32(); - dlci->state = state; - dlci->command_cb = cb; - - /* Let's start the timer if necessary */ - if (!k_work_delayable_remaining_get(&t1_timer)) { - k_work_reschedule(&t1_timer, - K_MSEC(dlci->mux->t1_timeout_value)); - } - - sys_slist_append(&dlci_active_t1_timers, &dlci->node); - - return gsm_mux_send_command(dlci->mux, dlci->num, command | GSM_PF); -} - -static int gsm_dlci_closing(struct gsm_dlci *dlci, dlci_command_cb_t cb) -{ - if (dlci->state == GSM_DLCI_CLOSED || - dlci->state == GSM_DLCI_CLOSING) { - return -EALREADY; - } - - LOG_DBG("[%p] DLCI %d closing", dlci, dlci->num); - - return gsm_dlci_opening_or_closing(dlci, GSM_DLCI_CLOSING, FT_DISC, - cb); -} - -static int gsm_dlci_opening(struct gsm_dlci *dlci, dlci_command_cb_t cb) -{ - if (dlci->state == GSM_DLCI_OPEN || dlci->state == GSM_DLCI_OPENING) { - return -EALREADY; - } - - LOG_DBG("[%p] DLCI %d opening", dlci, dlci->num); - - return gsm_dlci_opening_or_closing(dlci, GSM_DLCI_OPENING, FT_SABM, - cb); -} - -int gsm_mux_disconnect(struct gsm_mux *mux, k_timeout_t timeout) -{ - struct gsm_dlci *dlci; - - dlci = gsm_dlci_get(mux, 0); - if (dlci == NULL) { - return -ENOENT; - } - - (void)gsm_mux_send_control_message(dlci->mux, dlci->num, - CMD_CLD, NULL, 0); - - (void)k_work_cancel_delayable(&mux->t2_timer); - - (void)gsm_dlci_closing(dlci, NULL); - - return k_sem_take(&dlci->disconnect_sem, timeout); -} - -static int gsm_mux_control_reply(struct gsm_dlci *dlci, bool sub_cr, - uint8_t sub_cmd, const uint8_t *buf, size_t len) -{ - /* As this is a reply to received command, set the value according - * to initiator status. See GSM 07.10 page 17. - */ - bool cmd = !dlci->mux->is_initiator; - - return gsm_mux_send_data_msg(dlci->mux, cmd, dlci, FT_UIH | GSM_PF, buf, len); -} - -static bool get_field(struct net_buf *buf, int *ret_value) -{ - int value = 0; - uint8_t recv_byte; - - while (buf->len) { - recv_byte = net_buf_pull_u8(buf); - - if (gsm_mux_read_ea(&value, recv_byte)) { - *ret_value = value; - return true; - } - - if (buf->len == 0) { - buf = net_buf_frag_del(NULL, buf); - if (buf == NULL) { - break; - } - } - } - - return false; -} - -static int gsm_mux_msc_reply(struct gsm_dlci *dlci, bool cmd, - struct net_buf *buf, size_t len) -{ - uint32_t modem_sig = 0, break_sig = 0; - int ret; - - ret = get_field(buf, &modem_sig); - if (!ret) { - LOG_DBG("[%p] Malformed data", dlci->mux); - return -EINVAL; - } - - if (buf->len > 0) { - ret = get_field(buf, &break_sig); - if (!ret) { - LOG_DBG("[%p] Malformed data", dlci->mux); - return -EINVAL; - } - } - - LOG_DBG("Modem signal 0x%02x break signal 0x%02x", modem_sig, - break_sig); - - /* FIXME to return proper status back */ - - return gsm_mux_control_reply(dlci, cmd, CMD_MSC, buf->data, len); -} - -static int gsm_mux_control_message(struct gsm_dlci *dlci, struct net_buf *buf) -{ - uint32_t command = 0, len = 0; - int ret = 0; - bool cr; - - __ASSERT_NO_MSG(dlci != NULL); - - /* Remove the C/R bit from sub-command */ - cr = buf->data[0] & GSM_CR; - buf->data[0] &= ~GSM_CR; - - ret = get_field(buf, &command); - if (!ret) { - LOG_DBG("[%p] Malformed data", dlci->mux); - return -EINVAL; - } - - ret = get_field(buf, &len); - if (!ret) { - LOG_DBG("[%p] Malformed data", dlci->mux); - return -EINVAL; - } - - LOG_DBG("[%p] DLCI %d %s 0x%02x len %u", dlci->mux, dlci->num, - cr ? "cmd" : "rsp", command, len); - - /* buf->data should now point to start of dlci command data */ - - switch (command) { - case CMD_CLD: - /* Modem closing down */ - dlci->mux->refuse_service = true; - dlci->refuse_service = true; - gsm_dlci_closing(dlci, NULL); - break; - - case CMD_FCOFF: - /* Do not accept data */ - ret = gsm_mux_control_reply(dlci, cr, CMD_FCOFF, NULL, 0); - break; - - case CMD_FCON: - /* Accepting data */ - ret = gsm_mux_control_reply(dlci, cr, CMD_FCON, NULL, 0); - break; - - case CMD_MSC: - /* Modem status information */ - /* FIXME: WIP: MSC reply does not work */ - if (0) { - ret = gsm_mux_msc_reply(dlci, cr, buf, len); - } - - break; - - case CMD_PSC: - /* Modem wants to enter power saving state */ - ret = gsm_mux_control_reply(dlci, cr, CMD_PSC, NULL, len); - break; - - case CMD_RLS: - /* Out of band error reception for a DLCI */ - break; - - case CMD_TEST: - /* Send test message back */ - ret = gsm_mux_control_reply(dlci, cr, CMD_TEST, - buf->data, len); - break; - - /* Optional and currently unsupported commands */ - case CMD_PN: /* Parameter negotiation */ - case CMD_RPN: /* Remote port negotiation */ - case CMD_SNC: /* Service negotiation command */ - default: - /* Reply to bad commands with an NSC */ - buf->data[0] = command | (cr ? GSM_CR : 0); - buf->len = 1; - ret = gsm_mux_control_reply(dlci, cr, CMD_NSC, buf->data, len); - break; - } - - return ret; -} - -/* Handle a response to our control message */ -static int gsm_mux_control_response(struct gsm_dlci *dlci, struct net_buf *buf) -{ - struct gsm_control_msg *entry, *next; - - SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&dlci->mux->pending_ctrls, - entry, next, node) { - if (dlci->mux->control == entry->cmd) { - sys_slist_remove(&dlci->mux->pending_ctrls, NULL, - &entry->node); - sys_slist_append(&ctrls_free_entries, &entry->node); - entry->finished = true; - - if (dlci->command_cb) { - dlci->command_cb(dlci, true); - } - - break; - } - } - - return 0; -} - -static int gsm_dlci_process_command(struct gsm_dlci *dlci, bool cmd, - struct net_buf *buf) -{ - int ret; - - LOG_DBG("[%p] DLCI %d control %s", dlci->mux, dlci->num, - cmd ? "request" : "response"); - hexdump_buf("buf", buf); - - if (cmd) { - ret = gsm_mux_control_message(dlci, buf); - } else { - ret = gsm_mux_control_response(dlci, buf); - } - - return ret; -} - -static void gsm_dlci_free(struct gsm_mux *mux, uint8_t address) -{ - struct gsm_dlci *dlci; - int i; - - for (i = 0; i < ARRAY_SIZE(dlcis); i++) { - if (!dlcis[i].in_use) { - continue; - } - - dlci = &dlcis[i]; - - if (dlci->mux == mux && dlci->num == address) { - dlci->in_use = false; - - sys_slist_prepend(&dlci_free_entries, &dlci->node); - } - - break; - } -} - -static struct gsm_dlci *gsm_dlci_get_free(void) -{ - sys_snode_t *node; - - node = sys_slist_peek_head(&dlci_free_entries); - if (!node) { - return NULL; - } - - sys_slist_remove(&dlci_free_entries, NULL, node); - - return CONTAINER_OF(node, struct gsm_dlci, node); -} - -static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *mux, uint8_t address, - const struct device *uart, - gsm_mux_dlci_created_cb_t dlci_created_cb, - void *user_data) -{ - struct gsm_dlci *dlci; - - dlci = gsm_dlci_get_free(); - if (!dlci) { - return NULL; - } - - k_sem_init(&dlci->disconnect_sem, 1, 1); - - dlci->mux = mux; - dlci->num = address; - dlci->in_use = true; - dlci->retries = mux->retries; - dlci->state = GSM_DLCI_CLOSED; - dlci->uart = uart; - dlci->user_data = user_data; - dlci->dlci_created_cb = dlci_created_cb; - - /* Command channel (0) handling is separated from data */ - if (dlci->num) { - dlci->handler = gsm_dlci_process_data; - } else { - dlci->handler = gsm_dlci_process_command; - } - - return dlci; -} - -static int gsm_mux_process_pkt(struct gsm_mux *mux) -{ - uint8_t dlci_address = mux->address >> 2; - int ret = 0; - bool cmd; /* C/R bit, command (true) / response (false) */ - struct gsm_dlci *dlci; - - /* This function is only called for received packets so if the - * command is set, then it means a response if we are initiator. - */ - cmd = (mux->address >> 1) & 0x01; - - if (mux->is_initiator) { - cmd = !cmd; - } - - hexdump_packet("Received", dlci_address, cmd, mux->control, - mux->buf ? mux->buf->data : NULL, - mux->buf ? mux->buf->len : 0); - - dlci = gsm_dlci_get(mux, dlci_address); - - /* What to do next */ - switch (mux->control) { - case FT_SABM | GSM_PF: - if (cmd == false) { - ret = -ENOENT; - goto fail; - } - - if (dlci == NULL) { - const struct device *uart; - - uart = uart_mux_find(dlci_address); - if (uart == NULL) { - ret = -ENOENT; - goto fail; - } - - dlci = gsm_dlci_alloc(mux, dlci_address, uart, NULL, - NULL); - if (dlci == NULL) { - ret = -ENOENT; - goto fail; - } - } - - if (dlci->refuse_service) { - ret = gsm_mux_send_response(mux, dlci_address, FT_DM); - } else { - ret = gsm_mux_send_response(mux, dlci_address, FT_UA); - gsm_dlci_open(dlci); - } - - break; - - case FT_DISC | GSM_PF: - if (cmd == false) { - ret = -ENOENT; - goto fail; - } - - if (dlci == NULL || dlci->state == GSM_DLCI_CLOSED) { - (void)gsm_mux_send_response(mux, dlci_address, FT_DM); - ret = -ENOENT; - goto out; - } - - ret = gsm_mux_send_command(mux, dlci_address, FT_UA); - gsm_dlci_close(dlci); - break; - - case FT_UA | GSM_PF: - case FT_UA: - if (cmd == true || dlci == NULL) { - ret = -ENOENT; - goto out; - } - - switch (dlci->state) { - case GSM_DLCI_CLOSING: - gsm_dlci_close(dlci); - break; - case GSM_DLCI_OPENING: - gsm_dlci_open(dlci); - break; - default: - break; - } - - break; - - case FT_DM | GSM_PF: - case FT_DM: - if (cmd == true || dlci == NULL) { - ret = -ENOENT; - goto fail; - } - - gsm_dlci_close(dlci); - break; - - case FT_UI | GSM_PF: - case FT_UI: - case FT_UIH | GSM_PF: - case FT_UIH: - if (dlci == NULL || dlci->state != GSM_DLCI_OPEN) { - (void)gsm_mux_send_command(mux, dlci_address, FT_DM | GSM_PF); - ret = -ENOENT; - goto out; - } - - ret = dlci->handler(dlci, cmd, mux->buf); - - if (mux->buf) { - net_buf_unref(mux->buf); - mux->buf = NULL; - } - - break; - - default: - ret = -EINVAL; - goto fail; - } - -out: - return ret; - -fail: - LOG_ERR("Cannot handle command (0x%02x) (%d)", mux->control, ret); - return ret; -} - -static bool is_UI(struct gsm_mux *mux) -{ - return (mux->control & ~GSM_PF) == FT_UI; -} - -static const char *gsm_mux_state_str(enum gsm_mux_state state) -{ -#if (CONFIG_GSM_MUX_LOG_LEVEL >= LOG_LEVEL_DBG) || defined(CONFIG_NET_SHELL) - switch (state) { - case GSM_MUX_SOF: - return "Start-Of-Frame"; - case GSM_MUX_ADDRESS: - return "Address"; - case GSM_MUX_CONTROL: - return "Control"; - case GSM_MUX_LEN_0: - return "Len0"; - case GSM_MUX_LEN_1: - return "Len1"; - case GSM_MUX_DATA: - return "Data"; - case GSM_MUX_FCS: - return "FCS"; - case GSM_MUX_EOF: - return "End-Of-Frame"; - } -#else - ARG_UNUSED(state); -#endif - - return ""; -} - -#if CONFIG_GSM_MUX_LOG_LEVEL >= LOG_LEVEL_DBG -static void validate_state_transition(enum gsm_mux_state current, - enum gsm_mux_state new) -{ - static const uint8_t valid_transitions[] = { - [GSM_MUX_SOF] = 1 << GSM_MUX_ADDRESS, - [GSM_MUX_ADDRESS] = 1 << GSM_MUX_CONTROL, - [GSM_MUX_CONTROL] = 1 << GSM_MUX_LEN_0, - [GSM_MUX_LEN_0] = 1 << GSM_MUX_LEN_1 | - 1 << GSM_MUX_DATA | - 1 << GSM_MUX_FCS | - 1 << GSM_MUX_SOF, - [GSM_MUX_LEN_1] = 1 << GSM_MUX_DATA | - 1 << GSM_MUX_FCS | - 1 << GSM_MUX_SOF, - [GSM_MUX_DATA] = 1 << GSM_MUX_FCS | - 1 << GSM_MUX_SOF, - [GSM_MUX_FCS] = 1 << GSM_MUX_EOF, - [GSM_MUX_EOF] = 1 << GSM_MUX_SOF - }; - - if (!(valid_transitions[current] & 1 << new)) { - LOG_DBG("Invalid state transition: %s (%d) => %s (%d)", - gsm_mux_state_str(current), current, - gsm_mux_state_str(new), new); - } -} -#else -static inline void validate_state_transition(enum gsm_mux_state current, - enum gsm_mux_state new) -{ - ARG_UNUSED(current); - ARG_UNUSED(new); -} -#endif - -static inline enum gsm_mux_state gsm_mux_get_state(const struct gsm_mux *mux) -{ - return (enum gsm_mux_state)mux->state; -} - -void gsm_mux_change_state(struct gsm_mux *mux, enum gsm_mux_state new_state) -{ - __ASSERT_NO_MSG(mux); - - if (gsm_mux_get_state(mux) == new_state) { - return; - } - - LOG_DBG("[%p] state %s (%d) => %s (%d)", - mux, gsm_mux_state_str(mux->state), mux->state, - gsm_mux_state_str(new_state), new_state); - - validate_state_transition(mux->state, new_state); - - mux->state = new_state; -} - -static void gsm_mux_process_data(struct gsm_mux *mux, uint8_t recv_byte) -{ - size_t bytes_added; - - switch (mux->state) { - case GSM_MUX_SOF: - /* This is the initial state where we look for SOF char */ - if (recv_byte == SOF_MARKER) { - gsm_mux_change_state(mux, GSM_MUX_ADDRESS); - mux->fcs = FCS_INIT_VALUE; - mux->received = 0; - - /* Avoid memory leak by freeing all the allocated - * buffers at start. - */ - if (mux->buf) { - net_buf_unref(mux->buf); - mux->buf = NULL; - } - } - - break; - - case GSM_MUX_ADDRESS: - /* DLCI (Data Link Connection Identifier) address we want to - * talk. This address field also contains C/R bit. - * Currently we only support one byte addresses. - */ - mux->address = recv_byte; - LOG_DBG("[%p] recv %d address %d C/R %d", mux, recv_byte, - mux->address >> 2, !!(mux->address & GSM_CR)); - gsm_mux_change_state(mux, GSM_MUX_CONTROL); - mux->fcs = gsm_mux_fcs_add(mux->fcs, recv_byte); - break; - - case GSM_MUX_CONTROL: - mux->control = recv_byte; - LOG_DBG("[%p] recv %s (0x%02x) control 0x%02x P/F %d", mux, - get_frame_type_str(recv_byte & ~GSM_PF), recv_byte, - mux->control & ~GSM_PF, !!(mux->control & GSM_PF)); - gsm_mux_change_state(mux, GSM_MUX_LEN_0); - mux->fcs = gsm_mux_fcs_add(mux->fcs, recv_byte); - break; - - case GSM_MUX_LEN_0: - mux->fcs = gsm_mux_fcs_add(mux->fcs, recv_byte); - mux->msg_len = 0; - - if (gsm_mux_read_msg_len(mux, recv_byte)) { - if (mux->msg_len > mux->mru) { - gsm_mux_change_state(mux, GSM_MUX_SOF); - } else if (mux->msg_len == 0) { - gsm_mux_change_state(mux, GSM_MUX_FCS); - } else { - gsm_mux_change_state(mux, GSM_MUX_DATA); - - LOG_DBG("[%p] data len %d", mux, mux->msg_len); - } - } else { - gsm_mux_change_state(mux, GSM_MUX_LEN_1); - } - - break; - - case GSM_MUX_LEN_1: - mux->fcs = gsm_mux_fcs_add(mux->fcs, recv_byte); - - mux->msg_len |= recv_byte << 7; - if (mux->msg_len > mux->mru) { - gsm_mux_change_state(mux, GSM_MUX_SOF); - } else if (mux->msg_len == 0) { - gsm_mux_change_state(mux, GSM_MUX_FCS); - } else { - gsm_mux_change_state(mux, GSM_MUX_DATA); - - LOG_DBG("[%p] data len %d", mux, mux->msg_len); - } - - break; - - case GSM_MUX_DATA: - if (mux->buf == NULL) { - mux->buf = net_buf_alloc(&gsm_mux_pool, - BUF_ALLOC_TIMEOUT); - if (mux->buf == NULL) { - LOG_ERR("[%p] Can't allocate RX data! " - "Skipping data!", mux); - gsm_mux_change_state(mux, GSM_MUX_SOF); - break; - } - } - - bytes_added = net_buf_append_bytes(mux->buf, 1, - (void *)&recv_byte, - BUF_ALLOC_TIMEOUT, - gsm_mux_alloc_buf, - &gsm_mux_pool); - if (bytes_added != 1) { - gsm_mux_change_state(mux, GSM_MUX_SOF); - } else if (++mux->received == mux->msg_len) { - gsm_mux_change_state(mux, GSM_MUX_FCS); - } - - break; - - case GSM_MUX_FCS: - mux->received_fcs = recv_byte; - - /* Update the FCS for Unnumbered Information field (UI) */ - if (is_UI(mux)) { - struct net_buf *buf = mux->buf; - - while (buf) { - mux->fcs = gsm_mux_fcs_add_buf(mux->fcs, - buf->data, - buf->len); - buf = buf->frags; - } - } - - mux->fcs = gsm_mux_fcs_add(mux->fcs, mux->received_fcs); - if (mux->fcs == FCS_GOOD_VALUE) { - int ret = gsm_mux_process_pkt(mux); - - if (ret < 0) { - LOG_DBG("[%p] Cannot process pkt (%d)", mux, - ret); - } - } - - gsm_mux_change_state(mux, GSM_MUX_EOF); - break; - - case GSM_MUX_EOF: - if (recv_byte == SOF_MARKER) { - gsm_mux_change_state(mux, GSM_MUX_SOF); - } - - break; - } -} - -void gsm_mux_recv_buf(struct gsm_mux *mux, uint8_t *buf, int len) -{ - int i = 0; - - LOG_DBG("Received %d bytes", len); - - while (i < len) { - gsm_mux_process_data(mux, buf[i++]); - } -} - -static void dlci_done(struct gsm_dlci *dlci, bool connected) -{ - LOG_DBG("[%p] DLCI id %d %screated", dlci, dlci->num, - connected == false ? "not " : ""); - - /* Let the UART mux to continue */ - if (dlci->dlci_created_cb) { - dlci->dlci_created_cb(dlci, connected, dlci->user_data); - } -} - -int gsm_dlci_create(struct gsm_mux *mux, - const struct device *uart, - int dlci_address, - gsm_mux_dlci_created_cb_t dlci_created_cb, - void *user_data, - struct gsm_dlci **dlci) -{ - int ret; - - *dlci = gsm_dlci_alloc(mux, dlci_address, uart, dlci_created_cb, - user_data); - if (!*dlci) { - LOG_ERR("[%p] Cannot allocate DLCI %d", mux, dlci_address); - ret = -ENOMEM; - goto fail; - } - - ret = gsm_dlci_opening(*dlci, dlci_done); - if (ret < 0 && ret != -EALREADY) { - LOG_ERR("[%p] Cannot open DLCI %d", mux, dlci_address); - gsm_dlci_free(mux, dlci_address); - *dlci = NULL; - } else { - ret = 0; - } - -fail: - return ret; -} - -int gsm_dlci_send(struct gsm_dlci *dlci, const uint8_t *buf, size_t size) -{ - /* Mux the data and send to UART */ - return gsm_mux_send_data_msg(dlci->mux, true, dlci, FT_UIH, buf, size); -} - -int gsm_dlci_id(struct gsm_dlci *dlci) -{ - return dlci->num; -} - -struct gsm_mux *gsm_mux_create(const struct device *uart) -{ - struct gsm_mux *mux = NULL; - int i; - - if (!gsm_mux_init_done) { - LOG_ERR("GSM mux not initialized!"); - return NULL; - } - - for (i = 0; i < ARRAY_SIZE(muxes); i++) { - if (muxes[i].in_use) { - /* If the mux was already created, return it */ - if (uart && muxes[i].uart == uart) { - return &muxes[i]; - } - - continue; - } - - mux = &muxes[i]; - - memset(mux, 0, sizeof(*mux)); - - mux->in_use = true; - mux->uart = uart; - mux->mru = CONFIG_GSM_MUX_MRU_DEFAULT_LEN; - mux->retries = N2; - mux->t1_timeout_value = CONFIG_GSM_MUX_T1_TIMEOUT ? - CONFIG_GSM_MUX_T1_TIMEOUT : T1_MSEC; - mux->t2_timeout_value = T2_MSEC; - mux->is_initiator = CONFIG_GSM_MUX_INITIATOR; - mux->state = GSM_MUX_SOF; - mux->buf = NULL; - - k_work_init_delayable(&mux->t2_timer, gsm_mux_t2_timeout); - sys_slist_init(&mux->pending_ctrls); - - /* The system will continue after the control DLCI is - * created or timeout occurs. - */ - break; - } - - return mux; -} - -int gsm_mux_send(struct gsm_mux *mux, uint8_t dlci_address, - const uint8_t *buf, size_t size) -{ - struct gsm_dlci *dlci; - - dlci = gsm_dlci_get(mux, dlci_address); - if (!dlci) { - return -ENOENT; - } - - /* Mux the data and send to UART */ - return gsm_mux_send_data_msg(mux, true, dlci, FT_UIH, buf, size); -} - -void gsm_mux_detach(struct gsm_mux *mux) -{ - struct gsm_dlci *dlci; - - for (int i = 0; i < ARRAY_SIZE(dlcis); i++) { - dlci = &dlcis[i]; - - if (mux != dlci->mux || !dlci->in_use) { - continue; - } - - dlci->in_use = false; - sys_slist_prepend(&dlci_free_entries, &dlci->node); - } -} - -void gsm_mux_init(void) -{ - int i; - - if (gsm_mux_init_done) { - return; - } - - gsm_mux_init_done = true; - - sys_slist_init(&ctrls_free_entries); - - for (i = 0; i < ARRAY_SIZE(ctrls); i++) { - sys_slist_prepend(&ctrls_free_entries, &ctrls[i].node); - } - - sys_slist_init(&dlci_free_entries); - - for (i = 0; i < ARRAY_SIZE(dlcis); i++) { - sys_slist_prepend(&dlci_free_entries, &dlcis[i].node); - } - - k_work_init_delayable(&t1_timer, dlci_t1_timeout); -} diff --git a/drivers/console/gsm_mux.h b/drivers/console/gsm_mux.h deleted file mode 100644 index fce8a104bd7..00000000000 --- a/drivers/console/gsm_mux.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DLCI_CONTROL 0 - -#if defined(CONFIG_GSM_MUX) -#define DLCI_AT CONFIG_GSM_MUX_DLCI_AT -#define DLCI_PPP CONFIG_GSM_MUX_DLCI_PPP -#else -#define DLCI_AT -1 -#define DLCI_PPP -1 -#endif - -struct gsm_mux; -struct gsm_dlci; - -void gsm_mux_recv_buf(struct gsm_mux *mux, uint8_t *buf, int len); -int gsm_mux_send(struct gsm_mux *mux, uint8_t dlci_address, - const uint8_t *buf, size_t size); -struct gsm_mux *gsm_mux_create(const struct device *uart); -int gsm_mux_disconnect(struct gsm_mux *mux, k_timeout_t timeout); -void gsm_mux_init(void); - -typedef void (*gsm_mux_dlci_created_cb_t)(struct gsm_dlci *dlci, - bool connected, - void *user_data); - -int gsm_dlci_create(struct gsm_mux *mux, - const struct device *uart, - int dlci_address, - gsm_mux_dlci_created_cb_t dlci_created_cb, - void *user_data, - struct gsm_dlci **dlci); -int gsm_dlci_send(struct gsm_dlci *dlci, const uint8_t *buf, size_t size); -int gsm_dlci_id(struct gsm_dlci *dlci); -void gsm_mux_detach(struct gsm_mux *mux); diff --git a/drivers/console/uart_mux.c b/drivers/console/uart_mux.c deleted file mode 100644 index f42b1c3a305..00000000000 --- a/drivers/console/uart_mux.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(uart_mux, CONFIG_UART_MUX_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gsm_mux.h" - -#if CONFIG_UART_MUX_DEVICE_COUNT == 0 -#error "CONFIG_UART_MUX_DEVICE_COUNT tells number of DLCIs to create " \ - "and must be >0" -#endif - -#define UART_MUX_WORKQ_PRIORITY CONFIG_UART_MUX_RX_PRIORITY -#define UART_MUX_WORKQ_STACK_SIZE CONFIG_UART_MUX_RX_STACK_SIZE - -/* All the RX/TX data is passed via own workqueue. This is done like this - * as the GSM modem uses global workqueue which causes difficulties if we do - * the same here. This workqueue is shared between all the DLCI channels. - */ -K_KERNEL_STACK_DEFINE(uart_mux_stack, UART_MUX_WORKQ_STACK_SIZE); -static struct k_work_q uart_mux_workq; - -/* The UART mux contains information about the real UART. It will synchronize - * the access to the real UART and pass data between it and GSM muxing API. - * Usually there is only one instance of these in the system, if we have only - * one UART connected to modem device. - */ -struct uart_mux { - /* The real UART device that is shared between muxed UARTs */ - const struct device *uart; - - /* GSM mux related to this UART */ - struct gsm_mux *mux; - - /* Received data is routed from ISR to MUX API via ring buffer */ - struct ring_buf *rx_ringbuf; - - /* RX worker that passes data from RX ISR to GSM mux API */ - struct k_work rx_work; - - /* Mutex for accessing the real UART */ - struct k_mutex lock; - - /* Flag that tells whether this instance is initialized or not */ - atomic_t init_done; - - /* Temporary buffer when reading data in ISR */ - uint8_t rx_buf[CONFIG_UART_MUX_TEMP_BUF_SIZE]; -}; - -#define DEFINE_UART_MUX(x, _) \ - RING_BUF_DECLARE(uart_rx_ringbuf_##x, \ - CONFIG_UART_MUX_RINGBUF_SIZE); \ - STRUCT_SECTION_ITERABLE(uart_mux, uart_mux_##x) = { \ - .rx_ringbuf = &uart_rx_ringbuf_##x, \ - } - -LISTIFY(CONFIG_UART_MUX_REAL_DEVICE_COUNT, DEFINE_UART_MUX, (;), _); - -STRUCT_SECTION_START_EXTERN(uart_mux); -STRUCT_SECTION_END_EXTERN(uart_mux); - -/* UART Mux Driver Status Codes */ -enum uart_mux_status_code { - UART_MUX_UNKNOWN, /* Initial connection status */ - UART_MUX_CONFIGURED, /* UART mux configuration done */ - UART_MUX_CONNECTED, /* UART mux connected */ - UART_MUX_DISCONNECTED, /* UART mux connection lost */ -}; - -struct uart_mux_config { -}; - -struct uart_mux_dev_data { - sys_snode_t node; - - /* Configuration data */ - struct uart_mux_config cfg; - - /* This UART mux device */ - const struct device *dev; - - /* The UART device where we are running on top of */ - struct uart_mux *real_uart; - - /* TX worker that will mux the transmitted data */ - struct k_work tx_work; - - /* ISR function callback worker */ - struct k_work cb_work; - - /* ISR function callback */ - uart_irq_callback_user_data_t cb; - void *cb_user_data; - - /* Attach callback */ - uart_mux_attach_cb_t attach_cb; - void *attach_user_data; - - /* TX data from application is handled via ring buffer */ - struct ring_buf *tx_ringbuf; - - /* Received data is routed from RX worker to application via ring - * buffer. - */ - struct ring_buf *rx_ringbuf; - - /* Muxing status */ - enum uart_mux_status_code status; - - /* DLCI (muxing virtual channel) linked to this muxed UART */ - struct gsm_dlci *dlci; - - /* Status (enabled / disabled) for RX and TX */ - bool rx_enabled : 1; - bool tx_enabled : 1; - bool rx_ready : 1; - bool tx_ready : 1; - bool in_use : 1; -}; - -struct uart_mux_cfg_data { -}; - -static sys_slist_t uart_mux_data_devlist; - -static void uart_mux_cb_work(struct k_work *work) -{ - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(work, struct uart_mux_dev_data, cb_work); - - dev_data->cb(dev_data->dev, dev_data->cb_user_data); -} - -static int uart_mux_consume_ringbuf(struct uart_mux *uart_mux) -{ - uint8_t *data; - size_t len; - int ret; - - len = ring_buf_get_claim(uart_mux->rx_ringbuf, &data, - CONFIG_UART_MUX_RINGBUF_SIZE); - if (len == 0) { - LOG_DBG("Ringbuf %p is empty!", uart_mux->rx_ringbuf); - return 0; - } - - /* We have now received muxed data. Push that through GSM mux API which - * will parse it and call proper functions to get the data to the user. - */ - - if (IS_ENABLED(CONFIG_UART_MUX_VERBOSE_DEBUG)) { - char tmp[sizeof("RECV muxed ") + 10]; - - snprintk(tmp, sizeof(tmp), "RECV muxed %s", - uart_mux->uart->name); - LOG_HEXDUMP_DBG(data, len, tmp); - } - - gsm_mux_recv_buf(uart_mux->mux, data, len); - - ret = ring_buf_get_finish(uart_mux->rx_ringbuf, len); - if (ret < 0) { - LOG_DBG("Cannot flush ring buffer (%d)", ret); - } - - return -EAGAIN; -} - -static void uart_mux_rx_work(struct k_work *work) -{ - struct uart_mux *uart_mux = - CONTAINER_OF(work, struct uart_mux, rx_work);; - int ret; - - do { - ret = uart_mux_consume_ringbuf(uart_mux); - } while (ret == -EAGAIN); -} - -static void uart_mux_tx_work(struct k_work *work) -{ - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(work, struct uart_mux_dev_data, tx_work); - uint8_t *data; - size_t len; - - len = ring_buf_get_claim(dev_data->tx_ringbuf, &data, - CONFIG_UART_MUX_RINGBUF_SIZE); - if (!len) { - LOG_DBG("Ringbuf %p empty!", dev_data->tx_ringbuf); - return; - } - - LOG_DBG("Got %ld bytes from ringbuffer send to uart %p", (unsigned long)len, - dev_data->dev); - - if (IS_ENABLED(CONFIG_UART_MUX_VERBOSE_DEBUG)) { - char tmp[sizeof("SEND _x") + - sizeof(CONFIG_UART_MUX_DEVICE_NAME)]; - - snprintk(tmp, sizeof(tmp), "SEND %s", - dev_data->dev->name); - LOG_HEXDUMP_DBG(data, len, tmp); - } - - (void)gsm_dlci_send(dev_data->dlci, data, len); - - ring_buf_get_finish(dev_data->tx_ringbuf, len); -} - -static int uart_mux_init(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - gsm_mux_init(); - - dev_data->dev = dev; - dev_data->real_uart = NULL; /* will be set when user attach to it */ - - sys_slist_find_and_remove(&uart_mux_data_devlist, &dev_data->node); - sys_slist_prepend(&uart_mux_data_devlist, &dev_data->node); - - k_work_init(&dev_data->tx_work, uart_mux_tx_work); - k_work_init(&dev_data->cb_work, uart_mux_cb_work); - - LOG_DBG("Device %s dev %p dev_data %p cfg %p created", - dev->name, dev, dev_data, dev->config); - - return 0; -} - -/* This IRQ handler is shared between muxing UARTs. After we have received - * data from it in uart_mux_rx_work(), we push the data to GSM mux API which - * will call proper callbacks to pass data to correct recipient. - */ -static void uart_mux_isr(const struct device *uart, void *user_data) -{ - struct uart_mux *real_uart = user_data; - int rx = 0; - size_t wrote = 0; - - /* Read all data off UART, and send to RX worker for unmuxing */ - while (uart_irq_update(uart) && - uart_irq_rx_ready(uart)) { - rx = uart_fifo_read(uart, real_uart->rx_buf, - sizeof(real_uart->rx_buf)); - if (rx <= 0) { - continue; - } - - wrote = ring_buf_put(real_uart->rx_ringbuf, - real_uart->rx_buf, rx); - if (wrote < rx) { - LOG_ERR("Ring buffer full, drop %ld bytes", (long)(rx - wrote)); - } - - k_work_submit_to_queue(&uart_mux_workq, &real_uart->rx_work); - } -} - -static void uart_mux_flush_isr(const struct device *dev) -{ - uint8_t c; - - while (uart_fifo_read(dev, &c, 1) > 0) { - continue; - } -} - -void uart_mux_disable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - const struct device *uart = dev_data->real_uart->uart; - - uart_irq_rx_disable(uart); - uart_irq_tx_disable(uart); - uart_mux_flush_isr(uart); - - gsm_mux_detach(dev_data->real_uart->mux); -} - -void uart_mux_enable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - struct uart_mux *real_uart = dev_data->real_uart; - - LOG_DBG("Claiming uart for uart_mux"); - - uart_irq_rx_disable(real_uart->uart); - uart_irq_tx_disable(real_uart->uart); - uart_mux_flush_isr(real_uart->uart); - uart_irq_callback_user_data_set( - real_uart->uart, uart_mux_isr, - real_uart); - - uart_irq_rx_enable(real_uart->uart); -} - -static void dlci_created_cb(struct gsm_dlci *dlci, bool connected, - void *user_data) -{ - struct uart_mux_dev_data *dev_data = user_data; - - if (connected) { - dev_data->status = UART_MUX_CONNECTED; - } else { - dev_data->status = UART_MUX_DISCONNECTED; - } - - LOG_DBG("%s %s", dev_data->dev->name, - dev_data->status == UART_MUX_CONNECTED ? "connected" : - "disconnected"); - - if (dev_data->attach_cb) { - dev_data->attach_cb(dev_data->dev, - dlci ? gsm_dlci_id(dlci) : -1, - connected, - dev_data->attach_user_data); - } -} - -static int init_real_uart(const struct device *mux, const struct device *uart, - struct uart_mux **mux_uart) -{ - bool found = false; - struct uart_mux *real_uart; - - for (real_uart = TYPE_SECTION_START(uart_mux); - real_uart != TYPE_SECTION_END(uart_mux); - real_uart++) { - if (real_uart->uart == uart) { - found = true; - break; - } - } - - if (found == false) { - for (real_uart = TYPE_SECTION_START(uart_mux); - real_uart != TYPE_SECTION_END(uart_mux); - real_uart++) { - if (real_uart->uart == NULL) { - real_uart->uart = uart; - found = true; - break; - } - } - - if (found == false) { - return -ENOENT; - } - } - - /* Init the real UART only once */ - if (atomic_cas(&real_uart->init_done, false, true)) { - real_uart->mux = gsm_mux_create(mux); - - LOG_DBG("Initializing UART %s and GSM mux %p", - real_uart->uart->name, (void *)real_uart->mux); - - if (!real_uart->mux) { - real_uart->uart = NULL; - atomic_clear(&real_uart->init_done); - return -ENOMEM; - } - - k_work_init(&real_uart->rx_work, uart_mux_rx_work); - k_mutex_init(&real_uart->lock); - - uart_irq_rx_disable(real_uart->uart); - uart_irq_tx_disable(real_uart->uart); - uart_mux_flush_isr(real_uart->uart); - uart_irq_callback_user_data_set( - real_uart->uart, uart_mux_isr, - real_uart); - - uart_irq_rx_enable(real_uart->uart); - } - - __ASSERT(real_uart->uart, "Real UART not set"); - - *mux_uart = real_uart; - - return 0; -} - -/* This will bind the physical (real) UART to this muxed UART */ -static int attach(const struct device *mux_uart, const struct device *uart, - int dlci_address, uart_mux_attach_cb_t cb, - void *user_data) -{ - sys_snode_t *sn, *sns; - - if (mux_uart == NULL || uart == NULL) { - return -EINVAL; - } - - LOG_DBG("Attach DLCI %d (%s) to %s", dlci_address, - mux_uart->name, uart->name); - - SYS_SLIST_FOR_EACH_NODE_SAFE(&uart_mux_data_devlist, sn, sns) { - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(sn, struct uart_mux_dev_data, node); - - if (dev_data->dev == mux_uart) { - struct uart_mux *real_uart; - int ret; - - ret = init_real_uart(mux_uart, uart, &real_uart); - if (ret < 0) { - return ret; - } - - dev_data->real_uart = real_uart; - dev_data->tx_ready = true; - dev_data->tx_enabled = true; - dev_data->rx_enabled = true; - dev_data->attach_cb = cb; - dev_data->attach_user_data = user_data; - dev_data->status = UART_MUX_CONFIGURED; - - ret = gsm_dlci_create(real_uart->mux, - mux_uart, - dlci_address, - dlci_created_cb, - dev_data, - &dev_data->dlci); - if (ret < 0) { - LOG_DBG("Cannot create DLCI %d (%d)", - dlci_address, ret); - return ret; - } - - return 0; - } - } - - return -ENOENT; -} - -static int uart_mux_poll_in(const struct device *dev, unsigned char *p_char) -{ - ARG_UNUSED(dev); - ARG_UNUSED(p_char); - - return -ENOTSUP; -} - -static void uart_mux_poll_out(const struct device *dev, - unsigned char out_char) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data->dev == NULL) { - return; - } - - (void)gsm_dlci_send(dev_data->dlci, &out_char, 1); -} - -static int uart_mux_err_check(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - -static int uart_mux_fifo_fill(const struct device *dev, - const uint8_t *tx_data, int len) -{ - struct uart_mux_dev_data *dev_data; - size_t wrote; - - if (dev == NULL) { - return -EINVAL; - } - - dev_data = dev->data; - if (dev_data->dev == NULL) { - return -ENOENT; - } - - /* If we're not in ISR context, do the xfer synchronously. This - * effectively let's applications use this implementation of fifo_fill - * as a multi-byte poll_out which prevents each byte getting wrapped by - * mux headers. - */ - if (!k_is_in_isr() && dev_data->dlci) { - return gsm_dlci_send(dev_data->dlci, tx_data, len); - } - - LOG_DBG("dev_data %p len %d tx_ringbuf space %u", - dev_data, len, ring_buf_space_get(dev_data->tx_ringbuf)); - - if (dev_data->status != UART_MUX_CONNECTED) { - LOG_WRN("UART mux not connected, drop %d bytes", len); - return 0; - } - - dev_data->tx_ready = false; - - wrote = ring_buf_put(dev_data->tx_ringbuf, tx_data, len); - if (wrote < len) { - LOG_WRN("Ring buffer full, drop %ld bytes", (long)(len - wrote)); - } - - k_work_submit_to_queue(&uart_mux_workq, &dev_data->tx_work); - - return wrote; -} - -static int uart_mux_fifo_read(const struct device *dev, uint8_t *rx_data, - const int size) -{ - struct uart_mux_dev_data *dev_data; - uint32_t len; - - if (dev == NULL) { - return -EINVAL; - } - - dev_data = dev->data; - if (dev_data->dev == NULL) { - return -ENOENT; - } - - LOG_DBG("%s size %d rx_ringbuf space %u", - dev->name, size, - ring_buf_space_get(dev_data->rx_ringbuf)); - - len = ring_buf_get(dev_data->rx_ringbuf, rx_data, size); - - if (ring_buf_is_empty(dev_data->rx_ringbuf)) { - dev_data->rx_ready = false; - } - - return len; -} - -static void uart_mux_irq_tx_enable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL || dev_data->dev == NULL) { - return; - } - - dev_data->tx_enabled = true; - - if (dev_data->cb && dev_data->tx_ready) { - k_work_submit_to_queue(&uart_mux_workq, &dev_data->cb_work); - } -} - -static void uart_mux_irq_tx_disable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL || dev_data->dev == NULL) { - return; - } - - dev_data->tx_enabled = false; -} - -static int uart_mux_irq_tx_ready(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL) { - return -EINVAL; - } - - if (dev_data->dev == NULL) { - return -ENOENT; - } - - return dev_data->tx_ready; -} - -static void uart_mux_irq_rx_enable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL || dev_data->dev == NULL) { - return; - } - - dev_data->rx_enabled = true; - - if (dev_data->cb && dev_data->rx_ready) { - k_work_submit_to_queue(&uart_mux_workq, &dev_data->cb_work); - } -} - -static void uart_mux_irq_rx_disable(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL || dev_data->dev == NULL) { - return; - } - - dev_data->rx_enabled = false; -} - -static int uart_mux_irq_tx_complete(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - -static int uart_mux_irq_rx_ready(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL) { - return -EINVAL; - } - - if (dev_data->dev == NULL) { - return -ENOENT; - } - - return dev_data->rx_ready; -} - -static void uart_mux_irq_err_enable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - -static void uart_mux_irq_err_disable(const struct device *dev) -{ - ARG_UNUSED(dev); -} - -static int uart_mux_irq_is_pending(const struct device *dev) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL || dev_data->dev == NULL) { - return 0; - } - - if (dev_data->tx_ready && dev_data->tx_enabled) { - return 1; - } - - if (dev_data->rx_ready && dev_data->rx_enabled) { - return 1; - } - - return 0; -} - -static int uart_mux_irq_update(const struct device *dev) -{ - ARG_UNUSED(dev); - - return 1; -} - -static void uart_mux_irq_callback_set(const struct device *dev, - uart_irq_callback_user_data_t cb, - void *user_data) -{ - struct uart_mux_dev_data *dev_data = dev->data; - - if (dev_data == NULL) { - return; - } - - dev_data->cb = cb; - dev_data->cb_user_data = user_data; -} - -static struct uart_mux_driver_api uart_mux_driver_api = { - .uart_api.poll_in = uart_mux_poll_in, - .uart_api.poll_out = uart_mux_poll_out, - .uart_api.err_check = uart_mux_err_check, - .uart_api.fifo_fill = uart_mux_fifo_fill, - .uart_api.fifo_read = uart_mux_fifo_read, - .uart_api.irq_tx_enable = uart_mux_irq_tx_enable, - .uart_api.irq_tx_disable = uart_mux_irq_tx_disable, - .uart_api.irq_tx_ready = uart_mux_irq_tx_ready, - .uart_api.irq_rx_enable = uart_mux_irq_rx_enable, - .uart_api.irq_rx_disable = uart_mux_irq_rx_disable, - .uart_api.irq_tx_complete = uart_mux_irq_tx_complete, - .uart_api.irq_rx_ready = uart_mux_irq_rx_ready, - .uart_api.irq_err_enable = uart_mux_irq_err_enable, - .uart_api.irq_err_disable = uart_mux_irq_err_disable, - .uart_api.irq_is_pending = uart_mux_irq_is_pending, - .uart_api.irq_update = uart_mux_irq_update, - .uart_api.irq_callback_set = uart_mux_irq_callback_set, - - .attach = attach, -}; - -const struct device *uart_mux_alloc(void) -{ - sys_snode_t *sn, *sns; - - SYS_SLIST_FOR_EACH_NODE_SAFE(&uart_mux_data_devlist, sn, sns) { - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(sn, struct uart_mux_dev_data, node); - - if (dev_data->in_use) { - continue; - } - - dev_data->in_use = true; - - return dev_data->dev; - } - - return NULL; -} - -#ifdef CONFIG_USERSPACE -static inline const struct device *z_vrfy_uart_mux_find(int dlci_address) -{ - return z_impl_uart_mux_find(dlci_address); -} -#include -#endif /* CONFIG_USERSPACE */ - -const struct device *z_impl_uart_mux_find(int dlci_address) -{ - sys_snode_t *sn, *sns; - - SYS_SLIST_FOR_EACH_NODE_SAFE(&uart_mux_data_devlist, sn, sns) { - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(sn, struct uart_mux_dev_data, node); - - if (!dev_data->in_use) { - continue; - } - - if (dev_data->dlci == NULL) { - continue; - } - - if (gsm_dlci_id(dev_data->dlci) == dlci_address) { - return dev_data->dev; - } - } - - return NULL; -} - -int uart_mux_send(const struct device *uart, const uint8_t *buf, size_t size) -{ - struct uart_mux_dev_data *dev_data = uart->data; - size_t remaining = size; - - if (size == 0) { - return 0; - } - - if (atomic_get(&dev_data->real_uart->init_done) == false) { - return -ENODEV; - } - - if (IS_ENABLED(CONFIG_UART_MUX_VERBOSE_DEBUG)) { - char tmp[sizeof("SEND muxed ") + 10]; - - snprintk(tmp, sizeof(tmp), "SEND muxed %s", - dev_data->real_uart->uart->name); - LOG_HEXDUMP_DBG(buf, size, tmp); - } - - k_mutex_lock(&dev_data->real_uart->lock, K_FOREVER); - - do { - uart_poll_out(dev_data->real_uart->uart, *buf++); - } while (--remaining); - - k_mutex_unlock(&dev_data->real_uart->lock); - - return size; -} - -int uart_mux_recv(const struct device *mux, struct gsm_dlci *dlci, - uint8_t *data, - size_t len) -{ - struct uart_mux_dev_data *dev_data = mux->data; - size_t wrote = 0; - - LOG_DBG("%s: dlci %p data %p len %zd", mux->name, (void *)dlci, - data, len); - - if (IS_ENABLED(CONFIG_UART_MUX_VERBOSE_DEBUG)) { - char tmp[sizeof("RECV _x") + - sizeof(CONFIG_UART_MUX_DEVICE_NAME)]; - - snprintk(tmp, sizeof(tmp), "RECV %s", - dev_data->dev->name); - LOG_HEXDUMP_DBG(data, len, tmp); - } - - wrote = ring_buf_put(dev_data->rx_ringbuf, data, len); - if (wrote < len) { - LOG_ERR("Ring buffer full, drop %ld bytes", (long)(len - wrote)); - } - - dev_data->rx_ready = true; - - if (dev_data->cb && dev_data->rx_enabled) { - k_work_submit_to_queue(&uart_mux_workq, &dev_data->cb_work); - } - - return wrote; -} - -void uart_mux_foreach(uart_mux_cb_t cb, void *user_data) -{ - sys_snode_t *sn, *sns; - - SYS_SLIST_FOR_EACH_NODE_SAFE(&uart_mux_data_devlist, sn, sns) { - struct uart_mux_dev_data *dev_data = - CONTAINER_OF(sn, struct uart_mux_dev_data, node); - - if (!dev_data->in_use) { - continue; - } - - cb(dev_data->real_uart->uart, dev_data->dev, - dev_data->dlci ? gsm_dlci_id(dev_data->dlci) : -1, - user_data); - } -} - -#define DEFINE_UART_MUX_CFG_DATA(x, _) \ - struct uart_mux_cfg_data uart_mux_config_##x = { \ - } - -#define DEFINE_UART_MUX_DEV_DATA(x, _) \ - RING_BUF_DECLARE(tx_ringbuf_##x, CONFIG_UART_MUX_RINGBUF_SIZE); \ - RING_BUF_DECLARE(rx_ringbuf_##x, CONFIG_UART_MUX_RINGBUF_SIZE); \ - static struct uart_mux_dev_data uart_mux_dev_data_##x = { \ - .tx_ringbuf = &tx_ringbuf_##x, \ - .rx_ringbuf = &rx_ringbuf_##x, \ - } - -#define DEFINE_UART_MUX_DEVICE(x, _) \ - DEVICE_DEFINE(uart_mux_##x, \ - CONFIG_UART_MUX_DEVICE_NAME "_" #x, \ - &uart_mux_init, \ - NULL, \ - &uart_mux_dev_data_##x, \ - &uart_mux_config_##x, \ - POST_KERNEL, \ - CONFIG_CONSOLE_INIT_PRIORITY, \ - &uart_mux_driver_api) - -LISTIFY(CONFIG_UART_MUX_DEVICE_COUNT, DEFINE_UART_MUX_CFG_DATA, (;), _); -LISTIFY(CONFIG_UART_MUX_DEVICE_COUNT, DEFINE_UART_MUX_DEV_DATA, (;), _); -LISTIFY(CONFIG_UART_MUX_DEVICE_COUNT, DEFINE_UART_MUX_DEVICE, (;), _); - -static int init_uart_mux(void) -{ - - k_work_queue_start(&uart_mux_workq, uart_mux_stack, - K_KERNEL_STACK_SIZEOF(uart_mux_stack), - K_PRIO_COOP(UART_MUX_WORKQ_PRIORITY), NULL); - k_thread_name_set(&uart_mux_workq.thread, "uart_mux_workq"); - - return 0; -} - -SYS_INIT(init_uart_mux, POST_KERNEL, CONFIG_CONSOLE_INIT_PRIORITY); diff --git a/drivers/console/uart_mux_internal.h b/drivers/console/uart_mux_internal.h deleted file mode 100644 index 79e0f3264be..00000000000 --- a/drivers/console/uart_mux_internal.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Send data to real UART (the data should be muxed already) - * - * @param uart Muxed uart - * @param buf Data to send - * @param size Data length - * - * @return >=0 if data was sent (and number of bytes sent), <0 if error - */ -int uart_mux_send(const struct device *uart, const uint8_t *buf, size_t size); - -/** - * @brief Receive unmuxed data. - * - * @param mux UART mux device structure. - * @param dlci DLCI id for the muxing channel that should receive the data. - * @param data Received data (already unmuxed) - * @param len Length of the received data - * - * @retval >=0 No errors, number of bytes received - * @retval <0 Error - */ -int uart_mux_recv(const struct device *mux, struct gsm_dlci *dlci, - uint8_t *data, size_t len); - -#ifdef __cplusplus -} -#endif diff --git a/include/zephyr/drivers/console/uart_mux.h b/include/zephyr/drivers/console/uart_mux.h deleted file mode 100644 index 911372ce578..00000000000 --- a/include/zephyr/drivers/console/uart_mux.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2020 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Public APIs for UART MUX drivers - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_UART_MUX_H_ -#define ZEPHYR_INCLUDE_DRIVERS_UART_MUX_H_ - -/** - * @brief UART Mux Interface - * @defgroup uart_mux_interface UART Mux Interface - * @ingroup io_interfaces - * @{ - */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct gsm_dlci; - -/** - * @typedef uart_mux_attach_cb_t - * - * @brief Define the user callback function which is called when - * the UART mux is attached properly. - * - * @param mux UART mux device - * @param dlci_address DLCI id for the virtual muxing channel - * @param connected True if DLCI is connected, false otherwise. - * @param user_data Arbitrary user data. - */ -typedef void (*uart_mux_attach_cb_t)(const struct device *mux, - int dlci_address, - bool connected, void *user_data); - -/** @brief UART mux driver API structure. */ -__subsystem struct uart_mux_driver_api { - /** - * The uart_driver_api must be placed in first position in this - * struct so that we are compatible with uart API. Note that currently - * not all of the UART API functions are implemented. - */ - struct uart_driver_api uart_api; - - /** - * Attach the mux to this UART. The API will call the callback after - * the DLCI is created or not. - */ - int (*attach)(const struct device *mux, const struct device *uart, - int dlci_address, uart_mux_attach_cb_t cb, - void *user_data); -}; - -/** - * @brief Attach physical/real UART to UART muxing device. - * - * @param mux UART mux device structure. - * @param uart Real UART device structure. - * @param dlci_address DLCI id for the virtual muxing channel - * @param cb Callback is called when the DLCI is ready and connected - * @param user_data Caller supplied optional data - * - * @retval 0 No errors, the attachment was successful - * @retval <0 Error - */ -static inline int uart_mux_attach(const struct device *mux, - const struct device *uart, - int dlci_address, uart_mux_attach_cb_t cb, - void *user_data) -{ - const struct uart_mux_driver_api *api = - (const struct uart_mux_driver_api *)mux->api; - - return api->attach(mux, uart, dlci_address, cb, user_data); -} - -/** - * @brief Get UART related to a specific DLCI channel - * - * @param dlci_address DLCI address, value >0 and <63 - * - * @return UART device if found, NULL otherwise - */ -__syscall const struct device *uart_mux_find(int dlci_address); - -/** - * @brief Allocate muxing UART device. - * - * @details This will return next available uart mux driver that will mux the - * data when read or written. This device corresponds to one DLCI channel. - * User must first call this to allocate the DLCI and then call the attach - * function to fully enable the muxing. - * - * @retval device New UART device that will automatically mux data sent to it. - * @retval NULL if error - */ -const struct device *uart_mux_alloc(void); - -/** - * @typedef uart_mux_cb_t - * @brief Callback used while iterating over UART muxes - * - * @param uart Pointer to UART device where the mux is running - * @param dev Pointer to UART mux device - * @param dlci_address DLCI channel id this UART is muxed - * @param user_data A valid pointer to user data or NULL - */ -typedef void (*uart_mux_cb_t)(const struct device *uart, - const struct device *dev, - int dlci_address, void *user_data); - -/** - * @brief Go through all the UART muxes and call callback - * for each of them - * - * @param cb User-supplied callback function to call - * @param user_data User specified data - */ -void uart_mux_foreach(uart_mux_cb_t cb, void *user_data); - -/** - * @brief Disable the mux. - * - * @details Disable does not re-instate whatever ISRs and configs were present - * before the mux was enabled. This must be done by the user. - * - * @param dev UART mux device pointer - */ -void uart_mux_disable(const struct device *dev); - -/** - * @brief Enable the mux. - * - * @details Enables the correct ISRs for the UART mux. - * - * @param dev UART mux device pointer - */ -void uart_mux_enable(const struct device *dev); - -#ifdef __cplusplus -} -#endif - -#include - -/** - * @} - */ - -#endif /* ZEPHYR_INCLUDE_DRIVERS_UART_MUX_H_ */ diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index 0f750f93cd8..ecca31165a6 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -95,10 +95,6 @@ ITERABLE_SECTION_RAM(pcie_dev, Z_LINK_ITERABLE_SUBALIGN) #endif /* PCIE */ -#if defined(CONFIG_UART_MUX) - ITERABLE_SECTION_RAM(uart_mux, Z_LINK_ITERABLE_SUBALIGN) -#endif - #if defined(CONFIG_USB_DEVICE_STACK) SECTION_DATA_PROLOGUE(usb_descriptor,,SUBALIGN(1)) { diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv index f55899569e4..84d24dd1000 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -116,7 +116,6 @@ STM32_LPTIM_TIMER,n,experimental TFTP_LIB,n,experimental THRIFT,n,experimental UART_EMUL,n,experimental -UART_MUX,n,experimental UDC_DRIVER,n,experimental UHC_DRIVER,n,experimental USBD_CDC_ACM_CLASS,n,experimental diff --git a/scripts/pylib/twister/twisterlib/size_calc.py b/scripts/pylib/twister/twisterlib/size_calc.py index f449d26ac99..0c6634c8742 100644 --- a/scripts/pylib/twister/twisterlib/size_calc.py +++ b/scripts/pylib/twister/twisterlib/size_calc.py @@ -56,7 +56,6 @@ class SizeCalculator: "ccm_data", "usb_descriptor", "usb_data", "usb_bos_desc", - "uart_mux", 'log_backends_sections', 'log_dynamic_sections', 'log_const_sections',