aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r--drivers/acpi/scan.c60
1 files changed, 53 insertions, 7 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fe9f2c926663..1453cd0672fb 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -53,6 +53,7 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
53static LIST_HEAD(acpi_device_list); 53static LIST_HEAD(acpi_device_list);
54static LIST_HEAD(acpi_bus_id_list); 54static LIST_HEAD(acpi_bus_id_list);
55static DEFINE_MUTEX(acpi_scan_lock); 55static DEFINE_MUTEX(acpi_scan_lock);
56static LIST_HEAD(acpi_scan_handlers_list);
56DEFINE_MUTEX(acpi_device_lock); 57DEFINE_MUTEX(acpi_device_lock);
57LIST_HEAD(acpi_wakeup_device_list); 58LIST_HEAD(acpi_wakeup_device_list);
58 59
@@ -62,6 +63,15 @@ struct acpi_device_bus_id{
62 struct list_head node; 63 struct list_head node;
63}; 64};
64 65
66int acpi_scan_add_handler(struct acpi_scan_handler *handler)
67{
68 if (!handler || !handler->attach)
69 return -EINVAL;
70
71 list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
72 return 0;
73}
74
65/* 75/*
66 * Creates hid/cid(s) string needed for modalias and uevent 76 * Creates hid/cid(s) string needed for modalias and uevent
67 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: 77 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -1570,20 +1580,42 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
1570 return AE_OK; 1580 return AE_OK;
1571} 1581}
1572 1582
1583static int acpi_scan_attach_handler(struct acpi_device *device)
1584{
1585 struct acpi_scan_handler *handler;
1586 int ret = 0;
1587
1588 list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
1589 const struct acpi_device_id *id;
1590
1591 id = __acpi_match_device(device, handler->ids);
1592 if (!id)
1593 continue;
1594
1595 ret = handler->attach(device, id);
1596 if (ret > 0) {
1597 device->handler = handler;
1598 break;
1599 } else if (ret < 0) {
1600 break;
1601 }
1602 }
1603 return ret;
1604}
1605
1573static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, 1606static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
1574 void *not_used, void **ret_not_used) 1607 void *not_used, void **ret_not_used)
1575{ 1608{
1576 const struct acpi_device_id *id; 1609 const struct acpi_device_id *id;
1577 acpi_status status = AE_OK;
1578 struct acpi_device *device; 1610 struct acpi_device *device;
1579 unsigned long long sta_not_used; 1611 unsigned long long sta_not_used;
1580 int type_not_used; 1612 int ret;
1581 1613
1582 /* 1614 /*
1583 * Ignore errors ignored by acpi_bus_check_add() to avoid terminating 1615 * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
1584 * namespace walks prematurely. 1616 * namespace walks prematurely.
1585 */ 1617 */
1586 if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used)) 1618 if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
1587 return AE_OK; 1619 return AE_OK;
1588 1620
1589 if (acpi_bus_get_device(handle, &device)) 1621 if (acpi_bus_get_device(handle, &device))
@@ -1593,10 +1625,15 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
1593 if (id) { 1625 if (id) {
1594 /* This is a known good platform device. */ 1626 /* This is a known good platform device. */
1595 acpi_create_platform_device(device, id->driver_data); 1627 acpi_create_platform_device(device, id->driver_data);
1596 } else if (device_attach(&device->dev) < 0) { 1628 return AE_OK;
1597 status = AE_CTRL_DEPTH;
1598 } 1629 }
1599 return status; 1630
1631 ret = acpi_scan_attach_handler(device);
1632 if (ret)
1633 return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
1634
1635 ret = device_attach(&device->dev);
1636 return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
1600} 1637}
1601 1638
1602/** 1639/**
@@ -1639,8 +1676,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
1639 struct acpi_device *device = NULL; 1676 struct acpi_device *device = NULL;
1640 1677
1641 if (!acpi_bus_get_device(handle, &device)) { 1678 if (!acpi_bus_get_device(handle, &device)) {
1679 struct acpi_scan_handler *dev_handler = device->handler;
1680
1642 device->removal_type = ACPI_BUS_REMOVAL_EJECT; 1681 device->removal_type = ACPI_BUS_REMOVAL_EJECT;
1643 device_release_driver(&device->dev); 1682 if (dev_handler) {
1683 if (dev_handler->detach)
1684 dev_handler->detach(device);
1685
1686 device->handler = NULL;
1687 } else {
1688 device_release_driver(&device->dev);
1689 }
1644 } 1690 }
1645 return AE_OK; 1691 return AE_OK;
1646} 1692}