dynamically generate a proper VTY reference for phys_chan_config

this uses vty_cmd_string_from_valstr() from _very_ recent libosmocore,
so you have to update the library, sorry.
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index 310e888..3ba7a4b 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -658,6 +658,10 @@
 
 struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
 
+
+const struct value_string gsm_pchant_names[10];
+const struct value_string gsm_pchant_descs[10];
+const struct value_string gsm_lchant_names[6];
 const char *gsm_pchan_name(enum gsm_phys_chan_config c);
 enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
 const char *gsm_lchant_name(enum gsm_chan_t c);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 4031cec..7c434b9 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -25,6 +25,7 @@
 #include <osmocom/vty/vty.h>
 #include <osmocom/vty/logging.h>
 #include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/misc.h>
 
 #include <arpa/inet.h>
 
@@ -2555,6 +2556,25 @@
 
 DEFUN(cfg_ts_pchan,
       cfg_ts_pchan_cmd,
+      "phys_chan_config PCHAN", /* dynamically generated! */
+      "Physical Channel configuration (TCH/SDCCH/...)")
+{
+	struct gsm_bts_trx_ts *ts = vty->index;
+	int pchanc;
+
+	pchanc = gsm_pchan_parse(argv[0]);
+	if (pchanc < 0)
+		return CMD_WARNING;
+
+	ts->pchan = pchanc;
+
+	return CMD_SUCCESS;
+}
+
+/* used for backwards compatibility with old config files that still
+ * have uppercase pchan type names */
+DEFUN_HIDDEN(cfg_ts_pchan_compat,
+      cfg_ts_pchan_compat_cmd,
       "phys_chan_config PCHAN",
       "Physical Channel configuration (TCH/SDCCH/...)")
 {
@@ -2570,6 +2590,8 @@
 	return CMD_SUCCESS;
 }
 
+
+
 DEFUN(cfg_ts_tsc,
       cfg_ts_tsc_cmd,
       "training_sequence_code <0-7>",
@@ -2821,6 +2843,17 @@
 
 int bsc_vty_init(const struct log_info *cat)
 {
+	cfg_ts_pchan_cmd.string =
+		vty_cmd_string_from_valstr(tall_bsc_ctx,
+					   gsm_pchant_names,
+					   "phys_chan_config (", "|", ")",
+					   VTY_DO_LOWER);
+	cfg_ts_pchan_cmd.doc =
+		vty_cmd_string_from_valstr(tall_bsc_ctx,
+					   gsm_pchant_descs,
+					   "Physical Channel Combination\n",
+					   "\n", "", 0);
+
 	install_element_ve(&show_net_cmd);
 	install_element_ve(&show_bts_cmd);
 	install_element_ve(&show_trx_cmd);
@@ -2948,6 +2981,7 @@
 	install_element(TS_NODE, &ournode_exit_cmd);
 	install_element(TS_NODE, &ournode_end_cmd);
 	install_element(TS_NODE, &cfg_ts_pchan_cmd);
+	install_element(TS_NODE, &cfg_ts_pchan_compat_cmd);
 	install_element(TS_NODE, &cfg_ts_tsc_cmd);
 	install_element(TS_NODE, &cfg_ts_hopping_cmd);
 	install_element(TS_NODE, &cfg_ts_hsn_cmd);
diff --git a/openbsc/src/libcommon/gsm_data_shared.c b/openbsc/src/libcommon/gsm_data_shared.c
index 9e7b59c..3ec1d10 100644
--- a/openbsc/src/libcommon/gsm_data_shared.c
+++ b/openbsc/src/libcommon/gsm_data_shared.c
@@ -51,7 +51,7 @@
 	gsm_abis_mo_reset(mo);
 }
 
-static const struct value_string pchan_names[] = {
+const struct value_string gsm_pchant_names[10] = {
 	{ GSM_PCHAN_NONE,	"NONE" },
 	{ GSM_PCHAN_CCCH,	"CCCH" },
 	{ GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" },
@@ -64,17 +64,31 @@
 	{ 0,			NULL }
 };
 
+const struct value_string gsm_pchant_descs[10] = {
+	{ GSM_PCHAN_NONE,	"Physical Channel not configured" },
+	{ GSM_PCHAN_CCCH,	"FCCH + SCH + BCCH + CCCH (Comb. IV)" },
+	{ GSM_PCHAN_CCCH_SDCCH4,
+		"FCCH + SCH + BCCH + CCCH + 4 SDCCH + 2 SACCH (Comb. V)" },
+	{ GSM_PCHAN_TCH_F,	"TCH/F + FACCH/F + SACCH (Comb. I)" },
+	{ GSM_PCHAN_TCH_H,	"2 TCH/H + 2 FACCH/H + 2 SACCH (Comb. II)" },
+	{ GSM_PCHAN_SDCCH8_SACCH8C, "8 SDCCH + 4 SACCH (Comb. VII)" },
+	{ GSM_PCHAN_PDCH,	"Packet Data Channel for GPRS/EDGE" },
+	{ GSM_PCHAN_TCH_F_PDCH,	"Dynamic TCH/F or GPRS PDCH" },
+	{ GSM_PCHAN_UNKNOWN,	"Unknown / Unsupported channel combination" },
+	{ 0,			NULL }
+};
+
 const char *gsm_pchan_name(enum gsm_phys_chan_config c)
 {
-	return get_value_string(pchan_names, c);
+	return get_value_string(gsm_pchant_names, c);
 }
 
 enum gsm_phys_chan_config gsm_pchan_parse(const char *name)
 {
-	return get_string_value(pchan_names, name);
+	return get_string_value(gsm_pchant_names, name);
 }
 
-static const struct value_string lchant_names[] = {
+const struct value_string gsm_lchant_names[6] = {
 	{ GSM_LCHAN_NONE,	"NONE" },
 	{ GSM_LCHAN_SDCCH,	"SDCCH" },
 	{ GSM_LCHAN_TCH_F,	"TCH/F" },
@@ -85,7 +99,7 @@
 
 const char *gsm_lchant_name(enum gsm_chan_t c)
 {
-	return get_value_string(lchant_names, c);
+	return get_value_string(gsm_lchant_names, c);
 }
 
 static const struct value_string lchan_s_names[] = {