drivers: console: remove uart_mux and gsm_mux
Remove the deprecated uart_mux and gsm_mux modules and all of their configurations/dependencies across zephyr. Optimally uart_mux and gsm_mux would be removed in their own respective PRs, but the two modules are directly coupled, so to preserve bisectability, they must be removed together. Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
parent
e79428cda8
commit
79640aea09
12 changed files with 0 additions and 2879 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
|
@ -1,890 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(uart_mux, CONFIG_UART_MUX_LOG_LEVEL);
|
||||
|
||||
#include <zephyr/sys/__assert.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/internal/syscall_handler.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/drivers/console/uart_mux.h>
|
||||
#include <zephyr/sys/ring_buffer.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/iterable_sections.h>
|
||||
|
||||
#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 <zephyr/syscalls/uart_mux_find_mrsh.c>
|
||||
#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);
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/console/uart_mux.h>
|
||||
|
||||
#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
|
|
@ -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 <zephyr/device.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
|
||||
#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 <zephyr/syscalls/uart_mux.h>
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_UART_MUX_H_ */
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 50.
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue