Power management and ACPI updates for 3.10-rc1

- ARM big.LITTLE cpufreq driver from Viresh Kumar.
 
 - exynos5440 cpufreq driver from Amit Daniel Kachhap.
 
 - cpufreq core cleanup and code consolidation from Viresh Kumar and
   Stratos Karafotis.
 
 - cpufreq scalability improvement from Nathan Zimmer.
 
 - AMD "frequency sensitivity feedback" powersave bias for the ondemand
   cpufreq governor from Jacob Shin.
 
 - cpuidle code consolidation and cleanups from Daniel Lezcano.
 
 - ARM OMAP cpuidle fixes from Santosh Shilimkar and Daniel Lezcano.
 
 - ACPICA fixes and other improvements from Bob Moore, Jung-uk Kim,
   Lv Zheng, Yinghai Lu, Tang Chen, Colin Ian King, and Linn Crosetto.
 
 - ACPI core updates related to hotplug from Toshi Kani, Paul Bolle,
   Yasuaki Ishimatsu, and Rafael J. Wysocki.
 
 - Intel Lynxpoint LPSS (Low-Power Subsystem) support improvements
   from Rafael J. Wysocki and Andy Shevchenko.
 
 /
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJRf8M8AAoJEKhOf7ml8uNsud4P/3cabXP5lDipzibRrpOiONse
 puuvIdhtNdMRMc3t1oSDjNH/w/JA51Gc+ICGFAORiyVmqxBc85mpT6J5ibqV7hNd
 pCqbKJceoB5PajHZSx22e4wG9O7YN1k3r80p38IfFzA+Ct0KNSuE0ixMEfHKYjiq
 p5pXswk6TY3gtBReH9agrafHqDtXw4IMTE0asMuJ+BorPW7vQeiNlrkuA+0qmDuu
 26O0Pm2TVkx1ryfTjdM9zSZ9X2G4JuM8rm1/VFZWQJTExwlv3bA2Za1nvQNJlJ99
 6JZ0JXfAehcEW2Ye0sqsZ8HSEabDVHM29QvvOszJ5RpBXERiOCHOkhvFleCoTpn0
 Xq0rtXPrLMH1G28Ej+cxmsAjfzOLV2Byg30CAoI/GCLuQ+xh+VMCpuNYQuld25CG
 9rtYd0fWESeYsAebhDcX0E3xyzJtbrHtOb9PyGwNkbAJ8YQfhVSMCOPi2SX2wa+Q
 qXLXi2VaHvjBSUKcAv5BmM+Ya57Be+88D0LxbgXbUeOnYefUK1ljldKDDshkMjgG
 P4LPdm4JpoB5ncXSOO1Dz9w9QnNcFexSUySd/TtKLNMha1vEHV8ISzNPYY+9IdXf
 XN0VZbFnUDzdj+Fwna7zyFb1cGihDYJKAtpXvRd8Y6RGUxKx9uGLAFJZw/xZB/cR
 KZKuML5O8MgJuef37F38
 =H/se
 -----END PGP SIGNATURE-----

Merge tag 'pm+acpi-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management and ACPI updates from Rafael J Wysocki:

 - ARM big.LITTLE cpufreq driver from Viresh Kumar.

 - exynos5440 cpufreq driver from Amit Daniel Kachhap.

 - cpufreq core cleanup and code consolidation from Viresh Kumar and
   Stratos Karafotis.

 - cpufreq scalability improvement from Nathan Zimmer.

 - AMD "frequency sensitivity feedback" powersave bias for the ondemand
   cpufreq governor from Jacob Shin.

 - cpuidle code consolidation and cleanups from Daniel Lezcano.

 - ARM OMAP cpuidle fixes from Santosh Shilimkar and Daniel Lezcano.

 - ACPICA fixes and other improvements from Bob Moore, Jung-uk Kim, Lv
   Zheng, Yinghai Lu, Tang Chen, Colin Ian King, and Linn Crosetto.

 - ACPI core updates related to hotplug from Toshi Kani, Paul Bolle,
   Yasuaki Ishimatsu, and Rafael J Wysocki.

 - Intel Lynxpoint LPSS (Low-Power Subsystem) support improvements from
   Rafael J Wysocki and Andy Shevchenko.

* tag 'pm+acpi-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (192 commits)
  cpufreq: Revert incorrect commit 5800043
  cpufreq: MAINTAINERS: Add co-maintainer
  cpuidle: add maintainer entry
  ACPI / thermal: do not always return THERMAL_TREND_RAISING for active trip points
  ARM: s3c64xx: cpuidle: use init/exit common routine
  cpufreq: pxa2xx: initialize variables
  ACPI: video: correct acpi_video_bus_add error processing
  SH: cpuidle: use init/exit common routine
  ARM: S5pv210: compiling issue, ARM_S5PV210_CPUFREQ needs CONFIG_CPU_FREQ_TABLE=y
  ACPI: Fix wrong parameter passed to memblock_reserve
  cpuidle: fix comment format
  pnp: use %*phC to dump small buffers
  isapnp: remove debug leftovers
  ARM: imx: cpuidle: use init/exit common routine
  ARM: davinci: cpuidle: use init/exit common routine
  ARM: kirkwood: cpuidle: use init/exit common routine
  ARM: calxeda: cpuidle: use init/exit common routine
  ARM: tegra: cpuidle: use init/exit common routine for tegra3
  ARM: tegra: cpuidle: use init/exit common routine for tegra2
  ARM: OMAP4: cpuidle: use init/exit common routine
  ...
This commit is contained in:
Linus Torvalds 2013-04-30 15:21:02 -07:00
commit 3ed1c478ef
253 changed files with 6938 additions and 4145 deletions

View file

@ -298,14 +298,6 @@ config ACPI_DEBUG
Documentation/kernel-parameters.txt to control the type and
amount of debug output.
config ACPI_DEBUG_FUNC_TRACE
bool "Additionally enable ACPI function tracing"
default n
depends on ACPI_DEBUG
help
ACPI Debug Statements slow down ACPI processing. Function trace
is about half of the penalty and is rarely useful.
config ACPI_PCI_SLOT
bool "PCI slot detection driver"
depends on SYSFS
@ -334,7 +326,7 @@ config X86_PM_TIMER
config ACPI_CONTAINER
bool "Container and Module Devices"
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU)
help
This driver supports ACPI Container and Module devices (IDs
ACPI0004, PNP0A05, and PNP0A06).
@ -345,9 +337,8 @@ config ACPI_CONTAINER
the module will be called container.
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
bool "Memory Hotplug"
depends on MEMORY_HOTPLUG
default n
help
This driver supports ACPI memory hotplug. The driver
fields notifications on ACPI memory devices (PNP0C80),

View file

@ -39,6 +39,7 @@ acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y += csrt.o
acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o
acpi-y += acpi_platform.o
acpi-y += power.o
acpi-y += event.o

292
drivers/acpi/acpi_lpss.c Normal file
View file

@ -0,0 +1,292 @@
/*
* ACPI support for Intel Lynxpoint LPSS.
*
* Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/pm_runtime.h>
#include "internal.h"
ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_CLK_SIZE 0x04
#define LPSS_LTR_SIZE 0x18
/* Offsets relative to LPSS_PRIVATE_OFFSET */
#define LPSS_GENERAL 0x08
#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
struct lpss_device_desc {
bool clk_required;
const char *clk_parent;
bool ltr_required;
unsigned int prv_offset;
};
struct lpss_private_data {
void __iomem *mmio_base;
resource_size_t mmio_size;
struct clk *clk;
const struct lpss_device_desc *dev_desc;
};
static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.clk_parent = "lpss_clk",
.prv_offset = 0x800,
.ltr_required = true,
};
static struct lpss_device_desc lpt_sdio_dev_desc = {
.prv_offset = 0x1000,
.ltr_required = true,
};
static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Lynxpoint LPSS devices */
{ "INT33C0", (unsigned long)&lpt_dev_desc },
{ "INT33C1", (unsigned long)&lpt_dev_desc },
{ "INT33C2", (unsigned long)&lpt_dev_desc },
{ "INT33C3", (unsigned long)&lpt_dev_desc },
{ "INT33C4", (unsigned long)&lpt_dev_desc },
{ "INT33C5", (unsigned long)&lpt_dev_desc },
{ "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
{ "INT33C7", },
{ }
};
static int is_memory(struct acpi_resource *res, void *not_used)
{
struct resource r;
return !acpi_dev_resource_memory(res, &r);
}
/* LPSS main clock device. */
static struct platform_device *lpss_clk_dev;
static inline void lpt_register_clock_device(void)
{
lpss_clk_dev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
}
static int register_device_clock(struct acpi_device *adev,
struct lpss_private_data *pdata)
{
const struct lpss_device_desc *dev_desc = pdata->dev_desc;
if (!lpss_clk_dev)
lpt_register_clock_device();
if (!dev_desc->clk_parent || !pdata->mmio_base
|| pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
return -ENODATA;
pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev),
dev_desc->clk_parent, 0,
pdata->mmio_base + dev_desc->prv_offset,
0, 0, NULL);
if (IS_ERR(pdata->clk))
return PTR_ERR(pdata->clk);
clk_register_clkdev(pdata->clk, NULL, dev_name(&adev->dev));
return 0;
}
static int acpi_lpss_create_device(struct acpi_device *adev,
const struct acpi_device_id *id)
{
struct lpss_device_desc *dev_desc;
struct lpss_private_data *pdata;
struct resource_list_entry *rentry;
struct list_head resource_list;
int ret;
dev_desc = (struct lpss_device_desc *)id->driver_data;
if (!dev_desc)
return acpi_create_platform_device(adev, id);
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL);
if (ret < 0)
goto err_out;
list_for_each_entry(rentry, &resource_list, node)
if (resource_type(&rentry->res) == IORESOURCE_MEM) {
pdata->mmio_size = resource_size(&rentry->res);
pdata->mmio_base = ioremap(rentry->res.start,
pdata->mmio_size);
pdata->dev_desc = dev_desc;
break;
}
acpi_dev_free_resource_list(&resource_list);
if (dev_desc->clk_required) {
ret = register_device_clock(adev, pdata);
if (ret) {
/*
* Skip the device, but don't terminate the namespace
* scan.
*/
kfree(pdata);
return 0;
}
}
adev->driver_data = pdata;
ret = acpi_create_platform_device(adev, id);
if (ret > 0)
return ret;
adev->driver_data = NULL;
err_out:
kfree(pdata);
return ret;
}
static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
{
struct acpi_device *adev;
struct lpss_private_data *pdata;
unsigned long flags;
int ret;
ret = acpi_bus_get_device(ACPI_HANDLE(dev), &adev);
if (WARN_ON(ret))
return ret;
spin_lock_irqsave(&dev->power.lock, flags);
if (pm_runtime_suspended(dev)) {
ret = -EAGAIN;
goto out;
}
pdata = acpi_driver_data(adev);
if (WARN_ON(!pdata || !pdata->mmio_base)) {
ret = -ENODEV;
goto out;
}
*val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
return ret;
}
static ssize_t lpss_ltr_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
u32 ltr_value = 0;
unsigned int reg;
int ret;
reg = strcmp(attr->attr.name, "auto_ltr") ? LPSS_SW_LTR : LPSS_AUTO_LTR;
ret = lpss_reg_read(dev, reg, &ltr_value);
if (ret)
return ret;
return snprintf(buf, PAGE_SIZE, "%08x\n", ltr_value);
}
static ssize_t lpss_ltr_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 ltr_mode = 0;
char *outstr;
int ret;
ret = lpss_reg_read(dev, LPSS_GENERAL, &ltr_mode);
if (ret)
return ret;
outstr = (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) ? "sw" : "auto";
return sprintf(buf, "%s\n", outstr);
}
static DEVICE_ATTR(auto_ltr, S_IRUSR, lpss_ltr_show, NULL);
static DEVICE_ATTR(sw_ltr, S_IRUSR, lpss_ltr_show, NULL);
static DEVICE_ATTR(ltr_mode, S_IRUSR, lpss_ltr_mode_show, NULL);
static struct attribute *lpss_attrs[] = {
&dev_attr_auto_ltr.attr,
&dev_attr_sw_ltr.attr,
&dev_attr_ltr_mode.attr,
NULL,
};
static struct attribute_group lpss_attr_group = {
.attrs = lpss_attrs,
.name = "lpss_ltr",
};
static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct platform_device *pdev = to_platform_device(data);
struct lpss_private_data *pdata;
struct acpi_device *adev;
const struct acpi_device_id *id;
int ret = 0;
id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
if (!id || !id->driver_data)
return 0;
if (acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
return 0;
pdata = acpi_driver_data(adev);
if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
return 0;
if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
return 0;
}
if (action == BUS_NOTIFY_ADD_DEVICE)
ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group);
else if (action == BUS_NOTIFY_DEL_DEVICE)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
return ret;
}
static struct notifier_block acpi_lpss_nb = {
.notifier_call = acpi_lpss_platform_notify,
};
static struct acpi_scan_handler lpss_handler = {
.ids = acpi_lpss_device_ids,
.attach = acpi_lpss_create_device,
};
void __init acpi_lpss_init(void)
{
if (!lpt_clk_init()) {
bus_register_notifier(&platform_bus_type, &acpi_lpss_nb);
acpi_scan_add_handler(&lpss_handler);
}
}

View file

@ -1,5 +1,7 @@
/*
* Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
* Copyright (C) 2004, 2013 Intel Corporation
* Author: Naveen B S <naveen.b.s@intel.com>
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* All rights reserved.
*
@ -25,14 +27,10 @@
* ranges.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/memory_hotplug.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <linux/memory_hotplug.h>
#include "internal.h"
#define ACPI_MEMORY_DEVICE_CLASS "memory"
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
@ -44,32 +42,28 @@
#define PREFIX "ACPI:memory_hp:"
ACPI_MODULE_NAME("acpi_memhotplug");
MODULE_AUTHOR("Naveen B S <[email protected]>");
MODULE_DESCRIPTION("Hotplug Mem Driver");
MODULE_LICENSE("GPL");
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
#define MEMORY_POWER_OFF_STATE 2
static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device);
static int acpi_memory_device_add(struct acpi_device *device,
const struct acpi_device_id *not_used);
static void acpi_memory_device_remove(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, memory_device_ids);
static struct acpi_driver acpi_memory_device_driver = {
.name = "acpi_memhotplug",
.class = ACPI_MEMORY_DEVICE_CLASS,
static struct acpi_scan_handler memory_device_handler = {
.ids = memory_device_ids,
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
},
.attach = acpi_memory_device_add,
.detach = acpi_memory_device_remove,
.hotplug = {
.enabled = true,
},
};
struct acpi_memory_info {
@ -79,7 +73,6 @@ struct acpi_memory_info {
unsigned short caching; /* memory cache attribute */
unsigned short write_protect; /* memory read/write attribute */
unsigned int enabled:1;
unsigned int failed:1;
};
struct acpi_memory_device {
@ -153,48 +146,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}
static int acpi_memory_get_device(acpi_handle handle,
struct acpi_memory_device **mem_device)
{
struct acpi_device *device = NULL;
int result = 0;
acpi_scan_lock_acquire();
acpi_bus_get_device(handle, &device);
if (device)
goto end;
/*
* Now add the notified device. This creates the acpi_device
* and invokes .add function
*/
result = acpi_bus_scan(handle);
if (result) {
acpi_handle_warn(handle, "ACPI namespace scan failed\n");
result = -EINVAL;
goto out;
}
result = acpi_bus_get_device(handle, &device);
if (result) {
acpi_handle_warn(handle, "Missing device object\n");
result = -EINVAL;
goto out;
}
end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
dev_err(&device->dev, "driver data not found\n");
result = -ENODEV;
goto out;
}
out:
acpi_scan_lock_release();
return result;
}
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
{
unsigned long long current_status;
@ -249,13 +200,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
* returns -EEXIST. If add_memory() returns the other error, it
* means that this memory block is not used by the kernel.
*/
if (result && result != -EEXIST) {
info->failed = 1;
if (result && result != -EEXIST)
continue;
}
if (!result)
info->enabled = 1;
info->enabled = 1;
/*
* Add num_enable even if add_memory() returns -EEXIST, so the
* device is bound to this driver.
@ -286,16 +235,8 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
nid = acpi_get_node(mem_device->device->handle);
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
if (info->failed)
/* The kernel does not use this memory block */
continue;
if (!info->enabled)
/*
* The kernel uses this memory block, but it may be not
* managed by us.
*/
return -EBUSY;
continue;
if (nid < 0)
nid = memory_add_physaddr_to_nid(info->start_addr);
@ -310,95 +251,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
return result;
}
static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_memory_device *mem_device;
struct acpi_device *device;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
acpi_status status;
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived BUS CHECK notification for device\n"));
/* Fall Through */
case ACPI_NOTIFY_DEVICE_CHECK:
if (event == ACPI_NOTIFY_DEVICE_CHECK)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived DEVICE CHECK notification for device\n"));
if (acpi_memory_get_device(handle, &mem_device)) {
acpi_handle_err(handle, "Cannot find driver data\n");
break;
}
ost_code = ACPI_OST_SC_SUCCESS;
break;
case ACPI_NOTIFY_EJECT_REQUEST:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived EJECT REQUEST notification for device\n"));
status = AE_ERROR;
acpi_scan_lock_acquire();
if (acpi_bus_get_device(handle, &device)) {
acpi_handle_err(handle, "Device doesn't exist\n");
goto unlock;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
acpi_handle_err(handle, "Driver Data is NULL\n");
goto unlock;
}
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
pr_err(PREFIX "No memory, dropping EJECT\n");
goto unlock;
}
get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
/* The eject is carried out asynchronously. */
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
ej_event);
if (ACPI_FAILURE(status)) {
put_device(&device->dev);
kfree(ej_event);
}
unlock:
acpi_scan_lock_release();
if (ACPI_SUCCESS(status))
return;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
/* non-hotplug event; possibly handled by other handler */
return;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
}
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
{
if (!mem_device)
return;
acpi_memory_free_device_resources(mem_device);
mem_device->device->driver_data = NULL;
kfree(mem_device);
}
static int acpi_memory_device_add(struct acpi_device *device)
static int acpi_memory_device_add(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
struct acpi_memory_device *mem_device;
int result;
struct acpi_memory_device *mem_device = NULL;
if (!device)
return -EINVAL;
@ -423,147 +290,36 @@ static int acpi_memory_device_add(struct acpi_device *device)
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
pr_debug("%s\n", acpi_device_name(device));
if (!acpi_memory_check_device(mem_device)) {
/* call add_memory func */
result = acpi_memory_enable_device(mem_device);
if (result) {
dev_err(&device->dev,
"Error in acpi_memory_enable_device\n");
acpi_memory_device_free(mem_device);
}
result = acpi_memory_check_device(mem_device);
if (result) {
acpi_memory_device_free(mem_device);
return 0;
}
return result;
result = acpi_memory_enable_device(mem_device);
if (result) {
dev_err(&device->dev, "acpi_memory_enable_device() error\n");
acpi_memory_device_free(mem_device);
return -ENODEV;
}
dev_dbg(&device->dev, "Memory device configured by ACPI\n");
return 1;
}
static int acpi_memory_device_remove(struct acpi_device *device)
static void acpi_memory_device_remove(struct acpi_device *device)
{
struct acpi_memory_device *mem_device = NULL;
int result;
struct acpi_memory_device *mem_device;
if (!device || !acpi_driver_data(device))
return -EINVAL;
return;
mem_device = acpi_driver_data(device);
result = acpi_memory_remove_memory(mem_device);
if (result)
return result;
acpi_memory_remove_memory(mem_device);
acpi_memory_device_free(mem_device);
return 0;
}
/*
* Helper function to check for memory device
*/
static acpi_status is_memory_device(acpi_handle handle)
void __init acpi_memory_hotplug_init(void)
{
char *hardware_id;
acpi_status status;
struct acpi_device_info *info;
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status))
return status;
if (!(info->valid & ACPI_VALID_HID)) {
kfree(info);
return AE_ERROR;
}
hardware_id = info->hardware_id.string;
if ((hardware_id == NULL) ||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
status = AE_ERROR;
kfree(info);
return status;
acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
}
static acpi_status
acpi_memory_register_notify_handler(acpi_handle handle,
u32 level, void *ctxt, void **retv)
{
acpi_status status;
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
return AE_OK; /* continue */
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_memory_device_notify, NULL);
/* continue */
return AE_OK;
}
static acpi_status
acpi_memory_deregister_notify_handler(acpi_handle handle,
u32 level, void *ctxt, void **retv)
{
acpi_status status;
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
return AE_OK; /* continue */
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
acpi_memory_device_notify);
return AE_OK; /* continue */
}
static int __init acpi_memory_device_init(void)
{
int result;
acpi_status status;
result = acpi_bus_register_driver(&acpi_memory_device_driver);
if (result < 0)
return -ENODEV;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
acpi_memory_register_notify_handler, NULL,
NULL, NULL);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
return -ENODEV;
}
return 0;
}
static void __exit acpi_memory_device_exit(void)
{
acpi_status status;
/*
* Adding this to un-install notification handlers for all the device
* handles.
*/
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
acpi_memory_deregister_notify_handler, NULL,
NULL, NULL);
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
return;
}
module_init(acpi_memory_device_init);
module_exit(acpi_memory_device_exit);

View file

@ -236,7 +236,7 @@ static int create_power_saving_task(void)
ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
(void *)(unsigned long)ps_tsk_num,
"acpi_pad/%d", ps_tsk_num);
rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0;
rc = PTR_RET(ps_tsks[ps_tsk_num]);
if (!rc)
ps_tsk_num++;
else

View file

@ -22,9 +22,6 @@
ACPI_MODULE_NAME("platform");
/* Flags for acpi_create_platform_device */
#define ACPI_PLATFORM_CLK BIT(0)
/*
* The following ACPI IDs are known to be suitable for representing as
* platform devices.
@ -33,33 +30,9 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
{ "PNP0D40" },
/* Haswell LPSS devices */
{ "INT33C0", ACPI_PLATFORM_CLK },
{ "INT33C1", ACPI_PLATFORM_CLK },
{ "INT33C2", ACPI_PLATFORM_CLK },
{ "INT33C3", ACPI_PLATFORM_CLK },
{ "INT33C4", ACPI_PLATFORM_CLK },
{ "INT33C5", ACPI_PLATFORM_CLK },
{ "INT33C6", ACPI_PLATFORM_CLK },
{ "INT33C7", ACPI_PLATFORM_CLK },
{ }
};
static int acpi_create_platform_clks(struct acpi_device *adev)
{
static struct platform_device *pdev;
/* Create Lynxpoint LPSS clocks */
if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
}
return 0;
}
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
@ -71,10 +44,9 @@ static int acpi_create_platform_clks(struct acpi_device *adev)
*
* Name of the platform device will be the same as @adev's.
*/
static int acpi_create_platform_device(struct acpi_device *adev,
const struct acpi_device_id *id)
int acpi_create_platform_device(struct acpi_device *adev,
const struct acpi_device_id *id)
{
unsigned long flags = id->driver_data;
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
@ -83,14 +55,6 @@ static int acpi_create_platform_device(struct acpi_device *adev,
struct resource *resources;
int count;
if (flags & ACPI_PLATFORM_CLK) {
int ret = acpi_create_platform_clks(adev);
if (ret) {
dev_err(&adev->dev, "failed to create clocks\n");
return ret;
}
}
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
return 0;

View file

@ -83,6 +83,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
acpi-y += \
nsaccess.o \
nsalloc.o \
nsconvert.o \
nsdump.o \
nseval.o \
nsinit.o \
@ -160,6 +161,7 @@ acpi-y += \
utobject.o \
utosi.o \
utownerid.o \
utpredef.o \
utresrc.o \
utstate.o \
utstring.o \

View file

@ -224,6 +224,7 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
*/
ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock; /* For GPE data structs and registers */
ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
ACPI_EXTERN acpi_spinlock acpi_gbl_reference_count_lock;
/* Mutex for _OSI support */
@ -413,10 +414,12 @@ ACPI_EXTERN u8 acpi_gbl_db_output_flags;
#ifdef ACPI_DISASSEMBLER
u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
ACPI_EXTERN u8 acpi_gbl_num_external_methods;
ACPI_EXTERN u32 acpi_gbl_resolved_external_methods;
ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
#endif

View file

@ -294,6 +294,8 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */
#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF
#pragma pack(1)
/*
* Information structure for ACPI predefined names.
* Each entry in the table contains the following items:
@ -304,7 +306,7 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
*/
struct acpi_name_info {
char name[ACPI_NAME_SIZE];
u8 param_count;
u16 argument_list;
u8 expected_btypes;
};
@ -327,7 +329,7 @@ struct acpi_package_info {
u8 count1;
u8 object_type2;
u8 count2;
u8 reserved;
u16 reserved;
};
/* Used for ACPI_PTYPE2_FIXED */
@ -336,6 +338,7 @@ struct acpi_package_info2 {
u8 type;
u8 count;
u8 object_type[4];
u8 reserved;
};
/* Used for ACPI_PTYPE1_OPTION */
@ -345,7 +348,7 @@ struct acpi_package_info3 {
u8 count;
u8 object_type[2];
u8 tail_object_type;
u8 reserved;
u16 reserved;
};
union acpi_predefined_info {
@ -355,6 +358,10 @@ union acpi_predefined_info {
struct acpi_package_info3 ret_info3;
};
/* Reset to default packing */
#pragma pack()
/* Data block used during object validation */
struct acpi_predefined_data {
@ -363,6 +370,7 @@ struct acpi_predefined_data {
union acpi_operand_object *parent_package;
struct acpi_namespace_node *node;
u32 flags;
u32 return_btype;
u8 node_flags;
};
@ -371,6 +379,20 @@ struct acpi_predefined_data {
#define ACPI_OBJECT_REPAIRED 1
#define ACPI_OBJECT_WRAPPED 2
/* Return object auto-repair info */
typedef acpi_status(*acpi_object_converter) (union acpi_operand_object
*original_object,
union acpi_operand_object
**converted_object);
struct acpi_simple_repair_info {
char name[ACPI_NAME_SIZE];
u32 unexpected_btypes;
u32 package_index;
acpi_object_converter object_converter;
};
/*
* Bitmapped return value types
* Note: the actual data types must be contiguous, a loop in nspredef.c
@ -1037,6 +1059,7 @@ struct acpi_external_list {
u16 length;
u8 type;
u8 flags;
u8 resolved;
};
/* Values for Flags field above */

View file

@ -322,10 +322,12 @@
* where a pointer to an object of type union acpi_operand_object can also
* appear. This macro is used to distinguish them.
*
* The "Descriptor" field is the first field in both structures.
* The "DescriptorType" field is the second field in both structures.
*/
#define ACPI_GET_DESCRIPTOR_PTR(d) (((union acpi_descriptor *)(void *)(d))->common.common_pointer)
#define ACPI_SET_DESCRIPTOR_PTR(d, p) (((union acpi_descriptor *)(void *)(d))->common.common_pointer = (p))
#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type)
#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t)
#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = (t))
/*
* Macros for the master AML opcode table

View file

@ -166,6 +166,29 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent);
int acpi_ns_compare_names(char *name1, char *name2);
/*
* nsconvert - Dynamic object conversion routines
*/
acpi_status
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
acpi_status
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
acpi_status
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
acpi_status
acpi_ns_convert_to_unicode(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
acpi_status
acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
/*
* nsdump - Namespace dump/print utilities
*/
@ -208,10 +231,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status return_status,
union acpi_operand_object **return_object);
const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
acpi_namespace_node
*node);
void
acpi_ns_check_parameter_count(char *pathname,
struct acpi_namespace_node *node,
@ -289,7 +308,7 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node,
* predefined methods/objects
*/
acpi_status
acpi_ns_repair_object(struct acpi_predefined_data *data,
acpi_ns_simple_repair(struct acpi_predefined_data *data,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr);

File diff suppressed because it is too large Load diff

View file

@ -113,9 +113,10 @@ struct acpi_pkg_info {
u32 num_packages;
};
/* Object reference counts */
#define REF_INCREMENT (u16) 0
#define REF_DECREMENT (u16) 1
#define REF_FORCE_DELETE (u16) 2
/* acpi_ut_dump_buffer */
@ -421,7 +422,7 @@ acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
*/
acpi_status acpi_ut_initialize_interfaces(void);
void acpi_ut_interface_terminate(void);
acpi_status acpi_ut_interface_terminate(void);
acpi_status acpi_ut_install_interface(acpi_string interface_name);
@ -431,6 +432,26 @@ struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
/*
* utpredef - support for predefined names
*/
const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union
acpi_predefined_info
*this_name);
const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name);
const union acpi_predefined_info *acpi_ut_match_resource_name(char *name);
void
acpi_ut_display_predefined_method(char *buffer,
const union acpi_predefined_info *this_name,
u8 multi_line);
void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes);
u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types);
/*
* utstate - Generic state creation/cache routines
*/
@ -483,7 +504,8 @@ acpi_ut_short_divide(u64 in_dividend,
/*
* utmisc
*/
const char *acpi_ut_validate_exception(acpi_status status);
const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status
status);
u8 acpi_ut_is_pci_root_bridge(char *id);

View file

@ -178,7 +178,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
if (!op) {
ACPI_ERROR((AE_INFO, "Null Op"));
return_VALUE(TRUE);
return_UINT8(TRUE);
}
/*
@ -210,7 +210,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
"At Method level, result of [%s] not used\n",
acpi_ps_get_opcode_name(op->common.
aml_opcode)));
return_VALUE(FALSE);
return_UINT8(FALSE);
}
/* Get info on the parent. The root_op is AML_SCOPE */
@ -219,7 +219,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
if (parent_info->class == AML_CLASS_UNKNOWN) {
ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
return_VALUE(FALSE);
return_UINT8(FALSE);
}
/*
@ -307,7 +307,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
return_VALUE(TRUE);
return_UINT8(TRUE);
result_not_used:
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@ -316,7 +316,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
return_VALUE(FALSE);
return_UINT8(FALSE);
}
/*******************************************************************************

View file

@ -693,7 +693,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
default:
ACPI_ERROR((AE_INFO,
"Unimplemented opcode, class=0x%X type=0x%X Opcode=-0x%X Op=%p",
"Unimplemented opcode, class=0x%X type=0x%X Opcode=0x%X Op=%p",
op_class, op_type, op->common.aml_opcode,
op));

View file

@ -257,6 +257,8 @@ u32 acpi_ev_fixed_event_detect(void)
*
* DESCRIPTION: Clears the status bit for the requested event, calls the
* handler that previously registered for the event.
* NOTE: If there is no handler for the event, the event is
* disabled to prevent further interrupts.
*
******************************************************************************/
@ -271,17 +273,17 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
status_register_id, ACPI_CLEAR_STATUS);
/*
* Make sure we've got a handler. If not, report an error. The event is
* disabled to prevent further interrupts.
* Make sure that a handler exists. If not, report an error
* and disable the event to prevent further interrupts.
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
if (!acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
enable_register_id,
ACPI_DISABLE_EVENT);
ACPI_ERROR((AE_INFO,
"No installed handler for fixed event [0x%08X]",
event));
"No installed handler for fixed event - %s (%u), disabling",
acpi_ut_get_event_name(event), event));
return (ACPI_INTERRUPT_NOT_HANDLED);
}

View file

@ -707,7 +707,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to clear GPE%02X", gpe_number));
return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
}
@ -724,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to disable GPE%02X", gpe_number));
return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
/*
@ -784,7 +784,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
break;
}
return_VALUE(ACPI_INTERRUPT_HANDLED);
return_UINT32(ACPI_INTERRUPT_HANDLED);
}
#endif /* !ACPI_REDUCED_HARDWARE */

View file

@ -89,7 +89,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
*/
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
return_VALUE(interrupt_handled);
return_UINT32(interrupt_handled);
}
/*******************************************************************************
@ -120,7 +120,7 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
return_VALUE(interrupt_handled);
return_UINT32(interrupt_handled);
}
/******************************************************************************

View file

@ -467,9 +467,9 @@ acpi_install_fixed_event_handler(u32 event,
return_ACPI_STATUS(status);
}
/* Don't allow two handlers. */
/* Do not allow multiple handlers */
if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
if (acpi_gbl_fixed_event_handlers[event].handler) {
status = AE_ALREADY_EXISTS;
goto cleanup;
}
@ -483,8 +483,9 @@ acpi_install_fixed_event_handler(u32 event,
if (ACPI_SUCCESS(status))
status = acpi_enable_event(event, 0);
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO, "Could not enable fixed event 0x%X",
event));
ACPI_WARNING((AE_INFO,
"Could not enable fixed event - %s (%u)",
acpi_ut_get_event_name(event), event));
/* Remove the handler */
@ -492,7 +493,8 @@ acpi_install_fixed_event_handler(u32 event,
acpi_gbl_fixed_event_handlers[event].context = NULL;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Enabled fixed event %X, Handler=%p\n", event,
"Enabled fixed event %s (%X), Handler=%p\n",
acpi_ut_get_event_name(event), event,
handler));
}
@ -544,11 +546,12 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
"Could not write to fixed event enable register 0x%X",
event));
"Could not disable fixed event - %s (%u)",
acpi_ut_get_event_name(event), event));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
event));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Disabled fixed event - %s (%X)\n",
acpi_ut_get_event_name(event), event));
}
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);

View file

@ -74,6 +74,12 @@ acpi_status acpi_enable(void)
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
}
/* If the Hardware Reduced flag is set, machine is always in acpi mode */
if (acpi_gbl_reduced_hardware) {
return_ACPI_STATUS(AE_OK);
}
/* Check current mode */
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
@ -126,6 +132,12 @@ acpi_status acpi_disable(void)
ACPI_FUNCTION_TRACE(acpi_disable);
/* If the Hardware Reduced flag is set, machine is always in acpi mode */
if (acpi_gbl_reduced_hardware) {
return_ACPI_STATUS(AE_OK);
}
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in legacy (non-ACPI) mode\n"));

View file

@ -257,7 +257,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc = NULL;
u64 index;
acpi_status status = AE_OK;
acpi_size length;
acpi_size length = 0;
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
@ -320,7 +320,6 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
* NOTE: A length of zero is ok, and will create a zero-length, null
* terminated string.
*/
length = 0;
while ((length < operand[0]->buffer.length) &&
(length < operand[1]->integer.value) &&
(operand[0]->buffer.pointer[length])) {
@ -376,6 +375,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_STRING:
if (index >= operand[0]->string.length) {
length = operand[0]->string.length;
status = AE_AML_STRING_LIMIT;
}
@ -386,6 +386,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_BUFFER:
if (index >= operand[0]->buffer.length) {
length = operand[0]->buffer.length;
status = AE_AML_BUFFER_LIMIT;
}
@ -396,6 +397,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_PACKAGE:
if (index >= operand[0]->package.count) {
length = operand[0]->package.count;
status = AE_AML_PACKAGE_LIMIT;
}
@ -414,8 +416,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Index (0x%8.8X%8.8X) is beyond end of object",
ACPI_FORMAT_UINT64(index)));
"Index (0x%X%8.8X) is beyond end of object (length 0x%X)",
ACPI_FORMAT_UINT64(index),
(u32)length));
goto cleanup;
}

View file

@ -276,7 +276,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
/* Invalid field access type */
ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
return_VALUE(0);
return_UINT32(0);
}
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
@ -289,7 +289,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
}
*return_byte_alignment = byte_alignment;
return_VALUE(bit_length);
return_UINT32(bit_length);
}
/*******************************************************************************

View file

@ -340,7 +340,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
/* u64 is unsigned, so we don't worry about a '-' prefix */
if (value == 0) {
return_VALUE(1);
return_UINT32(1);
}
current_value = value;
@ -354,7 +354,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
num_digits++;
}
return_VALUE(num_digits);
return_UINT32(num_digits);
}
/*******************************************************************************

View file

@ -66,6 +66,12 @@ acpi_status acpi_hw_set_mode(u32 mode)
ACPI_FUNCTION_TRACE(hw_set_mode);
/* If the Hardware Reduced flag is set, machine is always in acpi mode */
if (acpi_gbl_reduced_hardware) {
return_ACPI_STATUS(AE_OK);
}
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
@ -146,23 +152,29 @@ u32 acpi_hw_get_mode(void)
ACPI_FUNCTION_TRACE(hw_get_mode);
/* If the Hardware Reduced flag is set, machine is always in acpi mode */
if (acpi_gbl_reduced_hardware) {
return_UINT32(ACPI_SYS_MODE_ACPI);
}
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
if (!acpi_gbl_FADT.smi_command) {
return_VALUE(ACPI_SYS_MODE_ACPI);
return_UINT32(ACPI_SYS_MODE_ACPI);
}
status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
return_VALUE(ACPI_SYS_MODE_LEGACY);
return_UINT32(ACPI_SYS_MODE_LEGACY);
}
if (value) {
return_VALUE(ACPI_SYS_MODE_ACPI);
return_UINT32(ACPI_SYS_MODE_ACPI);
} else {
return_VALUE(ACPI_SYS_MODE_LEGACY);
return_UINT32(ACPI_SYS_MODE_LEGACY);
}
}

View file

@ -0,0 +1,443 @@
/******************************************************************************
*
* Module Name: nsconvert - Object conversions for objects returned by
* predefined methods
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
#include "acinterp.h"
#include "acpredef.h"
#include "amlresrc.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsconvert")
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_integer
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
*
******************************************************************************/
acpi_status
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
acpi_status status;
u64 value = 0;
u32 i;
switch (original_object->common.type) {
case ACPI_TYPE_STRING:
/* String-to-Integer conversion */
status = acpi_ut_strtoul64(original_object->string.pointer,
ACPI_ANY_BASE, &value);
if (ACPI_FAILURE(status)) {
return (status);
}
break;
case ACPI_TYPE_BUFFER:
/* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
if (original_object->buffer.length > 8) {
return (AE_AML_OPERAND_TYPE);
}
/* Extract each buffer byte to create the integer */
for (i = 0; i < original_object->buffer.length; i++) {
value |=
((u64)original_object->buffer.
pointer[i] << (i * 8));
}
break;
default:
return (AE_AML_OPERAND_TYPE);
}
new_object = acpi_ut_create_integer_object(value);
if (!new_object) {
return (AE_NO_MEMORY);
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_string
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
*
******************************************************************************/
acpi_status
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
acpi_size length;
acpi_status status;
switch (original_object->common.type) {
case ACPI_TYPE_INTEGER:
/*
* Integer-to-String conversion. Commonly, convert
* an integer of value 0 to a NULL string. The last element of
* _BIF and _BIX packages occasionally need this fix.
*/
if (original_object->integer.value == 0) {
/* Allocate a new NULL string object */
new_object = acpi_ut_create_string_object(0);
if (!new_object) {
return (AE_NO_MEMORY);
}
} else {
status =
acpi_ex_convert_to_string(original_object,
&new_object,
ACPI_IMPLICIT_CONVERT_HEX);
if (ACPI_FAILURE(status)) {
return (status);
}
}
break;
case ACPI_TYPE_BUFFER:
/*
* Buffer-to-String conversion. Use a to_string
* conversion, no transform performed on the buffer data. The best
* example of this is the _BIF method, where the string data from
* the battery is often (incorrectly) returned as buffer object(s).
*/
length = 0;
while ((length < original_object->buffer.length) &&
(original_object->buffer.pointer[length])) {
length++;
}
/* Allocate a new string object */
new_object = acpi_ut_create_string_object(length);
if (!new_object) {
return (AE_NO_MEMORY);
}
/*
* Copy the raw buffer data with no transform. String is already NULL
* terminated at Length+1.
*/
ACPI_MEMCPY(new_object->string.pointer,
original_object->buffer.pointer, length);
break;
default:
return (AE_AML_OPERAND_TYPE);
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_buffer
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
*
******************************************************************************/
acpi_status
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
acpi_status status;
union acpi_operand_object **elements;
u32 *dword_buffer;
u32 count;
u32 i;
switch (original_object->common.type) {
case ACPI_TYPE_INTEGER:
/*
* Integer-to-Buffer conversion.
* Convert the Integer to a packed-byte buffer. _MAT and other
* objects need this sometimes, if a read has been performed on a
* Field object that is less than or equal to the global integer
* size (32 or 64 bits).
*/
status =
acpi_ex_convert_to_buffer(original_object, &new_object);
if (ACPI_FAILURE(status)) {
return (status);
}
break;
case ACPI_TYPE_STRING:
/* String-to-Buffer conversion. Simple data copy */
new_object =
acpi_ut_create_buffer_object(original_object->string.
length);
if (!new_object) {
return (AE_NO_MEMORY);
}
ACPI_MEMCPY(new_object->buffer.pointer,
original_object->string.pointer,
original_object->string.length);
break;
case ACPI_TYPE_PACKAGE:
/*
* This case is often seen for predefined names that must return a
* Buffer object with multiple DWORD integers within. For example,
* _FDE and _GTM. The Package can be converted to a Buffer.
*/
/* All elements of the Package must be integers */
elements = original_object->package.elements;
count = original_object->package.count;
for (i = 0; i < count; i++) {
if ((!*elements) ||
((*elements)->common.type != ACPI_TYPE_INTEGER)) {
return (AE_AML_OPERAND_TYPE);
}
elements++;
}
/* Create the new buffer object to replace the Package */
new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
if (!new_object) {
return (AE_NO_MEMORY);
}
/* Copy the package elements (integers) to the buffer as DWORDs */
elements = original_object->package.elements;
dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
for (i = 0; i < count; i++) {
*dword_buffer = (u32)(*elements)->integer.value;
dword_buffer++;
elements++;
}
break;
default:
return (AE_AML_OPERAND_TYPE);
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_unicode
*
* PARAMETERS: original_object - ASCII String Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer.
*
******************************************************************************/
acpi_status
acpi_ns_convert_to_unicode(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
char *ascii_string;
u16 *unicode_buffer;
u32 unicode_length;
u32 i;
if (!original_object) {
return (AE_OK);
}
/* If a Buffer was returned, it must be at least two bytes long */
if (original_object->common.type == ACPI_TYPE_BUFFER) {
if (original_object->buffer.length < 2) {
return (AE_AML_OPERAND_VALUE);
}
*return_object = NULL;
return (AE_OK);
}
/*
* The original object is an ASCII string. Convert this string to
* a unicode buffer.
*/
ascii_string = original_object->string.pointer;
unicode_length = (original_object->string.length * 2) + 2;
/* Create a new buffer object for the Unicode data */
new_object = acpi_ut_create_buffer_object(unicode_length);
if (!new_object) {
return (AE_NO_MEMORY);
}
unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer);
/* Convert ASCII to Unicode */
for (i = 0; i < original_object->string.length; i++) {
unicode_buffer[i] = (u16)ascii_string[i];
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_resource
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful
*
* DESCRIPTION: Attempt to convert a Integer object to a resource_template
* Buffer.
*
******************************************************************************/
acpi_status
acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
u8 *buffer;
/*
* We can fix the following cases for an expected resource template:
* 1. No return value (interpreter slack mode is disabled)
* 2. A "Return (Zero)" statement
* 3. A "Return empty buffer" statement
*
* We will return a buffer containing a single end_tag
* resource descriptor.
*/
if (original_object) {
switch (original_object->common.type) {
case ACPI_TYPE_INTEGER:
/* We can only repair an Integer==0 */
if (original_object->integer.value) {
return (AE_AML_OPERAND_TYPE);
}
break;
case ACPI_TYPE_BUFFER:
if (original_object->buffer.length) {
/* Additional checks can be added in the future */
*return_object = NULL;
return (AE_OK);
}
break;
case ACPI_TYPE_STRING:
default:
return (AE_AML_OPERAND_TYPE);
}
}
/* Create the new buffer object for the resource descriptor */
new_object = acpi_ut_create_buffer_object(2);
if (!new_object) {
return (AE_NO_MEMORY);
}
buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer);
/* Initialize the Buffer with a single end_tag descriptor */
buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE);
buffer[1] = 0x00;
*return_object = new_object;
return (AE_OK);
}

View file

@ -98,17 +98,21 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->return_object = NULL;
info->param_count = 0;
/*
* Get the actual namespace node for the target object. Handles these cases:
*
* 1) Null node, Pathname (absolute path)
* 2) Node, Pathname (path relative to Node)
* 3) Node, Null Pathname
*/
status = acpi_ns_get_node(info->prefix_node, info->pathname,
ACPI_NS_NO_UPSEARCH, &info->resolved_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
if (!info->resolved_node) {
/*
* Get the actual namespace node for the target object if we need to.
* Handles these cases:
*
* 1) Null node, Pathname (absolute path)
* 2) Node, Pathname (path relative to Node)
* 3) Node, Null Pathname
*/
status = acpi_ns_get_node(info->prefix_node, info->pathname,
ACPI_NS_NO_UPSEARCH,
&info->resolved_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}
/*

View file

@ -76,19 +76,7 @@ static acpi_status
acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object);
static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes);
/*
* Names for the types that can be returned by the predefined objects.
* Used for warning messages. Must be in the same order as the ACPI_RTYPEs
*/
static const char *acpi_rtype_names[] = {
"/Integer",
"/String",
"/Buffer",
"/Package",
"/Reference",
};
static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
/*******************************************************************************
*
@ -112,7 +100,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status return_status,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
const union acpi_predefined_info *predefined;
char *pathname;
@ -120,7 +107,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* Match the name for this method/object against the predefined list */
predefined = acpi_ns_check_for_predefined_name(node);
predefined = acpi_ut_match_predefined_method(node->name.ascii);
/* Get the full pathname to the object, for use in warning messages */
@ -151,25 +138,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
goto cleanup;
}
/*
* If there is no return value, check if we require a return value for
* this predefined name. Either one return value is expected, or none,
* for both methods and other objects.
*
* Exit now if there is no return object. Warning if one was expected.
*/
if (!return_object) {
if ((predefined->info.expected_btypes) &&
(!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) {
ACPI_WARN_PREDEFINED((AE_INFO, pathname,
ACPI_WARN_ALWAYS,
"Missing expected return value"));
status = AE_AML_NO_RETURN_VALUE;
}
goto cleanup;
}
/*
* Return value validation and possible repair.
*
@ -310,8 +278,10 @@ acpi_ns_check_parameter_count(char *pathname,
* Validate the user-supplied parameter count.
* Allow two different legal argument counts (_SCP, etc.)
*/
required_params_current = predefined->info.param_count & 0x0F;
required_params_old = predefined->info.param_count >> 4;
required_params_current =
predefined->info.argument_list & METHOD_ARG_MASK;
required_params_old =
predefined->info.argument_list >> METHOD_ARG_BIT_WIDTH;
if (user_param_count != ACPI_UINT32_MAX) {
if ((user_param_count != required_params_current) &&
@ -338,52 +308,6 @@ acpi_ns_check_parameter_count(char *pathname,
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_for_predefined_name
*
* PARAMETERS: node - Namespace node for the method/object
*
* RETURN: Pointer to entry in predefined table. NULL indicates not found.
*
* DESCRIPTION: Check an object name against the predefined object list.
*
******************************************************************************/
const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
acpi_namespace_node
*node)
{
const union acpi_predefined_info *this_name;
/* Quick check for a predefined name, first character must be underscore */
if (node->name.ascii[0] != '_') {
return (NULL);
}
/* Search info table for a predefined method/object name */
this_name = predefined_names;
while (this_name->info.name[0]) {
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) {
return (this_name);
}
/*
* Skip next entry in the table if this name returns a Package
* (next entry contains the package info)
*/
if (this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
this_name++;
}
this_name++;
}
return (NULL); /* Not found */
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_check_object_type
@ -410,28 +334,12 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
u32 return_btype;
char type_buffer[48]; /* Room for 5 types */
/*
* If we get a NULL return_object here, it is a NULL package element.
* Since all extraneous NULL package elements were removed earlier by a
* call to acpi_ns_remove_null_elements, this is an unexpected NULL element.
* We will attempt to repair it.
*/
if (!return_object) {
status = acpi_ns_repair_null_element(data, expected_btypes,
package_index,
return_object_ptr);
if (ACPI_SUCCESS(status)) {
return (AE_OK); /* Repair was successful */
}
goto type_error_exit;
}
/* A Namespace node should not get here, but make sure */
if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
if (return_object &&
ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
"Invalid return type - Found a Namespace node [%4.4s] type %s",
return_object->node.name.ascii,
@ -448,59 +356,31 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
* from all of the predefined names (including elements of returned
* packages)
*/
switch (return_object->common.type) {
case ACPI_TYPE_INTEGER:
return_btype = ACPI_RTYPE_INTEGER;
break;
data->return_btype = acpi_ns_get_bitmapped_type(return_object);
if (data->return_btype == ACPI_RTYPE_ANY) {
case ACPI_TYPE_BUFFER:
return_btype = ACPI_RTYPE_BUFFER;
break;
case ACPI_TYPE_STRING:
return_btype = ACPI_RTYPE_STRING;
break;
case ACPI_TYPE_PACKAGE:
return_btype = ACPI_RTYPE_PACKAGE;
break;
case ACPI_TYPE_LOCAL_REFERENCE:
return_btype = ACPI_RTYPE_REFERENCE;
break;
default:
/* Not one of the supported objects, must be incorrect */
goto type_error_exit;
}
/* Is the object one of the expected types? */
if (return_btype & expected_btypes) {
/* For reference objects, check that the reference type is correct */
if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
status = acpi_ns_check_reference(data, return_object);
}
/* For reference objects, check that the reference type is correct */
if ((data->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
status = acpi_ns_check_reference(data, return_object);
return (status);
}
/* Type mismatch -- attempt repair of the returned object */
/* Attempt simple repair of the returned object if necessary */
status = acpi_ns_repair_object(data, expected_btypes,
status = acpi_ns_simple_repair(data, expected_btypes,
package_index, return_object_ptr);
if (ACPI_SUCCESS(status)) {
return (AE_OK); /* Repair was successful */
}
return (status);
type_error_exit:
/* Create a string with all expected types for this predefined object */
acpi_ns_get_expected_types(type_buffer, expected_btypes);
acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
@ -558,36 +438,55 @@ acpi_ns_check_reference(struct acpi_predefined_data *data,
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_expected_types
* FUNCTION: acpi_ns_get_bitmapped_type
*
* PARAMETERS: buffer - Pointer to where the string is returned
* expected_btypes - Bitmap of expected return type(s)
* PARAMETERS: return_object - Object returned from method/obj evaluation
*
* RETURN: Buffer is populated with type names.
* RETURN: Object return type. ACPI_RTYPE_ANY indicates that the object
* type is not supported. ACPI_RTYPE_NONE indicates that no
* object was returned (return_object is NULL).
*
* DESCRIPTION: Translate the expected types bitmap into a string of ascii
* names of expected types, for use in warning messages.
* DESCRIPTION: Convert object type into a bitmapped object return type.
*
******************************************************************************/
static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes)
static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object)
{
u32 this_rtype;
u32 i;
u32 j;
u32 return_btype;
j = 1;
buffer[0] = 0;
this_rtype = ACPI_RTYPE_INTEGER;
for (i = 0; i < ACPI_NUM_RTYPES; i++) {
/* If one of the expected types, concatenate the name of this type */
if (expected_btypes & this_rtype) {
ACPI_STRCAT(buffer, &acpi_rtype_names[i][j]);
j = 0; /* Use name separator from now on */
}
this_rtype <<= 1; /* Next Rtype */
if (!return_object) {
return (ACPI_RTYPE_NONE);
}
/* Map acpi_object_type to internal bitmapped type */
switch (return_object->common.type) {
case ACPI_TYPE_INTEGER:
return_btype = ACPI_RTYPE_INTEGER;
break;
case ACPI_TYPE_BUFFER:
return_btype = ACPI_RTYPE_BUFFER;
break;
case ACPI_TYPE_STRING:
return_btype = ACPI_RTYPE_STRING;
break;
case ACPI_TYPE_PACKAGE:
return_btype = ACPI_RTYPE_PACKAGE;
break;
case ACPI_TYPE_LOCAL_REFERENCE:
return_btype = ACPI_RTYPE_REFERENCE;
break;
default:
/* Not one of the supported objects, must be incorrect */
return_btype = ACPI_RTYPE_ANY;
break;
}
return (return_btype);
}

View file

@ -112,9 +112,15 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
elements = return_object->package.elements;
count = return_object->package.count;
/* The package must have at least one element, else invalid */
/*
* Most packages must have at least one element. The only exception
* is the variable-length package (ACPI_PTYPE1_VAR).
*/
if (!count) {
if (package->ret_info.type == ACPI_PTYPE1_VAR) {
return (AE_OK);
}
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
"Return Package has no elements (empty)"));

View file

@ -46,6 +46,7 @@
#include "acnamesp.h"
#include "acinterp.h"
#include "acpredef.h"
#include "amlresrc.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair")
@ -71,6 +72,11 @@ ACPI_MODULE_NAME("nsrepair")
* Buffer -> String
* Buffer -> Package of Integers
* Package -> Package of one Package
*
* Additional conversions that are available:
* Convert a null return or zero return value to an end_tag descriptor
* Convert an ASCII string to a Unicode buffer
*
* An incorrect standalone object is wrapped with required outer package
*
* Additional possible repairs:
@ -78,21 +84,51 @@ ACPI_MODULE_NAME("nsrepair")
*
******************************************************************************/
/* Local prototypes */
static acpi_status
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
acpi_namespace_node
*node,
u32
return_btype,
u32
package_index);
static acpi_status
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
/*
* Special but simple repairs for some names.
*
* 2nd argument: Unexpected types that can be repaired
*/
static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
/* Resource descriptor conversions */
static acpi_status
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object);
{"_CRS",
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
ACPI_RTYPE_NONE,
ACPI_NOT_PACKAGE_ELEMENT,
acpi_ns_convert_to_resource},
{"_DMA",
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
ACPI_RTYPE_NONE,
ACPI_NOT_PACKAGE_ELEMENT,
acpi_ns_convert_to_resource},
{"_PRS",
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
ACPI_RTYPE_NONE,
ACPI_NOT_PACKAGE_ELEMENT,
acpi_ns_convert_to_resource},
/* Unicode conversions */
{"_MLS", ACPI_RTYPE_STRING, 1,
acpi_ns_convert_to_unicode},
{"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER,
ACPI_NOT_PACKAGE_ELEMENT,
acpi_ns_convert_to_unicode},
{{0, 0, 0, 0}, 0, 0, NULL} /* Table terminator */
};
/*******************************************************************************
*
* FUNCTION: acpi_ns_repair_object
* FUNCTION: acpi_ns_simple_repair
*
* PARAMETERS: data - Pointer to validation data structure
* expected_btypes - Object types expected
@ -110,16 +146,54 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
******************************************************************************/
acpi_status
acpi_ns_repair_object(struct acpi_predefined_data *data,
acpi_ns_simple_repair(struct acpi_predefined_data *data,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
union acpi_operand_object *new_object;
union acpi_operand_object *new_object = NULL;
acpi_status status;
const struct acpi_simple_repair_info *predefined;
ACPI_FUNCTION_NAME(ns_repair_object);
ACPI_FUNCTION_NAME(ns_simple_repair);
/*
* Special repairs for certain names that are in the repair table.
* Check if this name is in the list of repairable names.
*/
predefined = acpi_ns_match_simple_repair(data->node,
data->return_btype,
package_index);
if (predefined) {
if (!return_object) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
ACPI_WARN_ALWAYS,
"Missing expected return value"));
}
status =
predefined->object_converter(return_object, &new_object);
if (ACPI_FAILURE(status)) {
/* A fatal error occurred during a conversion */
ACPI_EXCEPTION((AE_INFO, status,
"During return object analysis"));
return (status);
}
if (new_object) {
goto object_repaired;
}
}
/*
* Do not perform simple object repair unless the return type is not
* expected.
*/
if (data->return_btype & expected_btypes) {
return (AE_OK);
}
/*
* At this point, we know that the type of the returned object was not
@ -127,6 +201,24 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
* repair the object by converting it to one of the expected object
* types for this predefined name.
*/
/*
* If there is no return value, check if we require a return value for
* this predefined name. Either one return value is expected, or none,
* for both methods and other objects.
*
* Exit now if there is no return object. Warning if one was expected.
*/
if (!return_object) {
if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
ACPI_WARN_ALWAYS,
"Missing expected return value"));
return (AE_AML_NO_RETURN_VALUE);
}
}
if (expected_btypes & ACPI_RTYPE_INTEGER) {
status = acpi_ns_convert_to_integer(return_object, &new_object);
if (ACPI_SUCCESS(status)) {
@ -216,254 +308,51 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
return (AE_OK);
}
/*******************************************************************************
/******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_integer
* FUNCTION: acpi_ns_match_simple_repair
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
* PARAMETERS: node - Namespace node for the method/object
* return_btype - Object type that was returned
* package_index - Index of object within parent package (if
* applicable - ACPI_NOT_PACKAGE_ELEMENT
* otherwise)
*
* RETURN: Status. AE_OK if conversion was successful.
* RETURN: Pointer to entry in repair table. NULL indicates not found.
*
* DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
* DESCRIPTION: Check an object name against the repairable object list.
*
******************************************************************************/
*****************************************************************************/
static acpi_status
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
acpi_namespace_node
*node,
u32
return_btype,
u32
package_index)
{
union acpi_operand_object *new_object;
acpi_status status;
u64 value = 0;
u32 i;
const struct acpi_simple_repair_info *this_name;
switch (original_object->common.type) {
case ACPI_TYPE_STRING:
/* Search info table for a repairable predefined method/object name */
/* String-to-Integer conversion */
this_name = acpi_object_repair_info;
while (this_name->object_converter) {
if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
status = acpi_ut_strtoul64(original_object->string.pointer,
ACPI_ANY_BASE, &value);
if (ACPI_FAILURE(status)) {
return (status);
}
break;
/* Check if we can actually repair this name/type combination */
case ACPI_TYPE_BUFFER:
/* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
if (original_object->buffer.length > 8) {
return (AE_AML_OPERAND_TYPE);
}
/* Extract each buffer byte to create the integer */
for (i = 0; i < original_object->buffer.length; i++) {
value |=
((u64) original_object->buffer.
pointer[i] << (i * 8));
}
break;
default:
return (AE_AML_OPERAND_TYPE);
}
new_object = acpi_ut_create_integer_object(value);
if (!new_object) {
return (AE_NO_MEMORY);
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_string
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
*
******************************************************************************/
static acpi_status
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
acpi_size length;
acpi_status status;
switch (original_object->common.type) {
case ACPI_TYPE_INTEGER:
/*
* Integer-to-String conversion. Commonly, convert
* an integer of value 0 to a NULL string. The last element of
* _BIF and _BIX packages occasionally need this fix.
*/
if (original_object->integer.value == 0) {
/* Allocate a new NULL string object */
new_object = acpi_ut_create_string_object(0);
if (!new_object) {
return (AE_NO_MEMORY);
}
} else {
status =
acpi_ex_convert_to_string(original_object,
&new_object,
ACPI_IMPLICIT_CONVERT_HEX);
if (ACPI_FAILURE(status)) {
return (status);
if ((return_btype & this_name->unexpected_btypes) &&
(package_index == this_name->package_index)) {
return (this_name);
}
return (NULL);
}
break;
case ACPI_TYPE_BUFFER:
/*
* Buffer-to-String conversion. Use a to_string
* conversion, no transform performed on the buffer data. The best
* example of this is the _BIF method, where the string data from
* the battery is often (incorrectly) returned as buffer object(s).
*/
length = 0;
while ((length < original_object->buffer.length) &&
(original_object->buffer.pointer[length])) {
length++;
}
/* Allocate a new string object */
new_object = acpi_ut_create_string_object(length);
if (!new_object) {
return (AE_NO_MEMORY);
}
/*
* Copy the raw buffer data with no transform. String is already NULL
* terminated at Length+1.
*/
ACPI_MEMCPY(new_object->string.pointer,
original_object->buffer.pointer, length);
break;
default:
return (AE_AML_OPERAND_TYPE);
this_name++;
}
*return_object = new_object;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_convert_to_buffer
*
* PARAMETERS: original_object - Object to be converted
* return_object - Where the new converted object is returned
*
* RETURN: Status. AE_OK if conversion was successful.
*
* DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
*
******************************************************************************/
static acpi_status
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
union acpi_operand_object **return_object)
{
union acpi_operand_object *new_object;
acpi_status status;
union acpi_operand_object **elements;
u32 *dword_buffer;
u32 count;
u32 i;
switch (original_object->common.type) {
case ACPI_TYPE_INTEGER:
/*
* Integer-to-Buffer conversion.
* Convert the Integer to a packed-byte buffer. _MAT and other
* objects need this sometimes, if a read has been performed on a
* Field object that is less than or equal to the global integer
* size (32 or 64 bits).
*/
status =
acpi_ex_convert_to_buffer(original_object, &new_object);
if (ACPI_FAILURE(status)) {
return (status);
}
break;
case ACPI_TYPE_STRING:
/* String-to-Buffer conversion. Simple data copy */
new_object =
acpi_ut_create_buffer_object(original_object->string.
length);
if (!new_object) {
return (AE_NO_MEMORY);
}
ACPI_MEMCPY(new_object->buffer.pointer,
original_object->string.pointer,
original_object->string.length);
break;
case ACPI_TYPE_PACKAGE:
/*
* This case is often seen for predefined names that must return a
* Buffer object with multiple DWORD integers within. For example,
* _FDE and _GTM. The Package can be converted to a Buffer.
*/
/* All elements of the Package must be integers */
elements = original_object->package.elements;
count = original_object->package.count;
for (i = 0; i < count; i++) {
if ((!*elements) ||
((*elements)->common.type != ACPI_TYPE_INTEGER)) {
return (AE_AML_OPERAND_TYPE);
}
elements++;
}
/* Create the new buffer object to replace the Package */
new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
if (!new_object) {
return (AE_NO_MEMORY);
}
/* Copy the package elements (integers) to the buffer as DWORDs */
elements = original_object->package.elements;
dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
for (i = 0; i < count; i++) {
*dword_buffer = (u32) (*elements)->integer.value;
dword_buffer++;
elements++;
}
break;
default:
return (AE_AML_OPERAND_TYPE);
}
*return_object = new_object;
return (AE_OK);
return (NULL); /* Name was not found in the repair table */
}
/*******************************************************************************

View file

@ -66,9 +66,9 @@ typedef struct acpi_repair_info {
/* Local prototypes */
static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
acpi_namespace_node
*node);
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
acpi_namespace_node
*node);
static acpi_status
acpi_ns_repair_ALR(struct acpi_predefined_data *data,
@ -175,7 +175,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
/* Check if this name is in the list of repairable names */
predefined = acpi_ns_match_repairable_name(node);
predefined = acpi_ns_match_complex_repair(node);
if (!predefined) {
return (validate_status);
}
@ -186,7 +186,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
/******************************************************************************
*
* FUNCTION: acpi_ns_match_repairable_name
* FUNCTION: acpi_ns_match_complex_repair
*
* PARAMETERS: node - Namespace node for the method/object
*
@ -196,9 +196,9 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
*
*****************************************************************************/
static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
acpi_namespace_node
*node)
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
acpi_namespace_node
*node)
{
const struct acpi_repair_info *this_name;

View file

@ -112,10 +112,10 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
if (!node) {
ACPI_WARNING((AE_INFO, "Null Node parameter"));
return_VALUE(ACPI_TYPE_ANY);
return_UINT8(ACPI_TYPE_ANY);
}
return_VALUE(node->type);
return_UINT8(node->type);
}
/*******************************************************************************
@ -140,10 +140,10 @@ u32 acpi_ns_local(acpi_object_type type)
/* Type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
return_VALUE(ACPI_NS_NORMAL);
return_UINT32(ACPI_NS_NORMAL);
}
return_VALUE(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
}
/*******************************************************************************

View file

@ -108,7 +108,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
/* Byte 0 is a special case, either bits [0:3] or [0:5] are used */
package_length |= (aml[0] & byte_zero_mask);
return_VALUE(package_length);
return_UINT32(package_length);
}
/*******************************************************************************

View file

@ -202,6 +202,12 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE);
}
/* Sanity check the length. It must not be zero, or we loop forever */
if (!resource->length) {
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
}
/* Get the base size of the (external stream) resource descriptor */
total_size = acpi_gbl_aml_resource_sizes[resource->type];

View file

@ -385,6 +385,14 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list)
return;
}
/* Sanity check the length. It must not be zero, or we loop forever */
if (!resource_list->length) {
acpi_os_printf
("Invalid zero length descriptor in resource list\n");
return;
}
/* Dump the resource descriptor */
if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {

View file

@ -178,6 +178,14 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
return_ACPI_STATUS(AE_BAD_DATA);
}
/* Sanity check the length. It must not be zero, or we loop forever */
if (!resource->length) {
ACPI_ERROR((AE_INFO,
"Invalid zero length descriptor in resource list\n"));
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
}
/* Perform the conversion */
if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {

View file

@ -563,13 +563,19 @@ acpi_walk_resource_buffer(struct acpi_buffer * buffer,
while (resource < resource_end) {
/* Sanity check the resource */
/* Sanity check the resource type */
if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
status = AE_AML_INVALID_RESOURCE_TYPE;
break;
}
/* Sanity check the length. It must not be zero, or we loop forever */
if (!resource->length) {
return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
}
/* Invoke the user function, abort on any error returned */
status = user_function(resource, context);

View file

@ -559,8 +559,12 @@ static void acpi_tb_validate_fadt(void)
/*
* For each extended field, check for length mismatch between the
* legacy length field and the corresponding 64-bit X length field.
* Note: If the legacy length field is > 0xFF bits, ignore this
* check. (GPE registers can be larger than the 64-bit GAS structure
* can accomodate, 0xFF bits).
*/
if (address64->address &&
(ACPI_MUL_8(length) <= ACPI_UINT8_MAX) &&
(address64->bit_width != ACPI_MUL_8(length))) {
ACPI_BIOS_WARNING((AE_INFO,
"32/64X length mismatch in FADT/%s: %u/%u",

View file

@ -1,6 +1,6 @@
/******************************************************************************
*
* Module Name: tbxface - ACPI table oriented external interfaces
* Module Name: tbxface - ACPI table-oriented external interfaces
*
*****************************************************************************/
@ -80,7 +80,7 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count)
* array is dynamically allocated.
* initial_table_count - Size of initial_table_array, in number of
* struct acpi_table_desc structures
* allow_realloc - Flag to tell Table Manager if resize of
* allow_resize - Flag to tell Table Manager if resize of
* pre-allocated array is allowed. Ignored
* if initial_table_array is NULL.
*
@ -107,8 +107,8 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
ACPI_FUNCTION_TRACE(acpi_initialize_tables);
/*
* Set up the Root Table Array
* Allocate the table array if requested
* Setup the Root Table Array and allocate the table array
* if requested
*/
if (!initial_table_array) {
status = acpi_allocate_root_table(initial_table_count);
@ -305,9 +305,10 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
* instance - Which instance (for SSDTs)
* out_table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to table
* RETURN: Status and pointer to the requested table
*
* DESCRIPTION: Finds and verifies an ACPI table.
* DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
* RSDT/XSDT.
*
******************************************************************************/
acpi_status
@ -375,9 +376,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
* PARAMETERS: table_index - Table index
* table - Where the pointer to the table is returned
*
* RETURN: Status and pointer to the table
* RETURN: Status and pointer to the requested table
*
* DESCRIPTION: Obtain a table by an index into the global table list.
* DESCRIPTION: Obtain a table by an index into the global table list. Used
* internally also.
*
******************************************************************************/
acpi_status
@ -432,7 +434,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
*
* RETURN: Status
*
* DESCRIPTION: Install table event handler
* DESCRIPTION: Install a global table event handler.
*
******************************************************************************/
acpi_status
@ -479,7 +481,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
*
* RETURN: Status
*
* DESCRIPTION: Remove table event handler
* DESCRIPTION: Remove a table event handler
*
******************************************************************************/
acpi_status acpi_remove_table_handler(acpi_table_handler handler)

View file

@ -214,7 +214,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
return_VALUE(0);
return_UINT32(0);
}
range_info = acpi_gbl_address_range_list[space_id];
@ -256,7 +256,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
range_info = range_info->next;
}
return_VALUE(overlap_count);
return_UINT32(overlap_count);
}
/*******************************************************************************

View file

@ -85,7 +85,6 @@ acpi_os_create_cache(char *cache_name,
/* Populate the cache object and return it */
ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list));
cache->link_offset = 8;
cache->list_name = cache_name;
cache->object_size = object_size;
cache->max_depth = max_depth;
@ -108,7 +107,7 @@ acpi_os_create_cache(char *cache_name,
acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
{
char *next;
void *next;
acpi_status status;
ACPI_FUNCTION_ENTRY();
@ -128,10 +127,7 @@ acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
/* Delete and unlink one cached state object */
next = *(ACPI_CAST_INDIRECT_PTR(char,
&(((char *)cache->
list_head)[cache->
link_offset])));
next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head);
ACPI_FREE(cache->list_head);
cache->list_head = next;
@ -221,10 +217,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object)
/* Put the object at the head of the cache list */
*(ACPI_CAST_INDIRECT_PTR(char,
&(((char *)object)[cache->
link_offset]))) =
cache->list_head;
ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head);
cache->list_head = object;
cache->current_depth++;
@ -272,10 +265,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
/* There is an object available, use it */
object = cache->list_head;
cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char,
&(((char *)
object)[cache->
link_offset])));
cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object);
cache->current_depth--;

View file

@ -359,19 +359,20 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
* FUNCTION: acpi_ut_update_ref_count
*
* PARAMETERS: object - Object whose ref count is to be updated
* action - What to do
* action - What to do (REF_INCREMENT or REF_DECREMENT)
*
* RETURN: New ref count
* RETURN: None. Sets new reference count within the object
*
* DESCRIPTION: Modify the ref count and return it.
* DESCRIPTION: Modify the reference count for an internal acpi object
*
******************************************************************************/
static void
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
{
u16 count;
u16 new_count;
u16 original_count;
u16 new_count = 0;
acpi_cpu_flags lock_flags;
ACPI_FUNCTION_NAME(ut_update_ref_count);
@ -379,76 +380,79 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
return;
}
count = object->common.reference_count;
new_count = count;
/*
* Perform the reference count action (increment, decrement, force delete)
* Always get the reference count lock. Note: Interpreter and/or
* Namespace is not always locked when this function is called.
*/
lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
original_count = object->common.reference_count;
/* Perform the reference count action (increment, decrement) */
switch (action) {
case REF_INCREMENT:
new_count++;
new_count = original_count + 1;
object->common.reference_count = new_count;
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
/* The current reference count should never be zero here */
if (!original_count) {
ACPI_WARNING((AE_INFO,
"Obj %p, Reference Count was zero before increment\n",
object));
}
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Refs=%X, [Incremented]\n",
object, new_count));
"Obj %p Type %.2X Refs %.2X [Incremented]\n",
object, object->common.type, new_count));
break;
case REF_DECREMENT:
if (count < 1) {
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Refs=%X, can't decrement! (Set to 0)\n",
object, new_count));
/* The current reference count must be non-zero */
new_count = 0;
} else {
new_count--;
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Refs=%X, [Decremented]\n",
object, new_count));
if (original_count) {
new_count = original_count - 1;
object->common.reference_count = new_count;
}
if (object->common.type == ACPI_TYPE_METHOD) {
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Method Obj %p Refs=%X, [Decremented]\n",
object, new_count));
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
if (!original_count) {
ACPI_WARNING((AE_INFO,
"Obj %p, Reference Count is already zero, cannot decrement\n",
object));
}
object->common.reference_count = new_count;
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Type %.2X Refs %.2X [Decremented]\n",
object, object->common.type, new_count));
/* Actually delete the object on a reference count of zero */
if (new_count == 0) {
acpi_ut_delete_internal_obj(object);
}
break;
case REF_FORCE_DELETE:
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Refs=%X, Force delete! (Set to 0)\n",
object, count));
new_count = 0;
object->common.reference_count = new_count;
acpi_ut_delete_internal_obj(object);
break;
default:
ACPI_ERROR((AE_INFO, "Unknown action (0x%X)", action));
break;
acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
action));
return;
}
/*
* Sanity check the reference count, for debug purposes only.
* (A deleted object will have a huge reference count)
*/
if (count > ACPI_MAX_REFERENCE_COUNT) {
if (new_count > ACPI_MAX_REFERENCE_COUNT) {
ACPI_WARNING((AE_INFO,
"Large Reference Count (0x%X) in object %p",
count, object));
"Large Reference Count (0x%X) in object %p, Type=0x%.2X",
new_count, object, object->common.type));
}
}
@ -458,8 +462,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
*
* PARAMETERS: object - Increment ref count for this object
* and all sub-objects
* action - Either REF_INCREMENT or REF_DECREMENT or
* REF_FORCE_DELETE
* action - Either REF_INCREMENT or REF_DECREMENT
*
* RETURN: Status
*
@ -714,7 +717,6 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
/*
* Allow a NULL pointer to be passed in, just ignore it. This saves
* each caller from having to check. Also, ignore NS nodes.
*
*/
if (!object ||
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {

View file

@ -64,7 +64,7 @@ ACPI_MODULE_NAME("utexcep")
******************************************************************************/
const char *acpi_format_exception(acpi_status status)
{
const char *exception = NULL;
const struct acpi_exception_info *exception;
ACPI_FUNCTION_ENTRY();
@ -76,10 +76,10 @@ const char *acpi_format_exception(acpi_status status)
ACPI_ERROR((AE_INFO,
"Unknown exception code: 0x%8.8X", status));
exception = "UNKNOWN_STATUS_CODE";
return ("UNKNOWN_STATUS_CODE");
}
return (ACPI_CAST_PTR(const char, exception));
return (exception->name);
}
ACPI_EXPORT_SYMBOL(acpi_format_exception)
@ -97,10 +97,10 @@ ACPI_EXPORT_SYMBOL(acpi_format_exception)
* an ASCII string.
*
******************************************************************************/
const char *acpi_ut_validate_exception(acpi_status status)
const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status status)
{
u32 sub_status;
const char *exception = NULL;
const struct acpi_exception_info *exception = NULL;
ACPI_FUNCTION_ENTRY();
@ -113,35 +113,35 @@ const char *acpi_ut_validate_exception(acpi_status status)
case AE_CODE_ENVIRONMENTAL:
if (sub_status <= AE_CODE_ENV_MAX) {
exception = acpi_gbl_exception_names_env[sub_status];
exception = &acpi_gbl_exception_names_env[sub_status];
}
break;
case AE_CODE_PROGRAMMER:
if (sub_status <= AE_CODE_PGM_MAX) {
exception = acpi_gbl_exception_names_pgm[sub_status];
exception = &acpi_gbl_exception_names_pgm[sub_status];
}
break;
case AE_CODE_ACPI_TABLES:
if (sub_status <= AE_CODE_TBL_MAX) {
exception = acpi_gbl_exception_names_tbl[sub_status];
exception = &acpi_gbl_exception_names_tbl[sub_status];
}
break;
case AE_CODE_AML:
if (sub_status <= AE_CODE_AML_MAX) {
exception = acpi_gbl_exception_names_aml[sub_status];
exception = &acpi_gbl_exception_names_aml[sub_status];
}
break;
case AE_CODE_CONTROL:
if (sub_status <= AE_CODE_CTRL_MAX) {
exception = acpi_gbl_exception_names_ctrl[sub_status];
exception = &acpi_gbl_exception_names_ctrl[sub_status];
}
break;
@ -149,5 +149,9 @@ const char *acpi_ut_validate_exception(acpi_status status)
break;
}
return (ACPI_CAST_PTR(const char, exception));
if (!exception || !exception->name) {
return (NULL);
}
return (exception);
}

View file

@ -359,6 +359,8 @@ acpi_status acpi_ut_init_globals(void)
#ifdef ACPI_DISASSEMBLER
acpi_gbl_external_list = NULL;
acpi_gbl_num_external_methods = 0;
acpi_gbl_resolved_external_methods = 0;
#endif
#ifdef ACPI_DEBUG_OUTPUT

View file

@ -81,7 +81,7 @@ acpi_status acpi_ut_mutex_initialize(void)
}
}
/* Create the spinlocks for use at interrupt level */
/* Create the spinlocks for use at interrupt level or for speed */
status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
if (ACPI_FAILURE (status)) {
@ -93,7 +93,13 @@ acpi_status acpi_ut_mutex_initialize(void)
return_ACPI_STATUS (status);
}
status = acpi_os_create_lock(&acpi_gbl_reference_count_lock);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Mutex for _OSI support */
status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@ -136,6 +142,7 @@ void acpi_ut_mutex_terminate(void)
acpi_os_delete_lock(acpi_gbl_gpe_lock);
acpi_os_delete_lock(acpi_gbl_hardware_lock);
acpi_os_delete_lock(acpi_gbl_reference_count_lock);
/* Delete the reader/writer lock */

View file

@ -108,9 +108,14 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
acpi_status acpi_ut_initialize_interfaces(void)
{
acpi_status status;
u32 i;
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
/* Link the static list of supported interfaces */
@ -132,20 +137,24 @@ acpi_status acpi_ut_initialize_interfaces(void)
*
* PARAMETERS: None
*
* RETURN: None
* RETURN: Status
*
* DESCRIPTION: Delete all interfaces in the global list. Sets
* acpi_gbl_supported_interfaces to NULL.
*
******************************************************************************/
void acpi_ut_interface_terminate(void)
acpi_status acpi_ut_interface_terminate(void)
{
acpi_status status;
struct acpi_interface_info *next_interface;
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
next_interface = acpi_gbl_supported_interfaces;
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
next_interface = acpi_gbl_supported_interfaces;
while (next_interface) {
acpi_gbl_supported_interfaces = next_interface->next;
@ -160,6 +169,7 @@ void acpi_ut_interface_terminate(void)
}
acpi_os_release_mutex(acpi_gbl_osi_mutex);
return (AE_OK);
}
/*******************************************************************************
@ -315,6 +325,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
union acpi_operand_object *return_desc;
struct acpi_interface_info *interface_info;
acpi_interface_handler interface_handler;
acpi_status status;
u32 return_value;
ACPI_FUNCTION_TRACE(ut_osi_implementation);
@ -336,7 +347,10 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
/* Default return value is 0, NOT SUPPORTED */
return_value = 0;
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
/* Lookup the interface in the global _OSI list */

View file

@ -0,0 +1,399 @@
/******************************************************************************
*
* Module Name: utpredef - support functions for predefined names
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acpredef.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utpredef")
/*
* Names for the types that can be returned by the predefined objects.
* Used for warning messages. Must be in the same order as the ACPI_RTYPEs
*/
static const char *ut_rtype_names[] = {
"/Integer",
"/String",
"/Buffer",
"/Package",
"/Reference",
};
/*******************************************************************************
*
* FUNCTION: acpi_ut_get_next_predefined_method
*
* PARAMETERS: this_name - Entry in the predefined method/name table
*
* RETURN: Pointer to next entry in predefined table.
*
* DESCRIPTION: Get the next entry in the predefine method table. Handles the
* cases where a package info entry follows a method name that
* returns a package.
*
******************************************************************************/
const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union
acpi_predefined_info
*this_name)
{
/*
* Skip next entry in the table if this name returns a Package
* (next entry contains the package info)
*/
if ((this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) &&
(this_name->info.expected_btypes != ACPI_RTYPE_ALL)) {
this_name++;
}
this_name++;
return (this_name);
}
/*******************************************************************************
*
* FUNCTION: acpi_ut_match_predefined_method
*
* PARAMETERS: name - Name to find
*
* RETURN: Pointer to entry in predefined table. NULL indicates not found.
*
* DESCRIPTION: Check an object name against the predefined object list.
*
******************************************************************************/
const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name)
{
const union acpi_predefined_info *this_name;
/* Quick check for a predefined name, first character must be underscore */
if (name[0] != '_') {
return (NULL);
}
/* Search info table for a predefined method/object name */
this_name = acpi_gbl_predefined_methods;
while (this_name->info.name[0]) {
if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
return (this_name);
}
this_name = acpi_ut_get_next_predefined_method(this_name);
}
return (NULL); /* Not found */
}
/*******************************************************************************
*
* FUNCTION: acpi_ut_get_expected_return_types
*
* PARAMETERS: buffer - Where the formatted string is returned
* expected_Btypes - Bitfield of expected data types
*
* RETURN: Formatted string in Buffer.
*
* DESCRIPTION: Format the expected object types into a printable string.
*
******************************************************************************/
void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes)
{
u32 this_rtype;
u32 i;
u32 j;
j = 1;
buffer[0] = 0;
this_rtype = ACPI_RTYPE_INTEGER;
for (i = 0; i < ACPI_NUM_RTYPES; i++) {
/* If one of the expected types, concatenate the name of this type */
if (expected_btypes & this_rtype) {
ACPI_STRCAT(buffer, &ut_rtype_names[i][j]);
j = 0; /* Use name separator from now on */
}
this_rtype <<= 1; /* Next Rtype */
}
}
/*******************************************************************************
*
* The remaining functions are used by iASL and acpi_help only
*
******************************************************************************/
#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP)
#include <stdio.h>
#include <string.h>
/* Local prototypes */
static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types);
/* Types that can be returned externally by a predefined name */
static const char *ut_external_type_names[] = /* Indexed by ACPI_TYPE_* */
{
", UNSUPPORTED-TYPE",
", Integer",
", String",
", Buffer",
", Package"
};
/* Bit widths for resource descriptor predefined names */
static const char *ut_resource_type_names[] = {
"/1",
"/2",
"/3",
"/8",
"/16",
"/32",
"/64",
"/variable",
};
/*******************************************************************************
*
* FUNCTION: acpi_ut_match_resource_name
*
* PARAMETERS: name - Name to find
*
* RETURN: Pointer to entry in the resource table. NULL indicates not
* found.
*
* DESCRIPTION: Check an object name against the predefined resource
* descriptor object list.
*
******************************************************************************/
const union acpi_predefined_info *acpi_ut_match_resource_name(char *name)
{
const union acpi_predefined_info *this_name;
/* Quick check for a predefined name, first character must be underscore */
if (name[0] != '_') {
return (NULL);
}
/* Search info table for a predefined method/object name */
this_name = acpi_gbl_resource_names;
while (this_name->info.name[0]) {
if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
return (this_name);
}
this_name++;
}
return (NULL); /* Not found */
}
/*******************************************************************************
*
* FUNCTION: acpi_ut_display_predefined_method
*
* PARAMETERS: buffer - Scratch buffer for this function
* this_name - Entry in the predefined method/name table
* multi_line - TRUE if output should be on >1 line
*
* RETURN: None
*
* DESCRIPTION: Display information about a predefined method. Number and
* type of the input arguments, and expected type(s) for the
* return value, if any.
*
******************************************************************************/
void
acpi_ut_display_predefined_method(char *buffer,
const union acpi_predefined_info *this_name,
u8 multi_line)
{
u32 arg_count;
/*
* Get the argument count and the string buffer
* containing all argument types
*/
arg_count = acpi_ut_get_argument_types(buffer,
this_name->info.argument_list);
if (multi_line) {
printf(" ");
}
printf("%4.4s Requires %s%u argument%s",
this_name->info.name,
(this_name->info.argument_list & ARG_COUNT_IS_MINIMUM) ?
"(at least) " : "", arg_count, arg_count != 1 ? "s" : "");
/* Display the types for any arguments */
if (arg_count > 0) {
printf(" (%s)", buffer);
}
if (multi_line) {
printf("\n ");
}
/* Get the return value type(s) allowed */
if (this_name->info.expected_btypes) {
acpi_ut_get_expected_return_types(buffer,
this_name->info.
expected_btypes);
printf(" Return value types: %s\n", buffer);
} else {
printf(" No return value\n");
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ut_get_argument_types
*
* PARAMETERS: buffer - Where to return the formatted types
* argument_types - Types field for this method
*
* RETURN: count - the number of arguments required for this method
*
* DESCRIPTION: Format the required data types for this method (Integer,
* String, Buffer, or Package) and return the required argument
* count.
*
******************************************************************************/
static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
{
u16 this_argument_type;
u16 sub_index;
u16 arg_count;
u32 i;
*buffer = 0;
sub_index = 2;
/* First field in the types list is the count of args to follow */
arg_count = (argument_types & METHOD_ARG_MASK);
argument_types >>= METHOD_ARG_BIT_WIDTH;
if (arg_count > METHOD_PREDEF_ARGS_MAX) {
printf("**** Invalid argument count (%u) "
"in predefined info structure\n", arg_count);
return (arg_count);
}
/* Get each argument from the list, convert to ascii, store to buffer */
for (i = 0; i < arg_count; i++) {
this_argument_type = (argument_types & METHOD_ARG_MASK);
if (!this_argument_type
|| (this_argument_type > METHOD_MAX_ARG_TYPE)) {
printf("**** Invalid argument type (%u) "
"in predefined info structure\n",
this_argument_type);
return (arg_count);
}
strcat(buffer,
ut_external_type_names[this_argument_type] + sub_index);
/* Shift to next argument type field */
argument_types >>= METHOD_ARG_BIT_WIDTH;
sub_index = 0;
}
return (arg_count);
}
/*******************************************************************************
*
* FUNCTION: acpi_ut_get_resource_bit_width
*
* PARAMETERS: buffer - Where the formatted string is returned
* types - Bitfield of expected data types
*
* RETURN: Count of return types. Formatted string in Buffer.
*
* DESCRIPTION: Format the resource bit widths into a printable string.
*
******************************************************************************/
u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types)
{
u32 i;
u16 sub_index;
u32 found;
*buffer = 0;
sub_index = 1;
found = 0;
for (i = 0; i < NUM_RESOURCE_WIDTHS; i++) {
if (types & 1) {
strcat(buffer, &(ut_resource_type_names[i][sub_index]));
sub_index = 0;
found++;
}
types >>= 1;
}
return (found);
}
#endif

View file

@ -287,7 +287,10 @@ acpi_status acpi_install_interface(acpi_string interface_name)
return (AE_BAD_PARAMETER);
}
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
/* Check if the interface name is already in the global list */
@ -336,7 +339,10 @@ acpi_status acpi_remove_interface(acpi_string interface_name)
return (AE_BAD_PARAMETER);
}
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
status = acpi_ut_remove_interface(interface_name);
@ -362,9 +368,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_interface)
****************************************************************************/
acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
{
acpi_status status = AE_OK;
acpi_status status;
(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
return (status);
}
if (handler && acpi_gbl_interface_handler) {
status = AE_ALREADY_EXISTS;

View file

@ -146,7 +146,7 @@ struct acpi_battery {
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat)
inline int acpi_battery_present(struct acpi_battery *battery)
static inline int acpi_battery_present(struct acpi_battery *battery)
{
return battery->device->status.battery_present;
}

View file

@ -288,13 +288,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
}
out_success:
context->ret.length = out_obj->buffer.length;
context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
context->ret.pointer = kmemdup(out_obj->buffer.pointer,
context->ret.length, GFP_KERNEL);
if (!context->ret.pointer) {
status = AE_NO_MEMORY;
goto out_kfree;
}
memcpy(context->ret.pointer, out_obj->buffer.pointer,
context->ret.length);
status = AE_OK;
out_kfree:

View file

@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/button.h>
#define PREFIX "ACPI: "

View file

@ -1,12 +1,12 @@
/*
* acpi_container.c - ACPI Generic Container Driver
* ($Revision: )
* container.c - ACPI Generic Container Driver
*
* Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
* Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
* Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
* Copyright (C) 2004 Intel Corp.
* Copyright (C) 2004 FUJITSU LIMITED
* Copyright (C) 2004, 2013 Intel Corp.
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@ -26,14 +26,11 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
#include "internal.h"
#define PREFIX "ACPI: "
@ -50,141 +47,20 @@ static const struct acpi_device_id container_device_ids[] = {
static int container_device_attach(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
/*
* FIXME: This is necessary, so that acpi_eject_store() doesn't return
* -ENODEV for containers.
*/
/* This is necessary for container hotplug to work. */
return 1;
}
static struct acpi_scan_handler container_device_handler = {
static struct acpi_scan_handler container_handler = {
.ids = container_device_ids,
.attach = container_device_attach,
.hotplug = {
.enabled = true,
.mode = AHM_CONTAINER,
},
};
static int is_device_present(acpi_handle handle)
{
acpi_handle temp;
acpi_status status;
unsigned long long sta;
status = acpi_get_handle(handle, "_STA", &temp);
if (ACPI_FAILURE(status))
return 1; /* _STA not found, assume device present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return 0; /* Firmware error */
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
}
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
{
struct acpi_device *device = NULL;
int result;
int present;
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
acpi_scan_lock_acquire();
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* Fall through */
case ACPI_NOTIFY_DEVICE_CHECK:
pr_debug("Container driver received %s event\n",
(type == ACPI_NOTIFY_BUS_CHECK) ?
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
present = is_device_present(handle);
status = acpi_bus_get_device(handle, &device);
if (!present) {
if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
goto out;
}
break;
}
if (!ACPI_FAILURE(status) || device)
break;
result = acpi_bus_scan(handle);
if (result) {
acpi_handle_warn(handle, "Failed to add container\n");
break;
}
result = acpi_bus_get_device(handle, &device);
if (result) {
acpi_handle_warn(handle, "Missing device object\n");
break;
}
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
ost_code = ACPI_OST_SC_SUCCESS;
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
goto out;
}
break;
default:
/* non-hotplug event; possibly handled by other handler */
goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
out:
acpi_scan_lock_release();
}
static bool is_container(acpi_handle handle)
{
struct acpi_device_info *info;
bool ret = false;
if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
return false;
if (info->valid & ACPI_VALID_HID) {
const struct acpi_device_id *id;
for (id = container_device_ids; id->id[0]; id++) {
ret = !strcmp((char *)id->id, info->hardware_id.string);
if (ret)
break;
}
}
kfree(info);
return ret;
}
static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
u32 lvl, void *ctxt,
void **retv)
{
if (is_container(handle))
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
container_notify_cb, NULL);
return AE_OK;
}
void __init acpi_container_init(void)
{
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
acpi_container_register_notify_handler, NULL,
NULL, NULL);
acpi_scan_add_handler(&container_device_handler);
acpi_scan_add_handler_with_hotplug(&container_handler, "container");
}

View file

@ -145,27 +145,36 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
}
/*
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
* Get the device's power state from power resources settings and _PSC,
* if available.
*/
if (device->power.flags.explicit_get) {
unsigned long long psc;
acpi_status status = acpi_evaluate_integer(device->handle,
"_PSC", NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
result = psc;
}
/* The test below covers ACPI_STATE_UNKNOWN too. */
if (result <= ACPI_STATE_D2) {
; /* Do nothing. */
} else if (device->power.flags.power_resources) {
if (device->power.flags.power_resources) {
int error = acpi_power_get_inferred_state(device, &result);
if (error)
return error;
} else if (result == ACPI_STATE_D3_HOT) {
result = ACPI_STATE_D3;
}
if (device->power.flags.explicit_get) {
acpi_handle handle = device->handle;
unsigned long long psc;
acpi_status status;
status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
/*
* The power resources settings may indicate a power state
* shallower than the actual power state of the device.
*
* Moreover, on systems predating ACPI 4.0, if the device
* doesn't depend on any power resources and _PSC returns 3,
* that means "power off". We need to maintain compatibility
* with those systems.
*/
if (psc > result && psc < ACPI_STATE_D3_COLD)
result = psc;
else if (result == ACPI_STATE_UNKNOWN)
result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
}
/*

View file

@ -174,9 +174,13 @@ static int acpi_fan_add(struct acpi_device *device)
static int acpi_fan_remove(struct acpi_device *device)
{
struct thermal_cooling_device *cdev = acpi_driver_data(device);
struct thermal_cooling_device *cdev;
if (!device || !cdev)
if (!device)
return -EINVAL;
cdev = acpi_driver_data(device);
if (!cdev)
return -EINVAL;
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");

View file

@ -41,6 +41,17 @@ void acpi_container_init(void);
#else
static inline void acpi_container_init(void) {}
#endif
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
void acpi_memory_hotplug_init(void);
#else
static inline void acpi_memory_hotplug_init(void) {}
#endif
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
const char *name);
int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
const char *hotplug_profile_name);
void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
#ifdef CONFIG_DEBUG_FS
extern struct dentry *acpi_debugfs_dir;
@ -48,6 +59,11 @@ int acpi_debugfs_init(void);
#else
static inline void acpi_debugfs_init(void) { return; }
#endif
#ifdef CONFIG_X86_INTEL_LPSS
void acpi_lpss_init(void);
#else
static inline void acpi_lpss_init(void) {}
#endif
/* --------------------------------------------------------------------------
Device Node Initialization / Removal
@ -60,7 +76,7 @@ int acpi_device_add(struct acpi_device *device,
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta);
void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_ids(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
/* --------------------------------------------------------------------------
Power Resource
@ -131,4 +147,7 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;
int acpi_create_platform_device(struct acpi_device *adev,
const struct acpi_device_id *id);
#endif /* _ACPI_INTERNAL_H_ */

View file

@ -641,7 +641,7 @@ void __init acpi_initrd_override(void *data, size_t size)
* Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
* works fine.
*/
memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size);
memblock_reserve(acpi_tables_addr, all_tables_size);
arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
p = early_ioremap(acpi_tables_addr, all_tables_size);
@ -1555,7 +1555,7 @@ int acpi_check_resource_conflict(const struct resource *res)
else
space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
length = res->end - res->start + 1;
length = resource_size(res);
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO)
warn = 1;
clash = acpi_check_address_range(space_id, res->start, length, warn);

View file

@ -354,6 +354,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
}
resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
resource->end.length = sizeof(struct acpi_resource);
/* Attempt to set the resource */
status = acpi_set_current_resources(link->device->handle, &buffer);

View file

@ -169,8 +169,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
*control &= OSC_PCI_CONTROL_MASKS;
capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
} else {
/* Run _OSC query for all possible controls. */
capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
/* Run _OSC query only with existing controls. */
capbuf[OSC_CONTROL_TYPE] = root->osc_control_set;
}
status = acpi_pci_run_osc(root->device->handle, capbuf, &result);

View file

@ -459,57 +459,79 @@ static struct attribute_group attr_groups[] = {
},
};
static void acpi_power_hide_list(struct acpi_device *adev, int state)
static struct attribute_group wakeup_attr_group = {
.name = "power_resources_wakeup",
.attrs = attrs,
};
static void acpi_power_hide_list(struct acpi_device *adev,
struct list_head *resources,
struct attribute_group *attr_group)
{
struct acpi_device_power_state *ps = &adev->power.states[state];
struct acpi_power_resource_entry *entry;
if (list_empty(&ps->resources))
if (list_empty(resources))
return;
list_for_each_entry_reverse(entry, &ps->resources, node) {
list_for_each_entry_reverse(entry, resources, node) {
struct acpi_device *res_dev = &entry->resource->device;
sysfs_remove_link_from_group(&adev->dev.kobj,
attr_groups[state].name,
attr_group->name,
dev_name(&res_dev->dev));
}
sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
sysfs_remove_group(&adev->dev.kobj, attr_group);
}
static void acpi_power_expose_list(struct acpi_device *adev, int state)
static void acpi_power_expose_list(struct acpi_device *adev,
struct list_head *resources,
struct attribute_group *attr_group)
{
struct acpi_device_power_state *ps = &adev->power.states[state];
struct acpi_power_resource_entry *entry;
int ret;
if (list_empty(&ps->resources))
if (list_empty(resources))
return;
ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
ret = sysfs_create_group(&adev->dev.kobj, attr_group);
if (ret)
return;
list_for_each_entry(entry, &ps->resources, node) {
list_for_each_entry(entry, resources, node) {
struct acpi_device *res_dev = &entry->resource->device;
ret = sysfs_add_link_to_group(&adev->dev.kobj,
attr_groups[state].name,
attr_group->name,
&res_dev->dev.kobj,
dev_name(&res_dev->dev));
if (ret) {
acpi_power_hide_list(adev, state);
acpi_power_hide_list(adev, resources, attr_group);
break;
}
}
}
static void acpi_power_expose_hide(struct acpi_device *adev,
struct list_head *resources,
struct attribute_group *attr_group,
bool expose)
{
if (expose)
acpi_power_expose_list(adev, resources, attr_group);
else
acpi_power_hide_list(adev, resources, attr_group);
}
void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
{
struct acpi_device_power_state *ps;
struct acpi_power_resource_entry *entry;
int state;
if (adev->wakeup.flags.valid)
acpi_power_expose_hide(adev, &adev->wakeup.resources,
&wakeup_attr_group, add);
if (!adev->power.flags.power_resources)
return;
@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
acpi_power_remove_dependent(resource, adev);
}
for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
if (add)
acpi_power_expose_list(adev, state);
else
acpi_power_hide_list(adev, state);
}
for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
acpi_power_expose_hide(adev,
&adev->power.states[state].resources,
&attr_groups[state], add);
}
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
@ -824,7 +844,7 @@ static void acpi_release_power_resource(struct device *dev)
list_del(&resource->list_node);
mutex_unlock(&power_resource_list_lock);
acpi_free_ids(device);
acpi_free_pnp_ids(&device->pnp);
kfree(resource);
}

View file

@ -918,7 +918,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
struct cpuidle_driver acpi_idle_driver = {
.name = "acpi_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
};
/**

View file

@ -218,9 +218,13 @@ processor_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
struct acpi_processor *pr;
if (!device || !pr)
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
*state = acpi_processor_max_state(pr);
@ -232,9 +236,13 @@ processor_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
struct acpi_processor *pr;
if (!device || !pr)
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
*cur_state = cpufreq_get_cur_state(pr->id);
@ -248,11 +256,15 @@ processor_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
struct acpi_processor *pr;
int result = 0;
int max_pstate;
if (!device || !pr)
if (!device)
return -EINVAL;
pr = acpi_driver_data(device);
if (!pr)
return -EINVAL;
max_pstate = cpufreq_get_max_state(pr->id);

View file

@ -211,9 +211,10 @@ err_ret:
*/
void acpi_processor_throttling_init(void)
{
if (acpi_processor_update_tsd_coord())
if (acpi_processor_update_tsd_coord()) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Assume no T-state coordination\n"));
}
return;
}

View file

@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler)
return 0;
}
int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
const char *hotplug_profile_name)
{
int error;
error = acpi_scan_add_handler(handler);
if (error)
return error;
acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
return 0;
}
/*
* Creates hid/cid(s) string needed for modalias and uevent
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@ -107,32 +120,20 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
/**
* acpi_bus_hot_remove_device: hot-remove a device and its children
* @context: struct acpi_eject_event pointer (freed in this func)
*
* Hot-remove a device and its children. This function frees up the
* memory space passed by arg context, so that the caller may call
* this function asynchronously through acpi_os_hotplug_execute().
*/
void acpi_bus_hot_remove_device(void *context)
static int acpi_scan_hot_remove(struct acpi_device *device)
{
struct acpi_eject_event *ej_event = context;
struct acpi_device *device = ej_event->device;
acpi_handle handle = device->handle;
acpi_handle temp;
acpi_handle not_used;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
mutex_lock(&acpi_scan_lock);
acpi_status status;
unsigned long long sta;
/* If there is no handle, the device node has been unregistered. */
if (!device->handle) {
if (!handle) {
dev_dbg(&device->dev, "ACPI handle missing\n");
put_device(&device->dev);
goto out;
return -EINVAL;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@ -143,7 +144,7 @@ void acpi_bus_hot_remove_device(void *context)
put_device(&device->dev);
device = NULL;
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
@ -161,18 +162,205 @@ void acpi_bus_hot_remove_device(void *context)
*/
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
acpi_handle_warn(handle, "Eject failed\n");
if (status == AE_NOT_FOUND) {
return -ENODEV;
} else {
acpi_handle_warn(handle, "Eject failed (0x%x)\n",
status);
return -EIO;
}
}
/* Tell the firmware the hot-remove operation has failed. */
acpi_evaluate_hotplug_ost(handle, ej_event->event,
ost_code, NULL);
/*
* Verify if eject was indeed successful. If not, log an error
* message. No need to call _OST since _EJ0 call was made OK.
*/
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status)) {
acpi_handle_warn(handle,
"Status check after eject failed (0x%x)\n", status);
} else if (sta & ACPI_STA_DEVICE_ENABLED) {
acpi_handle_warn(handle,
"Eject incomplete - status 0x%llx\n", sta);
}
return 0;
}
static void acpi_bus_device_eject(void *context)
{
acpi_handle handle = context;
struct acpi_device *device = NULL;
struct acpi_scan_handler *handler;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
mutex_lock(&acpi_scan_lock);
acpi_bus_get_device(handle, &device);
if (!device)
goto err_out;
handler = device->handler;
if (!handler || !handler->hotplug.enabled) {
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out;
}
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
if (handler->hotplug.mode == AHM_CONTAINER) {
device->flags.eject_pending = true;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
} else {
int error;
get_device(&device->dev);
error = acpi_scan_hot_remove(device);
if (error)
goto err_out;
}
out:
mutex_unlock(&acpi_scan_lock);
kfree(context);
return;
err_out:
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
NULL);
goto out;
}
static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
{
struct acpi_device *device = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
int error;
mutex_lock(&acpi_scan_lock);
acpi_bus_get_device(handle, &device);
if (device) {
dev_warn(&device->dev, "Attempt to re-insert\n");
goto out;
}
acpi_evaluate_hotplug_ost(handle, ost_source,
ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
error = acpi_bus_scan(handle);
if (error) {
acpi_handle_warn(handle, "Namespace scan failure\n");
goto out;
}
error = acpi_bus_get_device(handle, &device);
if (error) {
acpi_handle_warn(handle, "Missing device node object\n");
goto out;
}
ost_code = ACPI_OST_SC_SUCCESS;
if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
out:
acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
mutex_unlock(&acpi_scan_lock);
}
static void acpi_scan_bus_check(void *context)
{
acpi_scan_bus_device_check((acpi_handle)context,
ACPI_NOTIFY_BUS_CHECK);
}
static void acpi_scan_device_check(void *context)
{
acpi_scan_bus_device_check((acpi_handle)context,
ACPI_NOTIFY_DEVICE_CHECK);
}
static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
{
u32 ost_status;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle,
"ACPI_NOTIFY_BUS_CHECK event: unsupported\n");
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle,
"ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n");
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
break;
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle,
"ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n");
ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
break;
default:
/* non-hotplug event; possibly handled by other handler */
return;
}
acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL);
}
static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
{
acpi_osd_exec_callback callback;
struct acpi_scan_handler *handler = data;
acpi_status status;
if (!handler->hotplug.enabled)
return acpi_hotplug_unsupported(handle, type);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
callback = acpi_scan_bus_check;
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
callback = acpi_scan_device_check;
break;
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
callback = acpi_bus_device_eject;
break;
default:
/* non-hotplug event; possibly handled by other handler */
return;
}
status = acpi_os_hotplug_execute(callback, handle);
if (ACPI_FAILURE(status))
acpi_evaluate_hotplug_ost(handle, type,
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
NULL);
}
/**
* acpi_bus_hot_remove_device: hot-remove a device and its children
* @context: struct acpi_eject_event pointer (freed in this func)
*
* Hot-remove a device and its children. This function frees up the
* memory space passed by arg context, so that the caller may call
* this function asynchronously through acpi_os_hotplug_execute().
*/
void acpi_bus_hot_remove_device(void *context)
{
struct acpi_eject_event *ej_event = context;
struct acpi_device *device = ej_event->device;
acpi_handle handle = device->handle;
int error;
mutex_lock(&acpi_scan_lock);
error = acpi_scan_hot_remove(device);
if (error && handle)
acpi_evaluate_hotplug_ost(handle, ej_event->event,
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
NULL);
mutex_unlock(&acpi_scan_lock);
kfree(context);
}
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
@ -206,51 +394,61 @@ static ssize_t
acpi_eject_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = count;
acpi_status status;
acpi_object_type type = 0;
struct acpi_device *acpi_device = to_acpi_device(d);
struct acpi_eject_event *ej_event;
acpi_object_type not_used;
acpi_status status;
u32 ost_source;
int ret;
if ((!count) || (buf[0] != '1')) {
if (!count || buf[0] != '1')
return -EINVAL;
}
if (!acpi_device->driver && !acpi_device->handler) {
ret = -ENODEV;
goto err;
}
status = acpi_get_type(acpi_device->handle, &type);
if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
ret = -ENODEV;
goto err;
}
if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
&& !acpi_device->driver)
return -ENODEV;
status = acpi_get_type(acpi_device->handle, &not_used);
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
return -ENODEV;
mutex_lock(&acpi_scan_lock);
if (acpi_device->flags.eject_pending) {
/* ACPI eject notification event. */
ost_source = ACPI_NOTIFY_EJECT_REQUEST;
acpi_device->flags.eject_pending = 0;
} else {
/* Eject initiated by user space. */
ost_source = ACPI_OST_EC_OSPM_EJECT;
}
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
ret = -ENOMEM;
goto err;
goto err_out;
}
get_device(&acpi_device->dev);
acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
ej_event->device = acpi_device;
if (acpi_device->flags.eject_pending) {
/* event originated from ACPI eject notification */
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
acpi_device->flags.eject_pending = 0;
} else {
/* event originated from user */
ej_event->event = ACPI_OST_EC_OSPM_EJECT;
(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
}
ej_event->event = ost_source;
get_device(&acpi_device->dev);
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
if (ACPI_FAILURE(status)) {
put_device(&acpi_device->dev);
kfree(ej_event);
ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
goto err_out;
}
err:
ret = count;
out:
mutex_unlock(&acpi_scan_lock);
return ret;
err_out:
acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
goto out;
}
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@ -376,7 +574,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
if (dev->flags.bus_address)
if (dev->pnp.type.bus_address)
result = device_create_file(&dev->dev, &dev_attr_adr);
if (dev->pnp.unique_id)
result = device_create_file(&dev->dev, &dev_attr_uid);
@ -449,7 +647,7 @@ static void acpi_device_remove_files(struct acpi_device *dev)
if (dev->pnp.unique_id)
device_remove_file(&dev->dev, &dev_attr_uid);
if (dev->flags.bus_address)
if (dev->pnp.type.bus_address)
device_remove_file(&dev->dev, &dev_attr_adr);
device_remove_file(&dev->dev, &dev_attr_modalias);
device_remove_file(&dev->dev, &dev_attr_hid);
@ -512,17 +710,6 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
void acpi_free_ids(struct acpi_device *device)
{
struct acpi_hardware_id *id, *tmp;
list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
kfree(id->id);
kfree(id);
}
kfree(device->pnp.unique_id);
}
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
@ -543,7 +730,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
acpi_free_ids(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
}
@ -1256,19 +1443,17 @@ static void acpi_device_get_busid(struct acpi_device *device)
}
/*
* acpi_bay_match - see if a device is an ejectable driver bay
* acpi_bay_match - see if an acpi object is an ejectable driver bay
*
* If an acpi object is ejectable and has one of the ACPI ATA methods defined,
* then we can safely call it an ejectable drive bay
*/
static int acpi_bay_match(struct acpi_device *device){
static int acpi_bay_match(acpi_handle handle)
{
acpi_status status;
acpi_handle handle;
acpi_handle tmp;
acpi_handle phandle;
handle = device->handle;
status = acpi_get_handle(handle, "_EJ0", &tmp);
if (ACPI_FAILURE(status))
return -ENODEV;
@ -1292,12 +1477,12 @@ static int acpi_bay_match(struct acpi_device *device){
}
/*
* acpi_dock_match - see if a device has a _DCK method
* acpi_dock_match - see if an acpi object has a _DCK method
*/
static int acpi_dock_match(struct acpi_device *device)
static int acpi_dock_match(acpi_handle handle)
{
acpi_handle tmp;
return acpi_get_handle(device->handle, "_DCK", &tmp);
return acpi_get_handle(handle, "_DCK", &tmp);
}
const char *acpi_device_hid(struct acpi_device *device)
@ -1312,7 +1497,7 @@ const char *acpi_device_hid(struct acpi_device *device)
}
EXPORT_SYMBOL(acpi_device_hid);
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
{
struct acpi_hardware_id *id;
@ -1326,7 +1511,8 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
return;
}
list_add_tail(&id->list, &device->pnp.ids);
list_add_tail(&id->list, &pnp->ids);
pnp->type.hardware_id = 1;
}
/*
@ -1334,7 +1520,7 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
* lacks the SMBUS01 HID and the methods do not have the necessary "_"
* prefix. Work around this.
*/
static int acpi_ibm_smbus_match(struct acpi_device *device)
static int acpi_ibm_smbus_match(acpi_handle handle)
{
acpi_handle h_dummy;
struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
@ -1344,7 +1530,7 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
return -ENODEV;
/* Look for SMBS object */
result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
if (result)
return result;
@ -1355,48 +1541,50 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
/* Does it have the necessary (but misnamed) methods? */
result = -ENODEV;
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
result = 0;
out:
kfree(path.pointer);
return result;
}
static void acpi_device_set_id(struct acpi_device *device)
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
int device_type)
{
acpi_status status;
struct acpi_device_info *info;
struct acpi_pnp_device_id_list *cid_list;
int i;
switch (device->device_type) {
switch (device_type) {
case ACPI_BUS_TYPE_DEVICE:
if (ACPI_IS_ROOT_DEVICE(device)) {
acpi_add_id(device, ACPI_SYSTEM_HID);
if (handle == ACPI_ROOT_OBJECT) {
acpi_add_id(pnp, ACPI_SYSTEM_HID);
break;
}
status = acpi_get_object_info(device->handle, &info);
status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
pr_err(PREFIX "%s: Error reading device info\n",
__func__);
return;
}
if (info->valid & ACPI_VALID_HID)
acpi_add_id(device, info->hardware_id.string);
acpi_add_id(pnp, info->hardware_id.string);
if (info->valid & ACPI_VALID_CID) {
cid_list = &info->compatible_id_list;
for (i = 0; i < cid_list->count; i++)
acpi_add_id(device, cid_list->ids[i].string);
acpi_add_id(pnp, cid_list->ids[i].string);
}
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
pnp->bus_address = info->address;
pnp->type.bus_address = 1;
}
if (info->valid & ACPI_VALID_UID)
device->pnp.unique_id = kstrdup(info->unique_id.string,
pnp->unique_id = kstrdup(info->unique_id.string,
GFP_KERNEL);
kfree(info);
@ -1405,40 +1593,50 @@ static void acpi_device_set_id(struct acpi_device *device)
* Some devices don't reliably have _HIDs & _CIDs, so add
* synthetic HIDs to make sure drivers can find them.
*/
if (acpi_is_video_device(device))
acpi_add_id(device, ACPI_VIDEO_HID);
else if (ACPI_SUCCESS(acpi_bay_match(device)))
acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device)))
acpi_add_id(device, ACPI_DOCK_HID);
else if (!acpi_ibm_smbus_match(device))
acpi_add_id(device, ACPI_SMBUS_IBM_HID);
else if (list_empty(&device->pnp.ids) &&
ACPI_IS_ROOT_DEVICE(device->parent)) {
acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
if (acpi_is_video_device(handle))
acpi_add_id(pnp, ACPI_VIDEO_HID);
else if (ACPI_SUCCESS(acpi_bay_match(handle)))
acpi_add_id(pnp, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(handle)))
acpi_add_id(pnp, ACPI_DOCK_HID);
else if (!acpi_ibm_smbus_match(handle))
acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
strcpy(pnp->device_class, ACPI_BUS_CLASS);
}
break;
case ACPI_BUS_TYPE_POWER:
acpi_add_id(device, ACPI_POWER_HID);
acpi_add_id(pnp, ACPI_POWER_HID);
break;
case ACPI_BUS_TYPE_PROCESSOR:
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID);
break;
case ACPI_BUS_TYPE_THERMAL:
acpi_add_id(device, ACPI_THERMAL_HID);
acpi_add_id(pnp, ACPI_THERMAL_HID);
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
break;
}
}
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
{
struct acpi_hardware_id *id, *tmp;
list_for_each_entry_safe(id, tmp, &pnp->ids, list) {
kfree(id->id);
kfree(id);
}
kfree(pnp->unique_id);
}
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta)
{
@ -1448,7 +1646,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->parent = acpi_bus_get_parent(handle);
STRUCT_TO_INT(device->status) = sta;
acpi_device_get_busid(device);
acpi_device_set_id(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device_initialize(&device->dev);
@ -1536,6 +1734,75 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
return 0;
}
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
char *idstr,
const struct acpi_device_id **matchid)
{
const struct acpi_device_id *devid;
for (devid = handler->ids; devid->id[0]; devid++)
if (!strcmp((char *)devid->id, idstr)) {
if (matchid)
*matchid = devid;
return true;
}
return false;
}
static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
const struct acpi_device_id **matchid)
{
struct acpi_scan_handler *handler;
list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
if (acpi_scan_handler_matching(handler, idstr, matchid))
return handler;
return NULL;
}
void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
{
if (!!hotplug->enabled == !!val)
return;
mutex_lock(&acpi_scan_lock);
hotplug->enabled = val;
mutex_unlock(&acpi_scan_lock);
}
static void acpi_scan_init_hotplug(acpi_handle handle, int type)
{
struct acpi_device_pnp pnp = {};
struct acpi_hardware_id *hwid;
struct acpi_scan_handler *handler;
INIT_LIST_HEAD(&pnp.ids);
acpi_set_pnp_ids(handle, &pnp, type);
if (!pnp.type.hardware_id)
return;
/*
* This relies on the fact that acpi_install_notify_handler() will not
* install the same notify handler routine twice for the same handle.
*/
list_for_each_entry(hwid, &pnp.ids, list) {
handler = acpi_scan_match_handler(hwid->id, NULL);
if (handler) {
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_hotplug_notify_cb, handler);
break;
}
}
acpi_free_pnp_ids(&pnp);
}
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
@ -1558,6 +1825,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
acpi_scan_init_hotplug(handle, type);
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
struct acpi_device_wakeup wakeup;
@ -1583,41 +1852,25 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
{
struct acpi_scan_handler *handler;
list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
const struct acpi_device_id *devid;
for (devid = handler->ids; devid->id[0]; devid++) {
int ret;
if (strcmp((char *)devid->id, id))
continue;
ret = handler->attach(device, devid);
if (ret > 0) {
device->handler = handler;
return ret;
} else if (ret < 0) {
return ret;
}
}
}
return 0;
}
static int acpi_scan_attach_handler(struct acpi_device *device)
{
struct acpi_hardware_id *hwid;
int ret = 0;
list_for_each_entry(hwid, &device->pnp.ids, list) {
ret = acpi_scan_do_attach_handler(device, hwid->id);
if (ret)
break;
const struct acpi_device_id *devid;
struct acpi_scan_handler *handler;
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
ret = handler->attach(device, devid);
if (ret > 0) {
device->handler = handler;
break;
} else if (ret < 0) {
break;
}
}
}
return ret;
}
@ -1788,8 +2041,10 @@ int __init acpi_scan_init(void)
acpi_pci_root_init();
acpi_pci_link_init();
acpi_platform_init();
acpi_lpss_init();
acpi_csrt_init();
acpi_container_init();
acpi_memory_hotplug_init();
mutex_lock(&acpi_scan_lock);
/*

View file

@ -7,6 +7,8 @@
#include <linux/moduleparam.h>
#include <acpi/acpi_drivers.h>
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("sysfs");
@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
static LIST_HEAD(acpi_table_attr_list);
static struct kobject *tables_kobj;
static struct kobject *dynamic_tables_kobj;
static struct kobject *hotplug_kobj;
struct acpi_table_attr {
struct bin_attribute attr;
@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, struct device_attribute *attr,
static const struct device_attribute pm_profile_attr =
__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
static ssize_t hotplug_enabled_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
return sprintf(buf, "%d\n", hotplug->enabled);
}
static ssize_t hotplug_enabled_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t size)
{
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
unsigned int val;
if (kstrtouint(buf, 10, &val) || val > 1)
return -EINVAL;
acpi_scan_hotplug_enabled(hotplug, val);
return size;
}
static struct kobj_attribute hotplug_enabled_attr =
__ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
hotplug_enabled_store);
static struct attribute *hotplug_profile_attrs[] = {
&hotplug_enabled_attr.attr,
NULL
};
static struct kobj_type acpi_hotplug_profile_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
.default_attrs = hotplug_profile_attrs,
};
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
const char *name)
{
int error;
if (!hotplug_kobj)
goto err_out;
kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
error = kobject_set_name(&hotplug->kobj, "%s", name);
if (error)
goto err_out;
hotplug->kobj.parent = hotplug_kobj;
error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
if (error)
goto err_out;
kobject_uevent(&hotplug->kobj, KOBJ_ADD);
return;
err_out:
pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
}
int __init acpi_sysfs_init(void)
{
int result;
@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void)
result = acpi_tables_sysfs_init();
if (result)
return result;
hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
return result;
}

View file

@ -723,9 +723,19 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
return -EINVAL;
if (type == THERMAL_TRIP_ACTIVE) {
/* aggressive active cooling */
*trend = THERMAL_TREND_RAISING;
return 0;
unsigned long trip_temp;
unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature,
tz->kelvin_offset);
if (thermal_get_trip_temp(thermal, trip, &trip_temp))
return -EINVAL;
if (temp > trip_temp) {
*trend = THERMAL_TREND_RAISING;
return 0;
} else {
/* Fall back on default trend */
return -EINVAL;
}
}
/*

View file

@ -167,7 +167,8 @@ struct acpi_video_device_flags {
u8 dvi:1;
u8 bios:1;
u8 unknown:1;
u8 reserved:2;
u8 notify:1;
u8 reserved:1;
};
struct acpi_video_device_cap {
@ -222,7 +223,7 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level);
static int acpi_video_device_lcd_get_level_current(
struct acpi_video_device *device,
unsigned long long *level, int init);
unsigned long long *level, bool raw);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static int acpi_video_switch_brightness(struct acpi_video_device *device,
@ -236,7 +237,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))
if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
return -EINVAL;
for (i = 2; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level)
@ -281,7 +282,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig
unsigned long long level;
int offset;
if (acpi_video_device_lcd_get_level_current(video, &level, 0))
if (acpi_video_device_lcd_get_level_current(video, &level, false))
return -EINVAL;
for (offset = 2; offset < video->brightness->count; offset++)
if (level == video->brightness->levels[offset]) {
@ -447,12 +448,45 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13 - 2000 Notebook PC"),
},
},
{
.callback = video_ignore_initial_backlight,
.ident = "HP Pavilion dm4",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dm4 Notebook PC"),
},
},
{}
};
static unsigned long long
acpi_video_bqc_value_to_level(struct acpi_video_device *device,
unsigned long long bqc_value)
{
unsigned long long level;
if (device->brightness->flags._BQC_use_index) {
/*
* _BQC returns an index that doesn't account for
* the first 2 items with special meaning, so we need
* to compensate for that by offsetting ourselves
*/
if (device->brightness->flags._BCL_reversed)
bqc_value = device->brightness->count - 3 - bqc_value;
level = device->brightness->levels[bqc_value + 2];
} else {
level = bqc_value;
}
level += bqc_offset_aml_bug_workaround;
return level;
}
static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long long *level, int init)
unsigned long long *level, bool raw)
{
acpi_status status = AE_OK;
int i;
@ -463,29 +497,30 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
status = acpi_evaluate_integer(device->dev->handle, buf,
NULL, level);
if (ACPI_SUCCESS(status)) {
if (device->brightness->flags._BQC_use_index) {
if (device->brightness->flags._BCL_reversed)
*level = device->brightness->count
- 3 - (*level);
*level = device->brightness->levels[*level + 2];
if (raw) {
/*
* Caller has indicated he wants the raw
* value returned by _BQC, so don't furtherly
* mess with the value.
*/
return 0;
}
*level += bqc_offset_aml_bug_workaround;
*level = acpi_video_bqc_value_to_level(device, *level);
for (i = 2; i < device->brightness->count; i++)
if (device->brightness->levels[i] == *level) {
device->brightness->curr = *level;
return 0;
}
if (!init) {
/*
* BQC returned an invalid level.
* Stop using it.
*/
ACPI_WARNING((AE_INFO,
"%s returned an invalid level",
buf));
device->cap._BQC = device->cap._BCQ = 0;
}
/*
* BQC returned an invalid level.
* Stop using it.
*/
ACPI_WARNING((AE_INFO,
"%s returned an invalid level",
buf));
device->cap._BQC = device->cap._BCQ = 0;
} else {
/* Fixme:
* should we return an error or ignore this failure?
@ -597,6 +632,56 @@ acpi_video_cmp_level(const void *a, const void *b)
return *(int *)a - *(int *)b;
}
/*
* Decides if _BQC/_BCQ for this system is usable
*
* We do this by changing the level first and then read out the current
* brightness level, if the value does not match, find out if it is using
* index. If not, clear the _BQC/_BCQ capability.
*/
static int acpi_video_bqc_quirk(struct acpi_video_device *device,
int max_level, int current_level)
{
struct acpi_video_device_brightness *br = device->brightness;
int result;
unsigned long long level;
int test_level;
/* don't mess with existing known broken systems */
if (bqc_offset_aml_bug_workaround)
return 0;
/*
* Some systems always report current brightness level as maximum
* through _BQC, we need to test another value for them.
*/
test_level = current_level == max_level ? br->levels[2] : max_level;
result = acpi_video_device_lcd_set_level(device, test_level);
if (result)
return result;
result = acpi_video_device_lcd_get_level_current(device, &level, true);
if (result)
return result;
if (level != test_level) {
/* buggy _BQC found, need to find out if it uses index */
if (level < br->count) {
if (br->flags._BCL_reversed)
level = br->count - 3 - level;
if (br->levels[level + 2] == test_level)
br->flags._BQC_use_index = 1;
}
if (!br->flags._BQC_use_index)
device->cap._BQC = device->cap._BCQ = 0;
}
return 0;
}
/*
* Arg:
* device : video output device (LCD, CRT, ..)
@ -703,41 +788,35 @@ acpi_video_init_brightness(struct acpi_video_device *device)
if (!device->cap._BQC)
goto set_level;
result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);
result = acpi_video_device_lcd_get_level_current(device,
&level_old, true);
if (result)
goto out_free_levels;
result = acpi_video_bqc_quirk(device, max_level, level_old);
if (result)
goto out_free_levels;
/*
* Set the level to maximum and check if _BQC uses indexed value
* cap._BQC may get cleared due to _BQC is found to be broken
* in acpi_video_bqc_quirk, so check again here.
*/
result = acpi_video_device_lcd_set_level(device, max_level);
if (result)
goto out_free_levels;
result = acpi_video_device_lcd_get_level_current(device, &level, 0);
if (result)
goto out_free_levels;
br->flags._BQC_use_index = (level == max_level ? 0 : 1);
if (!br->flags._BQC_use_index) {
/*
* Set the backlight to the initial state.
* On some buggy laptops, _BQC returns an uninitialized value
* when invoked for the first time, i.e. level_old is invalid.
* set the backlight to max_level in this case
*/
if (use_bios_initial_backlight) {
for (i = 2; i < br->count; i++)
if (level_old == br->levels[i])
level = level_old;
}
if (!device->cap._BQC)
goto set_level;
}
if (br->flags._BCL_reversed)
level_old = (br->count - 1) - level_old;
level = br->levels[level_old];
if (use_bios_initial_backlight) {
level = acpi_video_bqc_value_to_level(device, level_old);
/*
* On some buggy laptops, _BQC returns an uninitialized
* value when invoked for the first time, i.e.
* level_old is invalid (no matter whether it's a level
* or an index). Set the backlight to max_level in this case.
*/
for (i = 2; i < br->count; i++)
if (level_old == br->levels[i])
break;
if (i == br->count)
level = max_level;
}
set_level:
result = acpi_video_device_lcd_set_level(device, level);
@ -996,53 +1075,51 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute;
if (!device || !video)
return -EINVAL;
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
if (ACPI_SUCCESS(status)) {
/* Some device omits _ADR, we skip them instead of fail */
if (ACPI_FAILURE(status))
return 0;
data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
if (!data)
return -ENOMEM;
data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
if (!data)
return -ENOMEM;
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
device->driver_data = data;
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
device->driver_data = data;
data->device_id = device_id;
data->video = video;
data->dev = device;
data->device_id = device_id;
data->video = video;
data->dev = device;
attribute = acpi_video_get_device_attr(video, device_id);
attribute = acpi_video_get_device_attr(video, device_id);
if((attribute != NULL) && attribute->device_id_scheme) {
switch (attribute->display_type) {
case ACPI_VIDEO_DISPLAY_CRT:
data->flags.crt = 1;
break;
case ACPI_VIDEO_DISPLAY_TV:
data->flags.tvout = 1;
break;
case ACPI_VIDEO_DISPLAY_DVI:
data->flags.dvi = 1;
break;
case ACPI_VIDEO_DISPLAY_LCD:
data->flags.lcd = 1;
break;
default:
data->flags.unknown = 1;
break;
}
if(attribute->bios_can_detect)
data->flags.bios = 1;
} else {
/* Check for legacy IDs */
device_type = acpi_video_get_device_type(video,
device_id);
/* Ignore bits 16 and 18-20 */
switch (device_type & 0xffe2ffff) {
if((attribute != NULL) && attribute->device_id_scheme) {
switch (attribute->display_type) {
case ACPI_VIDEO_DISPLAY_CRT:
data->flags.crt = 1;
break;
case ACPI_VIDEO_DISPLAY_TV:
data->flags.tvout = 1;
break;
case ACPI_VIDEO_DISPLAY_DVI:
data->flags.dvi = 1;
break;
case ACPI_VIDEO_DISPLAY_LCD:
data->flags.lcd = 1;
break;
default:
data->flags.unknown = 1;
break;
}
if(attribute->bios_can_detect)
data->flags.bios = 1;
} else {
/* Check for legacy IDs */
device_type = acpi_video_get_device_type(video, device_id);
/* Ignore bits 16 and 18-20 */
switch (device_type & 0xffe2ffff) {
case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
data->flags.crt = 1;
break;
@ -1054,34 +1131,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
break;
default:
data->flags.unknown = 1;
}
}
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify,
data);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX
"Error installing notify handler\n");
if(data->brightness)
kfree(data->brightness->levels);
kfree(data->brightness);
kfree(data);
return -ENODEV;
}
mutex_lock(&video->device_list_lock);
list_add_tail(&data->entry, &video->video_device_list);
mutex_unlock(&video->device_list_lock);
return 0;
}
return -ENOENT;
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
acpi_video_device_notify, data);
if (ACPI_FAILURE(status))
dev_err(&device->dev, "Error installing notify handler\n");
else
data->flags.notify = 1;
mutex_lock(&video->device_list_lock);
list_add_tail(&data->entry, &video->video_device_list);
mutex_unlock(&video->device_list_lock);
return status;
}
/*
@ -1268,7 +1335,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
goto out;
result = acpi_video_device_lcd_get_level_current(device,
&level_current, 0);
&level_current,
false);
if (result)
goto out;
@ -1373,9 +1441,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (status) {
printk(KERN_WARNING PREFIX
"Can't attach device\n");
continue;
dev_err(&dev->dev, "Can't attach device\n");
break;
}
}
return status;
@ -1388,13 +1455,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
if (!device || !device->video)
return -ENOENT;
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
if (ACPI_FAILURE(status)) {
printk(KERN_WARNING PREFIX
"Can't remove video notify handler\n");
if (device->flags.notify) {
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY, acpi_video_device_notify);
if (ACPI_FAILURE(status))
dev_err(&device->dev->dev,
"Can't remove video notify handler\n");
}
if (device->backlight) {
backlight_device_unregister(device->backlight);
device->backlight = NULL;
@ -1676,7 +1744,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
error = acpi_video_bus_get_devices(video, device);
if (error)
goto err_free_video;
goto err_put_video;
video->input = input = input_allocate_device();
if (!input) {

View file

@ -67,40 +67,37 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
return 0;
}
/* Returns true if the device is a video device which can be handled by
* video.ko.
/* Returns true if the ACPI object is a video device which can be
* handled by video.ko.
* The device will get a Linux specific CID added in scan.c to
* identify the device as an ACPI graphics device
* Be aware that the graphics device may not be physically present
* Use acpi_video_get_capabilities() to detect general ACPI video
* capabilities of present cards
*/
long acpi_is_video_device(struct acpi_device *device)
long acpi_is_video_device(acpi_handle handle)
{
acpi_handle h_dummy;
long video_caps = 0;
if (!device)
return 0;
/* Is this device able to support video switching ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
/* Is this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
/* Is this device able to configure which video head to be POSTed ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
video_caps |= ACPI_VIDEO_DEVICE_POSTING;
/* Only check for backlight functionality if one of the above hit. */
if (video_caps)
acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
&video_caps, NULL);
@ -127,7 +124,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
if (!dev)
return AE_OK;
pci_dev_put(dev);
*cap |= acpi_is_video_device(acpi_dev);
*cap |= acpi_is_video_device(handle);
}
return AE_OK;
}