fixeria has submitted this change. ( 
https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email )

Change subject: mobile: integrate V.110 TA & soft-UART from libosmocore
......................................................................

mobile: integrate V.110 TA & soft-UART from libosmocore

Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0
Depends: libosmocore.git I6d2f8e250df31c233a2741163113dc07515409ae
Depends: libosmocore.git I5716bd6fd0201ee7a7a29e72f775972cd374082f
Depends: libosmocore.git I2ca95963fd5852ddb89bdd35b86b31489127fe84
Related: OS#4396
---
M src/host/layer23/configure.ac
M src/host/layer23/include/osmocom/bb/mobile/tch.h
M src/host/layer23/src/mobile/Makefile.am
M src/host/layer23/src/mobile/tch.c
A src/host/layer23/src/mobile/tch_data.c
5 files changed, 511 insertions(+), 13 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve
  fixeria: Looks good to me, approved




diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac
index b4eb860..7fb8bf1 100644
--- a/src/host/layer23/configure.ac
+++ b/src/host/layer23/configure.ac
@@ -45,6 +45,7 @@
 PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
 PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
 PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm)
+PKG_CHECK_MODULES(LIBOSMOISDN, libosmoisdn)
 PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec)
 PKG_CHECK_MODULES(LIBOSMOGPRSRLCMAC, libosmo-gprs-rlcmac)
 PKG_CHECK_MODULES(LIBOSMOGPRSLLC, libosmo-gprs-llc)
diff --git a/src/host/layer23/include/osmocom/bb/mobile/tch.h 
b/src/host/layer23/include/osmocom/bb/mobile/tch.h
index b99b834..8672860 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/tch.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/tch.h
@@ -13,6 +13,10 @@
                } voice;
                struct tch_data_state {
                        enum tch_data_io_handler handler;
+                       struct osmo_v110_ta *v110_ta;
+                       struct osmo_soft_uart *suart;
+                       unsigned int num_tx;
+                       uint8_t e1e2e3[3];
                } data;
        };
 };
diff --git a/src/host/layer23/src/mobile/Makefile.am 
b/src/host/layer23/src/mobile/Makefile.am
index 0639916..b4e45e2 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -8,6 +8,7 @@
        $(LIBOSMOCORE_CFLAGS) \
        $(LIBOSMOVTY_CFLAGS) \
        $(LIBOSMOGSM_CFLAGS) \
+       $(LIBOSMOISDN_CFLAGS) \
        $(LIBOSMOGPRSRLCMAC_CFLAGS) \
        $(LIBOSMOGPRSLLC_CFLAGS) \
        $(LIBOSMOGPRSSNDCP_CFLAGS) \
@@ -31,6 +32,7 @@
        mncc_sock.c \
        primitives.c \
        tch.c \
+       tch_data.c \
        tch_voice.c \
        transaction.c \
        vty_interface.c \
@@ -45,6 +47,7 @@
        $(LIBOSMOCORE_LIBS) \
        $(LIBOSMOVTY_LIBS) \
        $(LIBOSMOGSM_LIBS) \
+       $(LIBOSMOISDN_LIBS) \
        $(LIBOSMOGPRSRLCMAC_LIBS) \
        $(LIBOSMOGPRSLLC_LIBS) \
        $(LIBOSMOGPRSSNDCP_LIBS) \
diff --git a/src/host/layer23/src/mobile/tch.c 
b/src/host/layer23/src/mobile/tch.c
index ad5a724..70c9163 100644
--- a/src/host/layer23/src/mobile/tch.c
+++ b/src/host/layer23/src/mobile/tch.c
@@ -37,16 +37,21 @@

 int tch_voice_state_init(struct gsm_trans *trans,
                         struct tch_voice_state *state);
+int tch_data_state_init(struct gsm_trans *trans,
+                       struct tch_data_state *state);
+
 void tch_voice_state_free(struct tch_voice_state *state);
+void tch_data_state_free(struct tch_data_state *state);

 int tch_voice_recv(struct osmocom_ms *ms, struct msgb *msg);
+int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg);
 int tch_voice_serve_ms(struct osmocom_ms *ms);

 /* Receive a Downlink traffic (voice/data) frame from the lower layers */
 static int tch_recv_cb(struct osmocom_ms *ms, struct msgb *msg)
 {
        struct tch_state *state = ms->tch_state;
-       int rc = 0;
+       int rc;

        if (state == NULL) {
                msgb_free(msg);
@@ -55,9 +60,8 @@

        if (state->is_voice)
                rc = tch_voice_recv(ms, msg);
-       else /* TODO: tch_recv_data() */
-               msgb_free(msg);
-
+       else
+               rc = tch_data_recv(ms, msg);
        return rc;
 }

@@ -126,6 +130,7 @@

        state = talloc_zero(ms, struct tch_state);
        OSMO_ASSERT(state != NULL);
+       ms->tch_state = state;

        ch_mode = ms->rrlayer.cd_now.mode;
        switch (ch_mode) {
@@ -141,24 +146,20 @@
        case GSM48_CMODE_DATA_12k0:
        case GSM48_CMODE_DATA_6k0:
        case GSM48_CMODE_DATA_3k6:
-#if 0
                state->is_voice = false;
                state->data.handler = ms->settings.tch_data.io_handler;
-               /* TODO: tch_data_state_init() */
                if (tch_data_state_init(trans, &state->data) != 0)
                        goto exit_free;
                break;
-#endif
        case GSM48_CMODE_SIGN:
        default:
                LOGP(DL1C, LOGL_ERROR, "Unhandled channel mode %s\n",
                     get_value_string(gsm48_chan_mode_names, ch_mode));
 exit_free:
                talloc_free(state);
+               ms->tch_state = NULL;
                return;
        }
-
-       ms->tch_state = state;
 }

 static void tch_trans_free_cb(struct gsm_trans *trans)
@@ -170,10 +171,8 @@
                return;
        if (state->is_voice)
                tch_voice_state_free(&state->voice);
-#if 0
-       else /* TODO: tch_state_free_data() */
-               tch_state_free_data(&state->data);
-#endif
+       else
+               tch_data_state_free(&state->data);

        talloc_free(state);
        ms->tch_state = NULL;
diff --git a/src/host/layer23/src/mobile/tch_data.c 
b/src/host/layer23/src/mobile/tch_data.c
new file mode 100644
index 0000000..9f46641
--- /dev/null
+++ b/src/host/layer23/src/mobile/tch_data.c
@@ -0,0 +1,478 @@
+/*
+ * (C) 2023-2024 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanits...@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/soft_uart.h>
+
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/gsm44021.h>
+
+#include <osmocom/isdn/v110.h>
+#include <osmocom/isdn/v110_ta.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/ms.h>
+#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/transaction.h>
+#include <osmocom/bb/mobile/tch.h>
+
+struct csd_v110_frame_desc {
+       uint16_t num_blocks;
+       uint16_t num_bits;
+};
+
+struct csd_v110_lchan_desc {
+       struct csd_v110_frame_desc fr;
+       struct csd_v110_frame_desc hr;
+};
+
+/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */
+const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = {
+#if 0
+       [GSM48_CMODE_DATA_14k5] = {
+               /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */
+               .fr = { .num_blocks = 1, .num_bits = 290 },
+       },
+#endif
+       [GSM48_CMODE_DATA_12k0] = {
+               /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */
+               .fr = { .num_blocks = 4, .num_bits = 60 },
+       },
+       [GSM48_CMODE_DATA_6k0] = {
+               /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */
+               .fr = { .num_blocks = 2, .num_bits = 60 },
+               /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */
+               .hr = { .num_blocks = 4, .num_bits = 60 },
+       },
+       [GSM48_CMODE_DATA_3k6] = {
+               /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */
+               .fr = { .num_blocks = 2, .num_bits = 36 },
+               /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */
+               .hr = { .num_blocks = 4, .num_bits = 36 },
+       },
+};
+
+static void tch_soft_uart_rx_cb(void *priv, struct msgb *msg, unsigned int 
flags)
+{
+       LOGP(DL1C, LOGL_FATAL, "%s(): [flags=0x%08x] %s\n",
+            __func__, flags, msgb_hexdump(msg));
+       msgb_free(msg);
+}
+
+static void tch_soft_uart_tx_cb(void *priv, struct msgb *msg)
+{
+       const char *data = "TEST\r\n";
+       size_t n_bytes;
+
+       n_bytes = OSMO_MIN(msg->data_len, strlen(data));
+       if (n_bytes > 0)
+               memcpy(msgb_put(msg, n_bytes), (void *)data, n_bytes);
+}
+
+struct osmo_soft_uart *tch_soft_uart_alloc(struct osmocom_ms *ms,
+                                          const struct gsm_mncc_bearer_cap 
*bcap)
+{
+       struct osmo_soft_uart *suart;
+
+       struct osmo_soft_uart_cfg cfg = {
+               .num_data_bits = bcap->data.nr_data_bits,
+               .num_stop_bits = bcap->data.nr_stop_bits,
+               /* .parity_mode is set below */
+               .rx_buf_size = 1024, /* TODO: align with the current TCH mode */
+               .rx_timeout_ms = 100, /* TODO: align with TCH framing interval 
*/
+               .priv = (void *)&ms->tch_state->data,
+               .rx_cb = &tch_soft_uart_rx_cb,
+               .tx_cb = &tch_soft_uart_tx_cb,
+       };
+
+       switch (bcap->data.parity) {
+       case GSM48_BCAP_PAR_ODD:
+               cfg.parity_mode = OSMO_SUART_PARITY_ODD;
+               break;
+       case GSM48_BCAP_PAR_EVEN:
+               cfg.parity_mode = OSMO_SUART_PARITY_EVEN;
+               break;
+       case GSM48_BCAP_PAR_ZERO:
+               cfg.parity_mode = OSMO_SUART_PARITY_SPACE;
+               break;
+       case GSM48_BCAP_PAR_ONE:
+               cfg.parity_mode = OSMO_SUART_PARITY_MARK;
+               break;
+       case GSM48_BCAP_PAR_NONE:
+       default:
+               cfg.parity_mode = OSMO_SUART_PARITY_NONE;
+               break;
+       }
+
+       suart = osmo_soft_uart_alloc(ms, "csd_soft_uart", &cfg);
+       if (suart == NULL)
+               return NULL;
+
+       osmo_soft_uart_set_rx(suart, true);
+       osmo_soft_uart_set_tx(suart, true);
+
+       return suart;
+}
+
+/*************************************************************************************/
+
+static void tch_v110_ta_rx_cb(void *priv, const ubit_t *buf, size_t buf_size)
+{
+       /* TODO: send to the configured I/O handler */
+}
+
+static void tch_v110_ta_tx_cb(void *priv, ubit_t *buf, size_t buf_size)
+{
+       /* TODO: send to the configured I/O handler */
+}
+
+static void tch_v110_ta_async_rx_cb(void *priv, const ubit_t *buf, size_t 
buf_size)
+{
+       const struct tch_data_state *state = (struct tch_data_state *)priv;
+
+       osmo_soft_uart_rx_ubits(state->suart, buf, buf_size);
+}
+
+static void tch_v110_ta_async_tx_cb(void *priv, ubit_t *buf, size_t buf_size)
+{
+       const struct tch_data_state *state = (struct tch_data_state *)priv;
+
+       osmo_soft_uart_tx_ubits(state->suart, buf, buf_size);
+}
+
+static void tch_v110_ta_status_update_cb(void *priv, unsigned int status)
+{
+       LOGP(DL1C, LOGL_DEBUG, "%s(): [status=0x%08x]\n", __func__, status);
+
+       /* TODO: update status lines of the soft-UART (if state.suart != NULL) 
*/
+}
+
+struct osmo_v110_ta *tch_v110_ta_alloc(struct osmocom_ms *ms,
+                                      const struct gsm_mncc_bearer_cap *bcap)
+{
+       struct tch_data_state *state = &ms->tch_state->data;
+
+       struct osmo_v110_ta_cfg cfg = {
+               /* .rate is set below */
+               .priv = (void *)state,
+               .rx_cb = &tch_v110_ta_rx_cb,
+               .tx_cb = &tch_v110_ta_tx_cb,
+               .status_update_cb = &tch_v110_ta_status_update_cb,
+       };
+
+       if (bcap->data.async) {
+               OSMO_ASSERT(state->suart != NULL);
+               cfg.rx_cb = &tch_v110_ta_async_rx_cb;
+               cfg.tx_cb = &tch_v110_ta_async_tx_cb;
+       }
+
+#define BCAP_RATE(interm_rate, user_rate) \
+       ((interm_rate << 8) | (user_rate << 0))
+
+       switch (BCAP_RATE(bcap->data.interm_rate, bcap->data.user_rate)) {
+       case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_1200):
+               cfg.rate = OSMO_V110_SYNC_RA1_1200;
+               break;
+       case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_2400):
+               cfg.rate = OSMO_V110_SYNC_RA1_2400;
+               break;
+       case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_4800):
+               cfg.rate = OSMO_V110_SYNC_RA1_4800;
+               break;
+       case BCAP_RATE(GSM48_BCAP_IR_16k, GSM48_BCAP_UR_9600):
+               cfg.rate = OSMO_V110_SYNC_RA1_9600;
+               break;
+       /* TODO: according to 3GPP TS 44.021, section 4.1, the 300 bit/s user 
data
+        * signalling rate shall be adapted to a synchronous 600 bit/s stream. 
*/
+       case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_300):
+       default:
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): User rate 0x%02x (octets 6a) is not supported 
(IR=0x%02x)\n",
+                    __func__, bcap->data.user_rate, bcap->data.interm_rate);
+               return NULL;
+       }
+
+#undef BCAP_RATE
+
+       osmo_v110_e1e2e3_set(state->e1e2e3, cfg.rate);
+
+       return osmo_v110_ta_alloc(ms, "csd_v110_ta", &cfg);
+}
+
+/*************************************************************************************/
+
+static void swap_words(uint8_t *data, size_t data_len)
+{
+       /* swap bytes in words */
+       while (data_len >= 2) {
+               uint8_t tmp = data[0];
+               data[0] = data[1];
+               data[1] = tmp;
+               data_len -= 2;
+               data += 2;
+       }
+}
+
+static int tch_csd_rx_from_l1(struct osmocom_ms *ms, struct msgb *msg)
+{
+       const struct tch_data_state *state = &ms->tch_state->data;
+       const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
+       const struct csd_v110_frame_desc *desc;
+       ubit_t data[4 * 60];
+
+       if (msgb_l3len(msg) < 30)
+               return -EINVAL;
+
+       if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs)
+               desc = &csd_v110_lchan_desc[cd->mode].fr;
+       else /* RSL_CHAN_Lm_ACCHs */
+               desc = &csd_v110_lchan_desc[cd->mode].hr;
+       if (OSMO_UNLIKELY(desc->num_blocks == 0))
+               return -ENOTSUP;
+
+       switch (ms->settings.tch_data.io_format) {
+       case TCH_DATA_IOF_OSMO:
+               break;
+       case TCH_DATA_IOF_TI:
+               /* the layer1 firmware emits frames with swapped words (LE 
ordering) */
+               swap_words(msgb_l3(msg), msgb_l3len(msg));
+               break;
+       }
+
+       /* unpack packed bits (MSB goes first) */
+       osmo_pbit2ubit_ext(data, 0, msgb_l3(msg), 0, sizeof(data), 1);
+
+       for (unsigned int i = 0; i < desc->num_blocks; i++) {
+               struct osmo_v110_decoded_frame df;
+
+               if (desc->num_bits == 60)
+                       osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60);
+               else /* desc->num_bits == 36 */
+                       osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36);
+
+               /* E1/E2/E3 is out-of-band knowledge in GSM/CSD */
+               memcpy(df.e_bits, state->e1e2e3, sizeof(state->e1e2e3));
+
+               osmo_v110_ta_frame_in(state->v110_ta, &df);
+       }
+
+       if (state->suart != NULL)
+               osmo_soft_uart_flush_rx(state->suart);
+
+       return 0;
+}
+
+static int tch_csd_tx_to_l1(struct osmocom_ms *ms)
+{
+       struct tch_data_state *state = &ms->tch_state->data;
+       const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
+       const struct csd_v110_frame_desc *desc;
+       ubit_t data[60 * 4];
+       struct msgb *nmsg;
+
+       if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs)
+               desc = &csd_v110_lchan_desc[cd->mode].fr;
+       else /* RSL_CHAN_Lm_ACCHs */
+               desc = &csd_v110_lchan_desc[cd->mode].hr;
+       if (OSMO_UNLIKELY(desc->num_blocks == 0))
+               return -ENOTSUP;
+
+       for (unsigned int i = 0; i < desc->num_blocks; i++) {
+               struct osmo_v110_decoded_frame df;
+
+               if (osmo_v110_ta_frame_out(state->v110_ta, &df) != 0)
+                       memset(&df, 0x01, sizeof(df));
+
+               /* If E1/E2/E3 bits indicate a meaningful user data rate (see 
Table 5/V.110),
+                * set E7 to binary 0 in every 4-th frame (as per 3GPP TS 
44.021, subclause 10.2.1).
+                * ITU-T V.110 requires this only for 600 bps, but 3GPP TS 
44.021 clearly states
+                * that "such a multiframe structure exists for all user data 
rates". */
+               if ((df.e_bits[0] + df.e_bits[1] + df.e_bits[2]) == 2)
+                       df.e_bits[6] = (state->num_tx != 0);
+               state->num_tx = (state->num_tx + 1) & 0x03;
+
+               if (desc->num_bits == 60)
+                       osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df);
+               else /* desc->num_bits == 36 */
+                       osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df);
+       }
+
+       nmsg = msgb_alloc_headroom(33 + 64, 64, __func__);
+       OSMO_ASSERT(nmsg != NULL);
+
+       nmsg->l2h = msgb_put(nmsg, 33); /* XXX: proper size */
+
+       /* pack unpacked bits (MSB goes first) */
+       osmo_ubit2pbit_ext(msgb_l2(nmsg), 0, &data[0], 0, sizeof(data), 1);
+
+       switch (ms->settings.tch_data.io_format) {
+       case TCH_DATA_IOF_OSMO:
+               break;
+       case TCH_DATA_IOF_TI:
+               /* the layer1 firmware expects frames with swapped words (LE 
ordering) */
+               swap_words(msgb_l2(nmsg), msgb_l2len(nmsg));
+               break;
+       }
+
+       return gsm48_rr_tx_traffic(ms, nmsg);
+}
+
+static int tch_data_check_bcap(const struct gsm_mncc_bearer_cap *bcap)
+{
+       if (bcap == NULL) {
+               LOGP(DL1C, LOGL_ERROR,
+                    "%s(): CC transaction without BCap\n",
+                    __func__);
+               return -ENODEV;
+       }
+
+       if (bcap->mode != GSM48_BCAP_TMOD_CIRCUIT) {
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): Transfer mode 0x%02x is not supported\n",
+                    __func__, bcap->mode);
+               return -ENOTSUP;
+       }
+       if (bcap->coding != GSM48_BCAP_CODING_GSM_STD) {
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): Coding standard 0x%02x is not supported\n",
+                    __func__, bcap->coding);
+               return -ENOTSUP;
+       }
+
+       switch (bcap->transfer) {
+       case GSM48_BCAP_ITCAP_UNR_DIG_INF:
+       case GSM48_BCAP_ITCAP_3k1_AUDIO:
+       case GSM48_BCAP_ITCAP_FAX_G3:
+               break;
+       default:
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): Information transfer capability 0x%02x is not 
supported\n",
+                    __func__, bcap->transfer);
+               return -ENOTSUP;
+       }
+
+       if (bcap->data.rate_adaption != GSM48_BCAP_RA_V110_X30) {
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): Rate adaption (octet 5) 0x%02x is not supported\n",
+                    __func__, bcap->data.rate_adaption);
+               return -ENOTSUP;
+       }
+       if (bcap->data.sig_access != GSM48_BCAP_SA_I440_I450) {
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): Signalling access protocol (octet 5) 0x%02x is not 
supported\n",
+                    __func__, bcap->data.sig_access);
+               return -ENOTSUP;
+       }
+       if (bcap->data.transp != GSM48_BCAP_TR_TRANSP) {
+               LOGP(DCC, LOGL_ERROR,
+                    "%s(): only transparent calls are supported so far\n",
+                    __func__);
+               return -ENOTSUP;
+       }
+
+       return 0;
+}
+
+/*************************************************************************************/
+
+int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg)
+{
+       struct tch_data_state *state = &ms->tch_state->data;
+
+       switch (state->handler) {
+       case TCH_DATA_IOH_LOOPBACK:
+               /* Remove the DL info header */
+               msgb_pull_to_l2(msg);
+               /* Send data frame back */
+               return tch_send_msg(ms, msg);
+       case TCH_DATA_IOH_UNIX_SOCK:
+               tch_csd_rx_from_l1(ms, msg);
+               tch_csd_tx_to_l1(ms);
+               msgb_free(msg);
+               break;
+       case TCH_DATA_IOH_NONE:
+               /* Drop voice frame */
+               msgb_free(msg);
+               break;
+       }
+
+       return 0;
+}
+
+int tch_data_state_init(struct gsm_trans *trans,
+                       struct tch_data_state *state)
+{
+       struct osmocom_ms *ms = trans->ms;
+       const struct gsm_mncc_bearer_cap *bcap = trans->cc.bcap;
+       int rc;
+
+       if ((rc = tch_data_check_bcap(bcap)) != 0)
+               return rc;
+
+       switch (state->handler) {
+       case TCH_DATA_IOH_UNIX_SOCK:
+               /* TODO: open listening socket */
+               break;
+       case TCH_DATA_IOH_LOOPBACK:
+       case TCH_DATA_IOH_NONE:
+               /* we don't need V.110 TA / soft-UART */
+               return 0;
+       default:
+               break;
+       }
+
+       if (bcap->data.async) {
+               state->suart = tch_soft_uart_alloc(ms, bcap);
+               if (state->suart == NULL)
+                       goto exit_free;
+       }
+
+       state->v110_ta = tch_v110_ta_alloc(ms, bcap);
+       if (state->v110_ta == NULL)
+               goto exit_free;
+
+       return 0;
+
+exit_free:
+       if (state->suart != NULL)
+               osmo_soft_uart_free(state->suart);
+       if (state->v110_ta != NULL)
+               osmo_v110_ta_free(state->v110_ta);
+       return -1;
+}
+
+void tch_data_state_free(struct tch_data_state *state)
+{
+       switch (state->handler) {
+       case TCH_DATA_IOH_UNIX_SOCK:
+               /* TODO: close listening socket */
+               break;
+       default:
+               break;
+       }
+
+       if (state->suart != NULL)
+               osmo_soft_uart_free(state->suart);
+       if (state->v110_ta != NULL)
+               osmo_v110_ta_free(state->v110_ta);
+}

--
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0
Gerrit-Change-Number: 35582
Gerrit-PatchSet: 6
Gerrit-Owner: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: osmith <osm...@sysmocom.de>
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to