diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2008-02-08 04:21:04 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 09:22:37 -0800 |
commit | dfa7f343e526f3595d8f1d99807d141ae0c08601 (patch) | |
tree | e9adc3c14cc518518c4af9a71267300c60bb7f9f | |
parent | 1c0fd82f9375b41f880dc9d7fe32920f33dc945b (diff) | |
download | op-kernel-dev-dfa7f343e526f3595d8f1d99807d141ae0c08601.zip op-kernel-dev-dfa7f343e526f3595d8f1d99807d141ae0c08601.tar.gz |
atmel_serial: fix bugs in probe() error path and remove()
When an error happens in probe(), the clocks should be disabled, but
only if the port isn't already used as a console.
In remove(), the port struct shouldn't be freed because it's defined
statically.
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Andrew Victor <linux@maxim.org.za>
Tested-by: Marc Pignat <marc.pignat@hevs.ch>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/serial/atmel_serial.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 0b7b274..e06c6c8 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -934,8 +934,18 @@ static int __init atmel_late_console_init(void) core_initcall(atmel_late_console_init); +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return port->cons && port->cons->index == port->line; +} + #else #define ATMEL_CONSOLE_DEVICE NULL + +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return false; +} #endif static struct uart_driver atmel_uart = { @@ -993,9 +1003,19 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) atmel_init_port(port, pdev); ret = uart_add_one_port(&atmel_uart, &port->uart); - if (!ret) { - device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, port); + if (ret) + goto err_add_port; + + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, port); + + return 0; + +err_add_port: + if (!atmel_is_console_port(&port->uart)) { + clk_disable(port->clk); + clk_put(port->clk); + port->clk = NULL; } return ret; @@ -1007,16 +1027,15 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev) struct atmel_uart_port *atmel_port = (struct atmel_uart_port *)port; int ret = 0; - clk_disable(atmel_port->clk); - clk_put(atmel_port->clk); - device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); - if (port) { - ret = uart_remove_one_port(&atmel_uart, port); - kfree(port); - } + ret = uart_remove_one_port(&atmel_uart, port); + + /* "port" is allocated statically, so we shouldn't free it */ + + clk_disable(atmel_port->clk); + clk_put(atmel_port->clk); return ret; } |