[E1 INPUT] explicitly configure the E1 input driver for each line

This introduces a new 'e1_input' config node with a command to be
used like:
  e1_line 0 driver misdn

This allows us to have different input drivers in the future
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 290bc06..351b269 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -19,7 +19,8 @@
 libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
 		chan_alloc.c debug.c socket.c abis_nm_vty.c \
 		gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
-		trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \
+		trau_frame.c trau_mux.c paging.c \
+		e1_config.c e1_input.c e1_input_vty.c \
 		input/misdn.c input/ipaccess.c handover_logic.c \
 		talloc_ctx.c system_information.c rest_octets.c \
 		bts_siemens_bs11.c bts_ipaccess_nanobts.c mncc_upqueue.c \
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 11499ab..dacaad3 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -238,6 +238,8 @@
 	bts_model_bs11_init();
 	bts_model_nanobts_init();
 
+	e1inp_init();
+
 	/* enable filters */
 	log_set_all_filter(stderr_target, 1);
 
diff --git a/openbsc/src/bsc_vty.c b/openbsc/src/bsc_vty.c
index 9709301..739d9aa 100644
--- a/openbsc/src/bsc_vty.c
+++ b/openbsc/src/bsc_vty.c
@@ -2702,6 +2702,7 @@
 	install_element(ENABLE_NODE, &pdch_act_cmd);
 
 	abis_nm_vty_init();
+	e1inp_vty_init();
 
 	bsc_vty_init_extra();
 
diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c
index dd78720..f781b9e 100644
--- a/openbsc/src/e1_config.c
+++ b/openbsc/src/e1_config.c
@@ -51,7 +51,7 @@
 	if (!e1_link->e1_ts)
 		return 0;
 
-	line = e1inp_line_get_create(e1_link->e1_nr);
+	line = e1inp_line_get(e1_link->e1_nr);
 	if (!line)
 		return -ENOMEM;
 
@@ -81,7 +81,7 @@
 		return -EINVAL;
 
 	/* RSL Link */
-	line = e1inp_line_get_create(e1_link->e1_nr);
+	line = e1inp_line_get(e1_link->e1_nr);
 	if (!line)
 		return -ENOMEM;
 	sign_ts = &line->ts[e1_link->e1_ts-1];
@@ -114,7 +114,7 @@
 		return -EINVAL;
 
 	/* OML link */
-	line = e1inp_line_get_create(e1_link->e1_nr);
+	line = e1inp_line_get(e1_link->e1_nr);
 	if (!line)
 		return -ENOMEM;
 	sign_ts = &line->ts[e1_link->e1_ts-1];
diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c
index 45231c3..923d7db 100644
--- a/openbsc/src/e1_input.c
+++ b/openbsc/src/e1_input.c
@@ -322,7 +322,7 @@
 	return 0;
 }
 
-static struct e1inp_line *e1inp_line_get(u_int8_t e1_nr)
+struct e1inp_line *e1inp_line_get(u_int8_t e1_nr)
 {
 	struct e1inp_line *e1i_line;
 
@@ -334,6 +334,37 @@
 	return NULL;
 }
 
+struct e1inp_line *e1inp_line_create(u_int8_t e1_nr, const char *driver_name)
+{
+	struct e1inp_driver *driver;
+	struct e1inp_line *line;
+	int i;
+
+	line = e1inp_line_get(e1_nr);
+	if (line)
+		return NULL;
+
+	driver = e1inp_driver_find(driver_name);
+	if (!driver)
+		return NULL;
+
+	line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
+	if (!line)
+		return NULL;
+
+	line->driver = driver;
+
+	line->num = e1_nr;
+	for (i = 0; i < NUM_E1_TS; i++) {
+		line->ts[i].num = i+1;
+		line->ts[i].line = line;
+	}
+	llist_add_tail(&line->list, &e1inp_line_list);
+
+	return line;
+}
+
+#if 0
 struct e1inp_line *e1inp_line_get_create(u_int8_t e1_nr)
 {
 	struct e1inp_line *line;
@@ -356,6 +387,7 @@
 
 	return line;
 }
+#endif
 
 static struct e1inp_ts *e1inp_ts_get(u_int8_t e1_nr, u_int8_t ts_nr)
 {
@@ -536,10 +568,23 @@
 /* register a driver with the E1 core */
 int e1inp_driver_register(struct e1inp_driver *drv)
 {
+	printf("registering driver %s\n", drv->name);
 	llist_add_tail(&drv->list, &e1inp_driver_list);
 	return 0;
 }
 
+struct e1inp_driver *e1inp_driver_find(const char *name)
+{
+	struct e1inp_driver *drv;
+
+	printf("trying to find driver %s\n", name);
+	llist_for_each_entry(drv, &e1inp_driver_list, list) {
+		if (!strcasecmp(name, drv->name))
+			return drv;
+	}
+	return NULL;
+}
+
 int e1inp_line_update(struct e1inp_line *line)
 {
 	if (line->driver && line->driver->line_update)
@@ -563,9 +608,13 @@
 	return 0;
 }
 
-static __attribute__((constructor)) void on_dso_load_e1_inp(void)
+void e1inp_misdn_init(void);
+
+void e1inp_init(void)
 {
 	tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1,
 					   "e1inp_sign_link");
 	register_signal_handler(SS_GLOBAL, e1i_sig_cb, NULL);
+
+	e1inp_misdn_init();
 }
diff --git a/openbsc/src/e1_input_vty.c b/openbsc/src/e1_input_vty.c
new file mode 100644
index 0000000..6d44a95
--- /dev/null
+++ b/openbsc/src/e1_input_vty.c
@@ -0,0 +1,99 @@
+/* OpenBSC E1 vty interface */
+/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
+ * 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 Affero 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 <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+
+#include <osmocore/linuxlist.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/e1_input.h>
+#include <osmocore/utils.h>
+#include <osmocore/gsm_utils.h>
+#include <osmocore/talloc.h>
+#include <openbsc/vty.h>
+#include <openbsc/debug.h>
+
+#include "../bscconfig.h"
+
+#define E1_DRIVER_NAMES		"(misdn)"
+#define E1_DRIVER_HELP		"mISDN supported E1 Card\n"
+
+DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd,
+	"e1_line <0-255> driver " E1_DRIVER_NAMES,
+	"Configure E1/T1/J1 Line\n" "Line Number\n" "Set driver for this line\n"
+	E1_DRIVER_HELP)
+{
+	struct e1inp_line *line;
+	int e1_nr = atoi(argv[0]);
+
+	line = e1inp_line_get(e1_nr);
+	if (line) {
+		vty_out(vty, "%% Line %d already exists%s", e1_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	line = e1inp_line_create(e1_nr, argv[1]);
+	if (!line) {
+		vty_out(vty, "%% Error creating line %d%s", e1_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1inp, cfg_e1inp_cmd,
+	"e1_input",
+	"Configure E1/T1/J1 TDM input\n")
+{
+	vty->node = E1INP_NODE;
+
+	return CMD_SUCCESS;
+}
+
+static int e1inp_config_write(struct vty *vty)
+{
+	struct e1inp_line *line;
+
+	llist_for_each_entry(line, &e1inp_line_list, list) {
+		vty_out(vty, " e1_line %u driver %s%s", line->num,
+			line->driver->name, VTY_NEWLINE);
+	}
+	return CMD_SUCCESS;
+}
+
+struct cmd_node e1inp_node = {
+	E1INP_NODE,
+	"%s(e1_input)#",
+	1,
+};
+
+int e1inp_vty_init(void)
+{
+	install_element(CONFIG_NODE, &cfg_e1inp_cmd);
+	install_node(&e1inp_node, e1inp_config_write);
+	install_element(E1INP_NODE, &cfg_e1_line_driver_cmd);
+
+	return 0;
+}
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index 1f24a27..77b1fd8 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -386,7 +386,7 @@
 static int mi_e1_line_update(struct e1inp_line *line);
 
 struct e1inp_driver misdn_driver = {
-	.name = "mISDNuser",
+	.name = "mISDN",
 	.want_write = ts_want_write,
 	.default_delay = 50000,
 	.line_update = &mi_e1_line_update,
@@ -486,16 +486,6 @@
 	struct mISDN_devinfo devinfo;
 	int sk, ret, cnt;
 
-	if (!line->driver) {
-		/* this must be the first update */
-		line->driver = &misdn_driver;
-	} else {
-		/* this is a subsequent update */
-		/* FIXME: first close all sockets */
-		fprintf(stderr, "incremental line updates not supported yet\n");
-		return 0;
-	}
-
 	if (line->driver != &misdn_driver)
 		return -EINVAL;
 
@@ -544,7 +534,7 @@
 	return 0;
 }
 
-static __attribute__((constructor)) void on_dso_load_sms(void)
+void e1inp_misdn_init(void)
 {
 	/* register the driver with the core */
 	e1inp_driver_register(&misdn_driver);