mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 21:24:08 +08:00
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (123 commits) dock: make dock driver not a module ACPI: fix ia64 build warning ACPI: hack around sysfs warning with link order ACPI suspend: fix build warning when CONFIG_ACPI_SLEEP=n intel_menlo: fix build warning panasonic-laptop: fix build ACPICA: Update version to 20080926 ACPICA: Add support for zero-length buffer-to-string conversions ACPICA: New: Validation for predefined ACPI methods/objects ACPICA: Fix for implicit return compatibility ACPICA: Fixed a couple memory leaks associated with "implicit return" ACPICA: Optimize buffer allocation procedure ACPICA: Fix possible memory leak, error exit path ACPICA: Fix fault after mem allocation failure in AML parser ACPICA: Remove unused ACPI register bit definition ACPICA: Update version to 20080829 ACPICA: Fix possible memory leak in acpi_ns_get_external_pathname ACPICA: Cleanup for internal Reference Object ACPICA: Update comments - no functional changes ACPICA: Update for Reference ACPI_OPERAND_OBJECT ...
This commit is contained in:
commit
765426e8ee
@ -218,20 +218,47 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
acpi.debug_level= [HW,ACPI]
|
||||
Format: <int>
|
||||
Each bit of the <int> indicates an ACPI debug level,
|
||||
1: enable, 0: disable. It is useful for boot time
|
||||
debugging. After system has booted up, it can be set
|
||||
via /sys/module/acpi/parameters/debug_level.
|
||||
CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
|
||||
Available bits (add the numbers together) to enable different
|
||||
debug output levels of the ACPI subsystem:
|
||||
0x01 error 0x02 warn 0x04 init 0x08 debug object
|
||||
0x10 info 0x20 init names 0x40 parse 0x80 load
|
||||
0x100 dispatch 0x200 execute 0x400 names 0x800 operation region
|
||||
0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects
|
||||
0x10000 resources 0x20000 user requests 0x40000 package.
|
||||
The number can be in decimal or prefixed with 0x in hex.
|
||||
Warning: Many of these options can produce a lot of
|
||||
output and make your system unusable. Be very careful.
|
||||
which corresponds to the level in an ACPI_DEBUG_PRINT
|
||||
statement. After system has booted up, this mask
|
||||
can be set via /sys/module/acpi/parameters/debug_level.
|
||||
|
||||
CONFIG_ACPI_DEBUG must be enabled for this to produce
|
||||
any output. The number can be in decimal or prefixed
|
||||
with 0x in hex. Some of these options produce so much
|
||||
output that the system is unusable.
|
||||
|
||||
The following global components are defined by the
|
||||
ACPI CA:
|
||||
0x01 error
|
||||
0x02 warn
|
||||
0x04 init
|
||||
0x08 debug object
|
||||
0x10 info
|
||||
0x20 init names
|
||||
0x40 parse
|
||||
0x80 load
|
||||
0x100 dispatch
|
||||
0x200 execute
|
||||
0x400 names
|
||||
0x800 operation region
|
||||
0x1000 bfield
|
||||
0x2000 tables
|
||||
0x4000 values
|
||||
0x8000 objects
|
||||
0x10000 resources
|
||||
0x20000 user requests
|
||||
0x40000 package
|
||||
The number can be in decimal or prefixed with 0x in hex.
|
||||
Warning: Many of these options can produce a lot of
|
||||
output and make your system unusable. Be very careful.
|
||||
|
||||
acpi.power_nocheck= [HW,ACPI]
|
||||
Format: 1/0 enable/disable the check of power state.
|
||||
On some bogus BIOS the _PSC object/_STA object of
|
||||
power resource can't return the correct device power
|
||||
state. In such case it is unneccessary to check its
|
||||
power state again in power transition.
|
||||
1 : disable the power state check
|
||||
|
||||
acpi_pm_good [X86-32,X86-64]
|
||||
Override the pmtimer bug detection: force the kernel
|
||||
@ -1711,6 +1738,10 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
Override pmtimer IOPort with a hex value.
|
||||
e.g. pmtmr=0x508
|
||||
|
||||
pnp.debug [PNP]
|
||||
Enable PNP debug messages. This depends on the
|
||||
CONFIG_PNP_DEBUG_MESSAGES option.
|
||||
|
||||
pnpacpi= [ACPI]
|
||||
{ off }
|
||||
|
||||
@ -2208,7 +2239,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
|
||||
thermal.crt= [HW,ACPI]
|
||||
-1: disable all critical trip points in all thermal zones
|
||||
<degrees C>: lower all critical trip points
|
||||
<degrees C>: override all critical trip points
|
||||
|
||||
thermal.nocrt= [HW,ACPI]
|
||||
Set to disable actions on ACPI thermal zone
|
||||
|
@ -1,7 +1,7 @@
|
||||
Acer Laptop WMI Extras Driver
|
||||
http://code.google.com/p/aceracpi
|
||||
Version 0.1
|
||||
9th February 2008
|
||||
Version 0.2
|
||||
18th August 2008
|
||||
|
||||
Copyright 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
|
||||
|
||||
@ -87,17 +87,7 @@ acer-wmi come with built-in wireless. However, should you feel so inclined to
|
||||
ever wish to remove the card, or swap it out at some point, please get in touch
|
||||
with me, as we may well be able to gain some data on wireless card detection.
|
||||
|
||||
To read the status of the wireless radio (0=off, 1=on):
|
||||
cat /sys/devices/platform/acer-wmi/wireless
|
||||
|
||||
To enable the wireless radio:
|
||||
echo 1 > /sys/devices/platform/acer-wmi/wireless
|
||||
|
||||
To disable the wireless radio:
|
||||
echo 0 > /sys/devices/platform/acer-wmi/wireless
|
||||
|
||||
To set the state of the wireless radio when loading acer-wmi, pass:
|
||||
wireless=X (where X is 0 or 1)
|
||||
The wireless radio is exposed through rfkill.
|
||||
|
||||
Bluetooth
|
||||
*********
|
||||
@ -117,17 +107,7 @@ For the adventurously minded - if you want to buy an internal bluetooth
|
||||
module off the internet that is compatible with your laptop and fit it, then
|
||||
it will work just fine with acer-wmi.
|
||||
|
||||
To read the status of the bluetooth module (0=off, 1=on):
|
||||
cat /sys/devices/platform/acer-wmi/wireless
|
||||
|
||||
To enable the bluetooth module:
|
||||
echo 1 > /sys/devices/platform/acer-wmi/bluetooth
|
||||
|
||||
To disable the bluetooth module:
|
||||
echo 0 > /sys/devices/platform/acer-wmi/bluetooth
|
||||
|
||||
To set the state of the bluetooth module when loading acer-wmi, pass:
|
||||
bluetooth=X (where X is 0 or 1)
|
||||
Bluetooth is exposed through rfkill.
|
||||
|
||||
3G
|
||||
**
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -1433,8 +1433,8 @@ M: rdunlap@xenotime.net
|
||||
S: Maintained
|
||||
|
||||
DOCKING STATION DRIVER
|
||||
P: Kristen Carlson Accardi
|
||||
M: kristen.c.accardi@intel.com
|
||||
P: Shaohua Li
|
||||
M: shaohua.li@intel.com
|
||||
L: linux-acpi@vger.kernel.org
|
||||
S: Supported
|
||||
|
||||
@ -2109,6 +2109,12 @@ L: linux-ide@vger.kernel.org
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Orphan
|
||||
|
||||
IDLE-I7300
|
||||
P: Andy Henroid
|
||||
M: andrew.d.henroid@intel.com
|
||||
L: linux-pm@lists.linux-foundation.org
|
||||
S: Supported
|
||||
|
||||
IEEE 1394 SUBSYSTEM (drivers/ieee1394)
|
||||
P: Ben Collins
|
||||
M: ben.collins@ubuntu.com
|
||||
@ -3186,6 +3192,11 @@ M: olof@lixom.net
|
||||
L: i2c@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
PANASONIC LAPTOP ACPI EXTRAS DRIVER
|
||||
P: Harald Welte
|
||||
M: laforge@gnumonks.org
|
||||
S: Maintained
|
||||
|
||||
PANASONIC MN10300/AM33 PORT
|
||||
P: David Howells
|
||||
M: dhowells@redhat.com
|
||||
|
@ -232,7 +232,7 @@ exit:
|
||||
static unsigned int
|
||||
get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
|
||||
{
|
||||
unsigned long adr;
|
||||
unsigned long long adr;
|
||||
acpi_handle child;
|
||||
unsigned int devfn;
|
||||
int function;
|
||||
@ -292,8 +292,8 @@ get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
|
||||
static acpi_status
|
||||
find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
unsigned long bbn = -1;
|
||||
unsigned long adr;
|
||||
unsigned long long bbn = -1;
|
||||
unsigned long long adr;
|
||||
acpi_handle parent = NULL;
|
||||
acpi_status status;
|
||||
unsigned int devfn;
|
||||
@ -348,7 +348,7 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
|
||||
unsigned int host_devfn;
|
||||
struct sn_pcidev_match pcidev_match;
|
||||
acpi_handle rootbus_handle;
|
||||
unsigned long segment;
|
||||
unsigned long long segment;
|
||||
acpi_status status;
|
||||
|
||||
rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle;
|
||||
@ -357,7 +357,7 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (segment != pci_domain_nr(dev)) {
|
||||
printk(KERN_ERR
|
||||
"%s: Segment number mismatch, 0x%lx vs 0x%x for: ",
|
||||
"%s: Segment number mismatch, 0x%llx vs 0x%x for: ",
|
||||
__func__, segment, pci_domain_nr(dev));
|
||||
acpi_ns_print_node_pathname(rootbus_handle, NULL);
|
||||
printk("\n");
|
||||
|
@ -116,6 +116,9 @@ config GENERIC_TIME_VSYSCALL
|
||||
config ARCH_HAS_CPU_RELAX
|
||||
def_bool y
|
||||
|
||||
config ARCH_HAS_DEFAULT_IDLE
|
||||
def_bool y
|
||||
|
||||
config ARCH_HAS_CACHE_LINE_SIZE
|
||||
def_bool y
|
||||
|
||||
@ -1635,6 +1638,8 @@ source "arch/x86/kernel/cpu/cpufreq/Kconfig"
|
||||
|
||||
source "drivers/cpuidle/Kconfig"
|
||||
|
||||
source "drivers/idle/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
|
@ -153,12 +153,13 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
|
||||
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
|
||||
|
||||
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
|
||||
struct acpi_mcfg_allocation *pci_mmcfg_config;
|
||||
int pci_mmcfg_config_num;
|
||||
|
||||
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
|
||||
|
||||
static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
|
||||
{
|
||||
if (!strcmp(mcfg->header.oem_id, "SGI"))
|
||||
|
@ -22,7 +22,7 @@ unsigned long acpi_realmode_flags;
|
||||
static unsigned long acpi_realmode;
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
|
||||
static char temp_stack[10240];
|
||||
static char temp_stack[4096];
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -98,7 +98,7 @@ int acpi_save_state_mem(void)
|
||||
#else /* CONFIG_64BIT */
|
||||
header->trampoline_segment = setup_trampoline() >> 4;
|
||||
#ifdef CONFIG_SMP
|
||||
stack_start.sp = temp_stack + 4096;
|
||||
stack_start.sp = temp_stack + sizeof(temp_stack);
|
||||
early_gdt_descr.address =
|
||||
(unsigned long)get_cpu_gdt_table(smp_processor_id());
|
||||
#endif
|
||||
|
@ -780,6 +780,9 @@ static int __init acpi_cpufreq_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
dprintk("acpi_cpufreq_init\n");
|
||||
|
||||
ret = acpi_cpufreq_early_init();
|
||||
|
@ -45,7 +45,6 @@
|
||||
#endif
|
||||
|
||||
#define PFX "powernow-k8: "
|
||||
#define BFX PFX "BIOS error: "
|
||||
#define VERSION "version 2.20.00"
|
||||
#include "powernow-k8.h"
|
||||
|
||||
@ -536,35 +535,40 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
|
||||
|
||||
for (j = 0; j < data->numps; j++) {
|
||||
if (pst[j].vid > LEAST_VID) {
|
||||
printk(KERN_ERR PFX "vid %d invalid : 0x%x\n", j, pst[j].vid);
|
||||
printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x\n",
|
||||
j, pst[j].vid);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pst[j].vid < data->rvo) { /* vid + rvo >= 0 */
|
||||
printk(KERN_ERR BFX "0 vid exceeded with pstate %d\n", j);
|
||||
printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate"
|
||||
" %d\n", j);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (pst[j].vid < maxvid + data->rvo) { /* vid + rvo >= maxvid */
|
||||
printk(KERN_ERR BFX "maxvid exceeded with pstate %d\n", j);
|
||||
printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate"
|
||||
" %d\n", j);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (pst[j].fid > MAX_FID) {
|
||||
printk(KERN_ERR BFX "maxfid exceeded with pstate %d\n", j);
|
||||
printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate"
|
||||
" %d\n", j);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
|
||||
/* Only first fid is allowed to be in "low" range */
|
||||
printk(KERN_ERR BFX "two low fids - %d : 0x%x\n", j, pst[j].fid);
|
||||
printk(KERN_ERR FW_BUG PFX "two low fids - %d : "
|
||||
"0x%x\n", j, pst[j].fid);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pst[j].fid < lastfid)
|
||||
lastfid = pst[j].fid;
|
||||
}
|
||||
if (lastfid & 1) {
|
||||
printk(KERN_ERR BFX "lastfid invalid\n");
|
||||
printk(KERN_ERR FW_BUG PFX "lastfid invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (lastfid > LO_FID_TABLE_TOP)
|
||||
printk(KERN_INFO BFX "first fid not from lo freq table\n");
|
||||
printk(KERN_INFO FW_BUG PFX "first fid not from lo freq table\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -672,13 +676,13 @@ static int find_psb_table(struct powernow_k8_data *data)
|
||||
|
||||
dprintk("table vers: 0x%x\n", psb->tableversion);
|
||||
if (psb->tableversion != PSB_VERSION_1_4) {
|
||||
printk(KERN_ERR BFX "PSB table is not v1.4\n");
|
||||
printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dprintk("flags: 0x%x\n", psb->flags1);
|
||||
if (psb->flags1) {
|
||||
printk(KERN_ERR BFX "unknown flags\n");
|
||||
printk(KERN_ERR FW_BUG PFX "unknown flags\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -705,7 +709,7 @@ static int find_psb_table(struct powernow_k8_data *data)
|
||||
}
|
||||
}
|
||||
if (cpst != 1) {
|
||||
printk(KERN_ERR BFX "numpst must be 1\n");
|
||||
printk(KERN_ERR FW_BUG PFX "numpst must be 1\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1130,17 +1134,19 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
||||
"ACPI Processor module before starting this "
|
||||
"driver.\n");
|
||||
#else
|
||||
printk(KERN_ERR PFX "Your BIOS does not provide ACPI "
|
||||
"_PSS objects in a way that Linux understands. "
|
||||
"Please report this to the Linux ACPI maintainers"
|
||||
" and complain to your BIOS vendor.\n");
|
||||
printk(KERN_ERR FW_BUG PFX "Your BIOS does not provide"
|
||||
" ACPI _PSS objects in a way that Linux "
|
||||
"understands. Please report this to the Linux "
|
||||
"ACPI maintainers and complain to your BIOS "
|
||||
"vendor.\n");
|
||||
#endif
|
||||
kfree(data);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (pol->cpu != 0) {
|
||||
printk(KERN_ERR PFX "No ACPI _PSS objects for CPU other than "
|
||||
"CPU0. Complain to your BIOS vendor.\n");
|
||||
printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
|
||||
"CPU other than CPU0. Complain to your BIOS "
|
||||
"vendor.\n");
|
||||
kfree(data);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1193,7 +1199,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
||||
|
||||
/* min/max the cpu is capable of */
|
||||
if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
|
||||
printk(KERN_ERR PFX "invalid powernow_table\n");
|
||||
printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n");
|
||||
powernow_k8_cpu_exit_acpi(data);
|
||||
kfree(data->powernow_table);
|
||||
kfree(data);
|
||||
|
@ -95,7 +95,8 @@ static void __init nvidia_bugs(int num, int slot, int func)
|
||||
|
||||
}
|
||||
|
||||
static u32 ati_ixp4x0_rev(int num, int slot, int func)
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
|
||||
static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
|
||||
{
|
||||
u32 d;
|
||||
u8 b;
|
||||
@ -115,7 +116,6 @@ static u32 ati_ixp4x0_rev(int num, int slot, int func)
|
||||
|
||||
static void __init ati_bugs(int num, int slot, int func)
|
||||
{
|
||||
#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
|
||||
u32 d;
|
||||
u8 b;
|
||||
|
||||
@ -138,9 +138,56 @@ static void __init ati_bugs(int num, int slot, int func)
|
||||
printk(KERN_INFO "If you got timer trouble "
|
||||
"try acpi_use_timer_override\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 __init ati_sbx00_rev(int num, int slot, int func)
|
||||
{
|
||||
u32 old, d;
|
||||
|
||||
d = read_pci_config(num, slot, func, 0x70);
|
||||
old = d;
|
||||
d &= ~(1<<8);
|
||||
write_pci_config(num, slot, func, 0x70, d);
|
||||
d = read_pci_config(num, slot, func, 0x8);
|
||||
d &= 0xff;
|
||||
write_pci_config(num, slot, func, 0x70, old);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void __init ati_bugs_contd(int num, int slot, int func)
|
||||
{
|
||||
u32 d, rev;
|
||||
|
||||
if (acpi_use_timer_override)
|
||||
return;
|
||||
|
||||
rev = ati_sbx00_rev(num, slot, func);
|
||||
if (rev > 0x13)
|
||||
return;
|
||||
|
||||
/* check for IRQ0 interrupt swap */
|
||||
d = read_pci_config(num, slot, func, 0x64);
|
||||
if (!(d & (1<<14)))
|
||||
acpi_skip_timer_override = 1;
|
||||
|
||||
if (acpi_skip_timer_override) {
|
||||
printk(KERN_INFO "SB600 revision 0x%x\n", rev);
|
||||
printk(KERN_INFO "Ignoring ACPI timer override.\n");
|
||||
printk(KERN_INFO "If you got timer trouble "
|
||||
"try acpi_use_timer_override\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void __init ati_bugs(int num, int slot, int func)
|
||||
{
|
||||
}
|
||||
|
||||
static void __init ati_bugs_contd(int num, int slot, int func)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DMAR
|
||||
static void __init intel_g33_dmar(int num, int slot, int func)
|
||||
{
|
||||
@ -176,6 +223,8 @@ static struct chipset early_qrk[] __initdata = {
|
||||
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
|
||||
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
|
||||
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
|
||||
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
|
||||
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
|
||||
#ifdef CONFIG_DMAR
|
||||
{ PCI_VENDOR_ID_INTEL, 0x29c0,
|
||||
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
|
||||
|
@ -63,6 +63,13 @@ void idle_notifier_register(struct notifier_block *n)
|
||||
{
|
||||
atomic_notifier_chain_register(&idle_notifier, n);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(idle_notifier_register);
|
||||
|
||||
void idle_notifier_unregister(struct notifier_block *n)
|
||||
{
|
||||
atomic_notifier_chain_unregister(&idle_notifier, n);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(idle_notifier_unregister);
|
||||
|
||||
void enter_idle(void)
|
||||
{
|
||||
|
@ -82,6 +82,7 @@ obj-$(CONFIG_EISA) += eisa/
|
||||
obj-y += lguest/
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle/
|
||||
obj-y += idle/
|
||||
obj-$(CONFIG_MMC) += mmc/
|
||||
obj-$(CONFIG_MEMSTICK) += memstick/
|
||||
obj-$(CONFIG_NEW_LEDS) += leds/
|
||||
|
@ -42,7 +42,7 @@ if ACPI
|
||||
|
||||
config ACPI_SLEEP
|
||||
bool
|
||||
depends on PM_SLEEP
|
||||
depends on SUSPEND || HIBERNATION
|
||||
default y
|
||||
|
||||
config ACPI_PROCFS
|
||||
@ -157,18 +157,11 @@ config ACPI_FAN
|
||||
applications to perform basic fan control (on, off, status).
|
||||
|
||||
config ACPI_DOCK
|
||||
tristate "Dock"
|
||||
bool "Dock"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
This driver adds support for ACPI controlled docking stations
|
||||
|
||||
config ACPI_BAY
|
||||
tristate "Removable Drive Bay (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
depends on ACPI_DOCK
|
||||
help
|
||||
This driver adds support for ACPI controlled removable drive
|
||||
bays such as the IBM ultrabay or the Dell Module Bay.
|
||||
This driver adds support for ACPI controlled docking stations and removable
|
||||
drive bays such as the IBM ultrabay or the Dell Module Bay.
|
||||
|
||||
config ACPI_PROCESSOR
|
||||
tristate "Processor"
|
||||
|
@ -45,14 +45,13 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
|
||||
obj-$(CONFIG_ACPI_BUTTON) += button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
obj-$(CONFIG_ACPI_DOCK) += dock.o
|
||||
obj-$(CONFIG_ACPI_BAY) += bay.o
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
|
||||
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
|
||||
obj-$(CONFIG_ACPI_POWER) += power.o
|
||||
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
|
||||
obj-$(CONFIG_ACPI_CONTAINER) += container.o
|
||||
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
|
||||
obj-$(CONFIG_ACPI_POWER) += power.o
|
||||
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
|
||||
obj-$(CONFIG_ACPI_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa.o
|
||||
|
@ -85,7 +85,7 @@ struct acpi_ac {
|
||||
struct power_supply charger;
|
||||
#endif
|
||||
struct acpi_device * device;
|
||||
unsigned long state;
|
||||
unsigned long long state;
|
||||
};
|
||||
|
||||
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
|
||||
@ -269,7 +269,7 @@ static int acpi_ac_add(struct acpi_device *device)
|
||||
ac->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_AC_CLASS);
|
||||
acpi_driver_data(device) = ac;
|
||||
device->driver_data = ac;
|
||||
|
||||
result = acpi_ac_get_state(ac);
|
||||
if (result)
|
||||
|
@ -194,8 +194,7 @@ acpi_memory_get_device(acpi_handle handle,
|
||||
|
||||
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
unsigned long current_status;
|
||||
|
||||
unsigned long long current_status;
|
||||
|
||||
/* Get device present/absent information from the _STA */
|
||||
if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
|
||||
@ -264,7 +263,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
|
||||
acpi_status status;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
unsigned long current_status;
|
||||
unsigned long long current_status;
|
||||
|
||||
|
||||
/* Issue the _EJ0 command */
|
||||
@ -403,7 +402,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
|
||||
mem_device->device = device;
|
||||
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
|
||||
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
|
||||
acpi_driver_data(device) = mem_device;
|
||||
device->driver_data = mem_device;
|
||||
|
||||
/* Get the range from the _CRS */
|
||||
result = acpi_memory_get_device_resources(mem_device);
|
||||
@ -454,8 +453,8 @@ static int acpi_memory_device_start (struct acpi_device *device)
|
||||
/* call add_memory func */
|
||||
result = acpi_memory_enable_device(mem_device);
|
||||
if (result)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error in acpi_memory_enable_device\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error in acpi_memory_enable_device\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
#define ASUS_ACPI_VERSION "0.30"
|
||||
|
||||
#define PROC_ASUS "asus" //the directory
|
||||
#define PROC_ASUS "asus" /* The directory */
|
||||
#define PROC_MLED "mled"
|
||||
#define PROC_WLED "wled"
|
||||
#define PROC_TLED "tled"
|
||||
@ -66,10 +66,10 @@
|
||||
/*
|
||||
* Flags for hotk status
|
||||
*/
|
||||
#define MLED_ON 0x01 //mail LED
|
||||
#define WLED_ON 0x02 //wireless LED
|
||||
#define TLED_ON 0x04 //touchpad LED
|
||||
#define BT_ON 0x08 //internal Bluetooth
|
||||
#define MLED_ON 0x01 /* Mail LED */
|
||||
#define WLED_ON 0x02 /* Wireless LED */
|
||||
#define TLED_ON 0x04 /* Touchpad LED */
|
||||
#define BT_ON 0x08 /* Internal Bluetooth */
|
||||
|
||||
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
|
||||
MODULE_DESCRIPTION(ACPI_HOTK_NAME);
|
||||
@ -82,28 +82,28 @@ MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
|
||||
module_param(asus_gid, uint, 0);
|
||||
MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
|
||||
|
||||
/* For each model, all features implemented,
|
||||
/* For each model, all features implemented,
|
||||
* those marked with R are relative to HOTK, A for absolute */
|
||||
struct model_data {
|
||||
char *name; //name of the laptop________________A
|
||||
char *mt_mled; //method to handle mled_____________R
|
||||
char *mled_status; //node to handle mled reading_______A
|
||||
char *mt_wled; //method to handle wled_____________R
|
||||
char *wled_status; //node to handle wled reading_______A
|
||||
char *mt_tled; //method to handle tled_____________R
|
||||
char *tled_status; //node to handle tled reading_______A
|
||||
char *mt_ledd; //method to handle LED display______R
|
||||
char *mt_bt_switch; //method to switch Bluetooth on/off_R
|
||||
char *bt_status; //no model currently supports this__?
|
||||
char *mt_lcd_switch; //method to turn LCD on/off_________A
|
||||
char *lcd_status; //node to read LCD panel state______A
|
||||
char *brightness_up; //method to set brightness up_______A
|
||||
char *brightness_down; //guess what ?______________________A
|
||||
char *brightness_set; //method to set absolute brightness_R
|
||||
char *brightness_get; //method to get absolute brightness_R
|
||||
char *brightness_status; //node to get brightness____________A
|
||||
char *display_set; //method to set video output________R
|
||||
char *display_get; //method to get video output________R
|
||||
char *name; /* name of the laptop________________A */
|
||||
char *mt_mled; /* method to handle mled_____________R */
|
||||
char *mled_status; /* node to handle mled reading_______A */
|
||||
char *mt_wled; /* method to handle wled_____________R */
|
||||
char *wled_status; /* node to handle wled reading_______A */
|
||||
char *mt_tled; /* method to handle tled_____________R */
|
||||
char *tled_status; /* node to handle tled reading_______A */
|
||||
char *mt_ledd; /* method to handle LED display______R */
|
||||
char *mt_bt_switch; /* method to switch Bluetooth on/off_R */
|
||||
char *bt_status; /* no model currently supports this__? */
|
||||
char *mt_lcd_switch; /* method to turn LCD on/off_________A */
|
||||
char *lcd_status; /* node to read LCD panel state______A */
|
||||
char *brightness_up; /* method to set brightness up_______A */
|
||||
char *brightness_down; /* method to set brightness down ____A */
|
||||
char *brightness_set; /* method to set absolute brightness_R */
|
||||
char *brightness_get; /* method to get absolute brightness_R */
|
||||
char *brightness_status;/* node to get brightness____________A */
|
||||
char *display_set; /* method to set video output________R */
|
||||
char *display_get; /* method to get video output________R */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -111,41 +111,41 @@ struct model_data {
|
||||
* about the hotk device
|
||||
*/
|
||||
struct asus_hotk {
|
||||
struct acpi_device *device; //the device we are in
|
||||
acpi_handle handle; //the handle of the hotk device
|
||||
char status; //status of the hotk, for LEDs, ...
|
||||
u32 ledd_status; //status of the LED display
|
||||
struct model_data *methods; //methods available on the laptop
|
||||
u8 brightness; //brightness level
|
||||
struct acpi_device *device; /* the device we are in */
|
||||
acpi_handle handle; /* the handle of the hotk device */
|
||||
char status; /* status of the hotk, for LEDs */
|
||||
u32 ledd_status; /* status of the LED display */
|
||||
struct model_data *methods; /* methods available on the laptop */
|
||||
u8 brightness; /* brightness level */
|
||||
enum {
|
||||
A1x = 0, //A1340D, A1300F
|
||||
A2x, //A2500H
|
||||
A4G, //A4700G
|
||||
D1x, //D1
|
||||
L2D, //L2000D
|
||||
L3C, //L3800C
|
||||
L3D, //L3400D
|
||||
L3H, //L3H, L2000E, L5D
|
||||
L4R, //L4500R
|
||||
L5x, //L5800C
|
||||
L8L, //L8400L
|
||||
M1A, //M1300A
|
||||
M2E, //M2400E, L4400L
|
||||
M6N, //M6800N, W3400N
|
||||
M6R, //M6700R, A3000G
|
||||
P30, //Samsung P30
|
||||
S1x, //S1300A, but also L1400B and M2400A (L84F)
|
||||
S2x, //S200 (J1 reported), Victor MP-XP7210
|
||||
W1N, //W1000N
|
||||
W5A, //W5A
|
||||
W3V, //W3030V
|
||||
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
|
||||
A4S, //Z81sp
|
||||
//(Centrino)
|
||||
F3Sa,
|
||||
A1x = 0, /* A1340D, A1300F */
|
||||
A2x, /* A2500H */
|
||||
A4G, /* A4700G */
|
||||
D1x, /* D1 */
|
||||
L2D, /* L2000D */
|
||||
L3C, /* L3800C */
|
||||
L3D, /* L3400D */
|
||||
L3H, /* L3H, L2000E, L5D */
|
||||
L4R, /* L4500R */
|
||||
L5x, /* L5800C */
|
||||
L8L, /* L8400L */
|
||||
M1A, /* M1300A */
|
||||
M2E, /* M2400E, L4400L */
|
||||
M6N, /* M6800N, W3400N */
|
||||
M6R, /* M6700R, A3000G */
|
||||
P30, /* Samsung P30 */
|
||||
S1x, /* S1300A, but also L1400B and M2400A (L84F) */
|
||||
S2x, /* S200 (J1 reported), Victor MP-XP7210 */
|
||||
W1N, /* W1000N */
|
||||
W5A, /* W5A */
|
||||
W3V, /* W3030V */
|
||||
xxN, /* M2400N, M3700N, M5200N, M6800N,
|
||||
S1300N, S5200N*/
|
||||
A4S, /* Z81sp */
|
||||
F3Sa, /* (Centrino) */
|
||||
END_MODEL
|
||||
} model; //Models currently supported
|
||||
u16 event_count[128]; //count for each event TODO make this better
|
||||
} model; /* Models currently supported */
|
||||
u16 event_count[128]; /* Count for each event TODO make this better */
|
||||
};
|
||||
|
||||
/* Here we go */
|
||||
@ -459,18 +459,18 @@ static struct acpi_driver asus_hotk_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
* This function evaluates an ACPI method, given an int as parameter, the
|
||||
* method is searched within the scope of the handle, can be NULL. The output
|
||||
* of the method is written is output, which can also be NULL
|
||||
*
|
||||
* returns 1 if write is successful, 0 else.
|
||||
* returns 1 if write is successful, 0 else.
|
||||
*/
|
||||
static int write_acpi_int(acpi_handle handle, const char *method, int val,
|
||||
struct acpi_buffer *output)
|
||||
{
|
||||
struct acpi_object_list params; //list of input parameters (an int here)
|
||||
union acpi_object in_obj; //the only param we use
|
||||
struct acpi_object_list params; /* list of input parameters (int) */
|
||||
union acpi_object in_obj; /* the only param we use */
|
||||
acpi_status status;
|
||||
|
||||
params.count = 1;
|
||||
@ -507,18 +507,18 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
|
||||
{
|
||||
int len = 0;
|
||||
int temp;
|
||||
char buf[16]; //enough for all info
|
||||
char buf[16]; /* enough for all info */
|
||||
/*
|
||||
* We use the easy way, we don't care of off and count, so we don't set eof
|
||||
* to 1
|
||||
* We use the easy way, we don't care of off and count,
|
||||
* so we don't set eof to 1
|
||||
*/
|
||||
|
||||
len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
|
||||
len += sprintf(page + len, "Model reference : %s\n",
|
||||
hotk->methods->name);
|
||||
/*
|
||||
* The SFUN method probably allows the original driver to get the list
|
||||
* of features supported by a given model. For now, 0x0100 or 0x0800
|
||||
/*
|
||||
* The SFUN method probably allows the original driver to get the list
|
||||
* of features supported by a given model. For now, 0x0100 or 0x0800
|
||||
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
|
||||
* The significance of others is yet to be found.
|
||||
*/
|
||||
@ -528,7 +528,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
|
||||
/*
|
||||
* Another value for userspace: the ASYM method returns 0x02 for
|
||||
* battery low and 0x04 for battery critical, its readings tend to be
|
||||
* more accurate than those provided by _BST.
|
||||
* more accurate than those provided by _BST.
|
||||
* Note: since not all the laptops provide this method, errors are
|
||||
* silently ignored.
|
||||
*/
|
||||
@ -579,7 +579,7 @@ static int read_led(const char *ledname, int ledmask)
|
||||
return (hotk->status & ledmask) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int parse_arg(const char __user * buf, unsigned long count, int *val)
|
||||
static int parse_arg(const char __user *buf, unsigned long count, int *val)
|
||||
{
|
||||
char s[32];
|
||||
if (!count)
|
||||
@ -596,7 +596,7 @@ static int parse_arg(const char __user * buf, unsigned long count, int *val)
|
||||
|
||||
/* FIXME: kill extraneous args so it can be called independently */
|
||||
static int
|
||||
write_led(const char __user * buffer, unsigned long count,
|
||||
write_led(const char __user *buffer, unsigned long count,
|
||||
char *ledname, int ledmask, int invert)
|
||||
{
|
||||
int rv, value;
|
||||
@ -631,7 +631,7 @@ proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_mled(struct file *file, const char __user * buffer,
|
||||
proc_write_mled(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
|
||||
@ -648,7 +648,7 @@ proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_ledd(struct file *file, const char __user * buffer,
|
||||
proc_write_ledd(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int rv, value;
|
||||
@ -677,7 +677,7 @@ proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_wled(struct file *file, const char __user * buffer,
|
||||
proc_write_wled(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
|
||||
@ -694,10 +694,10 @@ proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_bluetooth(struct file *file, const char __user * buffer,
|
||||
proc_write_bluetooth(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
/* Note: mt_bt_switch controls both internal Bluetooth adapter's
|
||||
/* Note: mt_bt_switch controls both internal Bluetooth adapter's
|
||||
presence and its LED */
|
||||
return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
|
||||
}
|
||||
@ -714,7 +714,7 @@ proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_tled(struct file *file, const char __user * buffer,
|
||||
proc_write_tled(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
|
||||
@ -734,7 +734,7 @@ static int get_lcd_state(void)
|
||||
|
||||
input.count = 2;
|
||||
input.pointer = mt_params;
|
||||
/* Note: the following values are partly guessed up, but
|
||||
/* Note: the following values are partly guessed up, but
|
||||
otherwise they seem to work */
|
||||
mt_params[0].type = ACPI_TYPE_INTEGER;
|
||||
mt_params[0].integer.value = 0x02;
|
||||
@ -753,7 +753,7 @@ static int get_lcd_state(void)
|
||||
/* That's what the AML code does */
|
||||
lcd = out_obj.integer.value >> 8;
|
||||
} else if (hotk->model == F3Sa) {
|
||||
unsigned long tmp;
|
||||
unsigned long long tmp;
|
||||
union acpi_object param;
|
||||
struct acpi_object_list input;
|
||||
acpi_status status;
|
||||
@ -796,12 +796,13 @@ static int set_lcd_state(int value)
|
||||
acpi_evaluate_object(NULL,
|
||||
hotk->methods->mt_lcd_switch,
|
||||
NULL, NULL);
|
||||
} else { /* L3H and the like have to be handled differently */
|
||||
} else {
|
||||
/* L3H and the like must be handled differently */
|
||||
if (!write_acpi_int
|
||||
(hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
|
||||
NULL))
|
||||
status = AE_ERROR;
|
||||
/* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
|
||||
/* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
|
||||
the exact behaviour is simulated here */
|
||||
}
|
||||
if (ACPI_FAILURE(status))
|
||||
@ -819,7 +820,7 @@ proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_lcd(struct file *file, const char __user * buffer,
|
||||
proc_write_lcd(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int rv, value;
|
||||
@ -897,7 +898,7 @@ proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_write_brn(struct file *file, const char __user * buffer,
|
||||
proc_write_brn(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int rv, value;
|
||||
@ -921,7 +922,7 @@ static void set_display(int value)
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, *this* one could be more user-friendly, but so far, no-one has
|
||||
* Now, *this* one could be more user-friendly, but so far, no-one has
|
||||
* complained. The significance of bits is the same as in proc_write_disp()
|
||||
*/
|
||||
static int
|
||||
@ -933,18 +934,18 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
|
||||
if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
|
||||
printk(KERN_WARNING
|
||||
"Asus ACPI: Error reading display status\n");
|
||||
value &= 0x07; /* needed for some models, shouldn't hurt others */
|
||||
value &= 0x07; /* needed for some models, shouldn't hurt others */
|
||||
return sprintf(page, "%d\n", value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Experimental support for display switching. As of now: 1 should activate
|
||||
* the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
|
||||
* (bitwise) of these will suffice. I never actually tested 3 displays hooked up
|
||||
* simultaneously, so be warned. See the acpi4asus README for more info.
|
||||
* Experimental support for display switching. As of now: 1 should activate
|
||||
* the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
|
||||
* (bitwise) of these will suffice. I never actually tested 3 displays hooked
|
||||
* up simultaneously, so be warned. See the acpi4asus README for more info.
|
||||
*/
|
||||
static int
|
||||
proc_write_disp(struct file *file, const char __user * buffer,
|
||||
proc_write_disp(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
int rv, value;
|
||||
@ -957,12 +958,12 @@ proc_write_disp(struct file *file, const char __user * buffer,
|
||||
|
||||
typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
|
||||
int *eof, void *data);
|
||||
typedef int (proc_writefunc) (struct file * file, const char __user * buffer,
|
||||
typedef int (proc_writefunc) (struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data);
|
||||
|
||||
static int
|
||||
asus_proc_add(char *name, proc_writefunc * writefunc,
|
||||
proc_readfunc * readfunc, mode_t mode,
|
||||
asus_proc_add(char *name, proc_writefunc *writefunc,
|
||||
proc_readfunc *readfunc, mode_t mode,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *proc =
|
||||
@ -1040,9 +1041,9 @@ static int asus_hotk_add_fs(struct acpi_device *device)
|
||||
&proc_read_bluetooth, mode, device);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need both read node and write method as LCD switch is also accessible
|
||||
* from keyboard
|
||||
/*
|
||||
* We need both read node and write method as LCD switch is also
|
||||
* accessible from the keyboard
|
||||
*/
|
||||
if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
|
||||
asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode,
|
||||
@ -1096,11 +1097,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||
if (!hotk)
|
||||
return;
|
||||
|
||||
if ((event & ~((u32) BR_UP)) < 16) {
|
||||
if ((event & ~((u32) BR_UP)) < 16)
|
||||
hotk->brightness = (event & ~((u32) BR_UP));
|
||||
} else if ((event & ~((u32) BR_DOWN)) < 16) {
|
||||
else if ((event & ~((u32) BR_DOWN)) < 16)
|
||||
hotk->brightness = (event & ~((u32) BR_DOWN));
|
||||
}
|
||||
|
||||
acpi_bus_generate_proc_event(hotk->device, event,
|
||||
hotk->event_count[event % 128]++);
|
||||
@ -1186,8 +1186,8 @@ static int asus_hotk_get_info(void)
|
||||
acpi_status status;
|
||||
|
||||
/*
|
||||
* Get DSDT headers early enough to allow for differentiating between
|
||||
* models, but late enough to allow acpi_bus_register_driver() to fail
|
||||
* Get DSDT headers early enough to allow for differentiating between
|
||||
* models, but late enough to allow acpi_bus_register_driver() to fail
|
||||
* before doing anything ACPI-specific. Should we encounter a machine,
|
||||
* which needs special handling (i.e. its hotkey device has a different
|
||||
* HID), this bit will be moved. A global variable asus_info contains
|
||||
@ -1212,8 +1212,8 @@ static int asus_hotk_get_info(void)
|
||||
|
||||
/*
|
||||
* Try to match the object returned by INIT to the specific model.
|
||||
* Handle every possible object (or the lack of thereof) the DSDT
|
||||
* writers might throw at us. When in trouble, we pass NULL to
|
||||
* Handle every possible object (or the lack of thereof) the DSDT
|
||||
* writers might throw at us. When in trouble, we pass NULL to
|
||||
* asus_model_match() and try something completely different.
|
||||
*/
|
||||
if (buffer.pointer) {
|
||||
@ -1244,6 +1244,8 @@ static int asus_hotk_get_info(void)
|
||||
"default values\n", string);
|
||||
printk(KERN_NOTICE
|
||||
" send /proc/acpi/dsdt to the developers\n");
|
||||
kfree(model);
|
||||
return -ENODEV;
|
||||
}
|
||||
hotk->methods = &model_conf[hotk->model];
|
||||
return AE_OK;
|
||||
@ -1254,7 +1256,7 @@ static int asus_hotk_get_info(void)
|
||||
/* Sort of per-model blacklist */
|
||||
if (strncmp(string, "L2B", 3) == 0)
|
||||
hotk->methods->lcd_status = NULL;
|
||||
/* L2B is similar enough to L3C to use its settings, with this only
|
||||
/* L2B is similar enough to L3C to use its settings, with this only
|
||||
exception */
|
||||
else if (strncmp(string, "A3G", 3) == 0)
|
||||
hotk->methods->lcd_status = "\\BLFG";
|
||||
@ -1321,7 +1323,7 @@ static int asus_hotk_add(struct acpi_device *device)
|
||||
hotk->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
|
||||
acpi_driver_data(device) = hotk;
|
||||
device->driver_data = hotk;
|
||||
hotk->device = device;
|
||||
|
||||
result = asus_hotk_check();
|
||||
@ -1366,10 +1368,9 @@ static int asus_hotk_add(struct acpi_device *device)
|
||||
/* LED display is off by default */
|
||||
hotk->ledd_status = 0xFFF;
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
end:
|
||||
if (result)
|
||||
kfree(hotk);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1394,8 +1395,8 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
|
||||
}
|
||||
|
||||
static struct backlight_ops asus_backlight_data = {
|
||||
.get_brightness = read_brightness,
|
||||
.update_status = set_brightness_status,
|
||||
.get_brightness = read_brightness,
|
||||
.update_status = set_brightness_status,
|
||||
};
|
||||
|
||||
static void asus_acpi_exit(void)
|
||||
@ -1442,15 +1443,15 @@ static int __init asus_acpi_init(void)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
asus_backlight_device = backlight_device_register("asus",NULL,NULL,
|
||||
asus_backlight_device = backlight_device_register("asus", NULL, NULL,
|
||||
&asus_backlight_data);
|
||||
if (IS_ERR(asus_backlight_device)) {
|
||||
if (IS_ERR(asus_backlight_device)) {
|
||||
printk(KERN_ERR "Could not register asus backlight device\n");
|
||||
asus_backlight_device = NULL;
|
||||
asus_acpi_exit();
|
||||
return -ENODEV;
|
||||
}
|
||||
asus_backlight_device->props.max_brightness = 15;
|
||||
asus_backlight_device->props.max_brightness = 15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -804,7 +804,7 @@ static int acpi_battery_add(struct acpi_device *device)
|
||||
battery->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
|
||||
acpi_driver_data(device) = battery;
|
||||
device->driver_data = battery;
|
||||
mutex_init(&battery->lock);
|
||||
acpi_battery_update(battery);
|
||||
#ifdef CONFIG_ACPI_PROCFS_POWER
|
||||
|
@ -1,411 +0,0 @@
|
||||
/*
|
||||
* bay.c - ACPI removable drive bay driver
|
||||
*
|
||||
* Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
ACPI_MODULE_NAME("bay");
|
||||
MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
#define ACPI_BAY_CLASS "bay"
|
||||
#define ACPI_BAY_COMPONENT 0x10000000
|
||||
#define _COMPONENT ACPI_BAY_COMPONENT
|
||||
#define bay_dprintk(h,s) {\
|
||||
char prefix[80] = {'\0'};\
|
||||
struct acpi_buffer buffer = {sizeof(prefix), prefix};\
|
||||
acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
|
||||
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
|
||||
static void bay_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
static const struct acpi_device_id bay_device_ids[] = {
|
||||
{"LNXIOBAY", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bay_device_ids);
|
||||
|
||||
struct bay {
|
||||
acpi_handle handle;
|
||||
char *name;
|
||||
struct list_head list;
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
||||
static LIST_HEAD(drive_bays);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Drive Bay functions *
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* is_ejectable - see if a device is ejectable
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object has a _EJ0 method, then it is ejectable
|
||||
*/
|
||||
static int is_ejectable(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* bay_present - see if the bay device is present
|
||||
* @bay: the drive bay
|
||||
*
|
||||
* execute the _STA method.
|
||||
*/
|
||||
static int bay_present(struct bay *bay)
|
||||
{
|
||||
unsigned long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (bay) {
|
||||
status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
|
||||
if (ACPI_SUCCESS(status) && sta)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* eject_device - respond to an eject request
|
||||
* @handle - the device to eject
|
||||
*
|
||||
* Call this devices _EJ0 method.
|
||||
*/
|
||||
static void eject_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
|
||||
bay_dprintk(handle, "Ejecting device");
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
&arg_list, NULL)))
|
||||
pr_debug("Failed to evaluate _EJ0!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* show_present - read method for "present" file in sysfs
|
||||
*/
|
||||
static ssize_t show_present(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct bay *bay = dev_get_drvdata(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
|
||||
|
||||
}
|
||||
static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
|
||||
|
||||
/*
|
||||
* write_eject - write method for "eject" file in sysfs
|
||||
*/
|
||||
static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct bay *bay = dev_get_drvdata(dev);
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
eject_device(bay->handle);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
|
||||
|
||||
/**
|
||||
* is_ata - see if a device is an ata device
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* If an acpi object has one of 4 ATA ACPI methods defined,
|
||||
* then it is an ATA device
|
||||
*/
|
||||
static int is_ata(acpi_handle handle)
|
||||
{
|
||||
acpi_handle tmp;
|
||||
|
||||
if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* parent_is_ata(acpi_handle handle)
|
||||
*
|
||||
*/
|
||||
static int parent_is_ata(acpi_handle handle)
|
||||
{
|
||||
acpi_handle phandle;
|
||||
|
||||
if (acpi_get_parent(handle, &phandle))
|
||||
return 0;
|
||||
|
||||
return is_ata(phandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_ejectable_bay - see if a device is an ejectable drive bay
|
||||
* @handle: acpi handle of the device
|
||||
*
|
||||
* 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 is_ejectable_bay(acpi_handle handle)
|
||||
{
|
||||
if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* eject_removable_drive - try to eject this drive
|
||||
* @dev : the device structure of the drive
|
||||
*
|
||||
* If a device is a removable drive that requires an _EJ0 method
|
||||
* to be executed in order to safely remove from the system, do
|
||||
* it. ATM - always returns success
|
||||
*/
|
||||
int eject_removable_drive(struct device *dev)
|
||||
{
|
||||
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
|
||||
|
||||
if (handle) {
|
||||
bay_dprintk(handle, "Got device handle");
|
||||
if (is_ejectable_bay(handle))
|
||||
eject_device(handle);
|
||||
} else {
|
||||
printk("No acpi handle for device\n");
|
||||
}
|
||||
|
||||
/* should I return an error code? */
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eject_removable_drive);
|
||||
#endif /* 0 */
|
||||
|
||||
static int acpi_bay_add_fs(struct bay *bay)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &bay->pdev->dev;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_present);
|
||||
if (ret)
|
||||
goto add_fs_err;
|
||||
ret = device_create_file(dev, &dev_attr_eject);
|
||||
if (ret) {
|
||||
device_remove_file(dev, &dev_attr_present);
|
||||
goto add_fs_err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
add_fs_err:
|
||||
bay_dprintk(bay->handle, "Error adding sysfs files\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_bay_remove_fs(struct bay *bay)
|
||||
{
|
||||
struct device *dev = &bay->pdev->dev;
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(dev, &dev_attr_present);
|
||||
device_remove_file(dev, &dev_attr_eject);
|
||||
}
|
||||
|
||||
static int bay_is_dock_device(acpi_handle handle)
|
||||
{
|
||||
acpi_handle parent;
|
||||
|
||||
acpi_get_parent(handle, &parent);
|
||||
|
||||
/* if the device or it's parent is dependent on the
|
||||
* dock, then we are a dock device
|
||||
*/
|
||||
return (is_dock_device(handle) || is_dock_device(parent));
|
||||
}
|
||||
|
||||
static int bay_add(acpi_handle handle, int id)
|
||||
{
|
||||
acpi_status status;
|
||||
struct bay *new_bay;
|
||||
struct platform_device *pdev;
|
||||
struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
|
||||
|
||||
bay_dprintk(handle, "Adding notify handler");
|
||||
|
||||
/*
|
||||
* Initialize bay device structure
|
||||
*/
|
||||
new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
|
||||
INIT_LIST_HEAD(&new_bay->list);
|
||||
new_bay->handle = handle;
|
||||
new_bay->name = (char *)nbuffer.pointer;
|
||||
|
||||
/* initialize platform device stuff */
|
||||
pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
printk(KERN_ERR PREFIX "Error registering bay device\n");
|
||||
goto bay_add_err;
|
||||
}
|
||||
new_bay->pdev = pdev;
|
||||
platform_set_drvdata(pdev, new_bay);
|
||||
|
||||
/*
|
||||
* we want the bay driver to be able to send uevents
|
||||
*/
|
||||
pdev->dev.uevent_suppress = 0;
|
||||
|
||||
/* register for events on this device */
|
||||
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
bay_notify, new_bay);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
|
||||
platform_device_unregister(new_bay->pdev);
|
||||
goto bay_add_err;
|
||||
}
|
||||
|
||||
if (acpi_bay_add_fs(new_bay)) {
|
||||
acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
bay_notify);
|
||||
platform_device_unregister(new_bay->pdev);
|
||||
goto bay_add_err;
|
||||
}
|
||||
|
||||
/* if we are on a dock station, we should register for dock
|
||||
* notifications.
|
||||
*/
|
||||
if (bay_is_dock_device(handle)) {
|
||||
bay_dprintk(handle, "Is dependent on dock\n");
|
||||
register_hotplug_dock_device(handle, bay_notify, new_bay);
|
||||
}
|
||||
list_add(&new_bay->list, &drive_bays);
|
||||
printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
|
||||
return 0;
|
||||
|
||||
bay_add_err:
|
||||
kfree(new_bay->name);
|
||||
kfree(new_bay);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* bay_notify - act upon an acpi bay notification
|
||||
* @handle: the bay handle
|
||||
* @event: the acpi event
|
||||
* @data: our driver data struct
|
||||
*
|
||||
*/
|
||||
static void bay_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct bay *bay_dev = (struct bay *)data;
|
||||
struct device *dev = &bay_dev->pdev->dev;
|
||||
char event_string[12];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
bay_dprintk(handle, "Bay event");
|
||||
sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int *count = (int *)context;
|
||||
|
||||
/*
|
||||
* there could be more than one ejectable bay.
|
||||
* so, just return AE_OK always so that every object
|
||||
* will be checked.
|
||||
*/
|
||||
if (is_ejectable_bay(handle)) {
|
||||
bay_dprintk(handle, "found ejectable bay");
|
||||
if (!bay_add(handle, *count))
|
||||
(*count)++;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init bay_init(void)
|
||||
{
|
||||
int bays = 0;
|
||||
|
||||
INIT_LIST_HEAD(&drive_bays);
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
/* look for dockable drive bays */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_bay, &bays, NULL);
|
||||
|
||||
if (!bays)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit bay_exit(void)
|
||||
{
|
||||
struct bay *bay, *tmp;
|
||||
|
||||
list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
|
||||
if (is_dock_device(bay->handle))
|
||||
unregister_hotplug_dock_device(bay->handle);
|
||||
acpi_bay_remove_fs(bay);
|
||||
acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
|
||||
bay_notify);
|
||||
platform_device_unregister(bay->pdev);
|
||||
kfree(bay->name);
|
||||
kfree(bay);
|
||||
}
|
||||
}
|
||||
|
||||
postcore_initcall(bay_init);
|
||||
module_exit(bay_exit);
|
||||
|
@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir);
|
||||
|
||||
#define STRUCT_TO_INT(s) (*((int*)&s))
|
||||
|
||||
static int set_power_nocheck(const struct dmi_system_id *id)
|
||||
{
|
||||
printk(KERN_NOTICE PREFIX "%s detected - "
|
||||
"disable power check in power transistion\n", id->ident);
|
||||
acpi_power_nocheck = 1;
|
||||
return 0;
|
||||
}
|
||||
static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
|
||||
{
|
||||
set_power_nocheck, "HP Pavilion 05", {
|
||||
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Device Management
|
||||
-------------------------------------------------------------------------- */
|
||||
@ -77,7 +94,7 @@ EXPORT_SYMBOL(acpi_bus_get_device);
|
||||
int acpi_bus_get_status(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long sta = 0;
|
||||
unsigned long long sta = 0;
|
||||
|
||||
|
||||
if (!device)
|
||||
@ -95,21 +112,21 @@ int acpi_bus_get_status(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we assume the status of our parent (unless we don't
|
||||
* have one, in which case status is implied).
|
||||
* According to ACPI spec some device can be present and functional
|
||||
* even if the parent is not present but functional.
|
||||
* In such conditions the child device should not inherit the status
|
||||
* from the parent.
|
||||
*/
|
||||
else if (device->parent)
|
||||
device->status = device->parent->status;
|
||||
else
|
||||
STRUCT_TO_INT(device->status) =
|
||||
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
|
||||
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
|
||||
|
||||
if (device->status.functional && !device->status.present) {
|
||||
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
|
||||
"functional but not present; setting present\n",
|
||||
device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status));
|
||||
device->status.present = 1;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
|
||||
"functional but not present;\n",
|
||||
device->pnp.bus_id,
|
||||
(u32) STRUCT_TO_INT(device->status)));
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
|
||||
@ -155,7 +172,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
unsigned long psc = 0;
|
||||
unsigned long long psc = 0;
|
||||
|
||||
|
||||
result = acpi_bus_get_device(handle, &device);
|
||||
@ -223,7 +240,19 @@ int acpi_bus_set_power(acpi_handle handle, int state)
|
||||
/*
|
||||
* Get device's current power state
|
||||
*/
|
||||
acpi_bus_get_power(device->handle, &device->power.state);
|
||||
if (!acpi_power_nocheck) {
|
||||
/*
|
||||
* Maybe the incorrect power state is returned on the bogus
|
||||
* bios, which is different with the real power state.
|
||||
* For example: the bios returns D0 state and the real power
|
||||
* state is D3. OS expects to set the device to D0 state. In
|
||||
* such case if OS uses the power state returned by the BIOS,
|
||||
* the device can't be transisted to the correct power state.
|
||||
* So if the acpi_power_nocheck is set, it is unnecessary to
|
||||
* get the power state by calling acpi_bus_get_power.
|
||||
*/
|
||||
acpi_bus_get_power(device->handle, &device->power.state);
|
||||
}
|
||||
if ((state == device->power.state) && !device->flags.force_power_state) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
|
||||
state));
|
||||
@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
|
||||
int register_acpi_bus_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
|
||||
|
||||
void unregister_acpi_bus_notifier(struct notifier_block *nb)
|
||||
{
|
||||
blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
|
||||
|
||||
/**
|
||||
* acpi_bus_notify
|
||||
* ---------------
|
||||
@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||
int result = 0;
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
blocking_notifier_call_chain(&acpi_bus_notify_list,
|
||||
type, (void *)handle);
|
||||
|
||||
if (acpi_bus_get_device(handle, &device))
|
||||
return;
|
||||
@ -749,6 +793,12 @@ static int __init acpi_bus_init(void)
|
||||
goto error1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maybe EC region is required at bus_scan/acpi_get_devices. So it
|
||||
* is necessary to enable it as early as possible.
|
||||
*/
|
||||
acpi_boot_ec_enable();
|
||||
|
||||
printk(KERN_INFO PREFIX "Interpreter enabled\n");
|
||||
|
||||
/* Initialize sleep structures */
|
||||
@ -818,7 +868,11 @@ static int __init acpi_init(void)
|
||||
}
|
||||
} else
|
||||
disable_acpi();
|
||||
|
||||
/*
|
||||
* If the laptop falls into the DMI check table, the power state check
|
||||
* will be disabled in the course of device power transistion.
|
||||
*/
|
||||
dmi_check_system(power_nocheck_dmi_table);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_button *button = seq->private;
|
||||
acpi_status status;
|
||||
unsigned long state;
|
||||
unsigned long long state;
|
||||
|
||||
if (!button || !button->device)
|
||||
return 0;
|
||||
@ -253,7 +253,7 @@ static int acpi_button_remove_fs(struct acpi_device *device)
|
||||
-------------------------------------------------------------------------- */
|
||||
static int acpi_lid_send_state(struct acpi_button *button)
|
||||
{
|
||||
unsigned long state;
|
||||
unsigned long long state;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL,
|
||||
@ -384,7 +384,7 @@ static int acpi_button_add(struct acpi_device *device)
|
||||
return -ENOMEM;
|
||||
|
||||
button->device = device;
|
||||
acpi_driver_data(device) = button;
|
||||
device->driver_data = button;
|
||||
|
||||
button->input = input = input_allocate_device();
|
||||
if (!input) {
|
||||
|
@ -52,8 +52,8 @@ struct proc_dir_entry *acpi_lock_ac_dir(void)
|
||||
if (acpi_ac_dir) {
|
||||
lock_ac_dir_cnt++;
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Cannot create %s\n", ACPI_AC_CLASS));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Cannot create %s\n", ACPI_AC_CLASS);
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
return acpi_ac_dir;
|
||||
@ -83,8 +83,8 @@ struct proc_dir_entry *acpi_lock_battery_dir(void)
|
||||
if (acpi_battery_dir) {
|
||||
lock_battery_dir_cnt++;
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Cannot create %s\n", ACPI_BATTERY_CLASS));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Cannot create %s\n", ACPI_BATTERY_CLASS);
|
||||
}
|
||||
mutex_unlock(&cm_sbs_mutex);
|
||||
return acpi_battery_dir;
|
||||
|
@ -76,7 +76,7 @@ static int is_device_present(acpi_handle handle)
|
||||
{
|
||||
acpi_handle temp;
|
||||
acpi_status status;
|
||||
unsigned long sta;
|
||||
unsigned long long sta;
|
||||
|
||||
|
||||
status = acpi_get_handle(handle, "_STA", &temp);
|
||||
@ -108,7 +108,7 @@ static int acpi_container_add(struct acpi_device *device)
|
||||
container->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
|
||||
acpi_driver_data(device) = container;
|
||||
device->driver_data = container;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
|
||||
acpi_device_name(device), acpi_device_bid(device)));
|
||||
|
@ -47,8 +47,6 @@ static const struct acpi_dlayer acpi_debug_layers[] = {
|
||||
};
|
||||
|
||||
static const struct acpi_dlevel acpi_debug_levels[] = {
|
||||
ACPI_DEBUG_INIT(ACPI_LV_ERROR),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_WARN),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INIT),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
|
||||
ACPI_DEBUG_INIT(ACPI_LV_INFO),
|
||||
|
@ -103,6 +103,9 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
|
||||
NULL);
|
||||
acpi_ex_enter_interpreter();
|
||||
}
|
||||
|
||||
acpi_ds_clear_implicit_return(walk_state);
|
||||
|
||||
#ifdef ACPI_DISASSEMBLER
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acinterp.h>
|
||||
|
||||
@ -52,11 +51,11 @@ ACPI_MODULE_NAME("dsmthdat")
|
||||
|
||||
/* Local prototypes */
|
||||
static void
|
||||
acpi_ds_method_data_delete_value(u16 opcode,
|
||||
acpi_ds_method_data_delete_value(u8 type,
|
||||
u32 index, struct acpi_walk_state *walk_state);
|
||||
|
||||
static acpi_status
|
||||
acpi_ds_method_data_set_value(u16 opcode,
|
||||
acpi_ds_method_data_set_value(u8 type,
|
||||
u32 index,
|
||||
union acpi_operand_object *object,
|
||||
struct acpi_walk_state *walk_state);
|
||||
@ -216,7 +215,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
|
||||
* Store the argument in the method/walk descriptor.
|
||||
* Do not copy the arg in order to implement call by reference
|
||||
*/
|
||||
status = acpi_ds_method_data_set_value(AML_ARG_OP, index,
|
||||
status = acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,
|
||||
params[index],
|
||||
walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -234,7 +233,8 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_get_node
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
|
||||
* ACPI_REFCLASS_ARG
|
||||
* Index - Which Local or Arg whose type to get
|
||||
* walk_state - Current walk state object
|
||||
* Node - Where the node is returned.
|
||||
@ -246,7 +246,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ds_method_data_get_node(u16 opcode,
|
||||
acpi_ds_method_data_get_node(u8 type,
|
||||
u32 index,
|
||||
struct acpi_walk_state *walk_state,
|
||||
struct acpi_namespace_node **node)
|
||||
@ -256,8 +256,8 @@ acpi_ds_method_data_get_node(u16 opcode,
|
||||
/*
|
||||
* Method Locals and Arguments are supported
|
||||
*/
|
||||
switch (opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
switch (type) {
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
|
||||
if (index > ACPI_METHOD_MAX_LOCAL) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
@ -271,7 +271,7 @@ acpi_ds_method_data_get_node(u16 opcode,
|
||||
*node = &walk_state->local_variables[index];
|
||||
break;
|
||||
|
||||
case AML_ARG_OP:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
if (index > ACPI_METHOD_MAX_ARG) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
@ -286,8 +286,8 @@ acpi_ds_method_data_get_node(u16 opcode,
|
||||
break;
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO, "Opcode %d is invalid", opcode));
|
||||
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
|
||||
ACPI_ERROR((AE_INFO, "Type %d is invalid", type));
|
||||
return_ACPI_STATUS(AE_TYPE);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
@ -297,7 +297,8 @@ acpi_ds_method_data_get_node(u16 opcode,
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_set_value
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
|
||||
* ACPI_REFCLASS_ARG
|
||||
* Index - Which Local or Arg to get
|
||||
* Object - Object to be inserted into the stack entry
|
||||
* walk_state - Current walk state object
|
||||
@ -310,7 +311,7 @@ acpi_ds_method_data_get_node(u16 opcode,
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ds_method_data_set_value(u16 opcode,
|
||||
acpi_ds_method_data_set_value(u8 type,
|
||||
u32 index,
|
||||
union acpi_operand_object *object,
|
||||
struct acpi_walk_state *walk_state)
|
||||
@ -321,13 +322,13 @@ acpi_ds_method_data_set_value(u16 opcode,
|
||||
ACPI_FUNCTION_TRACE(ds_method_data_set_value);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"NewObj %p Opcode %X, Refs=%d [%s]\n", object,
|
||||
opcode, object->common.reference_count,
|
||||
"NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
|
||||
type, object->common.reference_count,
|
||||
acpi_ut_get_type_name(object->common.type)));
|
||||
|
||||
/* Get the namespace node for the arg/local */
|
||||
|
||||
status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
|
||||
status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
@ -350,7 +351,8 @@ acpi_ds_method_data_set_value(u16 opcode,
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_get_value
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
|
||||
* ACPI_REFCLASS_ARG
|
||||
* Index - Which local_var or argument to get
|
||||
* walk_state - Current walk state object
|
||||
* dest_desc - Where Arg or Local value is returned
|
||||
@ -363,7 +365,7 @@ acpi_ds_method_data_set_value(u16 opcode,
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ds_method_data_get_value(u16 opcode,
|
||||
acpi_ds_method_data_get_value(u8 type,
|
||||
u32 index,
|
||||
struct acpi_walk_state *walk_state,
|
||||
union acpi_operand_object **dest_desc)
|
||||
@ -383,7 +385,7 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
|
||||
/* Get the namespace node for the arg/local */
|
||||
|
||||
status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
|
||||
status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
@ -419,8 +421,8 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
/* Otherwise, return the error */
|
||||
|
||||
else
|
||||
switch (opcode) {
|
||||
case AML_ARG_OP:
|
||||
switch (type) {
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Uninitialized Arg[%d] at node %p",
|
||||
@ -428,7 +430,7 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
|
||||
return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Uninitialized Local[%d] at node %p",
|
||||
@ -437,9 +439,10 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Not a Arg/Local opcode: %X",
|
||||
opcode));
|
||||
type));
|
||||
return_ACPI_STATUS(AE_AML_INTERNAL);
|
||||
}
|
||||
}
|
||||
@ -458,7 +461,8 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
*
|
||||
* FUNCTION: acpi_ds_method_data_delete_value
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
|
||||
* ACPI_REFCLASS_ARG
|
||||
* Index - Which local_var or argument to delete
|
||||
* walk_state - Current walk state object
|
||||
*
|
||||
@ -470,7 +474,7 @@ acpi_ds_method_data_get_value(u16 opcode,
|
||||
******************************************************************************/
|
||||
|
||||
static void
|
||||
acpi_ds_method_data_delete_value(u16 opcode,
|
||||
acpi_ds_method_data_delete_value(u8 type,
|
||||
u32 index, struct acpi_walk_state *walk_state)
|
||||
{
|
||||
acpi_status status;
|
||||
@ -481,7 +485,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
|
||||
|
||||
/* Get the namespace node for the arg/local */
|
||||
|
||||
status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
|
||||
status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_VOID;
|
||||
}
|
||||
@ -514,7 +518,8 @@ acpi_ds_method_data_delete_value(u16 opcode,
|
||||
*
|
||||
* FUNCTION: acpi_ds_store_object_to_local
|
||||
*
|
||||
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
|
||||
* PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
|
||||
* ACPI_REFCLASS_ARG
|
||||
* Index - Which Local or Arg to set
|
||||
* obj_desc - Value to be stored
|
||||
* walk_state - Current walk state
|
||||
@ -528,7 +533,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ds_store_object_to_local(u16 opcode,
|
||||
acpi_ds_store_object_to_local(u8 type,
|
||||
u32 index,
|
||||
union acpi_operand_object *obj_desc,
|
||||
struct acpi_walk_state *walk_state)
|
||||
@ -539,8 +544,8 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
union acpi_operand_object *new_obj_desc;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ds_store_object_to_local);
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n",
|
||||
opcode, index, obj_desc));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
|
||||
type, index, obj_desc));
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
@ -550,7 +555,7 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
|
||||
/* Get the namespace node for the arg/local */
|
||||
|
||||
status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
|
||||
status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
@ -602,7 +607,7 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
*
|
||||
* Weird, but true.
|
||||
*/
|
||||
if (opcode == AML_ARG_OP) {
|
||||
if (type == ACPI_REFCLASS_ARG) {
|
||||
/*
|
||||
* If we have a valid reference object that came from ref_of(),
|
||||
* do the indirect store
|
||||
@ -611,8 +616,8 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
ACPI_DESC_TYPE_OPERAND)
|
||||
&& (current_obj_desc->common.type ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& (current_obj_desc->reference.opcode ==
|
||||
AML_REF_OF_OP)) {
|
||||
&& (current_obj_desc->reference.class ==
|
||||
ACPI_REFCLASS_REFOF)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Arg (%p) is an ObjRef(Node), storing in node %p\n",
|
||||
new_obj_desc,
|
||||
@ -640,11 +645,9 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the existing object
|
||||
* before storing the new one
|
||||
*/
|
||||
acpi_ds_method_data_delete_value(opcode, index, walk_state);
|
||||
/* Delete the existing object before storing the new one */
|
||||
|
||||
acpi_ds_method_data_delete_value(type, index, walk_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -653,7 +656,7 @@ acpi_ds_store_object_to_local(u16 opcode,
|
||||
* (increments the object reference count by one)
|
||||
*/
|
||||
status =
|
||||
acpi_ds_method_data_set_value(opcode, index, new_obj_desc,
|
||||
acpi_ds_method_data_set_value(type, index, new_obj_desc,
|
||||
walk_state);
|
||||
|
||||
/* Remove local reference if we copied the object above */
|
||||
|
@ -731,54 +731,70 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
|
||||
switch (op_info->type) {
|
||||
case AML_TYPE_LOCAL_VARIABLE:
|
||||
|
||||
/* Split the opcode into a base opcode + offset */
|
||||
/* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */
|
||||
|
||||
obj_desc->reference.opcode = AML_LOCAL_OP;
|
||||
obj_desc->reference.offset = opcode - AML_LOCAL_OP;
|
||||
obj_desc->reference.value = opcode - AML_LOCAL_OP;
|
||||
obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
status = acpi_ds_method_data_get_node(AML_LOCAL_OP,
|
||||
obj_desc->
|
||||
reference.offset,
|
||||
walk_state,
|
||||
(struct
|
||||
acpi_namespace_node
|
||||
**)&obj_desc->
|
||||
reference.object);
|
||||
status =
|
||||
acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL,
|
||||
obj_desc->reference.
|
||||
value, walk_state,
|
||||
ACPI_CAST_INDIRECT_PTR
|
||||
(struct
|
||||
acpi_namespace_node,
|
||||
&obj_desc->reference.
|
||||
object));
|
||||
#endif
|
||||
break;
|
||||
|
||||
case AML_TYPE_METHOD_ARGUMENT:
|
||||
|
||||
/* Split the opcode into a base opcode + offset */
|
||||
/* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */
|
||||
|
||||
obj_desc->reference.opcode = AML_ARG_OP;
|
||||
obj_desc->reference.offset = opcode - AML_ARG_OP;
|
||||
obj_desc->reference.value = opcode - AML_ARG_OP;
|
||||
obj_desc->reference.class = ACPI_REFCLASS_ARG;
|
||||
|
||||
#ifndef ACPI_NO_METHOD_EXECUTION
|
||||
status = acpi_ds_method_data_get_node(AML_ARG_OP,
|
||||
status = acpi_ds_method_data_get_node(ACPI_REFCLASS_ARG,
|
||||
obj_desc->
|
||||
reference.offset,
|
||||
reference.value,
|
||||
walk_state,
|
||||
ACPI_CAST_INDIRECT_PTR
|
||||
(struct
|
||||
acpi_namespace_node
|
||||
**)&obj_desc->
|
||||
reference.object);
|
||||
acpi_namespace_node,
|
||||
&obj_desc->
|
||||
reference.
|
||||
object));
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: /* Other literals, etc.. */
|
||||
default: /* Object name or Debug object */
|
||||
|
||||
if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
|
||||
switch (op->common.aml_opcode) {
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
|
||||
/* Node was saved in Op */
|
||||
|
||||
obj_desc->reference.node = op->common.node;
|
||||
obj_desc->reference.object =
|
||||
op->common.node->object;
|
||||
}
|
||||
obj_desc->reference.class = ACPI_REFCLASS_NAME;
|
||||
break;
|
||||
|
||||
obj_desc->reference.opcode = opcode;
|
||||
case AML_DEBUG_OP:
|
||||
|
||||
obj_desc->reference.class = ACPI_REFCLASS_DEBUG;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unimplemented reference type for AML opcode: %4.4X",
|
||||
opcode));
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -1330,7 +1330,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
|
||||
(walk_state->results->results.obj_desc[0]) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& ((walk_state->results->results.obj_desc[0])->
|
||||
reference.opcode != AML_INDEX_OP)) {
|
||||
reference.class != ACPI_REFCLASS_INDEX)) {
|
||||
status =
|
||||
acpi_ex_resolve_to_value(&walk_state->
|
||||
results->results.
|
||||
|
@ -166,6 +166,10 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
|
||||
status = AE_CTRL_FALSE;
|
||||
}
|
||||
|
||||
/* Predicate can be used for an implicit return value */
|
||||
|
||||
(void)acpi_ds_do_implicit_return(local_obj_desc, walk_state, TRUE);
|
||||
|
||||
cleanup:
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n",
|
||||
@ -429,10 +433,10 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& (walk_state->operands[1]->common.type ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& (walk_state->operands[0]->reference.opcode ==
|
||||
walk_state->operands[1]->reference.opcode)
|
||||
&& (walk_state->operands[0]->reference.offset ==
|
||||
walk_state->operands[1]->reference.offset)) {
|
||||
&& (walk_state->operands[0]->reference.class ==
|
||||
walk_state->operands[1]->reference.class)
|
||||
&& (walk_state->operands[0]->reference.value ==
|
||||
walk_state->operands[1]->reference.value)) {
|
||||
status = AE_OK;
|
||||
} else {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
|
@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
|
||||
" before undocking");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
static struct platform_device *dock_device;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
static const struct acpi_device_id dock_device_ids[] = {
|
||||
@ -65,23 +64,29 @@ struct dock_station {
|
||||
struct mutex hp_lock;
|
||||
struct list_head dependent_devices;
|
||||
struct list_head hotplug_devices;
|
||||
|
||||
struct list_head sibiling;
|
||||
struct platform_device *dock_device;
|
||||
};
|
||||
static LIST_HEAD(dock_stations);
|
||||
static int dock_station_count;
|
||||
|
||||
struct dock_dependent_device {
|
||||
struct list_head list;
|
||||
struct list_head hotplug_list;
|
||||
acpi_handle handle;
|
||||
acpi_notify_handler handler;
|
||||
struct acpi_dock_ops *ops;
|
||||
void *context;
|
||||
};
|
||||
|
||||
#define DOCK_DOCKING 0x00000001
|
||||
#define DOCK_UNDOCKING 0x00000002
|
||||
#define DOCK_IS_DOCK 0x00000010
|
||||
#define DOCK_IS_ATA 0x00000020
|
||||
#define DOCK_IS_BAT 0x00000040
|
||||
#define DOCK_EVENT 3
|
||||
#define UNDOCK_EVENT 2
|
||||
|
||||
static struct dock_station *dock_station;
|
||||
|
||||
/*****************************************************************************
|
||||
* Dock Dependent device functions *
|
||||
*****************************************************************************/
|
||||
@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_ejectable(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_ata(acpi_handle handle)
|
||||
{
|
||||
acpi_handle tmp;
|
||||
|
||||
if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
|
||||
(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_battery(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device_info *info;
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
int ret = 1;
|
||||
|
||||
if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
|
||||
return 0;
|
||||
info = buffer.pointer;
|
||||
if (!(info->valid & ACPI_VALID_HID))
|
||||
ret = 0;
|
||||
else
|
||||
ret = !strcmp("PNP0C0A", info->hardware_id.value);
|
||||
|
||||
kfree(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_ejectable_bay(acpi_handle handle)
|
||||
{
|
||||
acpi_handle phandle;
|
||||
if (!is_ejectable(handle))
|
||||
return 0;
|
||||
if (is_battery(handle) || is_ata(handle))
|
||||
return 1;
|
||||
if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_dock_device - see if a device is on a dock station
|
||||
* @handle: acpi handle of the device
|
||||
@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
|
||||
*/
|
||||
int is_dock_device(acpi_handle handle)
|
||||
{
|
||||
if (!dock_station)
|
||||
struct dock_station *dock_station;
|
||||
|
||||
if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
|
||||
if (is_dock(handle))
|
||||
return 1;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
if (find_dock_dependent_device(dock_station, handle))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -229,7 +294,7 @@ EXPORT_SYMBOL_GPL(is_dock_device);
|
||||
*/
|
||||
static int dock_present(struct dock_station *ds)
|
||||
{
|
||||
unsigned long sta;
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
|
||||
if (ds) {
|
||||
@ -320,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
* First call driver specific hotplug functions
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
|
||||
if (dd->handler)
|
||||
dd->handler(dd->handle, event, dd->context);
|
||||
if (dd->ops && dd->ops->handler)
|
||||
dd->ops->handler(dd->handle, event, dd->context);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -341,9 +406,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
|
||||
static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
{
|
||||
struct device *dev = &dock_device->dev;
|
||||
struct device *dev = &ds->dock_device->dev;
|
||||
char event_string[13];
|
||||
char *envp[] = { event_string, NULL };
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
if (num == UNDOCK_EVENT)
|
||||
sprintf(event_string, "EVENT=undock");
|
||||
@ -354,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
* Indicate that the status of the dock station has
|
||||
* changed.
|
||||
*/
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
if (num == DOCK_EVENT)
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
|
||||
if (dd->ops && dd->ops->uevent)
|
||||
dd->ops->uevent(dd->handle, event, dd->context);
|
||||
if (num != DOCK_EVENT)
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -414,9 +487,10 @@ static void handle_dock(struct dock_station *ds, int dock)
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = dock;
|
||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
|
||||
(char *)name_buffer.pointer);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||
ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
|
||||
" _DCK\n", (char *)name_buffer.pointer));
|
||||
|
||||
kfree(buffer.pointer);
|
||||
kfree(name_buffer.pointer);
|
||||
}
|
||||
@ -452,6 +526,25 @@ static inline void complete_undock(struct dock_station *ds)
|
||||
ds->flags &= ~(DOCK_UNDOCKING);
|
||||
}
|
||||
|
||||
static void dock_lock(struct dock_station *ds, int lock)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status;
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = !!lock;
|
||||
status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
if (lock)
|
||||
printk(KERN_WARNING PREFIX "Locking device failed\n");
|
||||
else
|
||||
printk(KERN_WARNING PREFIX "Unlocking device failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_in_progress - see if we are in the middle of handling a dock event
|
||||
* @ds: the dock station
|
||||
@ -479,7 +572,7 @@ static int dock_in_progress(struct dock_station *ds)
|
||||
*/
|
||||
int register_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
if (!dock_station)
|
||||
if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
||||
@ -493,7 +586,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
|
||||
*/
|
||||
void unregister_dock_notifier(struct notifier_block *nb)
|
||||
{
|
||||
if (!dock_station)
|
||||
if (!dock_station_count)
|
||||
return;
|
||||
|
||||
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
||||
@ -504,7 +597,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
/**
|
||||
* register_hotplug_dock_device - register a hotplug function
|
||||
* @handle: the handle of the device
|
||||
* @handler: the acpi_notifier_handler to call after docking
|
||||
* @ops: handlers to call after docking
|
||||
* @context: device specific data
|
||||
*
|
||||
* If a driver would like to perform a hotplug operation after a dock
|
||||
@ -512,27 +605,36 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
* the dock driver after _DCK is executed.
|
||||
*/
|
||||
int
|
||||
register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
|
||||
register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
|
||||
void *context)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!dock_station)
|
||||
if (!dock_station_count)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* make sure this handle is for a device dependent on the dock,
|
||||
* this would include the dock station itself
|
||||
*/
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
dd->handler = handler;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
return 0;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
/*
|
||||
* An ATA bay can be in a dock and itself can be ejected
|
||||
* seperately, so there are two 'dock stations' which need the
|
||||
* ops
|
||||
*/
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd) {
|
||||
dd->ops = ops;
|
||||
dd->context = context;
|
||||
dock_add_hotplug_device(dock_station, dd);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
@ -544,13 +646,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
void unregister_hotplug_dock_device(acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
|
||||
if (!dock_station)
|
||||
if (!dock_station_count)
|
||||
return;
|
||||
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd)
|
||||
dock_del_hotplug_device(dock_station, dd);
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
dd = find_dock_dependent_device(dock_station, handle);
|
||||
if (dd)
|
||||
dock_del_hotplug_device(dock_station, dd);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
|
||||
@ -575,13 +680,9 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
*/
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
|
||||
if (!dock_present(ds)) {
|
||||
complete_undock(ds);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
|
||||
undock(ds);
|
||||
dock_lock(ds, 0);
|
||||
eject_dock(ds);
|
||||
if (dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
||||
@ -604,14 +705,36 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct dock_station *ds = data;
|
||||
struct acpi_device *tmp;
|
||||
int surprise_removal = 0;
|
||||
|
||||
/*
|
||||
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
* is sent and _DCK is present, it is assumed to mean an undock
|
||||
* request.
|
||||
*/
|
||||
if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
|
||||
/*
|
||||
* dock station: BUS_CHECK - docked or surprise removal
|
||||
* DEVICE_CHECK - undocked
|
||||
* other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
|
||||
*
|
||||
* To simplify event handling, dock dependent device handler always
|
||||
* get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
* ACPI_NOTIFY_EJECT_REQUEST for removal
|
||||
*/
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
if (!dock_in_progress(ds) && dock_present(ds)) {
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
|
||||
&tmp)) {
|
||||
begin_dock(ds);
|
||||
dock(ds);
|
||||
if (!dock_present(ds)) {
|
||||
printk(KERN_ERR PREFIX "Unable to dock!\n");
|
||||
complete_dock(ds);
|
||||
break;
|
||||
}
|
||||
atomic_notifier_call_chain(&dock_notifier_list,
|
||||
@ -619,20 +742,19 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
hotplug_dock_devices(ds, event);
|
||||
complete_dock(ds);
|
||||
dock_event(ds, event, DOCK_EVENT);
|
||||
dock_lock(ds, 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
/*
|
||||
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
|
||||
* is sent and _DCK is present, it is assumed to mean an
|
||||
* undock request. This notify routine will only be called
|
||||
* for objects defining _DCK, so we will fall through to eject
|
||||
* request here. However, we will pass an eject request through
|
||||
* to the driver who wish to hotplug.
|
||||
*/
|
||||
if (dock_present(ds) || dock_in_progress(ds))
|
||||
break;
|
||||
/* This is a surprise removal */
|
||||
surprise_removal = 1;
|
||||
event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
/* Fall back */
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
begin_undock(ds);
|
||||
if (immediate_undock)
|
||||
if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
|
||||
|| surprise_removal)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
@ -642,6 +764,51 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
struct dock_data {
|
||||
acpi_handle handle;
|
||||
unsigned long event;
|
||||
struct dock_station *ds;
|
||||
};
|
||||
|
||||
static void acpi_dock_deferred_cb(void *context)
|
||||
{
|
||||
struct dock_data *data = (struct dock_data *)context;
|
||||
|
||||
dock_notify(data->handle, data->event, data->ds);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int acpi_dock_notifier_call(struct notifier_block *this,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct dock_station *dock_station;
|
||||
acpi_handle handle = (acpi_handle)data;
|
||||
|
||||
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
||||
&& event != ACPI_NOTIFY_EJECT_REQUEST)
|
||||
return 0;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling) {
|
||||
if (dock_station->handle == handle) {
|
||||
struct dock_data *dock_data;
|
||||
|
||||
dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
|
||||
if (!dock_data)
|
||||
return 0;
|
||||
dock_data->handle = handle;
|
||||
dock_data->event = event;
|
||||
dock_data->ds = dock_station;
|
||||
acpi_os_hotplug_execute(acpi_dock_deferred_cb,
|
||||
dock_data);
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block dock_acpi_notifier = {
|
||||
.notifier_call = acpi_dock_notifier_call,
|
||||
};
|
||||
|
||||
/**
|
||||
* find_dock_devices - find devices on the dock station
|
||||
* @handle: the handle of the device we are examining
|
||||
@ -688,6 +855,8 @@ fdd_out:
|
||||
static ssize_t show_docked(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
|
||||
|
||||
}
|
||||
@ -699,6 +868,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
||||
static ssize_t show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
|
||||
|
||||
}
|
||||
@ -711,6 +882,8 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
@ -727,16 +900,38 @@ static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
|
||||
static ssize_t show_dock_uid(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long lbuf;
|
||||
unsigned long long lbuf;
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle,
|
||||
"_UID", NULL, &lbuf);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
|
||||
return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
|
||||
}
|
||||
static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
||||
|
||||
static ssize_t show_dock_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
char *type;
|
||||
|
||||
if (dock_station->flags & DOCK_IS_DOCK)
|
||||
type = "dock_station";
|
||||
else if (dock_station->flags & DOCK_IS_ATA)
|
||||
type = "ata_bay";
|
||||
else if (dock_station->flags & DOCK_IS_BAT)
|
||||
type = "battery_bay";
|
||||
else
|
||||
type = "unknown";
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", type);
|
||||
}
|
||||
static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
|
||||
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
@ -747,8 +942,9 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
||||
static int dock_add(acpi_handle handle)
|
||||
{
|
||||
int ret;
|
||||
acpi_status status;
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
struct platform_device *dock_device;
|
||||
|
||||
/* allocate & initialize the dock_station private data */
|
||||
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
|
||||
@ -758,22 +954,34 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station->last_dock_time = jiffies - HZ;
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
INIT_LIST_HEAD(&dock_station->sibiling);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
dock_device =
|
||||
platform_device_register_simple(dock_device_name, 0, NULL, 0);
|
||||
dock_station->dock_device =
|
||||
platform_device_register_simple(dock_device_name,
|
||||
dock_station_count, NULL, 0);
|
||||
dock_device = dock_station->dock_device;
|
||||
if (IS_ERR(dock_device)) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return PTR_ERR(dock_device);
|
||||
}
|
||||
platform_device_add_data(dock_device, &dock_station,
|
||||
sizeof(struct dock_station *));
|
||||
|
||||
/* we want the dock device to send uevents */
|
||||
dock_device->dev.uevent_suppress = 0;
|
||||
|
||||
if (is_dock(handle))
|
||||
dock_station->flags |= DOCK_IS_DOCK;
|
||||
if (is_ata(handle))
|
||||
dock_station->flags |= DOCK_IS_ATA;
|
||||
if (is_battery(handle))
|
||||
dock_station->flags |= DOCK_IS_BAT;
|
||||
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
@ -812,6 +1020,9 @@ static int dock_add(acpi_handle handle)
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_type);
|
||||
if (ret)
|
||||
printk(KERN_ERR"Error %d adding sysfs file\n", ret);
|
||||
|
||||
/* Find dependent devices */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
@ -828,24 +1039,12 @@ static int dock_add(acpi_handle handle)
|
||||
}
|
||||
add_dock_dependent_device(dock_station, dd);
|
||||
|
||||
/* register for dock events */
|
||||
status = acpi_install_notify_handler(dock_station->handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
dock_notify, dock_station);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Error installing notify handler\n");
|
||||
ret = -ENODEV;
|
||||
goto dock_add_err;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
|
||||
dock_station_count++;
|
||||
list_add(&dock_station->sibiling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
dock_add_err:
|
||||
kfree(dd);
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@ -859,12 +1058,12 @@ dock_add_err_unregister:
|
||||
/**
|
||||
* dock_remove - free up resources related to the dock station
|
||||
*/
|
||||
static int dock_remove(void)
|
||||
static int dock_remove(struct dock_station *dock_station)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
acpi_status status;
|
||||
struct platform_device *dock_device = dock_station->dock_device;
|
||||
|
||||
if (!dock_station)
|
||||
if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
/* remove dependent devices */
|
||||
@ -872,14 +1071,8 @@ static int dock_remove(void)
|
||||
list)
|
||||
kfree(dd);
|
||||
|
||||
/* remove dock notify handler */
|
||||
status = acpi_remove_notify_handler(dock_station->handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
dock_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_ERR "Error removing notify handler\n");
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
@ -904,41 +1097,60 @@ static int dock_remove(void)
|
||||
static acpi_status
|
||||
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int *count = context;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (is_dock(handle)) {
|
||||
if (dock_add(handle) >= 0) {
|
||||
(*count)++;
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
/* If bay is a dock, it's already handled */
|
||||
if (is_ejectable_bay(handle) && !is_dock(handle))
|
||||
dock_add(handle);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int __init dock_init(void)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
dock_station = NULL;
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* look for a dock station */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_dock, &num, NULL);
|
||||
ACPI_UINT32_MAX, find_dock, NULL, NULL);
|
||||
|
||||
if (!num)
|
||||
printk(KERN_INFO "No dock devices found.\n");
|
||||
/* look for bay */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, find_bay, NULL, NULL);
|
||||
if (!dock_station_count) {
|
||||
printk(KERN_INFO PREFIX "No dock devices found.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
register_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
|
||||
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dock_exit(void)
|
||||
{
|
||||
dock_remove();
|
||||
struct dock_station *dock_station;
|
||||
|
||||
unregister_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
list_for_each_entry(dock_station, &dock_stations, sibiling)
|
||||
dock_remove(dock_station);
|
||||
}
|
||||
|
||||
postcore_initcall(dock_init);
|
||||
/*
|
||||
* Must be called before drivers of devices in dock, otherwise we can't know
|
||||
* which devices are in a dock
|
||||
*/
|
||||
subsys_initcall(dock_init);
|
||||
module_exit(dock_exit);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ec.c - ACPI Embedded Controller Driver (v2.0)
|
||||
* ec.c - ACPI Embedded Controller Driver (v2.1)
|
||||
*
|
||||
* Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
|
||||
* Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de>
|
||||
* Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
|
||||
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
|
||||
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
|
||||
@ -26,7 +26,7 @@
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
/* Uncomment next line to get verbose print outs*/
|
||||
/* Uncomment next line to get verbose printout */
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -38,6 +38,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
@ -65,22 +66,21 @@ enum ec_command {
|
||||
ACPI_EC_COMMAND_QUERY = 0x84,
|
||||
};
|
||||
|
||||
/* EC events */
|
||||
enum ec_event {
|
||||
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
|
||||
ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
|
||||
};
|
||||
|
||||
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
|
||||
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
|
||||
#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
|
||||
|
||||
#define ACPI_EC_STORM_THRESHOLD 20 /* number of false interrupts
|
||||
per one transaction */
|
||||
|
||||
enum {
|
||||
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
|
||||
EC_FLAGS_QUERY_PENDING, /* Query is pending */
|
||||
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
|
||||
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent
|
||||
* for status change */
|
||||
EC_FLAGS_NO_GPE, /* Don't use GPE mode */
|
||||
EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
|
||||
EC_FLAGS_GPE_STORM, /* GPE storm detected */
|
||||
EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and
|
||||
* OpReg are installed */
|
||||
};
|
||||
|
||||
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
|
||||
@ -95,6 +95,15 @@ struct acpi_ec_query_handler {
|
||||
u8 query_bit;
|
||||
};
|
||||
|
||||
struct transaction {
|
||||
const u8 *wdata;
|
||||
u8 *rdata;
|
||||
unsigned short irq_count;
|
||||
u8 command;
|
||||
u8 wlen;
|
||||
u8 rlen;
|
||||
};
|
||||
|
||||
static struct acpi_ec {
|
||||
acpi_handle handle;
|
||||
unsigned long gpe;
|
||||
@ -105,9 +114,8 @@ static struct acpi_ec {
|
||||
struct mutex lock;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct delayed_work work;
|
||||
atomic_t irq_count;
|
||||
u8 handlers_installed;
|
||||
struct transaction *curr;
|
||||
spinlock_t curr_lock;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
/*
|
||||
@ -150,7 +158,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
|
||||
{
|
||||
u8 x = inb(ec->data_addr);
|
||||
pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
|
||||
return inb(ec->data_addr);
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
|
||||
@ -165,158 +173,172 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
|
||||
outb(data, ec->data_addr);
|
||||
}
|
||||
|
||||
static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
|
||||
static int ec_transaction_done(struct acpi_ec *ec)
|
||||
{
|
||||
if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags))
|
||||
return 0;
|
||||
if (event == ACPI_EC_EVENT_OBF_1) {
|
||||
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
|
||||
return 1;
|
||||
} else if (event == ACPI_EC_EVENT_IBF_0) {
|
||||
if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF))
|
||||
return 1;
|
||||
}
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
spin_lock_irqsave(&ec->curr_lock, flags);
|
||||
if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen))
|
||||
ret = 1;
|
||||
spin_unlock_irqrestore(&ec->curr_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gpe_transaction(struct acpi_ec *ec, u8 status)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&ec->curr_lock, flags);
|
||||
if (!ec->curr)
|
||||
goto unlock;
|
||||
if (ec->curr->wlen > 0) {
|
||||
if ((status & ACPI_EC_FLAG_IBF) == 0) {
|
||||
acpi_ec_write_data(ec, *(ec->curr->wdata++));
|
||||
--ec->curr->wlen;
|
||||
} else
|
||||
/* false interrupt, state didn't change */
|
||||
++ec->curr->irq_count;
|
||||
|
||||
} else if (ec->curr->rlen > 0) {
|
||||
if ((status & ACPI_EC_FLAG_OBF) == 1) {
|
||||
*(ec->curr->rdata++) = acpi_ec_read_data(ec);
|
||||
--ec->curr->rlen;
|
||||
} else
|
||||
/* false interrupt, state didn't change */
|
||||
++ec->curr->irq_count;
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&ec->curr_lock, flags);
|
||||
}
|
||||
|
||||
static int acpi_ec_wait(struct acpi_ec *ec)
|
||||
{
|
||||
if (wait_event_timeout(ec->wait, ec_transaction_done(ec),
|
||||
msecs_to_jiffies(ACPI_EC_DELAY)))
|
||||
return 0;
|
||||
/* missing GPEs, switch back to poll mode */
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "missing confirmations, "
|
||||
"switch off interrupt mode.\n");
|
||||
set_bit(EC_FLAGS_NO_GPE, &ec->flags);
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void acpi_ec_gpe_query(void *ec_cxt);
|
||||
|
||||
static int ec_check_sci(struct acpi_ec *ec, u8 state)
|
||||
{
|
||||
if (state & ACPI_EC_FLAG_SCI) {
|
||||
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
|
||||
return acpi_os_execute(OSL_EC_BURST_HANDLER,
|
||||
acpi_ec_gpe_query, ec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ec_schedule_ec_poll(struct acpi_ec *ec)
|
||||
static int ec_poll(struct acpi_ec *ec)
|
||||
{
|
||||
if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
|
||||
schedule_delayed_work(&ec->work,
|
||||
msecs_to_jiffies(ACPI_EC_DELAY));
|
||||
}
|
||||
|
||||
static void ec_switch_to_poll_mode(struct acpi_ec *ec)
|
||||
{
|
||||
set_bit(EC_FLAGS_NO_GPE, &ec->flags);
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
}
|
||||
|
||||
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
|
||||
{
|
||||
atomic_set(&ec->irq_count, 0);
|
||||
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
|
||||
likely(!force_poll)) {
|
||||
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
|
||||
msecs_to_jiffies(ACPI_EC_DELAY)))
|
||||
return 0;
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
if (acpi_ec_check_status(ec, event)) {
|
||||
/* missing GPEs, switch back to poll mode */
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "missing confirmations, "
|
||||
"switch off interrupt mode.\n");
|
||||
ec_switch_to_poll_mode(ec);
|
||||
ec_schedule_ec_poll(ec);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
while (time_before(jiffies, delay)) {
|
||||
if (acpi_ec_check_status(ec, event))
|
||||
return 0;
|
||||
msleep(1);
|
||||
}
|
||||
if (acpi_ec_check_status(ec,event))
|
||||
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
|
||||
msleep(1);
|
||||
while (time_before(jiffies, delay)) {
|
||||
gpe_transaction(ec, acpi_ec_read_status(ec));
|
||||
msleep(1);
|
||||
if (ec_transaction_done(ec))
|
||||
return 0;
|
||||
}
|
||||
pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
|
||||
acpi_ec_read_status(ec),
|
||||
(event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
|
||||
const u8 * wdata, unsigned wdata_len,
|
||||
u8 * rdata, unsigned rdata_len,
|
||||
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
|
||||
struct transaction *t,
|
||||
int force_poll)
|
||||
{
|
||||
int result = 0;
|
||||
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
unsigned long tmp;
|
||||
int ret = 0;
|
||||
pr_debug(PREFIX "transaction start\n");
|
||||
acpi_ec_write_cmd(ec, command);
|
||||
for (; wdata_len > 0; --wdata_len) {
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
|
||||
if (result) {
|
||||
pr_err(PREFIX
|
||||
"write_cmd timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
acpi_ec_write_data(ec, *(wdata++));
|
||||
/* disable GPE during transaction if storm is detected */
|
||||
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
}
|
||||
|
||||
if (!rdata_len) {
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
|
||||
if (result) {
|
||||
pr_err(PREFIX
|
||||
"finish-write timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
} else if (command == ACPI_EC_COMMAND_QUERY)
|
||||
/* start transaction */
|
||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
||||
/* following two actions should be kept atomic */
|
||||
t->irq_count = 0;
|
||||
ec->curr = t;
|
||||
acpi_ec_write_cmd(ec, ec->curr->command);
|
||||
if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
|
||||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||
|
||||
for (; rdata_len > 0; --rdata_len) {
|
||||
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll);
|
||||
if (result) {
|
||||
pr_err(PREFIX "read timeout, command = %d\n", command);
|
||||
goto end;
|
||||
}
|
||||
/* Don't expect GPE after last read */
|
||||
if (rdata_len > 1)
|
||||
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
*(rdata++) = acpi_ec_read_data(ec);
|
||||
}
|
||||
end:
|
||||
spin_unlock_irqrestore(&ec->curr_lock, tmp);
|
||||
/* if we selected poll mode or failed in GPE-mode do a poll loop */
|
||||
if (force_poll ||
|
||||
!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ||
|
||||
acpi_ec_wait(ec))
|
||||
ret = ec_poll(ec);
|
||||
pr_debug(PREFIX "transaction end\n");
|
||||
return result;
|
||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
||||
ec->curr = NULL;
|
||||
spin_unlock_irqrestore(&ec->curr_lock, tmp);
|
||||
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
|
||||
/* check if we received SCI during transaction */
|
||||
ec_check_sci(ec, acpi_ec_read_status(ec));
|
||||
/* it is safe to enable GPE outside of transaction */
|
||||
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
} else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
|
||||
t->irq_count > ACPI_EC_STORM_THRESHOLD) {
|
||||
pr_debug(PREFIX "GPE storm detected\n");
|
||||
set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
|
||||
const u8 * wdata, unsigned wdata_len,
|
||||
u8 * rdata, unsigned rdata_len,
|
||||
static int ec_check_ibf0(struct acpi_ec *ec)
|
||||
{
|
||||
u8 status = acpi_ec_read_status(ec);
|
||||
return (status & ACPI_EC_FLAG_IBF) == 0;
|
||||
}
|
||||
|
||||
static int ec_wait_ibf0(struct acpi_ec *ec)
|
||||
{
|
||||
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
|
||||
/* interrupt wait manually if GPE mode is not active */
|
||||
unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ?
|
||||
msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1);
|
||||
while (time_before(jiffies, delay))
|
||||
if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout))
|
||||
return 0;
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t,
|
||||
int force_poll)
|
||||
{
|
||||
int status;
|
||||
u32 glk;
|
||||
|
||||
if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
|
||||
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
|
||||
return -EINVAL;
|
||||
|
||||
if (rdata)
|
||||
memset(rdata, 0, rdata_len);
|
||||
|
||||
if (t->rdata)
|
||||
memset(t->rdata, 0, t->rlen);
|
||||
mutex_lock(&ec->lock);
|
||||
if (ec->global_lock) {
|
||||
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
mutex_unlock(&ec->lock);
|
||||
return -ENODEV;
|
||||
status = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
|
||||
if (status) {
|
||||
if (ec_wait_ibf0(ec)) {
|
||||
pr_err(PREFIX "input buffer is not empty, "
|
||||
"aborting transaction\n");
|
||||
status = -ETIME;
|
||||
goto end;
|
||||
}
|
||||
|
||||
status = acpi_ec_transaction_unlocked(ec, command,
|
||||
wdata, wdata_len,
|
||||
rdata, rdata_len,
|
||||
force_poll);
|
||||
|
||||
end:
|
||||
|
||||
status = acpi_ec_transaction_unlocked(ec, t, force_poll);
|
||||
end:
|
||||
if (ec->global_lock)
|
||||
acpi_release_global_lock(glk);
|
||||
unlock:
|
||||
mutex_unlock(&ec->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -327,21 +349,32 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
|
||||
int acpi_ec_burst_enable(struct acpi_ec *ec)
|
||||
{
|
||||
u8 d;
|
||||
return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
|
||||
struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
|
||||
.wdata = NULL, .rdata = &d,
|
||||
.wlen = 0, .rlen = 1};
|
||||
|
||||
return acpi_ec_transaction(ec, &t, 0);
|
||||
}
|
||||
|
||||
int acpi_ec_burst_disable(struct acpi_ec *ec)
|
||||
{
|
||||
return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
|
||||
struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
|
||||
.wdata = NULL, .rdata = NULL,
|
||||
.wlen = 0, .rlen = 0};
|
||||
|
||||
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
|
||||
acpi_ec_transaction(ec, &t, 0) : 0;
|
||||
}
|
||||
|
||||
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
|
||||
{
|
||||
int result;
|
||||
u8 d;
|
||||
struct transaction t = {.command = ACPI_EC_COMMAND_READ,
|
||||
.wdata = &address, .rdata = &d,
|
||||
.wlen = 1, .rlen = 1};
|
||||
|
||||
result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
|
||||
&address, 1, &d, 1, 0);
|
||||
result = acpi_ec_transaction(ec, &t, 0);
|
||||
*data = d;
|
||||
return result;
|
||||
}
|
||||
@ -349,8 +382,11 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
|
||||
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
|
||||
{
|
||||
u8 wdata[2] = { address, data };
|
||||
return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
|
||||
wdata, 2, NULL, 0, 0);
|
||||
struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
|
||||
.wdata = wdata, .rdata = NULL,
|
||||
.wlen = 2, .rlen = 0};
|
||||
|
||||
return acpi_ec_transaction(ec, &t, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -412,12 +448,13 @@ int ec_transaction(u8 command,
|
||||
u8 * rdata, unsigned rdata_len,
|
||||
int force_poll)
|
||||
{
|
||||
struct transaction t = {.command = command,
|
||||
.wdata = wdata, .rdata = rdata,
|
||||
.wlen = wdata_len, .rlen = rdata_len};
|
||||
if (!first_ec)
|
||||
return -ENODEV;
|
||||
|
||||
return acpi_ec_transaction(first_ec, command, wdata,
|
||||
wdata_len, rdata, rdata_len,
|
||||
force_poll);
|
||||
return acpi_ec_transaction(first_ec, &t, force_poll);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ec_transaction);
|
||||
@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
|
||||
{
|
||||
int result;
|
||||
u8 d;
|
||||
|
||||
struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
|
||||
.wdata = NULL, .rdata = &d,
|
||||
.wlen = 0, .rlen = 1};
|
||||
if (!ec || !data)
|
||||
return -EINVAL;
|
||||
|
||||
@ -436,7 +475,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
|
||||
* bit to be cleared (and thus clearing the interrupt source).
|
||||
*/
|
||||
|
||||
result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
|
||||
result = acpi_ec_transaction(ec, &t, 0);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt)
|
||||
|
||||
static u32 acpi_ec_gpe_handler(void *data)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_ec *ec = data;
|
||||
u8 state = acpi_ec_read_status(ec);
|
||||
u8 status;
|
||||
|
||||
pr_debug(PREFIX "~~~> interrupt\n");
|
||||
atomic_inc(&ec->irq_count);
|
||||
if (atomic_read(&ec->irq_count) > 5) {
|
||||
pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
|
||||
ec_switch_to_poll_mode(ec);
|
||||
goto end;
|
||||
}
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
|
||||
status = acpi_ec_read_status(ec);
|
||||
|
||||
gpe_transaction(ec, status);
|
||||
if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
|
||||
wake_up(&ec->wait);
|
||||
|
||||
if (state & ACPI_EC_FLAG_SCI) {
|
||||
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
|
||||
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
|
||||
acpi_ec_gpe_query, ec);
|
||||
} else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
|
||||
!test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
|
||||
in_interrupt()) {
|
||||
ec_check_sci(ec, status);
|
||||
if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
|
||||
!test_bit(EC_FLAGS_NO_GPE, &ec->flags)) {
|
||||
/* this is non-query, must be confirmation */
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "non-query interrupt received,"
|
||||
" switching to interrupt mode\n");
|
||||
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
}
|
||||
end:
|
||||
ec_schedule_ec_poll(ec);
|
||||
return ACPI_SUCCESS(status) ?
|
||||
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static void do_ec_poll(struct work_struct *work)
|
||||
{
|
||||
struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
|
||||
atomic_set(&ec->irq_count, 0);
|
||||
(void)acpi_ec_gpe_handler(ec);
|
||||
return ACPI_INTERRUPT_HANDLED;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void)
|
||||
mutex_init(&ec->lock);
|
||||
init_waitqueue_head(&ec->wait);
|
||||
INIT_LIST_HEAD(&ec->list);
|
||||
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
|
||||
atomic_set(&ec->irq_count, 0);
|
||||
spin_lock_init(&ec->curr_lock);
|
||||
return ec;
|
||||
}
|
||||
|
||||
@ -718,6 +736,7 @@ static acpi_status
|
||||
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
|
||||
{
|
||||
acpi_status status;
|
||||
unsigned long long tmp;
|
||||
|
||||
struct acpi_ec *ec = context;
|
||||
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
|
||||
@ -727,31 +746,26 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
|
||||
|
||||
/* Get GPE bit assignment (EC events). */
|
||||
/* TODO: Add support for _GPE returning a package */
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
ec->gpe = tmp;
|
||||
/* Use the global lock for all EC transactions? */
|
||||
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
|
||||
acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
|
||||
ec->global_lock = tmp;
|
||||
ec->handle = handle;
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
static void ec_poll_stop(struct acpi_ec *ec)
|
||||
{
|
||||
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
cancel_delayed_work(&ec->work);
|
||||
}
|
||||
|
||||
static void ec_remove_handlers(struct acpi_ec *ec)
|
||||
{
|
||||
ec_poll_stop(ec);
|
||||
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
|
||||
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
|
||||
pr_err(PREFIX "failed to remove space handler\n");
|
||||
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
|
||||
&acpi_ec_gpe_handler)))
|
||||
pr_err(PREFIX "failed to remove gpe handler\n");
|
||||
ec->handlers_installed = 0;
|
||||
clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
|
||||
}
|
||||
|
||||
static int acpi_ec_add(struct acpi_device *device)
|
||||
@ -788,7 +802,7 @@ static int acpi_ec_add(struct acpi_device *device)
|
||||
|
||||
if (!first_ec)
|
||||
first_ec = ec;
|
||||
acpi_driver_data(device) = ec;
|
||||
device->driver_data = ec;
|
||||
acpi_ec_add_fs(device);
|
||||
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
|
||||
ec->gpe, ec->command_addr, ec->data_addr);
|
||||
@ -813,7 +827,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
|
||||
}
|
||||
mutex_unlock(&ec->lock);
|
||||
acpi_ec_remove_fs(device);
|
||||
acpi_driver_data(device) = NULL;
|
||||
device->driver_data = NULL;
|
||||
if (ec == first_ec)
|
||||
first_ec = NULL;
|
||||
kfree(ec);
|
||||
@ -846,27 +860,36 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
|
||||
static int ec_install_handlers(struct acpi_ec *ec)
|
||||
{
|
||||
acpi_status status;
|
||||
if (ec->handlers_installed)
|
||||
if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
|
||||
return 0;
|
||||
status = acpi_install_gpe_handler(NULL, ec->gpe,
|
||||
ACPI_GPE_EDGE_TRIGGERED,
|
||||
&acpi_ec_gpe_handler, ec);
|
||||
ACPI_GPE_EDGE_TRIGGERED,
|
||||
&acpi_ec_gpe_handler, ec);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
|
||||
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
|
||||
status = acpi_install_address_space_handler(ec->handle,
|
||||
ACPI_ADR_SPACE_EC,
|
||||
&acpi_ec_space_handler,
|
||||
NULL, ec);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
|
||||
return -ENODEV;
|
||||
if (status == AE_NOT_FOUND) {
|
||||
/*
|
||||
* Maybe OS fails in evaluating the _REG object.
|
||||
* The AE_NOT_FOUND error will be ignored and OS
|
||||
* continue to initialize EC.
|
||||
*/
|
||||
printk(KERN_ERR "Fail in evaluating the _REG object"
|
||||
" of EC device. Broken bios is suspected.\n");
|
||||
} else {
|
||||
acpi_remove_gpe_handler(NULL, ec->gpe,
|
||||
&acpi_ec_gpe_handler);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
ec->handlers_installed = 1;
|
||||
set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -887,7 +910,6 @@ static int acpi_ec_start(struct acpi_device *device)
|
||||
|
||||
/* EC is fully operational, allow queries */
|
||||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||
ec_schedule_ec_poll(ec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -906,7 +928,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
|
||||
|
||||
int __init acpi_boot_ec_enable(void)
|
||||
{
|
||||
if (!boot_ec || boot_ec->handlers_installed)
|
||||
if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
|
||||
return 0;
|
||||
if (!ec_install_handlers(boot_ec)) {
|
||||
first_ec = boot_ec;
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/actables.h>
|
||||
#include <acpi/acdispat.h>
|
||||
@ -91,13 +90,12 @@ acpi_ex_add_table(u32 table_index,
|
||||
|
||||
/* Init the table handle */
|
||||
|
||||
obj_desc->reference.opcode = AML_LOAD_OP;
|
||||
obj_desc->reference.class = ACPI_REFCLASS_TABLE;
|
||||
*ddb_handle = obj_desc;
|
||||
|
||||
/* Install the new table into the local data structures */
|
||||
|
||||
obj_desc->reference.object = ACPI_CAST_PTR(void,
|
||||
(unsigned long)table_index);
|
||||
obj_desc->reference.value = table_index;
|
||||
|
||||
/* Add the table to the namespace */
|
||||
|
||||
@ -280,6 +278,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
struct acpi_walk_state *walk_state)
|
||||
{
|
||||
union acpi_operand_object *ddb_handle;
|
||||
struct acpi_table_header *table;
|
||||
struct acpi_table_desc table_desc;
|
||||
u32 table_index;
|
||||
acpi_status status;
|
||||
@ -294,9 +293,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
case ACPI_TYPE_REGION:
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
|
||||
obj_desc,
|
||||
acpi_ut_get_object_type_name(obj_desc)));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Load table from Region %p\n", obj_desc));
|
||||
|
||||
/* Region must be system_memory (from ACPI spec) */
|
||||
|
||||
@ -316,22 +314,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
}
|
||||
|
||||
/*
|
||||
* We will simply map the memory region for the table. However, the
|
||||
* memory region is technically not guaranteed to remain stable and
|
||||
* we may eventually have to copy the table to a local buffer.
|
||||
* Map the table header and get the actual table length. The region
|
||||
* length is not guaranteed to be the same as the table length.
|
||||
*/
|
||||
table_desc.address = obj_desc->region.address;
|
||||
table_desc.length = obj_desc->region.length;
|
||||
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
|
||||
break;
|
||||
table = acpi_os_map_memory(obj_desc->region.address,
|
||||
sizeof(struct acpi_table_header));
|
||||
if (!table) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Load from Buffer or Field %p %s\n", obj_desc,
|
||||
acpi_ut_get_object_type_name(obj_desc)));
|
||||
|
||||
length = obj_desc->buffer.length;
|
||||
length = table->length;
|
||||
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
|
||||
|
||||
/* Must have at least an ACPI table header */
|
||||
|
||||
@ -339,38 +332,94 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||
}
|
||||
|
||||
/* Validate checksum here. It won't get validated in tb_add_table */
|
||||
/*
|
||||
* The memory region is not guaranteed to remain stable and we must
|
||||
* copy the table to a local buffer. For example, the memory region
|
||||
* is corrupted after suspend on some machines. Dynamically loaded
|
||||
* tables are usually small, so this overhead is minimal.
|
||||
*/
|
||||
|
||||
status =
|
||||
acpi_tb_verify_checksum(ACPI_CAST_PTR
|
||||
(struct acpi_table_header,
|
||||
obj_desc->buffer.pointer), length);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
/* Allocate a buffer for the table */
|
||||
|
||||
table_desc.pointer = ACPI_ALLOCATE(length);
|
||||
if (!table_desc.pointer) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Map the entire table and copy it */
|
||||
|
||||
table = acpi_os_map_memory(obj_desc->region.address, length);
|
||||
if (!table) {
|
||||
ACPI_FREE(table_desc.pointer);
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
ACPI_MEMCPY(table_desc.pointer, table, length);
|
||||
acpi_os_unmap_memory(table, length);
|
||||
|
||||
table_desc.address = obj_desc->region.address;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Load table from Buffer or Field %p\n",
|
||||
obj_desc));
|
||||
|
||||
/* Must have at least an ACPI table header */
|
||||
|
||||
if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) {
|
||||
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||
}
|
||||
|
||||
/* Get the actual table length from the table header */
|
||||
|
||||
table =
|
||||
ACPI_CAST_PTR(struct acpi_table_header,
|
||||
obj_desc->buffer.pointer);
|
||||
length = table->length;
|
||||
|
||||
/* Table cannot extend beyond the buffer */
|
||||
|
||||
if (length > obj_desc->buffer.length) {
|
||||
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
|
||||
}
|
||||
if (length < sizeof(struct acpi_table_header)) {
|
||||
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to copy the buffer since the original buffer could be
|
||||
* changed or deleted in the future
|
||||
* Copy the table from the buffer because the buffer could be modified
|
||||
* or even deleted in the future
|
||||
*/
|
||||
table_desc.pointer = ACPI_ALLOCATE(length);
|
||||
if (!table_desc.pointer) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
|
||||
length);
|
||||
table_desc.length = length;
|
||||
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
|
||||
ACPI_MEMCPY(table_desc.pointer, table, length);
|
||||
table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
|
||||
break;
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the new table into the local data structures
|
||||
*/
|
||||
/* Validate table checksum (will not get validated in tb_add_table) */
|
||||
|
||||
status = acpi_tb_verify_checksum(table_desc.pointer, length);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_FREE(table_desc.pointer);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Complete the table descriptor */
|
||||
|
||||
table_desc.length = length;
|
||||
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
|
||||
|
||||
/* Install the new table into the local data structures */
|
||||
|
||||
status = acpi_tb_add_table(&table_desc, &table_index);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
@ -379,7 +428,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
/*
|
||||
* Add the table to the namespace.
|
||||
*
|
||||
* Note: We load the table objects relative to the root of the namespace.
|
||||
* Note: Load the table objects relative to the root of the namespace.
|
||||
* This appears to go against the ACPI specification, but we do it for
|
||||
* compatibility with other ACPI implementations.
|
||||
*/
|
||||
@ -415,7 +464,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
||||
cleanup:
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
||||
/* Delete allocated buffer or mapping */
|
||||
/* Delete allocated table buffer */
|
||||
|
||||
acpi_tb_delete_table(&table_desc);
|
||||
}
|
||||
@ -455,9 +504,9 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
/* Get the table index from the ddb_handle (acpi_size for 64-bit case) */
|
||||
/* Get the table index from the ddb_handle */
|
||||
|
||||
table_index = (u32) (acpi_size) table_desc->reference.object;
|
||||
table_index = table_desc->reference.value;
|
||||
|
||||
/* Invoke table handler if present */
|
||||
|
||||
|
@ -57,7 +57,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
|
||||
*
|
||||
* FUNCTION: acpi_ex_convert_to_integer
|
||||
*
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* Integer, Buffer, or String
|
||||
* result_desc - Where the new Integer object is returned
|
||||
* Flags - Used for string conversion
|
||||
@ -103,7 +103,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the buffer/string to an integer. Note that both buffers and
|
||||
* Convert the buffer/string to an integer. Note that both buffers and
|
||||
* strings are treated as raw data - we don't convert ascii to hex for
|
||||
* strings.
|
||||
*
|
||||
@ -120,7 +120,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
|
||||
|
||||
/*
|
||||
* Convert string to an integer - for most cases, the string must be
|
||||
* hexadecimal as per the ACPI specification. The only exception (as
|
||||
* hexadecimal as per the ACPI specification. The only exception (as
|
||||
* of ACPI 3.0) is that the to_integer() operator allows both decimal
|
||||
* and hexadecimal strings (hex prefixed with "0x").
|
||||
*/
|
||||
@ -159,6 +159,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* No other types can get here */
|
||||
break;
|
||||
}
|
||||
@ -185,7 +186,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
|
||||
*
|
||||
* FUNCTION: acpi_ex_convert_to_buffer
|
||||
*
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* Integer, Buffer, or String
|
||||
* result_desc - Where the new buffer object is returned
|
||||
*
|
||||
@ -365,7 +366,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
|
||||
}
|
||||
|
||||
/*
|
||||
* Since leading zeros are supressed, we must check for the case where
|
||||
* Since leading zeros are suppressed, we must check for the case where
|
||||
* the integer equals 0
|
||||
*
|
||||
* Finally, null terminate the string and return the length
|
||||
@ -383,7 +384,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
|
||||
*
|
||||
* FUNCTION: acpi_ex_convert_to_string
|
||||
*
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* PARAMETERS: obj_desc - Object to be converted. Must be an
|
||||
* Integer, Buffer, or String
|
||||
* result_desc - Where the string object is returned
|
||||
* Type - String flags (base and conversion type)
|
||||
@ -472,7 +473,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
|
||||
base = 10;
|
||||
|
||||
/*
|
||||
* Calculate the final string length. Individual string values
|
||||
* Calculate the final string length. Individual string values
|
||||
* are variable length (include separator for each)
|
||||
*/
|
||||
for (i = 0; i < obj_desc->buffer.length; i++) {
|
||||
@ -511,9 +512,14 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
|
||||
/*
|
||||
* Create a new string object and string buffer
|
||||
* (-1 because of extra separator included in string_length from above)
|
||||
* Allow creation of zero-length strings from zero-length buffers.
|
||||
*/
|
||||
if (string_length) {
|
||||
string_length--;
|
||||
}
|
||||
|
||||
return_desc = acpi_ut_create_string_object((acpi_size)
|
||||
(string_length - 1));
|
||||
string_length);
|
||||
if (!return_desc) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
@ -536,7 +542,9 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
|
||||
* Null terminate the string
|
||||
* (overwrites final comma/space from above)
|
||||
*/
|
||||
new_buf--;
|
||||
if (obj_desc->buffer.length) {
|
||||
new_buf--;
|
||||
}
|
||||
*new_buf = 0;
|
||||
break;
|
||||
|
||||
@ -617,7 +625,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
|
||||
case ACPI_TYPE_LOCAL_BANK_FIELD:
|
||||
case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
||||
/*
|
||||
* These types require an Integer operand. We can convert
|
||||
* These types require an Integer operand. We can convert
|
||||
* a Buffer or a String to an Integer if necessary.
|
||||
*/
|
||||
status =
|
||||
@ -627,7 +635,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
|
||||
|
||||
case ACPI_TYPE_STRING:
|
||||
/*
|
||||
* The operand must be a String. We can convert an
|
||||
* The operand must be a String. We can convert an
|
||||
* Integer or Buffer if necessary
|
||||
*/
|
||||
status =
|
||||
@ -637,7 +645,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
/*
|
||||
* The operand must be a Buffer. We can convert an
|
||||
* The operand must be a Buffer. We can convert an
|
||||
* Integer or String if necessary
|
||||
*/
|
||||
status =
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exdump")
|
||||
@ -214,10 +213,11 @@ static struct acpi_exdump_info acpi_ex_dump_index_field[5] = {
|
||||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(index_field.data_obj), "Data Object"}
|
||||
};
|
||||
|
||||
static struct acpi_exdump_info acpi_ex_dump_reference[7] = {
|
||||
static struct acpi_exdump_info acpi_ex_dump_reference[8] = {
|
||||
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_reference), NULL},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.class), "Class"},
|
||||
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"},
|
||||
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.offset), "Offset"},
|
||||
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"},
|
||||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"},
|
||||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
|
||||
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"},
|
||||
@ -413,10 +413,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
|
||||
|
||||
case ACPI_EXD_REFERENCE:
|
||||
|
||||
acpi_ex_out_string("Opcode",
|
||||
(acpi_ps_get_opcode_info
|
||||
(obj_desc->reference.opcode))->
|
||||
name);
|
||||
acpi_ex_out_string("Class Name",
|
||||
(char *)
|
||||
acpi_ut_get_reference_name
|
||||
(obj_desc));
|
||||
acpi_ex_dump_reference_obj(obj_desc);
|
||||
break;
|
||||
|
||||
@ -494,40 +494,41 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
|
||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_DEBUG_OP:
|
||||
acpi_os_printf("Reference: [%s] ",
|
||||
acpi_ut_get_reference_name(obj_desc));
|
||||
|
||||
acpi_os_printf("Reference: Debug\n");
|
||||
switch (obj_desc->reference.class) {
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
|
||||
acpi_os_printf("\n");
|
||||
break;
|
||||
|
||||
case AML_INDEX_OP:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
acpi_os_printf("Reference: Index %p\n",
|
||||
obj_desc->reference.object);
|
||||
acpi_os_printf("%p\n", obj_desc->reference.object);
|
||||
break;
|
||||
|
||||
case AML_LOAD_OP:
|
||||
case ACPI_REFCLASS_TABLE:
|
||||
|
||||
acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n",
|
||||
obj_desc->reference.object);
|
||||
acpi_os_printf("Table Index %X\n",
|
||||
obj_desc->reference.value);
|
||||
break;
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
|
||||
acpi_os_printf("Reference: (RefOf) %p [%s]\n",
|
||||
obj_desc->reference.object,
|
||||
acpi_os_printf("%p [%s]\n", obj_desc->reference.object,
|
||||
acpi_ut_get_type_name(((union
|
||||
acpi_operand_object
|
||||
*)obj_desc->
|
||||
*)
|
||||
obj_desc->
|
||||
reference.
|
||||
object)->common.
|
||||
type));
|
||||
break;
|
||||
|
||||
case AML_ARG_OP:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
acpi_os_printf("Reference: Arg%d",
|
||||
obj_desc->reference.offset);
|
||||
acpi_os_printf("%X", obj_desc->reference.value);
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
|
||||
|
||||
@ -542,10 +543,9 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
|
||||
acpi_os_printf("\n");
|
||||
break;
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
|
||||
acpi_os_printf("Reference: Local%d",
|
||||
obj_desc->reference.offset);
|
||||
acpi_os_printf("%X", obj_desc->reference.value);
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
|
||||
|
||||
@ -560,21 +560,16 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
|
||||
acpi_os_printf("\n");
|
||||
break;
|
||||
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
case ACPI_REFCLASS_NAME:
|
||||
|
||||
acpi_os_printf("Reference: Namepath %X [%4.4s]\n",
|
||||
obj_desc->reference.node->name.integer,
|
||||
acpi_os_printf("- [%4.4s]\n",
|
||||
obj_desc->reference.node->name.ascii);
|
||||
break;
|
||||
|
||||
default:
|
||||
default: /* Unknown reference class */
|
||||
|
||||
/* Unknown opcode */
|
||||
|
||||
acpi_os_printf("Unknown Reference opcode=%X\n",
|
||||
obj_desc->reference.opcode);
|
||||
acpi_os_printf("%2.2X\n", obj_desc->reference.class);
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@ -865,8 +860,8 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
|
||||
|
||||
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
|
||||
|
||||
if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) {
|
||||
acpi_os_printf(" Named Object %p ", obj_desc->reference.node);
|
||||
if (obj_desc->reference.class == ACPI_REFCLASS_NAME) {
|
||||
acpi_os_printf(" %p ", obj_desc->reference.node);
|
||||
|
||||
status =
|
||||
acpi_ns_handle_to_pathname(obj_desc->reference.node,
|
||||
@ -882,14 +877,12 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc)
|
||||
ACPI_DESC_TYPE_OPERAND) {
|
||||
acpi_os_printf(" Target: %p",
|
||||
obj_desc->reference.object);
|
||||
if (obj_desc->reference.opcode == AML_LOAD_OP) {
|
||||
/*
|
||||
* For DDBHandle reference,
|
||||
* obj_desc->Reference.Object is the table index
|
||||
*/
|
||||
acpi_os_printf(" [DDBHandle]\n");
|
||||
if (obj_desc->reference.class == ACPI_REFCLASS_TABLE) {
|
||||
acpi_os_printf(" Table Index: %X\n",
|
||||
obj_desc->reference.value);
|
||||
} else {
|
||||
acpi_os_printf(" [%s]\n",
|
||||
acpi_os_printf(" Target: %p [%s]\n",
|
||||
obj_desc->reference.object,
|
||||
acpi_ut_get_type_name(((union
|
||||
acpi_operand_object
|
||||
*)
|
||||
@ -988,9 +981,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
|
||||
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
acpi_os_printf("[Object Reference] %s",
|
||||
(acpi_ps_get_opcode_info
|
||||
(obj_desc->reference.opcode))->name);
|
||||
acpi_os_printf("[Object Reference] Type [%s] %2.2X",
|
||||
acpi_ut_get_reference_name(obj_desc),
|
||||
obj_desc->reference.class);
|
||||
acpi_ex_dump_reference_obj(obj_desc);
|
||||
break;
|
||||
|
||||
|
@ -86,10 +86,10 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
|
||||
/*
|
||||
* Must be a reference to a Local or Arg
|
||||
*/
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
case AML_DEBUG_OP:
|
||||
switch (obj_desc->reference.class) {
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
|
||||
/* The referenced object is the pseudo-node for the local/arg */
|
||||
|
||||
@ -98,8 +98,8 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X",
|
||||
obj_desc->reference.opcode));
|
||||
ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
|
||||
obj_desc->reference.class));
|
||||
return_ACPI_STATUS(AE_AML_INTERNAL);
|
||||
}
|
||||
break;
|
||||
@ -127,7 +127,7 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
reference_obj->reference.opcode = AML_REF_OF_OP;
|
||||
reference_obj->reference.class = ACPI_REFCLASS_REFOF;
|
||||
reference_obj->reference.object = referenced_obj;
|
||||
*return_desc = reference_obj;
|
||||
|
||||
|
@ -825,16 +825,16 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
*
|
||||
* Must resolve/dereference the local/arg reference first
|
||||
*/
|
||||
switch (operand[0]->reference.opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
switch (operand[0]->reference.class) {
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
/* Set Operand[0] to the value of the local/arg */
|
||||
|
||||
status =
|
||||
acpi_ds_method_data_get_value
|
||||
(operand[0]->reference.opcode,
|
||||
operand[0]->reference.offset,
|
||||
(operand[0]->reference.class,
|
||||
operand[0]->reference.value,
|
||||
walk_state, &temp_desc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
@ -848,7 +848,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
operand[0] = temp_desc;
|
||||
break;
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
|
||||
/* Get the object to which the reference refers */
|
||||
|
||||
@ -928,8 +928,8 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
* This must be a reference object produced by either the
|
||||
* Index() or ref_of() operator
|
||||
*/
|
||||
switch (operand[0]->reference.opcode) {
|
||||
case AML_INDEX_OP:
|
||||
switch (operand[0]->reference.class) {
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
/*
|
||||
* The target type for the Index operator must be
|
||||
@ -965,7 +965,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
return_desc->integer.value =
|
||||
temp_desc->buffer.
|
||||
pointer[operand[0]->reference.
|
||||
offset];
|
||||
value];
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
@ -985,7 +985,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown Index TargetType %X in obj %p",
|
||||
"Unknown Index TargetType %X in reference object %p",
|
||||
operand[0]->reference.
|
||||
target_type, operand[0]));
|
||||
status = AE_AML_OPERAND_TYPE;
|
||||
@ -993,7 +993,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
|
||||
return_desc = operand[0]->reference.object;
|
||||
|
||||
@ -1013,9 +1013,9 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
|
||||
|
||||
default:
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown opcode in reference(%p) - %X",
|
||||
"Unknown class in reference(%p) - %2.2X",
|
||||
operand[0],
|
||||
operand[0]->reference.opcode));
|
||||
operand[0]->reference.class));
|
||||
|
||||
status = AE_TYPE;
|
||||
goto cleanup;
|
||||
|
@ -391,8 +391,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
|
||||
/* Initialize the Index reference object */
|
||||
|
||||
index = operand[1]->integer.value;
|
||||
return_desc->reference.offset = (u32) index;
|
||||
return_desc->reference.opcode = AML_INDEX_OP;
|
||||
return_desc->reference.value = (u32) index;
|
||||
return_desc->reference.class = ACPI_REFCLASS_INDEX;
|
||||
|
||||
/*
|
||||
* At this point, the Source operand is a String, Buffer, or Package.
|
||||
|
@ -46,8 +46,6 @@
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/amlcode.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exresnte")
|
||||
@ -238,10 +236,10 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
|
||||
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
switch (source_desc->reference.opcode) {
|
||||
case AML_LOAD_OP: /* This is a ddb_handle */
|
||||
case AML_REF_OF_OP:
|
||||
case AML_INDEX_OP:
|
||||
switch (source_desc->reference.class) {
|
||||
case ACPI_REFCLASS_TABLE: /* This is a ddb_handle */
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
/* Return an additional reference to the object */
|
||||
|
||||
@ -253,10 +251,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
|
||||
/* No named references are allowed here */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unsupported Reference opcode %X (%s)",
|
||||
source_desc->reference.opcode,
|
||||
acpi_ps_get_opcode_name(source_desc->
|
||||
reference.opcode)));
|
||||
"Unsupported Reference type %X",
|
||||
source_desc->reference.class));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include <acpi/acdispat.h>
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exresolv")
|
||||
@ -141,7 +140,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_operand_object *stack_desc;
|
||||
union acpi_operand_object *obj_desc = NULL;
|
||||
u16 opcode;
|
||||
u8 ref_type;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
|
||||
|
||||
@ -152,19 +151,19 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
switch (ACPI_GET_OBJECT_TYPE(stack_desc)) {
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
opcode = stack_desc->reference.opcode;
|
||||
ref_type = stack_desc->reference.class;
|
||||
|
||||
switch (opcode) {
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
switch (ref_type) {
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
/*
|
||||
* Get the local from the method's state info
|
||||
* Note: this increments the local's object reference count
|
||||
*/
|
||||
status = acpi_ds_method_data_get_value(opcode,
|
||||
status = acpi_ds_method_data_get_value(ref_type,
|
||||
stack_desc->
|
||||
reference.offset,
|
||||
reference.value,
|
||||
walk_state,
|
||||
&obj_desc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -173,7 +172,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"[Arg/Local %X] ValueObj is %p\n",
|
||||
stack_desc->reference.offset,
|
||||
stack_desc->reference.value,
|
||||
obj_desc));
|
||||
|
||||
/*
|
||||
@ -184,7 +183,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
*stack_ptr = obj_desc;
|
||||
break;
|
||||
|
||||
case AML_INDEX_OP:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
switch (stack_desc->reference.target_type) {
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
@ -239,15 +238,15 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_REF_OF_OP:
|
||||
case AML_DEBUG_OP:
|
||||
case AML_LOAD_OP:
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
case ACPI_REFCLASS_TABLE:
|
||||
|
||||
/* Just leave the object as-is, do not dereference */
|
||||
|
||||
break;
|
||||
|
||||
case AML_INT_NAMEPATH_OP: /* Reference to a named object */
|
||||
case ACPI_REFCLASS_NAME: /* Reference to a named object */
|
||||
|
||||
/* Dereference the name */
|
||||
|
||||
@ -273,8 +272,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown Reference opcode %X (%s) in %p",
|
||||
opcode, acpi_ps_get_opcode_name(opcode),
|
||||
"Unknown Reference type %X in %p", ref_type,
|
||||
stack_desc));
|
||||
status = AE_AML_INTERNAL;
|
||||
break;
|
||||
@ -388,13 +386,13 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
* traversing the list of possibly many nested references.
|
||||
*/
|
||||
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_REF_OF_OP:
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
switch (obj_desc->reference.class) {
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
case ACPI_REFCLASS_NAME:
|
||||
|
||||
/* Dereference the reference pointer */
|
||||
|
||||
if (obj_desc->reference.opcode == AML_REF_OF_OP) {
|
||||
if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) {
|
||||
node = obj_desc->reference.object;
|
||||
} else { /* AML_INT_NAMEPATH_OP */
|
||||
|
||||
@ -429,7 +427,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_INDEX_OP:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
/* Get the type of this reference (index into another object) */
|
||||
|
||||
@ -455,22 +453,22 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_LOAD_OP:
|
||||
case ACPI_REFCLASS_TABLE:
|
||||
|
||||
type = ACPI_TYPE_DDB_HANDLE;
|
||||
goto exit;
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
if (return_desc) {
|
||||
status =
|
||||
acpi_ds_method_data_get_value(obj_desc->
|
||||
reference.
|
||||
opcode,
|
||||
class,
|
||||
obj_desc->
|
||||
reference.
|
||||
offset,
|
||||
value,
|
||||
walk_state,
|
||||
&obj_desc);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -481,10 +479,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
status =
|
||||
acpi_ds_method_data_get_node(obj_desc->
|
||||
reference.
|
||||
opcode,
|
||||
class,
|
||||
obj_desc->
|
||||
reference.
|
||||
offset,
|
||||
value,
|
||||
walk_state,
|
||||
&node);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -499,7 +497,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_DEBUG_OP:
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
|
||||
/* The Debug Object is of type "DebugObject" */
|
||||
|
||||
@ -509,8 +507,8 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unknown Reference subtype %X",
|
||||
obj_desc->reference.opcode));
|
||||
"Unknown Reference Class %2.2X",
|
||||
obj_desc->reference.class));
|
||||
return_ACPI_STATUS(AE_AML_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
@ -225,41 +225,36 @@ acpi_ex_resolve_operands(u16 opcode,
|
||||
|
||||
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
|
||||
/* Decode the Reference */
|
||||
/* Validate the Reference */
|
||||
|
||||
op_info = acpi_ps_get_opcode_info(opcode);
|
||||
if (op_info->class == AML_CLASS_UNKNOWN) {
|
||||
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
|
||||
}
|
||||
switch (obj_desc->reference.class) {
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
|
||||
switch (obj_desc->reference.opcode) {
|
||||
case AML_DEBUG_OP:
|
||||
target_op = AML_DEBUG_OP;
|
||||
|
||||
/*lint -fallthrough */
|
||||
|
||||
case AML_INDEX_OP:
|
||||
case AML_REF_OF_OP:
|
||||
case AML_ARG_OP:
|
||||
case AML_LOCAL_OP:
|
||||
case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
|
||||
case AML_INT_NAMEPATH_OP: /* Reference to a named object */
|
||||
case ACPI_REFCLASS_ARG:
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
case ACPI_REFCLASS_TABLE: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
|
||||
case ACPI_REFCLASS_NAME: /* Reference to a named object */
|
||||
|
||||
ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT
|
||||
((ACPI_DB_EXEC,
|
||||
"Operand is a Reference, RefOpcode [%s]\n",
|
||||
(acpi_ps_get_opcode_info
|
||||
(obj_desc->
|
||||
reference.
|
||||
opcode))->
|
||||
name)));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Operand is a Reference, Class [%s] %2.2X\n",
|
||||
acpi_ut_get_reference_name
|
||||
(obj_desc),
|
||||
obj_desc->reference.
|
||||
class));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Operand is a Reference, Unknown Reference Opcode: %X",
|
||||
obj_desc->reference.
|
||||
opcode));
|
||||
"Unknown Reference Class %2.2X in %p",
|
||||
obj_desc->reference.class,
|
||||
obj_desc));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
@ -270,8 +265,7 @@ acpi_ex_resolve_operands(u16 opcode,
|
||||
|
||||
/* Invalid descriptor */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Invalid descriptor %p [%s]",
|
||||
ACPI_ERROR((AE_INFO, "Invalid descriptor %p [%s]",
|
||||
obj_desc,
|
||||
acpi_ut_get_descriptor_name(obj_desc)));
|
||||
|
||||
@ -343,7 +337,7 @@ acpi_ex_resolve_operands(u16 opcode,
|
||||
if ((opcode == AML_STORE_OP) &&
|
||||
(ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) {
|
||||
&& ((*stack_ptr)->reference.class == ACPI_REFCLASS_INDEX)) {
|
||||
goto next_operand;
|
||||
}
|
||||
break;
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_EXECUTER
|
||||
ACPI_MODULE_NAME("exstore")
|
||||
@ -179,22 +178,26 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
|
||||
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
if (source_desc->reference.opcode == AML_INDEX_OP) {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
"[%s, 0x%X]\n",
|
||||
acpi_ps_get_opcode_name
|
||||
(source_desc->reference.opcode),
|
||||
source_desc->reference.offset));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
|
||||
acpi_ps_get_opcode_name
|
||||
(source_desc->reference.opcode)));
|
||||
}
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s] ",
|
||||
acpi_ut_get_reference_name(source_desc)));
|
||||
|
||||
/* Decode the reference */
|
||||
|
||||
switch (source_desc->reference.class) {
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "0x%X\n",
|
||||
source_desc->reference.value));
|
||||
break;
|
||||
|
||||
case ACPI_REFCLASS_TABLE:
|
||||
|
||||
if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */
|
||||
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
|
||||
" Table OwnerId %p\n",
|
||||
source_desc->reference.object));
|
||||
"Table Index 0x%X\n",
|
||||
source_desc->reference.value));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -347,15 +350,15 @@ acpi_ex_store(union acpi_operand_object *source_desc,
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine the Reference opcode. These cases are handled:
|
||||
* Examine the Reference class. These cases are handled:
|
||||
*
|
||||
* 1) Store to Name (Change the object associated with a name)
|
||||
* 2) Store to an indexed area of a Buffer or Package
|
||||
* 3) Store to a Method Local or Arg
|
||||
* 4) Store to the debug object
|
||||
*/
|
||||
switch (ref_desc->reference.opcode) {
|
||||
case AML_REF_OF_OP:
|
||||
switch (ref_desc->reference.class) {
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
|
||||
/* Storing an object into a Name "container" */
|
||||
|
||||
@ -365,7 +368,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
|
||||
ACPI_IMPLICIT_CONVERSION);
|
||||
break;
|
||||
|
||||
case AML_INDEX_OP:
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
/* Storing to an Index (pointer into a packager or buffer) */
|
||||
|
||||
@ -374,18 +377,18 @@ acpi_ex_store(union acpi_operand_object *source_desc,
|
||||
walk_state);
|
||||
break;
|
||||
|
||||
case AML_LOCAL_OP:
|
||||
case AML_ARG_OP:
|
||||
case ACPI_REFCLASS_LOCAL:
|
||||
case ACPI_REFCLASS_ARG:
|
||||
|
||||
/* Store to a method local/arg */
|
||||
|
||||
status =
|
||||
acpi_ds_store_object_to_local(ref_desc->reference.opcode,
|
||||
ref_desc->reference.offset,
|
||||
acpi_ds_store_object_to_local(ref_desc->reference.class,
|
||||
ref_desc->reference.value,
|
||||
source_desc, walk_state);
|
||||
break;
|
||||
|
||||
case AML_DEBUG_OP:
|
||||
case ACPI_REFCLASS_DEBUG:
|
||||
|
||||
/*
|
||||
* Storing to the Debug object causes the value stored to be
|
||||
@ -401,9 +404,9 @@ acpi_ex_store(union acpi_operand_object *source_desc,
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X",
|
||||
ref_desc->reference.opcode));
|
||||
ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_ERROR);
|
||||
ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
|
||||
ref_desc->reference.class));
|
||||
ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO);
|
||||
|
||||
status = AE_AML_INTERNAL;
|
||||
break;
|
||||
@ -458,7 +461,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(source_desc) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE
|
||||
&& source_desc->reference.opcode == AML_LOAD_OP) {
|
||||
&& source_desc->reference.class == ACPI_REFCLASS_TABLE) {
|
||||
|
||||
/* This is a DDBHandle, just add a reference to it */
|
||||
|
||||
@ -553,7 +556,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
|
||||
|
||||
/* Store the source value into the target buffer byte */
|
||||
|
||||
obj_desc->buffer.pointer[index_desc->reference.offset] = value;
|
||||
obj_desc->buffer.pointer[index_desc->reference.value] = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -121,7 +121,8 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
|
||||
(ACPI_GET_OBJECT_TYPE(source_desc) != ACPI_TYPE_STRING) &&
|
||||
!((ACPI_GET_OBJECT_TYPE(source_desc) ==
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
&& (source_desc->reference.opcode == AML_LOAD_OP))) {
|
||||
&& (source_desc->reference.class ==
|
||||
ACPI_REFCLASS_TABLE))) {
|
||||
|
||||
/* Conversion successful but still not a valid type */
|
||||
|
||||
|
@ -265,7 +265,7 @@ static int acpi_fan_add(struct acpi_device *device)
|
||||
|
||||
dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id);
|
||||
|
||||
acpi_driver_data(device) = cdev;
|
||||
device->driver_data = cdev;
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
&cdev->device.kobj,
|
||||
"thermal_cooling");
|
||||
@ -327,8 +327,8 @@ static int acpi_fan_resume(struct acpi_device *device)
|
||||
|
||||
result = acpi_bus_get_power(device->handle, &power_state);
|
||||
if (result) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error reading fan power state\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error reading fan power state\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -78,19 +78,17 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Set the vector */
|
||||
/*
|
||||
* According to the ACPI specification 2.0c and later, the 64-bit
|
||||
* waking vector should be cleared and the 32-bit waking vector should
|
||||
* be used, unless we want the wake-up code to be called by the BIOS in
|
||||
* Protected Mode. Some systems (for example HP dv5-1004nr) are known
|
||||
* to fail to resume if the 64-bit vector is used.
|
||||
*/
|
||||
if (facs->version >= 1)
|
||||
facs->xfirmware_waking_vector = 0;
|
||||
|
||||
if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
|
||||
/*
|
||||
* ACPI 1.0 FACS or short table or optional X_ field is zero
|
||||
*/
|
||||
facs->firmware_waking_vector = (u32) physical_address;
|
||||
} else {
|
||||
/*
|
||||
* ACPI 2.0 FACS with valid X_ field
|
||||
*/
|
||||
facs->xfirmware_waking_vector = physical_address;
|
||||
}
|
||||
facs->firmware_waking_vector = (u32)physical_address;
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
@ -134,20 +132,7 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
|
||||
}
|
||||
|
||||
/* Get the vector */
|
||||
|
||||
if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
|
||||
/*
|
||||
* ACPI 1.0 FACS or short table or optional X_ field is zero
|
||||
*/
|
||||
*physical_address =
|
||||
(acpi_physical_address) facs->firmware_waking_vector;
|
||||
} else {
|
||||
/*
|
||||
* ACPI 2.0 FACS with valid X_ field
|
||||
*/
|
||||
*physical_address =
|
||||
(acpi_physical_address) facs->xfirmware_waking_vector;
|
||||
}
|
||||
*physical_address = (acpi_physical_address)facs->firmware_waking_vector;
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
@ -627,6 +612,13 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
|
||||
}
|
||||
/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
|
||||
|
||||
/*
|
||||
* Some BIOSes assume that WAK_STS will be cleared on resume and use
|
||||
* it to determine whether the system is rebooting or resuming. Clear
|
||||
* it for compatibility.
|
||||
*/
|
||||
acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
|
||||
|
||||
acpi_gbl_system_awake_and_running = TRUE;
|
||||
|
||||
/* Enable power button */
|
||||
|
@ -5,7 +5,7 @@
|
||||
obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \
|
||||
nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
|
||||
nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
|
||||
nsparse.o
|
||||
nsparse.o nspredef.o
|
||||
|
||||
obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsdump")
|
||||
@ -334,9 +333,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
acpi_os_printf("[%s]\n",
|
||||
acpi_ps_get_opcode_name(obj_desc->
|
||||
reference.
|
||||
opcode));
|
||||
acpi_ut_get_reference_name(obj_desc));
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER_FIELD:
|
||||
|
@ -78,6 +78,7 @@ ACPI_MODULE_NAME("nseval")
|
||||
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_namespace_node *node;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ns_evaluate);
|
||||
|
||||
@ -117,6 +118,8 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
|
||||
info->resolved_node,
|
||||
acpi_ns_get_attached_object(info->resolved_node)));
|
||||
|
||||
node = info->resolved_node;
|
||||
|
||||
/*
|
||||
* Two major cases here:
|
||||
*
|
||||
@ -148,21 +151,22 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
|
||||
info->param_count++;
|
||||
}
|
||||
|
||||
/* Error if too few arguments were passed in */
|
||||
/*
|
||||
* Warning if too few or too many arguments have been passed by the
|
||||
* caller. We don't want to abort here with an error because an
|
||||
* incorrect number of arguments may not cause the method to fail.
|
||||
* However, the method will fail if there are too few arguments passed
|
||||
* and the method attempts to use one of the missing ones.
|
||||
*/
|
||||
|
||||
if (info->param_count < info->obj_desc->method.param_count) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Insufficient arguments - "
|
||||
"method [%4.4s] needs %d, found %d",
|
||||
acpi_ut_get_node_name(info->resolved_node),
|
||||
info->obj_desc->method.param_count,
|
||||
info->param_count));
|
||||
return_ACPI_STATUS(AE_MISSING_ARGUMENTS);
|
||||
}
|
||||
|
||||
/* Just a warning if too many arguments */
|
||||
|
||||
else if (info->param_count >
|
||||
} else if (info->param_count >
|
||||
info->obj_desc->method.param_count) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Excess arguments - "
|
||||
@ -195,7 +199,28 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
|
||||
} else {
|
||||
/*
|
||||
* 2) Object is not a method, return its current value
|
||||
*
|
||||
* Disallow certain object types. For these, "evaluation" is undefined.
|
||||
*/
|
||||
switch (info->resolved_node->type) {
|
||||
case ACPI_TYPE_DEVICE:
|
||||
case ACPI_TYPE_EVENT:
|
||||
case ACPI_TYPE_MUTEX:
|
||||
case ACPI_TYPE_REGION:
|
||||
case ACPI_TYPE_THERMAL:
|
||||
case ACPI_TYPE_LOCAL_SCOPE:
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"[%4.4s] Evaluation of object type [%s] is not supported",
|
||||
info->resolved_node->name.ascii,
|
||||
acpi_ut_get_type_name(info->resolved_node->
|
||||
type)));
|
||||
|
||||
return_ACPI_STATUS(AE_TYPE);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Objects require additional resolution steps (e.g., the Node may be
|
||||
@ -239,9 +264,35 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there is a return value that must be dealt with
|
||||
*/
|
||||
/* Validation of return values for ACPI-predefined methods and objects */
|
||||
|
||||
if ((status == AE_OK) || (status == AE_CTRL_RETURN_VALUE)) {
|
||||
/*
|
||||
* If this is the first evaluation, check the return value. This
|
||||
* ensures that any warnings will only be emitted during the very
|
||||
* first evaluation of the object.
|
||||
*/
|
||||
if (!(node->flags & ANOBJ_EVALUATED)) {
|
||||
/*
|
||||
* Check for a predefined ACPI name. If found, validate the
|
||||
* returned object.
|
||||
*
|
||||
* Note: Ignore return status for now, emit warnings if there are
|
||||
* problems with the returned object. May change later to abort
|
||||
* the method on invalid return object.
|
||||
*/
|
||||
(void)acpi_ns_check_predefined_names(node,
|
||||
info->
|
||||
return_object);
|
||||
}
|
||||
|
||||
/* Mark the node as having been evaluated */
|
||||
|
||||
node->flags |= ANOBJ_EVALUATED;
|
||||
}
|
||||
|
||||
/* Check if there is a return value that must be dealt with */
|
||||
|
||||
if (status == AE_CTRL_RETURN_VALUE) {
|
||||
|
||||
/* If caller does not want the return value, delete it */
|
||||
|
@ -115,7 +115,6 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
#ifdef ACPI_DEBUG_OUTPUT
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_get_external_pathname
|
||||
@ -142,7 +141,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
|
||||
|
||||
size = acpi_ns_get_pathname_length(node);
|
||||
if (!size) {
|
||||
return (NULL);
|
||||
return_PTR(NULL);
|
||||
}
|
||||
|
||||
/* Allocate a buffer to be returned to caller */
|
||||
@ -157,12 +156,12 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
|
||||
|
||||
status = acpi_ns_build_external_path(node, size, name_buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (NULL);
|
||||
ACPI_FREE(name_buffer);
|
||||
return_PTR(NULL);
|
||||
}
|
||||
|
||||
return_PTR(name_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
|
900
drivers/acpi/namespace/nspredef.c
Normal file
900
drivers/acpi/namespace/nspredef.c
Normal file
@ -0,0 +1,900 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Module Name: nspredef - Validation of ACPI predefined methods and objects
|
||||
* $Revision: 1.1 $
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2008, 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 <acpi/acnamesp.h>
|
||||
#include <acpi/acpredef.h>
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nspredef")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* This module validates predefined ACPI objects that appear in the namespace,
|
||||
* at the time they are evaluated (via acpi_evaluate_object). The purpose of this
|
||||
* validation is to detect problems with BIOS-exposed predefined ACPI objects
|
||||
* before the results are returned to the ACPI-related drivers.
|
||||
*
|
||||
* There are several areas that are validated:
|
||||
*
|
||||
* 1) The number of input arguments as defined by the method/object in the
|
||||
* ASL is validated against the ACPI specification.
|
||||
* 2) The type of the return object (if any) is validated against the ACPI
|
||||
* specification.
|
||||
* 3) For returned package objects, the count of package elements is
|
||||
* validated, as well as the type of each package element. Nested
|
||||
* packages are supported.
|
||||
*
|
||||
* For any problems found, a warning message is issued.
|
||||
*
|
||||
******************************************************************************/
|
||||
/* Local prototypes */
|
||||
static acpi_status
|
||||
acpi_ns_check_package(char *pathname,
|
||||
union acpi_operand_object *return_object,
|
||||
const union acpi_predefined_info *predefined);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_package_elements(char *pathname,
|
||||
union acpi_operand_object **elements,
|
||||
u8 type1, u32 count1, u8 type2, u32 count2);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_object_type(char *pathname,
|
||||
union acpi_operand_object *return_object,
|
||||
u32 expected_btypes, u32 package_index);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_reference(char *pathname,
|
||||
union acpi_operand_object *return_object);
|
||||
|
||||
/*
|
||||
* 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",
|
||||
};
|
||||
|
||||
#define ACPI_NOT_PACKAGE ACPI_UINT32_MAX
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_predefined_names
|
||||
*
|
||||
* PARAMETERS: Node - Namespace node for the method/object
|
||||
* return_object - Object returned from the evaluation of this
|
||||
* method/object
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Check an ACPI name for a match in the predefined name list.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
|
||||
union acpi_operand_object *return_object)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
const union acpi_predefined_info *predefined;
|
||||
char *pathname;
|
||||
|
||||
/* Match the name for this method/object against the predefined list */
|
||||
|
||||
predefined = acpi_ns_check_for_predefined_name(node);
|
||||
if (!predefined) {
|
||||
|
||||
/* Name was not one of the predefined names */
|
||||
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/* Get the full pathname to the object, for use in error messages */
|
||||
|
||||
pathname = acpi_ns_get_external_pathname(node);
|
||||
if (!pathname) {
|
||||
pathname = ACPI_CAST_PTR(char, predefined->info.name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the parameter count for this method is in accordance
|
||||
* with the ACPI specification.
|
||||
*/
|
||||
acpi_ns_check_parameter_count(pathname, node, predefined);
|
||||
|
||||
/*
|
||||
* 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_ERROR((AE_INFO,
|
||||
"%s: Missing expected return value",
|
||||
pathname));
|
||||
|
||||
status = AE_AML_NO_RETURN_VALUE;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a return value, but if one wasn't expected, just exit, this is
|
||||
* not a problem
|
||||
*
|
||||
* For example, if "Implicit return value" is enabled, methods will
|
||||
* always return a value
|
||||
*/
|
||||
if (!predefined->info.expected_btypes) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the type of the return object is what is expected for
|
||||
* this predefined name
|
||||
*/
|
||||
status = acpi_ns_check_object_type(pathname, return_object,
|
||||
predefined->info.expected_btypes,
|
||||
ACPI_NOT_PACKAGE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* For returned Package objects, check the type of all sub-objects */
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_PACKAGE) {
|
||||
status =
|
||||
acpi_ns_check_package(pathname, return_object, predefined);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (pathname) {
|
||||
ACPI_FREE(pathname);
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_parameter_count
|
||||
*
|
||||
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
|
||||
* Node - Namespace node for the method/object
|
||||
* Predefined - Pointer to entry in predefined name table
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Check that the declared (in ASL/AML) parameter count for a
|
||||
* predefined name is what is expected (i.e., what is defined in
|
||||
* the ACPI specification for this predefined name.)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
acpi_ns_check_parameter_count(char *pathname,
|
||||
struct acpi_namespace_node *node,
|
||||
const union acpi_predefined_info *predefined)
|
||||
{
|
||||
u32 param_count;
|
||||
u32 required_params_current;
|
||||
u32 required_params_old;
|
||||
|
||||
/*
|
||||
* Check that the ASL-defined parameter count is what is expected for
|
||||
* this predefined name.
|
||||
*
|
||||
* Methods have 0-7 parameters. All other types have zero.
|
||||
*/
|
||||
param_count = 0;
|
||||
if (node->type == ACPI_TYPE_METHOD) {
|
||||
param_count = node->object->method.param_count;
|
||||
}
|
||||
|
||||
/* Validate parameter count - allow two different legal counts (_SCP) */
|
||||
|
||||
required_params_current = predefined->info.param_count & 0x0F;
|
||||
required_params_old = predefined->info.param_count >> 4;
|
||||
|
||||
if ((param_count != required_params_current) &&
|
||||
(param_count != required_params_old)) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Parameter count mismatch - ASL declared %d, expected %d",
|
||||
pathname, param_count, required_params_current));
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* 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 pointer to this table entry */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_package
|
||||
*
|
||||
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
|
||||
* return_object - Object returned from the evaluation of a
|
||||
* method or object
|
||||
* Predefined - Pointer to entry in predefined name table
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Check a returned package object for the correct count and
|
||||
* correct type of all sub-objects.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_package(char *pathname,
|
||||
union acpi_operand_object *return_object,
|
||||
const union acpi_predefined_info *predefined)
|
||||
{
|
||||
const union acpi_predefined_info *package;
|
||||
union acpi_operand_object *sub_package;
|
||||
union acpi_operand_object **elements;
|
||||
union acpi_operand_object **sub_elements;
|
||||
acpi_status status;
|
||||
u32 expected_count;
|
||||
u32 count;
|
||||
u32 i;
|
||||
u32 j;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_check_package);
|
||||
|
||||
/* The package info for this name is in the next table entry */
|
||||
|
||||
package = predefined + 1;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
|
||||
"%s Validating return Package of Type %X, Count %X\n",
|
||||
pathname, package->ret_info.type,
|
||||
return_object->package.count));
|
||||
|
||||
/* Extract package count and elements array */
|
||||
|
||||
elements = return_object->package.elements;
|
||||
count = return_object->package.count;
|
||||
|
||||
/* The package must have at least one element, else invalid */
|
||||
|
||||
if (!count) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Return Package has no elements (empty)",
|
||||
pathname));
|
||||
|
||||
return (AE_AML_OPERAND_VALUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the type of the expected package contents
|
||||
*
|
||||
* PTYPE1 packages contain no subpackages
|
||||
* PTYPE2 packages contain sub-packages
|
||||
*/
|
||||
switch (package->ret_info.type) {
|
||||
case ACPI_PTYPE1_FIXED:
|
||||
|
||||
/*
|
||||
* The package count is fixed and there are no sub-packages
|
||||
*
|
||||
* If package is too small, exit.
|
||||
* If package is larger than expected, issue warning but continue
|
||||
*/
|
||||
expected_count =
|
||||
package->ret_info.count1 + package->ret_info.count2;
|
||||
if (count < expected_count) {
|
||||
goto package_too_small;
|
||||
} else if (count > expected_count) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Return Package is larger than needed - "
|
||||
"found %u, expected %u", pathname, count,
|
||||
expected_count));
|
||||
}
|
||||
|
||||
/* Validate all elements of the returned package */
|
||||
|
||||
status = acpi_ns_check_package_elements(pathname, elements,
|
||||
package->ret_info.
|
||||
object_type1,
|
||||
package->ret_info.
|
||||
count1,
|
||||
package->ret_info.
|
||||
object_type2,
|
||||
package->ret_info.
|
||||
count2);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE1_VAR:
|
||||
|
||||
/*
|
||||
* The package count is variable, there are no sub-packages, and all
|
||||
* elements must be of the same type
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
status = acpi_ns_check_object_type(pathname, *elements,
|
||||
package->ret_info.
|
||||
object_type1, i);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
elements++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE1_OPTION:
|
||||
|
||||
/*
|
||||
* The package count is variable, there are no sub-packages. There are
|
||||
* a fixed number of required elements, and a variable number of
|
||||
* optional elements.
|
||||
*
|
||||
* Check if package is at least as large as the minimum required
|
||||
*/
|
||||
expected_count = package->ret_info3.count;
|
||||
if (count < expected_count) {
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
/* Variable number of sub-objects */
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i < package->ret_info3.count) {
|
||||
|
||||
/* These are the required package elements (0, 1, or 2) */
|
||||
|
||||
status =
|
||||
acpi_ns_check_object_type(pathname,
|
||||
*elements,
|
||||
package->
|
||||
ret_info3.
|
||||
object_type[i],
|
||||
i);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
} else {
|
||||
/* These are the optional package elements */
|
||||
|
||||
status =
|
||||
acpi_ns_check_object_type(pathname,
|
||||
*elements,
|
||||
package->
|
||||
ret_info3.
|
||||
tail_object_type,
|
||||
i);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
elements++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE2_PKG_COUNT:
|
||||
|
||||
/* First element is the (Integer) count of sub-packages to follow */
|
||||
|
||||
status = acpi_ns_check_object_type(pathname, *elements,
|
||||
ACPI_RTYPE_INTEGER, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Count cannot be larger than the parent package length, but allow it
|
||||
* to be smaller. The >= accounts for the Integer above.
|
||||
*/
|
||||
expected_count = (u32) (*elements)->integer.value;
|
||||
if (expected_count >= count) {
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
count = expected_count;
|
||||
elements++;
|
||||
|
||||
/* Now we can walk the sub-packages */
|
||||
|
||||
/*lint -fallthrough */
|
||||
|
||||
case ACPI_PTYPE2:
|
||||
case ACPI_PTYPE2_FIXED:
|
||||
case ACPI_PTYPE2_MIN:
|
||||
case ACPI_PTYPE2_COUNT:
|
||||
|
||||
/*
|
||||
* These types all return a single package that consists of a variable
|
||||
* number of sub-packages
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
sub_package = *elements;
|
||||
sub_elements = sub_package->package.elements;
|
||||
|
||||
/* Each sub-object must be of type Package */
|
||||
|
||||
status =
|
||||
acpi_ns_check_object_type(pathname, sub_package,
|
||||
ACPI_RTYPE_PACKAGE, i);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* Examine the different types of sub-packages */
|
||||
|
||||
switch (package->ret_info.type) {
|
||||
case ACPI_PTYPE2:
|
||||
case ACPI_PTYPE2_PKG_COUNT:
|
||||
|
||||
/* Each subpackage has a fixed number of elements */
|
||||
|
||||
expected_count =
|
||||
package->ret_info.count1 +
|
||||
package->ret_info.count2;
|
||||
if (sub_package->package.count !=
|
||||
expected_count) {
|
||||
count = sub_package->package.count;
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
status =
|
||||
acpi_ns_check_package_elements(pathname,
|
||||
sub_elements,
|
||||
package->
|
||||
ret_info.
|
||||
object_type1,
|
||||
package->
|
||||
ret_info.
|
||||
count1,
|
||||
package->
|
||||
ret_info.
|
||||
object_type2,
|
||||
package->
|
||||
ret_info.
|
||||
count2);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE2_FIXED:
|
||||
|
||||
/* Each sub-package has a fixed length */
|
||||
|
||||
expected_count = package->ret_info2.count;
|
||||
if (sub_package->package.count < expected_count) {
|
||||
count = sub_package->package.count;
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
/* Check the type of each sub-package element */
|
||||
|
||||
for (j = 0; j < expected_count; j++) {
|
||||
status =
|
||||
acpi_ns_check_object_type(pathname,
|
||||
sub_elements
|
||||
[j],
|
||||
package->
|
||||
ret_info2.
|
||||
object_type
|
||||
[j], j);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE2_MIN:
|
||||
|
||||
/* Each sub-package has a variable but minimum length */
|
||||
|
||||
expected_count = package->ret_info.count1;
|
||||
if (sub_package->package.count < expected_count) {
|
||||
count = sub_package->package.count;
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
/* Check the type of each sub-package element */
|
||||
|
||||
status =
|
||||
acpi_ns_check_package_elements(pathname,
|
||||
sub_elements,
|
||||
package->
|
||||
ret_info.
|
||||
object_type1,
|
||||
sub_package->
|
||||
package.
|
||||
count, 0, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_PTYPE2_COUNT:
|
||||
|
||||
/* First element is the (Integer) count of elements to follow */
|
||||
|
||||
status =
|
||||
acpi_ns_check_object_type(pathname,
|
||||
*sub_elements,
|
||||
ACPI_RTYPE_INTEGER,
|
||||
0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
/* Make sure package is large enough for the Count */
|
||||
|
||||
expected_count =
|
||||
(u32) (*sub_elements)->integer.value;
|
||||
if (sub_package->package.count < expected_count) {
|
||||
count = sub_package->package.count;
|
||||
goto package_too_small;
|
||||
}
|
||||
|
||||
/* Check the type of each sub-package element */
|
||||
|
||||
status =
|
||||
acpi_ns_check_package_elements(pathname,
|
||||
(sub_elements
|
||||
+ 1),
|
||||
package->
|
||||
ret_info.
|
||||
object_type1,
|
||||
(expected_count
|
||||
- 1), 0, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
elements++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Should not get here if predefined info table is correct */
|
||||
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Invalid internal return type in table entry: %X",
|
||||
pathname, package->ret_info.type));
|
||||
|
||||
return (AE_AML_INTERNAL);
|
||||
}
|
||||
|
||||
return (AE_OK);
|
||||
|
||||
package_too_small:
|
||||
|
||||
/* Error exit for the case with an incorrect package count */
|
||||
|
||||
ACPI_WARNING((AE_INFO, "%s: Return Package is too small - "
|
||||
"found %u, expected %u", pathname, count,
|
||||
expected_count));
|
||||
|
||||
return (AE_AML_OPERAND_VALUE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_package_elements
|
||||
*
|
||||
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
|
||||
* Elements - Pointer to the package elements array
|
||||
* Type1 - Object type for first group
|
||||
* Count1 - Count for first group
|
||||
* Type2 - Object type for second group
|
||||
* Count2 - Count for second group
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Check that all elements of a package are of the correct object
|
||||
* type. Supports up to two groups of different object types.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_package_elements(char *pathname,
|
||||
union acpi_operand_object **elements,
|
||||
u8 type1, u32 count1, u8 type2, u32 count2)
|
||||
{
|
||||
union acpi_operand_object **this_element = elements;
|
||||
acpi_status status;
|
||||
u32 i;
|
||||
|
||||
/*
|
||||
* Up to two groups of package elements are supported by the data
|
||||
* structure. All elements in each group must be of the same type.
|
||||
* The second group can have a count of zero.
|
||||
*/
|
||||
for (i = 0; i < count1; i++) {
|
||||
status = acpi_ns_check_object_type(pathname, *this_element,
|
||||
type1, i);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
this_element++;
|
||||
}
|
||||
|
||||
for (i = 0; i < count2; i++) {
|
||||
status = acpi_ns_check_object_type(pathname, *this_element,
|
||||
type2, (i + count1));
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
this_element++;
|
||||
}
|
||||
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_object_type
|
||||
*
|
||||
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
|
||||
* return_object - Object return from the execution of this
|
||||
* method/object
|
||||
* expected_btypes - Bitmap of expected return type(s)
|
||||
* package_index - Index of object within parent package (if
|
||||
* applicable - ACPI_NOT_PACKAGE otherwise)
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Check the type of the return object against the expected object
|
||||
* type(s). Use of Btype allows multiple expected object types.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_object_type(char *pathname,
|
||||
union acpi_operand_object *return_object,
|
||||
u32 expected_btypes, u32 package_index)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
u32 return_btype;
|
||||
char type_buffer[48]; /* Room for 5 types */
|
||||
u32 this_rtype;
|
||||
u32 i;
|
||||
u32 j;
|
||||
|
||||
/*
|
||||
* If we get a NULL return_object here, it is a NULL package element,
|
||||
* and this is always an error.
|
||||
*/
|
||||
if (!return_object) {
|
||||
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) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Invalid return type - Found a Namespace node [%4.4s] type %s",
|
||||
pathname, return_object->node.name.ascii,
|
||||
acpi_ut_get_type_name(return_object->node.type)));
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the object type (ACPI_TYPE_xxx) to a bitmapped object type.
|
||||
* The bitmapped type allows multiple possible return types.
|
||||
*
|
||||
* Note, the cases below must handle all of the possible types returned
|
||||
* from all of the predefined names (including elements of returned
|
||||
* packages)
|
||||
*/
|
||||
switch (ACPI_GET_OBJECT_TYPE(return_object)) {
|
||||
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 */
|
||||
|
||||
goto type_error_exit;
|
||||
}
|
||||
|
||||
/* Is the object one of the expected types? */
|
||||
|
||||
if (!(return_btype & expected_btypes)) {
|
||||
goto type_error_exit;
|
||||
}
|
||||
|
||||
/* For reference objects, check that the reference type is correct */
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
status = acpi_ns_check_reference(pathname, return_object);
|
||||
}
|
||||
|
||||
return (status);
|
||||
|
||||
type_error_exit:
|
||||
|
||||
/* Create a string with all expected types for this predefined object */
|
||||
|
||||
j = 1;
|
||||
type_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(type_buffer, &acpi_rtype_names[i][j]);
|
||||
j = 0; /* Use name separator from now on */
|
||||
}
|
||||
this_rtype <<= 1; /* Next Rtype */
|
||||
}
|
||||
|
||||
if (package_index == ACPI_NOT_PACKAGE) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Return type mismatch - found %s, expected %s",
|
||||
pathname,
|
||||
acpi_ut_get_object_type_name(return_object),
|
||||
type_buffer));
|
||||
} else {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Return Package type mismatch at index %u - "
|
||||
"found %s, expected %s", pathname, package_index,
|
||||
acpi_ut_get_object_type_name(return_object),
|
||||
type_buffer));
|
||||
}
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_check_reference
|
||||
*
|
||||
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
|
||||
* return_object - Object returned from the evaluation of a
|
||||
* method or object
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Check a returned reference object for the correct reference
|
||||
* type. The only reference type that can be returned from a
|
||||
* predefined method is a named reference. All others are invalid.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_check_reference(char *pathname,
|
||||
union acpi_operand_object *return_object)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check the reference object for the correct reference type (opcode).
|
||||
* The only type of reference that can be converted to an union acpi_object is
|
||||
* a reference to a named object (reference class: NAME)
|
||||
*/
|
||||
if (return_object->reference.class == ACPI_REFCLASS_NAME) {
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"%s: Return type mismatch - unexpected reference object type [%s] %2.2X",
|
||||
pathname, acpi_ut_get_reference_name(return_object),
|
||||
return_object->reference.class));
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
@ -331,7 +331,7 @@ acpi_ns_search_and_enter(u32 target_name,
|
||||
"Found bad character(s) in name, repaired: [%4.4s]\n",
|
||||
ACPI_CAST_PTR(char, &target_name)));
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Found bad character(s) in name, repaired: [%4.4s]\n",
|
||||
ACPI_CAST_PTR(char, &target_name)));
|
||||
}
|
||||
|
@ -48,6 +48,10 @@
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsxfeval")
|
||||
|
||||
/* Local prototypes */
|
||||
static void acpi_ns_resolve_references(struct acpi_evaluate_info *info);
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
/*******************************************************************************
|
||||
*
|
||||
@ -69,6 +73,7 @@ ACPI_MODULE_NAME("nsxfeval")
|
||||
* be valid (non-null)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_evaluate_object_typed(acpi_handle handle,
|
||||
acpi_string pathname,
|
||||
@ -283,6 +288,10 @@ acpi_evaluate_object(acpi_handle handle,
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
||||
/* Dereference Index and ref_of references */
|
||||
|
||||
acpi_ns_resolve_references(info);
|
||||
|
||||
/* Get the size of the returned object */
|
||||
|
||||
status =
|
||||
@ -350,6 +359,74 @@ acpi_evaluate_object(acpi_handle handle,
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_resolve_references
|
||||
*
|
||||
* PARAMETERS: Info - Evaluation info block
|
||||
*
|
||||
* RETURN: Info->return_object is replaced with the dereferenced object
|
||||
*
|
||||
* DESCRIPTION: Dereference certain reference objects. Called before an
|
||||
* internal return object is converted to an external union acpi_object.
|
||||
*
|
||||
* Performs an automatic dereference of Index and ref_of reference objects.
|
||||
* These reference objects are not supported by the union acpi_object, so this is a
|
||||
* last resort effort to return something useful. Also, provides compatibility
|
||||
* with other ACPI implementations.
|
||||
*
|
||||
* NOTE: does not handle references within returned package objects or nested
|
||||
* references, but this support could be added later if found to be necessary.
|
||||
*
|
||||
******************************************************************************/
|
||||
static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
|
||||
{
|
||||
union acpi_operand_object *obj_desc = NULL;
|
||||
struct acpi_namespace_node *node;
|
||||
|
||||
/* We are interested in reference objects only */
|
||||
|
||||
if (ACPI_GET_OBJECT_TYPE(info->return_object) !=
|
||||
ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Two types of references are supported - those created by Index and
|
||||
* ref_of operators. A name reference (AML_NAMEPATH_OP) can be converted
|
||||
* to an union acpi_object, so it is not dereferenced here. A ddb_handle
|
||||
* (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to
|
||||
* an union acpi_object.
|
||||
*/
|
||||
switch (info->return_object->reference.class) {
|
||||
case ACPI_REFCLASS_INDEX:
|
||||
|
||||
obj_desc = *(info->return_object->reference.where);
|
||||
break;
|
||||
|
||||
case ACPI_REFCLASS_REFOF:
|
||||
|
||||
node = info->return_object->reference.object;
|
||||
if (node) {
|
||||
obj_desc = node->object;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace the existing reference object */
|
||||
|
||||
if (obj_desc) {
|
||||
acpi_ut_add_reference(obj_desc);
|
||||
acpi_ut_remove_reference(info->return_object);
|
||||
info->return_object = obj_desc;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_walk_namespace
|
||||
@ -379,6 +456,7 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
|
||||
* function, etc.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_walk_namespace(acpi_object_type type,
|
||||
acpi_handle start_object,
|
||||
|
@ -253,6 +253,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
if (!node) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -264,6 +265,10 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
|
||||
info->name = node->name.integer;
|
||||
info->valid = 0;
|
||||
|
||||
if (node->type == ACPI_TYPE_METHOD) {
|
||||
info->param_count = node->object->method.param_count;
|
||||
}
|
||||
|
||||
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
|
@ -258,7 +258,7 @@ int __init acpi_numa_init(void)
|
||||
|
||||
int acpi_get_pxm(acpi_handle h)
|
||||
{
|
||||
unsigned long pxm;
|
||||
unsigned long long pxm;
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
acpi_handle phandle = h;
|
||||
|
@ -608,7 +608,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
|
||||
acpi_handle handle;
|
||||
struct acpi_pci_id *pci_id = *id;
|
||||
acpi_status status;
|
||||
unsigned long temp;
|
||||
unsigned long long temp;
|
||||
acpi_object_type type;
|
||||
|
||||
acpi_get_parent(chandle, &handle);
|
||||
@ -620,8 +620,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
|
||||
if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
|
||||
return;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
|
||||
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
|
||||
&temp);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
u32 val;
|
||||
@ -682,6 +681,22 @@ static void acpi_os_execute_deferred(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
static void acpi_os_execute_hp_deferred(struct work_struct *work)
|
||||
{
|
||||
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
|
||||
if (!dpc) {
|
||||
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
|
||||
return;
|
||||
}
|
||||
|
||||
acpi_os_wait_events_complete(NULL);
|
||||
|
||||
dpc->function(dpc->context);
|
||||
kfree(dpc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_os_execute
|
||||
@ -697,12 +712,13 @@ static void acpi_os_execute_deferred(struct work_struct *work)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context)
|
||||
static acpi_status __acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context, int hp)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_os_dpc *dpc;
|
||||
struct workqueue_struct *queue;
|
||||
int ret;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p)] for deferred execution.\n",
|
||||
function, context));
|
||||
@ -726,19 +742,38 @@ acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
dpc->function = function;
|
||||
dpc->context = context;
|
||||
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
|
||||
if (!queue_work(queue, &dpc->work)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Call to queue_work() failed.\n"));
|
||||
if (!hp) {
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
queue = (type == OSL_NOTIFY_HANDLER) ?
|
||||
kacpi_notify_wq : kacpid_wq;
|
||||
ret = queue_work(queue, &dpc->work);
|
||||
} else {
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
|
||||
ret = schedule_work(&dpc->work);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Call to queue_work() failed.\n");
|
||||
status = AE_ERROR;
|
||||
kfree(dpc);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
acpi_status acpi_os_execute(acpi_execute_type type,
|
||||
acpi_osd_exec_callback function, void *context)
|
||||
{
|
||||
return __acpi_os_execute(type, function, context, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_os_execute);
|
||||
|
||||
acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
|
||||
void *context)
|
||||
{
|
||||
return __acpi_os_execute(0, function, context, 1);
|
||||
}
|
||||
|
||||
void acpi_os_wait_events_complete(void *context)
|
||||
{
|
||||
flush_workqueue(kacpid_wq);
|
||||
|
@ -719,6 +719,8 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
|
||||
*op = NULL;
|
||||
}
|
||||
|
||||
ACPI_PREEMPTION_POINT();
|
||||
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
union acpi_parse_object *next;
|
||||
const struct acpi_opcode_info *parent_info;
|
||||
union acpi_parse_object *replacement_op = NULL;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
|
||||
|
||||
@ -186,7 +187,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
replacement_op =
|
||||
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
|
||||
if (!replacement_op) {
|
||||
goto allocate_error;
|
||||
status = AE_NO_MEMORY;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -211,7 +212,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
replacement_op =
|
||||
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
|
||||
if (!replacement_op) {
|
||||
goto allocate_error;
|
||||
status = AE_NO_MEMORY;
|
||||
}
|
||||
} else
|
||||
if ((op->common.parent->common.aml_opcode ==
|
||||
@ -226,13 +227,13 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
acpi_ps_alloc_op(op->common.
|
||||
aml_opcode);
|
||||
if (!replacement_op) {
|
||||
goto allocate_error;
|
||||
status = AE_NO_MEMORY;
|
||||
} else {
|
||||
replacement_op->named.data =
|
||||
op->named.data;
|
||||
replacement_op->named.length =
|
||||
op->named.length;
|
||||
}
|
||||
|
||||
replacement_op->named.data =
|
||||
op->named.data;
|
||||
replacement_op->named.length =
|
||||
op->named.length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -242,7 +243,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
replacement_op =
|
||||
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
|
||||
if (!replacement_op) {
|
||||
goto allocate_error;
|
||||
status = AE_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,14 +303,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
|
||||
/* Now we can actually delete the subtree rooted at Op */
|
||||
|
||||
acpi_ps_delete_parse_tree(op);
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
|
||||
allocate_error:
|
||||
|
||||
/* Always delete the subtree, even on error */
|
||||
|
||||
acpi_ps_delete_parse_tree(op);
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@ -641,10 +635,12 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
|
||||
ACPI_WALK_METHOD_RESTART;
|
||||
}
|
||||
} else {
|
||||
/* On error, delete any return object */
|
||||
/* On error, delete any return object or implicit return */
|
||||
|
||||
acpi_ut_remove_reference(previous_walk_state->
|
||||
return_desc);
|
||||
acpi_ds_clear_implicit_return
|
||||
(previous_walk_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,7 +709,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
|
||||
acpi_device_bid(link->device)));
|
||||
|
||||
if (link->refcnt == 0) {
|
||||
acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL);
|
||||
acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
|
||||
}
|
||||
mutex_unlock(&acpi_link_lock);
|
||||
return (link->irq.active);
|
||||
@ -737,7 +737,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
|
||||
link->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
|
||||
acpi_driver_data(device) = link;
|
||||
device->driver_data = link;
|
||||
|
||||
mutex_lock(&acpi_link_lock);
|
||||
result = acpi_pci_link_get_possible(link);
|
||||
@ -773,7 +773,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
|
||||
|
||||
end:
|
||||
/* disable all links -- to be activated on use */
|
||||
acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL);
|
||||
acpi_evaluate_object(device->handle, "_DIS", NULL, NULL);
|
||||
mutex_unlock(&acpi_link_lock);
|
||||
|
||||
if (result)
|
||||
|
@ -190,7 +190,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
|
||||
struct acpi_pci_root *root = NULL;
|
||||
struct acpi_pci_root *tmp;
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long value = 0;
|
||||
unsigned long long value = 0;
|
||||
acpi_handle handle = NULL;
|
||||
struct acpi_device *child;
|
||||
|
||||
@ -206,7 +206,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
|
||||
root->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
|
||||
acpi_driver_data(device) = root;
|
||||
device->driver_data = root;
|
||||
|
||||
device->ops.bind = acpi_pci_bind;
|
||||
|
||||
|
@ -76,10 +76,10 @@ static struct acpi_pci_driver acpi_pci_slot_driver = {
|
||||
};
|
||||
|
||||
static int
|
||||
check_slot(acpi_handle handle, unsigned long *sun)
|
||||
check_slot(acpi_handle handle, unsigned long long *sun)
|
||||
{
|
||||
int device = -1;
|
||||
unsigned long adr, sta;
|
||||
unsigned long long adr, sta;
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
@ -132,7 +132,7 @@ static acpi_status
|
||||
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int device;
|
||||
unsigned long sun;
|
||||
unsigned long long sun;
|
||||
char name[SLOT_NAME_SIZE];
|
||||
struct acpi_pci_slot *slot;
|
||||
struct pci_slot *pci_slot;
|
||||
@ -182,7 +182,7 @@ static acpi_status
|
||||
walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
{
|
||||
int device, function;
|
||||
unsigned long adr;
|
||||
unsigned long long adr;
|
||||
acpi_status status;
|
||||
acpi_handle dummy_handle;
|
||||
acpi_walk_callback user_function;
|
||||
@ -239,7 +239,7 @@ static int
|
||||
walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
|
||||
{
|
||||
int seg, bus;
|
||||
unsigned long tmp;
|
||||
unsigned long long tmp;
|
||||
acpi_status status;
|
||||
acpi_handle dummy_handle;
|
||||
struct pci_bus *pci_bus;
|
||||
|
@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power");
|
||||
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
|
||||
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
|
||||
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
|
||||
|
||||
#ifdef MODULE_PARAM_PREFIX
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#endif
|
||||
#define MODULE_PARAM_PREFIX "acpi."
|
||||
int acpi_power_nocheck;
|
||||
module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
|
||||
|
||||
static int acpi_power_add(struct acpi_device *device);
|
||||
static int acpi_power_remove(struct acpi_device *device, int type);
|
||||
static int acpi_power_resume(struct acpi_device *device);
|
||||
@ -128,16 +136,16 @@ acpi_power_get_context(acpi_handle handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_power_get_state(struct acpi_power_resource *resource, int *state)
|
||||
static int acpi_power_get_state(acpi_handle handle, int *state)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long sta = 0;
|
||||
unsigned long long sta = 0;
|
||||
|
||||
|
||||
if (!resource || !state)
|
||||
if (!handle || !state)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta);
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
@ -145,7 +153,7 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
|
||||
ACPI_POWER_RESOURCE_STATE_OFF;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
|
||||
resource->name, state ? "on" : "off"));
|
||||
acpi_ut_get_node_name(handle), state ? "on" : "off"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -153,7 +161,6 @@ static int acpi_power_get_state(struct acpi_power_resource *resource, int *state
|
||||
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
|
||||
{
|
||||
int result = 0, state1;
|
||||
struct acpi_power_resource *resource = NULL;
|
||||
u32 i = 0;
|
||||
|
||||
|
||||
@ -161,12 +168,15 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
|
||||
return -EINVAL;
|
||||
|
||||
/* The state of the list is 'on' IFF all resources are 'on'. */
|
||||
/* */
|
||||
|
||||
for (i = 0; i < list->count; i++) {
|
||||
result = acpi_power_get_context(list->handles[i], &resource);
|
||||
if (result)
|
||||
return result;
|
||||
result = acpi_power_get_state(resource, &state1);
|
||||
/*
|
||||
* The state of the power resource can be obtained by
|
||||
* using the ACPI handle. In such case it is unnecessary to
|
||||
* get the Power resource first and then get its state again.
|
||||
*/
|
||||
result = acpi_power_get_state(list->handles[i], &state1);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
@ -226,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_power_get_state(resource, &state);
|
||||
if (result)
|
||||
return result;
|
||||
if (state != ACPI_POWER_RESOURCE_STATE_ON)
|
||||
return -ENOEXEC;
|
||||
|
||||
if (!acpi_power_nocheck) {
|
||||
/*
|
||||
* If acpi_power_nocheck is set, it is unnecessary to check
|
||||
* the power state after power transition.
|
||||
*/
|
||||
result = acpi_power_get_state(resource->device->handle,
|
||||
&state);
|
||||
if (result)
|
||||
return result;
|
||||
if (state != ACPI_POWER_RESOURCE_STATE_ON)
|
||||
return -ENOEXEC;
|
||||
}
|
||||
/* Update the power resource's _device_ power state */
|
||||
resource->device->power.state = ACPI_STATE_D0;
|
||||
|
||||
@ -277,11 +293,17 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_power_get_state(resource, &state);
|
||||
if (result)
|
||||
return result;
|
||||
if (state != ACPI_POWER_RESOURCE_STATE_OFF)
|
||||
return -ENOEXEC;
|
||||
if (!acpi_power_nocheck) {
|
||||
/*
|
||||
* If acpi_power_nocheck is set, it is unnecessary to check
|
||||
* the power state after power transition.
|
||||
*/
|
||||
result = acpi_power_get_state(handle, &state);
|
||||
if (result)
|
||||
return result;
|
||||
if (state != ACPI_POWER_RESOURCE_STATE_OFF)
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Update the power resource's _device_ power state */
|
||||
resource->device->power.state = ACPI_STATE_D3;
|
||||
@ -555,7 +577,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
|
||||
if (!resource)
|
||||
goto end;
|
||||
|
||||
result = acpi_power_get_state(resource, &state);
|
||||
result = acpi_power_get_state(resource->device->handle, &state);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
@ -657,7 +679,7 @@ static int acpi_power_add(struct acpi_device *device)
|
||||
strcpy(resource->name, device->pnp.bus_id);
|
||||
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
|
||||
acpi_driver_data(device) = resource;
|
||||
device->driver_data = resource;
|
||||
|
||||
/* Evalute the object to get the system level and resource order. */
|
||||
status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
|
||||
@ -668,7 +690,7 @@ static int acpi_power_add(struct acpi_device *device)
|
||||
resource->system_level = acpi_object.power_resource.system_level;
|
||||
resource->order = acpi_object.power_resource.resource_order;
|
||||
|
||||
result = acpi_power_get_state(resource, &state);
|
||||
result = acpi_power_get_state(device->handle, &state);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
@ -733,9 +755,9 @@ static int acpi_power_resume(struct acpi_device *device)
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
resource = (struct acpi_power_resource *)acpi_driver_data(device);
|
||||
resource = acpi_driver_data(device);
|
||||
|
||||
result = acpi_power_get_state(resource, &state);
|
||||
result = acpi_power_get_state(device->handle, &state);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
@ -563,7 +563,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
|
||||
|
||||
/* Check if it is a Device with HID and UID */
|
||||
if (has_uid) {
|
||||
unsigned long value;
|
||||
unsigned long long value;
|
||||
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
|
||||
NULL, &value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -818,7 +818,7 @@ static int acpi_processor_add(struct acpi_device *device)
|
||||
pr->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
|
||||
acpi_driver_data(device) = pr;
|
||||
device->driver_data = pr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -875,7 +875,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
|
||||
static int is_processor_present(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
unsigned long sta = 0;
|
||||
unsigned long long sta = 0;
|
||||
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
|
@ -1587,6 +1587,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
||||
|
||||
if (acpi_idle_bm_check()) {
|
||||
if (dev->safe_state) {
|
||||
dev->last_state = dev->safe_state;
|
||||
return dev->safe_state->enter(dev, dev->safe_state);
|
||||
} else {
|
||||
local_irq_disable();
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#endif
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/processor.h>
|
||||
@ -126,7 +127,7 @@ static struct notifier_block acpi_ppc_notifier_block = {
|
||||
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
unsigned long ppc = 0;
|
||||
unsigned long long ppc = 0;
|
||||
|
||||
|
||||
if (!pr)
|
||||
@ -334,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
|
||||
acpi_status status = AE_OK;
|
||||
acpi_handle handle = NULL;
|
||||
|
||||
|
||||
if (!pr || !pr->performance || !pr->handle)
|
||||
return -EINVAL;
|
||||
|
||||
@ -347,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
|
||||
|
||||
result = acpi_processor_get_performance_control(pr);
|
||||
if (result)
|
||||
return result;
|
||||
goto update_bios;
|
||||
|
||||
result = acpi_processor_get_performance_states(pr);
|
||||
if (result)
|
||||
return result;
|
||||
goto update_bios;
|
||||
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
|
||||
* the BIOS is older than the CPU and does not know its frequencies
|
||||
*/
|
||||
update_bios:
|
||||
if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
|
||||
if(boot_cpu_has(X86_FEATURE_EST))
|
||||
printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
|
||||
"frequency support\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int acpi_processor_notify_smm(struct module *calling_module)
|
||||
@ -524,13 +536,13 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
|
||||
|
||||
psd = buffer.pointer;
|
||||
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _PSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (psd->package.count != 1) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _PSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
@ -543,19 +555,19 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
|
||||
status = acpi_extract_package(&(psd->package.elements[0]),
|
||||
&format, &state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _PSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
|
||||
printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
|
||||
printk(KERN_ERR PREFIX "Unknown _PSD:revision\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
|
||||
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
unsigned long tpc = 0;
|
||||
unsigned long long tpc = 0;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
@ -528,13 +528,13 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
|
||||
|
||||
tsd = buffer.pointer;
|
||||
if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _TSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (tsd->package.count != 1) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _TSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
@ -547,19 +547,19 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
|
||||
status = acpi_extract_package(&(tsd->package.elements[0]),
|
||||
&format, &state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
printk(KERN_ERR PREFIX "Invalid _TSD data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
|
||||
printk(KERN_ERR PREFIX "Unknown _TSD:num_entries\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
|
||||
printk(KERN_ERR PREFIX "Unknown _TSD:revision\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
@ -15,9 +15,28 @@ void acpi_reboot(void)
|
||||
|
||||
rr = &acpi_gbl_FADT.reset_register;
|
||||
|
||||
/* Is the reset register supported? */
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
|
||||
rr->bit_width != 8 || rr->bit_offset != 0)
|
||||
/*
|
||||
* Is the ACPI reset register supported?
|
||||
*
|
||||
* According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates
|
||||
* whether the ACPI reset mechanism is supported.
|
||||
*
|
||||
* However, some boxes have this bit clear, yet a valid
|
||||
* ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only
|
||||
* mechanism that works for them after S3.
|
||||
*
|
||||
* This suggests that other operating systems may not be checking
|
||||
* the RESET_REG_SUP bit, and are using other means to decide
|
||||
* whether to use the ACPI reboot mechanism or not.
|
||||
*
|
||||
* So when acpi reboot is requested,
|
||||
* only the reset_register is checked. If the following
|
||||
* conditions are met, it indicates that the reset register is supported.
|
||||
* a. reset_register is not zero
|
||||
* b. the access width is eight
|
||||
* c. the bit_offset is zero
|
||||
*/
|
||||
if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0)
|
||||
return;
|
||||
|
||||
reset_value = acpi_gbl_FADT.reset_value;
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acresrc.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_RESOURCES
|
||||
@ -560,8 +559,8 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
|
||||
ACPI_GET_OBJECT_TYPE(*sub_object_list)) ||
|
||||
((ACPI_TYPE_LOCAL_REFERENCE ==
|
||||
ACPI_GET_OBJECT_TYPE(*sub_object_list)) &&
|
||||
((*sub_object_list)->reference.opcode ==
|
||||
AML_INT_NAMEPATH_OP)))) {
|
||||
((*sub_object_list)->reference.class ==
|
||||
ACPI_REFCLASS_NAME)))) {
|
||||
name_found = TRUE;
|
||||
} else {
|
||||
/* Look at the next element */
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acresrc.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#define _COMPONENT ACPI_RESOURCES
|
||||
@ -310,13 +309,12 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
|
||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
if (obj_desc->reference.opcode !=
|
||||
AML_INT_NAMEPATH_OP) {
|
||||
if (obj_desc->reference.class !=
|
||||
ACPI_REFCLASS_NAME) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"(PRT[%X].Source) Need name, found reference op %X",
|
||||
"(PRT[%X].Source) Need name, found Reference Class %X",
|
||||
index,
|
||||
obj_desc->reference.
|
||||
opcode));
|
||||
obj_desc->reference.class));
|
||||
return_ACPI_STATUS(AE_BAD_DATA);
|
||||
}
|
||||
|
||||
|
@ -931,7 +931,7 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
sbs->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
|
||||
acpi_driver_data(device) = sbs;
|
||||
device->driver_data = sbs;
|
||||
|
||||
result = acpi_charger_add(sbs);
|
||||
if (result)
|
||||
|
@ -258,7 +258,7 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
|
||||
static int acpi_smbus_hc_add(struct acpi_device *device)
|
||||
{
|
||||
int status;
|
||||
unsigned long val;
|
||||
unsigned long long val;
|
||||
struct acpi_smb_hc *hc;
|
||||
|
||||
if (!device)
|
||||
@ -282,7 +282,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
|
||||
hc->ec = acpi_driver_data(device->parent);
|
||||
hc->offset = (val >> 8) & 0xff;
|
||||
hc->query_bit = val & 0xff;
|
||||
acpi_driver_data(device) = hc;
|
||||
device->driver_data = hc;
|
||||
|
||||
acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
|
||||
printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
|
||||
@ -303,7 +303,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
|
||||
hc = acpi_driver_data(device);
|
||||
acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
|
||||
kfree(hc);
|
||||
acpi_driver_data(device) = NULL;
|
||||
device->driver_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -113,16 +113,16 @@ static int acpi_bus_hot_remove_device(void *context)
|
||||
|
||||
|
||||
if (acpi_bus_trim(device, 1)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Removing device failed\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Removing device failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* power off device */
|
||||
status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
"Power-off device failed\n"));
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Power-off device failed\n");
|
||||
|
||||
if (device->flags.lockable) {
|
||||
arg_list.count = 1;
|
||||
@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device,
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
/*
|
||||
* If the device is not present, it is unnecessary to load device
|
||||
* driver for it.
|
||||
*/
|
||||
if (!device->status.present)
|
||||
return -ENODEV;
|
||||
|
||||
if (device->flags.hardware_id) {
|
||||
for (id = ids; id->id[0]; id++) {
|
||||
if (!strcmp((char*)id->id, device->pnp.hardware_id))
|
||||
@ -384,7 +391,7 @@ static int acpi_device_remove(struct device * dev)
|
||||
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
|
||||
}
|
||||
acpi_dev->driver = NULL;
|
||||
acpi_driver_data(dev) = NULL;
|
||||
acpi_dev->driver_data = NULL;
|
||||
|
||||
put_device(dev);
|
||||
return 0;
|
||||
@ -477,7 +484,7 @@ static int acpi_device_register(struct acpi_device *device,
|
||||
|
||||
result = acpi_device_setup_files(device);
|
||||
if(result)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
|
||||
printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", device->dev.bus_id);
|
||||
|
||||
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
|
||||
return 0;
|
||||
@ -537,7 +544,7 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
|
||||
result = driver->ops.add(device);
|
||||
if (result) {
|
||||
device->driver = NULL;
|
||||
acpi_driver_data(device) = NULL;
|
||||
device->driver_data = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -744,6 +751,16 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
|
||||
if (!acpi_match_device_ids(device, button_device_ids))
|
||||
device->wakeup.flags.run_wake = 1;
|
||||
|
||||
/*
|
||||
* Don't set Power button GPE as run_wake
|
||||
* if Fixed Power button is used
|
||||
*/
|
||||
if (!strcmp(device->pnp.hardware_id, "PNP0C0C") &&
|
||||
!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
|
||||
device->wakeup.flags.run_wake = 0;
|
||||
device->wakeup.flags.valid = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ACPI_FAILURE(status))
|
||||
device->flags.wake_capable = 0;
|
||||
@ -807,6 +824,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
|
||||
/* TBD: System wake support and resource requirements. */
|
||||
|
||||
device->power.state = ACPI_STATE_UNKNOWN;
|
||||
acpi_bus_get_power(device->handle, &(device->power.state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1152,20 +1170,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_is_child_device(struct acpi_device *device,
|
||||
int (*matcher)(struct acpi_device *))
|
||||
{
|
||||
int result = -ENODEV;
|
||||
|
||||
do {
|
||||
if (ACPI_SUCCESS(matcher(device)))
|
||||
return AE_OK;
|
||||
} while ((device = device->parent));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_add_single_object(struct acpi_device **child,
|
||||
struct acpi_device *parent, acpi_handle handle, int type,
|
||||
@ -1221,15 +1225,18 @@ acpi_add_single_object(struct acpi_device **child,
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
if (!device->status.present) {
|
||||
/* Bay and dock should be handled even if absent */
|
||||
if (!ACPI_SUCCESS(
|
||||
acpi_is_child_device(device, acpi_bay_match)) &&
|
||||
!ACPI_SUCCESS(
|
||||
acpi_is_child_device(device, acpi_dock_match))) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
/*
|
||||
* When the device is neither present nor functional, the
|
||||
* device should not be added to Linux ACPI device tree.
|
||||
* When the status of the device is not present but functinal,
|
||||
* it should be added to Linux ACPI tree. For example : bay
|
||||
* device , dock device.
|
||||
* In such conditions it is unncessary to check whether it is
|
||||
* bay device or dock device.
|
||||
*/
|
||||
if (!device->status.present && !device->status.functional) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1251,6 +1258,16 @@ acpi_add_single_object(struct acpi_device **child,
|
||||
*/
|
||||
acpi_device_set_id(device, parent, handle, type);
|
||||
|
||||
/*
|
||||
* The ACPI device is attached to acpi handle before getting
|
||||
* the power/wakeup/peformance flags. Otherwise OS can't get
|
||||
* the corresponding ACPI device by the acpi handle in the course
|
||||
* of getting the power/wakeup/performance flags.
|
||||
*/
|
||||
result = acpi_device_set_context(device, type);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* Power Management
|
||||
* ----------------
|
||||
@ -1281,8 +1298,6 @@ acpi_add_single_object(struct acpi_device **child,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((result = acpi_device_set_context(device, type)))
|
||||
goto end;
|
||||
|
||||
result = acpi_device_register(device, parent);
|
||||
|
||||
@ -1402,7 +1417,12 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
|
||||
* TBD: Need notifications and other detection mechanisms
|
||||
* in place before we can fully implement this.
|
||||
*/
|
||||
if (child->status.present) {
|
||||
/*
|
||||
* When the device is not present but functional, it is also
|
||||
* necessary to scan the children of this device.
|
||||
*/
|
||||
if (child->status.present || (!child->status.present &&
|
||||
child->status.functional)) {
|
||||
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
|
||||
NULL, NULL);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
@ -1545,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
|
||||
return result;
|
||||
}
|
||||
|
||||
int __init acpi_boot_ec_enable(void);
|
||||
|
||||
static int __init acpi_scan_init(void)
|
||||
{
|
||||
@ -1579,9 +1598,6 @@ static int __init acpi_scan_init(void)
|
||||
*/
|
||||
result = acpi_bus_scan_fixed(acpi_root);
|
||||
|
||||
/* EC region might be needed at bus_scan, so enable it now */
|
||||
acpi_boot_ec_enable();
|
||||
|
||||
if (!result)
|
||||
result = acpi_bus_scan(acpi_root, &ops);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
@ -24,6 +25,36 @@
|
||||
|
||||
u8 sleep_states[ACPI_S_STATE_COUNT];
|
||||
|
||||
static void acpi_sleep_tts_switch(u32 acpi_state)
|
||||
{
|
||||
union acpi_object in_arg = { ACPI_TYPE_INTEGER };
|
||||
struct acpi_object_list arg_list = { 1, &in_arg };
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
in_arg.integer.value = acpi_state;
|
||||
status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
/*
|
||||
* OS can't evaluate the _TTS object correctly. Some warning
|
||||
* message will be printed. But it won't break anything.
|
||||
*/
|
||||
printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int tts_notify_reboot(struct notifier_block *this,
|
||||
unsigned long code, void *x)
|
||||
{
|
||||
acpi_sleep_tts_switch(ACPI_STATE_S5);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block tts_notifier = {
|
||||
.notifier_call = tts_notify_reboot,
|
||||
.next = NULL,
|
||||
.priority = 0,
|
||||
};
|
||||
|
||||
static int acpi_sleep_prepare(u32 acpi_state)
|
||||
{
|
||||
#ifdef CONFIG_ACPI_SLEEP
|
||||
@ -45,9 +76,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_ACPI_SLEEP
|
||||
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
|
||||
|
||||
/*
|
||||
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
|
||||
* user to request that behavior by using the 'acpi_old_suspend_ordering'
|
||||
@ -131,8 +161,9 @@ static void acpi_pm_end(void)
|
||||
* failing transition to a sleep state.
|
||||
*/
|
||||
acpi_target_sleep_state = ACPI_STATE_S0;
|
||||
acpi_sleep_tts_switch(acpi_target_sleep_state);
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#endif /* CONFIG_ACPI_SLEEP */
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
extern void do_suspend_lowlevel(void);
|
||||
@ -155,6 +186,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
|
||||
|
||||
if (sleep_states[acpi_state]) {
|
||||
acpi_target_sleep_state = acpi_state;
|
||||
acpi_sleep_tts_switch(acpi_target_sleep_state);
|
||||
} else {
|
||||
printk(KERN_ERR "ACPI does not support this state: %d\n",
|
||||
pm_state);
|
||||
@ -200,6 +232,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If ACPI is not enabled by the BIOS, we need to enable it here. */
|
||||
acpi_enable();
|
||||
/* Reprogram control registers and execute _BFS */
|
||||
acpi_leave_sleep_state_prep(acpi_state);
|
||||
|
||||
@ -296,6 +330,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = init_old_suspend_ordering,
|
||||
.ident = "HP xw4600 Workstation",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
|
||||
},
|
||||
},
|
||||
{},
|
||||
};
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
@ -313,6 +355,7 @@ void __init acpi_no_s4_hw_signature(void)
|
||||
static int acpi_hibernation_begin(void)
|
||||
{
|
||||
acpi_target_sleep_state = ACPI_STATE_S4;
|
||||
acpi_sleep_tts_switch(acpi_target_sleep_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -376,7 +419,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
|
||||
*/
|
||||
static int acpi_hibernation_begin_old(void)
|
||||
{
|
||||
int error = acpi_sleep_prepare(ACPI_STATE_S4);
|
||||
int error;
|
||||
/*
|
||||
* The _TTS object should always be evaluated before the _PTS object.
|
||||
* When the old_suspended_ordering is true, the _PTS object is
|
||||
* evaluated in the acpi_sleep_prepare.
|
||||
*/
|
||||
acpi_sleep_tts_switch(ACPI_STATE_S4);
|
||||
|
||||
error = acpi_sleep_prepare(ACPI_STATE_S4);
|
||||
|
||||
if (!error)
|
||||
acpi_target_sleep_state = ACPI_STATE_S4;
|
||||
@ -444,7 +495,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
|
||||
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
|
||||
struct acpi_device *adev;
|
||||
char acpi_method[] = "_SxD";
|
||||
unsigned long d_min, d_max;
|
||||
unsigned long long d_min, d_max;
|
||||
|
||||
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
|
||||
printk(KERN_DEBUG "ACPI handle has no context!\n");
|
||||
@ -596,5 +647,10 @@ int __init acpi_sleep_init(void)
|
||||
pm_power_off = acpi_power_off;
|
||||
}
|
||||
printk(")\n");
|
||||
/*
|
||||
* Register the tts_notifier to reboot notifier list so that the _TTS
|
||||
* object can also be evaluated when the system enters S5.
|
||||
*/
|
||||
register_reboot_notifier(&tts_notifier);
|
||||
return 0;
|
||||
}
|
||||
|
@ -386,8 +386,8 @@ static ssize_t counter_set(struct kobject *kobj,
|
||||
goto end;
|
||||
|
||||
if (!(all_counters[index].flags & ACPI_EVENT_VALID)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
"Can not change Invalid GPE/Fixed Event status\n"));
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Can not change Invalid GPE/Fixed Event status\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ ACPI_MODULE_NAME("tbfadt")
|
||||
/* Local prototypes */
|
||||
static void inline
|
||||
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
|
||||
u8 bit_width, u64 address);
|
||||
u8 byte_width, u64 address);
|
||||
|
||||
static void acpi_tb_convert_fadt(void);
|
||||
|
||||
@ -111,7 +111,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
|
||||
* FUNCTION: acpi_tb_init_generic_address
|
||||
*
|
||||
* PARAMETERS: generic_address - GAS struct to be initialized
|
||||
* bit_width - Width of this register
|
||||
* byte_width - Width of this register
|
||||
* Address - Address of the register
|
||||
*
|
||||
* RETURN: None
|
||||
@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
|
||||
|
||||
static void inline
|
||||
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
|
||||
u8 bit_width, u64 address)
|
||||
u8 byte_width, u64 address)
|
||||
{
|
||||
|
||||
/*
|
||||
@ -136,7 +136,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
|
||||
/* All other fields are byte-wide */
|
||||
|
||||
generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
|
||||
generic_address->bit_width = bit_width;
|
||||
generic_address->bit_width = byte_width << 3;
|
||||
generic_address->bit_offset = 0;
|
||||
generic_address->access_width = 0;
|
||||
}
|
||||
@ -342,9 +342,20 @@ static void acpi_tb_convert_fadt(void)
|
||||
* useful to calculate them once, here.
|
||||
*
|
||||
* The PM event blocks are split into two register blocks, first is the
|
||||
* PM Status Register block, followed immediately by the PM Enable Register
|
||||
* block. Each is of length (pm1_event_length/2)
|
||||
* PM Status Register block, followed immediately by the PM Enable
|
||||
* Register block. Each is of length (xpm1x_event_block.bit_width/2).
|
||||
*
|
||||
* On various systems the v2 fields (and particularly the bit widths)
|
||||
* cannot be relied upon, though. Hence resort to using the v1 length
|
||||
* here (and warn about the inconsistency).
|
||||
*/
|
||||
if (acpi_gbl_FADT.xpm1a_event_block.bit_width
|
||||
!= acpi_gbl_FADT.pm1_event_length * 8)
|
||||
printk(KERN_WARNING "FADT: "
|
||||
"X_PM1a_EVT_BLK.bit_width (%u) does not match"
|
||||
" PM1_EVT_LEN (%u)\n",
|
||||
acpi_gbl_FADT.xpm1a_event_block.bit_width,
|
||||
acpi_gbl_FADT.pm1_event_length);
|
||||
pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
|
||||
|
||||
/* The PM1A register block is required */
|
||||
@ -360,13 +371,20 @@ static void acpi_tb_convert_fadt(void)
|
||||
/* The PM1B register block is optional, ignore if not present */
|
||||
|
||||
if (acpi_gbl_FADT.xpm1b_event_block.address) {
|
||||
if (acpi_gbl_FADT.xpm1b_event_block.bit_width
|
||||
!= acpi_gbl_FADT.pm1_event_length * 8)
|
||||
printk(KERN_WARNING "FADT: "
|
||||
"X_PM1b_EVT_BLK.bit_width (%u) does not match"
|
||||
" PM1_EVT_LEN (%u)\n",
|
||||
acpi_gbl_FADT.xpm1b_event_block.bit_width,
|
||||
acpi_gbl_FADT.pm1_event_length);
|
||||
acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
|
||||
pm1_register_length,
|
||||
(acpi_gbl_FADT.xpm1b_event_block.
|
||||
address + pm1_register_length));
|
||||
/* Don't forget to copy space_id of the GAS */
|
||||
acpi_gbl_xpm1b_enable.space_id =
|
||||
acpi_gbl_FADT.xpm1a_event_block.space_id;
|
||||
acpi_gbl_FADT.xpm1b_event_block.space_id;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,6 @@ acpi_status
|
||||
acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
|
||||
{
|
||||
u32 i;
|
||||
u32 length;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_TRACE(tb_add_table);
|
||||
@ -145,25 +144,64 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
|
||||
}
|
||||
}
|
||||
|
||||
length = ACPI_MIN(table_desc->length,
|
||||
acpi_gbl_root_table_list.tables[i].length);
|
||||
if (ACPI_MEMCMP(table_desc->pointer,
|
||||
acpi_gbl_root_table_list.tables[i].pointer,
|
||||
length)) {
|
||||
/*
|
||||
* Check for a table match on the entire table length,
|
||||
* not just the header.
|
||||
*/
|
||||
if (table_desc->length !=
|
||||
acpi_gbl_root_table_list.tables[i].length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Table is already registered */
|
||||
if (ACPI_MEMCMP(table_desc->pointer,
|
||||
acpi_gbl_root_table_list.tables[i].pointer,
|
||||
acpi_gbl_root_table_list.tables[i].length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: the current mechanism does not unregister a table if it is
|
||||
* dynamically unloaded. The related namespace entries are deleted,
|
||||
* but the table remains in the root table list.
|
||||
*
|
||||
* The assumption here is that the number of different tables that
|
||||
* will be loaded is actually small, and there is minimal overhead
|
||||
* in just keeping the table in case it is needed again.
|
||||
*
|
||||
* If this assumption changes in the future (perhaps on large
|
||||
* machines with many table load/unload operations), tables will
|
||||
* need to be unregistered when they are unloaded, and slots in the
|
||||
* root table list should be reused when empty.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Table is already registered.
|
||||
* We can delete the table that was passed as a parameter.
|
||||
*/
|
||||
acpi_tb_delete_table(table_desc);
|
||||
*table_index = i;
|
||||
status = AE_ALREADY_EXISTS;
|
||||
goto release;
|
||||
|
||||
if (acpi_gbl_root_table_list.tables[i].
|
||||
flags & ACPI_TABLE_IS_LOADED) {
|
||||
|
||||
/* Table is still loaded, this is an error */
|
||||
|
||||
status = AE_ALREADY_EXISTS;
|
||||
goto release;
|
||||
} else {
|
||||
/* Table was unloaded, allow it to be reloaded */
|
||||
|
||||
table_desc->pointer =
|
||||
acpi_gbl_root_table_list.tables[i].pointer;
|
||||
table_desc->address =
|
||||
acpi_gbl_root_table_list.tables[i].address;
|
||||
status = AE_OK;
|
||||
goto print_header;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the table to the global table list
|
||||
*/
|
||||
/* Add the table to the global root table list */
|
||||
|
||||
status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
|
||||
table_desc->length, table_desc->flags,
|
||||
table_index);
|
||||
@ -171,6 +209,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
|
||||
goto release;
|
||||
}
|
||||
|
||||
print_header:
|
||||
acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
|
||||
|
||||
release:
|
||||
|
@ -246,18 +246,18 @@ static const struct file_operations acpi_thermal_polling_fops = {
|
||||
static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
unsigned long long tmp;
|
||||
|
||||
if (!tz)
|
||||
return -EINVAL;
|
||||
|
||||
tz->last_temperature = tz->temperature;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
|
||||
status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
tz->temperature = tmp;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
|
||||
tz->temperature));
|
||||
|
||||
@ -267,17 +267,16 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
|
||||
static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
unsigned long long tmp;
|
||||
|
||||
if (!tz)
|
||||
return -EINVAL;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
|
||||
&tz->polling_frequency);
|
||||
status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
tz->polling_frequency = tmp;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
|
||||
tz->polling_frequency));
|
||||
|
||||
@ -356,6 +355,7 @@ do { \
|
||||
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long long tmp;
|
||||
struct acpi_handle_list devices;
|
||||
int valid = 0;
|
||||
int i;
|
||||
@ -363,7 +363,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
/* Critical Shutdown (required) */
|
||||
if (flag & ACPI_TRIPS_CRITICAL) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
"_CRT", NULL, &tz->trips.critical.temperature);
|
||||
"_CRT", NULL, &tmp);
|
||||
tz->trips.critical.temperature = tmp;
|
||||
/*
|
||||
* Treat freezing temperatures as invalid as well; some
|
||||
* BIOSes return really low values and cause reboots at startup.
|
||||
@ -388,10 +389,12 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
} else if (crt > 0) {
|
||||
unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
|
||||
/*
|
||||
* Allow override to lower critical threshold
|
||||
* Allow override critical threshold
|
||||
*/
|
||||
if (crt_k < tz->trips.critical.temperature)
|
||||
tz->trips.critical.temperature = crt_k;
|
||||
if (crt_k > tz->trips.critical.temperature)
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Critical threshold %d C\n", crt);
|
||||
tz->trips.critical.temperature = crt_k;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,12 +402,13 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
/* Critical Sleep (optional) */
|
||||
if (flag & ACPI_TRIPS_HOT) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
"_HOT", NULL, &tz->trips.hot.temperature);
|
||||
"_HOT", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
tz->trips.hot.flags.valid = 0;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"No hot threshold\n"));
|
||||
} else {
|
||||
tz->trips.hot.temperature = tmp;
|
||||
tz->trips.hot.flags.valid = 1;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Found hot threshold [%lu]\n",
|
||||
@ -418,33 +422,40 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
if (psv == -1) {
|
||||
status = AE_SUPPORT;
|
||||
} else if (psv > 0) {
|
||||
tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
|
||||
tmp = CELSIUS_TO_KELVIN(psv);
|
||||
status = AE_OK;
|
||||
} else {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
"_PSV", NULL, &tz->trips.passive.temperature);
|
||||
"_PSV", NULL, &tmp);
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
tz->trips.passive.flags.valid = 0;
|
||||
else {
|
||||
tz->trips.passive.temperature = tmp;
|
||||
tz->trips.passive.flags.valid = 1;
|
||||
if (flag == ACPI_TRIPS_INIT) {
|
||||
status = acpi_evaluate_integer(
|
||||
tz->device->handle, "_TC1",
|
||||
NULL, &tz->trips.passive.tc1);
|
||||
NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
tz->trips.passive.flags.valid = 0;
|
||||
else
|
||||
tz->trips.passive.tc1 = tmp;
|
||||
status = acpi_evaluate_integer(
|
||||
tz->device->handle, "_TC2",
|
||||
NULL, &tz->trips.passive.tc2);
|
||||
NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
tz->trips.passive.flags.valid = 0;
|
||||
else
|
||||
tz->trips.passive.tc2 = tmp;
|
||||
status = acpi_evaluate_integer(
|
||||
tz->device->handle, "_TSP",
|
||||
NULL, &tz->trips.passive.tsp);
|
||||
NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
tz->trips.passive.flags.valid = 0;
|
||||
else
|
||||
tz->trips.passive.tsp = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -479,7 +490,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
|
||||
if (flag & ACPI_TRIPS_ACTIVE) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
name, NULL, &tz->trips.active[i].temperature);
|
||||
name, NULL, &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
tz->trips.active[i].flags.valid = 0;
|
||||
if (i == 0)
|
||||
@ -500,8 +511,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
|
||||
tz->trips.active[i - 2].temperature :
|
||||
CELSIUS_TO_KELVIN(act));
|
||||
break;
|
||||
} else
|
||||
} else {
|
||||
tz->trips.active[i].temperature = tmp;
|
||||
tz->trips.active[i].flags.valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
name[2] = 'L';
|
||||
@ -1213,8 +1226,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
|
||||
acpi_bus_private_data_handler,
|
||||
tz->thermal_zone);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error attaching device data\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error attaching device data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1647,7 +1660,7 @@ static int acpi_thermal_add(struct acpi_device *device)
|
||||
strcpy(tz->name, device->pnp.bus_id);
|
||||
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
|
||||
acpi_driver_data(device) = tz;
|
||||
device->driver_data = tz;
|
||||
mutex_init(&tz->lock);
|
||||
|
||||
|
||||
|
@ -548,7 +548,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
|
||||
|
||||
hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS) {
|
||||
int new_video_out = video_out;
|
||||
unsigned int new_video_out = video_out;
|
||||
if (lcd_out != -1)
|
||||
_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
|
||||
if (crt_out != -1)
|
||||
|
@ -232,7 +232,7 @@ acpi_status acpi_ut_validate_buffer(struct acpi_buffer * buffer)
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Validate that the buffer is of the required length or
|
||||
* allocate a new buffer. Returned buffer is always zeroed.
|
||||
* allocate a new buffer. Returned buffer is always zeroed.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
@ -240,7 +240,7 @@ acpi_status
|
||||
acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
|
||||
acpi_size required_length)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
acpi_size input_buffer_length;
|
||||
|
||||
/* Parameter validation */
|
||||
|
||||
@ -248,55 +248,58 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
switch (buffer->length) {
|
||||
/*
|
||||
* Buffer->Length is used as both an input and output parameter. Get the
|
||||
* input actual length and set the output required buffer length.
|
||||
*/
|
||||
input_buffer_length = buffer->length;
|
||||
buffer->length = required_length;
|
||||
|
||||
/*
|
||||
* The input buffer length contains the actual buffer length, or the type
|
||||
* of buffer to be allocated by this routine.
|
||||
*/
|
||||
switch (input_buffer_length) {
|
||||
case ACPI_NO_BUFFER:
|
||||
|
||||
/* Set the exception and returned the required length */
|
||||
/* Return the exception (and the required buffer length) */
|
||||
|
||||
status = AE_BUFFER_OVERFLOW;
|
||||
break;
|
||||
return (AE_BUFFER_OVERFLOW);
|
||||
|
||||
case ACPI_ALLOCATE_BUFFER:
|
||||
|
||||
/* Allocate a new buffer */
|
||||
|
||||
buffer->pointer = acpi_os_allocate(required_length);
|
||||
if (!buffer->pointer) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Clear the buffer */
|
||||
|
||||
ACPI_MEMSET(buffer->pointer, 0, required_length);
|
||||
break;
|
||||
|
||||
case ACPI_ALLOCATE_LOCAL_BUFFER:
|
||||
|
||||
/* Allocate a new buffer with local interface to allow tracking */
|
||||
|
||||
buffer->pointer = ACPI_ALLOCATE_ZEROED(required_length);
|
||||
if (!buffer->pointer) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
buffer->pointer = ACPI_ALLOCATE(required_length);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Existing buffer: Validate the size of the buffer */
|
||||
|
||||
if (buffer->length < required_length) {
|
||||
status = AE_BUFFER_OVERFLOW;
|
||||
break;
|
||||
if (input_buffer_length < required_length) {
|
||||
return (AE_BUFFER_OVERFLOW);
|
||||
}
|
||||
|
||||
/* Clear the buffer */
|
||||
|
||||
ACPI_MEMSET(buffer->pointer, 0, required_length);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer->length = required_length;
|
||||
return (status);
|
||||
/* Validate allocation from above or input buffer pointer */
|
||||
|
||||
if (!buffer->pointer) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Have a valid buffer, clear it */
|
||||
|
||||
ACPI_MEMSET(buffer->pointer, 0, required_length);
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED_BY_LINUX
|
||||
|
@ -42,7 +42,6 @@
|
||||
*/
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/amlcode.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
|
||||
@ -176,20 +175,24 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
|
||||
|
||||
/* This is an object reference. */
|
||||
|
||||
switch (internal_object->reference.opcode) {
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
|
||||
/* For namepath, return the object handle ("reference") */
|
||||
|
||||
default:
|
||||
|
||||
/* We are referring to the namespace node */
|
||||
switch (internal_object->reference.class) {
|
||||
case ACPI_REFCLASS_NAME:
|
||||
|
||||
/*
|
||||
* For namepath, return the object handle ("reference")
|
||||
* We are referring to the namespace node
|
||||
*/
|
||||
external_object->reference.handle =
|
||||
internal_object->reference.node;
|
||||
external_object->reference.actual_type =
|
||||
acpi_ns_get_type(internal_object->reference.node);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* All other reference types are unsupported */
|
||||
|
||||
return_ACPI_STATUS(AE_TYPE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -533,7 +536,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
|
||||
|
||||
/* TBD: should validate incoming handle */
|
||||
|
||||
internal_object->reference.opcode = AML_INT_NAMEPATH_OP;
|
||||
internal_object->reference.class = ACPI_REFCLASS_NAME;
|
||||
internal_object->reference.node =
|
||||
external_object->reference.handle;
|
||||
break;
|
||||
@ -743,11 +746,11 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
|
||||
* We copied the reference object, so we now must add a reference
|
||||
* to the object pointed to by the reference
|
||||
*
|
||||
* DDBHandle reference (from Load/load_table is a special reference,
|
||||
* it's Reference.Object is the table index, so does not need to
|
||||
* DDBHandle reference (from Load/load_table) is a special reference,
|
||||
* it does not have a Reference.Object, so does not need to
|
||||
* increase the reference count
|
||||
*/
|
||||
if (source_desc->reference.opcode == AML_LOAD_OP) {
|
||||
if (source_desc->reference.class == ACPI_REFCLASS_TABLE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include <acpi/acinterp.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acevents.h>
|
||||
#include <acpi/amlcode.h>
|
||||
|
||||
#define _COMPONENT ACPI_UTILITIES
|
||||
ACPI_MODULE_NAME("utdelete")
|
||||
@ -548,8 +547,8 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
|
||||
* reference must track changes to the ref count of the index or
|
||||
* target object.
|
||||
*/
|
||||
if ((object->reference.opcode == AML_INDEX_OP) ||
|
||||
(object->reference.opcode == AML_INT_NAMEPATH_OP)) {
|
||||
if ((object->reference.class == ACPI_REFCLASS_INDEX) ||
|
||||
(object->reference.class == ACPI_REFCLASS_NAME)) {
|
||||
next_object = object->reference.object;
|
||||
}
|
||||
break;
|
||||
@ -586,6 +585,13 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Could not update object reference count"));
|
||||
|
||||
/* Free any stacked Update State objects */
|
||||
|
||||
while (state_list) {
|
||||
state = acpi_ut_pop_generic_state(&state_list);
|
||||
acpi_ut_delete_generic_state(state);
|
||||
}
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,6 @@ struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG] = {
|
||||
/* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE,
|
||||
ACPI_BITPOSITION_RT_CLOCK_ENABLE,
|
||||
ACPI_BITMASK_RT_CLOCK_ENABLE},
|
||||
/* ACPI_BITREG_WAKE_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, 0, 0},
|
||||
/* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE,
|
||||
ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE,
|
||||
ACPI_BITMASK_PCIEXP_WAKE_DISABLE},
|
||||
@ -575,6 +574,47 @@ char *acpi_ut_get_descriptor_name(void *object)
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ut_get_reference_name
|
||||
*
|
||||
* PARAMETERS: Object - An ACPI reference object
|
||||
*
|
||||
* RETURN: Pointer to a string
|
||||
*
|
||||
* DESCRIPTION: Decode a reference object sub-type to a string.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* Printable names of reference object sub-types */
|
||||
|
||||
static const char *acpi_gbl_ref_class_names[] = {
|
||||
/* 00 */ "Local",
|
||||
/* 01 */ "Argument",
|
||||
/* 02 */ "RefOf",
|
||||
/* 03 */ "Index",
|
||||
/* 04 */ "DdbHandle",
|
||||
/* 05 */ "Named Object",
|
||||
/* 06 */ "Debug"
|
||||
};
|
||||
|
||||
const char *acpi_ut_get_reference_name(union acpi_operand_object *object)
|
||||
{
|
||||
if (!object)
|
||||
return "NULL Object";
|
||||
|
||||
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND)
|
||||
return "Not an Operand object";
|
||||
|
||||
if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE)
|
||||
return "Not a Reference object";
|
||||
|
||||
if (object->reference.class > ACPI_REFCLASS_MAX)
|
||||
return "Unknown Reference class";
|
||||
|
||||
return acpi_gbl_ref_class_names[object->reference.class];
|
||||
}
|
||||
|
||||
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
|
||||
/*
|
||||
* Strings and procedures used for debug only
|
||||
@ -677,14 +717,14 @@ u8 acpi_ut_valid_object_type(acpi_object_type type)
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: None
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Init library globals. All globals that require specific
|
||||
* initialization should be initialized here!
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ut_init_globals(void)
|
||||
acpi_status acpi_ut_init_globals(void)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 i;
|
||||
@ -695,7 +735,7 @@ void acpi_ut_init_globals(void)
|
||||
|
||||
status = acpi_ut_create_caches();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return;
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Mutex locked flags */
|
||||
@ -772,8 +812,8 @@ void acpi_ut_init_globals(void)
|
||||
acpi_gbl_display_final_mem_stats = FALSE;
|
||||
#endif
|
||||
|
||||
return_VOID;
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
|
||||
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
|
||||
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
|
||||
|
@ -995,6 +995,15 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
|
||||
state->pkg.
|
||||
this_target_obj, 0);
|
||||
if (!state) {
|
||||
|
||||
/* Free any stacked Update State objects */
|
||||
|
||||
while (state_list) {
|
||||
state =
|
||||
acpi_ut_pop_generic_state
|
||||
(&state_list);
|
||||
acpi_ut_delete_generic_state(state);
|
||||
}
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,6 @@
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/amlcode.h>
|
||||
|
||||
#define _COMPONENT ACPI_UTILITIES
|
||||
ACPI_MODULE_NAME("utobject")
|
||||
@ -478,8 +477,8 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
|
||||
|
||||
case ACPI_TYPE_LOCAL_REFERENCE:
|
||||
|
||||
switch (internal_object->reference.opcode) {
|
||||
case AML_INT_NAMEPATH_OP:
|
||||
switch (internal_object->reference.class) {
|
||||
case ACPI_REFCLASS_NAME:
|
||||
|
||||
/*
|
||||
* Get the actual length of the full pathname to this object.
|
||||
@ -503,8 +502,10 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
|
||||
* required eventually.
|
||||
*/
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Unsupported Reference opcode=%X in object %p",
|
||||
internal_object->reference.opcode,
|
||||
"Cannot convert to external object - "
|
||||
"unsupported Reference Class [%s] %X in object %p",
|
||||
acpi_ut_get_reference_name(internal_object),
|
||||
internal_object->reference.class,
|
||||
internal_object));
|
||||
status = AE_TYPE;
|
||||
break;
|
||||
@ -513,7 +514,9 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
|
||||
|
||||
default:
|
||||
|
||||
ACPI_ERROR((AE_INFO, "Unsupported type=%X in object %p",
|
||||
ACPI_ERROR((AE_INFO, "Cannot convert to external object - "
|
||||
"unsupported type [%s] %X in object %p",
|
||||
acpi_ut_get_object_type_name(internal_object),
|
||||
ACPI_GET_OBJECT_TYPE(internal_object),
|
||||
internal_object));
|
||||
status = AE_TYPE;
|
||||
|
@ -81,7 +81,12 @@ acpi_status __init acpi_initialize_subsystem(void)
|
||||
|
||||
/* Initialize all globals used by the subsystem */
|
||||
|
||||
acpi_ut_init_globals();
|
||||
status = acpi_ut_init_globals();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"During initialization of globals"));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Create the default mutex objects */
|
||||
|
||||
|
@ -256,7 +256,7 @@ EXPORT_SYMBOL(acpi_extract_package);
|
||||
acpi_status
|
||||
acpi_evaluate_integer(acpi_handle handle,
|
||||
acpi_string pathname,
|
||||
struct acpi_object_list *arguments, unsigned long *data)
|
||||
struct acpi_object_list *arguments, unsigned long long *data)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_object *element;
|
||||
@ -288,7 +288,7 @@ acpi_evaluate_integer(acpi_handle handle,
|
||||
*data = element->integer.value;
|
||||
kfree(element);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
@ -291,20 +291,20 @@ 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 *level);
|
||||
unsigned long long *level);
|
||||
static int acpi_video_get_next_level(struct acpi_video_device *device,
|
||||
u32 level_current, u32 event);
|
||||
static void acpi_video_switch_brightness(struct acpi_video_device *device,
|
||||
int event);
|
||||
static int acpi_video_device_get_state(struct acpi_video_device *device,
|
||||
unsigned long *state);
|
||||
unsigned long long *state);
|
||||
static int acpi_video_output_get(struct output_device *od);
|
||||
static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
|
||||
|
||||
/*backlight device sysfs support*/
|
||||
static int acpi_video_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
unsigned long cur_level;
|
||||
unsigned long long cur_level;
|
||||
int i;
|
||||
struct acpi_video_device *vd =
|
||||
(struct acpi_video_device *)bl_get_data(bd);
|
||||
@ -336,7 +336,7 @@ static struct backlight_ops acpi_backlight_ops = {
|
||||
/*video output device sysfs support*/
|
||||
static int acpi_video_output_get(struct output_device *od)
|
||||
{
|
||||
unsigned long state;
|
||||
unsigned long long state;
|
||||
struct acpi_video_device *vd =
|
||||
(struct acpi_video_device *)dev_get_drvdata(&od->dev);
|
||||
acpi_video_device_get_state(vd, &state);
|
||||
@ -370,7 +370,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
|
||||
{
|
||||
struct acpi_device *device = cdev->devdata;
|
||||
struct acpi_video_device *video = acpi_driver_data(device);
|
||||
unsigned long level;
|
||||
unsigned long long level;
|
||||
int state;
|
||||
|
||||
acpi_video_device_lcd_get_level_current(video, &level);
|
||||
@ -410,7 +410,7 @@ static struct thermal_cooling_device_ops video_cooling_ops = {
|
||||
/* device */
|
||||
|
||||
static int
|
||||
acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
|
||||
acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state)
|
||||
{
|
||||
int status;
|
||||
|
||||
@ -421,7 +421,7 @@ acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
|
||||
|
||||
static int
|
||||
acpi_video_device_get_state(struct acpi_video_device *device,
|
||||
unsigned long *state)
|
||||
unsigned long long *state)
|
||||
{
|
||||
int status;
|
||||
|
||||
@ -436,7 +436,7 @@ acpi_video_device_set_state(struct acpi_video_device *device, int state)
|
||||
int status;
|
||||
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
|
||||
struct acpi_object_list args = { 1, &arg0 };
|
||||
unsigned long ret;
|
||||
unsigned long long ret;
|
||||
|
||||
|
||||
arg0.integer.value = state;
|
||||
@ -495,7 +495,7 @@ 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 *level)
|
||||
unsigned long long *level)
|
||||
{
|
||||
if (device->cap._BQC)
|
||||
return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
|
||||
@ -549,7 +549,7 @@ static int
|
||||
acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
|
||||
{
|
||||
int status;
|
||||
unsigned long tmp;
|
||||
unsigned long long tmp;
|
||||
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
|
||||
struct acpi_object_list args = { 1, &arg0 };
|
||||
|
||||
@ -564,7 +564,7 @@ acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
|
||||
}
|
||||
|
||||
static int
|
||||
acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
|
||||
acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
|
||||
{
|
||||
int status;
|
||||
|
||||
@ -575,7 +575,7 @@ acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
|
||||
|
||||
static int
|
||||
acpi_video_bus_POST_options(struct acpi_video_bus *video,
|
||||
unsigned long *options)
|
||||
unsigned long long *options)
|
||||
{
|
||||
int status;
|
||||
|
||||
@ -918,7 +918,7 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
int status;
|
||||
struct acpi_video_device *dev = seq->private;
|
||||
unsigned long state;
|
||||
unsigned long long state;
|
||||
|
||||
|
||||
if (!dev)
|
||||
@ -927,14 +927,14 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
|
||||
status = acpi_video_device_get_state(dev, &state);
|
||||
seq_printf(seq, "state: ");
|
||||
if (ACPI_SUCCESS(status))
|
||||
seq_printf(seq, "0x%02lx\n", state);
|
||||
seq_printf(seq, "0x%02llx\n", state);
|
||||
else
|
||||
seq_printf(seq, "<not supported>\n");
|
||||
|
||||
status = acpi_video_device_query(dev, &state);
|
||||
seq_printf(seq, "query: ");
|
||||
if (ACPI_SUCCESS(status))
|
||||
seq_printf(seq, "0x%02lx\n", state);
|
||||
seq_printf(seq, "0x%02llx\n", state);
|
||||
else
|
||||
seq_printf(seq, "<not supported>\n");
|
||||
|
||||
@ -1217,7 +1217,7 @@ static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
|
||||
static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_video_bus *video = seq->private;
|
||||
unsigned long options;
|
||||
unsigned long long options;
|
||||
int status;
|
||||
|
||||
|
||||
@ -1232,7 +1232,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
|
||||
printk(KERN_WARNING PREFIX
|
||||
"This indicates a BIOS bug. Please contact the manufacturer.\n");
|
||||
}
|
||||
printk("%lx\n", options);
|
||||
printk("%llx\n", options);
|
||||
seq_printf(seq, "can POST: <integrated video>");
|
||||
if (options & 2)
|
||||
seq_printf(seq, " <PCI video>");
|
||||
@ -1256,7 +1256,7 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct acpi_video_bus *video = seq->private;
|
||||
int status;
|
||||
unsigned long id;
|
||||
unsigned long long id;
|
||||
|
||||
|
||||
if (!video)
|
||||
@ -1303,7 +1303,7 @@ acpi_video_bus_write_POST(struct file *file,
|
||||
struct seq_file *m = file->private_data;
|
||||
struct acpi_video_bus *video = m->private;
|
||||
char str[12] = { 0 };
|
||||
unsigned long opt, options;
|
||||
unsigned long long opt, options;
|
||||
|
||||
|
||||
if (!video || count + 1 > sizeof str)
|
||||
@ -1473,7 +1473,7 @@ static int
|
||||
acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
struct acpi_video_bus *video)
|
||||
{
|
||||
unsigned long device_id;
|
||||
unsigned long long device_id;
|
||||
int status;
|
||||
struct acpi_video_device *data;
|
||||
struct acpi_video_device_attrib* attribute;
|
||||
@ -1491,7 +1491,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
|
||||
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
|
||||
acpi_driver_data(device) = data;
|
||||
device->driver_data = data;
|
||||
|
||||
data->device_id = device_id;
|
||||
data->video = video;
|
||||
@ -1530,8 +1530,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
|
||||
acpi_video_device_notify,
|
||||
data);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing notify handler\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error installing notify handler\n");
|
||||
if(data->brightness)
|
||||
kfree(data->brightness->levels);
|
||||
kfree(data->brightness);
|
||||
@ -1724,7 +1724,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
|
||||
static void
|
||||
acpi_video_switch_brightness(struct acpi_video_device *device, int event)
|
||||
{
|
||||
unsigned long level_current, level_next;
|
||||
unsigned long long level_current, level_next;
|
||||
if (!device->brightness)
|
||||
return;
|
||||
acpi_video_device_lcd_get_level_current(device, &level_current);
|
||||
@ -1745,8 +1745,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
|
||||
|
||||
status = acpi_video_bus_get_one_device(dev, video);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
|
||||
"Cant attach device"));
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Cant attach device");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -1982,7 +1982,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
||||
video->device = device;
|
||||
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
|
||||
acpi_driver_data(device) = video;
|
||||
device->driver_data = video;
|
||||
|
||||
acpi_video_bus_find_cap(video);
|
||||
error = acpi_video_bus_check(video);
|
||||
@ -2003,8 +2003,8 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_video_bus_notify, video);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing notify handler\n"));
|
||||
printk(KERN_ERR PREFIX
|
||||
"Error installing notify handler\n");
|
||||
error = -ENODEV;
|
||||
goto err_stop_video;
|
||||
}
|
||||
@ -2058,7 +2058,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
|
||||
acpi_video_bus_remove_fs(device);
|
||||
err_free_video:
|
||||
kfree(video);
|
||||
acpi_driver_data(device) = NULL;
|
||||
device->driver_data = NULL;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
|
||||
{
|
||||
struct guid_block *block = NULL;
|
||||
char method[5];
|
||||
struct acpi_object_list input;
|
||||
union acpi_object params[1];
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
|
||||
if (!block)
|
||||
return AE_NOT_EXIST;
|
||||
|
||||
input.count = 1;
|
||||
input.pointer = params;
|
||||
params[0].type = ACPI_TYPE_INTEGER;
|
||||
params[0].integer.value = enable;
|
||||
|
||||
snprintf(method, 5, "WE%02X", block->notify_id);
|
||||
status = acpi_evaluate_object(handle, method, &input, NULL);
|
||||
|
||||
if (status != AE_OK && status != AE_NOT_FOUND)
|
||||
return status;
|
||||
else
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported WMI functions
|
||||
*/
|
||||
@ -242,7 +271,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
|
||||
char method[4] = "WM";
|
||||
|
||||
if (!find_guid(guid_string, &wblock))
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
@ -304,7 +333,7 @@ struct acpi_buffer *out)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (!find_guid(guid_string, &wblock))
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
@ -314,7 +343,7 @@ struct acpi_buffer *out)
|
||||
|
||||
/* Check GUID is a data block */
|
||||
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
|
||||
input.count = 1;
|
||||
input.pointer = wq_params;
|
||||
@ -385,7 +414,7 @@ const struct acpi_buffer *in)
|
||||
return AE_BAD_DATA;
|
||||
|
||||
if (!find_guid(guid_string, &wblock))
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
|
||||
block = &wblock->gblock;
|
||||
handle = wblock->handle;
|
||||
@ -395,7 +424,7 @@ const struct acpi_buffer *in)
|
||||
|
||||
/* Check GUID is a data block */
|
||||
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
|
||||
input.count = 2;
|
||||
input.pointer = params;
|
||||
@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
|
||||
wmi_notify_handler handler, void *data)
|
||||
{
|
||||
struct wmi_block *block;
|
||||
acpi_status status;
|
||||
|
||||
if (!guid || !handler)
|
||||
return AE_BAD_PARAMETER;
|
||||
@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
|
||||
block->handler = handler;
|
||||
block->handler_data = data;
|
||||
|
||||
return AE_OK;
|
||||
status = wmi_method_enable(block, 1);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
|
||||
|
||||
@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
|
||||
acpi_status wmi_remove_notify_handler(const char *guid)
|
||||
{
|
||||
struct wmi_block *block;
|
||||
acpi_status status;
|
||||
|
||||
if (!guid)
|
||||
return AE_BAD_PARAMETER;
|
||||
@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
|
||||
if (!block->handler)
|
||||
return AE_NULL_ENTRY;
|
||||
|
||||
status = wmi_method_enable(block, 0);
|
||||
|
||||
block->handler = NULL;
|
||||
block->handler_data = NULL;
|
||||
|
||||
return AE_OK;
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
|
||||
|
||||
|
@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
|
||||
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
||||
}
|
||||
|
||||
static void ata_acpi_eject_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
|
||||
&arg_list, NULL)))
|
||||
printk(KERN_ERR "Failed to evaluate _EJ0!\n");
|
||||
}
|
||||
|
||||
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
|
||||
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* @ap: ATA port ACPI event occurred
|
||||
* @dev: ATA device ACPI event occurred (can be NULL)
|
||||
* @event: ACPI event which occurred
|
||||
* @is_dock_event: boolean indicating whether the event was a dock one
|
||||
*
|
||||
* All ACPI bay / device realted events end up in this function. If
|
||||
* the event is port-wide @dev is NULL. If the event is specific to a
|
||||
@ -171,116 +155,99 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
||||
* ACPI notify handler context. May sleep.
|
||||
*/
|
||||
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
|
||||
u32 event, int is_dock_event)
|
||||
u32 event)
|
||||
{
|
||||
char event_string[12];
|
||||
char *envp[] = { event_string, NULL };
|
||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||
struct kobject *kobj = NULL;
|
||||
int wait = 0;
|
||||
unsigned long flags;
|
||||
acpi_handle handle, tmphandle;
|
||||
unsigned long sta;
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
|
||||
if (dev) {
|
||||
if (dev->sdev)
|
||||
kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
if (dev)
|
||||
handle = dev->acpi_handle;
|
||||
} else {
|
||||
kobj = &ap->dev->kobj;
|
||||
else
|
||||
handle = ap->acpi_handle;
|
||||
}
|
||||
|
||||
status = acpi_get_handle(handle, "_EJ0", &tmphandle);
|
||||
if (ACPI_FAILURE(status))
|
||||
/* This device does not support hotplug */
|
||||
return;
|
||||
|
||||
if (event == ACPI_NOTIFY_BUS_CHECK ||
|
||||
event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/*
|
||||
* When dock driver calls into the routine, it will always use
|
||||
* ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
|
||||
* ACPI_NOTIFY_EJECT_REQUEST for remove
|
||||
*/
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ata_port_printk(ap, KERN_ERR,
|
||||
"acpi: failed to determine bay status (0x%x)\n",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
ata_ehi_hotplugged(ehi);
|
||||
ata_port_freeze(ap);
|
||||
} else {
|
||||
/* The device has gone - unplug it */
|
||||
ata_acpi_detach_device(ap, dev);
|
||||
wait = 1;
|
||||
}
|
||||
ata_ehi_hotplugged(ehi);
|
||||
ata_port_freeze(ap);
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ata_ehi_push_desc(ehi, "ACPI event");
|
||||
|
||||
if (!is_dock_event)
|
||||
break;
|
||||
|
||||
/* undock event - immediate unplug */
|
||||
ata_acpi_detach_device(ap, dev);
|
||||
wait = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* make sure kobj doesn't go away while ap->lock is released */
|
||||
kobject_get(kobj);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
if (wait) {
|
||||
if (wait)
|
||||
ata_port_wait_eh(ap);
|
||||
ata_acpi_eject_device(handle);
|
||||
}
|
||||
|
||||
if (kobj && !is_dock_event) {
|
||||
sprintf(event_string, "BAY_EVENT=%d", event);
|
||||
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
kobject_put(kobj);
|
||||
}
|
||||
|
||||
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_device *dev = data;
|
||||
|
||||
ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
|
||||
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_port *ap = data;
|
||||
|
||||
ata_acpi_handle_hotplug(ap, NULL, event, 1);
|
||||
ata_acpi_handle_hotplug(ap, NULL, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
|
||||
static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
|
||||
u32 event)
|
||||
{
|
||||
struct kobject *kobj = NULL;
|
||||
char event_string[20];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
if (dev) {
|
||||
if (dev->sdev)
|
||||
kobj = &dev->sdev->sdev_gendev.kobj;
|
||||
} else
|
||||
kobj = &ap->dev->kobj;
|
||||
|
||||
if (kobj) {
|
||||
snprintf(event_string, 20, "BAY_EVENT=%d", event);
|
||||
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
ata_acpi_uevent(data, NULL, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_device *dev = data;
|
||||
|
||||
ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
|
||||
ata_acpi_uevent(dev->link->ap, dev, event);
|
||||
}
|
||||
|
||||
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct ata_port *ap = data;
|
||||
static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
|
||||
.handler = ata_acpi_dev_notify_dock,
|
||||
.uevent = ata_acpi_dev_uevent,
|
||||
};
|
||||
|
||||
ata_acpi_handle_hotplug(ap, NULL, event, 0);
|
||||
}
|
||||
static struct acpi_dock_ops ata_acpi_ap_dock_ops = {
|
||||
.handler = ata_acpi_ap_notify_dock,
|
||||
.uevent = ata_acpi_ap_uevent,
|
||||
};
|
||||
|
||||
/**
|
||||
* ata_acpi_associate - associate ATA host with ACPI objects
|
||||
@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host)
|
||||
ata_acpi_associate_ide_port(ap);
|
||||
|
||||
if (ap->acpi_handle) {
|
||||
acpi_install_notify_handler(ap->acpi_handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
ata_acpi_ap_notify, ap);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(ap->acpi_handle,
|
||||
ata_acpi_ap_notify_dock, ap);
|
||||
&ata_acpi_ap_dock_ops, ap);
|
||||
}
|
||||
|
||||
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
|
||||
struct ata_device *dev = &ap->link.device[j];
|
||||
|
||||
if (dev->acpi_handle) {
|
||||
acpi_install_notify_handler(dev->acpi_handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
ata_acpi_dev_notify, dev);
|
||||
/* we might be on a docking station */
|
||||
register_hotplug_dock_device(dev->acpi_handle,
|
||||
ata_acpi_dev_notify_dock, dev);
|
||||
&ata_acpi_dev_dock_ops, dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,11 @@ static void cpuidle_idle_call(void)
|
||||
if (pm_idle_old)
|
||||
pm_idle_old();
|
||||
else
|
||||
#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
|
||||
default_idle();
|
||||
#else
|
||||
local_irq_enable();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,8 +71,11 @@ static void cpuidle_idle_call(void)
|
||||
target_state = &dev->states[next_state];
|
||||
|
||||
/* enter the state and update stats */
|
||||
dev->last_residency = target_state->enter(dev, target_state);
|
||||
dev->last_state = target_state;
|
||||
dev->last_residency = target_state->enter(dev, target_state);
|
||||
if (dev->last_state)
|
||||
target_state = dev->last_state;
|
||||
|
||||
target_state->time += (unsigned long long)dev->last_residency;
|
||||
target_state->usage++;
|
||||
|
||||
|
@ -171,6 +171,9 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
|
||||
xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
|
||||
xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
|
||||
|
||||
#if CONFIG_I7300_IDLE_IOAT_CHANNEL
|
||||
device->common.chancnt--;
|
||||
#endif
|
||||
for (i = 0; i < device->common.chancnt; i++) {
|
||||
ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
|
||||
if (!ioat_chan) {
|
||||
|
16
drivers/idle/Kconfig
Normal file
16
drivers/idle/Kconfig
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
menu "Memory power savings"
|
||||
|
||||
config I7300_IDLE_IOAT_CHANNEL
|
||||
bool
|
||||
|
||||
config I7300_IDLE
|
||||
tristate "Intel chipset idle power saving driver"
|
||||
select I7300_IDLE_IOAT_CHANNEL
|
||||
depends on X86_64
|
||||
help
|
||||
Enable idle power savings with certain Intel server chipsets.
|
||||
The chipset must have I/O AT support, such as the Intel 7300.
|
||||
The power savings depends on the type and quantity of DRAM devices.
|
||||
|
||||
endmenu
|
2
drivers/idle/Makefile
Normal file
2
drivers/idle/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_I7300_IDLE) += i7300_idle.o
|
||||
|
674
drivers/idle/i7300_idle.c
Normal file
674
drivers/idle/i7300_idle.c
Normal file
@ -0,0 +1,674 @@
|
||||
/*
|
||||
* (C) Copyright 2008 Intel Corporation
|
||||
* Authors:
|
||||
* Andy Henroid <andrew.d.henroid@intel.com>
|
||||
* Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Save DIMM power on Intel 7300-based platforms when all CPUs/cores
|
||||
* are idle, using the DIMM thermal throttling capability.
|
||||
*
|
||||
* This driver depends on the Intel integrated DMA controller (I/O AT).
|
||||
* If the driver for I/O AT (drivers/dma/ioatdma*) is also enabled,
|
||||
* this driver should work cooperatively.
|
||||
*/
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/stop_machine.h>
|
||||
|
||||
#include <asm/idle.h>
|
||||
|
||||
#include "../dma/ioatdma_hw.h"
|
||||
#include "../dma/ioatdma_registers.h"
|
||||
|
||||
#define I7300_IDLE_DRIVER_VERSION "1.55"
|
||||
#define I7300_PRINT "i7300_idle:"
|
||||
|
||||
static int debug;
|
||||
module_param_named(debug, debug, uint, 0644);
|
||||
MODULE_PARM_DESC(debug, "Enable debug printks in this driver");
|
||||
|
||||
#define dprintk(fmt, arg...) \
|
||||
do { if (debug) printk(KERN_INFO I7300_PRINT fmt, ##arg); } while (0)
|
||||
|
||||
/*
|
||||
* Value to set THRTLOW to when initiating throttling
|
||||
* 0 = No throttling
|
||||
* 1 = Throttle when > 4 activations per eval window (Maximum throttling)
|
||||
* 2 = Throttle when > 8 activations
|
||||
* 168 = Throttle when > 168 activations (Minimum throttling)
|
||||
*/
|
||||
#define MAX_THRTLWLIMIT 168
|
||||
static uint i7300_idle_thrtlowlm = 1;
|
||||
module_param_named(thrtlwlimit, i7300_idle_thrtlowlm, uint, 0644);
|
||||
MODULE_PARM_DESC(thrtlwlimit,
|
||||
"Value for THRTLOWLM activation field "
|
||||
"(0 = disable throttle, 1 = Max throttle, 168 = Min throttle)");
|
||||
|
||||
/*
|
||||
* simple invocation and duration statistics
|
||||
*/
|
||||
static unsigned long total_starts;
|
||||
static unsigned long total_us;
|
||||
|
||||
#ifdef DEBUG
|
||||
static unsigned long past_skip;
|
||||
#endif
|
||||
|
||||
static struct pci_dev *fbd_dev;
|
||||
|
||||
static spinlock_t i7300_idle_lock;
|
||||
static int i7300_idle_active;
|
||||
|
||||
static u8 i7300_idle_thrtctl_saved;
|
||||
static u8 i7300_idle_thrtlow_saved;
|
||||
static u32 i7300_idle_mc_saved;
|
||||
|
||||
static cpumask_t idle_cpumask;
|
||||
static ktime_t start_ktime;
|
||||
static unsigned long avg_idle_us;
|
||||
|
||||
static struct dentry *debugfs_dir;
|
||||
|
||||
/* Begin: I/O AT Helper routines */
|
||||
|
||||
#define IOAT_CHANBASE(ioat_ctl, chan) (ioat_ctl + 0x80 + 0x80 * chan)
|
||||
/* Snoop control (disable snoops when coherency is not important) */
|
||||
#define IOAT_DESC_SADDR_SNP_CTL (1UL << 1)
|
||||
#define IOAT_DESC_DADDR_SNP_CTL (1UL << 2)
|
||||
|
||||
static struct pci_dev *ioat_dev;
|
||||
static struct ioat_dma_descriptor *ioat_desc; /* I/O AT desc & data (1 page) */
|
||||
static unsigned long ioat_desc_phys;
|
||||
static u8 *ioat_iomap; /* I/O AT memory-mapped control regs (aka CB_BAR) */
|
||||
static u8 *ioat_chanbase;
|
||||
|
||||
/* Start I/O AT memory copy */
|
||||
static int i7300_idle_ioat_start(void)
|
||||
{
|
||||
u32 err;
|
||||
/* Clear error (due to circular descriptor pointer) */
|
||||
err = readl(ioat_chanbase + IOAT_CHANERR_OFFSET);
|
||||
if (err)
|
||||
writel(err, ioat_chanbase + IOAT_CHANERR_OFFSET);
|
||||
|
||||
writeb(IOAT_CHANCMD_START, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stop I/O AT memory copy */
|
||||
static void i7300_idle_ioat_stop(void)
|
||||
{
|
||||
int i;
|
||||
u8 sts;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
writeb(IOAT_CHANCMD_RESET,
|
||||
ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
|
||||
udelay(10);
|
||||
|
||||
sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
|
||||
IOAT_CHANSTS_DMA_TRANSFER_STATUS;
|
||||
|
||||
if (sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (i == 5)
|
||||
dprintk("failed to suspend+reset I/O AT after 5 retries\n");
|
||||
|
||||
}
|
||||
|
||||
/* Test I/O AT by copying 1024 byte from 2k to 1k */
|
||||
static int __init i7300_idle_ioat_selftest(u8 *ctl,
|
||||
struct ioat_dma_descriptor *desc, unsigned long desc_phys)
|
||||
{
|
||||
u64 chan_sts;
|
||||
|
||||
memset(desc, 0, 2048);
|
||||
memset((u8 *) desc + 2048, 0xab, 1024);
|
||||
|
||||
desc[0].size = 1024;
|
||||
desc[0].ctl = 0;
|
||||
desc[0].src_addr = desc_phys + 2048;
|
||||
desc[0].dst_addr = desc_phys + 1024;
|
||||
desc[0].next = 0;
|
||||
|
||||
writeb(IOAT_CHANCMD_RESET, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
writeb(IOAT_CHANCMD_START, ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
|
||||
udelay(1000);
|
||||
|
||||
chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
|
||||
IOAT_CHANSTS_DMA_TRANSFER_STATUS;
|
||||
|
||||
if (chan_sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE) {
|
||||
/* Not complete, reset the channel */
|
||||
writeb(IOAT_CHANCMD_RESET,
|
||||
ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*(u32 *) ((u8 *) desc + 3068) != 0xabababab ||
|
||||
*(u32 *) ((u8 *) desc + 2044) != 0xabababab) {
|
||||
dprintk("Data values src 0x%x, dest 0x%x, memset 0x%x\n",
|
||||
*(u32 *) ((u8 *) desc + 2048),
|
||||
*(u32 *) ((u8 *) desc + 1024),
|
||||
*(u32 *) ((u8 *) desc + 3072));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device dummy_dma_dev = {
|
||||
.bus_id = "fallback device",
|
||||
.coherent_dma_mask = DMA_64BIT_MASK,
|
||||
.dma_mask = &dummy_dma_dev.coherent_dma_mask,
|
||||
};
|
||||
|
||||
/* Setup and initialize I/O AT */
|
||||
/* This driver needs I/O AT as the throttling takes effect only when there is
|
||||
* some memory activity. We use I/O AT to set up a dummy copy, while all CPUs
|
||||
* go idle and memory is throttled.
|
||||
*/
|
||||
static int __init i7300_idle_ioat_init(void)
|
||||
{
|
||||
u8 ver, chan_count, ioat_chan;
|
||||
u16 chan_ctl;
|
||||
|
||||
ioat_iomap = (u8 *) ioremap_nocache(pci_resource_start(ioat_dev, 0),
|
||||
pci_resource_len(ioat_dev, 0));
|
||||
|
||||
if (!ioat_iomap) {
|
||||
printk(KERN_ERR I7300_PRINT "failed to map I/O AT registers\n");
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
ver = readb(ioat_iomap + IOAT_VER_OFFSET);
|
||||
if (ver != IOAT_VER_1_2) {
|
||||
printk(KERN_ERR I7300_PRINT "unknown I/O AT version (%u.%u)\n",
|
||||
ver >> 4, ver & 0xf);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
chan_count = readb(ioat_iomap + IOAT_CHANCNT_OFFSET);
|
||||
if (!chan_count) {
|
||||
printk(KERN_ERR I7300_PRINT "unexpected # of I/O AT channels "
|
||||
"(%u)\n",
|
||||
chan_count);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
ioat_chan = chan_count - 1;
|
||||
ioat_chanbase = IOAT_CHANBASE(ioat_iomap, ioat_chan);
|
||||
|
||||
chan_ctl = readw(ioat_chanbase + IOAT_CHANCTRL_OFFSET);
|
||||
if (chan_ctl & IOAT_CHANCTRL_CHANNEL_IN_USE) {
|
||||
printk(KERN_ERR I7300_PRINT "channel %d in use\n", ioat_chan);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
writew(IOAT_CHANCTRL_CHANNEL_IN_USE,
|
||||
ioat_chanbase + IOAT_CHANCTRL_OFFSET);
|
||||
|
||||
ioat_desc = (struct ioat_dma_descriptor *)dma_alloc_coherent(
|
||||
&dummy_dma_dev, 4096,
|
||||
(dma_addr_t *)&ioat_desc_phys, GFP_KERNEL);
|
||||
if (!ioat_desc) {
|
||||
printk(KERN_ERR I7300_PRINT "failed to allocate I/O AT desc\n");
|
||||
goto err_mark_unused;
|
||||
}
|
||||
|
||||
writel(ioat_desc_phys & 0xffffffffUL,
|
||||
ioat_chanbase + IOAT1_CHAINADDR_OFFSET_LOW);
|
||||
writel(ioat_desc_phys >> 32,
|
||||
ioat_chanbase + IOAT1_CHAINADDR_OFFSET_HIGH);
|
||||
|
||||
if (i7300_idle_ioat_selftest(ioat_iomap, ioat_desc, ioat_desc_phys)) {
|
||||
printk(KERN_ERR I7300_PRINT "I/O AT self-test failed\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* Setup circular I/O AT descriptor chain */
|
||||
ioat_desc[0].ctl = IOAT_DESC_SADDR_SNP_CTL | IOAT_DESC_DADDR_SNP_CTL;
|
||||
ioat_desc[0].src_addr = ioat_desc_phys + 2048;
|
||||
ioat_desc[0].dst_addr = ioat_desc_phys + 3072;
|
||||
ioat_desc[0].size = 128;
|
||||
ioat_desc[0].next = ioat_desc_phys + sizeof(struct ioat_dma_descriptor);
|
||||
|
||||
ioat_desc[1].ctl = ioat_desc[0].ctl;
|
||||
ioat_desc[1].src_addr = ioat_desc[0].src_addr;
|
||||
ioat_desc[1].dst_addr = ioat_desc[0].dst_addr;
|
||||
ioat_desc[1].size = ioat_desc[0].size;
|
||||
ioat_desc[1].next = ioat_desc_phys;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
dma_free_coherent(&dummy_dma_dev, 4096, (void *)ioat_desc, 0);
|
||||
err_mark_unused:
|
||||
writew(0, ioat_chanbase + IOAT_CHANCTRL_OFFSET);
|
||||
err_unmap:
|
||||
iounmap(ioat_iomap);
|
||||
err_ret:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Cleanup I/O AT */
|
||||
static void __exit i7300_idle_ioat_exit(void)
|
||||
{
|
||||
int i;
|
||||
u64 chan_sts;
|
||||
|
||||
i7300_idle_ioat_stop();
|
||||
|
||||
/* Wait for a while for the channel to halt before releasing */
|
||||
for (i = 0; i < 10; i++) {
|
||||
writeb(IOAT_CHANCMD_RESET,
|
||||
ioat_chanbase + IOAT1_CHANCMD_OFFSET);
|
||||
|
||||
chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
|
||||
IOAT_CHANSTS_DMA_TRANSFER_STATUS;
|
||||
|
||||
if (chan_sts != IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE) {
|
||||
writew(0, ioat_chanbase + IOAT_CHANCTRL_OFFSET);
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
chan_sts = readq(ioat_chanbase + IOAT1_CHANSTS_OFFSET) &
|
||||
IOAT_CHANSTS_DMA_TRANSFER_STATUS;
|
||||
|
||||
/*
|
||||
* We tried to reset multiple times. If IO A/T channel is still active
|
||||
* flag an error and return without cleanup. Memory leak is better
|
||||
* than random corruption in that extreme error situation.
|
||||
*/
|
||||
if (chan_sts == IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE) {
|
||||
printk(KERN_ERR I7300_PRINT "Unable to stop IO A/T channels."
|
||||
" Not freeing resources\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_free_coherent(&dummy_dma_dev, 4096, (void *)ioat_desc, 0);
|
||||
iounmap(ioat_iomap);
|
||||
}
|
||||
|
||||
/* End: I/O AT Helper routines */
|
||||
|
||||
#define DIMM_THRTLOW 0x64
|
||||
#define DIMM_THRTCTL 0x67
|
||||
#define DIMM_THRTCTL_THRMHUNT (1UL << 0)
|
||||
#define DIMM_MC 0x40
|
||||
#define DIMM_GTW_MODE (1UL << 17)
|
||||
#define DIMM_GBLACT 0x60
|
||||
|
||||
/*
|
||||
* Keep track of an exponential-decaying average of recent idle durations.
|
||||
* The latest duration gets DURATION_WEIGHT_PCT percentage weight
|
||||
* in this average, with the old average getting the remaining weight.
|
||||
*
|
||||
* High weights emphasize recent history, low weights include long history.
|
||||
*/
|
||||
#define DURATION_WEIGHT_PCT 55
|
||||
|
||||
/*
|
||||
* When the decaying average of recent durations or the predicted duration
|
||||
* of the next timer interrupt is shorter than duration_threshold, the
|
||||
* driver will decline to throttle.
|
||||
*/
|
||||
#define DURATION_THRESHOLD_US 100
|
||||
|
||||
|
||||
/* Store DIMM thermal throttle configuration */
|
||||
static int i7300_idle_thrt_save(void)
|
||||
{
|
||||
u32 new_mc_val;
|
||||
u8 gblactlm;
|
||||
|
||||
pci_read_config_byte(fbd_dev, DIMM_THRTCTL, &i7300_idle_thrtctl_saved);
|
||||
pci_read_config_byte(fbd_dev, DIMM_THRTLOW, &i7300_idle_thrtlow_saved);
|
||||
pci_read_config_dword(fbd_dev, DIMM_MC, &i7300_idle_mc_saved);
|
||||
/*
|
||||
* Make sure we have Global Throttling Window Mode set to have a
|
||||
* "short" window. This (mostly) works around an issue where
|
||||
* throttling persists until the end of the global throttling window
|
||||
* size. On the tested system, this was resulting in a maximum of
|
||||
* 64 ms to exit throttling (average 32 ms). The actual numbers
|
||||
* depends on system frequencies. Setting the short window reduces
|
||||
* this by a factor of 4096.
|
||||
*
|
||||
* We will only do this only if the system is set for
|
||||
* unlimited-activations while in open-loop throttling (i.e., when
|
||||
* Global Activation Throttle Limit is zero).
|
||||
*/
|
||||
pci_read_config_byte(fbd_dev, DIMM_GBLACT, &gblactlm);
|
||||
dprintk("thrtctl_saved = 0x%02x, thrtlow_saved = 0x%02x\n",
|
||||
i7300_idle_thrtctl_saved,
|
||||
i7300_idle_thrtlow_saved);
|
||||
dprintk("mc_saved = 0x%08x, gblactlm = 0x%02x\n",
|
||||
i7300_idle_mc_saved,
|
||||
gblactlm);
|
||||
if (gblactlm == 0) {
|
||||
new_mc_val = i7300_idle_mc_saved | DIMM_GTW_MODE;
|
||||
pci_write_config_dword(fbd_dev, DIMM_MC, new_mc_val);
|
||||
return 0;
|
||||
} else {
|
||||
dprintk("could not set GTW_MODE = 1 (OLTT enabled)\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore DIMM thermal throttle configuration */
|
||||
static void i7300_idle_thrt_restore(void)
|
||||
{
|
||||
pci_write_config_dword(fbd_dev, DIMM_MC, i7300_idle_mc_saved);
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTLOW, i7300_idle_thrtlow_saved);
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTCTL, i7300_idle_thrtctl_saved);
|
||||
}
|
||||
|
||||
/* Enable DIMM thermal throttling */
|
||||
static void i7300_idle_start(void)
|
||||
{
|
||||
u8 new_ctl;
|
||||
u8 limit;
|
||||
|
||||
new_ctl = i7300_idle_thrtctl_saved & ~DIMM_THRTCTL_THRMHUNT;
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
|
||||
|
||||
limit = i7300_idle_thrtlowlm;
|
||||
if (unlikely(limit > MAX_THRTLWLIMIT))
|
||||
limit = MAX_THRTLWLIMIT;
|
||||
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTLOW, limit);
|
||||
|
||||
new_ctl = i7300_idle_thrtctl_saved | DIMM_THRTCTL_THRMHUNT;
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
|
||||
}
|
||||
|
||||
/* Disable DIMM thermal throttling */
|
||||
static void i7300_idle_stop(void)
|
||||
{
|
||||
u8 new_ctl;
|
||||
u8 got_ctl;
|
||||
|
||||
new_ctl = i7300_idle_thrtctl_saved & ~DIMM_THRTCTL_THRMHUNT;
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTCTL, new_ctl);
|
||||
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTLOW, i7300_idle_thrtlow_saved);
|
||||
pci_write_config_byte(fbd_dev, DIMM_THRTCTL, i7300_idle_thrtctl_saved);
|
||||
pci_read_config_byte(fbd_dev, DIMM_THRTCTL, &got_ctl);
|
||||
WARN_ON_ONCE(got_ctl != i7300_idle_thrtctl_saved);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* i7300_avg_duration_check()
|
||||
* return 0 if the decaying average of recent idle durations is
|
||||
* more than DURATION_THRESHOLD_US
|
||||
*/
|
||||
static int i7300_avg_duration_check(void)
|
||||
{
|
||||
if (avg_idle_us >= DURATION_THRESHOLD_US)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
past_skip++;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Idle notifier to look at idle CPUs */
|
||||
static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
ktime_t now_ktime;
|
||||
static ktime_t idle_begin_time;
|
||||
static int time_init = 1;
|
||||
|
||||
if (!i7300_idle_thrtlowlm)
|
||||
return 0;
|
||||
|
||||
if (unlikely(time_init)) {
|
||||
time_init = 0;
|
||||
idle_begin_time = ktime_get();
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&i7300_idle_lock, flags);
|
||||
if (val == IDLE_START) {
|
||||
|
||||
cpu_set(smp_processor_id(), idle_cpumask);
|
||||
|
||||
if (cpus_weight(idle_cpumask) != num_online_cpus())
|
||||
goto end;
|
||||
|
||||
now_ktime = ktime_get();
|
||||
idle_begin_time = now_ktime;
|
||||
|
||||
if (i7300_avg_duration_check())
|
||||
goto end;
|
||||
|
||||
i7300_idle_active = 1;
|
||||
total_starts++;
|
||||
start_ktime = now_ktime;
|
||||
|
||||
i7300_idle_start();
|
||||
i7300_idle_ioat_start();
|
||||
|
||||
} else if (val == IDLE_END) {
|
||||
cpu_clear(smp_processor_id(), idle_cpumask);
|
||||
if (cpus_weight(idle_cpumask) == (num_online_cpus() - 1)) {
|
||||
/* First CPU coming out of idle */
|
||||
u64 idle_duration_us;
|
||||
|
||||
now_ktime = ktime_get();
|
||||
|
||||
idle_duration_us = ktime_to_us(ktime_sub
|
||||
(now_ktime, idle_begin_time));
|
||||
|
||||
avg_idle_us =
|
||||
((100 - DURATION_WEIGHT_PCT) * avg_idle_us +
|
||||
DURATION_WEIGHT_PCT * idle_duration_us) / 100;
|
||||
|
||||
if (i7300_idle_active) {
|
||||
ktime_t idle_ktime;
|
||||
|
||||
idle_ktime = ktime_sub(now_ktime, start_ktime);
|
||||
total_us += ktime_to_us(idle_ktime);
|
||||
|
||||
i7300_idle_ioat_stop();
|
||||
i7300_idle_stop();
|
||||
i7300_idle_active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
spin_unlock_irqrestore(&i7300_idle_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block i7300_idle_nb = {
|
||||
.notifier_call = i7300_idle_notifier,
|
||||
};
|
||||
|
||||
/*
|
||||
* I/O AT controls (PCI bus 0 device 8 function 0)
|
||||
* DIMM controls (PCI bus 0 device 16 function 1)
|
||||
*/
|
||||
#define IOAT_BUS 0
|
||||
#define IOAT_DEVFN PCI_DEVFN(8, 0)
|
||||
#define MEMCTL_BUS 0
|
||||
#define MEMCTL_DEVFN PCI_DEVFN(16, 1)
|
||||
|
||||
struct fbd_ioat {
|
||||
unsigned int vendor;
|
||||
unsigned int ioat_dev;
|
||||
};
|
||||
|
||||
/*
|
||||
* The i5000 chip-set has the same hooks as the i7300
|
||||
* but support is disabled by default because this driver
|
||||
* has not been validated on that platform.
|
||||
*/
|
||||
#define SUPPORT_I5000 0
|
||||
|
||||
static const struct fbd_ioat fbd_ioat_list[] = {
|
||||
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB},
|
||||
#if SUPPORT_I5000
|
||||
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT},
|
||||
#endif
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static const struct pci_device_id pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_FBD_CNB) },
|
||||
#if SUPPORT_I5000
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
|
||||
#endif
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pci_tbl);
|
||||
|
||||
/* Check for known platforms with I/O-AT */
|
||||
static int __init i7300_idle_platform_probe(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
fbd_dev = pci_get_bus_and_slot(MEMCTL_BUS, MEMCTL_DEVFN);
|
||||
if (!fbd_dev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; pci_tbl[i].vendor != 0; i++) {
|
||||
if (fbd_dev->vendor == pci_tbl[i].vendor &&
|
||||
fbd_dev->device == pci_tbl[i].device) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pci_tbl[i].vendor == 0)
|
||||
return -ENODEV;
|
||||
|
||||
ioat_dev = pci_get_bus_and_slot(IOAT_BUS, IOAT_DEVFN);
|
||||
if (!ioat_dev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; fbd_ioat_list[i].vendor != 0; i++) {
|
||||
if (ioat_dev->vendor == fbd_ioat_list[i].vendor &&
|
||||
ioat_dev->device == fbd_ioat_list[i].ioat_dev) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int stats_open_generic(struct inode *inode, struct file *fp)
|
||||
{
|
||||
fp->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count,
|
||||
loff_t *off)
|
||||
{
|
||||
unsigned long *p = fp->private_data;
|
||||
char buf[32];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, 32, "%lu\n", *p);
|
||||
return simple_read_from_buffer(ubuf, count, off, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations idle_fops = {
|
||||
.open = stats_open_generic,
|
||||
.read = stats_read_ul,
|
||||
};
|
||||
|
||||
struct debugfs_file_info {
|
||||
void *ptr;
|
||||
char name[32];
|
||||
struct dentry *file;
|
||||
} debugfs_file_list[] = {
|
||||
{&total_starts, "total_starts", NULL},
|
||||
{&total_us, "total_us", NULL},
|
||||
#ifdef DEBUG
|
||||
{&past_skip, "past_skip", NULL},
|
||||
#endif
|
||||
{NULL, "", NULL}
|
||||
};
|
||||
|
||||
static int __init i7300_idle_init(void)
|
||||
{
|
||||
spin_lock_init(&i7300_idle_lock);
|
||||
cpus_clear(idle_cpumask);
|
||||
total_us = 0;
|
||||
|
||||
if (i7300_idle_platform_probe())
|
||||
return -ENODEV;
|
||||
|
||||
if (i7300_idle_thrt_save())
|
||||
return -ENODEV;
|
||||
|
||||
if (i7300_idle_ioat_init())
|
||||
return -ENODEV;
|
||||
|
||||
debugfs_dir = debugfs_create_dir("i7300_idle", NULL);
|
||||
if (debugfs_dir) {
|
||||
int i = 0;
|
||||
|
||||
while (debugfs_file_list[i].ptr != NULL) {
|
||||
debugfs_file_list[i].file = debugfs_create_file(
|
||||
debugfs_file_list[i].name,
|
||||
S_IRUSR,
|
||||
debugfs_dir,
|
||||
debugfs_file_list[i].ptr,
|
||||
&idle_fops);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
idle_notifier_register(&i7300_idle_nb);
|
||||
|
||||
printk(KERN_INFO "i7300_idle: loaded v%s\n", I7300_IDLE_DRIVER_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit i7300_idle_exit(void)
|
||||
{
|
||||
idle_notifier_unregister(&i7300_idle_nb);
|
||||
|
||||
if (debugfs_dir) {
|
||||
int i = 0;
|
||||
|
||||
while (debugfs_file_list[i].file != NULL) {
|
||||
debugfs_remove(debugfs_file_list[i].file);
|
||||
i++;
|
||||
}
|
||||
|
||||
debugfs_remove(debugfs_dir);
|
||||
}
|
||||
i7300_idle_thrt_restore();
|
||||
i7300_idle_ioat_exit();
|
||||
}
|
||||
|
||||
module_init(i7300_idle_init);
|
||||
module_exit(i7300_idle_exit);
|
||||
|
||||
MODULE_AUTHOR("Andy Henroid <andrew.d.henroid@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Chipset DIMM Idle Power Saving Driver v"
|
||||
I7300_IDLE_DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
@ -145,6 +145,7 @@ config ACER_WMI
|
||||
depends on NEW_LEDS
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on SERIO_I8042
|
||||
depends on RFKILL
|
||||
select ACPI_WMI
|
||||
---help---
|
||||
This is a driver for newer Acer (and Wistron) laptops. It adds
|
||||
@ -245,6 +246,17 @@ config MSI_LAPTOP
|
||||
|
||||
If you have an MSI S270 laptop, say Y or M here.
|
||||
|
||||
config PANASONIC_LAPTOP
|
||||
tristate "Panasonic Laptop Extras"
|
||||
depends on X86 && INPUT && ACPI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver adds support for access to backlight control and hotkeys
|
||||
on Panasonic Let's Note laptops.
|
||||
|
||||
If you have a Panasonic Let's note laptop (such as the R1(N variant),
|
||||
R2, R3, R5, T2, W2 and Y2 series), say Y.
|
||||
|
||||
config COMPAL_LAPTOP
|
||||
tristate "Compal Laptop Extras"
|
||||
depends on X86
|
||||
|
@ -23,6 +23,7 @@ obj-$(CONFIG_SGI_IOC4) += ioc4.o
|
||||
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
|
||||
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
|
||||
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
|
||||
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
|
||||
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <acpi/acpi_drivers.h>
|
||||
@ -123,21 +125,15 @@ enum interface_flags {
|
||||
|
||||
static int max_brightness = 0xF;
|
||||
|
||||
static int wireless = -1;
|
||||
static int bluetooth = -1;
|
||||
static int mailled = -1;
|
||||
static int brightness = -1;
|
||||
static int threeg = -1;
|
||||
static int force_series;
|
||||
|
||||
module_param(mailled, int, 0444);
|
||||
module_param(wireless, int, 0444);
|
||||
module_param(bluetooth, int, 0444);
|
||||
module_param(brightness, int, 0444);
|
||||
module_param(threeg, int, 0444);
|
||||
module_param(force_series, int, 0444);
|
||||
MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
|
||||
MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
|
||||
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
|
||||
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
|
||||
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
|
||||
@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
|
||||
|
||||
struct acer_data {
|
||||
int mailled;
|
||||
int wireless;
|
||||
int bluetooth;
|
||||
int threeg;
|
||||
int brightness;
|
||||
};
|
||||
@ -157,6 +151,9 @@ struct acer_debug {
|
||||
u32 wmid_devices;
|
||||
};
|
||||
|
||||
static struct rfkill *wireless_rfkill;
|
||||
static struct rfkill *bluetooth_rfkill;
|
||||
|
||||
/* Each low-level interface must define at least some of the following */
|
||||
struct wmi_interface {
|
||||
/* The WMI device type */
|
||||
@ -476,7 +473,7 @@ struct wmi_interface *iface)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
@ -514,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
/* Actually do the set */
|
||||
@ -689,7 +686,7 @@ struct wmi_interface *iface)
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
}
|
||||
status = WMI_execute_u32(method_id, 0, &result);
|
||||
|
||||
@ -735,7 +732,7 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return AE_BAD_ADDRESS;
|
||||
return AE_ERROR;
|
||||
}
|
||||
return WMI_execute_u32(method_id, (u32)value, NULL);
|
||||
}
|
||||
@ -785,7 +782,7 @@ static struct wmi_interface wmid_interface = {
|
||||
|
||||
static acpi_status get_u32(u32 *value, u32 cap)
|
||||
{
|
||||
acpi_status status = AE_BAD_ADDRESS;
|
||||
acpi_status status = AE_ERROR;
|
||||
|
||||
switch (interface->type) {
|
||||
case ACER_AMW0:
|
||||
@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
|
||||
* capability isn't available on the given interface
|
||||
*/
|
||||
set_u32(mailled, ACER_CAP_MAILLED);
|
||||
set_u32(wireless, ACER_CAP_WIRELESS);
|
||||
set_u32(bluetooth, ACER_CAP_BLUETOOTH);
|
||||
set_u32(threeg, ACER_CAP_THREEG);
|
||||
set_u32(brightness, ACER_CAP_BRIGHTNESS);
|
||||
}
|
||||
@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read/ write bool sysfs macro
|
||||
* Rfkill devices
|
||||
*/
|
||||
#define show_set_bool(value, cap) \
|
||||
static ssize_t \
|
||||
show_bool_##value(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
u32 result; \
|
||||
acpi_status status = get_u32(&result, cap); \
|
||||
if (ACPI_SUCCESS(status)) \
|
||||
return sprintf(buf, "%u\n", result); \
|
||||
return sprintf(buf, "Read error\n"); \
|
||||
} \
|
||||
\
|
||||
static ssize_t \
|
||||
set_bool_##value(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
u32 tmp = simple_strtoul(buf, NULL, 10); \
|
||||
acpi_status status = set_u32(tmp, cap); \
|
||||
if (ACPI_FAILURE(status)) \
|
||||
return -EINVAL; \
|
||||
return count; \
|
||||
} \
|
||||
static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
|
||||
show_bool_##value, set_bool_##value);
|
||||
static void acer_rfkill_update(struct work_struct *ignored);
|
||||
static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
|
||||
static void acer_rfkill_update(struct work_struct *ignored)
|
||||
{
|
||||
u32 state;
|
||||
acpi_status status;
|
||||
|
||||
show_set_bool(wireless, ACER_CAP_WIRELESS);
|
||||
show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
|
||||
show_set_bool(threeg, ACER_CAP_THREEG);
|
||||
status = get_u32(&state, ACER_CAP_WIRELESS);
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_force_state(wireless_rfkill, state ?
|
||||
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_force_state(bluetooth_rfkill, state ?
|
||||
RFKILL_STATE_UNBLOCKED :
|
||||
RFKILL_STATE_SOFT_BLOCKED);
|
||||
}
|
||||
|
||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||
}
|
||||
|
||||
static int acer_rfkill_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 *cap = data;
|
||||
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rfkill * acer_rfkill_register(struct device *dev,
|
||||
enum rfkill_type type, char *name, u32 cap)
|
||||
{
|
||||
int err;
|
||||
u32 state;
|
||||
u32 *data;
|
||||
struct rfkill *rfkill_dev;
|
||||
|
||||
rfkill_dev = rfkill_allocate(dev, type);
|
||||
if (!rfkill_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
rfkill_dev->name = name;
|
||||
get_u32(&state, cap);
|
||||
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
data = kzalloc(sizeof(u32), GFP_KERNEL);
|
||||
if (!data) {
|
||||
rfkill_free(rfkill_dev);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
*data = cap;
|
||||
rfkill_dev->data = data;
|
||||
rfkill_dev->toggle_radio = acer_rfkill_set;
|
||||
rfkill_dev->user_claim_unsupported = 1;
|
||||
|
||||
err = rfkill_register(rfkill_dev);
|
||||
if (err) {
|
||||
kfree(rfkill_dev->data);
|
||||
rfkill_free(rfkill_dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return rfkill_dev;
|
||||
}
|
||||
|
||||
static int acer_rfkill_init(struct device *dev)
|
||||
{
|
||||
wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
|
||||
"acer-wireless", ACER_CAP_WIRELESS);
|
||||
if (IS_ERR(wireless_rfkill))
|
||||
return PTR_ERR(wireless_rfkill);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
bluetooth_rfkill = acer_rfkill_register(dev,
|
||||
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
||||
ACER_CAP_BLUETOOTH);
|
||||
if (IS_ERR(bluetooth_rfkill)) {
|
||||
kfree(wireless_rfkill->data);
|
||||
rfkill_unregister(wireless_rfkill);
|
||||
return PTR_ERR(bluetooth_rfkill);
|
||||
}
|
||||
}
|
||||
|
||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acer_rfkill_exit(void)
|
||||
{
|
||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||
kfree(wireless_rfkill->data);
|
||||
rfkill_unregister(wireless_rfkill);
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
kfree(wireless_rfkill->data);
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read interface sysfs macro
|
||||
* sysfs interface
|
||||
*/
|
||||
static ssize_t show_bool_threeg(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 result; \
|
||||
acpi_status status = get_u32(&result, ACER_CAP_THREEG);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return sprintf(buf, "%u\n", result);
|
||||
return sprintf(buf, "Read error\n");
|
||||
}
|
||||
|
||||
static ssize_t set_bool_threeg(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
u32 tmp = simple_strtoul(buf, NULL, 10);
|
||||
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EINVAL;
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
|
||||
set_bool_threeg);
|
||||
|
||||
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
|
||||
goto error_brightness;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err = acer_rfkill_init(&device->dev);
|
||||
|
||||
return err;
|
||||
|
||||
error_brightness:
|
||||
acer_led_exit();
|
||||
@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
|
||||
acer_led_exit();
|
||||
if (has_cap(ACER_CAP_BRIGHTNESS))
|
||||
acer_backlight_exit();
|
||||
|
||||
acer_rfkill_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1052,16 +1146,6 @@ pm_message_t state)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||
get_u32(&value, ACER_CAP_WIRELESS);
|
||||
data->wireless = value;
|
||||
}
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
get_u32(&value, ACER_CAP_BLUETOOTH);
|
||||
data->bluetooth = value;
|
||||
}
|
||||
|
||||
if (has_cap(ACER_CAP_MAILLED)) {
|
||||
get_u32(&value, ACER_CAP_MAILLED);
|
||||
data->mailled = value;
|
||||
@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (has_cap(ACER_CAP_WIRELESS))
|
||||
set_u32(data->wireless, ACER_CAP_WIRELESS);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH))
|
||||
set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
|
||||
|
||||
if (has_cap(ACER_CAP_THREEG))
|
||||
set_u32(data->threeg, ACER_CAP_THREEG);
|
||||
|
||||
if (has_cap(ACER_CAP_MAILLED))
|
||||
set_u32(data->mailled, ACER_CAP_MAILLED);
|
||||
|
||||
@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
|
||||
|
||||
static int remove_sysfs(struct platform_device *device)
|
||||
{
|
||||
if (has_cap(ACER_CAP_WIRELESS))
|
||||
device_remove_file(&device->dev, &dev_attr_wireless);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH))
|
||||
device_remove_file(&device->dev, &dev_attr_bluetooth);
|
||||
|
||||
if (has_cap(ACER_CAP_THREEG))
|
||||
device_remove_file(&device->dev, &dev_attr_threeg);
|
||||
|
||||
@ -1133,20 +1202,6 @@ static int create_sysfs(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||
retval = device_create_file(&acer_platform_device->dev,
|
||||
&dev_attr_wireless);
|
||||
if (retval)
|
||||
goto error_sysfs;
|
||||
}
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
retval = device_create_file(&acer_platform_device->dev,
|
||||
&dev_attr_bluetooth);
|
||||
if (retval)
|
||||
goto error_sysfs;
|
||||
}
|
||||
|
||||
if (has_cap(ACER_CAP_THREEG)) {
|
||||
retval = device_create_file(&acer_platform_device->dev,
|
||||
&dev_attr_threeg);
|
||||
|
@ -139,6 +139,7 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
|
||||
"\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
|
||||
"\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
|
||||
"\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
|
||||
"\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
|
||||
"\\_SB.PCI0.PX40.Q10", /* S1x */
|
||||
"\\Q10"); /* A2x, L2D, L3D, M2E */
|
||||
|
||||
@ -280,7 +281,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
|
||||
|
||||
static int read_wireless_status(int mask)
|
||||
{
|
||||
ulong status;
|
||||
unsigned long long status;
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
if (!wireless_status_handle)
|
||||
@ -297,7 +298,7 @@ static int read_wireless_status(int mask)
|
||||
|
||||
static int read_gps_status(void)
|
||||
{
|
||||
ulong status;
|
||||
unsigned long long status;
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
|
||||
@ -350,7 +351,7 @@ static void write_status(acpi_handle handle, int out, int mask)
|
||||
static void object##_led_set(struct led_classdev *led_cdev, \
|
||||
enum led_brightness value) \
|
||||
{ \
|
||||
object##_led_wk = value; \
|
||||
object##_led_wk = (value > 0) ? 1 : 0; \
|
||||
queue_work(led_workqueue, &object##_led_work); \
|
||||
} \
|
||||
static void object##_led_update(struct work_struct *ignored) \
|
||||
@ -404,7 +405,7 @@ static void lcd_blank(int blank)
|
||||
|
||||
static int read_brightness(struct backlight_device *bd)
|
||||
{
|
||||
ulong value;
|
||||
unsigned long long value;
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
|
||||
@ -455,7 +456,7 @@ static ssize_t show_infos(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
int len = 0;
|
||||
ulong temp;
|
||||
unsigned long long temp;
|
||||
char buf[16]; //enough for all info
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
@ -603,7 +604,7 @@ static void set_display(int value)
|
||||
|
||||
static int read_display(void)
|
||||
{
|
||||
ulong value = 0;
|
||||
unsigned long long value = 0;
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
/* In most of the case, we know how to set the display, but sometime
|
||||
@ -849,7 +850,7 @@ static int asus_hotk_get_info(void)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *model = NULL;
|
||||
ulong bsts_result, hwrs_result;
|
||||
unsigned long long bsts_result, hwrs_result;
|
||||
char *string = NULL;
|
||||
acpi_status status;
|
||||
|
||||
@ -996,7 +997,7 @@ static int asus_hotk_add(struct acpi_device *device)
|
||||
hotk->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
|
||||
acpi_driver_data(device) = hotk;
|
||||
device->driver_data = hotk;
|
||||
hotk->device = device;
|
||||
|
||||
result = asus_hotk_check();
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
||||
#define EEEPC_LAPTOP_VERSION "0.1"
|
||||
|
||||
@ -125,6 +127,10 @@ struct eeepc_hotk {
|
||||
by this BIOS */
|
||||
uint init_flag; /* Init flags */
|
||||
u16 event_count[128]; /* count for each event */
|
||||
struct input_dev *inputdev;
|
||||
u16 *keycode_map;
|
||||
struct rfkill *eeepc_wlan_rfkill;
|
||||
struct rfkill *eeepc_bluetooth_rfkill;
|
||||
};
|
||||
|
||||
/* The actual device the driver binds to */
|
||||
@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
|
||||
|
||||
static struct platform_device *platform_device;
|
||||
|
||||
struct key_entry {
|
||||
char type;
|
||||
u8 code;
|
||||
u16 keycode;
|
||||
};
|
||||
|
||||
enum { KE_KEY, KE_END };
|
||||
|
||||
static struct key_entry eeepc_keymap[] = {
|
||||
/* Sleep already handled via generic ACPI code */
|
||||
{KE_KEY, 0x10, KEY_WLAN },
|
||||
{KE_KEY, 0x12, KEY_PROG1 },
|
||||
{KE_KEY, 0x13, KEY_MUTE },
|
||||
{KE_KEY, 0x14, KEY_VOLUMEDOWN },
|
||||
{KE_KEY, 0x15, KEY_VOLUMEUP },
|
||||
{KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
|
||||
{KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
|
||||
{KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
|
||||
{KE_END, 0},
|
||||
};
|
||||
|
||||
/*
|
||||
* The hotkey driver declaration
|
||||
*/
|
||||
@ -204,7 +231,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
|
||||
static int read_acpi_int(acpi_handle handle, const char *method, int *val)
|
||||
{
|
||||
acpi_status status;
|
||||
ulong result;
|
||||
unsigned long long result;
|
||||
|
||||
status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -260,6 +287,44 @@ static int update_bl_status(struct backlight_device *bd)
|
||||
return set_brightness(bd, bd->props.brightness);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rfkill helpers
|
||||
*/
|
||||
|
||||
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
||||
return set_acpi(CM_ASL_WLAN, 0);
|
||||
else
|
||||
return set_acpi(CM_ASL_WLAN, 1);
|
||||
}
|
||||
|
||||
static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
|
||||
{
|
||||
if (get_acpi(CM_ASL_WLAN) == 1)
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
||||
return set_acpi(CM_ASL_BLUETOOTH, 0);
|
||||
else
|
||||
return set_acpi(CM_ASL_BLUETOOTH, 1);
|
||||
}
|
||||
|
||||
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
|
||||
{
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sys helpers
|
||||
*/
|
||||
@ -311,13 +376,11 @@ static ssize_t show_sys_acpi(int cm, char *buf)
|
||||
EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
|
||||
EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
|
||||
EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
|
||||
EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
|
||||
|
||||
static struct attribute *platform_attributes[] = {
|
||||
&dev_attr_camera.attr,
|
||||
&dev_attr_cardr.attr,
|
||||
&dev_attr_disp.attr,
|
||||
&dev_attr_wlan.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -328,8 +391,64 @@ static struct attribute_group platform_attribute_group = {
|
||||
/*
|
||||
* Hotkey functions
|
||||
*/
|
||||
static struct key_entry *eepc_get_entry_by_scancode(int code)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
||||
for (key = eeepc_keymap; key->type != KE_END; key++)
|
||||
if (code == key->code)
|
||||
return key;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct key_entry *eepc_get_entry_by_keycode(int code)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
||||
for (key = eeepc_keymap; key->type != KE_END; key++)
|
||||
if (code == key->keycode && key->type == KE_KEY)
|
||||
return key;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
|
||||
{
|
||||
struct key_entry *key = eepc_get_entry_by_scancode(scancode);
|
||||
|
||||
if (key && key->type == KE_KEY) {
|
||||
*keycode = key->keycode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
|
||||
{
|
||||
struct key_entry *key;
|
||||
int old_keycode;
|
||||
|
||||
if (keycode < 0 || keycode > KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
key = eepc_get_entry_by_scancode(scancode);
|
||||
if (key && key->type == KE_KEY) {
|
||||
old_keycode = key->keycode;
|
||||
key->keycode = keycode;
|
||||
set_bit(keycode, dev->keybit);
|
||||
if (!eepc_get_entry_by_keycode(old_keycode))
|
||||
clear_bit(old_keycode, dev->keybit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_check(void)
|
||||
{
|
||||
const struct key_entry *key;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
int result;
|
||||
|
||||
@ -356,6 +475,31 @@ static int eeepc_hotk_check(void)
|
||||
"Get control methods supported: 0x%x\n",
|
||||
ehotk->cm_supported);
|
||||
}
|
||||
ehotk->inputdev = input_allocate_device();
|
||||
if (!ehotk->inputdev) {
|
||||
printk(EEEPC_INFO "Unable to allocate input device\n");
|
||||
return 0;
|
||||
}
|
||||
ehotk->inputdev->name = "Asus EeePC extra buttons";
|
||||
ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
|
||||
ehotk->inputdev->id.bustype = BUS_HOST;
|
||||
ehotk->inputdev->getkeycode = eeepc_getkeycode;
|
||||
ehotk->inputdev->setkeycode = eeepc_setkeycode;
|
||||
|
||||
for (key = eeepc_keymap; key->type != KE_END; key++) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
set_bit(EV_KEY, ehotk->inputdev->evbit);
|
||||
set_bit(key->keycode, ehotk->inputdev->keybit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = input_register_device(ehotk->inputdev);
|
||||
if (result) {
|
||||
printk(EEEPC_INFO "Unable to register input device\n");
|
||||
input_free_device(ehotk->inputdev);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
printk(EEEPC_ERR "Hotkey device not present, aborting\n");
|
||||
return -EINVAL;
|
||||
@ -363,21 +507,6 @@ static int eeepc_hotk_check(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void notify_wlan(u32 *event)
|
||||
{
|
||||
/* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
|
||||
will always be 0x10 */
|
||||
if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
|
||||
const char *method = cm_getv[CM_ASL_WLAN];
|
||||
int value;
|
||||
if (read_acpi_int(ehotk->handle, method, &value))
|
||||
printk(EEEPC_WARNING "Error reading %s\n",
|
||||
method);
|
||||
else if (value == 1)
|
||||
*event = 0x11;
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_brn(void)
|
||||
{
|
||||
struct backlight_device *bd = eeepc_backlight_device;
|
||||
@ -386,14 +515,28 @@ static void notify_brn(void)
|
||||
|
||||
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
static struct key_entry *key;
|
||||
if (!ehotk)
|
||||
return;
|
||||
if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
|
||||
notify_wlan(&event);
|
||||
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
|
||||
notify_brn();
|
||||
acpi_bus_generate_proc_event(ehotk->device, event,
|
||||
ehotk->event_count[event % 128]++);
|
||||
if (ehotk->inputdev) {
|
||||
key = eepc_get_entry_by_scancode(event);
|
||||
if (key) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
input_report_key(ehotk->inputdev, key->keycode,
|
||||
1);
|
||||
input_sync(ehotk->inputdev);
|
||||
input_report_key(ehotk->inputdev, key->keycode,
|
||||
0);
|
||||
input_sync(ehotk->inputdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int eeepc_hotk_add(struct acpi_device *device)
|
||||
@ -411,7 +554,7 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
ehotk->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
|
||||
acpi_driver_data(device) = ehotk;
|
||||
device->driver_data = ehotk;
|
||||
ehotk->device = device;
|
||||
result = eeepc_hotk_check();
|
||||
if (result)
|
||||
@ -420,6 +563,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
eeepc_hotk_notify, ehotk);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(EEEPC_ERR "Error installing notify handler\n");
|
||||
|
||||
if (get_acpi(CM_ASL_WLAN) != -1) {
|
||||
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
|
||||
RFKILL_TYPE_WLAN);
|
||||
|
||||
if (!ehotk->eeepc_wlan_rfkill)
|
||||
goto end;
|
||||
|
||||
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
|
||||
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
|
||||
ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
|
||||
if (get_acpi(CM_ASL_WLAN) == 1)
|
||||
ehotk->eeepc_wlan_rfkill->state =
|
||||
RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
ehotk->eeepc_wlan_rfkill->state =
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
rfkill_register(ehotk->eeepc_wlan_rfkill);
|
||||
}
|
||||
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
|
||||
ehotk->eeepc_bluetooth_rfkill =
|
||||
rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
|
||||
|
||||
if (!ehotk->eeepc_bluetooth_rfkill)
|
||||
goto end;
|
||||
|
||||
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
|
||||
ehotk->eeepc_bluetooth_rfkill->toggle_radio =
|
||||
eeepc_bluetooth_rfkill_set;
|
||||
ehotk->eeepc_bluetooth_rfkill->get_state =
|
||||
eeepc_bluetooth_rfkill_state;
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
|
||||
ehotk->eeepc_bluetooth_rfkill->state =
|
||||
RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
ehotk->eeepc_bluetooth_rfkill->state =
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
||||
}
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
kfree(ehotk);
|
||||
@ -553,6 +737,12 @@ static void eeepc_backlight_exit(void)
|
||||
{
|
||||
if (eeepc_backlight_device)
|
||||
backlight_device_unregister(eeepc_backlight_device);
|
||||
if (ehotk->inputdev)
|
||||
input_unregister_device(ehotk->inputdev);
|
||||
if (ehotk->eeepc_wlan_rfkill)
|
||||
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
|
||||
if (ehotk->eeepc_bluetooth_rfkill)
|
||||
rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
|
||||
eeepc_backlight_device = NULL;
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,9 @@
|
||||
* Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
|
||||
* also supported by this driver.
|
||||
*
|
||||
* This driver has been tested on a Fujitsu Lifebook S6410 and S7020. It
|
||||
* should work on most P-series and S-series Lifebooks, but YMMV.
|
||||
* This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
|
||||
* P8010. It should work on most P-series and S-series Lifebooks, but
|
||||
* YMMV.
|
||||
*
|
||||
* The module parameter use_alt_lcd_levels switches between different ACPI
|
||||
* brightness controls which are used by different Fujitsu laptops. In most
|
||||
@ -65,7 +66,7 @@
|
||||
#include <linux/video_output.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define FUJITSU_DRIVER_VERSION "0.4.2"
|
||||
#define FUJITSU_DRIVER_VERSION "0.4.3"
|
||||
|
||||
#define FUJITSU_LCD_N_LEVELS 8
|
||||
|
||||
@ -83,10 +84,10 @@
|
||||
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
|
||||
|
||||
/* Hotkey details */
|
||||
#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */
|
||||
#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */
|
||||
#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */
|
||||
#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */
|
||||
#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
|
||||
#define KEY2_CODE 0x411
|
||||
#define KEY3_CODE 0x412
|
||||
#define KEY4_CODE 0x413
|
||||
|
||||
#define MAX_HOTKEY_RINGBUFFER_SIZE 100
|
||||
#define RINGBUFFERSIZE 40
|
||||
@ -123,6 +124,7 @@ struct fujitsu_t {
|
||||
char phys[32];
|
||||
struct backlight_device *bl_device;
|
||||
struct platform_device *pf_device;
|
||||
int keycode1, keycode2, keycode3, keycode4;
|
||||
|
||||
unsigned int max_brightness;
|
||||
unsigned int brightness_changed;
|
||||
@ -224,7 +226,7 @@ static int set_lcd_level_alt(int level)
|
||||
|
||||
static int get_lcd_level(void)
|
||||
{
|
||||
unsigned long state = 0;
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
|
||||
@ -246,7 +248,7 @@ static int get_lcd_level(void)
|
||||
|
||||
static int get_max_brightness(void)
|
||||
{
|
||||
unsigned long state = 0;
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
|
||||
@ -263,7 +265,7 @@ static int get_max_brightness(void)
|
||||
|
||||
static int get_lcd_level_alt(void)
|
||||
{
|
||||
unsigned long state = 0;
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
|
||||
@ -384,7 +386,7 @@ static ssize_t store_lcd_level(struct device *dev,
|
||||
|
||||
static int get_irb(void)
|
||||
{
|
||||
unsigned long state = 0;
|
||||
unsigned long long state = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
|
||||
@ -430,7 +432,7 @@ static struct platform_driver fujitsupf_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int dmi_check_cb_s6410(const struct dmi_system_id *id)
|
||||
static void dmi_check_cb_common(const struct dmi_system_id *id)
|
||||
{
|
||||
acpi_handle handle;
|
||||
int have_blnf;
|
||||
@ -452,24 +454,40 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
|
||||
"auto-detecting disable_adjust\n");
|
||||
disable_brightness_adjust = have_blnf ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int dmi_check_cb_s6410(const struct dmi_system_id *id)
|
||||
{
|
||||
dmi_check_cb_common(id);
|
||||
fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
|
||||
fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmi_check_cb_p8010(const struct dmi_system_id *id)
|
||||
{
|
||||
dmi_check_cb_common(id);
|
||||
fujitsu->keycode1 = KEY_HELP; /* "Support" */
|
||||
fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
|
||||
fujitsu->keycode4 = KEY_WWW; /* "Internet" */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
|
||||
{
|
||||
.ident = "Fujitsu Siemens",
|
||||
.ident = "Fujitsu Siemens S6410",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
|
||||
},
|
||||
.callback = dmi_check_cb_s6410},
|
||||
{
|
||||
.ident = "FUJITSU LifeBook P8010",
|
||||
.ident = "Fujitsu LifeBook P8010",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
|
||||
},
|
||||
.callback = dmi_check_cb_s6410},
|
||||
},
|
||||
.callback = dmi_check_cb_p8010},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -490,7 +508,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
|
||||
fujitsu->acpi_handle = device->handle;
|
||||
sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
|
||||
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
|
||||
acpi_driver_data(device) = fujitsu;
|
||||
device->driver_data = fujitsu;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
@ -547,7 +565,6 @@ static int acpi_fujitsu_add(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/* do config (detect defaults) */
|
||||
dmi_check_system(fujitsu_dmi_table);
|
||||
use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
|
||||
disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
|
||||
disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
|
||||
@ -623,17 +640,17 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
|
||||
keycode = 0;
|
||||
if (disable_brightness_keys != 1) {
|
||||
if (oldb == 0) {
|
||||
acpi_bus_generate_proc_event(fujitsu->
|
||||
dev,
|
||||
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
|
||||
0);
|
||||
acpi_bus_generate_proc_event
|
||||
(fujitsu->dev,
|
||||
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
|
||||
0);
|
||||
keycode = KEY_BRIGHTNESSDOWN;
|
||||
} else if (oldb ==
|
||||
(fujitsu->max_brightness) - 1) {
|
||||
acpi_bus_generate_proc_event(fujitsu->
|
||||
dev,
|
||||
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
|
||||
0);
|
||||
acpi_bus_generate_proc_event
|
||||
(fujitsu->dev,
|
||||
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
|
||||
0);
|
||||
keycode = KEY_BRIGHTNESSUP;
|
||||
}
|
||||
}
|
||||
@ -646,8 +663,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
if (disable_brightness_keys != 1) {
|
||||
acpi_bus_generate_proc_event(fujitsu->dev,
|
||||
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
|
||||
0);
|
||||
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
|
||||
keycode = KEY_BRIGHTNESSUP;
|
||||
}
|
||||
} else if (oldb > newb) {
|
||||
@ -659,8 +675,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
if (disable_brightness_keys != 1) {
|
||||
acpi_bus_generate_proc_event(fujitsu->dev,
|
||||
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
|
||||
0);
|
||||
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
|
||||
keycode = KEY_BRIGHTNESSDOWN;
|
||||
}
|
||||
} else {
|
||||
@ -703,7 +718,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
|
||||
sprintf(acpi_device_name(device), "%s",
|
||||
ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
|
||||
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
|
||||
acpi_driver_data(device) = fujitsu_hotkey;
|
||||
device->driver_data = fujitsu_hotkey;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
@ -742,10 +757,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
|
||||
input->id.product = 0x06;
|
||||
input->dev.parent = &device->dev;
|
||||
input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_SCREENLOCK, input->keybit);
|
||||
set_bit(KEY_MEDIA, input->keybit);
|
||||
set_bit(KEY_EMAIL, input->keybit);
|
||||
set_bit(KEY_SUSPEND, input->keybit);
|
||||
set_bit(fujitsu->keycode1, input->keybit);
|
||||
set_bit(fujitsu->keycode2, input->keybit);
|
||||
set_bit(fujitsu->keycode3, input->keybit);
|
||||
set_bit(fujitsu->keycode4, input->keybit);
|
||||
set_bit(KEY_UNKNOWN, input->keybit);
|
||||
|
||||
error = input_register_device(input);
|
||||
@ -833,24 +848,24 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
|
||||
irb);
|
||||
|
||||
switch (irb & 0x4ff) {
|
||||
case LOCK_KEY:
|
||||
keycode = KEY_SCREENLOCK;
|
||||
case KEY1_CODE:
|
||||
keycode = fujitsu->keycode1;
|
||||
break;
|
||||
case DISPLAY_KEY:
|
||||
keycode = KEY_MEDIA;
|
||||
case KEY2_CODE:
|
||||
keycode = fujitsu->keycode2;
|
||||
break;
|
||||
case ENERGY_KEY:
|
||||
keycode = KEY_EMAIL;
|
||||
case KEY3_CODE:
|
||||
keycode = fujitsu->keycode3;
|
||||
break;
|
||||
case REST_KEY:
|
||||
keycode = KEY_SUSPEND;
|
||||
case KEY4_CODE:
|
||||
keycode = fujitsu->keycode4;
|
||||
break;
|
||||
case 0:
|
||||
keycode = 0;
|
||||
break;
|
||||
default:
|
||||
vdbg_printk(FUJLAPTOP_DBG_WARN,
|
||||
"Unknown GIRB result [%x]\n", irb);
|
||||
"Unknown GIRB result [%x]\n", irb);
|
||||
keycode = -1;
|
||||
break;
|
||||
}
|
||||
@ -859,12 +874,12 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
|
||||
"Push keycode into ringbuffer [%d]\n",
|
||||
keycode);
|
||||
status = kfifo_put(fujitsu_hotkey->fifo,
|
||||
(unsigned char *)&keycode,
|
||||
sizeof(keycode));
|
||||
(unsigned char *)&keycode,
|
||||
sizeof(keycode));
|
||||
if (status != sizeof(keycode)) {
|
||||
vdbg_printk(FUJLAPTOP_DBG_WARN,
|
||||
"Could not push keycode [0x%x]\n",
|
||||
keycode);
|
||||
"Could not push keycode [0x%x]\n",
|
||||
keycode);
|
||||
} else {
|
||||
input_report_key(input, keycode, 1);
|
||||
input_sync(input);
|
||||
@ -879,8 +894,8 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
|
||||
input_report_key(input, keycode_r, 0);
|
||||
input_sync(input);
|
||||
vdbg_printk(FUJLAPTOP_DBG_TRACE,
|
||||
"Pop keycode from ringbuffer [%d]\n",
|
||||
keycode_r);
|
||||
"Pop keycode from ringbuffer [%d]\n",
|
||||
keycode_r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -943,6 +958,11 @@ static int __init fujitsu_init(void)
|
||||
if (!fujitsu)
|
||||
return -ENOMEM;
|
||||
memset(fujitsu, 0, sizeof(struct fujitsu_t));
|
||||
fujitsu->keycode1 = KEY_PROG1;
|
||||
fujitsu->keycode2 = KEY_PROG2;
|
||||
fujitsu->keycode3 = KEY_PROG3;
|
||||
fujitsu->keycode4 = KEY_PROG4;
|
||||
dmi_check_system(fujitsu_dmi_table);
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_fujitsu_driver);
|
||||
if (result < 0) {
|
||||
@ -1076,15 +1096,14 @@ MODULE_DESCRIPTION("Fujitsu laptop extras support");
|
||||
MODULE_VERSION(FUJITSU_DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_ALIAS
|
||||
("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
|
||||
MODULE_ALIAS
|
||||
("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
|
||||
MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
|
||||
MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
|
||||
|
||||
static struct pnp_device_id pnp_ids[] = {
|
||||
{ .id = "FUJ02bf" },
|
||||
{ .id = "FUJ02B1" },
|
||||
{ .id = "FUJ02E3" },
|
||||
{ .id = "" }
|
||||
{.id = "FUJ02bf"},
|
||||
{.id = "FUJ02B1"},
|
||||
{.id = "FUJ02E3"},
|
||||
{.id = ""}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_ids);
|
||||
|
@ -57,7 +57,7 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
|
||||
{
|
||||
struct acpi_device *device = cdev->devdata;
|
||||
acpi_handle handle = device->handle;
|
||||
unsigned long value;
|
||||
unsigned long long value;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status = AE_OK;
|
||||
@ -90,7 +90,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
|
||||
{
|
||||
struct acpi_device *device = cdev->devdata;
|
||||
acpi_handle handle = device->handle;
|
||||
unsigned long value;
|
||||
unsigned long long value;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status = AE_OK;
|
||||
@ -104,7 +104,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EFAULT;
|
||||
|
||||
return sprintf(buf, "%ld\n", value);
|
||||
return sprintf(buf, "%llu\n", value);
|
||||
}
|
||||
|
||||
static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
|
||||
@ -115,7 +115,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status;
|
||||
int temp;
|
||||
unsigned long long temp;
|
||||
unsigned long max_state;
|
||||
|
||||
if (memory_get_int_max_bandwidth(cdev, &max_state))
|
||||
@ -131,7 +131,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
|
||||
(unsigned long *)&temp);
|
||||
&temp);
|
||||
|
||||
printk(KERN_INFO
|
||||
"Bandwidth value was %d: status is %d\n", state, status);
|
||||
@ -175,7 +175,7 @@ static int intel_menlow_memory_add(struct acpi_device *device)
|
||||
goto end;
|
||||
}
|
||||
|
||||
acpi_driver_data(device) = cdev;
|
||||
device->driver_data = cdev;
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
&cdev->device.kobj, "thermal_cooling");
|
||||
if (result)
|
||||
@ -252,7 +252,8 @@ static DEFINE_MUTEX(intel_menlow_attr_lock);
|
||||
* @auxtype : AUX0/AUX1
|
||||
* @buf: syfs buffer
|
||||
*/
|
||||
static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
|
||||
static int sensor_get_auxtrip(acpi_handle handle, int index,
|
||||
unsigned long long *value)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
@ -260,7 +261,7 @@ static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
|
||||
NULL, (unsigned long *)value);
|
||||
NULL, value);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
@ -282,13 +283,13 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
|
||||
struct acpi_object_list args = {
|
||||
1, &arg
|
||||
};
|
||||
int temp;
|
||||
unsigned long long temp;
|
||||
|
||||
if (index != 0 && index != 1)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
|
||||
NULL, (unsigned long *)&temp);
|
||||
NULL, &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
if ((index && value < temp) || (!index && value > temp))
|
||||
@ -296,7 +297,7 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
|
||||
|
||||
arg.integer.value = value;
|
||||
status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
|
||||
&args, (unsigned long *)&temp);
|
||||
&args, &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
@ -312,7 +313,7 @@ static ssize_t aux0_show(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
|
||||
int value;
|
||||
unsigned long long value;
|
||||
int result;
|
||||
|
||||
result = sensor_get_auxtrip(attr->handle, 0, &value);
|
||||
@ -324,7 +325,7 @@ static ssize_t aux1_show(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
|
||||
int value;
|
||||
unsigned long long value;
|
||||
int result;
|
||||
|
||||
result = sensor_get_auxtrip(attr->handle, 1, &value);
|
||||
@ -376,7 +377,7 @@ static ssize_t bios_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
acpi_status status;
|
||||
unsigned long bios_enabled;
|
||||
unsigned long long bios_enabled;
|
||||
|
||||
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
|
||||
if (ACPI_FAILURE(status))
|
||||
@ -492,7 +493,7 @@ static int __init intel_menlow_module_init(void)
|
||||
{
|
||||
int result = -ENODEV;
|
||||
acpi_status status;
|
||||
unsigned long enable;
|
||||
unsigned long long enable;
|
||||
|
||||
if (acpi_disabled)
|
||||
return result;
|
||||
|
767
drivers/misc/panasonic-laptop.c
Normal file
767
drivers/misc/panasonic-laptop.c
Normal file
@ -0,0 +1,767 @@
|
||||
/*
|
||||
* Panasonic HotKey and LCD brightness control driver
|
||||
* (C) 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
|
||||
* (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
|
||||
* (C) 2004 David Bronaugh <dbronaugh>
|
||||
* (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
|
||||
*
|
||||
* 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
|
||||
* publicshed by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* ChangeLog:
|
||||
* Sep.23, 2008 Harald Welte <laforge@gnumonks.org>
|
||||
* -v0.95 rename driver from drivers/acpi/pcc_acpi.c to
|
||||
* drivers/misc/panasonic-laptop.c
|
||||
*
|
||||
* Jul.04, 2008 Harald Welte <laforge@gnumonks.org>
|
||||
* -v0.94 replace /proc interface with device attributes
|
||||
* support {set,get}keycode on th input device
|
||||
*
|
||||
* Jun.27, 2008 Harald Welte <laforge@gnumonks.org>
|
||||
* -v0.92 merge with 2.6.26-rc6 input API changes
|
||||
* remove broken <= 2.6.15 kernel support
|
||||
* resolve all compiler warnings
|
||||
* various coding style fixes (checkpatch.pl)
|
||||
* add support for backlight api
|
||||
* major code restructuring
|
||||
*
|
||||
* Dac.28, 2007 Harald Welte <laforge@gnumonks.org>
|
||||
* -v0.91 merge with 2.6.24-rc6 ACPI changes
|
||||
*
|
||||
* Nov.04, 2006 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.9 remove warning about section reference.
|
||||
* remove acpi_os_free
|
||||
* add /proc/acpi/pcc/brightness interface for HAL access
|
||||
* merge dbronaugh's enhancement
|
||||
* Aug.17, 2004 David Bronaugh (dbronaugh)
|
||||
* - Added screen brightness setting interface
|
||||
* Thanks to FreeBSD crew (acpi_panasonic.c)
|
||||
* for the ideas I needed to accomplish it
|
||||
*
|
||||
* May.29, 2006 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.8.4 follow to change keyinput structure
|
||||
* thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
|
||||
* Jacob Bower <jacob.bower@ic.ac.uk> and
|
||||
* Hiroshi Yokota for providing solutions.
|
||||
*
|
||||
* Oct.02, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.8.2 merge code of YOKOTA Hiroshi
|
||||
* <yokota@netlab.is.tsukuba.ac.jp>.
|
||||
* Add sticky key mode interface.
|
||||
* Refactoring acpi_pcc_generate_keyinput().
|
||||
*
|
||||
* Sep.15, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.8 Generate key input event on input subsystem.
|
||||
* This is based on yet another driver written by
|
||||
* Ryuta Nakanishi.
|
||||
*
|
||||
* Sep.10, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.7 Change proc interface functions using seq_file
|
||||
* facility as same as other ACPI drivers.
|
||||
*
|
||||
* Aug.28, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.6.4 Fix a silly error with status checking
|
||||
*
|
||||
* Aug.25, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* -v0.6.3 replace read_acpi_int by standard function
|
||||
* acpi_evaluate_integer
|
||||
* some clean up and make smart copyright notice.
|
||||
* fix return value of pcc_acpi_get_key()
|
||||
* fix checking return value of acpi_bus_register_driver()
|
||||
*
|
||||
* Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
|
||||
* -v0.6.2 Add check on ACPI data (num_sifr)
|
||||
* Coding style cleanups, better error messages/handling
|
||||
* Fixed an off-by-one error in memory allocation
|
||||
*
|
||||
* Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
|
||||
* -v0.6.1 Fix a silly error with status checking
|
||||
*
|
||||
* Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
|
||||
* - v0.6 Correct brightness controls to reflect reality
|
||||
* based on information gleaned by Hiroshi Miura
|
||||
* and discussions with Hiroshi Miura
|
||||
*
|
||||
* Aug.10, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* - v0.5 support LCD brightness control
|
||||
* based on the disclosed information by MEI.
|
||||
*
|
||||
* Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* - v0.4 first post version
|
||||
* add function to retrive SIFR
|
||||
*
|
||||
* Jul.24, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* - v0.3 get proper status of hotkey
|
||||
*
|
||||
* Jul.22, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* - v0.2 add HotKey handler
|
||||
*
|
||||
* Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
|
||||
* - v0.1 start from toshiba_acpi driver written by John Belmonte
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
|
||||
#ifndef ACPI_HOTKEY_COMPONENT
|
||||
#define ACPI_HOTKEY_COMPONENT 0x10000000
|
||||
#endif
|
||||
|
||||
#define _COMPONENT ACPI_HOTKEY_COMPONENT
|
||||
|
||||
MODULE_AUTHOR("Hiroshi Miura, David Bronaugh and Harald Welte");
|
||||
MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define LOGPREFIX "pcc_acpi: "
|
||||
|
||||
/* Define ACPI PATHs */
|
||||
/* Lets note hotkeys */
|
||||
#define METHOD_HKEY_QUERY "HINF"
|
||||
#define METHOD_HKEY_SQTY "SQTY"
|
||||
#define METHOD_HKEY_SINF "SINF"
|
||||
#define METHOD_HKEY_SSET "SSET"
|
||||
#define HKEY_NOTIFY 0x80
|
||||
|
||||
#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
|
||||
#define ACPI_PCC_DEVICE_NAME "Hotkey"
|
||||
#define ACPI_PCC_CLASS "pcc"
|
||||
|
||||
#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
|
||||
|
||||
/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
|
||||
ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
|
||||
*/
|
||||
enum SINF_BITS { SINF_NUM_BATTERIES = 0,
|
||||
SINF_LCD_TYPE,
|
||||
SINF_AC_MAX_BRIGHT,
|
||||
SINF_AC_MIN_BRIGHT,
|
||||
SINF_AC_CUR_BRIGHT,
|
||||
SINF_DC_MAX_BRIGHT,
|
||||
SINF_DC_MIN_BRIGHT,
|
||||
SINF_DC_CUR_BRIGHT,
|
||||
SINF_MUTE,
|
||||
SINF_RESERVED,
|
||||
SINF_ENV_STATE,
|
||||
SINF_STICKY_KEY = 0x80,
|
||||
};
|
||||
/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
|
||||
|
||||
static int acpi_pcc_hotkey_add(struct acpi_device *device);
|
||||
static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
|
||||
static int acpi_pcc_hotkey_resume(struct acpi_device *device);
|
||||
|
||||
static const struct acpi_device_id pcc_device_ids[] = {
|
||||
{ "MAT0012", 0},
|
||||
{ "MAT0013", 0},
|
||||
{ "MAT0018", 0},
|
||||
{ "MAT0019", 0},
|
||||
{ "", 0},
|
||||
};
|
||||
|
||||
static struct acpi_driver acpi_pcc_driver = {
|
||||
.name = ACPI_PCC_DRIVER_NAME,
|
||||
.class = ACPI_PCC_CLASS,
|
||||
.ids = pcc_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_pcc_hotkey_add,
|
||||
.remove = acpi_pcc_hotkey_remove,
|
||||
.resume = acpi_pcc_hotkey_resume,
|
||||
},
|
||||
};
|
||||
|
||||
#define KEYMAP_SIZE 11
|
||||
static const int initial_keymap[KEYMAP_SIZE] = {
|
||||
/* 0 */ KEY_RESERVED,
|
||||
/* 1 */ KEY_BRIGHTNESSDOWN,
|
||||
/* 2 */ KEY_BRIGHTNESSUP,
|
||||
/* 3 */ KEY_DISPLAYTOGGLE,
|
||||
/* 4 */ KEY_MUTE,
|
||||
/* 5 */ KEY_VOLUMEDOWN,
|
||||
/* 6 */ KEY_VOLUMEUP,
|
||||
/* 7 */ KEY_SLEEP,
|
||||
/* 8 */ KEY_PROG1, /* Change CPU boost */
|
||||
/* 9 */ KEY_BATTERY,
|
||||
/* 10 */ KEY_SUSPEND,
|
||||
};
|
||||
|
||||
struct pcc_acpi {
|
||||
acpi_handle handle;
|
||||
unsigned long num_sifr;
|
||||
int sticky_mode;
|
||||
u32 *sinf;
|
||||
struct acpi_device *device;
|
||||
struct input_dev *input_dev;
|
||||
struct backlight_device *backlight;
|
||||
int keymap[KEYMAP_SIZE];
|
||||
};
|
||||
|
||||
struct pcc_keyinput {
|
||||
struct acpi_hotkey *hotkey;
|
||||
};
|
||||
|
||||
/* method access functions */
|
||||
static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
|
||||
{
|
||||
union acpi_object in_objs[] = {
|
||||
{ .integer.type = ACPI_TYPE_INTEGER,
|
||||
.integer.value = func, },
|
||||
{ .integer.type = ACPI_TYPE_INTEGER,
|
||||
.integer.value = val, },
|
||||
};
|
||||
struct acpi_object_list params = {
|
||||
.count = ARRAY_SIZE(in_objs),
|
||||
.pointer = in_objs,
|
||||
};
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
|
||||
|
||||
status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
|
||||
¶ms, NULL);
|
||||
|
||||
return status == AE_OK;
|
||||
}
|
||||
|
||||
static inline int acpi_pcc_get_sqty(struct acpi_device *device)
|
||||
{
|
||||
unsigned long long s;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty");
|
||||
|
||||
status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
|
||||
NULL, &s);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return s;
|
||||
else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"evaluation error HKEY.SQTY\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
union acpi_object *hkey = NULL;
|
||||
int i;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata");
|
||||
|
||||
status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0,
|
||||
&buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"evaluation error HKEY.SINF\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hkey = buffer.pointer;
|
||||
if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pcc->num_sifr < hkey->package.count) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"SQTY reports bad SINF length\n"));
|
||||
status = AE_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < hkey->package.count; i++) {
|
||||
union acpi_object *element = &(hkey->package.elements[i]);
|
||||
if (likely(element->type == ACPI_TYPE_INTEGER)) {
|
||||
sinf[i] = element->integer.value;
|
||||
} else
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Invalid HKEY.SINF data\n"));
|
||||
}
|
||||
sinf[hkey->package.count] = -1;
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
return status == AE_OK;
|
||||
}
|
||||
|
||||
/* backlight API interface functions */
|
||||
|
||||
/* This driver currently treats AC and DC brightness identical,
|
||||
* since we don't need to invent an interface to the core ACPI
|
||||
* logic to receive events in case a power supply is plugged in
|
||||
* or removed */
|
||||
|
||||
static int bl_get(struct backlight_device *bd)
|
||||
{
|
||||
struct pcc_acpi *pcc = bl_get_data(bd);
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
return pcc->sinf[SINF_AC_CUR_BRIGHT];
|
||||
}
|
||||
|
||||
static int bl_set_status(struct backlight_device *bd)
|
||||
{
|
||||
struct pcc_acpi *pcc = bl_get_data(bd);
|
||||
int bright = bd->props.brightness;
|
||||
int rc;
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
|
||||
bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
|
||||
|
||||
if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
|
||||
bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
|
||||
|
||||
if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
|
||||
bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
|
||||
return -EINVAL;
|
||||
|
||||
rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
|
||||
}
|
||||
|
||||
static struct backlight_ops pcc_backlight_ops = {
|
||||
.get_brightness = bl_get,
|
||||
.update_status = bl_set_status,
|
||||
};
|
||||
|
||||
|
||||
/* sysfs user interface functions */
|
||||
|
||||
static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct acpi_device *acpi = to_acpi_device(dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(acpi);
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
|
||||
}
|
||||
|
||||
static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct acpi_device *acpi = to_acpi_device(dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(acpi);
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
|
||||
}
|
||||
|
||||
static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct acpi_device *acpi = to_acpi_device(dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(acpi);
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%u\n", pcc->sinf[SINF_MUTE]);
|
||||
}
|
||||
|
||||
static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct acpi_device *acpi = to_acpi_device(dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(acpi);
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
|
||||
}
|
||||
|
||||
static ssize_t set_sticky(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct acpi_device *acpi = to_acpi_device(dev);
|
||||
struct pcc_acpi *pcc = acpi_driver_data(acpi);
|
||||
int val;
|
||||
|
||||
if (count && sscanf(buf, "%i", &val) == 1 &&
|
||||
(val == 0 || val == 1)) {
|
||||
acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
|
||||
pcc->sticky_mode = val;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL);
|
||||
static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL);
|
||||
static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL);
|
||||
static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky);
|
||||
|
||||
static struct attribute *pcc_sysfs_entries[] = {
|
||||
&dev_attr_numbatt.attr,
|
||||
&dev_attr_lcdtype.attr,
|
||||
&dev_attr_mute.attr,
|
||||
&dev_attr_sticky_key.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group pcc_attr_group = {
|
||||
.name = NULL, /* put in device directory */
|
||||
.attrs = pcc_sysfs_entries,
|
||||
};
|
||||
|
||||
|
||||
/* hotkey input device driver */
|
||||
|
||||
static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
|
||||
{
|
||||
struct pcc_acpi *pcc = input_get_drvdata(dev);
|
||||
|
||||
if (scancode >= ARRAY_SIZE(pcc->keymap))
|
||||
return -EINVAL;
|
||||
|
||||
*keycode = pcc->keymap[scancode];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
|
||||
if (pcc->keymap[i] == keycode)
|
||||
return i+1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
|
||||
{
|
||||
struct pcc_acpi *pcc = input_get_drvdata(dev);
|
||||
int oldkeycode;
|
||||
|
||||
if (scancode >= ARRAY_SIZE(pcc->keymap))
|
||||
return -EINVAL;
|
||||
|
||||
if (keycode < 0 || keycode > KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
oldkeycode = pcc->keymap[scancode];
|
||||
pcc->keymap[scancode] = keycode;
|
||||
|
||||
set_bit(keycode, dev->keybit);
|
||||
|
||||
if (!keymap_get_by_keycode(pcc, oldkeycode))
|
||||
clear_bit(oldkeycode, dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
|
||||
{
|
||||
struct input_dev *hotk_input_dev = pcc->input_dev;
|
||||
int rc;
|
||||
int key_code, hkey_num;
|
||||
unsigned long long result;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput");
|
||||
|
||||
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
|
||||
NULL, &result);
|
||||
if (!ACPI_SUCCESS(rc)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"error getting hotkey status\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
|
||||
|
||||
hkey_num = result & 0xf;
|
||||
|
||||
if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"hotkey number out of range: %d\n",
|
||||
hkey_num));
|
||||
return;
|
||||
}
|
||||
|
||||
key_code = pcc->keymap[hkey_num];
|
||||
|
||||
if (key_code != KEY_RESERVED) {
|
||||
int pushed = (result & 0x80) ? TRUE : FALSE;
|
||||
|
||||
input_report_key(hotk_input_dev, key_code, pushed);
|
||||
input_sync(hotk_input_dev);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct pcc_acpi *pcc = (struct pcc_acpi *) data;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
|
||||
|
||||
switch (event) {
|
||||
case HKEY_NOTIFY:
|
||||
acpi_pcc_generate_keyinput(pcc);
|
||||
break;
|
||||
default:
|
||||
/* nothing to do */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_pcc_init_input(struct pcc_acpi *pcc)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
|
||||
|
||||
pcc->input_dev = input_allocate_device();
|
||||
if (!pcc->input_dev) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Couldn't allocate input device for hotkey"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pcc->input_dev->evbit[0] = BIT(EV_KEY);
|
||||
|
||||
pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
|
||||
pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
|
||||
pcc->input_dev->id.bustype = BUS_HOST;
|
||||
pcc->input_dev->id.vendor = 0x0001;
|
||||
pcc->input_dev->id.product = 0x0001;
|
||||
pcc->input_dev->id.version = 0x0100;
|
||||
pcc->input_dev->getkeycode = pcc_getkeycode;
|
||||
pcc->input_dev->setkeycode = pcc_setkeycode;
|
||||
|
||||
/* load initial keymap */
|
||||
memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
|
||||
__set_bit(pcc->keymap[i], pcc->input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
|
||||
|
||||
input_set_drvdata(pcc->input_dev, pcc);
|
||||
|
||||
rc = input_register_device(pcc->input_dev);
|
||||
if (rc < 0)
|
||||
input_free_device(pcc->input_dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* kernel module interface */
|
||||
|
||||
static int acpi_pcc_hotkey_resume(struct acpi_device *device)
|
||||
{
|
||||
struct pcc_acpi *pcc = acpi_driver_data(device);
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
|
||||
|
||||
if (device == NULL || pcc == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
|
||||
pcc->sticky_mode));
|
||||
|
||||
status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
|
||||
|
||||
return status == AE_OK ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
struct pcc_acpi *pcc;
|
||||
int num_sifr, result;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
num_sifr = acpi_pcc_get_sqty(device);
|
||||
|
||||
if (num_sifr > 255) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
|
||||
if (!pcc) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Couldn't allocate mem for pcc"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL);
|
||||
if (!pcc->sinf) {
|
||||
result = -ENOMEM;
|
||||
goto out_hotkey;
|
||||
}
|
||||
|
||||
pcc->device = device;
|
||||
pcc->handle = device->handle;
|
||||
pcc->num_sifr = num_sifr;
|
||||
device->driver_data = pcc;
|
||||
strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
|
||||
|
||||
result = acpi_pcc_init_input(pcc);
|
||||
if (result) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing keyinput handler\n"));
|
||||
goto out_sinf;
|
||||
}
|
||||
|
||||
/* initialize hotkey input device */
|
||||
status = acpi_install_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify, pcc);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing notify handler\n"));
|
||||
result = -ENODEV;
|
||||
goto out_input;
|
||||
}
|
||||
|
||||
/* initialize backlight */
|
||||
pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
|
||||
&pcc_backlight_ops);
|
||||
if (IS_ERR(pcc->backlight))
|
||||
goto out_notify;
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Couldn't retrieve BIOS data\n"));
|
||||
goto out_backlight;
|
||||
}
|
||||
|
||||
/* read the initial brightness setting from the hardware */
|
||||
pcc->backlight->props.max_brightness =
|
||||
pcc->sinf[SINF_AC_MAX_BRIGHT];
|
||||
pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
|
||||
|
||||
/* read the initial sticky key mode from the hardware */
|
||||
pcc->sticky_mode = pcc->sinf[SINF_STICKY_KEY];
|
||||
|
||||
/* add sysfs attributes */
|
||||
result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
|
||||
if (result)
|
||||
goto out_backlight;
|
||||
|
||||
return 0;
|
||||
|
||||
out_backlight:
|
||||
backlight_device_unregister(pcc->backlight);
|
||||
out_notify:
|
||||
acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify);
|
||||
out_input:
|
||||
input_unregister_device(pcc->input_dev);
|
||||
/* no need to input_free_device() since core input API refcount and
|
||||
* free()s the device */
|
||||
out_sinf:
|
||||
kfree(pcc->sinf);
|
||||
out_hotkey:
|
||||
kfree(pcc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int __init acpi_pcc_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_init");
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_pcc_driver);
|
||||
if (result < 0) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error registering hotkey driver\n"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct pcc_acpi *pcc = acpi_driver_data(device);
|
||||
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
|
||||
|
||||
if (!device || !pcc)
|
||||
return -EINVAL;
|
||||
|
||||
sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
|
||||
|
||||
backlight_device_unregister(pcc->backlight);
|
||||
|
||||
acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_pcc_hotkey_notify);
|
||||
|
||||
input_unregister_device(pcc->input_dev);
|
||||
/* no need to input_free_device() since core input API refcount and
|
||||
* free()s the device */
|
||||
|
||||
kfree(pcc->sinf);
|
||||
kfree(pcc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_pcc_exit(void)
|
||||
{
|
||||
ACPI_FUNCTION_TRACE("acpi_pcc_exit");
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_pcc_driver);
|
||||
}
|
||||
|
||||
module_init(acpi_pcc_init);
|
||||
module_exit(acpi_pcc_exit);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user