diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-07-18 00:07:17 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-07-21 17:18:08 -0400 |
commit | 67e23a1e60b6bc0a090407d0fc060166ab558b72 (patch) | |
tree | a690bed9a849ba177b046e76cb85f3209650ae55 | |
parent | 39329329565a5e24f0a5523eef3a9dd941e0b29d (diff) |
[SERIAL] sunzilog: Register IRQ after all devices have been probed.
Otherwise we will deref half-initialized channel pointers
and crash in the interrupt handler.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/serial/sunzilog.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index a1456d9352cb..496810c50947 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c | |||
@@ -1336,12 +1336,11 @@ static int __devinit zs_get_instance(struct device_node *dp) | |||
1336 | 1336 | ||
1337 | static int zilog_irq = -1; | 1337 | static int zilog_irq = -1; |
1338 | 1338 | ||
1339 | static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) | 1339 | static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match) |
1340 | { | 1340 | { |
1341 | struct of_device *op = to_of_device(&dev->dev); | ||
1342 | struct uart_sunzilog_port *up; | 1341 | struct uart_sunzilog_port *up; |
1343 | struct zilog_layout __iomem *rp; | 1342 | struct zilog_layout __iomem *rp; |
1344 | int inst = zs_get_instance(dev->node); | 1343 | int inst = zs_get_instance(op->node); |
1345 | int err; | 1344 | int err; |
1346 | 1345 | ||
1347 | sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, | 1346 | sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, |
@@ -1413,7 +1412,7 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id * | |||
1413 | } | 1412 | } |
1414 | } | 1413 | } |
1415 | 1414 | ||
1416 | dev_set_drvdata(&dev->dev, &up[0]); | 1415 | dev_set_drvdata(&op->dev, &up[0]); |
1417 | 1416 | ||
1418 | return 0; | 1417 | return 0; |
1419 | } | 1418 | } |
@@ -1462,18 +1461,19 @@ static struct of_platform_driver zs_driver = { | |||
1462 | static int __init sunzilog_init(void) | 1461 | static int __init sunzilog_init(void) |
1463 | { | 1462 | { |
1464 | struct device_node *dp; | 1463 | struct device_node *dp; |
1465 | int err; | 1464 | int err, uart_count; |
1466 | 1465 | ||
1467 | NUM_SUNZILOG = 0; | 1466 | NUM_SUNZILOG = 0; |
1468 | for_each_node_by_name(dp, "zs") | 1467 | for_each_node_by_name(dp, "zs") |
1469 | NUM_SUNZILOG++; | 1468 | NUM_SUNZILOG++; |
1470 | 1469 | ||
1470 | uart_count = 0; | ||
1471 | if (NUM_SUNZILOG) { | 1471 | if (NUM_SUNZILOG) { |
1472 | int uart_count; | 1472 | int uart_count; |
1473 | 1473 | ||
1474 | err = sunzilog_alloc_tables(); | 1474 | err = sunzilog_alloc_tables(); |
1475 | if (err) | 1475 | if (err) |
1476 | return err; | 1476 | goto out; |
1477 | 1477 | ||
1478 | /* Subtract 1 for keyboard, 1 for mouse. */ | 1478 | /* Subtract 1 for keyboard, 1 for mouse. */ |
1479 | uart_count = (NUM_SUNZILOG * 2) - 2; | 1479 | uart_count = (NUM_SUNZILOG * 2) - 2; |
@@ -1481,17 +1481,41 @@ static int __init sunzilog_init(void) | |||
1481 | sunzilog_reg.nr = uart_count; | 1481 | sunzilog_reg.nr = uart_count; |
1482 | sunzilog_reg.minor = sunserial_current_minor; | 1482 | sunzilog_reg.minor = sunserial_current_minor; |
1483 | err = uart_register_driver(&sunzilog_reg); | 1483 | err = uart_register_driver(&sunzilog_reg); |
1484 | if (err) { | 1484 | if (err) |
1485 | sunzilog_free_tables(); | 1485 | goto out_free_tables; |
1486 | return err; | 1486 | |
1487 | } | ||
1488 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; | 1487 | sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; |
1489 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); | 1488 | sunzilog_reg.cons = SUNZILOG_CONSOLE(); |
1490 | 1489 | ||
1491 | sunserial_current_minor += uart_count; | 1490 | sunserial_current_minor += uart_count; |
1492 | } | 1491 | } |
1493 | 1492 | ||
1494 | return of_register_driver(&zs_driver, &of_bus_type); | 1493 | err = of_register_driver(&zs_driver, &of_bus_type); |
1494 | if (err) | ||
1495 | goto out_unregister_uart; | ||
1496 | |||
1497 | if (zilog_irq != -1) { | ||
1498 | err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, | ||
1499 | "zs", sunzilog_irq_chain); | ||
1500 | if (err) | ||
1501 | goto out_unregister_driver; | ||
1502 | } | ||
1503 | |||
1504 | out: | ||
1505 | return err; | ||
1506 | |||
1507 | out_unregister_driver: | ||
1508 | of_unregister_driver(&zs_driver); | ||
1509 | |||
1510 | out_unregister_uart: | ||
1511 | if (NUM_SUNZILOG) { | ||
1512 | uart_unregister_driver(&sunzilog_reg); | ||
1513 | sunzilog_reg.cons = NULL; | ||
1514 | } | ||
1515 | |||
1516 | out_free_tables: | ||
1517 | sunzilog_free_tables(); | ||
1518 | goto out; | ||
1495 | } | 1519 | } |
1496 | 1520 | ||
1497 | static void __exit sunzilog_exit(void) | 1521 | static void __exit sunzilog_exit(void) |