diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2008-02-08 07:21:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:22:37 -0500 |
commit | dfa7f343e526f3595d8f1d99807d141ae0c08601 (patch) | |
tree | e9adc3c14cc518518c4af9a71267300c60bb7f9f | |
parent | 1c0fd82f9375b41f880dc9d7fe32920f33dc945b (diff) |
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 0b7b2743b996..e06c6c8f4dd8 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) | |||
934 | 934 | ||
935 | core_initcall(atmel_late_console_init); | 935 | core_initcall(atmel_late_console_init); |
936 | 936 | ||
937 | static inline bool atmel_is_console_port(struct uart_port *port) | ||
938 | { | ||
939 | return port->cons && port->cons->index == port->line; | ||
940 | } | ||
941 | |||
937 | #else | 942 | #else |
938 | #define ATMEL_CONSOLE_DEVICE NULL | 943 | #define ATMEL_CONSOLE_DEVICE NULL |
944 | |||
945 | static inline bool atmel_is_console_port(struct uart_port *port) | ||
946 | { | ||
947 | return false; | ||
948 | } | ||
939 | #endif | 949 | #endif |
940 | 950 | ||
941 | static struct uart_driver atmel_uart = { | 951 | static struct uart_driver atmel_uart = { |
@@ -993,9 +1003,19 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) | |||
993 | atmel_init_port(port, pdev); | 1003 | atmel_init_port(port, pdev); |
994 | 1004 | ||
995 | ret = uart_add_one_port(&atmel_uart, &port->uart); | 1005 | ret = uart_add_one_port(&atmel_uart, &port->uart); |
996 | if (!ret) { | 1006 | if (ret) |
997 | device_init_wakeup(&pdev->dev, 1); | 1007 | goto err_add_port; |
998 | platform_set_drvdata(pdev, port); | 1008 | |
1009 | device_init_wakeup(&pdev->dev, 1); | ||
1010 | platform_set_drvdata(pdev, port); | ||
1011 | |||
1012 | return 0; | ||
1013 | |||
1014 | err_add_port: | ||
1015 | if (!atmel_is_console_port(&port->uart)) { | ||
1016 | clk_disable(port->clk); | ||
1017 | clk_put(port->clk); | ||
1018 | port->clk = NULL; | ||
999 | } | 1019 | } |
1000 | 1020 | ||
1001 | return ret; | 1021 | return ret; |
@@ -1007,16 +1027,15 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev) | |||
1007 | struct atmel_uart_port *atmel_port = (struct atmel_uart_port *)port; | 1027 | struct atmel_uart_port *atmel_port = (struct atmel_uart_port *)port; |
1008 | int ret = 0; | 1028 | int ret = 0; |
1009 | 1029 | ||
1010 | clk_disable(atmel_port->clk); | ||
1011 | clk_put(atmel_port->clk); | ||
1012 | |||
1013 | device_init_wakeup(&pdev->dev, 0); | 1030 | device_init_wakeup(&pdev->dev, 0); |
1014 | platform_set_drvdata(pdev, NULL); | 1031 | platform_set_drvdata(pdev, NULL); |
1015 | 1032 | ||
1016 | if (port) { | 1033 | ret = uart_remove_one_port(&atmel_uart, port); |
1017 | ret = uart_remove_one_port(&atmel_uart, port); | 1034 | |
1018 | kfree(port); | 1035 | /* "port" is allocated statically, so we shouldn't free it */ |
1019 | } | 1036 | |
1037 | clk_disable(atmel_port->clk); | ||
1038 | clk_put(atmel_port->clk); | ||
1020 | 1039 | ||
1021 | return ret; | 1040 | return ret; |
1022 | } | 1041 | } |