diff options
author | David S. Miller <davem@davemloft.net> | 2006-06-29 18:13:40 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-29 19:37:44 -0400 |
commit | 4fa97dcf9d48b02934c60a48873199850351e760 (patch) | |
tree | eac7bda737afe4d723b12d8ae67dfe35d14098a7 | |
parent | 3676463178401293d625a102a00da0473fa33a1b (diff) |
[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) | |||
1335 | return ret; | 1335 | return ret; |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | static int zilog_irq = -1; | ||
1339 | |||
1338 | static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) | 1340 | static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) |
1339 | { | 1341 | { |
1340 | static int zilog_irq = -1; | ||
1341 | struct of_device *op = to_of_device(&dev->dev); | 1342 | struct of_device *op = to_of_device(&dev->dev); |
1342 | struct uart_sunzilog_port *up; | 1343 | struct uart_sunzilog_port *up; |
1343 | struct zilog_layout __iomem *rp; | 1344 | struct zilog_layout __iomem *rp; |
@@ -1413,24 +1414,33 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id * | |||
1413 | } | 1414 | } |
1414 | } | 1415 | } |
1415 | 1416 | ||
1417 | dev_set_drvdata(&dev->dev, &up[0]); | ||
1418 | |||
1416 | return 0; | 1419 | return 0; |
1417 | } | 1420 | } |
1418 | 1421 | ||
1419 | static int __devexit zs_remove(struct of_device *dev) | 1422 | static void __devexit zs_remove_one(struct uart_sunzilog_port *up) |
1420 | { | 1423 | { |
1421 | struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); | ||
1422 | struct zilog_channel __iomem *channel; | ||
1423 | |||
1424 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { | 1424 | if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { |
1425 | #ifdef CONFIG_SERIO | 1425 | #ifdef CONFIG_SERIO |
1426 | serio_unregister_port(&up->serio); | 1426 | serio_unregister_port(&up->serio); |
1427 | #endif | 1427 | #endif |
1428 | } else | 1428 | } else |
1429 | uart_remove_one_port(&sunzilog_reg, &up->port); | 1429 | uart_remove_one_port(&sunzilog_reg, &up->port); |
1430 | } | ||
1430 | 1431 | ||
1431 | channel = ZILOG_CHANNEL_FROM_PORT(&up->port); | 1432 | static int __devexit zs_remove(struct of_device *dev) |
1433 | { | ||
1434 | struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); | ||
1435 | struct zilog_layout __iomem *regs; | ||
1436 | |||
1437 | zs_remove_one(&up[0]); | ||
1438 | zs_remove_one(&up[1]); | ||
1432 | 1439 | ||
1433 | of_iounmap(channel, sizeof(struct zilog_channel)); | 1440 | regs = sunzilog_chip_regs[up[0].port.line / 2]; |
1441 | of_iounmap(regs, sizeof(struct zilog_layout)); | ||
1442 | |||
1443 | dev_set_drvdata(&dev->dev, NULL); | ||
1434 | 1444 | ||
1435 | return 0; | 1445 | return 0; |
1436 | } | 1446 | } |
@@ -1489,6 +1499,11 @@ static void __exit sunzilog_exit(void) | |||
1489 | { | 1499 | { |
1490 | of_unregister_driver(&zs_driver); | 1500 | of_unregister_driver(&zs_driver); |
1491 | 1501 | ||
1502 | if (zilog_irq != -1) { | ||
1503 | free_irq(zilog_irq, sunzilog_irq_chain); | ||
1504 | zilog_irq = -1; | ||
1505 | } | ||
1506 | |||
1492 | if (NUM_SUNZILOG) { | 1507 | if (NUM_SUNZILOG) { |
1493 | uart_unregister_driver(&sunzilog_reg); | 1508 | uart_unregister_driver(&sunzilog_reg); |
1494 | sunzilog_free_tables(); | 1509 | sunzilog_free_tables(); |