ANDROID: ARM: fiq_debugger: fix multiple consoles and make it a preferred console

Fix setting up consoles on multiple fiq debugger devices by
splitting the tty driver init into the initcall, and initializing
the single tty device during probe.  Has the side effect of moving
the tty device node to /dev/ttyFIQx, where x is the platform device
id, which should normally match the serial port.

To avoid having to pass a different console=/dev/ttyFIQx for every
device, make the fiq debugger a preferred console that will be used
by default if no console was passed on the command line.

Change-Id: I6cc2670628a41e84615859bc96adba189966d647
Signed-off-by: Colin Cross <ccross@android.com>
diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c
index 1f64d7d..ac95224 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/arch/arm/common/fiq_debugger.c
@@ -45,6 +45,8 @@
 #define DEBUG_MAX 64
 #define MAX_UNHANDLED_FIQ_COUNT 1000000
 
+#define MAX_FIQ_DEBUGGER_PORTS 4
+
 #define THREAD_INFO(sp) ((struct thread_info *) \
 		((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
 
@@ -81,7 +83,6 @@
 
 #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
 	struct console console;
-	struct tty_driver *tty_driver;
 	struct tty_struct *tty;
 	int tty_open_count;
 	struct fiq_debugger_ringbuf *tty_rbuf;
@@ -92,6 +93,10 @@
 	unsigned int last_local_timer_irqs[NR_CPUS];
 };
 
+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
+struct tty_driver *fiq_tty_driver;
+#endif
+
 #ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP
 static bool initial_no_sleep = true;
 #else
@@ -913,10 +918,8 @@
 #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
 struct tty_driver *debug_console_device(struct console *co, int *index)
 {
-	struct fiq_debugger_state *state;
-	state = container_of(co, struct fiq_debugger_state, console);
-	*index = 0;
-	return state->tty_driver;
+	*index = co->index;
+	return fiq_tty_driver;
 }
 
 static void debug_console_write(struct console *co,
@@ -948,7 +951,9 @@
 
 int fiq_tty_open(struct tty_struct *tty, struct file *filp)
 {
-	struct fiq_debugger_state *state = tty->driver->driver_state;
+	int line = tty->index;
+	struct fiq_debugger_state **states = tty->driver->driver_state;
+	struct fiq_debugger_state *state = states[line];
 	if (state->tty_open_count++)
 		return 0;
 
@@ -1035,36 +1040,66 @@
 #endif
 };
 
-static int fiq_debugger_tty_init(struct fiq_debugger_state *state)
+static int fiq_debugger_tty_init(void)
 {
-	int ret = -EINVAL;
+	int ret;
+	struct fiq_debugger_state **states = NULL;
 
-	state->tty_driver = alloc_tty_driver(1);
-	if (!state->tty_driver) {
-		pr_err("Failed to allocate fiq debugger tty\n");
+	states = kzalloc(sizeof(*states) * MAX_FIQ_DEBUGGER_PORTS, GFP_KERNEL);
+	if (!states) {
+		pr_err("Failed to allocate fiq debugger state structres\n");
 		return -ENOMEM;
 	}
 
-	state->tty_driver->owner		= THIS_MODULE;
-	state->tty_driver->driver_name	= "fiq-debugger";
-	state->tty_driver->name		= "ttyFIQ";
-	state->tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
-	state->tty_driver->subtype	= SERIAL_TYPE_NORMAL;
-	state->tty_driver->init_termios	= tty_std_termios;
-	state->tty_driver->init_termios.c_cflag =
-					B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-	state->tty_driver->init_termios.c_ispeed =
-		state->tty_driver->init_termios.c_ospeed = 115200;
-	state->tty_driver->flags		= TTY_DRIVER_REAL_RAW;
-	tty_set_operations(state->tty_driver, &fiq_tty_driver_ops);
-	state->tty_driver->driver_state = state;
+	fiq_tty_driver = alloc_tty_driver(MAX_FIQ_DEBUGGER_PORTS);
+	if (!fiq_tty_driver) {
+		pr_err("Failed to allocate fiq debugger tty\n");
+		ret = -ENOMEM;
+		goto err_free_state;
+	}
 
-	ret = tty_register_driver(state->tty_driver);
+	fiq_tty_driver->owner		= THIS_MODULE;
+	fiq_tty_driver->driver_name	= "fiq-debugger";
+	fiq_tty_driver->name		= "ttyFIQ";
+	fiq_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
+	fiq_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
+	fiq_tty_driver->init_termios	= tty_std_termios;
+	fiq_tty_driver->flags		= TTY_DRIVER_REAL_RAW |
+					  TTY_DRIVER_DYNAMIC_DEV;
+	fiq_tty_driver->driver_state	= states;
+
+	fiq_tty_driver->init_termios.c_cflag =
+					B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+	fiq_tty_driver->init_termios.c_ispeed = 115200;
+	fiq_tty_driver->init_termios.c_ospeed = 115200;
+
+	tty_set_operations(fiq_tty_driver, &fiq_tty_driver_ops);
+
+	ret = tty_register_driver(fiq_tty_driver);
 	if (ret) {
 		pr_err("Failed to register fiq tty: %d\n", ret);
-		goto err;
+		goto err_free_tty;
 	}
 
+	pr_info("Registered FIQ tty driver\n");
+	return 0;
+
+err_free_tty:
+	put_tty_driver(fiq_tty_driver);
+	fiq_tty_driver = NULL;
+err_free_state:
+	kfree(states);
+	return ret;
+}
+
+static int fiq_debugger_tty_init_one(struct fiq_debugger_state *state)
+{
+	int ret;
+	struct device *tty_dev;
+	struct fiq_debugger_state **states = fiq_tty_driver->driver_state;
+
+	states[state->pdev->id] = state;
+
 	state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024);
 	if (!state->tty_rbuf) {
 		pr_err("Failed to allocate fiq debugger ringbuf\n");
@@ -1072,13 +1107,23 @@
 		goto err;
 	}
 
-	pr_info("Registered FIQ tty driver %p\n", state->tty_driver);
+	tty_dev = tty_register_device(fiq_tty_driver, state->pdev->id,
+		&state->pdev->dev);
+	if (IS_ERR(tty_dev)) {
+		pr_err("Failed to register fiq debugger tty device\n");
+		ret = PTR_ERR(tty_dev);
+		goto err;
+	}
+
+	device_set_wakeup_capable(tty_dev, 1);
+
+	pr_info("Registered fiq debugger ttyFIQ%d\n", state->pdev->id);
+
 	return 0;
 
 err:
 	fiq_debugger_ringbuf_free(state->tty_rbuf);
 	state->tty_rbuf = NULL;
-	put_tty_driver(state->tty_driver);
 	return ret;
 }
 #endif
@@ -1111,6 +1156,9 @@
 	int fiq;
 	int uart_irq;
 
+	if (pdev->id >= MAX_FIQ_DEBUGGER_PORTS)
+		return -EINVAL;
+
 	if (!pdata->uart_getc || !pdata->uart_putc)
 		return -EINVAL;
 	if ((pdata->uart_enable && !pdata->uart_disable) ||
@@ -1228,8 +1276,12 @@
 
 #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
 	state->console = fiq_debugger_console;
+	state->console.index = pdev->id;
+	if (!console_set_on_cmdline)
+		add_preferred_console(state->console.name,
+			state->console.index, NULL);
 	register_console(&state->console);
-	fiq_debugger_tty_init(state);
+	fiq_debugger_tty_init_one(state);
 #endif
 	return 0;
 
@@ -1263,6 +1315,9 @@
 
 static int __init fiq_debugger_init(void)
 {
+#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
+	fiq_debugger_tty_init();
+#endif
 	return platform_driver_register(&fiq_debugger_driver);
 }