From: Max <[email protected]>

Move hardware-spicefic files into subdirectory similar to the way it's
done in OsmoBTS to make adding more hardware support easier.
Make DSP access option name generic.
---
 src/Makefile.am                   |  51 +++--
 src/femtobts.c                    | 275 --------------------------
 src/femtobts.h                    |  57 ------
 src/osmo-bts-sysmo/femtobts.c     | 275 ++++++++++++++++++++++++++
 src/osmo-bts-sysmo/femtobts.h     |  57 ++++++
 src/osmo-bts-sysmo/sysmo_l1_fwd.c | 145 ++++++++++++++
 src/osmo-bts-sysmo/sysmo_l1_hw.c  | 216 +++++++++++++++++++++
 src/osmo-bts-sysmo/sysmo_l1_if.c  | 396 ++++++++++++++++++++++++++++++++++++++
 src/osmo-bts-sysmo/sysmo_l1_if.h  |  91 +++++++++
 src/osmobts_sock.cpp              |   2 +-
 src/pcu_l1_if.cpp                 |   6 +-
 src/sysmo_l1_fwd.c                | 145 --------------
 src/sysmo_l1_hw.c                 | 216 ---------------------
 src/sysmo_l1_if.c                 | 396 --------------------------------------
 src/sysmo_l1_if.h                 |  91 ---------
 15 files changed, 1214 insertions(+), 1205 deletions(-)
 delete mode 100644 src/femtobts.c
 delete mode 100644 src/femtobts.h
 create mode 100644 src/osmo-bts-sysmo/femtobts.c
 create mode 100644 src/osmo-bts-sysmo/femtobts.h
 create mode 100644 src/osmo-bts-sysmo/sysmo_l1_fwd.c
 create mode 100644 src/osmo-bts-sysmo/sysmo_l1_hw.c
 create mode 100644 src/osmo-bts-sysmo/sysmo_l1_if.c
 create mode 100644 src/osmo-bts-sysmo/sysmo_l1_if.h
 delete mode 100644 src/sysmo_l1_fwd.c
 delete mode 100644 src/sysmo_l1_hw.c
 delete mode 100644 src/sysmo_l1_if.c
 delete mode 100644 src/sysmo_l1_if.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 6428bef..3049744 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,7 @@
 AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) 
$(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS)

 if ENABLE_SYSMODSP
-AM_CPPFLAGS += -DENABLE_SYSMODSP
+AM_CPPFLAGS += -DENABLE_DIRECT_PHY
 endif

 AM_CXXFLAGS = -Wall -ldl -pthread
@@ -64,11 +64,6 @@ bin_PROGRAMS = \

 noinst_PROGRAMS =

-if ENABLE_SYSMODSP
-noinst_PROGRAMS += \
-       osmo-pcu-remote
-endif
-
 noinst_HEADERS = \
        gprs_debug.h \
        csn1.h \
@@ -83,8 +78,6 @@ noinst_HEADERS = \
        bitvector.h \
        pcu_vty.h \
        pcu_vty_functions.h \
-       sysmo_l1_if.h \
-       femtobts.h \
        tbf.h \
        bts.h \
        poll_controller.h \
@@ -101,30 +94,46 @@ noinst_HEADERS = \
 osmo_pcu_SOURCES = pcu_main.cpp

 if ENABLE_SYSMODSP
-osmo_pcu_SOURCES += sysmo_l1_if.c \
-       sysmo_l1_hw.c \
-       femtobts.c
-
-osmo_pcu_remote_SOURCES = pcu_main.cpp \
-       sysmo_l1_if.c \
-       sysmo_l1_fwd.c \
-       femtobts.c
-endif
+AM_CPPFLAGS += -I$(srcdir)/osmo-bts-sysmo

-osmo_pcu_LDADD = \
+EXTRA_DIST = \
+       osmo-bts-sysmo/sysmo_l1_if.c \
+        osmo-bts-sysmo/sysmo_l1_if.h \
+        osmo-bts-sysmo/sysmo_l1_hw.c \
+        osmo-bts-sysmo/femtobts.c \
+        osmo-bts-sysmo/femtobts.h
+
+noinst_HEADERS += \
+        osmo-bts-sysmo/sysmo_l1_if.h \
+        osmo-bts-sysmo/femtobts.h
+
+noinst_PROGRAMS += \
+       osmo-pcu-remote
+
+osmo_pcu_SOURCES += \
+       osmo-bts-sysmo/sysmo_l1_if.c \
+       osmo-bts-sysmo/sysmo_l1_hw.c \
+       osmo-bts-sysmo/femtobts.c
+
+osmo_pcu_remote_SOURCES = \
+       pcu_main.cpp \
+       osmo-bts-sysmo/sysmo_l1_if.c \
+       osmo-bts-sysmo/sysmo_l1_fwd.c \
+       osmo-bts-sysmo/femtobts.c
+
+osmo_pcu_remote_LDADD = \
        libgprs.la \
        $(LIBOSMOGB_LIBS) \
        $(LIBOSMOCORE_LIBS) \
        $(LIBOSMOGSM_LIBS) \
        $(COMMON_LA)
+endif

-if ENABLE_SYSMODSP
-osmo_pcu_remote_LDADD = \
+osmo_pcu_LDADD = \
        libgprs.la \
        $(LIBOSMOGB_LIBS) \
        $(LIBOSMOCORE_LIBS) \
        $(LIBOSMOGSM_LIBS) \
        $(COMMON_LA)
-endif

 #MOSTLYCLEANFILES += testSource testDestination
diff --git a/src/femtobts.c b/src/femtobts.c
deleted file mode 100644
index f6957d2..0000000
--- a/src/femtobts.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* sysmocom femtobts L1 API related definitions */
-
-/* (C) 2011 by Harald Welte <[email protected]>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sysmocom/femtobts/superfemto.h>
-#include <sysmocom/femtobts/gsml1const.h>
-#include <sysmocom/femtobts/gsml1dbg.h>
-
-#include "femtobts.h"
-
-const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM] = {
-       [GsmL1_PrimId_MphInitReq]       = L1P_T_REQ,
-       [GsmL1_PrimId_MphCloseReq]      = L1P_T_REQ,
-       [GsmL1_PrimId_MphConnectReq]    = L1P_T_REQ,
-       [GsmL1_PrimId_MphDisconnectReq] = L1P_T_REQ,
-       [GsmL1_PrimId_MphActivateReq]   = L1P_T_REQ,
-       [GsmL1_PrimId_MphDeactivateReq] = L1P_T_REQ,
-       [GsmL1_PrimId_MphConfigReq]     = L1P_T_REQ,
-       [GsmL1_PrimId_MphMeasureReq]    = L1P_T_REQ,
-       [GsmL1_PrimId_MphInitCnf]       = L1P_T_CONF,
-       [GsmL1_PrimId_MphCloseCnf]      = L1P_T_CONF,
-       [GsmL1_PrimId_MphConnectCnf]    = L1P_T_CONF,
-       [GsmL1_PrimId_MphDisconnectCnf] = L1P_T_CONF,
-       [GsmL1_PrimId_MphActivateCnf]   = L1P_T_CONF,
-       [GsmL1_PrimId_MphDeactivateCnf] = L1P_T_CONF,
-       [GsmL1_PrimId_MphConfigCnf]     = L1P_T_CONF,
-       [GsmL1_PrimId_MphMeasureCnf]    = L1P_T_CONF,
-       [GsmL1_PrimId_MphTimeInd]       = L1P_T_IND,
-       [GsmL1_PrimId_MphSyncInd]       = L1P_T_IND,
-       [GsmL1_PrimId_PhEmptyFrameReq]  = L1P_T_REQ,
-       [GsmL1_PrimId_PhDataReq]        = L1P_T_REQ,
-       [GsmL1_PrimId_PhConnectInd]     = L1P_T_IND,
-       [GsmL1_PrimId_PhReadyToSendInd] = L1P_T_IND,
-       [GsmL1_PrimId_PhDataInd]        = L1P_T_IND,
-       [GsmL1_PrimId_PhRaInd]          = L1P_T_IND,
-};
-
-const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1] = {
-       { GsmL1_PrimId_MphInitReq,      "MPH-INIT.req" },
-       { GsmL1_PrimId_MphCloseReq,     "MPH-CLOSE.req" },
-       { GsmL1_PrimId_MphConnectReq,   "MPH-CONNECT.req" },
-       { GsmL1_PrimId_MphDisconnectReq,"MPH-DISCONNECT.req" },
-       { GsmL1_PrimId_MphActivateReq,  "MPH-ACTIVATE.req" },
-       { GsmL1_PrimId_MphDeactivateReq,"MPH-DEACTIVATE.req" },
-       { GsmL1_PrimId_MphConfigReq,    "MPH-CONFIG.req" },
-       { GsmL1_PrimId_MphMeasureReq,   "MPH-MEASURE.req" },
-       { GsmL1_PrimId_MphInitCnf,      "MPH-INIT.conf" },
-       { GsmL1_PrimId_MphCloseCnf,     "MPH-CLOSE.conf" },
-       { GsmL1_PrimId_MphConnectCnf,   "MPH-CONNECT.conf" },
-       { GsmL1_PrimId_MphDisconnectCnf,"MPH-DISCONNECT.conf" },
-       { GsmL1_PrimId_MphActivateCnf,  "MPH-ACTIVATE.conf" },
-       { GsmL1_PrimId_MphDeactivateCnf,"MPH-DEACTIVATE.conf" },
-       { GsmL1_PrimId_MphConfigCnf,    "MPH-CONFIG.conf" },
-       { GsmL1_PrimId_MphMeasureCnf,   "MPH-MEASURE.conf" },
-       { GsmL1_PrimId_MphTimeInd,      "MPH-TIME.ind" },
-       { GsmL1_PrimId_MphSyncInd,      "MPH-SYNC.ind" },
-       { GsmL1_PrimId_PhEmptyFrameReq, "PH-EMPTY_FRAME.req" },
-       { GsmL1_PrimId_PhDataReq,       "PH-DATA.req" },
-       { GsmL1_PrimId_PhConnectInd,    "PH-CONNECT.ind" },
-       { GsmL1_PrimId_PhReadyToSendInd,"PH-READY_TO_SEND.ind" },
-       { GsmL1_PrimId_PhDataInd,       "PH-DATA.ind" },
-       { GsmL1_PrimId_PhRaInd,         "PH-RA.ind" },
-       { 0, NULL }
-};
-
-const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM] = {
-       [GsmL1_PrimId_MphInitReq]       = GsmL1_PrimId_MphInitCnf,
-       [GsmL1_PrimId_MphCloseReq]      = GsmL1_PrimId_MphCloseCnf,
-       [GsmL1_PrimId_MphConnectReq]    = GsmL1_PrimId_MphConnectCnf,
-       [GsmL1_PrimId_MphDisconnectReq] = GsmL1_PrimId_MphDisconnectCnf,
-       [GsmL1_PrimId_MphActivateReq]   = GsmL1_PrimId_MphActivateCnf,
-       [GsmL1_PrimId_MphDeactivateReq] = GsmL1_PrimId_MphDeactivateCnf,
-       [GsmL1_PrimId_MphConfigReq]     = GsmL1_PrimId_MphConfigCnf,
-       [GsmL1_PrimId_MphMeasureReq]    = GsmL1_PrimId_MphMeasureCnf,
-};
-
-const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = {
-       [SuperFemto_PrimId_SystemInfoReq]               = L1P_T_REQ,
-       [SuperFemto_PrimId_SystemInfoCnf]               = L1P_T_CONF,
-       [SuperFemto_PrimId_SystemFailureInd]    = L1P_T_IND,
-       [SuperFemto_PrimId_ActivateRfReq]               = L1P_T_REQ,
-       [SuperFemto_PrimId_ActivateRfCnf]               = L1P_T_CONF,
-       [SuperFemto_PrimId_DeactivateRfReq]     = L1P_T_REQ,
-       [SuperFemto_PrimId_DeactivateRfCnf]     = L1P_T_CONF,
-       [SuperFemto_PrimId_SetTraceFlagsReq]    = L1P_T_REQ,
-       [SuperFemto_PrimId_RfClockInfoReq]      = L1P_T_REQ,
-       [SuperFemto_PrimId_RfClockInfoCnf]      = L1P_T_CONF,
-       [SuperFemto_PrimId_RfClockSetupReq]     = L1P_T_REQ,
-       [SuperFemto_PrimId_RfClockSetupCnf]     = L1P_T_CONF,
-       [SuperFemto_PrimId_Layer1ResetReq]      = L1P_T_REQ,
-       [SuperFemto_PrimId_Layer1ResetCnf]      = L1P_T_CONF,
-};
-
-const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = {
-       { SuperFemto_PrimId_SystemInfoReq,      "SYSTEM-INFO.req" },
-       { SuperFemto_PrimId_SystemInfoCnf,      "SYSTEM-INFO.conf" },
-       { SuperFemto_PrimId_SystemFailureInd,   "SYSTEM-FAILURE.ind" },
-       { SuperFemto_PrimId_ActivateRfReq,      "ACTIVATE-RF.req" },
-       { SuperFemto_PrimId_ActivateRfCnf,      "ACTIVATE-RF.conf" },
-       { SuperFemto_PrimId_DeactivateRfReq,    "DEACTIVATE-RF.req" },
-       { SuperFemto_PrimId_DeactivateRfCnf,    "DEACTIVATE-RF.conf" },
-       { SuperFemto_PrimId_SetTraceFlagsReq,   "SET-TRACE-FLAGS.req" },
-       { SuperFemto_PrimId_RfClockInfoReq,     "RF-CLOCK-INFO.req" },
-       { SuperFemto_PrimId_RfClockInfoCnf,     "RF-CLOCK-INFO.conf" },
-       { SuperFemto_PrimId_RfClockSetupReq,    "RF-CLOCK-SETUP.req" },
-       { SuperFemto_PrimId_RfClockSetupCnf,    "RF-CLOCK-SETUP.conf" },
-       { SuperFemto_PrimId_Layer1ResetReq,     "LAYER1-RESET.req" },
-       { SuperFemto_PrimId_Layer1ResetCnf,     "LAYER1-RESET.conf" },
-       { 0, NULL }
-};
-
-const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = {
-       [SuperFemto_PrimId_SystemInfoReq]       = 
SuperFemto_PrimId_SystemInfoCnf,
-       [SuperFemto_PrimId_ActivateRfReq]       = 
SuperFemto_PrimId_ActivateRfCnf,
-       [SuperFemto_PrimId_DeactivateRfReq]     = 
SuperFemto_PrimId_DeactivateRfCnf,
-       [SuperFemto_PrimId_RfClockInfoReq]      = 
SuperFemto_PrimId_RfClockInfoCnf,
-       [SuperFemto_PrimId_RfClockSetupReq]     = 
SuperFemto_PrimId_RfClockSetupCnf,
-       [SuperFemto_PrimId_Layer1ResetReq]      = 
SuperFemto_PrimId_Layer1ResetCnf,
-};
-
-const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = {
-       { GsmL1_Sapi_Fcch,      "FCCH" },
-       { GsmL1_Sapi_Sch,       "SCH" },
-       { GsmL1_Sapi_Sacch,     "SACCH" },
-       { GsmL1_Sapi_Sdcch,     "SDCCH" },
-       { GsmL1_Sapi_Bcch,      "BCCH" },
-       { GsmL1_Sapi_Pch,       "PCH" },
-       { GsmL1_Sapi_Agch,      "AGCH" },
-       { GsmL1_Sapi_Cbch,      "CBCH" },
-       { GsmL1_Sapi_Rach,      "RACH" },
-       { GsmL1_Sapi_TchF,      "TCH/F" },
-       { GsmL1_Sapi_FacchF,    "FACCH/F" },
-       { GsmL1_Sapi_TchH,      "TCH/H" },
-       { GsmL1_Sapi_FacchH,    "FACCH/H" },
-       { GsmL1_Sapi_Nch,       "NCH" },
-       { GsmL1_Sapi_Pdtch,     "PDTCH" },
-       { GsmL1_Sapi_Pacch,     "PACCH" },
-       { GsmL1_Sapi_Pbcch,     "PBCCH" },
-       { GsmL1_Sapi_Pagch,     "PAGCH" },
-       { GsmL1_Sapi_Ppch,      "PPCH" },
-       { GsmL1_Sapi_Pnch,      "PNCH" },
-       { GsmL1_Sapi_Ptcch,     "PTCCH" },
-       { GsmL1_Sapi_Prach,     "PRACH" },
-       { 0, NULL }
-};
-
-const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1] = {
-       { GsmL1_Status_Success,         "Success" },
-       { GsmL1_Status_Generic,         "Generic error" },
-       { GsmL1_Status_NoMemory,        "Not enough memory" },
-       { GsmL1_Status_Timeout,         "Timeout" },
-       { GsmL1_Status_InvalidParam,    "Invalid parameter" },
-       { GsmL1_Status_Busy,            "Resource busy" },
-       { GsmL1_Status_NoRessource,     "No more resources" },
-       { GsmL1_Status_Uninitialized,   "Trying to use uninitialized resource" 
},
-       { GsmL1_Status_NullInterface,   "Trying to call a NULL interface" },
-       { GsmL1_Status_NullFctnPtr,     "Trying to call a NULL function ptr" },
-       { GsmL1_Status_BadCrc,          "Bad CRC" },
-       { GsmL1_Status_BadUsf,          "Bad USF" },
-       { GsmL1_Status_InvalidCPS,      "Invalid CPS field" },
-       { GsmL1_Status_UnexpectedBurst, "Unexpected burst" },
-       { GsmL1_Status_UnavailCodec,    "AMR codec is unavailable" },
-       { GsmL1_Status_CriticalError,   "Critical error" },
-       { GsmL1_Status_OverheatError,   "Overheat error" },
-       { GsmL1_Status_DeviceError,     "Device error" },
-       { GsmL1_Status_FacchError,      "FACCH / TCH order error" },
-       { GsmL1_Status_AlreadyDeactivated, "Lchan already deactivated" },
-       { GsmL1_Status_TxBurstFifoOvrn, "FIFO overrun" },
-       { GsmL1_Status_TxBurstFifoUndr, "FIFO underrun" },
-       { GsmL1_Status_NotSynchronized, "Not synchronized" },
-       { GsmL1_Status_Unsupported,     "Unsupported feature" },
-       { 0, NULL }
-};
-
-const struct value_string femtobts_tracef_names[29] = {
-       { DBG_DEBUG,                    "DEBUG" },
-       { DBG_L1WARNING,                "L1_WARNING" },
-       { DBG_ERROR,                    "ERROR" },
-       { DBG_L1RXMSG,                  "L1_RX_MSG" },
-       { DBG_L1RXMSGBYTE,              "L1_RX_MSG_BYTE" },
-       { DBG_L1TXMSG,                  "L1_TX_MSG" },
-       { DBG_L1TXMSGBYTE,              "L1_TX_MSG_BYTE" },
-       { DBG_MPHCNF,                   "MPH_CNF" },
-       { DBG_MPHIND,                   "MPH_IND" },
-       { DBG_MPHREQ,                   "MPH_REQ" },
-       { DBG_PHIND,                    "PH_IND" },
-       { DBG_PHREQ,                    "PH_REQ" },
-       { DBG_PHYRF,                    "PHY_RF" },
-       { DBG_PHYRFMSGBYTE,             "PHY_MSG_BYTE" },
-       { DBG_MODE,                     "MODE" },
-       { DBG_TDMAINFO,                 "TDMA_INFO" },
-       { DBG_BADCRC,                   "BAD_CRC" },
-       { DBG_PHINDBYTE,                "PH_IND_BYTE" },
-       { DBG_PHREQBYTE,                "PH_REQ_BYTE" },
-       { DBG_DEVICEMSG,                "DEVICE_MSG" },
-       { DBG_RACHINFO,                 "RACH_INFO" },
-       { DBG_LOGCHINFO,                "LOG_CH_INFO" },
-       { DBG_MEMORY,                   "MEMORY" },
-       { DBG_PROFILING,                "PROFILING" },
-       { DBG_TESTCOMMENT,              "TEST_COMMENT" },
-       { DBG_TEST,                     "TEST" },
-       { DBG_STATUS,                   "STATUS" },
-       { 0, NULL }
-};
-
-const struct value_string femtobts_tch_pl_names[] = {
-       { GsmL1_TchPlType_NA,                   "N/A" },
-       { GsmL1_TchPlType_Fr,                   "FR" },
-       { GsmL1_TchPlType_Hr,                   "HR" },
-       { GsmL1_TchPlType_Efr,                  "EFR" },
-       { GsmL1_TchPlType_Amr,                  "AMR(IF2)" },
-       { GsmL1_TchPlType_Amr_SidBad,           "AMR(SID BAD)" },
-       { GsmL1_TchPlType_Amr_Onset,            "AMR(ONSET)" },
-       { GsmL1_TchPlType_Amr_Ratscch,          "AMR(RATSCCH)" },
-       { GsmL1_TchPlType_Amr_SidUpdateInH,     "AMR(SID_UPDATE INH)" },
-       { GsmL1_TchPlType_Amr_SidFirstP1,       "AMR(SID_FIRST P1)" },
-       { GsmL1_TchPlType_Amr_SidFirstP2,       "AMR(SID_FIRST P2)" },
-       { GsmL1_TchPlType_Amr_SidFirstInH,      "AMR(SID_FIRST INH)" },
-       { GsmL1_TchPlType_Amr_RatscchMarker,    "AMR(RATSCCH MARK)" },
-       { GsmL1_TchPlType_Amr_RatscchData,      "AMR(RATSCCH DATA)" },
-       { 0, NULL }
-};
-
-const struct value_string femtobts_dir_names[] = {
-       { GsmL1_Dir_TxDownlink, "TxDL" },
-       { GsmL1_Dir_TxUplink,   "TxUL" },
-       { GsmL1_Dir_RxUplink,   "RxUL" },
-       { GsmL1_Dir_RxDownlink, "RxDL" },
-       { GsmL1_Dir_TxDownlink|GsmL1_Dir_RxUplink, "BOTH" },
-       { 0, NULL }
-};
-
-const struct value_string femtobts_chcomb_names[] = {
-       { GsmL1_LogChComb_0,    "dummy" },
-       { GsmL1_LogChComb_I,    "tch_f" },
-       { GsmL1_LogChComb_II,   "tch_h" },
-       { GsmL1_LogChComb_IV,   "ccch" },
-       { GsmL1_LogChComb_V,    "ccch_sdcch4" },
-       { GsmL1_LogChComb_VII,  "sdcch8" },
-       { GsmL1_LogChComb_XIII, "pdtch" },
-       { 0, NULL }
-};
-
-const uint8_t pdch_msu_size[_NUM_PDCH_CS] = {
-       [PDCH_CS_1]     = 23,
-       [PDCH_CS_2]     = 34,
-       [PDCH_CS_3]     = 40,
-       [PDCH_CS_4]     = 54,
-       [PDCH_MCS_1]    = 27,
-       [PDCH_MCS_2]    = 33,
-       [PDCH_MCS_3]    = 42,
-       [PDCH_MCS_4]    = 49,
-       [PDCH_MCS_5]    = 60,
-       [PDCH_MCS_6]    = 78,
-       [PDCH_MCS_7]    = 118,
-       [PDCH_MCS_8]    = 142,
-       [PDCH_MCS_9]    = 154
-};
diff --git a/src/femtobts.h b/src/femtobts.h
deleted file mode 100644
index 7e45578..0000000
--- a/src/femtobts.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef FEMTOBTS_H
-#define FEMTOBTS_H
-
-#include <stdlib.h>
-#include <osmocom/core/utils.h>
-
-#include <sysmocom/femtobts/superfemto.h>
-#include <sysmocom/femtobts/gsml1const.h>
-
-#ifdef L1_HAS_RTP_MODE
-/* This is temporarily disabled, as AMR has some bugs in RTP mode */
-//#define USE_L1_RTP_MODE              /* Tell L1 to use RTP mode */
-#endif
-
-enum l1prim_type {
-       L1P_T_REQ,
-       L1P_T_CONF,
-       L1P_T_IND,
-};
-
-const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM];
-const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1];
-const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM];
-
-const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM];
-const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1];
-const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM];
-
-const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1];
-const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1];
-
-const struct value_string femtobts_tracef_names[29];
-
-const struct value_string femtobts_tch_pl_names[15];
-
-const struct value_string femtobts_dir_names[6];
-
-enum pdch_cs {
-       PDCH_CS_1,
-       PDCH_CS_2,
-       PDCH_CS_3,
-       PDCH_CS_4,
-       PDCH_MCS_1,
-       PDCH_MCS_2,
-       PDCH_MCS_3,
-       PDCH_MCS_4,
-       PDCH_MCS_5,
-       PDCH_MCS_6,
-       PDCH_MCS_7,
-       PDCH_MCS_8,
-       PDCH_MCS_9,
-       _NUM_PDCH_CS
-};
-
-const uint8_t pdch_msu_size[_NUM_PDCH_CS];
-
-#endif /* FEMTOBTS_H */
diff --git a/src/osmo-bts-sysmo/femtobts.c b/src/osmo-bts-sysmo/femtobts.c
new file mode 100644
index 0000000..f6957d2
--- /dev/null
+++ b/src/osmo-bts-sysmo/femtobts.c
@@ -0,0 +1,275 @@
+/* sysmocom femtobts L1 API related definitions */
+
+/* (C) 2011 by Harald Welte <[email protected]>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sysmocom/femtobts/superfemto.h>
+#include <sysmocom/femtobts/gsml1const.h>
+#include <sysmocom/femtobts/gsml1dbg.h>
+
+#include "femtobts.h"
+
+const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM] = {
+       [GsmL1_PrimId_MphInitReq]       = L1P_T_REQ,
+       [GsmL1_PrimId_MphCloseReq]      = L1P_T_REQ,
+       [GsmL1_PrimId_MphConnectReq]    = L1P_T_REQ,
+       [GsmL1_PrimId_MphDisconnectReq] = L1P_T_REQ,
+       [GsmL1_PrimId_MphActivateReq]   = L1P_T_REQ,
+       [GsmL1_PrimId_MphDeactivateReq] = L1P_T_REQ,
+       [GsmL1_PrimId_MphConfigReq]     = L1P_T_REQ,
+       [GsmL1_PrimId_MphMeasureReq]    = L1P_T_REQ,
+       [GsmL1_PrimId_MphInitCnf]       = L1P_T_CONF,
+       [GsmL1_PrimId_MphCloseCnf]      = L1P_T_CONF,
+       [GsmL1_PrimId_MphConnectCnf]    = L1P_T_CONF,
+       [GsmL1_PrimId_MphDisconnectCnf] = L1P_T_CONF,
+       [GsmL1_PrimId_MphActivateCnf]   = L1P_T_CONF,
+       [GsmL1_PrimId_MphDeactivateCnf] = L1P_T_CONF,
+       [GsmL1_PrimId_MphConfigCnf]     = L1P_T_CONF,
+       [GsmL1_PrimId_MphMeasureCnf]    = L1P_T_CONF,
+       [GsmL1_PrimId_MphTimeInd]       = L1P_T_IND,
+       [GsmL1_PrimId_MphSyncInd]       = L1P_T_IND,
+       [GsmL1_PrimId_PhEmptyFrameReq]  = L1P_T_REQ,
+       [GsmL1_PrimId_PhDataReq]        = L1P_T_REQ,
+       [GsmL1_PrimId_PhConnectInd]     = L1P_T_IND,
+       [GsmL1_PrimId_PhReadyToSendInd] = L1P_T_IND,
+       [GsmL1_PrimId_PhDataInd]        = L1P_T_IND,
+       [GsmL1_PrimId_PhRaInd]          = L1P_T_IND,
+};
+
+const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1] = {
+       { GsmL1_PrimId_MphInitReq,      "MPH-INIT.req" },
+       { GsmL1_PrimId_MphCloseReq,     "MPH-CLOSE.req" },
+       { GsmL1_PrimId_MphConnectReq,   "MPH-CONNECT.req" },
+       { GsmL1_PrimId_MphDisconnectReq,"MPH-DISCONNECT.req" },
+       { GsmL1_PrimId_MphActivateReq,  "MPH-ACTIVATE.req" },
+       { GsmL1_PrimId_MphDeactivateReq,"MPH-DEACTIVATE.req" },
+       { GsmL1_PrimId_MphConfigReq,    "MPH-CONFIG.req" },
+       { GsmL1_PrimId_MphMeasureReq,   "MPH-MEASURE.req" },
+       { GsmL1_PrimId_MphInitCnf,      "MPH-INIT.conf" },
+       { GsmL1_PrimId_MphCloseCnf,     "MPH-CLOSE.conf" },
+       { GsmL1_PrimId_MphConnectCnf,   "MPH-CONNECT.conf" },
+       { GsmL1_PrimId_MphDisconnectCnf,"MPH-DISCONNECT.conf" },
+       { GsmL1_PrimId_MphActivateCnf,  "MPH-ACTIVATE.conf" },
+       { GsmL1_PrimId_MphDeactivateCnf,"MPH-DEACTIVATE.conf" },
+       { GsmL1_PrimId_MphConfigCnf,    "MPH-CONFIG.conf" },
+       { GsmL1_PrimId_MphMeasureCnf,   "MPH-MEASURE.conf" },
+       { GsmL1_PrimId_MphTimeInd,      "MPH-TIME.ind" },
+       { GsmL1_PrimId_MphSyncInd,      "MPH-SYNC.ind" },
+       { GsmL1_PrimId_PhEmptyFrameReq, "PH-EMPTY_FRAME.req" },
+       { GsmL1_PrimId_PhDataReq,       "PH-DATA.req" },
+       { GsmL1_PrimId_PhConnectInd,    "PH-CONNECT.ind" },
+       { GsmL1_PrimId_PhReadyToSendInd,"PH-READY_TO_SEND.ind" },
+       { GsmL1_PrimId_PhDataInd,       "PH-DATA.ind" },
+       { GsmL1_PrimId_PhRaInd,         "PH-RA.ind" },
+       { 0, NULL }
+};
+
+const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM] = {
+       [GsmL1_PrimId_MphInitReq]       = GsmL1_PrimId_MphInitCnf,
+       [GsmL1_PrimId_MphCloseReq]      = GsmL1_PrimId_MphCloseCnf,
+       [GsmL1_PrimId_MphConnectReq]    = GsmL1_PrimId_MphConnectCnf,
+       [GsmL1_PrimId_MphDisconnectReq] = GsmL1_PrimId_MphDisconnectCnf,
+       [GsmL1_PrimId_MphActivateReq]   = GsmL1_PrimId_MphActivateCnf,
+       [GsmL1_PrimId_MphDeactivateReq] = GsmL1_PrimId_MphDeactivateCnf,
+       [GsmL1_PrimId_MphConfigReq]     = GsmL1_PrimId_MphConfigCnf,
+       [GsmL1_PrimId_MphMeasureReq]    = GsmL1_PrimId_MphMeasureCnf,
+};
+
+const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM] = {
+       [SuperFemto_PrimId_SystemInfoReq]               = L1P_T_REQ,
+       [SuperFemto_PrimId_SystemInfoCnf]               = L1P_T_CONF,
+       [SuperFemto_PrimId_SystemFailureInd]    = L1P_T_IND,
+       [SuperFemto_PrimId_ActivateRfReq]               = L1P_T_REQ,
+       [SuperFemto_PrimId_ActivateRfCnf]               = L1P_T_CONF,
+       [SuperFemto_PrimId_DeactivateRfReq]     = L1P_T_REQ,
+       [SuperFemto_PrimId_DeactivateRfCnf]     = L1P_T_CONF,
+       [SuperFemto_PrimId_SetTraceFlagsReq]    = L1P_T_REQ,
+       [SuperFemto_PrimId_RfClockInfoReq]      = L1P_T_REQ,
+       [SuperFemto_PrimId_RfClockInfoCnf]      = L1P_T_CONF,
+       [SuperFemto_PrimId_RfClockSetupReq]     = L1P_T_REQ,
+       [SuperFemto_PrimId_RfClockSetupCnf]     = L1P_T_CONF,
+       [SuperFemto_PrimId_Layer1ResetReq]      = L1P_T_REQ,
+       [SuperFemto_PrimId_Layer1ResetCnf]      = L1P_T_CONF,
+};
+
+const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1] = {
+       { SuperFemto_PrimId_SystemInfoReq,      "SYSTEM-INFO.req" },
+       { SuperFemto_PrimId_SystemInfoCnf,      "SYSTEM-INFO.conf" },
+       { SuperFemto_PrimId_SystemFailureInd,   "SYSTEM-FAILURE.ind" },
+       { SuperFemto_PrimId_ActivateRfReq,      "ACTIVATE-RF.req" },
+       { SuperFemto_PrimId_ActivateRfCnf,      "ACTIVATE-RF.conf" },
+       { SuperFemto_PrimId_DeactivateRfReq,    "DEACTIVATE-RF.req" },
+       { SuperFemto_PrimId_DeactivateRfCnf,    "DEACTIVATE-RF.conf" },
+       { SuperFemto_PrimId_SetTraceFlagsReq,   "SET-TRACE-FLAGS.req" },
+       { SuperFemto_PrimId_RfClockInfoReq,     "RF-CLOCK-INFO.req" },
+       { SuperFemto_PrimId_RfClockInfoCnf,     "RF-CLOCK-INFO.conf" },
+       { SuperFemto_PrimId_RfClockSetupReq,    "RF-CLOCK-SETUP.req" },
+       { SuperFemto_PrimId_RfClockSetupCnf,    "RF-CLOCK-SETUP.conf" },
+       { SuperFemto_PrimId_Layer1ResetReq,     "LAYER1-RESET.req" },
+       { SuperFemto_PrimId_Layer1ResetCnf,     "LAYER1-RESET.conf" },
+       { 0, NULL }
+};
+
+const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM] = {
+       [SuperFemto_PrimId_SystemInfoReq]       = 
SuperFemto_PrimId_SystemInfoCnf,
+       [SuperFemto_PrimId_ActivateRfReq]       = 
SuperFemto_PrimId_ActivateRfCnf,
+       [SuperFemto_PrimId_DeactivateRfReq]     = 
SuperFemto_PrimId_DeactivateRfCnf,
+       [SuperFemto_PrimId_RfClockInfoReq]      = 
SuperFemto_PrimId_RfClockInfoCnf,
+       [SuperFemto_PrimId_RfClockSetupReq]     = 
SuperFemto_PrimId_RfClockSetupCnf,
+       [SuperFemto_PrimId_Layer1ResetReq]      = 
SuperFemto_PrimId_Layer1ResetCnf,
+};
+
+const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1] = {
+       { GsmL1_Sapi_Fcch,      "FCCH" },
+       { GsmL1_Sapi_Sch,       "SCH" },
+       { GsmL1_Sapi_Sacch,     "SACCH" },
+       { GsmL1_Sapi_Sdcch,     "SDCCH" },
+       { GsmL1_Sapi_Bcch,      "BCCH" },
+       { GsmL1_Sapi_Pch,       "PCH" },
+       { GsmL1_Sapi_Agch,      "AGCH" },
+       { GsmL1_Sapi_Cbch,      "CBCH" },
+       { GsmL1_Sapi_Rach,      "RACH" },
+       { GsmL1_Sapi_TchF,      "TCH/F" },
+       { GsmL1_Sapi_FacchF,    "FACCH/F" },
+       { GsmL1_Sapi_TchH,      "TCH/H" },
+       { GsmL1_Sapi_FacchH,    "FACCH/H" },
+       { GsmL1_Sapi_Nch,       "NCH" },
+       { GsmL1_Sapi_Pdtch,     "PDTCH" },
+       { GsmL1_Sapi_Pacch,     "PACCH" },
+       { GsmL1_Sapi_Pbcch,     "PBCCH" },
+       { GsmL1_Sapi_Pagch,     "PAGCH" },
+       { GsmL1_Sapi_Ppch,      "PPCH" },
+       { GsmL1_Sapi_Pnch,      "PNCH" },
+       { GsmL1_Sapi_Ptcch,     "PTCCH" },
+       { GsmL1_Sapi_Prach,     "PRACH" },
+       { 0, NULL }
+};
+
+const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1] = {
+       { GsmL1_Status_Success,         "Success" },
+       { GsmL1_Status_Generic,         "Generic error" },
+       { GsmL1_Status_NoMemory,        "Not enough memory" },
+       { GsmL1_Status_Timeout,         "Timeout" },
+       { GsmL1_Status_InvalidParam,    "Invalid parameter" },
+       { GsmL1_Status_Busy,            "Resource busy" },
+       { GsmL1_Status_NoRessource,     "No more resources" },
+       { GsmL1_Status_Uninitialized,   "Trying to use uninitialized resource" 
},
+       { GsmL1_Status_NullInterface,   "Trying to call a NULL interface" },
+       { GsmL1_Status_NullFctnPtr,     "Trying to call a NULL function ptr" },
+       { GsmL1_Status_BadCrc,          "Bad CRC" },
+       { GsmL1_Status_BadUsf,          "Bad USF" },
+       { GsmL1_Status_InvalidCPS,      "Invalid CPS field" },
+       { GsmL1_Status_UnexpectedBurst, "Unexpected burst" },
+       { GsmL1_Status_UnavailCodec,    "AMR codec is unavailable" },
+       { GsmL1_Status_CriticalError,   "Critical error" },
+       { GsmL1_Status_OverheatError,   "Overheat error" },
+       { GsmL1_Status_DeviceError,     "Device error" },
+       { GsmL1_Status_FacchError,      "FACCH / TCH order error" },
+       { GsmL1_Status_AlreadyDeactivated, "Lchan already deactivated" },
+       { GsmL1_Status_TxBurstFifoOvrn, "FIFO overrun" },
+       { GsmL1_Status_TxBurstFifoUndr, "FIFO underrun" },
+       { GsmL1_Status_NotSynchronized, "Not synchronized" },
+       { GsmL1_Status_Unsupported,     "Unsupported feature" },
+       { 0, NULL }
+};
+
+const struct value_string femtobts_tracef_names[29] = {
+       { DBG_DEBUG,                    "DEBUG" },
+       { DBG_L1WARNING,                "L1_WARNING" },
+       { DBG_ERROR,                    "ERROR" },
+       { DBG_L1RXMSG,                  "L1_RX_MSG" },
+       { DBG_L1RXMSGBYTE,              "L1_RX_MSG_BYTE" },
+       { DBG_L1TXMSG,                  "L1_TX_MSG" },
+       { DBG_L1TXMSGBYTE,              "L1_TX_MSG_BYTE" },
+       { DBG_MPHCNF,                   "MPH_CNF" },
+       { DBG_MPHIND,                   "MPH_IND" },
+       { DBG_MPHREQ,                   "MPH_REQ" },
+       { DBG_PHIND,                    "PH_IND" },
+       { DBG_PHREQ,                    "PH_REQ" },
+       { DBG_PHYRF,                    "PHY_RF" },
+       { DBG_PHYRFMSGBYTE,             "PHY_MSG_BYTE" },
+       { DBG_MODE,                     "MODE" },
+       { DBG_TDMAINFO,                 "TDMA_INFO" },
+       { DBG_BADCRC,                   "BAD_CRC" },
+       { DBG_PHINDBYTE,                "PH_IND_BYTE" },
+       { DBG_PHREQBYTE,                "PH_REQ_BYTE" },
+       { DBG_DEVICEMSG,                "DEVICE_MSG" },
+       { DBG_RACHINFO,                 "RACH_INFO" },
+       { DBG_LOGCHINFO,                "LOG_CH_INFO" },
+       { DBG_MEMORY,                   "MEMORY" },
+       { DBG_PROFILING,                "PROFILING" },
+       { DBG_TESTCOMMENT,              "TEST_COMMENT" },
+       { DBG_TEST,                     "TEST" },
+       { DBG_STATUS,                   "STATUS" },
+       { 0, NULL }
+};
+
+const struct value_string femtobts_tch_pl_names[] = {
+       { GsmL1_TchPlType_NA,                   "N/A" },
+       { GsmL1_TchPlType_Fr,                   "FR" },
+       { GsmL1_TchPlType_Hr,                   "HR" },
+       { GsmL1_TchPlType_Efr,                  "EFR" },
+       { GsmL1_TchPlType_Amr,                  "AMR(IF2)" },
+       { GsmL1_TchPlType_Amr_SidBad,           "AMR(SID BAD)" },
+       { GsmL1_TchPlType_Amr_Onset,            "AMR(ONSET)" },
+       { GsmL1_TchPlType_Amr_Ratscch,          "AMR(RATSCCH)" },
+       { GsmL1_TchPlType_Amr_SidUpdateInH,     "AMR(SID_UPDATE INH)" },
+       { GsmL1_TchPlType_Amr_SidFirstP1,       "AMR(SID_FIRST P1)" },
+       { GsmL1_TchPlType_Amr_SidFirstP2,       "AMR(SID_FIRST P2)" },
+       { GsmL1_TchPlType_Amr_SidFirstInH,      "AMR(SID_FIRST INH)" },
+       { GsmL1_TchPlType_Amr_RatscchMarker,    "AMR(RATSCCH MARK)" },
+       { GsmL1_TchPlType_Amr_RatscchData,      "AMR(RATSCCH DATA)" },
+       { 0, NULL }
+};
+
+const struct value_string femtobts_dir_names[] = {
+       { GsmL1_Dir_TxDownlink, "TxDL" },
+       { GsmL1_Dir_TxUplink,   "TxUL" },
+       { GsmL1_Dir_RxUplink,   "RxUL" },
+       { GsmL1_Dir_RxDownlink, "RxDL" },
+       { GsmL1_Dir_TxDownlink|GsmL1_Dir_RxUplink, "BOTH" },
+       { 0, NULL }
+};
+
+const struct value_string femtobts_chcomb_names[] = {
+       { GsmL1_LogChComb_0,    "dummy" },
+       { GsmL1_LogChComb_I,    "tch_f" },
+       { GsmL1_LogChComb_II,   "tch_h" },
+       { GsmL1_LogChComb_IV,   "ccch" },
+       { GsmL1_LogChComb_V,    "ccch_sdcch4" },
+       { GsmL1_LogChComb_VII,  "sdcch8" },
+       { GsmL1_LogChComb_XIII, "pdtch" },
+       { 0, NULL }
+};
+
+const uint8_t pdch_msu_size[_NUM_PDCH_CS] = {
+       [PDCH_CS_1]     = 23,
+       [PDCH_CS_2]     = 34,
+       [PDCH_CS_3]     = 40,
+       [PDCH_CS_4]     = 54,
+       [PDCH_MCS_1]    = 27,
+       [PDCH_MCS_2]    = 33,
+       [PDCH_MCS_3]    = 42,
+       [PDCH_MCS_4]    = 49,
+       [PDCH_MCS_5]    = 60,
+       [PDCH_MCS_6]    = 78,
+       [PDCH_MCS_7]    = 118,
+       [PDCH_MCS_8]    = 142,
+       [PDCH_MCS_9]    = 154
+};
diff --git a/src/osmo-bts-sysmo/femtobts.h b/src/osmo-bts-sysmo/femtobts.h
new file mode 100644
index 0000000..7e45578
--- /dev/null
+++ b/src/osmo-bts-sysmo/femtobts.h
@@ -0,0 +1,57 @@
+#ifndef FEMTOBTS_H
+#define FEMTOBTS_H
+
+#include <stdlib.h>
+#include <osmocom/core/utils.h>
+
+#include <sysmocom/femtobts/superfemto.h>
+#include <sysmocom/femtobts/gsml1const.h>
+
+#ifdef L1_HAS_RTP_MODE
+/* This is temporarily disabled, as AMR has some bugs in RTP mode */
+//#define USE_L1_RTP_MODE              /* Tell L1 to use RTP mode */
+#endif
+
+enum l1prim_type {
+       L1P_T_REQ,
+       L1P_T_CONF,
+       L1P_T_IND,
+};
+
+const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM];
+const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1];
+const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM];
+
+const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM];
+const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1];
+const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM];
+
+const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1];
+const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1];
+
+const struct value_string femtobts_tracef_names[29];
+
+const struct value_string femtobts_tch_pl_names[15];
+
+const struct value_string femtobts_dir_names[6];
+
+enum pdch_cs {
+       PDCH_CS_1,
+       PDCH_CS_2,
+       PDCH_CS_3,
+       PDCH_CS_4,
+       PDCH_MCS_1,
+       PDCH_MCS_2,
+       PDCH_MCS_3,
+       PDCH_MCS_4,
+       PDCH_MCS_5,
+       PDCH_MCS_6,
+       PDCH_MCS_7,
+       PDCH_MCS_8,
+       PDCH_MCS_9,
+       _NUM_PDCH_CS
+};
+
+const uint8_t pdch_msu_size[_NUM_PDCH_CS];
+
+#endif /* FEMTOBTS_H */
diff --git a/src/osmo-bts-sysmo/sysmo_l1_fwd.c 
b/src/osmo-bts-sysmo/sysmo_l1_fwd.c
new file mode 100644
index 0000000..535a7f0
--- /dev/null
+++ b/src/osmo-bts-sysmo/sysmo_l1_fwd.c
@@ -0,0 +1,145 @@
+/* Interface handler for Sysmocom L1 (forwarding) */
+
+/* (C) 2011 by Harald Welte <[email protected]>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/write_queue.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <sysmocom/femtobts/superfemto.h>
+#include <sysmocom/femtobts/gsml1prim.h>
+#include <sysmocom/femtobts/gsml1const.h>
+#include <sysmocom/femtobts/gsml1types.h>
+
+#include "gprs_debug.h"
+#include "sysmo_l1_if.h"
+
+
+#define L1FWD_L1_PORT   9999
+#define L1FWD_SYS_PORT  9998
+#define L1FWD_TCH_PORT  9997
+#define L1FWD_PDTCH_PORT 9996
+
+static const uint16_t fwd_udp_ports[] = {
+       [MQ_SYS_WRITE]  = L1FWD_SYS_PORT,
+       [MQ_L1_WRITE]   = L1FWD_L1_PORT,
+       [MQ_TCH_WRITE]  = L1FWD_TCH_PORT,
+       [MQ_PDTCH_WRITE]= L1FWD_PDTCH_PORT,
+};
+
+static int fwd_read_cb(struct osmo_fd *ofd)
+{
+       struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128,
+               128, "udp_rx");
+       struct femtol1_hdl *fl1h = ofd->data;
+       int rc;
+
+       if (!msg)
+               return -ENOMEM;
+
+       msg->l1h = msg->data;
+       rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
+       if (rc < 0) {
+               LOGP(DL1IF, LOGL_ERROR, "Short read from UDP\n");
+               msgb_free(msg);
+               return rc;
+       } else if (rc == 0) {
+               LOGP(DL1IF, LOGL_ERROR, "Len=0 from UDP\n");
+               msgb_free(msg);
+               return rc;
+       }
+       msgb_put(msg, rc);
+
+       if (ofd->priv_nr == MQ_SYS_WRITE)
+               rc = l1if_handle_sysprim(fl1h, msg);
+       else
+               rc = l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
+
+       return rc;
+}
+
+static int prim_write_cb(struct osmo_fd *ofd, struct msgb *msg)
+{
+       /* write to the fd */
+       return write(ofd->fd, msg->head, msg->len);
+}
+
+int l1if_transport_open(int q, struct femtol1_hdl *fl1h)
+{
+       int rc;
+       char *bts_host = getenv("L1FWD_BTS_HOST");
+
+       printf("sizeof(GsmL1_Prim_t) = %zu\n", sizeof(GsmL1_Prim_t));
+       printf("sizeof(SuperFemto_Prim_t) = %zu\n", sizeof(SuperFemto_Prim_t));
+
+       if (!bts_host) {
+               fprintf(stderr, "You have to set the L1FWD_BTS_HOST environment 
variable\n");
+               exit(2);
+       }
+
+       struct osmo_wqueue *wq = &fl1h->write_q[q];
+       struct osmo_fd *ofd = &wq->bfd;
+
+       osmo_wqueue_init(wq, 10);
+       wq->write_cb = prim_write_cb;
+       wq->read_cb = fwd_read_cb;
+
+       ofd->data = fl1h;
+       ofd->priv_nr = q;
+       ofd->when |= BSC_FD_READ;
+
+       rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+                               bts_host, fwd_udp_ports[q],
+                               OSMO_SOCK_F_CONNECT);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+int l1if_transport_close(int q, struct femtol1_hdl *fl1h)
+{
+       struct osmo_wqueue *wq = &fl1h->write_q[q];
+       struct osmo_fd *ofd = &wq->bfd;
+
+       osmo_wqueue_clear(wq);
+       osmo_fd_unregister(ofd);
+       close(ofd->fd);
+       
+       return 0;
+}
diff --git a/src/osmo-bts-sysmo/sysmo_l1_hw.c b/src/osmo-bts-sysmo/sysmo_l1_hw.c
new file mode 100644
index 0000000..2c019be
--- /dev/null
+++ b/src/osmo-bts-sysmo/sysmo_l1_hw.c
@@ -0,0 +1,216 @@
+/* Interface handler for Sysmocom L1 (real hardware) */
+
+/* (C) 2011 by Harald Welte <[email protected]>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/write_queue.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <sysmocom/femtobts/superfemto.h>
+#include <sysmocom/femtobts/gsml1prim.h>
+#include <sysmocom/femtobts/gsml1const.h>
+#include <sysmocom/femtobts/gsml1types.h>
+
+#include "gprs_debug.h"
+#include "femtobts.h"
+#include "sysmo_l1_if.h"
+
+
+#ifdef HW_SYSMOBTS_V1
+#define DEV_SYS_DSP2ARM_NAME   "/dev/msgq/femtobts_dsp2arm"
+#define DEV_SYS_ARM2DSP_NAME   "/dev/msgq/femtobts_arm2dsp"
+#define DEV_L1_DSP2ARM_NAME    "/dev/msgq/gsml1_dsp2arm"
+#define DEV_L1_ARM2DSP_NAME    "/dev/msgq/gsml1_arm2dsp"
+#else
+#define DEV_SYS_DSP2ARM_NAME   "/dev/msgq/superfemto_dsp2arm"
+#define DEV_SYS_ARM2DSP_NAME   "/dev/msgq/superfemto_arm2dsp"
+#define DEV_L1_DSP2ARM_NAME    "/dev/msgq/gsml1_sig_dsp2arm"
+#define DEV_L1_ARM2DSP_NAME    "/dev/msgq/gsml1_sig_arm2dsp"
+
+#define DEV_TCH_DSP2ARM_NAME   "/dev/msgq/gsml1_tch_dsp2arm"
+#define DEV_TCH_ARM2DSP_NAME   "/dev/msgq/gsml1_tch_arm2dsp"
+#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm1" //2 -- trx1
+#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp1" //2
+#endif
+
+static const char *rd_devnames[] = {
+       [MQ_SYS_READ]   = DEV_SYS_DSP2ARM_NAME,
+       [MQ_L1_READ]    = DEV_L1_DSP2ARM_NAME,
+#ifndef HW_SYSMOBTS_V1
+       [MQ_TCH_READ]   = DEV_TCH_DSP2ARM_NAME,
+       [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME,
+#endif
+};
+
+static const char *wr_devnames[] = {
+       [MQ_SYS_WRITE]  = DEV_SYS_ARM2DSP_NAME,
+       [MQ_L1_WRITE]   = DEV_L1_ARM2DSP_NAME,
+#ifndef HW_SYSMOBTS_V1
+       [MQ_TCH_WRITE]  = DEV_TCH_ARM2DSP_NAME,
+       [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME,
+#endif
+};
+
+/* callback when there's something to read from the l1 msg_queue */
+static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+       //struct msgb *msg = l1p_msgb_alloc();
+       struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128,
+               128, "1l_fd");
+       struct femtol1_hdl *fl1h = ofd->data;
+       int rc;
+
+       msg->l1h = msg->data;
+       rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
+       if (rc < 0) {
+               if (rc != -1) 
+                       LOGP(DL1IF, LOGL_ERROR, "error reading from L1 
msg_queue: %s\n",
+                               strerror(errno));
+               msgb_free(msg);
+               return rc;
+       }
+       msgb_put(msg, rc);
+
+       switch (ofd->priv_nr) {
+       case MQ_SYS_WRITE:
+               if (rc != sizeof(SuperFemto_Prim_t))
+                       LOGP(DL1IF, LOGL_NOTICE, "%u != "
+                            "sizeof(SuperFemto_Prim_t)\n", rc);
+               return l1if_handle_sysprim(fl1h, msg);
+       case MQ_L1_WRITE:
+#ifndef HW_SYSMOBTS_V1
+       case MQ_TCH_WRITE:
+       case MQ_PDTCH_WRITE:
+#endif
+               if (rc != sizeof(GsmL1_Prim_t))
+                       LOGP(DL1IF, LOGL_NOTICE, "%u != "
+                            "sizeof(GsmL1_Prim_t)\n", rc);
+               return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
+       default:
+               /* The compiler can't know that priv_nr is an enum. Assist. */
+               LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n",
+                       ofd->priv_nr);
+               exit(0);
+               break;
+       }
+};
+
+/* callback when we can write to one of the l1 msg_queue devices */
+static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg)
+{
+       int rc;
+
+       rc = write(ofd->fd, msg->l1h, msgb_l1len(msg));
+       if (rc < 0) {
+               LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
+                       strerror(errno));
+               return rc;
+       } else if (rc < msg->len) {
+               LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: "
+                       "%u < %u\n", rc, msg->len);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int l1if_transport_open(int q, struct femtol1_hdl *hdl)
+{
+       int rc;
+
+       /* Step 1: Open all msg_queue file descriptors */
+       struct osmo_fd *read_ofd = &hdl->read_ofd[q];
+       struct osmo_wqueue *wq = &hdl->write_q[q];
+       struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
+
+       rc = open(rd_devnames[q], O_RDONLY);
+       if (rc < 0) {
+               LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
+                       strerror(errno));
+               return rc;
+       }
+       read_ofd->fd = rc;
+       read_ofd->priv_nr = q;
+       read_ofd->data = hdl;
+       read_ofd->cb = l1if_fd_cb;
+       read_ofd->when = BSC_FD_READ;
+       rc = osmo_fd_register(read_ofd);
+       if (rc < 0) {
+               close(read_ofd->fd);
+               read_ofd->fd = -1;
+               return rc;
+       }
+
+       rc = open(wr_devnames[q], O_WRONLY);
+       if (rc < 0) {
+               LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
+                       strerror(errno));
+               goto out_read;
+       }
+       osmo_wqueue_init(wq, 10);
+       wq->write_cb = l1fd_write_cb;
+       write_ofd->fd = rc;
+       write_ofd->priv_nr = q;
+       write_ofd->data = hdl;
+       write_ofd->when = BSC_FD_WRITE;
+       rc = osmo_fd_register(write_ofd);
+       if (rc < 0) {
+               close(write_ofd->fd);
+               write_ofd->fd = -1;
+               goto out_read;
+       }
+
+       return 0;
+
+out_read:
+       close(hdl->read_ofd[q].fd);
+       osmo_fd_unregister(&hdl->read_ofd[q]);
+
+       return rc;
+}
+
+int l1if_transport_close(int q, struct femtol1_hdl *hdl)
+{
+       struct osmo_fd *read_ofd = &hdl->read_ofd[q];
+       struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
+
+       osmo_fd_unregister(read_ofd);
+       close(read_ofd->fd);
+       read_ofd->fd = -1;
+
+       osmo_fd_unregister(write_ofd);
+       close(write_ofd->fd);
+       write_ofd->fd = -1;
+
+       return 0;
+}
diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c
new file mode 100644
index 0000000..8572786
--- /dev/null
+++ b/src/osmo-bts-sysmo/sysmo_l1_if.c
@@ -0,0 +1,396 @@
+
+#include <string.h>
+#include <errno.h>
+
+#include <sysmocom/femtobts/superfemto.h>
+#include <sysmocom/femtobts/gsml1prim.h>
+#include <sysmocom/femtobts/gsml1const.h>
+#include <sysmocom/femtobts/gsml1types.h>
+
+#include <osmocom/core/gsmtap.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer.h>
+#include <sysmo_l1_if.h>
+#include <gprs_debug.h>
+#include <pcu_l1_if.h>
+
+extern void *tall_pcu_ctx;
+
+uint32_t l1if_ts_to_hLayer2(uint8_t trx, uint8_t ts)
+{
+       return (ts << 16) | (trx << 24);
+}
+
+/* allocate a msgb containing a GsmL1_Prim_t */
+struct msgb *l1p_msgb_alloc(void)
+{
+       struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim");
+
+       if (msg)
+               msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t));
+
+       return msg;
+}
+
+static int l1if_req_pdch(struct femtol1_hdl *fl1h, struct msgb *msg)
+{
+       struct osmo_wqueue *wqueue = &fl1h->write_q[MQ_PDTCH_WRITE];
+
+       if (osmo_wqueue_enqueue(wqueue, msg) != 0) {
+               LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping 
message.\n");
+               msgb_free(msg);
+       }
+
+       return 0;
+}
+
+static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct 
femtol1_hdl *gl1)
+{
+       prim->id = id;
+
+       /* for some reason the hLayer1 field is not always at the same position
+        * in the GsmL1_Prim_t, so we have to have this ugly case statement 
here... */
+       switch (id) {
+       case GsmL1_PrimId_MphInitReq:
+               //prim->u.mphInitReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphCloseReq:
+               prim->u.mphCloseReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphConnectReq:
+               prim->u.mphConnectReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphDisconnectReq:
+               prim->u.mphDisconnectReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphActivateReq:
+               prim->u.mphActivateReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphDeactivateReq:
+               prim->u.mphDeactivateReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphConfigReq:
+               prim->u.mphConfigReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphMeasureReq:
+               prim->u.mphMeasureReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_MphInitCnf:
+       case GsmL1_PrimId_MphCloseCnf:
+       case GsmL1_PrimId_MphConnectCnf:
+       case GsmL1_PrimId_MphDisconnectCnf:
+       case GsmL1_PrimId_MphActivateCnf:
+       case GsmL1_PrimId_MphDeactivateCnf:
+       case GsmL1_PrimId_MphConfigCnf:
+       case GsmL1_PrimId_MphMeasureCnf:
+               break;
+       case GsmL1_PrimId_MphTimeInd:
+               break;
+       case GsmL1_PrimId_MphSyncInd:
+               break;
+       case GsmL1_PrimId_PhEmptyFrameReq:
+               prim->u.phEmptyFrameReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_PhDataReq:
+               prim->u.phDataReq.hLayer1 = gl1->hLayer1;
+               break;
+       case GsmL1_PrimId_PhConnectInd:
+               break;
+       case GsmL1_PrimId_PhReadyToSendInd:
+               break;
+       case GsmL1_PrimId_PhDataInd:
+               break;
+       case GsmL1_PrimId_PhRaInd:
+               break;
+       default:
+               LOGP(DL1IF, LOGL_ERROR, "unknown L1 primitive %u\n", id);
+               break;
+       }
+       return &prim->u;
+}
+
+struct sapi_dir {
+       GsmL1_Sapi_t sapi;
+       GsmL1_Dir_t dir;
+};
+
+static const struct sapi_dir pdtch_sapis[] = {
+       { GsmL1_Sapi_Pdtch,     GsmL1_Dir_TxDownlink },
+       { GsmL1_Sapi_Pdtch,     GsmL1_Dir_RxUplink },
+       { GsmL1_Sapi_Ptcch,     GsmL1_Dir_TxDownlink },
+       { GsmL1_Sapi_Prach,     GsmL1_Dir_RxUplink },
+#if 0
+       { GsmL1_Sapi_Ptcch,     GsmL1_Dir_RxUplink },
+       { GsmL1_Sapi_Pacch,     GsmL1_Dir_TxDownlink },
+#endif
+};
+
+
+/* connect PDTCH */
+int l1if_connect_pdch(void *obj, uint8_t ts)
+{
+       struct femtol1_hdl *fl1h = obj;
+       struct msgb *msg = l1p_msgb_alloc();
+       GsmL1_MphConnectReq_t *cr;
+
+       cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConnectReq, fl1h);
+       cr->u8Tn = ts;
+       cr->logChComb = GsmL1_LogChComb_XIII;
+       
+       return l1if_req_pdch(fl1h, msg);
+}
+
+static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h,
+                                    GsmL1_PhReadyToSendInd_t *rts_ind)
+{
+       struct gsm_time g_time;
+       int rc = 0;
+
+       gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
+
+       DEBUGP(DL1IF, "Rx PH-RTS.ind %02u/%02u/%02u SAPI=%s\n",
+               g_time.t1, g_time.t2, g_time.t3,
+               get_value_string(femtobts_l1sapi_names, rts_ind->sapi));
+
+       switch (rts_ind->sapi) {
+       case GsmL1_Sapi_Pdtch:
+       case GsmL1_Sapi_Pacch:
+               rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn,
+                       rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr);
+       case GsmL1_Sapi_Ptcch:
+               // FIXME
+       default:
+               break;
+       }
+
+       return rc;
+}
+
+static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t 
*l1_meas)
+{
+       meas->rssi = (int8_t) (l1_meas->fRssi);
+       meas->have_rssi = 1;
+       meas->ber  = (uint8_t) (l1_meas->fBer * 100);
+       meas->have_ber = 1;
+       meas->bto  = (int16_t) (l1_meas->i16BurstTiming);
+       meas->have_bto = 1;
+       meas->link_qual  = (int16_t) (l1_meas->fLinkQuality);
+       meas->have_link_qual = 1;
+}
+
+static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
+       GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
+{
+       int rc = 0;
+       struct pcu_l1_meas meas = {0};
+
+       DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
+               get_value_string(femtobts_l1sapi_names, data_ind->sapi),
+               data_ind->hLayer2,
+               osmo_hexdump(data_ind->msgUnitParam.u8Buffer,
+                            data_ind->msgUnitParam.u8Size));
+
+       pcu_rx_block_time(data_ind->u16Arfcn, data_ind->u32Fn, data_ind->u8Tn);
+
+       /*
+        * TODO: Add proper bad frame handling here. This could be used
+        * to switch the used CS. Avoid a crash with the PCU right now
+        * feed "0 - 1" amount of data.
+        */
+       if (data_ind->msgUnitParam.u8Size == 0)
+               return -1;
+
+       gsmtap_send(fl1h->gsmtap, data_ind->u16Arfcn | GSMTAP_ARFCN_F_UPLINK,
+                       data_ind->u8Tn, GSMTAP_CHANNEL_PACCH, 0,
+                       data_ind->u32Fn, 0, 0, 
data_ind->msgUnitParam.u8Buffer+1,
+                       data_ind->msgUnitParam.u8Size-1);
+
+       get_meas(&meas, &data_ind->measParam);
+
+       switch (data_ind->sapi) {
+       case GsmL1_Sapi_Pdtch:
+       case GsmL1_Sapi_Pacch:
+               /* drop incomplete UL block */
+               if (data_ind->msgUnitParam.u8Buffer[0]
+                       != GsmL1_PdtchPlType_Full)
+                       break;
+               /* PDTCH / PACCH frame handling */
+               pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn,
+                       data_ind->msgUnitParam.u8Buffer + 1,
+                       data_ind->msgUnitParam.u8Size - 1,
+                       data_ind->u32Fn,
+                       &meas);
+               break;
+       case GsmL1_Sapi_Ptcch:
+               // FIXME
+               break;
+       default:
+               LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI 
%s\n",
+                       get_value_string(femtobts_l1sapi_names, 
data_ind->sapi));
+               break;
+       }
+
+       return rc;
+}
+
+#define MIN_QUAL_RACH  5.0f
+
+static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind)
+{
+       uint8_t acc_delay;
+
+       pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn);
+
+       if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH)
+               return 0;
+
+       DEBUGP(DL1IF, "Rx PH-RA.ind");
+
+       /* check for under/overflow / sign */
+       if (ra_ind->measParam.i16BurstTiming < 0)
+               acc_delay = 0;
+       else
+               acc_delay = ra_ind->measParam.i16BurstTiming >> 2;
+
+       LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n",
+               acc_delay);
+
+#warning "The (P)RACH request is just dropped here"
+
+#if 0
+       if (acc_delay > bts->max_ta) {
+               LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n",
+                    acc_delay, btsb->max_ta);
+               return 0;
+       }
+#endif
+
+       return 0;
+}
+
+
+/* handle any random indication from the L1 */
+int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg)
+{
+       GsmL1_Prim_t *l1p = msgb_l1prim(msg);
+       int rc = 0;
+
+       LOGP(DL1IF, LOGL_DEBUG, "Rx L1 prim %s on queue %d\n",
+               get_value_string(femtobts_l1prim_names, l1p->id), wq);
+
+       switch (l1p->id) {
+#if 0
+       case GsmL1_PrimId_MphTimeInd:
+               rc = handle_mph_time_ind(fl1h, &l1p->u.mphTimeInd);
+               break;
+       case GsmL1_PrimId_MphSyncInd:
+               break;
+       case GsmL1_PrimId_PhConnectInd:
+               break;
+#endif
+       case GsmL1_PrimId_PhReadyToSendInd:
+               rc = handle_ph_readytosend_ind(fl1h, &l1p->u.phReadyToSendInd);
+               break;
+       case GsmL1_PrimId_PhDataInd:
+               rc = handle_ph_data_ind(fl1h, &l1p->u.phDataInd, msg);
+               break;
+       case GsmL1_PrimId_PhRaInd:
+               rc = handle_ph_ra_ind(fl1h, &l1p->u.phRaInd);
+               break;
+       default:
+               break;
+       }
+
+       msgb_free(msg);
+
+       return rc;
+}
+
+int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
+{
+       return -ENOTSUP;
+}
+
+/* send packet data request to L1 */
+int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
+       uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len)
+{
+       struct femtol1_hdl *fl1h = obj;
+       struct msgb *msg;
+       GsmL1_Prim_t *l1p;
+       GsmL1_PhDataReq_t *data_req;
+       GsmL1_MsgUnitParam_t *msu_param;
+       struct gsm_time g_time;
+
+       gsm_fn2gsmtime(&g_time, fn);
+
+       DEBUGP(DL1IF, "TX packet data %02u/%02u/%02u is_ptcch=%d ts=%d "
+               "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2,
+               g_time.t3, is_ptcch, ts, block_nr, arfcn, len);
+
+       msg = l1p_msgb_alloc();
+       l1p = msgb_l1prim(msg);
+       l1p->id = GsmL1_PrimId_PhDataReq;
+       data_req = &l1p->u.phDataReq;
+       data_req->hLayer1 = fl1h->hLayer1;
+       data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch;
+       data_req->subCh = GsmL1_SubCh_NA;
+       data_req->u8BlockNbr = block_nr;
+       data_req->u8Tn = ts;
+       data_req->u32Fn = fn;
+       msu_param = &data_req->msgUnitParam;
+       msu_param->u8Size = len;
+       memcpy(msu_param->u8Buffer, data, len);
+
+       gsmtap_send(fl1h->gsmtap, arfcn, data_req->u8Tn, GSMTAP_CHANNEL_PACCH,
+                       0, data_req->u32Fn, 0, 0,
+                       data_req->msgUnitParam.u8Buffer,
+                       data_req->msgUnitParam.u8Size);
+
+
+       /* transmit */
+       if (osmo_wqueue_enqueue(&fl1h->write_q[MQ_PDTCH_WRITE], msg) != 0) {
+               LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping 
message.\n");
+               msgb_free(msg);
+       }
+
+       return 0;
+}
+
+void *l1if_open_pdch(void *priv, uint32_t hlayer1)
+{
+       struct femtol1_hdl *fl1h;
+       int rc;
+
+       fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl);
+       if (!fl1h)
+               return NULL;
+
+       fl1h->hLayer1 = hlayer1;
+       fl1h->priv = priv;
+       fl1h->clk_cal = 0;
+       /* default clock source: OCXO */
+       fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo;
+
+       rc = l1if_transport_open(MQ_PDTCH_WRITE, fl1h);
+       if (rc < 0) {
+               talloc_free(fl1h);
+               return NULL;
+       }
+
+       fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1);
+       if (fl1h->gsmtap)
+               gsmtap_source_add_sink(fl1h->gsmtap);
+
+       return fl1h;
+}
+
+int l1if_close_pdch(void *obj)
+{
+       struct femtol1_hdl *fl1h = obj;
+       if (fl1h)
+               l1if_transport_close(MQ_PDTCH_WRITE, fl1h);
+       talloc_free(fl1h);
+       return 0;
+}
+
diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.h b/src/osmo-bts-sysmo/sysmo_l1_if.h
new file mode 100644
index 0000000..6b50d4e
--- /dev/null
+++ b/src/osmo-bts-sysmo/sysmo_l1_if.h
@@ -0,0 +1,91 @@
+#ifndef _SYSMO_L1_IF_H
+#define _SYSMO_L1_IF_H
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/write_queue.h>
+#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include "femtobts.h"
+
+enum {
+       MQ_SYS_READ,
+       MQ_L1_READ,
+#ifndef HW_SYSMOBTS_V1
+       MQ_TCH_READ,
+       MQ_PDTCH_READ,
+#endif
+       _NUM_MQ_READ
+};
+
+enum {
+       MQ_SYS_WRITE,
+       MQ_L1_WRITE,
+#ifndef HW_SYSMOBTS_V1
+       MQ_TCH_WRITE,
+       MQ_PDTCH_WRITE,
+#endif
+       _NUM_MQ_WRITE
+};
+
+struct femtol1_hdl {
+       struct gsm_time gsm_time;
+       uint32_t hLayer1;                       /* handle to the L1 instance in 
the DSP */
+       uint32_t dsp_trace_f;
+       int clk_cal;
+       uint8_t clk_src;
+       struct llist_head wlc_list;
+
+       struct gsmtap_inst *gsmtap;
+       uint32_t gsmtap_sapi_mask;
+
+       void *priv;                     /* user reference */
+
+       struct osmo_timer_list alive_timer;
+       unsigned int alive_prim_cnt;
+
+       struct osmo_fd read_ofd[_NUM_MQ_READ];  /* osmo file descriptors */
+       struct osmo_wqueue write_q[_NUM_MQ_WRITE];
+
+       struct {
+               uint8_t dsp_version[3];
+               uint8_t fpga_version[3];
+               uint32_t band_support;  /* bitmask of GSM_BAND_* */
+       } hw_info;
+};
+
+#define msgb_l1prim(msg)       ((GsmL1_Prim_t *)(msg)->l1h)
+#define msgb_sysprim(msg)      ((SuperFemto_Prim_t *)(msg)->l1h)
+
+typedef int l1if_compl_cb(struct msgb *l1_msg, void *data);
+
+/* send a request primitive to the L1 and schedule completion call-back */
+int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg,
+                  int is_system_prim, l1if_compl_cb *cb, void *data);
+
+int l1if_reset(struct femtol1_hdl *hdl);
+int l1if_activate_rf(struct femtol1_hdl *hdl, int on);
+int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags);
+int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power);
+
+struct msgb *l1p_msgb_alloc(void);
+struct msgb *sysp_msgb_alloc(void);
+
+uint32_t l1if_lchan_to_hLayer2(struct gsm_lchan *lchan);
+struct gsm_lchan *l1if_hLayer2_to_lchan(struct gsm_bts_trx *trx, uint32_t 
hLayer2);
+
+int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg);
+int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg);
+
+/* tch.c */
+int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg);
+int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer);
+struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan);
+
+/*
+ * The implementation of these functions is selected by either compiling and
+ * linking sysmo_l1_hw.c or sysmo_l1_fwd.c
+ */
+int l1if_transport_open(int q, struct femtol1_hdl *hdl);
+int l1if_transport_close(int q, struct femtol1_hdl *hdl);
+
+#endif /* _SYSMO_L1_IF_H */
diff --git a/src/osmobts_sock.cpp b/src/osmobts_sock.cpp
index b42f042..21a404f 100644
--- a/src/osmobts_sock.cpp
+++ b/src/osmobts_sock.cpp
@@ -100,7 +100,7 @@ static void pcu_sock_close(struct pcu_sock_state *state, 
int lost)

        /* disable all slots, kick all TBFs */
        for (trx = 0; trx < 8; trx++) {
-#ifdef ENABLE_SYSMODSP
+#ifdef ENABLE_DIRECT_PHY
                if (bts->trx[trx].fl1h) {
                        l1if_close_pdch(bts->trx[trx].fl1h);
                        bts->trx[trx].fl1h = NULL;
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 9d7dbee..a19b957 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -124,7 +124,7 @@ static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t 
sapi,
 void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
        uint32_t fn, uint8_t block_nr)
 {
-#ifdef ENABLE_SYSMODSP
+#ifdef ENABLE_DIRECT_PHY
        struct gprs_rlcmac_bts *bts = bts_main_data();

        if (bts->trx[trx].fl1h)
@@ -430,7 +430,7 @@ bssgp_failed:
                bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
                if ((info_ind->flags & PCU_IF_FLAG_SYSMO)
                 && info_ind->trx[trx].hlayer1) {
-#ifdef ENABLE_SYSMODSP
+#ifdef ENABLE_DIRECT_PHY
                        LOGP(DL1IF, LOGL_DEBUG, " TRX %d hlayer1=%x\n", trx,
                                info_ind->trx[trx].hlayer1);
                                if (!bts->trx[trx].fl1h)
@@ -455,7 +455,7 @@ bssgp_failed:
                        if ((info_ind->trx[trx].pdch_mask & (1 << ts))) {
                                /* FIXME: activate dynamically at RLCMAC */
                                if (!pdch->is_enabled()) {
-#ifdef ENABLE_SYSMODSP
+#ifdef ENABLE_DIRECT_PHY
                                        if ((info_ind->flags &
                                                        PCU_IF_FLAG_SYSMO))
                                                l1if_connect_pdch(
diff --git a/src/sysmo_l1_fwd.c b/src/sysmo_l1_fwd.c
deleted file mode 100644
index 535a7f0..0000000
--- a/src/sysmo_l1_fwd.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Interface handler for Sysmocom L1 (forwarding) */
-
-/* (C) 2011 by Harald Welte <[email protected]>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/write_queue.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/socket.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <sysmocom/femtobts/superfemto.h>
-#include <sysmocom/femtobts/gsml1prim.h>
-#include <sysmocom/femtobts/gsml1const.h>
-#include <sysmocom/femtobts/gsml1types.h>
-
-#include "gprs_debug.h"
-#include "sysmo_l1_if.h"
-
-
-#define L1FWD_L1_PORT   9999
-#define L1FWD_SYS_PORT  9998
-#define L1FWD_TCH_PORT  9997
-#define L1FWD_PDTCH_PORT 9996
-
-static const uint16_t fwd_udp_ports[] = {
-       [MQ_SYS_WRITE]  = L1FWD_SYS_PORT,
-       [MQ_L1_WRITE]   = L1FWD_L1_PORT,
-       [MQ_TCH_WRITE]  = L1FWD_TCH_PORT,
-       [MQ_PDTCH_WRITE]= L1FWD_PDTCH_PORT,
-};
-
-static int fwd_read_cb(struct osmo_fd *ofd)
-{
-       struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128,
-               128, "udp_rx");
-       struct femtol1_hdl *fl1h = ofd->data;
-       int rc;
-
-       if (!msg)
-               return -ENOMEM;
-
-       msg->l1h = msg->data;
-       rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
-       if (rc < 0) {
-               LOGP(DL1IF, LOGL_ERROR, "Short read from UDP\n");
-               msgb_free(msg);
-               return rc;
-       } else if (rc == 0) {
-               LOGP(DL1IF, LOGL_ERROR, "Len=0 from UDP\n");
-               msgb_free(msg);
-               return rc;
-       }
-       msgb_put(msg, rc);
-
-       if (ofd->priv_nr == MQ_SYS_WRITE)
-               rc = l1if_handle_sysprim(fl1h, msg);
-       else
-               rc = l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
-
-       return rc;
-}
-
-static int prim_write_cb(struct osmo_fd *ofd, struct msgb *msg)
-{
-       /* write to the fd */
-       return write(ofd->fd, msg->head, msg->len);
-}
-
-int l1if_transport_open(int q, struct femtol1_hdl *fl1h)
-{
-       int rc;
-       char *bts_host = getenv("L1FWD_BTS_HOST");
-
-       printf("sizeof(GsmL1_Prim_t) = %zu\n", sizeof(GsmL1_Prim_t));
-       printf("sizeof(SuperFemto_Prim_t) = %zu\n", sizeof(SuperFemto_Prim_t));
-
-       if (!bts_host) {
-               fprintf(stderr, "You have to set the L1FWD_BTS_HOST environment 
variable\n");
-               exit(2);
-       }
-
-       struct osmo_wqueue *wq = &fl1h->write_q[q];
-       struct osmo_fd *ofd = &wq->bfd;
-
-       osmo_wqueue_init(wq, 10);
-       wq->write_cb = prim_write_cb;
-       wq->read_cb = fwd_read_cb;
-
-       ofd->data = fl1h;
-       ofd->priv_nr = q;
-       ofd->when |= BSC_FD_READ;
-
-       rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
-                               bts_host, fwd_udp_ports[q],
-                               OSMO_SOCK_F_CONNECT);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-int l1if_transport_close(int q, struct femtol1_hdl *fl1h)
-{
-       struct osmo_wqueue *wq = &fl1h->write_q[q];
-       struct osmo_fd *ofd = &wq->bfd;
-
-       osmo_wqueue_clear(wq);
-       osmo_fd_unregister(ofd);
-       close(ofd->fd);
-       
-       return 0;
-}
diff --git a/src/sysmo_l1_hw.c b/src/sysmo_l1_hw.c
deleted file mode 100644
index 8351d68..0000000
--- a/src/sysmo_l1_hw.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Interface handler for Sysmocom L1 (real hardware) */
-
-/* (C) 2011 by Harald Welte <[email protected]>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <assert.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/write_queue.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <sysmocom/femtobts/superfemto.h>
-#include <sysmocom/femtobts/gsml1prim.h>
-#include <sysmocom/femtobts/gsml1const.h>
-#include <sysmocom/femtobts/gsml1types.h>
-
-#include "gprs_debug.h"
-#include "femtobts.h"
-#include "sysmo_l1_if.h"
-
-
-#ifdef HW_SYSMOBTS_V1
-#define DEV_SYS_DSP2ARM_NAME   "/dev/msgq/femtobts_dsp2arm"
-#define DEV_SYS_ARM2DSP_NAME   "/dev/msgq/femtobts_arm2dsp"
-#define DEV_L1_DSP2ARM_NAME    "/dev/msgq/gsml1_dsp2arm"
-#define DEV_L1_ARM2DSP_NAME    "/dev/msgq/gsml1_arm2dsp"
-#else
-#define DEV_SYS_DSP2ARM_NAME   "/dev/msgq/superfemto_dsp2arm"
-#define DEV_SYS_ARM2DSP_NAME   "/dev/msgq/superfemto_arm2dsp"
-#define DEV_L1_DSP2ARM_NAME    "/dev/msgq/gsml1_sig_dsp2arm"
-#define DEV_L1_ARM2DSP_NAME    "/dev/msgq/gsml1_sig_arm2dsp"
-
-#define DEV_TCH_DSP2ARM_NAME   "/dev/msgq/gsml1_tch_dsp2arm"
-#define DEV_TCH_ARM2DSP_NAME   "/dev/msgq/gsml1_tch_arm2dsp"
-#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm"
-#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp"
-#endif
-
-static const char *rd_devnames[] = {
-       [MQ_SYS_READ]   = DEV_SYS_DSP2ARM_NAME,
-       [MQ_L1_READ]    = DEV_L1_DSP2ARM_NAME,
-#ifndef HW_SYSMOBTS_V1
-       [MQ_TCH_READ]   = DEV_TCH_DSP2ARM_NAME,
-       [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME,
-#endif
-};
-
-static const char *wr_devnames[] = {
-       [MQ_SYS_WRITE]  = DEV_SYS_ARM2DSP_NAME,
-       [MQ_L1_WRITE]   = DEV_L1_ARM2DSP_NAME,
-#ifndef HW_SYSMOBTS_V1
-       [MQ_TCH_WRITE]  = DEV_TCH_ARM2DSP_NAME,
-       [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME,
-#endif
-};
-
-/* callback when there's something to read from the l1 msg_queue */
-static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what)
-{
-       //struct msgb *msg = l1p_msgb_alloc();
-       struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128,
-               128, "1l_fd");
-       struct femtol1_hdl *fl1h = ofd->data;
-       int rc;
-
-       msg->l1h = msg->data;
-       rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
-       if (rc < 0) {
-               if (rc != -1) 
-                       LOGP(DL1IF, LOGL_ERROR, "error reading from L1 
msg_queue: %s\n",
-                               strerror(errno));
-               msgb_free(msg);
-               return rc;
-       }
-       msgb_put(msg, rc);
-
-       switch (ofd->priv_nr) {
-       case MQ_SYS_WRITE:
-               if (rc != sizeof(SuperFemto_Prim_t))
-                       LOGP(DL1IF, LOGL_NOTICE, "%u != "
-                            "sizeof(SuperFemto_Prim_t)\n", rc);
-               return l1if_handle_sysprim(fl1h, msg);
-       case MQ_L1_WRITE:
-#ifndef HW_SYSMOBTS_V1
-       case MQ_TCH_WRITE:
-       case MQ_PDTCH_WRITE:
-#endif
-               if (rc != sizeof(GsmL1_Prim_t))
-                       LOGP(DL1IF, LOGL_NOTICE, "%u != "
-                            "sizeof(GsmL1_Prim_t)\n", rc);
-               return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
-       default:
-               /* The compiler can't know that priv_nr is an enum. Assist. */
-               LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n",
-                       ofd->priv_nr);
-               exit(0);
-               break;
-       }
-};
-
-/* callback when we can write to one of the l1 msg_queue devices */
-static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg)
-{
-       int rc;
-
-       rc = write(ofd->fd, msg->l1h, msgb_l1len(msg));
-       if (rc < 0) {
-               LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
-                       strerror(errno));
-               return rc;
-       } else if (rc < msg->len) {
-               LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: "
-                       "%u < %u\n", rc, msg->len);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-int l1if_transport_open(int q, struct femtol1_hdl *hdl)
-{
-       int rc;
-
-       /* Step 1: Open all msg_queue file descriptors */
-       struct osmo_fd *read_ofd = &hdl->read_ofd[q];
-       struct osmo_wqueue *wq = &hdl->write_q[q];
-       struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
-
-       rc = open(rd_devnames[q], O_RDONLY);
-       if (rc < 0) {
-               LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
-                       strerror(errno));
-               return rc;
-       }
-       read_ofd->fd = rc;
-       read_ofd->priv_nr = q;
-       read_ofd->data = hdl;
-       read_ofd->cb = l1if_fd_cb;
-       read_ofd->when = BSC_FD_READ;
-       rc = osmo_fd_register(read_ofd);
-       if (rc < 0) {
-               close(read_ofd->fd);
-               read_ofd->fd = -1;
-               return rc;
-       }
-
-       rc = open(wr_devnames[q], O_WRONLY);
-       if (rc < 0) {
-               LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
-                       strerror(errno));
-               goto out_read;
-       }
-       osmo_wqueue_init(wq, 10);
-       wq->write_cb = l1fd_write_cb;
-       write_ofd->fd = rc;
-       write_ofd->priv_nr = q;
-       write_ofd->data = hdl;
-       write_ofd->when = BSC_FD_WRITE;
-       rc = osmo_fd_register(write_ofd);
-       if (rc < 0) {
-               close(write_ofd->fd);
-               write_ofd->fd = -1;
-               goto out_read;
-       }
-
-       return 0;
-
-out_read:
-       close(hdl->read_ofd[q].fd);
-       osmo_fd_unregister(&hdl->read_ofd[q]);
-
-       return rc;
-}
-
-int l1if_transport_close(int q, struct femtol1_hdl *hdl)
-{
-       struct osmo_fd *read_ofd = &hdl->read_ofd[q];
-       struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
-
-       osmo_fd_unregister(read_ofd);
-       close(read_ofd->fd);
-       read_ofd->fd = -1;
-
-       osmo_fd_unregister(write_ofd);
-       close(write_ofd->fd);
-       write_ofd->fd = -1;
-
-       return 0;
-}
diff --git a/src/sysmo_l1_if.c b/src/sysmo_l1_if.c
deleted file mode 100644
index 8572786..0000000
--- a/src/sysmo_l1_if.c
+++ /dev/null
@@ -1,396 +0,0 @@
-
-#include <string.h>
-#include <errno.h>
-
-#include <sysmocom/femtobts/superfemto.h>
-#include <sysmocom/femtobts/gsml1prim.h>
-#include <sysmocom/femtobts/gsml1const.h>
-#include <sysmocom/femtobts/gsml1types.h>
-
-#include <osmocom/core/gsmtap.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/timer.h>
-#include <sysmo_l1_if.h>
-#include <gprs_debug.h>
-#include <pcu_l1_if.h>
-
-extern void *tall_pcu_ctx;
-
-uint32_t l1if_ts_to_hLayer2(uint8_t trx, uint8_t ts)
-{
-       return (ts << 16) | (trx << 24);
-}
-
-/* allocate a msgb containing a GsmL1_Prim_t */
-struct msgb *l1p_msgb_alloc(void)
-{
-       struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim");
-
-       if (msg)
-               msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t));
-
-       return msg;
-}
-
-static int l1if_req_pdch(struct femtol1_hdl *fl1h, struct msgb *msg)
-{
-       struct osmo_wqueue *wqueue = &fl1h->write_q[MQ_PDTCH_WRITE];
-
-       if (osmo_wqueue_enqueue(wqueue, msg) != 0) {
-               LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping 
message.\n");
-               msgb_free(msg);
-       }
-
-       return 0;
-}
-
-static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct 
femtol1_hdl *gl1)
-{
-       prim->id = id;
-
-       /* for some reason the hLayer1 field is not always at the same position
-        * in the GsmL1_Prim_t, so we have to have this ugly case statement 
here... */
-       switch (id) {
-       case GsmL1_PrimId_MphInitReq:
-               //prim->u.mphInitReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphCloseReq:
-               prim->u.mphCloseReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphConnectReq:
-               prim->u.mphConnectReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphDisconnectReq:
-               prim->u.mphDisconnectReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphActivateReq:
-               prim->u.mphActivateReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphDeactivateReq:
-               prim->u.mphDeactivateReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphConfigReq:
-               prim->u.mphConfigReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphMeasureReq:
-               prim->u.mphMeasureReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_MphInitCnf:
-       case GsmL1_PrimId_MphCloseCnf:
-       case GsmL1_PrimId_MphConnectCnf:
-       case GsmL1_PrimId_MphDisconnectCnf:
-       case GsmL1_PrimId_MphActivateCnf:
-       case GsmL1_PrimId_MphDeactivateCnf:
-       case GsmL1_PrimId_MphConfigCnf:
-       case GsmL1_PrimId_MphMeasureCnf:
-               break;
-       case GsmL1_PrimId_MphTimeInd:
-               break;
-       case GsmL1_PrimId_MphSyncInd:
-               break;
-       case GsmL1_PrimId_PhEmptyFrameReq:
-               prim->u.phEmptyFrameReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_PhDataReq:
-               prim->u.phDataReq.hLayer1 = gl1->hLayer1;
-               break;
-       case GsmL1_PrimId_PhConnectInd:
-               break;
-       case GsmL1_PrimId_PhReadyToSendInd:
-               break;
-       case GsmL1_PrimId_PhDataInd:
-               break;
-       case GsmL1_PrimId_PhRaInd:
-               break;
-       default:
-               LOGP(DL1IF, LOGL_ERROR, "unknown L1 primitive %u\n", id);
-               break;
-       }
-       return &prim->u;
-}
-
-struct sapi_dir {
-       GsmL1_Sapi_t sapi;
-       GsmL1_Dir_t dir;
-};
-
-static const struct sapi_dir pdtch_sapis[] = {
-       { GsmL1_Sapi_Pdtch,     GsmL1_Dir_TxDownlink },
-       { GsmL1_Sapi_Pdtch,     GsmL1_Dir_RxUplink },
-       { GsmL1_Sapi_Ptcch,     GsmL1_Dir_TxDownlink },
-       { GsmL1_Sapi_Prach,     GsmL1_Dir_RxUplink },
-#if 0
-       { GsmL1_Sapi_Ptcch,     GsmL1_Dir_RxUplink },
-       { GsmL1_Sapi_Pacch,     GsmL1_Dir_TxDownlink },
-#endif
-};
-
-
-/* connect PDTCH */
-int l1if_connect_pdch(void *obj, uint8_t ts)
-{
-       struct femtol1_hdl *fl1h = obj;
-       struct msgb *msg = l1p_msgb_alloc();
-       GsmL1_MphConnectReq_t *cr;
-
-       cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConnectReq, fl1h);
-       cr->u8Tn = ts;
-       cr->logChComb = GsmL1_LogChComb_XIII;
-       
-       return l1if_req_pdch(fl1h, msg);
-}
-
-static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h,
-                                    GsmL1_PhReadyToSendInd_t *rts_ind)
-{
-       struct gsm_time g_time;
-       int rc = 0;
-
-       gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
-
-       DEBUGP(DL1IF, "Rx PH-RTS.ind %02u/%02u/%02u SAPI=%s\n",
-               g_time.t1, g_time.t2, g_time.t3,
-               get_value_string(femtobts_l1sapi_names, rts_ind->sapi));
-
-       switch (rts_ind->sapi) {
-       case GsmL1_Sapi_Pdtch:
-       case GsmL1_Sapi_Pacch:
-               rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn,
-                       rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr);
-       case GsmL1_Sapi_Ptcch:
-               // FIXME
-       default:
-               break;
-       }
-
-       return rc;
-}
-
-static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t 
*l1_meas)
-{
-       meas->rssi = (int8_t) (l1_meas->fRssi);
-       meas->have_rssi = 1;
-       meas->ber  = (uint8_t) (l1_meas->fBer * 100);
-       meas->have_ber = 1;
-       meas->bto  = (int16_t) (l1_meas->i16BurstTiming);
-       meas->have_bto = 1;
-       meas->link_qual  = (int16_t) (l1_meas->fLinkQuality);
-       meas->have_link_qual = 1;
-}
-
-static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
-       GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
-{
-       int rc = 0;
-       struct pcu_l1_meas meas = {0};
-
-       DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
-               get_value_string(femtobts_l1sapi_names, data_ind->sapi),
-               data_ind->hLayer2,
-               osmo_hexdump(data_ind->msgUnitParam.u8Buffer,
-                            data_ind->msgUnitParam.u8Size));
-
-       pcu_rx_block_time(data_ind->u16Arfcn, data_ind->u32Fn, data_ind->u8Tn);
-
-       /*
-        * TODO: Add proper bad frame handling here. This could be used
-        * to switch the used CS. Avoid a crash with the PCU right now
-        * feed "0 - 1" amount of data.
-        */
-       if (data_ind->msgUnitParam.u8Size == 0)
-               return -1;
-
-       gsmtap_send(fl1h->gsmtap, data_ind->u16Arfcn | GSMTAP_ARFCN_F_UPLINK,
-                       data_ind->u8Tn, GSMTAP_CHANNEL_PACCH, 0,
-                       data_ind->u32Fn, 0, 0, 
data_ind->msgUnitParam.u8Buffer+1,
-                       data_ind->msgUnitParam.u8Size-1);
-
-       get_meas(&meas, &data_ind->measParam);
-
-       switch (data_ind->sapi) {
-       case GsmL1_Sapi_Pdtch:
-       case GsmL1_Sapi_Pacch:
-               /* drop incomplete UL block */
-               if (data_ind->msgUnitParam.u8Buffer[0]
-                       != GsmL1_PdtchPlType_Full)
-                       break;
-               /* PDTCH / PACCH frame handling */
-               pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn,
-                       data_ind->msgUnitParam.u8Buffer + 1,
-                       data_ind->msgUnitParam.u8Size - 1,
-                       data_ind->u32Fn,
-                       &meas);
-               break;
-       case GsmL1_Sapi_Ptcch:
-               // FIXME
-               break;
-       default:
-               LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI 
%s\n",
-                       get_value_string(femtobts_l1sapi_names, 
data_ind->sapi));
-               break;
-       }
-
-       return rc;
-}
-
-#define MIN_QUAL_RACH  5.0f
-
-static int handle_ph_ra_ind(struct femtol1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind)
-{
-       uint8_t acc_delay;
-
-       pcu_rx_ra_time(ra_ind->u16Arfcn, ra_ind->u32Fn, ra_ind->u8Tn);
-
-       if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH)
-               return 0;
-
-       DEBUGP(DL1IF, "Rx PH-RA.ind");
-
-       /* check for under/overflow / sign */
-       if (ra_ind->measParam.i16BurstTiming < 0)
-               acc_delay = 0;
-       else
-               acc_delay = ra_ind->measParam.i16BurstTiming >> 2;
-
-       LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n",
-               acc_delay);
-
-#warning "The (P)RACH request is just dropped here"
-
-#if 0
-       if (acc_delay > bts->max_ta) {
-               LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n",
-                    acc_delay, btsb->max_ta);
-               return 0;
-       }
-#endif
-
-       return 0;
-}
-
-
-/* handle any random indication from the L1 */
-int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg)
-{
-       GsmL1_Prim_t *l1p = msgb_l1prim(msg);
-       int rc = 0;
-
-       LOGP(DL1IF, LOGL_DEBUG, "Rx L1 prim %s on queue %d\n",
-               get_value_string(femtobts_l1prim_names, l1p->id), wq);
-
-       switch (l1p->id) {
-#if 0
-       case GsmL1_PrimId_MphTimeInd:
-               rc = handle_mph_time_ind(fl1h, &l1p->u.mphTimeInd);
-               break;
-       case GsmL1_PrimId_MphSyncInd:
-               break;
-       case GsmL1_PrimId_PhConnectInd:
-               break;
-#endif
-       case GsmL1_PrimId_PhReadyToSendInd:
-               rc = handle_ph_readytosend_ind(fl1h, &l1p->u.phReadyToSendInd);
-               break;
-       case GsmL1_PrimId_PhDataInd:
-               rc = handle_ph_data_ind(fl1h, &l1p->u.phDataInd, msg);
-               break;
-       case GsmL1_PrimId_PhRaInd:
-               rc = handle_ph_ra_ind(fl1h, &l1p->u.phRaInd);
-               break;
-       default:
-               break;
-       }
-
-       msgb_free(msg);
-
-       return rc;
-}
-
-int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
-{
-       return -ENOTSUP;
-}
-
-/* send packet data request to L1 */
-int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
-       uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len)
-{
-       struct femtol1_hdl *fl1h = obj;
-       struct msgb *msg;
-       GsmL1_Prim_t *l1p;
-       GsmL1_PhDataReq_t *data_req;
-       GsmL1_MsgUnitParam_t *msu_param;
-       struct gsm_time g_time;
-
-       gsm_fn2gsmtime(&g_time, fn);
-
-       DEBUGP(DL1IF, "TX packet data %02u/%02u/%02u is_ptcch=%d ts=%d "
-               "block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2,
-               g_time.t3, is_ptcch, ts, block_nr, arfcn, len);
-
-       msg = l1p_msgb_alloc();
-       l1p = msgb_l1prim(msg);
-       l1p->id = GsmL1_PrimId_PhDataReq;
-       data_req = &l1p->u.phDataReq;
-       data_req->hLayer1 = fl1h->hLayer1;
-       data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch;
-       data_req->subCh = GsmL1_SubCh_NA;
-       data_req->u8BlockNbr = block_nr;
-       data_req->u8Tn = ts;
-       data_req->u32Fn = fn;
-       msu_param = &data_req->msgUnitParam;
-       msu_param->u8Size = len;
-       memcpy(msu_param->u8Buffer, data, len);
-
-       gsmtap_send(fl1h->gsmtap, arfcn, data_req->u8Tn, GSMTAP_CHANNEL_PACCH,
-                       0, data_req->u32Fn, 0, 0,
-                       data_req->msgUnitParam.u8Buffer,
-                       data_req->msgUnitParam.u8Size);
-
-
-       /* transmit */
-       if (osmo_wqueue_enqueue(&fl1h->write_q[MQ_PDTCH_WRITE], msg) != 0) {
-               LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping 
message.\n");
-               msgb_free(msg);
-       }
-
-       return 0;
-}
-
-void *l1if_open_pdch(void *priv, uint32_t hlayer1)
-{
-       struct femtol1_hdl *fl1h;
-       int rc;
-
-       fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl);
-       if (!fl1h)
-               return NULL;
-
-       fl1h->hLayer1 = hlayer1;
-       fl1h->priv = priv;
-       fl1h->clk_cal = 0;
-       /* default clock source: OCXO */
-       fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo;
-
-       rc = l1if_transport_open(MQ_PDTCH_WRITE, fl1h);
-       if (rc < 0) {
-               talloc_free(fl1h);
-               return NULL;
-       }
-
-       fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1);
-       if (fl1h->gsmtap)
-               gsmtap_source_add_sink(fl1h->gsmtap);
-
-       return fl1h;
-}
-
-int l1if_close_pdch(void *obj)
-{
-       struct femtol1_hdl *fl1h = obj;
-       if (fl1h)
-               l1if_transport_close(MQ_PDTCH_WRITE, fl1h);
-       talloc_free(fl1h);
-       return 0;
-}
-
diff --git a/src/sysmo_l1_if.h b/src/sysmo_l1_if.h
deleted file mode 100644
index 6b50d4e..0000000
--- a/src/sysmo_l1_if.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef _SYSMO_L1_IF_H
-#define _SYSMO_L1_IF_H
-
-#include <osmocom/core/select.h>
-#include <osmocom/core/write_queue.h>
-#include <osmocom/core/gsmtap_util.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include "femtobts.h"
-
-enum {
-       MQ_SYS_READ,
-       MQ_L1_READ,
-#ifndef HW_SYSMOBTS_V1
-       MQ_TCH_READ,
-       MQ_PDTCH_READ,
-#endif
-       _NUM_MQ_READ
-};
-
-enum {
-       MQ_SYS_WRITE,
-       MQ_L1_WRITE,
-#ifndef HW_SYSMOBTS_V1
-       MQ_TCH_WRITE,
-       MQ_PDTCH_WRITE,
-#endif
-       _NUM_MQ_WRITE
-};
-
-struct femtol1_hdl {
-       struct gsm_time gsm_time;
-       uint32_t hLayer1;                       /* handle to the L1 instance in 
the DSP */
-       uint32_t dsp_trace_f;
-       int clk_cal;
-       uint8_t clk_src;
-       struct llist_head wlc_list;
-
-       struct gsmtap_inst *gsmtap;
-       uint32_t gsmtap_sapi_mask;
-
-       void *priv;                     /* user reference */
-
-       struct osmo_timer_list alive_timer;
-       unsigned int alive_prim_cnt;
-
-       struct osmo_fd read_ofd[_NUM_MQ_READ];  /* osmo file descriptors */
-       struct osmo_wqueue write_q[_NUM_MQ_WRITE];
-
-       struct {
-               uint8_t dsp_version[3];
-               uint8_t fpga_version[3];
-               uint32_t band_support;  /* bitmask of GSM_BAND_* */
-       } hw_info;
-};
-
-#define msgb_l1prim(msg)       ((GsmL1_Prim_t *)(msg)->l1h)
-#define msgb_sysprim(msg)      ((SuperFemto_Prim_t *)(msg)->l1h)
-
-typedef int l1if_compl_cb(struct msgb *l1_msg, void *data);
-
-/* send a request primitive to the L1 and schedule completion call-back */
-int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg,
-                  int is_system_prim, l1if_compl_cb *cb, void *data);
-
-int l1if_reset(struct femtol1_hdl *hdl);
-int l1if_activate_rf(struct femtol1_hdl *hdl, int on);
-int l1if_set_trace_flags(struct femtol1_hdl *hdl, uint32_t flags);
-int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power);
-
-struct msgb *l1p_msgb_alloc(void);
-struct msgb *sysp_msgb_alloc(void);
-
-uint32_t l1if_lchan_to_hLayer2(struct gsm_lchan *lchan);
-struct gsm_lchan *l1if_hLayer2_to_lchan(struct gsm_bts_trx *trx, uint32_t 
hLayer2);
-
-int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg);
-int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg);
-
-/* tch.c */
-int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg);
-int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer);
-struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan);
-
-/*
- * The implementation of these functions is selected by either compiling and
- * linking sysmo_l1_hw.c or sysmo_l1_fwd.c
- */
-int l1if_transport_open(int q, struct femtol1_hdl *hdl);
-int l1if_transport_close(int q, struct femtol1_hdl *hdl);
-
-#endif /* _SYSMO_L1_IF_H */
-- 
2.5.0

Reply via email to