* Transition Power
* ----------------
* In accordance with the ACPI specification first apply power (via
-- * power resources) and then evalute _PSx.
++ * power resources) and then evaluate _PSx.
*/
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
if (error)
return error;
+++ if (adev->wakeup.flags.enabled)
+++ return 0;
+++
res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
--- if (ACPI_FAILURE(res)) {
+++ if (ACPI_SUCCESS(res)) {
+++ adev->wakeup.flags.enabled = 1;
+++ } else {
acpi_disable_wakeup_device_power(adev);
return -EIO;
}
} else {
--- acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
+++ if (adev->wakeup.flags.enabled) {
+++ acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
+++ adev->wakeup.flags.enabled = 0;
+++ }
acpi_disable_wakeup_device_power(adev);
}
return 0;
}
---#ifdef CONFIG_PM_RUNTIME
/**
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable the platform to wake up.
return acpi_device_wakeup(adev, ACPI_STATE_S0, enable);
}
EXPORT_SYMBOL(acpi_pm_device_run_wake);
---#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
acpi_device_set_power(adev, ACPI_STATE_D0) : 0;
}
---#ifdef CONFIG_PM_RUNTIME
/**
* acpi_dev_runtime_suspend - Put device into a low-power state using ACPI.
* @dev: Device to put into a low-power state.
return ret ? ret : pm_generic_runtime_resume(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
---#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
static struct dev_pm_domain acpi_general_pm_domain = {
.ops = {
---#ifdef CONFIG_PM_RUNTIME
+++#ifdef CONFIG_PM
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
---#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
.poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
+++#endif
#endif
},
};
static const char *dummy_hid = "device";
++static LIST_HEAD(acpi_dep_list);
++static DEFINE_MUTEX(acpi_dep_list_lock);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
LIST_HEAD(acpi_wakeup_device_list);
static DEFINE_MUTEX(acpi_hp_context_lock);
++struct acpi_dep_data {
++ struct list_head node;
++ acpi_handle master;
++ acpi_handle slave;
++};
++
struct acpi_device_bus_id{
char bus_id[15];
unsigned int instance_no;
if (list_empty(&acpi_dev->pnp.ids))
return 0;
--- len = snprintf(modalias, size, "acpi:");
--- size -= len;
---
--- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
--- count = snprintf(&modalias[len], size, "%s:", id->id);
--- if (count < 0)
--- return -EINVAL;
--- if (count >= size)
--- return -ENOMEM;
--- len += count;
--- size -= count;
+++ /*
+++ * If the device has PRP0001 we expose DT compatible modalias
+++ * instead in form of of:NnameTCcompatible.
+++ */
+++ if (acpi_dev->data.of_compatible) {
+++ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+++ const union acpi_object *of_compatible, *obj;
+++ int i, nval;
+++ char *c;
+++
+++ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+++ /* DT strings are all in lower case */
+++ for (c = buf.pointer; *c != '\0'; c++)
+++ *c = tolower(*c);
+++
+++ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+++ ACPI_FREE(buf.pointer);
+++
+++ of_compatible = acpi_dev->data.of_compatible;
+++ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+++ nval = of_compatible->package.count;
+++ obj = of_compatible->package.elements;
+++ } else { /* Must be ACPI_TYPE_STRING. */
+++ nval = 1;
+++ obj = of_compatible;
+++ }
+++ for (i = 0; i < nval; i++, obj++) {
+++ count = snprintf(&modalias[len], size, "C%s",
+++ obj->string.pointer);
+++ if (count < 0)
+++ return -EINVAL;
+++ if (count >= size)
+++ return -ENOMEM;
+++
+++ len += count;
+++ size -= count;
+++ }
+++ } else {
+++ len = snprintf(modalias, size, "acpi:");
+++ size -= len;
+++
+++ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+++ count = snprintf(&modalias[len], size, "%s:", id->id);
+++ if (count < 0)
+++ return -EINVAL;
+++ if (count >= size)
+++ return -ENOMEM;
+++ len += count;
+++ size -= count;
+++ }
}
modalias[len] = '\0';
}
EXPORT_SYMBOL(acpi_match_device_ids);
+++/* Performs match against special "PRP0001" shoehorn ACPI ID */
+++static bool acpi_of_driver_match_device(struct device *dev,
+++ const struct device_driver *drv)
+++{
+++ const union acpi_object *of_compatible, *obj;
+++ struct acpi_device *adev;
+++ int i, nval;
+++
+++ adev = ACPI_COMPANION(dev);
+++ if (!adev)
+++ return false;
+++
+++ of_compatible = adev->data.of_compatible;
+++ if (!drv->of_match_table || !of_compatible)
+++ return false;
+++
+++ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+++ nval = of_compatible->package.count;
+++ obj = of_compatible->package.elements;
+++ } else { /* Must be ACPI_TYPE_STRING. */
+++ nval = 1;
+++ obj = of_compatible;
+++ }
+++ /* Now we can look for the driver DT compatible strings */
+++ for (i = 0; i < nval; i++, obj++) {
+++ const struct of_device_id *id;
+++
+++ for (id = drv->of_match_table; id->compatible[0]; id++)
+++ if (!strcasecmp(obj->string.pointer, id->compatible))
+++ return true;
+++ }
+++
+++ return false;
+++}
+++
+++bool acpi_driver_match_device(struct device *dev,
+++ const struct device_driver *drv)
+++{
+++ if (!drv->acpi_match_table)
+++ return acpi_of_driver_match_device(dev, drv);
+++
+++ return !!acpi_match_device(drv->acpi_match_table, dev);
+++}
+++EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+++
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+++ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
return result;
}
+++struct acpi_device *acpi_get_next_child(struct device *dev,
+++ struct acpi_device *child)
+++{
+++ struct acpi_device *adev = ACPI_COMPANION(dev);
+++ struct list_head *head, *next;
+++
+++ if (!adev)
+++ return NULL;
+++
+++ head = &adev->children;
+++ if (list_empty(head))
+++ return NULL;
+++
+++ if (!child)
+++ return list_first_entry(head, struct acpi_device, node);
+++
+++ next = child->node.next;
+++ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+++}
+++
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+++ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+++ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
}
}
- dev_err(&adev->dev, "Failed to evaluate _DEP.\n");
++static void acpi_device_dep_initialize(struct acpi_device *adev)
++{
++ struct acpi_dep_data *dep;
++ struct acpi_handle_list dep_devices;
++ acpi_status status;
++ int i;
++
++ if (!acpi_has_method(adev->handle, "_DEP"))
++ return;
++
++ status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
++ &dep_devices);
++ if (ACPI_FAILURE(status)) {
- dev_err(&adev->dev, "Error reading device info\n");
+ ++ dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
++ return;
++ }
++
++ for (i = 0; i < dep_devices.count; i++) {
++ struct acpi_device_info *info;
++ int skip;
++
++ status = acpi_get_object_info(dep_devices.handles[i], &info);
++ if (ACPI_FAILURE(status)) {
+ ++ dev_dbg(&adev->dev, "Error reading _DEP device info\n");
++ continue;
++ }
++
++ /*
++ * Skip the dependency of Windows System Power
++ * Management Controller
++ */
++ skip = info->valid & ACPI_VALID_HID &&
++ !strcmp(info->hardware_id.string, "INT3396");
++
++ kfree(info);
++
++ if (skip)
++ continue;
++
++ dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
++ if (!dep)
++ return;
++
++ dep->master = dep_devices.handles[i];
++ dep->slave = adev->handle;
++ adev->dep_unmet++;
++
++ mutex_lock(&acpi_dep_list_lock);
++ list_add_tail(&dep->node , &acpi_dep_list);
++ mutex_unlock(&acpi_dep_list_lock);
++ }
++}
++
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
return AE_CTRL_DEPTH;
acpi_scan_init_hotplug(device);
++ acpi_device_dep_initialize(device);
out:
if (!*return_value)
device->handler->hotplug.notify_online(device);
}
++void acpi_walk_dep_device_list(acpi_handle handle)
++{
++ struct acpi_dep_data *dep, *tmp;
++ struct acpi_device *adev;
++
++ mutex_lock(&acpi_dep_list_lock);
++ list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
++ if (dep->master == handle) {
++ acpi_bus_get_device(dep->slave, &adev);
++ if (!adev)
++ continue;
++
++ adev->dep_unmet--;
++ if (!adev->dep_unmet)
++ acpi_bus_attach(adev);
++ list_del(&dep->node);
++ kfree(dep);
++ }
++ }
++ mutex_unlock(&acpi_dep_list_lock);
++}
++EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
++
/**
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
* @handle: Root of the namespace scope to scan.
break;
case 'B':
size_required +=
--- sizeof(u8 *) +
--- (element->buffer.length * sizeof(u8));
+++ sizeof(u8 *) + element->buffer.length;
tail_offset += sizeof(u8 *);
break;
default:
memcpy(tail, element->buffer.pointer,
element->buffer.length);
head += sizeof(u8 *);
--- tail += element->buffer.length * sizeof(u8);
+++ tail += element->buffer.length;
break;
default:
/* Should never get here */
package = buffer.pointer;
if ((buffer.length == 0) || !package) {
-- - printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
-- - (unsigned)buffer.length, package);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
}
if (package->type != ACPI_TYPE_PACKAGE) {
-- - printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n",
-- - package->type);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
}
if (!package->package.count) {
-- - printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n",
-- - package);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA;
-- - printk(KERN_ERR PREFIX
-- - "Expecting a [Reference] package element, found type %X\n",
-- - element->type);
acpi_util_eval_error(handle, pathname, status);
break;
}
if (!element->reference.handle) {
-- - printk(KERN_WARNING PREFIX "Invalid reference in"
-- - " package %s\n", pathname);
status = AE_NULL_ENTRY;
++ + acpi_util_eval_error(handle, pathname, status);
break;
}
/* Get the acpi_handle. */
#define __ACPI_BUS_H__
#include <linux/device.h>
+++#include <linux/property.h>
/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
u8 valid:1; /* Can successfully enable wakeup? */
u8 run_wake:1; /* Run-Wake GPE devices */
u8 notifier_present:1; /* Wake-up notify handler has been installed */
+++ u8 enabled:1; /* Enabled for wakeup */
};
struct acpi_device_wakeup_context {
bool put_online:1;
};
+++/* ACPI Device Specific Data (_DSD) */
+++struct acpi_device_data {
+++ const union acpi_object *pointer;
+++ const union acpi_object *properties;
+++ const union acpi_object *of_compatible;
+++};
+++
+++struct acpi_gpio_mapping;
+++
/* Device */
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+++ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+++ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
+++ const struct acpi_gpio_mapping *driver_gpios;
void *driver_data;
struct device dev;
unsigned int physical_node_count;
++ unsigned int dep_unmet;
struct list_head physical_node_list;
struct mutex physical_node_lock;
void (*remove)(struct acpi_device *);
};
+++static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+++{
+++ return fwnode && fwnode->type == FWNODE_ACPI;
+++}
+++
+++static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+++{
+++ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+++}
+++
+++static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+++{
+++ return &adev->fwnode;
+++}
+++
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
void (*work_func)(struct work_struct *work));
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
+++int acpi_pm_device_run_wake(struct device *, bool);
#else
static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
struct device *dev,
return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
m : ACPI_STATE_D0;
}
---#endif
---
---#ifdef CONFIG_PM_RUNTIME
---int acpi_pm_device_run_wake(struct device *, bool);
---#else
static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
{
return -ENODEV;