[PATCH v2 4/5] tty/serial: atmel_serial: auto-enumerate ports

Nicolas Ferre nicolas.ferre at atmel.com
Wed Oct 12 12:06:59 EDT 2011


If no platform data provided to enumerate ports, use a bit field
to choose port number and check if port is already initialized.
Use this mechanism for both console and plain serial ports.

Signed-off-by: Nicolas Ferre <nicolas.ferre at atmel.com>
---
 drivers/tty/serial/atmel_serial.c |   44 ++++++++++++++++++++++++++++++------
 1 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index bb72354..1074329 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -157,6 +157,7 @@ struct atmel_uart_port {
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+static unsigned long atmel_ports_in_use;
 
 #ifdef SUPPORT_SYSRQ
 static struct console atmel_console;
@@ -1423,7 +1424,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
 	port->flags		= UPF_BOOT_AUTOCONF;
 	port->ops		= &atmel_pops;
 	port->fifosize		= 1;
-	port->line		= pdata->num;
 	port->dev		= &pdev->dev;
 	port->mapbase	= pdev->resource[0].start;
 	port->irq	= pdev->resource[1].start;
@@ -1613,10 +1613,15 @@ static struct console atmel_console = {
 static int __init atmel_console_init(void)
 {
 	if (atmel_default_console_device) {
-		add_preferred_console(ATMEL_DEVICENAME,
-				      atmel_default_console_device->id, NULL);
-		atmel_init_port(&atmel_ports[atmel_default_console_device->id],
-				atmel_default_console_device);
+		int id = atmel_default_console_device->id;
+		struct atmel_uart_port *port = &atmel_ports[id];
+
+		set_bit(id, &atmel_ports_in_use);
+		port->backup_imr = 0;
+		port->uart.line = id;
+
+		add_preferred_console(ATMEL_DEVICENAME, id, NULL);
+		atmel_init_port(port, atmel_default_console_device);
 		register_console(&atmel_console);
 	}
 
@@ -1715,12 +1720,33 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
 	struct atmel_uart_port *port;
 	struct atmel_uart_data *pdata = pdev->dev.platform_data;
 	void *data;
-	int ret;
+	int ret = -ENODEV;
 
 	BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
 
-	port = &atmel_ports[pdata->num];
+	if (pdata)
+		ret = pdata->num;
+
+	if (ret < 0)
+		/* port id not found in platform data:
+		 * auto-enumerate it */
+		ret = find_first_zero_bit(&atmel_ports_in_use,
+				sizeof(atmel_ports_in_use));
+
+	if (ret > ATMEL_MAX_UART) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	if (test_and_set_bit(ret, &atmel_ports_in_use)) {
+		/* port already in use */
+		ret = -EBUSY;
+		goto err;
+	}
+
+	port = &atmel_ports[ret];
 	port->backup_imr = 0;
+	port->uart.line = ret;
 
 	atmel_init_port(port, pdev);
 
@@ -1766,7 +1792,7 @@ err_alloc_ring:
 		clk_put(port->clk);
 		port->clk = NULL;
 	}
-
+err:
 	return ret;
 }
 
@@ -1786,6 +1812,8 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
 
 	/* "port" is allocated statically, so we shouldn't free it */
 
+	clear_bit(port->line, &atmel_ports_in_use);
+
 	clk_put(atmel_port->clk);
 
 	return ret;
-- 
1.7.5.4




More information about the linux-arm-kernel mailing list