aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/scan.c103
-rw-r--r--include/acpi/acpi_bus.h1
2 files changed, 73 insertions, 31 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 53502d1bbf26..726f0d1ace4b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -494,7 +494,8 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
494 struct acpi_device *acpi_dev = to_acpi_device(dev); 494 struct acpi_device *acpi_dev = to_acpi_device(dev);
495 struct acpi_driver *acpi_drv = to_acpi_driver(drv); 495 struct acpi_driver *acpi_drv = to_acpi_driver(drv);
496 496
497 return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); 497 return acpi_dev->bus_ops.acpi_op_match
498 && !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
498} 499}
499 500
500static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) 501static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -1418,6 +1419,17 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
1418 return 0; 1419 return 0;
1419} 1420}
1420 1421
1422/*
1423 * acpi_hot_add_bind - Bind _ADR-based devices on hot-add.
1424 * @device: ACPI device node to bind.
1425 */
1426static void acpi_hot_add_bind(struct acpi_device *device)
1427{
1428 if (device->flags.bus_address
1429 && device->parent && device->parent->ops.bind)
1430 device->parent->ops.bind(device);
1431}
1432
1421static int acpi_add_single_object(struct acpi_device **child, 1433static int acpi_add_single_object(struct acpi_device **child,
1422 acpi_handle handle, int type, 1434 acpi_handle handle, int type,
1423 unsigned long long sta, 1435 unsigned long long sta,
@@ -1490,13 +1502,8 @@ static int acpi_add_single_object(struct acpi_device **child,
1490 1502
1491 result = acpi_device_register(device); 1503 result = acpi_device_register(device);
1492 1504
1493 /* 1505 if (device->bus_ops.acpi_op_match)
1494 * Bind _ADR-Based Devices when hot add 1506 acpi_hot_add_bind(device);
1495 */
1496 if (device->flags.bus_address) {
1497 if (device->parent && device->parent->ops.bind)
1498 device->parent->ops.bind(device);
1499 }
1500 1507
1501end: 1508end:
1502 if (!result) { 1509 if (!result) {
@@ -1522,6 +1529,7 @@ static void acpi_bus_add_power_resource(acpi_handle handle)
1522 struct acpi_bus_ops ops = { 1529 struct acpi_bus_ops ops = {
1523 .acpi_op_add = 1, 1530 .acpi_op_add = 1,
1524 .acpi_op_start = 1, 1531 .acpi_op_start = 1,
1532 .acpi_op_match = 1,
1525 }; 1533 };
1526 struct acpi_device *device = NULL; 1534 struct acpi_device *device = NULL;
1527 1535
@@ -1574,9 +1582,9 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
1574 void *context, void **return_value) 1582 void *context, void **return_value)
1575{ 1583{
1576 struct acpi_bus_ops *ops = context; 1584 struct acpi_bus_ops *ops = context;
1585 struct acpi_device *device = NULL;
1577 int type; 1586 int type;
1578 unsigned long long sta; 1587 unsigned long long sta;
1579 struct acpi_device *device;
1580 acpi_status status; 1588 acpi_status status;
1581 int result; 1589 int result;
1582 1590
@@ -1596,52 +1604,84 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
1596 return AE_CTRL_DEPTH; 1604 return AE_CTRL_DEPTH;
1597 } 1605 }
1598 1606
1599 /*
1600 * We may already have an acpi_device from a previous enumeration. If
1601 * so, we needn't add it again, but we may still have to start it.
1602 */
1603 device = NULL;
1604 acpi_bus_get_device(handle, &device); 1607 acpi_bus_get_device(handle, &device);
1605 if (ops->acpi_op_add && !device) { 1608 if (ops->acpi_op_add && !device) {
1606 acpi_add_single_object(&device, handle, type, sta, ops); 1609 struct acpi_bus_ops add_ops = *ops;
1607 /* Is the device a known good platform device? */
1608 if (device
1609 && !acpi_match_device_ids(device, acpi_platform_device_ids))
1610 acpi_create_platform_device(device);
1611 }
1612 1610
1613 if (!device) 1611 add_ops.acpi_op_match = 0;
1614 return AE_CTRL_DEPTH; 1612 acpi_add_single_object(&device, handle, type, sta, &add_ops);
1615 1613 if (!device)
1616 if (ops->acpi_op_start && !(ops->acpi_op_add)) {
1617 status = acpi_start_single_object(device);
1618 if (ACPI_FAILURE(status))
1619 return AE_CTRL_DEPTH; 1614 return AE_CTRL_DEPTH;
1615
1616 device->bus_ops.acpi_op_match = 1;
1617 acpi_hot_add_bind(device);
1620 } 1618 }
1621 1619
1622 if (!*return_value) 1620 if (!*return_value)
1623 *return_value = device; 1621 *return_value = device;
1622
1624 return AE_OK; 1623 return AE_OK;
1625} 1624}
1626 1625
1626static acpi_status acpi_bus_probe_start(acpi_handle handle, u32 lvl,
1627 void *context, void **not_used)
1628{
1629 struct acpi_bus_ops *ops = context;
1630 acpi_status status = AE_OK;
1631 struct acpi_device *device;
1632 unsigned long long sta_not_used;
1633 int type_not_used;
1634
1635 /*
1636 * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
1637 * namespace walks prematurely.
1638 */
1639 if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used))
1640 return AE_OK;
1641
1642 if (acpi_bus_get_device(handle, &device))
1643 return AE_CTRL_DEPTH;
1644
1645 if (ops->acpi_op_add) {
1646 if (!acpi_match_device_ids(device, acpi_platform_device_ids)) {
1647 /* This is a known good platform device. */
1648 acpi_create_platform_device(device);
1649 } else if (device_attach(&device->dev)) {
1650 status = AE_CTRL_DEPTH;
1651 }
1652 } else if (ops->acpi_op_start) {
1653 if (ACPI_FAILURE(acpi_start_single_object(device)))
1654 status = AE_CTRL_DEPTH;
1655 }
1656 return status;
1657}
1658
1627static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, 1659static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
1628 struct acpi_device **child) 1660 struct acpi_device **child)
1629{ 1661{
1630 acpi_status status;
1631 void *device = NULL; 1662 void *device = NULL;
1663 acpi_status status;
1664 int ret = -ENODEV;
1632 1665
1633 status = acpi_bus_check_add(handle, 0, ops, &device); 1666 status = acpi_bus_check_add(handle, 0, ops, &device);
1634 if (ACPI_SUCCESS(status)) 1667 if (ACPI_SUCCESS(status))
1635 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, 1668 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
1636 acpi_bus_check_add, NULL, ops, &device); 1669 acpi_bus_check_add, NULL, ops, &device);
1637 1670
1671 if (!device)
1672 goto out;
1673
1674 ret = 0;
1675 status = acpi_bus_probe_start(handle, 0, ops, NULL);
1676 if (ACPI_SUCCESS(status))
1677 acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
1678 acpi_bus_probe_start, NULL, ops, NULL);
1679
1680 out:
1638 if (child) 1681 if (child)
1639 *child = device; 1682 *child = device;
1640 1683
1641 if (device) 1684 return ret;
1642 return 0;
1643 else
1644 return -ENODEV;
1645} 1685}
1646 1686
1647/* 1687/*
@@ -1752,6 +1792,7 @@ static int acpi_bus_scan_fixed(void)
1752 memset(&ops, 0, sizeof(ops)); 1792 memset(&ops, 0, sizeof(ops));
1753 ops.acpi_op_add = 1; 1793 ops.acpi_op_add = 1;
1754 ops.acpi_op_start = 1; 1794 ops.acpi_op_start = 1;
1795 ops.acpi_op_match = 1;
1755 1796
1756 /* 1797 /*
1757 * Enumerate all fixed-feature devices. 1798 * Enumerate all fixed-feature devices.
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 7ced5dc20dd3..016918c16c98 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -98,6 +98,7 @@ typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
98struct acpi_bus_ops { 98struct acpi_bus_ops {
99 u32 acpi_op_add:1; 99 u32 acpi_op_add:1;
100 u32 acpi_op_start:1; 100 u32 acpi_op_start:1;
101 u32 acpi_op_match:1;
101}; 102};
102 103
103struct acpi_device_ops { 104struct acpi_device_ops {