diff options
author | David S. Miller <davem@davemloft.net> | 2006-06-30 02:13:40 +0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-30 03:37:44 +0400 |
commit | 4fa97dcf9d48b02934c60a48873199850351e760 (patch) | |
tree | eac7bda737afe4d723b12d8ae67dfe35d14098a7 | |
parent | 3676463178401293d625a102a00da0473fa33a1b (diff) | |
download | linux-4fa97dcf9d48b02934c60a48873199850351e760.tar.xz |
[SERIAL] sunzilog: Fix bugs in device deregristration.
1) Need to unregister 2 ports per of_device.
2) Need to of_iounmap() 1 mapping per of_device.
3) Need to free up the IRQ only after all devices
have been unregistered.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/serial/sunzilog.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index cbdf9d605b3f..98342eeba734 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1335,9 +1335,10 @@ static int __devinit zs_get_instance(struct device_node *dp) return ret; } +static int zilog_irq = -1; + static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) { - static int zilog_irq = -1; struct of_device *op = to_of_device(&dev->dev); struct uart_sunzilog_port *up; struct zilog_layout __iomem *rp; @@ -1413,24 +1414,33 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id * } } + dev_set_drvdata(&dev->dev, &up[0]); + return 0; } -static int __devexit zs_remove(struct of_device *dev) +static void __devexit zs_remove_one(struct uart_sunzilog_port *up) { - struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); - struct zilog_channel __iomem *channel; - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { #ifdef CONFIG_SERIO serio_unregister_port(&up->serio); #endif } else uart_remove_one_port(&sunzilog_reg, &up->port); +} - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); +static int __devexit zs_remove(struct of_device *dev) +{ + struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); + struct zilog_layout __iomem *regs; + + zs_remove_one(&up[0]); + zs_remove_one(&up[1]); - of_iounmap(channel, sizeof(struct zilog_channel)); + regs = sunzilog_chip_regs[up[0].port.line / 2]; + of_iounmap(regs, sizeof(struct zilog_layout)); + + dev_set_drvdata(&dev->dev, NULL); return 0; } @@ -1489,6 +1499,11 @@ static void __exit sunzilog_exit(void) { of_unregister_driver(&zs_driver); + if (zilog_irq != -1) { + free_irq(zilog_irq, sunzilog_irq_chain); + zilog_irq = -1; + } + if (NUM_SUNZILOG) { uart_unregister_driver(&sunzilog_reg); sunzilog_free_tables(); |