#include #include #include #include #include #include #include #include #include #include #include static LLIST_HEAD(g_phy_links); struct phy_link *phy_link_by_num(int num) { struct phy_link *plink; llist_for_each_entry(plink, &g_phy_links, list) { if (plink->num == num) return plink; } return NULL; } struct phy_link *phy_link_create(void *ctx, int num) { struct phy_link *plink; if (phy_link_by_num(num)) return NULL; plink = talloc_zero(ctx, struct phy_link); plink->num = num; plink->state = PHY_LINK_SHUTDOWN; INIT_LLIST_HEAD(&plink->instances); llist_add_tail(&plink->list, &g_phy_links); bts_model_phy_link_set_defaults(plink); return plink; } const struct value_string phy_link_state_vals[] = { { PHY_LINK_SHUTDOWN, "shutdown" }, { PHY_LINK_CONNECTING, "connecting" }, { PHY_LINK_CONNECTED, "connected" }, { 0, NULL } }; void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) { struct phy_instance *pinst; LOGPPHL(plink, DL1C, LOGL_INFO, "PHY link state change %s -> %s\n", get_value_string(phy_link_state_vals, plink->state), get_value_string(phy_link_state_vals, state)); plink->state = state; /* notify all TRX associated with this phy */ llist_for_each_entry(pinst, &plink->instances, list) { struct gsm_bts_trx *trx = pinst->trx; if (!trx) continue; osmo_fsm_inst_dispatch(trx->mo.fi, state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP : NM_EV_PHYLINK_DOWN, NULL); osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, state == PHY_LINK_CONNECTED ? NM_EV_PHYLINK_UP : NM_EV_PHYLINK_DOWN, NULL); } } enum phy_link_state phy_link_state_get(struct phy_link *plink) { return plink->state; } const char *phy_link_state_name(enum phy_link_state state) { return get_value_string(phy_link_state_vals, state); } struct phy_instance *phy_instance_by_num(const struct phy_link *plink, int num) { struct phy_instance *pinst; llist_for_each_entry(pinst, &plink->instances, list) { if (pinst->num == num) return pinst; } return NULL; } struct phy_instance *phy_instance_create(struct phy_link *plink, int num) { struct phy_instance *pinst; if (phy_instance_by_num(plink, num)) return NULL; pinst = talloc_zero(plink, struct phy_instance); pinst->num = num; pinst->phy_link = plink; llist_add_tail(&pinst->list, &plink->instances); bts_model_phy_instance_set_defaults(pinst); return pinst; } void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx) { /* There might already be an associated TRX */ OSMO_ASSERT(pinst->trx == NULL) trx->pinst = pinst; pinst->trx = trx; } void phy_instance_destroy(struct phy_instance *pinst) { /* remove from list of instances in the link */ llist_del(&pinst->list); /* remove reverse link from TRX */ OSMO_ASSERT(pinst->trx->pinst == pinst); pinst->trx->pinst = NULL; pinst->trx = NULL; talloc_free(pinst); } void phy_link_destroy(struct phy_link *plink) { struct phy_instance *pinst, *pinst2; llist_for_each_entry_safe(pinst, pinst2, &plink->instances, list) phy_instance_destroy(pinst); talloc_free(plink); } static char name_buf[32]; const char *phy_link_name(const struct phy_link *plink) { snprintf(name_buf, sizeof(name_buf), "phy%u", plink->num); return name_buf; } int phy_links_open(void) { const struct phy_instance *pinst; struct phy_link *plink; llist_for_each_entry(plink, &g_phy_links, list) { int rc; /* Warn about dangling PHY instances */ llist_for_each_entry(pinst, &plink->instances, list) { if (pinst->trx != NULL) continue; LOGPPHI(pinst, DL1C, LOGL_NOTICE, "This PHY instance is not associated " "with a TRX instance, check the configuration file!\n"); } rc = bts_model_phy_link_open(plink); if (rc < 0) return rc; } return 0; } const char *phy_instance_name(const struct phy_instance *pinst) { snprintf(name_buf, sizeof(name_buf), "phy%u.%u", pinst->phy_link->num, pinst->num); return name_buf; }