diff options
author | Bjorn Helgaas <bjorn.helgaas@hp.com> | 2009-09-21 15:29:56 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-09-25 14:24:30 -0400 |
commit | 51a85faf2d4ffecd8384b3f501f9f7ee2b05ee53 (patch) | |
tree | 6ca93c9b1a14da2fb140a74f3f3b23976b5ecd0b /drivers/acpi | |
parent | 859ac9a4be0c753cece0e30a2e4a65fd2cdcaeee (diff) |
ACPI: use acpi_walk_namespace() to enumerate devices
acpi_bus_scan() currently walks the namespace manually. This patch changes
it to use acpi_walk_namespace() instead.
Besides removing some complicated code, this means we take advantage of the
namespace locking done by acpi_walk_namespace(). The locking isn't so
important at boot-time, but I hope to eventually use this same path to
handle hot-addition of devices, when it will be important.
Note that acpi_walk_namespace() does not actually visit the starting node
first, so we need to do that by hand first.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/scan.c | 196 |
1 files changed, 74 insertions, 122 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0b5aaf059c9b..ed2b5f9a9815 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1393,123 +1393,92 @@ end: | |||
1393 | return result; | 1393 | return result; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops) | 1396 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, |
1397 | void *context, void **return_value) | ||
1397 | { | 1398 | { |
1398 | acpi_status status = AE_OK; | 1399 | acpi_status status = AE_OK; |
1399 | struct acpi_device *parent = NULL; | 1400 | struct acpi_device *device = NULL; |
1400 | struct acpi_device *child = NULL; | ||
1401 | acpi_handle phandle = NULL; | ||
1402 | acpi_handle chandle = NULL; | ||
1403 | acpi_object_type type = 0; | 1401 | acpi_object_type type = 0; |
1404 | u32 level = 1; | 1402 | struct acpi_bus_ops *ops = context; |
1405 | int ret; | ||
1406 | 1403 | ||
1407 | /* | 1404 | status = acpi_get_type(handle, &type); |
1408 | * We must have an acpi_device for the starting node already, and | 1405 | if (ACPI_FAILURE(status)) |
1409 | * we scan its children. | 1406 | return AE_OK; |
1410 | */ | ||
1411 | phandle = handle; | ||
1412 | ret = acpi_bus_get_device(phandle, &parent); | ||
1413 | if (ret) | ||
1414 | return ret; | ||
1415 | 1407 | ||
1416 | /* | 1408 | /* |
1417 | * Parse through the ACPI namespace, identify all 'devices', and | 1409 | * We're only interested in objects that we consider 'devices'. |
1418 | * create a new 'struct acpi_device' for each. | ||
1419 | */ | 1410 | */ |
1420 | while ((level > 0) && parent) { | 1411 | switch (type) { |
1412 | case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ | ||
1413 | case ACPI_TYPE_DEVICE: | ||
1414 | type = ACPI_BUS_TYPE_DEVICE; | ||
1415 | break; | ||
1416 | case ACPI_TYPE_PROCESSOR: | ||
1417 | type = ACPI_BUS_TYPE_PROCESSOR; | ||
1418 | break; | ||
1419 | case ACPI_TYPE_THERMAL: | ||
1420 | type = ACPI_BUS_TYPE_THERMAL; | ||
1421 | break; | ||
1422 | case ACPI_TYPE_POWER: | ||
1423 | type = ACPI_BUS_TYPE_POWER; | ||
1424 | break; | ||
1425 | default: | ||
1426 | return AE_OK; | ||
1427 | } | ||
1421 | 1428 | ||
1422 | status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, | 1429 | if (ops->acpi_op_add) |
1423 | chandle, &chandle); | 1430 | status = acpi_add_single_object(&device, handle, type, ops); |
1431 | else | ||
1432 | status = acpi_bus_get_device(handle, &device); | ||
1424 | 1433 | ||
1425 | /* | 1434 | if (ACPI_FAILURE(status)) |
1426 | * If this scope is exhausted then move our way back up. | 1435 | return AE_CTRL_DEPTH; |
1427 | */ | ||
1428 | if (ACPI_FAILURE(status)) { | ||
1429 | level--; | ||
1430 | chandle = phandle; | ||
1431 | acpi_get_parent(phandle, &phandle); | ||
1432 | if (parent->parent) | ||
1433 | parent = parent->parent; | ||
1434 | continue; | ||
1435 | } | ||
1436 | 1436 | ||
1437 | status = acpi_get_type(chandle, &type); | 1437 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
1438 | status = acpi_start_single_object(device); | ||
1438 | if (ACPI_FAILURE(status)) | 1439 | if (ACPI_FAILURE(status)) |
1439 | continue; | 1440 | return AE_CTRL_DEPTH; |
1440 | 1441 | } | |
1441 | /* | ||
1442 | * If this is a scope object then parse it (depth-first). | ||
1443 | */ | ||
1444 | if (type == ACPI_TYPE_LOCAL_SCOPE) { | ||
1445 | level++; | ||
1446 | phandle = chandle; | ||
1447 | chandle = NULL; | ||
1448 | continue; | ||
1449 | } | ||
1450 | 1442 | ||
1451 | /* | 1443 | /* |
1452 | * We're only interested in objects that we consider 'devices'. | 1444 | * If the device is present, enabled, and functioning then |
1453 | */ | 1445 | * parse its scope (depth-first). Note that we need to |
1454 | switch (type) { | 1446 | * represent absent devices to facilitate PnP notifications |
1455 | case ACPI_TYPE_DEVICE: | 1447 | * -- but only the subtree head (not all of its children, |
1456 | type = ACPI_BUS_TYPE_DEVICE; | 1448 | * which will be enumerated when the parent is inserted). |
1457 | break; | 1449 | * |
1458 | case ACPI_TYPE_PROCESSOR: | 1450 | * TBD: Need notifications and other detection mechanisms |
1459 | type = ACPI_BUS_TYPE_PROCESSOR; | 1451 | * in place before we can fully implement this. |
1460 | break; | 1452 | * |
1461 | case ACPI_TYPE_THERMAL: | 1453 | * When the device is not present but functional, it is also |
1462 | type = ACPI_BUS_TYPE_THERMAL; | 1454 | * necessary to scan the children of this device. |
1463 | break; | 1455 | */ |
1464 | case ACPI_TYPE_POWER: | 1456 | if (!device->status.present && !device->status.functional) |
1465 | type = ACPI_BUS_TYPE_POWER; | 1457 | return AE_CTRL_DEPTH; |
1466 | break; | ||
1467 | default: | ||
1468 | continue; | ||
1469 | } | ||
1470 | 1458 | ||
1471 | if (ops->acpi_op_add) | 1459 | if (!*return_value) |
1472 | status = acpi_add_single_object(&child, chandle, type, | 1460 | *return_value = device; |
1473 | ops); | 1461 | return AE_OK; |
1474 | else | 1462 | } |
1475 | status = acpi_bus_get_device(chandle, &child); | ||
1476 | 1463 | ||
1477 | if (ACPI_FAILURE(status)) | 1464 | static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, |
1478 | continue; | 1465 | struct acpi_device **child) |
1466 | { | ||
1467 | acpi_status status; | ||
1468 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1469 | void *device = NULL; | ||
1479 | 1470 | ||
1480 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { | 1471 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
1481 | status = acpi_start_single_object(child); | 1472 | printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n", |
1482 | if (ACPI_FAILURE(status)) | 1473 | (char *) buffer.pointer); |
1483 | continue; | ||
1484 | } | ||
1485 | 1474 | ||
1486 | /* | 1475 | status = acpi_bus_check_add(handle, 0, ops, &device); |
1487 | * If the device is present, enabled, and functioning then | 1476 | if (ACPI_SUCCESS(status)) |
1488 | * parse its scope (depth-first). Note that we need to | 1477 | acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
1489 | * represent absent devices to facilitate PnP notifications | 1478 | acpi_bus_check_add, ops, &device); |
1490 | * -- but only the subtree head (not all of its children, | ||
1491 | * which will be enumerated when the parent is inserted). | ||
1492 | * | ||
1493 | * TBD: Need notifications and other detection mechanisms | ||
1494 | * in place before we can fully implement this. | ||
1495 | */ | ||
1496 | /* | ||
1497 | * When the device is not present but functional, it is also | ||
1498 | * necessary to scan the children of this device. | ||
1499 | */ | ||
1500 | if (child->status.present || (!child->status.present && | ||
1501 | child->status.functional)) { | ||
1502 | status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, | ||
1503 | NULL, NULL); | ||
1504 | if (ACPI_SUCCESS(status)) { | ||
1505 | level++; | ||
1506 | phandle = chandle; | ||
1507 | chandle = NULL; | ||
1508 | parent = child; | ||
1509 | } | ||
1510 | } | ||
1511 | } | ||
1512 | 1479 | ||
1480 | if (child) | ||
1481 | *child = device; | ||
1513 | return 0; | 1482 | return 0; |
1514 | } | 1483 | } |
1515 | 1484 | ||
@@ -1517,33 +1486,25 @@ int | |||
1517 | acpi_bus_add(struct acpi_device **child, | 1486 | acpi_bus_add(struct acpi_device **child, |
1518 | struct acpi_device *parent, acpi_handle handle, int type) | 1487 | struct acpi_device *parent, acpi_handle handle, int type) |
1519 | { | 1488 | { |
1520 | int result; | ||
1521 | struct acpi_bus_ops ops; | 1489 | struct acpi_bus_ops ops; |
1522 | 1490 | ||
1523 | memset(&ops, 0, sizeof(ops)); | 1491 | memset(&ops, 0, sizeof(ops)); |
1524 | ops.acpi_op_add = 1; | 1492 | ops.acpi_op_add = 1; |
1525 | 1493 | ||
1526 | result = acpi_add_single_object(child, handle, type, &ops); | 1494 | acpi_bus_scan(handle, &ops, child); |
1527 | if (!result) | 1495 | return 0; |
1528 | result = acpi_bus_scan((*child)->handle, &ops); | ||
1529 | |||
1530 | return result; | ||
1531 | } | 1496 | } |
1532 | EXPORT_SYMBOL(acpi_bus_add); | 1497 | EXPORT_SYMBOL(acpi_bus_add); |
1533 | 1498 | ||
1534 | int acpi_bus_start(struct acpi_device *device) | 1499 | int acpi_bus_start(struct acpi_device *device) |
1535 | { | 1500 | { |
1536 | int result; | ||
1537 | struct acpi_bus_ops ops; | 1501 | struct acpi_bus_ops ops; |
1538 | 1502 | ||
1539 | memset(&ops, 0, sizeof(ops)); | 1503 | memset(&ops, 0, sizeof(ops)); |
1540 | ops.acpi_op_start = 1; | 1504 | ops.acpi_op_start = 1; |
1541 | 1505 | ||
1542 | result = acpi_start_single_object(device); | 1506 | acpi_bus_scan(device->handle, &ops, NULL); |
1543 | if (!result) | 1507 | return 0; |
1544 | result = acpi_bus_scan(device->handle, &ops); | ||
1545 | |||
1546 | return result; | ||
1547 | } | 1508 | } |
1548 | EXPORT_SYMBOL(acpi_bus_start); | 1509 | EXPORT_SYMBOL(acpi_bus_start); |
1549 | 1510 | ||
@@ -1646,17 +1607,9 @@ int __init acpi_scan_init(void) | |||
1646 | } | 1607 | } |
1647 | 1608 | ||
1648 | /* | 1609 | /* |
1649 | * Create the root device in the bus's device tree | ||
1650 | */ | ||
1651 | result = acpi_add_single_object(&acpi_root, ACPI_ROOT_OBJECT, | ||
1652 | ACPI_BUS_TYPE_DEVICE, &ops); | ||
1653 | if (result) | ||
1654 | goto Done; | ||
1655 | |||
1656 | /* | ||
1657 | * Enumerate devices in the ACPI namespace. | 1610 | * Enumerate devices in the ACPI namespace. |
1658 | */ | 1611 | */ |
1659 | result = acpi_bus_scan(acpi_root->handle, &ops); | 1612 | result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); |
1660 | 1613 | ||
1661 | if (!result) | 1614 | if (!result) |
1662 | result = acpi_bus_scan_fixed(); | 1615 | result = acpi_bus_scan_fixed(); |
@@ -1664,6 +1617,5 @@ int __init acpi_scan_init(void) | |||
1664 | if (result) | 1617 | if (result) |
1665 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); | 1618 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); |
1666 | 1619 | ||
1667 | Done: | ||
1668 | return result; | 1620 | return result; |
1669 | } | 1621 | } |