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:
Linus Torvalds 2008-10-23 10:20:36 -07:00
commit 765426e8ee
145 changed files with 5929 additions and 2224 deletions

View File

@ -218,20 +218,47 @@ and is between 256 and 4096 characters. It is defined in the file
acpi.debug_level= [HW,ACPI] acpi.debug_level= [HW,ACPI]
Format: <int> Format: <int>
Each bit of the <int> indicates an ACPI debug level, Each bit of the <int> indicates an ACPI debug level,
1: enable, 0: disable. It is useful for boot time which corresponds to the level in an ACPI_DEBUG_PRINT
debugging. After system has booted up, it can be set statement. After system has booted up, this mask
via /sys/module/acpi/parameters/debug_level. 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 CONFIG_ACPI_DEBUG must be enabled for this to produce
debug output levels of the ACPI subsystem: any output. The number can be in decimal or prefixed
0x01 error 0x02 warn 0x04 init 0x08 debug object with 0x in hex. Some of these options produce so much
0x10 info 0x20 init names 0x40 parse 0x80 load output that the system is unusable.
0x100 dispatch 0x200 execute 0x400 names 0x800 operation region
0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects The following global components are defined by the
0x10000 resources 0x20000 user requests 0x40000 package. ACPI CA:
The number can be in decimal or prefixed with 0x in hex. 0x01 error
Warning: Many of these options can produce a lot of 0x02 warn
output and make your system unusable. Be very careful. 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] acpi_pm_good [X86-32,X86-64]
Override the pmtimer bug detection: force the kernel 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. Override pmtimer IOPort with a hex value.
e.g. pmtmr=0x508 e.g. pmtmr=0x508
pnp.debug [PNP]
Enable PNP debug messages. This depends on the
CONFIG_PNP_DEBUG_MESSAGES option.
pnpacpi= [ACPI] pnpacpi= [ACPI]
{ off } { off }
@ -2208,7 +2239,7 @@ and is between 256 and 4096 characters. It is defined in the file
thermal.crt= [HW,ACPI] thermal.crt= [HW,ACPI]
-1: disable all critical trip points in all thermal zones -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] thermal.nocrt= [HW,ACPI]
Set to disable actions on ACPI thermal zone Set to disable actions on ACPI thermal zone

View File

@ -1,7 +1,7 @@
Acer Laptop WMI Extras Driver Acer Laptop WMI Extras Driver
http://code.google.com/p/aceracpi http://code.google.com/p/aceracpi
Version 0.1 Version 0.2
9th February 2008 18th August 2008
Copyright 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk> 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 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. 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): The wireless radio is exposed through rfkill.
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)
Bluetooth 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 module off the internet that is compatible with your laptop and fit it, then
it will work just fine with acer-wmi. it will work just fine with acer-wmi.
To read the status of the bluetooth module (0=off, 1=on): Bluetooth is exposed through rfkill.
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)
3G 3G
** **

View File

@ -1433,8 +1433,8 @@ M: rdunlap@xenotime.net
S: Maintained S: Maintained
DOCKING STATION DRIVER DOCKING STATION DRIVER
P: Kristen Carlson Accardi P: Shaohua Li
M: kristen.c.accardi@intel.com M: shaohua.li@intel.com
L: linux-acpi@vger.kernel.org L: linux-acpi@vger.kernel.org
S: Supported S: Supported
@ -2109,6 +2109,12 @@ L: linux-ide@vger.kernel.org
L: linux-scsi@vger.kernel.org L: linux-scsi@vger.kernel.org
S: Orphan 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) IEEE 1394 SUBSYSTEM (drivers/ieee1394)
P: Ben Collins P: Ben Collins
M: ben.collins@ubuntu.com M: ben.collins@ubuntu.com
@ -3186,6 +3192,11 @@ M: olof@lixom.net
L: i2c@lm-sensors.org L: i2c@lm-sensors.org
S: Maintained S: Maintained
PANASONIC LAPTOP ACPI EXTRAS DRIVER
P: Harald Welte
M: laforge@gnumonks.org
S: Maintained
PANASONIC MN10300/AM33 PORT PANASONIC MN10300/AM33 PORT
P: David Howells P: David Howells
M: dhowells@redhat.com M: dhowells@redhat.com

View File

@ -232,7 +232,7 @@ exit:
static unsigned int static unsigned int
get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
{ {
unsigned long adr; unsigned long long adr;
acpi_handle child; acpi_handle child;
unsigned int devfn; unsigned int devfn;
int function; int function;
@ -292,8 +292,8 @@ get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
static acpi_status static acpi_status
find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
unsigned long bbn = -1; unsigned long long bbn = -1;
unsigned long adr; unsigned long long adr;
acpi_handle parent = NULL; acpi_handle parent = NULL;
acpi_status status; acpi_status status;
unsigned int devfn; 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; unsigned int host_devfn;
struct sn_pcidev_match pcidev_match; struct sn_pcidev_match pcidev_match;
acpi_handle rootbus_handle; acpi_handle rootbus_handle;
unsigned long segment; unsigned long long segment;
acpi_status status; acpi_status status;
rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle; 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 (ACPI_SUCCESS(status)) {
if (segment != pci_domain_nr(dev)) { if (segment != pci_domain_nr(dev)) {
printk(KERN_ERR 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)); __func__, segment, pci_domain_nr(dev));
acpi_ns_print_node_pathname(rootbus_handle, NULL); acpi_ns_print_node_pathname(rootbus_handle, NULL);
printk("\n"); printk("\n");

View File

@ -116,6 +116,9 @@ config GENERIC_TIME_VSYSCALL
config ARCH_HAS_CPU_RELAX config ARCH_HAS_CPU_RELAX
def_bool y def_bool y
config ARCH_HAS_DEFAULT_IDLE
def_bool y
config ARCH_HAS_CACHE_LINE_SIZE config ARCH_HAS_CACHE_LINE_SIZE
def_bool y def_bool y
@ -1635,6 +1638,8 @@ source "arch/x86/kernel/cpu/cpufreq/Kconfig"
source "drivers/cpuidle/Kconfig" source "drivers/cpuidle/Kconfig"
source "drivers/idle/Kconfig"
endmenu endmenu

View File

@ -153,12 +153,13 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size)
} }
#ifdef CONFIG_PCI_MMCONFIG #ifdef CONFIG_PCI_MMCONFIG
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config; struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num; 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) static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
{ {
if (!strcmp(mcfg->header.oem_id, "SGI")) if (!strcmp(mcfg->header.oem_id, "SGI"))

View File

@ -22,7 +22,7 @@ unsigned long acpi_realmode_flags;
static unsigned long acpi_realmode; static unsigned long acpi_realmode;
#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) #if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
static char temp_stack[10240]; static char temp_stack[4096];
#endif #endif
/** /**
@ -98,7 +98,7 @@ int acpi_save_state_mem(void)
#else /* CONFIG_64BIT */ #else /* CONFIG_64BIT */
header->trampoline_segment = setup_trampoline() >> 4; header->trampoline_segment = setup_trampoline() >> 4;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
stack_start.sp = temp_stack + 4096; stack_start.sp = temp_stack + sizeof(temp_stack);
early_gdt_descr.address = early_gdt_descr.address =
(unsigned long)get_cpu_gdt_table(smp_processor_id()); (unsigned long)get_cpu_gdt_table(smp_processor_id());
#endif #endif

View File

@ -780,6 +780,9 @@ static int __init acpi_cpufreq_init(void)
{ {
int ret; int ret;
if (acpi_disabled)
return 0;
dprintk("acpi_cpufreq_init\n"); dprintk("acpi_cpufreq_init\n");
ret = acpi_cpufreq_early_init(); ret = acpi_cpufreq_early_init();

View File

@ -45,7 +45,6 @@
#endif #endif
#define PFX "powernow-k8: " #define PFX "powernow-k8: "
#define BFX PFX "BIOS error: "
#define VERSION "version 2.20.00" #define VERSION "version 2.20.00"
#include "powernow-k8.h" #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++) { for (j = 0; j < data->numps; j++) {
if (pst[j].vid > LEAST_VID) { 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; return -EINVAL;
} }
if (pst[j].vid < data->rvo) { /* vid + rvo >= 0 */ 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; return -ENODEV;
} }
if (pst[j].vid < maxvid + data->rvo) { /* vid + rvo >= maxvid */ 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; return -ENODEV;
} }
if (pst[j].fid > MAX_FID) { 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; return -ENODEV;
} }
if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) { if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
/* Only first fid is allowed to be in "low" range */ /* 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; return -EINVAL;
} }
if (pst[j].fid < lastfid) if (pst[j].fid < lastfid)
lastfid = pst[j].fid; lastfid = pst[j].fid;
} }
if (lastfid & 1) { if (lastfid & 1) {
printk(KERN_ERR BFX "lastfid invalid\n"); printk(KERN_ERR FW_BUG PFX "lastfid invalid\n");
return -EINVAL; return -EINVAL;
} }
if (lastfid > LO_FID_TABLE_TOP) 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; return 0;
} }
@ -672,13 +676,13 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("table vers: 0x%x\n", psb->tableversion); dprintk("table vers: 0x%x\n", psb->tableversion);
if (psb->tableversion != PSB_VERSION_1_4) { 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; return -ENODEV;
} }
dprintk("flags: 0x%x\n", psb->flags1); dprintk("flags: 0x%x\n", psb->flags1);
if (psb->flags1) { if (psb->flags1) {
printk(KERN_ERR BFX "unknown flags\n"); printk(KERN_ERR FW_BUG PFX "unknown flags\n");
return -ENODEV; return -ENODEV;
} }
@ -705,7 +709,7 @@ static int find_psb_table(struct powernow_k8_data *data)
} }
} }
if (cpst != 1) { 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; return -ENODEV;
} }
@ -1130,17 +1134,19 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
"ACPI Processor module before starting this " "ACPI Processor module before starting this "
"driver.\n"); "driver.\n");
#else #else
printk(KERN_ERR PFX "Your BIOS does not provide ACPI " printk(KERN_ERR FW_BUG PFX "Your BIOS does not provide"
"_PSS objects in a way that Linux understands. " " ACPI _PSS objects in a way that Linux "
"Please report this to the Linux ACPI maintainers" "understands. Please report this to the Linux "
" and complain to your BIOS vendor.\n"); "ACPI maintainers and complain to your BIOS "
"vendor.\n");
#endif #endif
kfree(data); kfree(data);
return -ENODEV; return -ENODEV;
} }
if (pol->cpu != 0) { if (pol->cpu != 0) {
printk(KERN_ERR PFX "No ACPI _PSS objects for CPU other than " printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
"CPU0. Complain to your BIOS vendor.\n"); "CPU other than CPU0. Complain to your BIOS "
"vendor.\n");
kfree(data); kfree(data);
return -ENODEV; return -ENODEV;
} }
@ -1193,7 +1199,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
/* min/max the cpu is capable of */ /* min/max the cpu is capable of */
if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { 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); powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table); kfree(data->powernow_table);
kfree(data); kfree(data);

View File

@ -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; u32 d;
u8 b; 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) static void __init ati_bugs(int num, int slot, int func)
{ {
#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
u32 d; u32 d;
u8 b; 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 " printk(KERN_INFO "If you got timer trouble "
"try acpi_use_timer_override\n"); "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 #ifdef CONFIG_DMAR
static void __init intel_g33_dmar(int num, int slot, int func) 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_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs }, 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 #ifdef CONFIG_DMAR
{ PCI_VENDOR_ID_INTEL, 0x29c0, { PCI_VENDOR_ID_INTEL, 0x29c0,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar }, PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },

View File

@ -63,6 +63,13 @@ void idle_notifier_register(struct notifier_block *n)
{ {
atomic_notifier_chain_register(&idle_notifier, 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) void enter_idle(void)
{ {

View File

@ -82,6 +82,7 @@ obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/ obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/ obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-y += idle/
obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/ obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_NEW_LEDS) += leds/

View File

@ -42,7 +42,7 @@ if ACPI
config ACPI_SLEEP config ACPI_SLEEP
bool bool
depends on PM_SLEEP depends on SUSPEND || HIBERNATION
default y default y
config ACPI_PROCFS config ACPI_PROCFS
@ -157,18 +157,11 @@ config ACPI_FAN
applications to perform basic fan control (on, off, status). applications to perform basic fan control (on, off, status).
config ACPI_DOCK config ACPI_DOCK
tristate "Dock" bool "Dock"
depends on EXPERIMENTAL depends on EXPERIMENTAL
help help
This driver adds support for ACPI controlled docking stations 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_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.
config ACPI_PROCESSOR config ACPI_PROCESSOR
tristate "Processor" tristate "Processor"

View File

@ -45,14 +45,13 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.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_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-$(CONFIG_ACPI_CONTAINER) += container.o obj-$(CONFIG_ACPI_CONTAINER) += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_NUMA) += numa.o

View File

@ -85,7 +85,7 @@ struct acpi_ac {
struct power_supply charger; struct power_supply charger;
#endif #endif
struct acpi_device * device; struct acpi_device * device;
unsigned long state; unsigned long long state;
}; };
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger); #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; ac->device = device;
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_AC_CLASS); strcpy(acpi_device_class(device), ACPI_AC_CLASS);
acpi_driver_data(device) = ac; device->driver_data = ac;
result = acpi_ac_get_state(ac); result = acpi_ac_get_state(ac);
if (result) if (result)

View File

@ -194,8 +194,7 @@ acpi_memory_get_device(acpi_handle handle,
static int acpi_memory_check_device(struct acpi_memory_device *mem_device) 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 */ /* Get device present/absent information from the _STA */
if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_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; acpi_status status;
struct acpi_object_list arg_list; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
unsigned long current_status; unsigned long long current_status;
/* Issue the _EJ0 command */ /* Issue the _EJ0 command */
@ -403,7 +402,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
mem_device->device = device; mem_device->device = device;
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); 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 */ /* Get the range from the _CRS */
result = acpi_memory_get_device_resources(mem_device); 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 */ /* call add_memory func */
result = acpi_memory_enable_device(mem_device); result = acpi_memory_enable_device(mem_device);
if (result) if (result)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Error in acpi_memory_enable_device\n")); "Error in acpi_memory_enable_device\n");
} }
return result; return result;
} }

View File

@ -42,7 +42,7 @@
#define ASUS_ACPI_VERSION "0.30" #define ASUS_ACPI_VERSION "0.30"
#define PROC_ASUS "asus" //the directory #define PROC_ASUS "asus" /* The directory */
#define PROC_MLED "mled" #define PROC_MLED "mled"
#define PROC_WLED "wled" #define PROC_WLED "wled"
#define PROC_TLED "tled" #define PROC_TLED "tled"
@ -66,10 +66,10 @@
/* /*
* Flags for hotk status * Flags for hotk status
*/ */
#define MLED_ON 0x01 //mail LED #define MLED_ON 0x01 /* Mail LED */
#define WLED_ON 0x02 //wireless LED #define WLED_ON 0x02 /* Wireless LED */
#define TLED_ON 0x04 //touchpad LED #define TLED_ON 0x04 /* Touchpad LED */
#define BT_ON 0x08 //internal Bluetooth #define BT_ON 0x08 /* Internal Bluetooth */
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
MODULE_DESCRIPTION(ACPI_HOTK_NAME); 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_param(asus_gid, uint, 0);
MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus"); 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 */ * those marked with R are relative to HOTK, A for absolute */
struct model_data { struct model_data {
char *name; //name of the laptop________________A char *name; /* name of the laptop________________A */
char *mt_mled; //method to handle mled_____________R char *mt_mled; /* method to handle mled_____________R */
char *mled_status; //node to handle mled reading_______A char *mled_status; /* node to handle mled reading_______A */
char *mt_wled; //method to handle wled_____________R char *mt_wled; /* method to handle wled_____________R */
char *wled_status; //node to handle wled reading_______A char *wled_status; /* node to handle wled reading_______A */
char *mt_tled; //method to handle tled_____________R char *mt_tled; /* method to handle tled_____________R */
char *tled_status; //node to handle tled reading_______A char *tled_status; /* node to handle tled reading_______A */
char *mt_ledd; //method to handle LED display______R char *mt_ledd; /* method to handle LED display______R */
char *mt_bt_switch; //method to switch Bluetooth on/off_R char *mt_bt_switch; /* method to switch Bluetooth on/off_R */
char *bt_status; //no model currently supports this__? char *bt_status; /* no model currently supports this__? */
char *mt_lcd_switch; //method to turn LCD on/off_________A char *mt_lcd_switch; /* method to turn LCD on/off_________A */
char *lcd_status; //node to read LCD panel state______A char *lcd_status; /* node to read LCD panel state______A */
char *brightness_up; //method to set brightness up_______A char *brightness_up; /* method to set brightness up_______A */
char *brightness_down; //guess what ?______________________A char *brightness_down; /* method to set brightness down ____A */
char *brightness_set; //method to set absolute brightness_R char *brightness_set; /* method to set absolute brightness_R */
char *brightness_get; //method to get absolute brightness_R char *brightness_get; /* method to get absolute brightness_R */
char *brightness_status; //node to get brightness____________A char *brightness_status;/* node to get brightness____________A */
char *display_set; //method to set video output________R char *display_set; /* method to set video output________R */
char *display_get; //method to get video output________R char *display_get; /* method to get video output________R */
}; };
/* /*
@ -111,41 +111,41 @@ struct model_data {
* about the hotk device * about the hotk device
*/ */
struct asus_hotk { struct asus_hotk {
struct acpi_device *device; //the device we are in struct acpi_device *device; /* the device we are in */
acpi_handle handle; //the handle of the hotk device acpi_handle handle; /* the handle of the hotk device */
char status; //status of the hotk, for LEDs, ... char status; /* status of the hotk, for LEDs */
u32 ledd_status; //status of the LED display u32 ledd_status; /* status of the LED display */
struct model_data *methods; //methods available on the laptop struct model_data *methods; /* methods available on the laptop */
u8 brightness; //brightness level u8 brightness; /* brightness level */
enum { enum {
A1x = 0, //A1340D, A1300F A1x = 0, /* A1340D, A1300F */
A2x, //A2500H A2x, /* A2500H */
A4G, //A4700G A4G, /* A4700G */
D1x, //D1 D1x, /* D1 */
L2D, //L2000D L2D, /* L2000D */
L3C, //L3800C L3C, /* L3800C */
L3D, //L3400D L3D, /* L3400D */
L3H, //L3H, L2000E, L5D L3H, /* L3H, L2000E, L5D */
L4R, //L4500R L4R, /* L4500R */
L5x, //L5800C L5x, /* L5800C */
L8L, //L8400L L8L, /* L8400L */
M1A, //M1300A M1A, /* M1300A */
M2E, //M2400E, L4400L M2E, /* M2400E, L4400L */
M6N, //M6800N, W3400N M6N, /* M6800N, W3400N */
M6R, //M6700R, A3000G M6R, /* M6700R, A3000G */
P30, //Samsung P30 P30, /* Samsung P30 */
S1x, //S1300A, but also L1400B and M2400A (L84F) S1x, /* S1300A, but also L1400B and M2400A (L84F) */
S2x, //S200 (J1 reported), Victor MP-XP7210 S2x, /* S200 (J1 reported), Victor MP-XP7210 */
W1N, //W1000N W1N, /* W1000N */
W5A, //W5A W5A, /* W5A */
W3V, //W3030V W3V, /* W3030V */
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N xxN, /* M2400N, M3700N, M5200N, M6800N,
A4S, //Z81sp S1300N, S5200N*/
//(Centrino) A4S, /* Z81sp */
F3Sa, F3Sa, /* (Centrino) */
END_MODEL END_MODEL
} model; //Models currently supported } model; /* Models currently supported */
u16 event_count[128]; //count for each event TODO make this better u16 event_count[128]; /* Count for each event TODO make this better */
}; };
/* Here we go */ /* 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 * 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 * 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 * 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, static int write_acpi_int(acpi_handle handle, const char *method, int val,
struct acpi_buffer *output) struct acpi_buffer *output)
{ {
struct acpi_object_list params; //list of input parameters (an int here) struct acpi_object_list params; /* list of input parameters (int) */
union acpi_object in_obj; //the only param we use union acpi_object in_obj; /* the only param we use */
acpi_status status; acpi_status status;
params.count = 1; 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 len = 0;
int temp; 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 * We use the easy way, we don't care of off and count,
* to 1 * so we don't set eof to 1
*/ */
len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
len += sprintf(page + len, "Model reference : %s\n", len += sprintf(page + len, "Model reference : %s\n",
hotk->methods->name); hotk->methods->name);
/* /*
* The SFUN method probably allows the original driver to get the list * The SFUN method probably allows the original driver to get the list
* of features supported by a given model. For now, 0x0100 or 0x0800 * 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. * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found. * 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 * Another value for userspace: the ASYM method returns 0x02 for
* battery low and 0x04 for battery critical, its readings tend to be * 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 * Note: since not all the laptops provide this method, errors are
* silently ignored. * silently ignored.
*/ */
@ -579,7 +579,7 @@ static int read_led(const char *ledname, int ledmask)
return (hotk->status & ledmask) ? 1 : 0; 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]; char s[32];
if (!count) 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 */ /* FIXME: kill extraneous args so it can be called independently */
static int 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) char *ledname, int ledmask, int invert)
{ {
int rv, value; int rv, value;
@ -631,7 +631,7 @@ proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
} }
static int 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) unsigned long count, void *data)
{ {
return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); 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 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) unsigned long count, void *data)
{ {
int rv, value; int rv, value;
@ -677,7 +677,7 @@ proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
} }
static int 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) unsigned long count, void *data)
{ {
return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); 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 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) 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 */ presence and its LED */
return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0); 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 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) unsigned long count, void *data)
{ {
return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); 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.count = 2;
input.pointer = mt_params; 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 */ otherwise they seem to work */
mt_params[0].type = ACPI_TYPE_INTEGER; mt_params[0].type = ACPI_TYPE_INTEGER;
mt_params[0].integer.value = 0x02; mt_params[0].integer.value = 0x02;
@ -753,7 +753,7 @@ static int get_lcd_state(void)
/* That's what the AML code does */ /* That's what the AML code does */
lcd = out_obj.integer.value >> 8; lcd = out_obj.integer.value >> 8;
} else if (hotk->model == F3Sa) { } else if (hotk->model == F3Sa) {
unsigned long tmp; unsigned long long tmp;
union acpi_object param; union acpi_object param;
struct acpi_object_list input; struct acpi_object_list input;
acpi_status status; acpi_status status;
@ -796,12 +796,13 @@ static int set_lcd_state(int value)
acpi_evaluate_object(NULL, acpi_evaluate_object(NULL,
hotk->methods->mt_lcd_switch, hotk->methods->mt_lcd_switch,
NULL, NULL); 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 if (!write_acpi_int
(hotk->handle, hotk->methods->mt_lcd_switch, 0x07, (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
NULL)) NULL))
status = AE_ERROR; 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 */ the exact behaviour is simulated here */
} }
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
@ -819,7 +820,7 @@ proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
} }
static int 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) unsigned long count, void *data)
{ {
int rv, value; int rv, value;
@ -897,7 +898,7 @@ proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
} }
static int 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) unsigned long count, void *data)
{ {
int rv, value; 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() * complained. The significance of bits is the same as in proc_write_disp()
*/ */
static int 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)) if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
printk(KERN_WARNING printk(KERN_WARNING
"Asus ACPI: Error reading display status\n"); "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); return sprintf(page, "%d\n", value);
} }
/* /*
* Experimental support for display switching. As of now: 1 should activate * 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 * 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 * (bitwise) of these will suffice. I never actually tested 3 displays hooked
* simultaneously, so be warned. See the acpi4asus README for more info. * up simultaneously, so be warned. See the acpi4asus README for more info.
*/ */
static int 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) unsigned long count, void *data)
{ {
int rv, value; 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, typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
int *eof, void *data); 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); unsigned long count, void *data);
static int static int
asus_proc_add(char *name, proc_writefunc * writefunc, asus_proc_add(char *name, proc_writefunc *writefunc,
proc_readfunc * readfunc, mode_t mode, proc_readfunc *readfunc, mode_t mode,
struct acpi_device *device) struct acpi_device *device)
{ {
struct proc_dir_entry *proc = struct proc_dir_entry *proc =
@ -1040,9 +1041,9 @@ static int asus_hotk_add_fs(struct acpi_device *device)
&proc_read_bluetooth, mode, device); &proc_read_bluetooth, mode, device);
} }
/* /*
* We need both read node and write method as LCD switch is also accessible * We need both read node and write method as LCD switch is also
* from keyboard * accessible from the keyboard
*/ */
if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, 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) if (!hotk)
return; return;
if ((event & ~((u32) BR_UP)) < 16) { if ((event & ~((u32) BR_UP)) < 16)
hotk->brightness = (event & ~((u32) BR_UP)); 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)); hotk->brightness = (event & ~((u32) BR_DOWN));
}
acpi_bus_generate_proc_event(hotk->device, event, acpi_bus_generate_proc_event(hotk->device, event,
hotk->event_count[event % 128]++); hotk->event_count[event % 128]++);
@ -1186,8 +1186,8 @@ static int asus_hotk_get_info(void)
acpi_status status; acpi_status status;
/* /*
* Get DSDT headers early enough to allow for differentiating between * Get DSDT headers early enough to allow for differentiating between
* models, but late enough to allow acpi_bus_register_driver() to fail * models, but late enough to allow acpi_bus_register_driver() to fail
* before doing anything ACPI-specific. Should we encounter a machine, * before doing anything ACPI-specific. Should we encounter a machine,
* which needs special handling (i.e. its hotkey device has a different * which needs special handling (i.e. its hotkey device has a different
* HID), this bit will be moved. A global variable asus_info contains * 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. * Try to match the object returned by INIT to the specific model.
* Handle every possible object (or the lack of thereof) the DSDT * Handle every possible object (or the lack of thereof) the DSDT
* writers might throw at us. When in trouble, we pass NULL to * writers might throw at us. When in trouble, we pass NULL to
* asus_model_match() and try something completely different. * asus_model_match() and try something completely different.
*/ */
if (buffer.pointer) { if (buffer.pointer) {
@ -1244,6 +1244,8 @@ static int asus_hotk_get_info(void)
"default values\n", string); "default values\n", string);
printk(KERN_NOTICE printk(KERN_NOTICE
" send /proc/acpi/dsdt to the developers\n"); " send /proc/acpi/dsdt to the developers\n");
kfree(model);
return -ENODEV;
} }
hotk->methods = &model_conf[hotk->model]; hotk->methods = &model_conf[hotk->model];
return AE_OK; return AE_OK;
@ -1254,7 +1256,7 @@ static int asus_hotk_get_info(void)
/* Sort of per-model blacklist */ /* Sort of per-model blacklist */
if (strncmp(string, "L2B", 3) == 0) if (strncmp(string, "L2B", 3) == 0)
hotk->methods->lcd_status = NULL; 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 */ exception */
else if (strncmp(string, "A3G", 3) == 0) else if (strncmp(string, "A3G", 3) == 0)
hotk->methods->lcd_status = "\\BLFG"; hotk->methods->lcd_status = "\\BLFG";
@ -1321,7 +1323,7 @@ static int asus_hotk_add(struct acpi_device *device)
hotk->handle = device->handle; hotk->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_HOTK_CLASS); strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
acpi_driver_data(device) = hotk; device->driver_data = hotk;
hotk->device = device; hotk->device = device;
result = asus_hotk_check(); result = asus_hotk_check();
@ -1366,10 +1368,9 @@ static int asus_hotk_add(struct acpi_device *device)
/* LED display is off by default */ /* LED display is off by default */
hotk->ledd_status = 0xFFF; hotk->ledd_status = 0xFFF;
end: end:
if (result) { if (result)
kfree(hotk); kfree(hotk);
}
return result; return result;
} }
@ -1394,8 +1395,8 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
} }
static struct backlight_ops asus_backlight_data = { static struct backlight_ops asus_backlight_data = {
.get_brightness = read_brightness, .get_brightness = read_brightness,
.update_status = set_brightness_status, .update_status = set_brightness_status,
}; };
static void asus_acpi_exit(void) static void asus_acpi_exit(void)
@ -1442,15 +1443,15 @@ static int __init asus_acpi_init(void)
return -ENODEV; return -ENODEV;
} }
asus_backlight_device = backlight_device_register("asus",NULL,NULL, asus_backlight_device = backlight_device_register("asus", NULL, NULL,
&asus_backlight_data); &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"); printk(KERN_ERR "Could not register asus backlight device\n");
asus_backlight_device = NULL; asus_backlight_device = NULL;
asus_acpi_exit(); asus_acpi_exit();
return -ENODEV; return -ENODEV;
} }
asus_backlight_device->props.max_brightness = 15; asus_backlight_device->props.max_brightness = 15;
return 0; return 0;
} }

View File

@ -804,7 +804,7 @@ static int acpi_battery_add(struct acpi_device *device)
battery->device = device; battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery; device->driver_data = battery;
mutex_init(&battery->lock); mutex_init(&battery->lock);
acpi_battery_update(battery); acpi_battery_update(battery);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER

View File

@ -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);

View File

@ -48,6 +48,23 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s)) #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 Device Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -77,7 +94,7 @@ EXPORT_SYMBOL(acpi_bus_get_device);
int acpi_bus_get_status(struct acpi_device *device) int acpi_bus_get_status(struct acpi_device *device)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long sta = 0; unsigned long long sta = 0;
if (!device) 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 * According to ACPI spec some device can be present and functional
* have one, in which case status is implied). * 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 else
STRUCT_TO_INT(device->status) = STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) { if (device->status.functional && !device->status.present) {
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
"functional but not present; setting present\n", "functional but not present;\n",
device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); device->pnp.bus_id,
device->status.present = 1; (u32) STRUCT_TO_INT(device->status)));
} }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", 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; int result = 0;
acpi_status status = 0; acpi_status status = 0;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
unsigned long psc = 0; unsigned long long psc = 0;
result = acpi_bus_get_device(handle, &device); 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 * 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) { if ((state == device->power.state) && !device->flags.force_power_state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state)); state));
@ -496,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device)
return 0; 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 * acpi_bus_notify
* --------------- * ---------------
@ -506,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
int result = 0; int result = 0;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
blocking_notifier_call_chain(&acpi_bus_notify_list,
type, (void *)handle);
if (acpi_bus_get_device(handle, &device)) if (acpi_bus_get_device(handle, &device))
return; return;
@ -749,6 +793,12 @@ static int __init acpi_bus_init(void)
goto error1; 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"); printk(KERN_INFO PREFIX "Interpreter enabled\n");
/* Initialize sleep structures */ /* Initialize sleep structures */
@ -818,7 +868,11 @@ static int __init acpi_init(void)
} }
} else } else
disable_acpi(); 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; return result;
} }

View File

@ -145,7 +145,7 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
{ {
struct acpi_button *button = seq->private; struct acpi_button *button = seq->private;
acpi_status status; acpi_status status;
unsigned long state; unsigned long long state;
if (!button || !button->device) if (!button || !button->device)
return 0; 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) static int acpi_lid_send_state(struct acpi_button *button)
{ {
unsigned long state; unsigned long long state;
acpi_status status; acpi_status status;
status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, status = acpi_evaluate_integer(button->device->handle, "_LID", NULL,
@ -384,7 +384,7 @@ static int acpi_button_add(struct acpi_device *device)
return -ENOMEM; return -ENOMEM;
button->device = device; button->device = device;
acpi_driver_data(device) = button; device->driver_data = button;
button->input = input = input_allocate_device(); button->input = input = input_allocate_device();
if (!input) { if (!input) {

View File

@ -52,8 +52,8 @@ struct proc_dir_entry *acpi_lock_ac_dir(void)
if (acpi_ac_dir) { if (acpi_ac_dir) {
lock_ac_dir_cnt++; lock_ac_dir_cnt++;
} else { } else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Cannot create %s\n", ACPI_AC_CLASS)); "Cannot create %s\n", ACPI_AC_CLASS);
} }
mutex_unlock(&cm_sbs_mutex); mutex_unlock(&cm_sbs_mutex);
return acpi_ac_dir; return acpi_ac_dir;
@ -83,8 +83,8 @@ struct proc_dir_entry *acpi_lock_battery_dir(void)
if (acpi_battery_dir) { if (acpi_battery_dir) {
lock_battery_dir_cnt++; lock_battery_dir_cnt++;
} else { } else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Cannot create %s\n", ACPI_BATTERY_CLASS)); "Cannot create %s\n", ACPI_BATTERY_CLASS);
} }
mutex_unlock(&cm_sbs_mutex); mutex_unlock(&cm_sbs_mutex);
return acpi_battery_dir; return acpi_battery_dir;

View File

@ -76,7 +76,7 @@ static int is_device_present(acpi_handle handle)
{ {
acpi_handle temp; acpi_handle temp;
acpi_status status; acpi_status status;
unsigned long sta; unsigned long long sta;
status = acpi_get_handle(handle, "_STA", &temp); status = acpi_get_handle(handle, "_STA", &temp);
@ -108,7 +108,7 @@ static int acpi_container_add(struct acpi_device *device)
container->handle = device->handle; container->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS); 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_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
acpi_device_name(device), acpi_device_bid(device))); acpi_device_name(device), acpi_device_bid(device)));

View File

@ -47,8 +47,6 @@ static const struct acpi_dlayer acpi_debug_layers[] = {
}; };
static const struct acpi_dlevel acpi_debug_levels[] = { 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_INIT),
ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
ACPI_DEBUG_INIT(ACPI_LV_INFO), ACPI_DEBUG_INIT(ACPI_LV_INFO),

View File

@ -103,6 +103,9 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
NULL); NULL);
acpi_ex_enter_interpreter(); acpi_ex_enter_interpreter();
} }
acpi_ds_clear_implicit_return(walk_state);
#ifdef ACPI_DISASSEMBLER #ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acdispat.h> #include <acpi/acdispat.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
@ -52,11 +51,11 @@ ACPI_MODULE_NAME("dsmthdat")
/* Local prototypes */ /* Local prototypes */
static void 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); u32 index, struct acpi_walk_state *walk_state);
static acpi_status static acpi_status
acpi_ds_method_data_set_value(u16 opcode, acpi_ds_method_data_set_value(u8 type,
u32 index, u32 index,
union acpi_operand_object *object, union acpi_operand_object *object,
struct acpi_walk_state *walk_state); 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. * Store the argument in the method/walk descriptor.
* Do not copy the arg in order to implement call by reference * 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], params[index],
walk_state); walk_state);
if (ACPI_FAILURE(status)) { 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 * 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 * Index - Which Local or Arg whose type to get
* walk_state - Current walk state object * walk_state - Current walk state object
* Node - Where the node is returned. * Node - Where the node is returned.
@ -246,7 +246,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_ds_method_data_get_node(u16 opcode, acpi_ds_method_data_get_node(u8 type,
u32 index, u32 index,
struct acpi_walk_state *walk_state, struct acpi_walk_state *walk_state,
struct acpi_namespace_node **node) struct acpi_namespace_node **node)
@ -256,8 +256,8 @@ acpi_ds_method_data_get_node(u16 opcode,
/* /*
* Method Locals and Arguments are supported * Method Locals and Arguments are supported
*/ */
switch (opcode) { switch (type) {
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
if (index > ACPI_METHOD_MAX_LOCAL) { if (index > ACPI_METHOD_MAX_LOCAL) {
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
@ -271,7 +271,7 @@ acpi_ds_method_data_get_node(u16 opcode,
*node = &walk_state->local_variables[index]; *node = &walk_state->local_variables[index];
break; break;
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
if (index > ACPI_METHOD_MAX_ARG) { if (index > ACPI_METHOD_MAX_ARG) {
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
@ -286,8 +286,8 @@ acpi_ds_method_data_get_node(u16 opcode,
break; break;
default: default:
ACPI_ERROR((AE_INFO, "Opcode %d is invalid", opcode)); ACPI_ERROR((AE_INFO, "Type %d is invalid", type));
return_ACPI_STATUS(AE_AML_BAD_OPCODE); return_ACPI_STATUS(AE_TYPE);
} }
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
@ -297,7 +297,8 @@ acpi_ds_method_data_get_node(u16 opcode,
* *
* FUNCTION: acpi_ds_method_data_set_value * 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 * Index - Which Local or Arg to get
* Object - Object to be inserted into the stack entry * Object - Object to be inserted into the stack entry
* walk_state - Current walk state object * walk_state - Current walk state object
@ -310,7 +311,7 @@ acpi_ds_method_data_get_node(u16 opcode,
******************************************************************************/ ******************************************************************************/
static acpi_status static acpi_status
acpi_ds_method_data_set_value(u16 opcode, acpi_ds_method_data_set_value(u8 type,
u32 index, u32 index,
union acpi_operand_object *object, union acpi_operand_object *object,
struct acpi_walk_state *walk_state) 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_FUNCTION_TRACE(ds_method_data_set_value);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"NewObj %p Opcode %X, Refs=%d [%s]\n", object, "NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
opcode, object->common.reference_count, type, object->common.reference_count,
acpi_ut_get_type_name(object->common.type))); acpi_ut_get_type_name(object->common.type)));
/* Get the namespace node for the arg/local */ /* 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)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -350,7 +351,8 @@ acpi_ds_method_data_set_value(u16 opcode,
* *
* FUNCTION: acpi_ds_method_data_get_value * 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 * Index - Which local_var or argument to get
* walk_state - Current walk state object * walk_state - Current walk state object
* dest_desc - Where Arg or Local value is returned * dest_desc - Where Arg or Local value is returned
@ -363,7 +365,7 @@ acpi_ds_method_data_set_value(u16 opcode,
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_ds_method_data_get_value(u16 opcode, acpi_ds_method_data_get_value(u8 type,
u32 index, u32 index,
struct acpi_walk_state *walk_state, struct acpi_walk_state *walk_state,
union acpi_operand_object **dest_desc) 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 */ /* 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)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -419,8 +421,8 @@ acpi_ds_method_data_get_value(u16 opcode,
/* Otherwise, return the error */ /* Otherwise, return the error */
else else
switch (opcode) { switch (type) {
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Uninitialized Arg[%d] at node %p", "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); return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Uninitialized Local[%d] at node %p", "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); return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
default: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Not a Arg/Local opcode: %X", "Not a Arg/Local opcode: %X",
opcode)); type));
return_ACPI_STATUS(AE_AML_INTERNAL); 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 * 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 * Index - Which local_var or argument to delete
* walk_state - Current walk state object * walk_state - Current walk state object
* *
@ -470,7 +474,7 @@ acpi_ds_method_data_get_value(u16 opcode,
******************************************************************************/ ******************************************************************************/
static void 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) u32 index, struct acpi_walk_state *walk_state)
{ {
acpi_status status; acpi_status status;
@ -481,7 +485,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
/* Get the namespace node for the arg/local */ /* 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)) { if (ACPI_FAILURE(status)) {
return_VOID; return_VOID;
} }
@ -514,7 +518,8 @@ acpi_ds_method_data_delete_value(u16 opcode,
* *
* FUNCTION: acpi_ds_store_object_to_local * 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 * Index - Which Local or Arg to set
* obj_desc - Value to be stored * obj_desc - Value to be stored
* walk_state - Current walk state * walk_state - Current walk state
@ -528,7 +533,7 @@ acpi_ds_method_data_delete_value(u16 opcode,
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_ds_store_object_to_local(u16 opcode, acpi_ds_store_object_to_local(u8 type,
u32 index, u32 index,
union acpi_operand_object *obj_desc, union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state) 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; union acpi_operand_object *new_obj_desc;
ACPI_FUNCTION_TRACE(ds_store_object_to_local); ACPI_FUNCTION_TRACE(ds_store_object_to_local);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
opcode, index, obj_desc)); type, index, obj_desc));
/* Parameter validation */ /* Parameter validation */
@ -550,7 +555,7 @@ acpi_ds_store_object_to_local(u16 opcode,
/* Get the namespace node for the arg/local */ /* 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)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -602,7 +607,7 @@ acpi_ds_store_object_to_local(u16 opcode,
* *
* Weird, but true. * 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(), * If we have a valid reference object that came from ref_of(),
* do the indirect store * do the indirect store
@ -611,8 +616,8 @@ acpi_ds_store_object_to_local(u16 opcode,
ACPI_DESC_TYPE_OPERAND) ACPI_DESC_TYPE_OPERAND)
&& (current_obj_desc->common.type == && (current_obj_desc->common.type ==
ACPI_TYPE_LOCAL_REFERENCE) ACPI_TYPE_LOCAL_REFERENCE)
&& (current_obj_desc->reference.opcode == && (current_obj_desc->reference.class ==
AML_REF_OF_OP)) { ACPI_REFCLASS_REFOF)) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Arg (%p) is an ObjRef(Node), storing in node %p\n", "Arg (%p) is an ObjRef(Node), storing in node %p\n",
new_obj_desc, new_obj_desc,
@ -640,11 +645,9 @@ acpi_ds_store_object_to_local(u16 opcode,
} }
} }
/* /* Delete the existing object before storing the new one */
* Delete the existing object
* before storing the new one acpi_ds_method_data_delete_value(type, index, walk_state);
*/
acpi_ds_method_data_delete_value(opcode, index, walk_state);
} }
/* /*
@ -653,7 +656,7 @@ acpi_ds_store_object_to_local(u16 opcode,
* (increments the object reference count by one) * (increments the object reference count by one)
*/ */
status = 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); walk_state);
/* Remove local reference if we copied the object above */ /* Remove local reference if we copied the object above */

View File

@ -731,54 +731,70 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
switch (op_info->type) { switch (op_info->type) {
case AML_TYPE_LOCAL_VARIABLE: 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.value = opcode - AML_LOCAL_OP;
obj_desc->reference.offset = opcode - AML_LOCAL_OP; obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
#ifndef ACPI_NO_METHOD_EXECUTION #ifndef ACPI_NO_METHOD_EXECUTION
status = acpi_ds_method_data_get_node(AML_LOCAL_OP, status =
obj_desc-> acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL,
reference.offset, obj_desc->reference.
walk_state, value, walk_state,
(struct ACPI_CAST_INDIRECT_PTR
acpi_namespace_node (struct
**)&obj_desc-> acpi_namespace_node,
reference.object); &obj_desc->reference.
object));
#endif #endif
break; break;
case AML_TYPE_METHOD_ARGUMENT: 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.value = opcode - AML_ARG_OP;
obj_desc->reference.offset = opcode - AML_ARG_OP; obj_desc->reference.class = ACPI_REFCLASS_ARG;
#ifndef ACPI_NO_METHOD_EXECUTION #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-> obj_desc->
reference.offset, reference.value,
walk_state, walk_state,
ACPI_CAST_INDIRECT_PTR
(struct (struct
acpi_namespace_node acpi_namespace_node,
**)&obj_desc-> &obj_desc->
reference.object); reference.
object));
#endif #endif
break; 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 */ /* Node was saved in Op */
obj_desc->reference.node = op->common.node; obj_desc->reference.node = op->common.node;
obj_desc->reference.object = obj_desc->reference.object =
op->common.node->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;
} }
break; break;

View File

@ -1330,7 +1330,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
(walk_state->results->results.obj_desc[0]) == (walk_state->results->results.obj_desc[0]) ==
ACPI_TYPE_LOCAL_REFERENCE) ACPI_TYPE_LOCAL_REFERENCE)
&& ((walk_state->results->results.obj_desc[0])-> && ((walk_state->results->results.obj_desc[0])->
reference.opcode != AML_INDEX_OP)) { reference.class != ACPI_REFCLASS_INDEX)) {
status = status =
acpi_ex_resolve_to_value(&walk_state-> acpi_ex_resolve_to_value(&walk_state->
results->results. results->results.

View File

@ -166,6 +166,10 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
status = AE_CTRL_FALSE; 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: cleanup:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", 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) ACPI_TYPE_LOCAL_REFERENCE)
&& (walk_state->operands[1]->common.type == && (walk_state->operands[1]->common.type ==
ACPI_TYPE_LOCAL_REFERENCE) ACPI_TYPE_LOCAL_REFERENCE)
&& (walk_state->operands[0]->reference.opcode == && (walk_state->operands[0]->reference.class ==
walk_state->operands[1]->reference.opcode) walk_state->operands[1]->reference.class)
&& (walk_state->operands[0]->reference.offset == && (walk_state->operands[0]->reference.value ==
walk_state->operands[1]->reference.offset)) { walk_state->operands[1]->reference.value)) {
status = AE_OK; status = AE_OK;
} else { } else {
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,

View File

@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
" before undocking"); " before undocking");
static struct atomic_notifier_head dock_notifier_list; static struct atomic_notifier_head dock_notifier_list;
static struct platform_device *dock_device;
static char dock_device_name[] = "dock"; static char dock_device_name[] = "dock";
static const struct acpi_device_id dock_device_ids[] = { static const struct acpi_device_id dock_device_ids[] = {
@ -65,23 +64,29 @@ struct dock_station {
struct mutex hp_lock; struct mutex hp_lock;
struct list_head dependent_devices; struct list_head dependent_devices;
struct list_head hotplug_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 dock_dependent_device {
struct list_head list; struct list_head list;
struct list_head hotplug_list; struct list_head hotplug_list;
acpi_handle handle; acpi_handle handle;
acpi_notify_handler handler; struct acpi_dock_ops *ops;
void *context; void *context;
}; };
#define DOCK_DOCKING 0x00000001 #define DOCK_DOCKING 0x00000001
#define DOCK_UNDOCKING 0x00000002 #define DOCK_UNDOCKING 0x00000002
#define DOCK_IS_DOCK 0x00000010
#define DOCK_IS_ATA 0x00000020
#define DOCK_IS_BAT 0x00000040
#define DOCK_EVENT 3 #define DOCK_EVENT 3
#define UNDOCK_EVENT 2 #define UNDOCK_EVENT 2
static struct dock_station *dock_station;
/***************************************************************************** /*****************************************************************************
* Dock Dependent device functions * * Dock Dependent device functions *
*****************************************************************************/ *****************************************************************************/
@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
return 1; 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 * is_dock_device - see if a device is on a dock station
* @handle: acpi handle of the device * @handle: acpi handle of the device
@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
*/ */
int is_dock_device(acpi_handle handle) int is_dock_device(acpi_handle handle)
{ {
if (!dock_station) struct dock_station *dock_station;
if (!dock_station_count)
return 0; return 0;
if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) if (is_dock(handle))
return 1; return 1;
list_for_each_entry(dock_station, &dock_stations, sibiling) {
if (find_dock_dependent_device(dock_station, handle))
return 1;
}
return 0; return 0;
} }
@ -229,7 +294,7 @@ EXPORT_SYMBOL_GPL(is_dock_device);
*/ */
static int dock_present(struct dock_station *ds) static int dock_present(struct dock_station *ds)
{ {
unsigned long sta; unsigned long long sta;
acpi_status status; acpi_status status;
if (ds) { if (ds) {
@ -320,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
* First call driver specific hotplug functions * First call driver specific hotplug functions
*/ */
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
if (dd->handler) if (dd->ops && dd->ops->handler)
dd->handler(dd->handle, event, dd->context); 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) 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 event_string[13];
char *envp[] = { event_string, NULL }; char *envp[] = { event_string, NULL };
struct dock_dependent_device *dd;
if (num == UNDOCK_EVENT) if (num == UNDOCK_EVENT)
sprintf(event_string, "EVENT=undock"); 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 * Indicate that the status of the dock station has
* changed. * 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.type = ACPI_TYPE_INTEGER;
arg.integer.value = dock; arg.integer.value = dock;
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute"
(char *)name_buffer.pointer); " _DCK\n", (char *)name_buffer.pointer));
kfree(buffer.pointer); kfree(buffer.pointer);
kfree(name_buffer.pointer); kfree(name_buffer.pointer);
} }
@ -452,6 +526,25 @@ static inline void complete_undock(struct dock_station *ds)
ds->flags &= ~(DOCK_UNDOCKING); 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 * dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station * @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) int register_dock_notifier(struct notifier_block *nb)
{ {
if (!dock_station) if (!dock_station_count)
return -ENODEV; return -ENODEV;
return atomic_notifier_chain_register(&dock_notifier_list, nb); 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) void unregister_dock_notifier(struct notifier_block *nb)
{ {
if (!dock_station) if (!dock_station_count)
return; return;
atomic_notifier_chain_unregister(&dock_notifier_list, nb); 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 * register_hotplug_dock_device - register a hotplug function
* @handle: the handle of the device * @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 * @context: device specific data
* *
* If a driver would like to perform a hotplug operation after a dock * 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. * the dock driver after _DCK is executed.
*/ */
int 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) void *context)
{ {
struct dock_dependent_device *dd; struct dock_dependent_device *dd;
struct dock_station *dock_station;
int ret = -EINVAL;
if (!dock_station) if (!dock_station_count)
return -ENODEV; return -ENODEV;
/* /*
* make sure this handle is for a device dependent on the dock, * make sure this handle is for a device dependent on the dock,
* this would include the dock station itself * this would include the dock station itself
*/ */
dd = find_dock_dependent_device(dock_station, handle); list_for_each_entry(dock_station, &dock_stations, sibiling) {
if (dd) { /*
dd->handler = handler; * An ATA bay can be in a dock and itself can be ejected
dd->context = context; * seperately, so there are two 'dock stations' which need the
dock_add_hotplug_device(dock_station, dd); * ops
return 0; */
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); 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) void unregister_hotplug_dock_device(acpi_handle handle)
{ {
struct dock_dependent_device *dd; struct dock_dependent_device *dd;
struct dock_station *dock_station;
if (!dock_station) if (!dock_station_count)
return; return;
dd = find_dock_dependent_device(dock_station, handle); list_for_each_entry(dock_station, &dock_stations, sibiling) {
if (dd) dd = find_dock_dependent_device(dock_station, handle);
dock_del_hotplug_device(dock_station, dd); if (dd)
dock_del_hotplug_device(dock_station, dd);
}
} }
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); 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); dock_event(ds, event, UNDOCK_EVENT);
if (!dock_present(ds)) {
complete_undock(ds);
return -ENODEV;
}
hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
undock(ds); undock(ds);
dock_lock(ds, 0);
eject_dock(ds); eject_dock(ds);
if (dock_present(ds)) { if (dock_present(ds)) {
printk(KERN_ERR PREFIX "Unable to undock!\n"); 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) static void dock_notify(acpi_handle handle, u32 event, void *data)
{ {
struct dock_station *ds = 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) { switch (event) {
case ACPI_NOTIFY_BUS_CHECK: 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); begin_dock(ds);
dock(ds); dock(ds);
if (!dock_present(ds)) { if (!dock_present(ds)) {
printk(KERN_ERR PREFIX "Unable to dock!\n"); printk(KERN_ERR PREFIX "Unable to dock!\n");
complete_dock(ds);
break; break;
} }
atomic_notifier_call_chain(&dock_notifier_list, 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); hotplug_dock_devices(ds, event);
complete_dock(ds); complete_dock(ds);
dock_event(ds, event, DOCK_EVENT); dock_event(ds, event, DOCK_EVENT);
dock_lock(ds, 1);
break;
} }
break; if (dock_present(ds) || dock_in_progress(ds))
case ACPI_NOTIFY_DEVICE_CHECK: break;
/* /* This is a surprise removal */
* According to acpi spec 3.0a, if a DEVICE_CHECK notification surprise_removal = 1;
* is sent and _DCK is present, it is assumed to mean an event = ACPI_NOTIFY_EJECT_REQUEST;
* undock request. This notify routine will only be called /* Fall back */
* 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.
*/
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
begin_undock(ds); begin_undock(ds);
if (immediate_undock) if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
|| surprise_removal)
handle_eject_request(ds, event); handle_eject_request(ds, event);
else else
dock_event(ds, event, UNDOCK_EVENT); 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 * find_dock_devices - find devices on the dock station
* @handle: the handle of the device we are examining * @handle: the handle of the device we are examining
@ -688,6 +855,8 @@ fdd_out:
static ssize_t show_docked(struct device *dev, static ssize_t show_docked(struct device *dev,
struct device_attribute *attr, char *buf) 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)); 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, static ssize_t show_flags(struct device *dev,
struct device_attribute *attr, char *buf) 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); 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) const char *buf, size_t count)
{ {
int ret; int ret;
struct dock_station *dock_station = *((struct dock_station **)
dev->platform_data);
if (!count) if (!count)
return -EINVAL; return -EINVAL;
@ -727,16 +900,38 @@ static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
static ssize_t show_dock_uid(struct device *dev, static ssize_t show_dock_uid(struct device *dev,
struct device_attribute *attr, char *buf) 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, acpi_status status = acpi_evaluate_integer(dock_station->handle,
"_UID", NULL, &lbuf); "_UID", NULL, &lbuf);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return 0; 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 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 * dock_add - add a new dock station
* @handle: the dock station handle * @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) static int dock_add(acpi_handle handle)
{ {
int ret; int ret;
acpi_status status;
struct dock_dependent_device *dd; struct dock_dependent_device *dd;
struct dock_station *dock_station;
struct platform_device *dock_device;
/* allocate & initialize the dock_station private data */ /* allocate & initialize the dock_station private data */
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); 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; dock_station->last_dock_time = jiffies - HZ;
INIT_LIST_HEAD(&dock_station->dependent_devices); INIT_LIST_HEAD(&dock_station->dependent_devices);
INIT_LIST_HEAD(&dock_station->hotplug_devices); INIT_LIST_HEAD(&dock_station->hotplug_devices);
INIT_LIST_HEAD(&dock_station->sibiling);
spin_lock_init(&dock_station->dd_lock); spin_lock_init(&dock_station->dd_lock);
mutex_init(&dock_station->hp_lock); mutex_init(&dock_station->hp_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
/* initialize platform device stuff */ /* initialize platform device stuff */
dock_device = dock_station->dock_device =
platform_device_register_simple(dock_device_name, 0, NULL, 0); platform_device_register_simple(dock_device_name,
dock_station_count, NULL, 0);
dock_device = dock_station->dock_device;
if (IS_ERR(dock_device)) { if (IS_ERR(dock_device)) {
kfree(dock_station); kfree(dock_station);
dock_station = NULL; dock_station = NULL;
return PTR_ERR(dock_device); 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 */ /* we want the dock device to send uevents */
dock_device->dev.uevent_suppress = 0; 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); ret = device_create_file(&dock_device->dev, &dev_attr_docked);
if (ret) { if (ret) {
printk("Error %d adding sysfs file\n", ret); printk("Error %d adding sysfs file\n", ret);
@ -812,6 +1020,9 @@ static int dock_add(acpi_handle handle)
dock_station = NULL; dock_station = NULL;
return ret; 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 */ /* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 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); add_dock_dependent_device(dock_station, dd);
/* register for dock events */ dock_station_count++;
status = acpi_install_notify_handler(dock_station->handle, list_add(&dock_station->sibiling, &dock_stations);
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);
return 0; return 0;
dock_add_err:
kfree(dd);
dock_add_err_unregister: 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_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid); 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 * 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; 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; return 0;
/* remove dependent devices */ /* remove dependent devices */
@ -872,14 +1071,8 @@ static int dock_remove(void)
list) list)
kfree(dd); 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 */ /* 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_docked);
device_remove_file(&dock_device->dev, &dev_attr_undock); device_remove_file(&dock_device->dev, &dev_attr_undock);
device_remove_file(&dock_device->dev, &dev_attr_uid); device_remove_file(&dock_device->dev, &dev_attr_uid);
@ -904,41 +1097,60 @@ static int dock_remove(void)
static acpi_status static acpi_status
find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
int *count = context;
acpi_status status = AE_OK; acpi_status status = AE_OK;
if (is_dock(handle)) { if (is_dock(handle)) {
if (dock_add(handle) >= 0) { if (dock_add(handle) >= 0) {
(*count)++;
status = AE_CTRL_TERMINATE; status = AE_CTRL_TERMINATE;
} }
} }
return status; 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) static int __init dock_init(void)
{ {
int num = 0;
dock_station = NULL;
if (acpi_disabled) if (acpi_disabled)
return 0; return 0;
/* look for a dock station */ /* look for a dock station */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 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) /* look for bay */
printk(KERN_INFO "No dock devices found.\n"); 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; return 0;
} }
static void __exit dock_exit(void) 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); module_exit(dock_exit);

View File

@ -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) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com> * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@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 */ /* #define DEBUG */
#include <linux/kernel.h> #include <linux/kernel.h>
@ -38,6 +38,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/io.h> #include <asm/io.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
@ -65,22 +66,21 @@ enum ec_command {
ACPI_EC_COMMAND_QUERY = 0x84, 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_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_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ #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 { enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */ 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_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 */ /* 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; u8 query_bit;
}; };
struct transaction {
const u8 *wdata;
u8 *rdata;
unsigned short irq_count;
u8 command;
u8 wlen;
u8 rlen;
};
static struct acpi_ec { static struct acpi_ec {
acpi_handle handle; acpi_handle handle;
unsigned long gpe; unsigned long gpe;
@ -105,9 +114,8 @@ static struct acpi_ec {
struct mutex lock; struct mutex lock;
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
struct delayed_work work; struct transaction *curr;
atomic_t irq_count; spinlock_t curr_lock;
u8 handlers_installed;
} *boot_ec, *first_ec; } *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); u8 x = inb(ec->data_addr);
pr_debug(PREFIX "---> data = 0x%2.2x\n", x); 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) 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); 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)) unsigned long flags;
return 0; int ret = 0;
if (event == ACPI_EC_EVENT_OBF_1) { spin_lock_irqsave(&ec->curr_lock, flags);
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen))
return 1; ret = 1;
} else if (event == ACPI_EC_EVENT_IBF_0) { spin_unlock_irqrestore(&ec->curr_lock, flags);
if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) return ret;
return 1; }
}
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; 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)) unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
schedule_delayed_work(&ec->work, msleep(1);
msecs_to_jiffies(ACPI_EC_DELAY)); while (time_before(jiffies, delay)) {
} gpe_transaction(ec, acpi_ec_read_status(ec));
msleep(1);
static void ec_switch_to_poll_mode(struct acpi_ec *ec) if (ec_transaction_done(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))
return 0; 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; return -ETIME;
} }
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
const u8 * wdata, unsigned wdata_len, struct transaction *t,
u8 * rdata, unsigned rdata_len,
int force_poll) int force_poll)
{ {
int result = 0; unsigned long tmp;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); int ret = 0;
pr_debug(PREFIX "transaction start\n"); pr_debug(PREFIX "transaction start\n");
acpi_ec_write_cmd(ec, command); /* disable GPE during transaction if storm is detected */
for (; wdata_len > 0; --wdata_len) { if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
if (result) { acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
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++));
} }
/* start transaction */
if (!rdata_len) { spin_lock_irqsave(&ec->curr_lock, tmp);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); /* following two actions should be kept atomic */
if (result) { t->irq_count = 0;
pr_err(PREFIX ec->curr = t;
"finish-write timeout, command = %d\n", command); acpi_ec_write_cmd(ec, ec->curr->command);
goto end; if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
}
} else if (command == ACPI_EC_COMMAND_QUERY)
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
spin_unlock_irqrestore(&ec->curr_lock, tmp);
for (; rdata_len > 0; --rdata_len) { /* if we selected poll mode or failed in GPE-mode do a poll loop */
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); if (force_poll ||
if (result) { !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ||
pr_err(PREFIX "read timeout, command = %d\n", command); acpi_ec_wait(ec))
goto end; ret = ec_poll(ec);
}
/* 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:
pr_debug(PREFIX "transaction end\n"); 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, static int ec_check_ibf0(struct acpi_ec *ec)
const u8 * wdata, unsigned wdata_len, {
u8 * rdata, unsigned rdata_len, 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 force_poll)
{ {
int status; int status;
u32 glk; u32 glk;
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
return -EINVAL; return -EINVAL;
if (t->rdata)
if (rdata) memset(t->rdata, 0, t->rlen);
memset(rdata, 0, rdata_len);
mutex_lock(&ec->lock); mutex_lock(&ec->lock);
if (ec->global_lock) { if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
mutex_unlock(&ec->lock); status = -ENODEV;
return -ENODEV; goto unlock;
} }
} }
if (ec_wait_ibf0(ec)) {
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
if (status) {
pr_err(PREFIX "input buffer is not empty, " pr_err(PREFIX "input buffer is not empty, "
"aborting transaction\n"); "aborting transaction\n");
status = -ETIME;
goto end; goto end;
} }
status = acpi_ec_transaction_unlocked(ec, t, force_poll);
status = acpi_ec_transaction_unlocked(ec, command, end:
wdata, wdata_len,
rdata, rdata_len,
force_poll);
end:
if (ec->global_lock) if (ec->global_lock)
acpi_release_global_lock(glk); acpi_release_global_lock(glk);
unlock:
mutex_unlock(&ec->lock); mutex_unlock(&ec->lock);
return status; 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) int acpi_ec_burst_enable(struct acpi_ec *ec)
{ {
u8 d; 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) 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) static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{ {
int result; int result;
u8 d; 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, result = acpi_ec_transaction(ec, &t, 0);
&address, 1, &d, 1, 0);
*data = d; *data = d;
return result; 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) static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{ {
u8 wdata[2] = { address, data }; u8 wdata[2] = { address, data };
return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
wdata, 2, NULL, 0, 0); .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, u8 * rdata, unsigned rdata_len,
int force_poll) int force_poll)
{ {
struct transaction t = {.command = command,
.wdata = wdata, .rdata = rdata,
.wlen = wdata_len, .rlen = rdata_len};
if (!first_ec) if (!first_ec)
return -ENODEV; return -ENODEV;
return acpi_ec_transaction(first_ec, command, wdata, return acpi_ec_transaction(first_ec, &t, force_poll);
wdata_len, rdata, rdata_len,
force_poll);
} }
EXPORT_SYMBOL(ec_transaction); EXPORT_SYMBOL(ec_transaction);
@ -426,7 +463,9 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
{ {
int result; int result;
u8 d; u8 d;
struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
.wdata = NULL, .rdata = &d,
.wlen = 0, .rlen = 1};
if (!ec || !data) if (!ec || !data)
return -EINVAL; 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). * 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) if (result)
return result; return result;
@ -513,46 +552,26 @@ static void acpi_ec_gpe_query(void *ec_cxt)
static u32 acpi_ec_gpe_handler(void *data) static u32 acpi_ec_gpe_handler(void *data)
{ {
acpi_status status = AE_OK;
struct acpi_ec *ec = data; struct acpi_ec *ec = data;
u8 state = acpi_ec_read_status(ec); u8 status;
pr_debug(PREFIX "~~~> interrupt\n"); pr_debug(PREFIX "~~~> interrupt\n");
atomic_inc(&ec->irq_count); status = acpi_ec_read_status(ec);
if (atomic_read(&ec->irq_count) > 5) {
pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); gpe_transaction(ec, status);
ec_switch_to_poll_mode(ec); if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
goto end;
}
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait); wake_up(&ec->wait);
if (state & ACPI_EC_FLAG_SCI) { ec_check_sci(ec, status);
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
status = acpi_os_execute(OSL_EC_BURST_HANDLER, !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) {
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()) {
/* this is non-query, must be confirmation */ /* this is non-query, must be confirmation */
if (printk_ratelimit()) if (printk_ratelimit())
pr_info(PREFIX "non-query interrupt received," pr_info(PREFIX "non-query interrupt received,"
" switching to interrupt mode\n"); " switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags); set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
} }
end: return ACPI_INTERRUPT_HANDLED;
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);
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
@ -696,8 +715,7 @@ static struct acpi_ec *make_acpi_ec(void)
mutex_init(&ec->lock); mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait); init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list); INIT_LIST_HEAD(&ec->list);
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); spin_lock_init(&ec->curr_lock);
atomic_set(&ec->irq_count, 0);
return ec; return ec;
} }
@ -718,6 +736,7 @@ static acpi_status
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{ {
acpi_status status; acpi_status status;
unsigned long long tmp;
struct acpi_ec *ec = context; struct acpi_ec *ec = context;
status = acpi_walk_resources(handle, METHOD_NAME__CRS, 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). */ /* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */ /* 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)) if (ACPI_FAILURE(status))
return status; return status;
ec->gpe = tmp;
/* Use the global lock for all EC transactions? */ /* 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; ec->handle = handle;
return AE_CTRL_TERMINATE; 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) static void ec_remove_handlers(struct acpi_ec *ec)
{ {
ec_poll_stop(ec);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n"); pr_err(PREFIX "failed to remove space handler\n");
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler))) &acpi_ec_gpe_handler)))
pr_err(PREFIX "failed to remove gpe handler\n"); 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) 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) if (!first_ec)
first_ec = ec; first_ec = ec;
acpi_driver_data(device) = ec; device->driver_data = ec;
acpi_ec_add_fs(device); acpi_ec_add_fs(device);
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr); 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); mutex_unlock(&ec->lock);
acpi_ec_remove_fs(device); acpi_ec_remove_fs(device);
acpi_driver_data(device) = NULL; device->driver_data = NULL;
if (ec == first_ec) if (ec == first_ec)
first_ec = NULL; first_ec = NULL;
kfree(ec); 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) static int ec_install_handlers(struct acpi_ec *ec)
{ {
acpi_status status; acpi_status status;
if (ec->handlers_installed) if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
return 0; return 0;
status = acpi_install_gpe_handler(NULL, ec->gpe, status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED, ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec); &acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
status = acpi_install_address_space_handler(ec->handle, status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler, &acpi_ec_space_handler,
NULL, ec); NULL, ec);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); if (status == AE_NOT_FOUND) {
return -ENODEV; /*
* 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; return 0;
} }
@ -887,7 +910,6 @@ static int acpi_ec_start(struct acpi_device *device)
/* EC is fully operational, allow queries */ /* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
ec_schedule_ec_poll(ec);
return ret; return ret;
} }
@ -906,7 +928,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
int __init acpi_boot_ec_enable(void) 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; return 0;
if (!ec_install_handlers(boot_ec)) { if (!ec_install_handlers(boot_ec)) {
first_ec = boot_ec; first_ec = boot_ec;

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/actables.h> #include <acpi/actables.h>
#include <acpi/acdispat.h> #include <acpi/acdispat.h>
@ -91,13 +90,12 @@ acpi_ex_add_table(u32 table_index,
/* Init the table handle */ /* Init the table handle */
obj_desc->reference.opcode = AML_LOAD_OP; obj_desc->reference.class = ACPI_REFCLASS_TABLE;
*ddb_handle = obj_desc; *ddb_handle = obj_desc;
/* Install the new table into the local data structures */ /* Install the new table into the local data structures */
obj_desc->reference.object = ACPI_CAST_PTR(void, obj_desc->reference.value = table_index;
(unsigned long)table_index);
/* Add the table to the namespace */ /* 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) struct acpi_walk_state *walk_state)
{ {
union acpi_operand_object *ddb_handle; union acpi_operand_object *ddb_handle;
struct acpi_table_header *table;
struct acpi_table_desc table_desc; struct acpi_table_desc table_desc;
u32 table_index; u32 table_index;
acpi_status status; acpi_status status;
@ -294,9 +293,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION: case ACPI_TYPE_REGION:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
obj_desc, "Load table from Region %p\n", obj_desc));
acpi_ut_get_object_type_name(obj_desc)));
/* Region must be system_memory (from ACPI spec) */ /* 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 * Map the table header and get the actual table length. The region
* memory region is technically not guaranteed to remain stable and * length is not guaranteed to be the same as the table length.
* we may eventually have to copy the table to a local buffer.
*/ */
table_desc.address = obj_desc->region.address; table = acpi_os_map_memory(obj_desc->region.address,
table_desc.length = obj_desc->region.length; sizeof(struct acpi_table_header));
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; if (!table) {
break; return_ACPI_STATUS(AE_NO_MEMORY);
}
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
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;
/* Must have at least an 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); 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 = /* Allocate a buffer for the table */
acpi_tb_verify_checksum(ACPI_CAST_PTR
(struct acpi_table_header, table_desc.pointer = ACPI_ALLOCATE(length);
obj_desc->buffer.pointer), length); if (!table_desc.pointer) {
if (ACPI_FAILURE(status)) { return_ACPI_STATUS(AE_NO_MEMORY);
return_ACPI_STATUS(status); }
/* 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 * Copy the table from the buffer because the buffer could be modified
* changed or deleted in the future * or even deleted in the future
*/ */
table_desc.pointer = ACPI_ALLOCATE(length); table_desc.pointer = ACPI_ALLOCATE(length);
if (!table_desc.pointer) { if (!table_desc.pointer) {
return_ACPI_STATUS(AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer, ACPI_MEMCPY(table_desc.pointer, table, length);
length); table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
table_desc.length = length;
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
break; break;
default: default:
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
} }
/* /* Validate table checksum (will not get validated in tb_add_table) */
* Install the new table into the local data structures
*/ 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); status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto cleanup; goto cleanup;
@ -379,7 +428,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* /*
* Add the table to the namespace. * 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 * This appears to go against the ACPI specification, but we do it for
* compatibility with other ACPI implementations. * compatibility with other ACPI implementations.
*/ */
@ -415,7 +464,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
cleanup: cleanup:
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* Delete allocated buffer or mapping */ /* Delete allocated table buffer */
acpi_tb_delete_table(&table_desc); 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); 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 */ /* Invoke table handler if present */

View File

@ -57,7 +57,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
* *
* FUNCTION: acpi_ex_convert_to_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 * Integer, Buffer, or String
* result_desc - Where the new Integer object is returned * result_desc - Where the new Integer object is returned
* Flags - Used for string conversion * 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 are treated as raw data - we don't convert ascii to hex for
* strings. * 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 * 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 * of ACPI 3.0) is that the to_integer() operator allows both decimal
* and hexadecimal strings (hex prefixed with "0x"). * and hexadecimal strings (hex prefixed with "0x").
*/ */
@ -159,6 +159,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
break; break;
default: default:
/* No other types can get here */ /* No other types can get here */
break; break;
} }
@ -185,7 +186,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
* *
* FUNCTION: acpi_ex_convert_to_buffer * 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 * Integer, Buffer, or String
* result_desc - Where the new buffer object is returned * 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 * the integer equals 0
* *
* Finally, null terminate the string and return the length * 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 * 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 * Integer, Buffer, or String
* result_desc - Where the string object is returned * result_desc - Where the string object is returned
* Type - String flags (base and conversion type) * Type - String flags (base and conversion type)
@ -472,7 +473,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
base = 10; 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) * are variable length (include separator for each)
*/ */
for (i = 0; i < obj_desc->buffer.length; i++) { 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 * Create a new string object and string buffer
* (-1 because of extra separator included in string_length from above) * (-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) return_desc = acpi_ut_create_string_object((acpi_size)
(string_length - 1)); string_length);
if (!return_desc) { if (!return_desc) {
return_ACPI_STATUS(AE_NO_MEMORY); 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 * Null terminate the string
* (overwrites final comma/space from above) * (overwrites final comma/space from above)
*/ */
new_buf--; if (obj_desc->buffer.length) {
new_buf--;
}
*new_buf = 0; *new_buf = 0;
break; 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_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_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. * a Buffer or a String to an Integer if necessary.
*/ */
status = status =
@ -627,7 +635,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
case ACPI_TYPE_STRING: 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 * Integer or Buffer if necessary
*/ */
status = status =
@ -637,7 +645,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
case ACPI_TYPE_BUFFER: 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 * Integer or String if necessary
*/ */
status = status =

View File

@ -45,7 +45,6 @@
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/amlcode.h> #include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER #define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exdump") 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"} {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_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_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.object), "Object Desc"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"}, {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: case ACPI_EXD_REFERENCE:
acpi_ex_out_string("Opcode", acpi_ex_out_string("Class Name",
(acpi_ps_get_opcode_info (char *)
(obj_desc->reference.opcode))-> acpi_ut_get_reference_name
name); (obj_desc));
acpi_ex_dump_reference_obj(obj_desc); acpi_ex_dump_reference_obj(obj_desc);
break; 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)) { switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
switch (obj_desc->reference.opcode) { acpi_os_printf("Reference: [%s] ",
case AML_DEBUG_OP: 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; break;
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
acpi_os_printf("Reference: Index %p\n", acpi_os_printf("%p\n", obj_desc->reference.object);
obj_desc->reference.object);
break; break;
case AML_LOAD_OP: case ACPI_REFCLASS_TABLE:
acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n", acpi_os_printf("Table Index %X\n",
obj_desc->reference.object); obj_desc->reference.value);
break; break;
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
acpi_os_printf("Reference: (RefOf) %p [%s]\n", acpi_os_printf("%p [%s]\n", obj_desc->reference.object,
obj_desc->reference.object,
acpi_ut_get_type_name(((union acpi_ut_get_type_name(((union
acpi_operand_object acpi_operand_object
*)obj_desc-> *)
obj_desc->
reference. reference.
object)->common. object)->common.
type)); type));
break; break;
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
acpi_os_printf("Reference: Arg%d", acpi_os_printf("%X", obj_desc->reference.value);
obj_desc->reference.offset);
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { 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"); acpi_os_printf("\n");
break; break;
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
acpi_os_printf("Reference: Local%d", acpi_os_printf("%X", obj_desc->reference.value);
obj_desc->reference.offset);
if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { 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"); acpi_os_printf("\n");
break; break;
case AML_INT_NAMEPATH_OP: case ACPI_REFCLASS_NAME:
acpi_os_printf("Reference: Namepath %X [%4.4s]\n", acpi_os_printf("- [%4.4s]\n",
obj_desc->reference.node->name.integer,
obj_desc->reference.node->name.ascii); obj_desc->reference.node->name.ascii);
break; break;
default: default: /* Unknown reference class */
/* Unknown opcode */ acpi_os_printf("%2.2X\n", obj_desc->reference.class);
acpi_os_printf("Unknown Reference opcode=%X\n",
obj_desc->reference.opcode);
break; break;
} }
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; ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) { if (obj_desc->reference.class == ACPI_REFCLASS_NAME) {
acpi_os_printf(" Named Object %p ", obj_desc->reference.node); acpi_os_printf(" %p ", obj_desc->reference.node);
status = status =
acpi_ns_handle_to_pathname(obj_desc->reference.node, 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_DESC_TYPE_OPERAND) {
acpi_os_printf(" Target: %p", acpi_os_printf(" Target: %p",
obj_desc->reference.object); obj_desc->reference.object);
if (obj_desc->reference.opcode == AML_LOAD_OP) { if (obj_desc->reference.class == ACPI_REFCLASS_TABLE) {
/* acpi_os_printf(" Table Index: %X\n",
* For DDBHandle reference, obj_desc->reference.value);
* obj_desc->Reference.Object is the table index
*/
acpi_os_printf(" [DDBHandle]\n");
} else { } else {
acpi_os_printf(" [%s]\n", acpi_os_printf(" Target: %p [%s]\n",
obj_desc->reference.object,
acpi_ut_get_type_name(((union acpi_ut_get_type_name(((union
acpi_operand_object acpi_operand_object
*) *)
@ -988,9 +981,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
acpi_os_printf("[Object Reference] %s", acpi_os_printf("[Object Reference] Type [%s] %2.2X",
(acpi_ps_get_opcode_info acpi_ut_get_reference_name(obj_desc),
(obj_desc->reference.opcode))->name); obj_desc->reference.class);
acpi_ex_dump_reference_obj(obj_desc); acpi_ex_dump_reference_obj(obj_desc);
break; break;

View File

@ -86,10 +86,10 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
/* /*
* Must be a reference to a Local or Arg * Must be a reference to a Local or Arg
*/ */
switch (obj_desc->reference.opcode) { switch (obj_desc->reference.class) {
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
case AML_DEBUG_OP: case ACPI_REFCLASS_DEBUG:
/* The referenced object is the pseudo-node for the local/arg */ /* 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: default:
ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X", ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
obj_desc->reference.opcode)); obj_desc->reference.class));
return_ACPI_STATUS(AE_AML_INTERNAL); return_ACPI_STATUS(AE_AML_INTERNAL);
} }
break; break;
@ -127,7 +127,7 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_NO_MEMORY); 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; reference_obj->reference.object = referenced_obj;
*return_desc = reference_obj; *return_desc = reference_obj;

View File

@ -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 * Must resolve/dereference the local/arg reference first
*/ */
switch (operand[0]->reference.opcode) { switch (operand[0]->reference.class) {
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
/* Set Operand[0] to the value of the local/arg */ /* Set Operand[0] to the value of the local/arg */
status = status =
acpi_ds_method_data_get_value acpi_ds_method_data_get_value
(operand[0]->reference.opcode, (operand[0]->reference.class,
operand[0]->reference.offset, operand[0]->reference.value,
walk_state, &temp_desc); walk_state, &temp_desc);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto cleanup; goto cleanup;
@ -848,7 +848,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
operand[0] = temp_desc; operand[0] = temp_desc;
break; break;
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
/* Get the object to which the reference refers */ /* 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 * This must be a reference object produced by either the
* Index() or ref_of() operator * Index() or ref_of() operator
*/ */
switch (operand[0]->reference.opcode) { switch (operand[0]->reference.class) {
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
/* /*
* The target type for the Index operator must be * 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 = return_desc->integer.value =
temp_desc->buffer. temp_desc->buffer.
pointer[operand[0]->reference. pointer[operand[0]->reference.
offset]; value];
break; break;
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
@ -985,7 +985,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
default: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unknown Index TargetType %X in obj %p", "Unknown Index TargetType %X in reference object %p",
operand[0]->reference. operand[0]->reference.
target_type, operand[0])); target_type, operand[0]));
status = AE_AML_OPERAND_TYPE; status = AE_AML_OPERAND_TYPE;
@ -993,7 +993,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
} }
break; break;
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
return_desc = operand[0]->reference.object; 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: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unknown opcode in reference(%p) - %X", "Unknown class in reference(%p) - %2.2X",
operand[0], operand[0],
operand[0]->reference.opcode)); operand[0]->reference.class));
status = AE_TYPE; status = AE_TYPE;
goto cleanup; goto cleanup;

View File

@ -391,8 +391,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
/* Initialize the Index reference object */ /* Initialize the Index reference object */
index = operand[1]->integer.value; index = operand[1]->integer.value;
return_desc->reference.offset = (u32) index; return_desc->reference.value = (u32) index;
return_desc->reference.opcode = AML_INDEX_OP; return_desc->reference.class = ACPI_REFCLASS_INDEX;
/* /*
* At this point, the Source operand is a String, Buffer, or Package. * At this point, the Source operand is a String, Buffer, or Package.

View File

@ -46,8 +46,6 @@
#include <acpi/acdispat.h> #include <acpi/acdispat.h>
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#include <acpi/amlcode.h>
#define _COMPONENT ACPI_EXECUTER #define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresnte") 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: case ACPI_TYPE_LOCAL_REFERENCE:
switch (source_desc->reference.opcode) { switch (source_desc->reference.class) {
case AML_LOAD_OP: /* This is a ddb_handle */ case ACPI_REFCLASS_TABLE: /* This is a ddb_handle */
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
/* Return an additional reference to the object */ /* 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 */ /* No named references are allowed here */
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unsupported Reference opcode %X (%s)", "Unsupported Reference type %X",
source_desc->reference.opcode, source_desc->reference.class));
acpi_ps_get_opcode_name(source_desc->
reference.opcode)));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
} }

View File

@ -47,7 +47,6 @@
#include <acpi/acdispat.h> #include <acpi/acdispat.h>
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER #define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresolv") 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; acpi_status status = AE_OK;
union acpi_operand_object *stack_desc; union acpi_operand_object *stack_desc;
union acpi_operand_object *obj_desc = NULL; union acpi_operand_object *obj_desc = NULL;
u16 opcode; u8 ref_type;
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); 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)) { switch (ACPI_GET_OBJECT_TYPE(stack_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
opcode = stack_desc->reference.opcode; ref_type = stack_desc->reference.class;
switch (opcode) { switch (ref_type) {
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
/* /*
* Get the local from the method's state info * Get the local from the method's state info
* Note: this increments the local's object reference count * 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-> stack_desc->
reference.offset, reference.value,
walk_state, walk_state,
&obj_desc); &obj_desc);
if (ACPI_FAILURE(status)) { 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, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"[Arg/Local %X] ValueObj is %p\n", "[Arg/Local %X] ValueObj is %p\n",
stack_desc->reference.offset, stack_desc->reference.value,
obj_desc)); obj_desc));
/* /*
@ -184,7 +183,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
*stack_ptr = obj_desc; *stack_ptr = obj_desc;
break; break;
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
switch (stack_desc->reference.target_type) { switch (stack_desc->reference.target_type) {
case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_BUFFER_FIELD:
@ -239,15 +238,15 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
} }
break; break;
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
case AML_DEBUG_OP: case ACPI_REFCLASS_DEBUG:
case AML_LOAD_OP: case ACPI_REFCLASS_TABLE:
/* Just leave the object as-is, do not dereference */ /* Just leave the object as-is, do not dereference */
break; break;
case AML_INT_NAMEPATH_OP: /* Reference to a named object */ case ACPI_REFCLASS_NAME: /* Reference to a named object */
/* Dereference the name */ /* Dereference the name */
@ -273,8 +272,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
default: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unknown Reference opcode %X (%s) in %p", "Unknown Reference type %X in %p", ref_type,
opcode, acpi_ps_get_opcode_name(opcode),
stack_desc)); stack_desc));
status = AE_AML_INTERNAL; status = AE_AML_INTERNAL;
break; break;
@ -388,13 +386,13 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
* traversing the list of possibly many nested references. * traversing the list of possibly many nested references.
*/ */
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) { while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
switch (obj_desc->reference.opcode) { switch (obj_desc->reference.class) {
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
case AML_INT_NAMEPATH_OP: case ACPI_REFCLASS_NAME:
/* Dereference the reference pointer */ /* 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; node = obj_desc->reference.object;
} else { /* AML_INT_NAMEPATH_OP */ } else { /* AML_INT_NAMEPATH_OP */
@ -429,7 +427,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
} }
break; break;
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
/* Get the type of this reference (index into another object) */ /* 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; break;
case AML_LOAD_OP: case ACPI_REFCLASS_TABLE:
type = ACPI_TYPE_DDB_HANDLE; type = ACPI_TYPE_DDB_HANDLE;
goto exit; goto exit;
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
if (return_desc) { if (return_desc) {
status = status =
acpi_ds_method_data_get_value(obj_desc-> acpi_ds_method_data_get_value(obj_desc->
reference. reference.
opcode, class,
obj_desc-> obj_desc->
reference. reference.
offset, value,
walk_state, walk_state,
&obj_desc); &obj_desc);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -481,10 +479,10 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
status = status =
acpi_ds_method_data_get_node(obj_desc-> acpi_ds_method_data_get_node(obj_desc->
reference. reference.
opcode, class,
obj_desc-> obj_desc->
reference. reference.
offset, value,
walk_state, walk_state,
&node); &node);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -499,7 +497,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
} }
break; break;
case AML_DEBUG_OP: case ACPI_REFCLASS_DEBUG:
/* The Debug Object is of type "DebugObject" */ /* The Debug Object is of type "DebugObject" */
@ -509,8 +507,8 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
default: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unknown Reference subtype %X", "Unknown Reference Class %2.2X",
obj_desc->reference.opcode)); obj_desc->reference.class));
return_ACPI_STATUS(AE_AML_INTERNAL); return_ACPI_STATUS(AE_AML_INTERNAL);
} }
} }

View File

@ -225,41 +225,36 @@ acpi_ex_resolve_operands(u16 opcode,
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
/* Decode the Reference */ /* Validate the Reference */
op_info = acpi_ps_get_opcode_info(opcode); switch (obj_desc->reference.class) {
if (op_info->class == AML_CLASS_UNKNOWN) { case ACPI_REFCLASS_DEBUG:
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
}
switch (obj_desc->reference.opcode) {
case AML_DEBUG_OP:
target_op = AML_DEBUG_OP; target_op = AML_DEBUG_OP;
/*lint -fallthrough */ /*lint -fallthrough */
case AML_INDEX_OP: case ACPI_REFCLASS_ARG:
case AML_REF_OF_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_INDEX:
case AML_LOCAL_OP: case ACPI_REFCLASS_REFOF:
case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ case ACPI_REFCLASS_TABLE: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
case AML_INT_NAMEPATH_OP: /* Reference to a named object */ case ACPI_REFCLASS_NAME: /* Reference to a named object */
ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
((ACPI_DB_EXEC, "Operand is a Reference, Class [%s] %2.2X\n",
"Operand is a Reference, RefOpcode [%s]\n", acpi_ut_get_reference_name
(acpi_ps_get_opcode_info (obj_desc),
(obj_desc-> obj_desc->reference.
reference. class));
opcode))->
name)));
break; break;
default: default:
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Operand is a Reference, Unknown Reference Opcode: %X", "Unknown Reference Class %2.2X in %p",
obj_desc->reference. obj_desc->reference.class,
opcode)); obj_desc));
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
} }
@ -270,8 +265,7 @@ acpi_ex_resolve_operands(u16 opcode,
/* Invalid descriptor */ /* Invalid descriptor */
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO, "Invalid descriptor %p [%s]",
"Invalid descriptor %p [%s]",
obj_desc, obj_desc,
acpi_ut_get_descriptor_name(obj_desc))); acpi_ut_get_descriptor_name(obj_desc)));
@ -343,7 +337,7 @@ acpi_ex_resolve_operands(u16 opcode,
if ((opcode == AML_STORE_OP) && if ((opcode == AML_STORE_OP) &&
(ACPI_GET_OBJECT_TYPE(*stack_ptr) == (ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
ACPI_TYPE_LOCAL_REFERENCE) ACPI_TYPE_LOCAL_REFERENCE)
&& ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) { && ((*stack_ptr)->reference.class == ACPI_REFCLASS_INDEX)) {
goto next_operand; goto next_operand;
} }
break; break;

View File

@ -47,7 +47,6 @@
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/amlcode.h> #include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER #define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exstore") ACPI_MODULE_NAME("exstore")
@ -179,22 +178,26 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
if (source_desc->reference.opcode == AML_INDEX_OP) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s] ",
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, acpi_ut_get_reference_name(source_desc)));
"[%s, 0x%X]\n",
acpi_ps_get_opcode_name /* Decode the reference */
(source_desc->reference.opcode),
source_desc->reference.offset)); switch (source_desc->reference.class) {
} else { case ACPI_REFCLASS_INDEX:
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
acpi_ps_get_opcode_name ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "0x%X\n",
(source_desc->reference.opcode))); 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, ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
" Table OwnerId %p\n", "Table Index 0x%X\n",
source_desc->reference.object)); source_desc->reference.value));
break;
default:
break; 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) * 1) Store to Name (Change the object associated with a name)
* 2) Store to an indexed area of a Buffer or Package * 2) Store to an indexed area of a Buffer or Package
* 3) Store to a Method Local or Arg * 3) Store to a Method Local or Arg
* 4) Store to the debug object * 4) Store to the debug object
*/ */
switch (ref_desc->reference.opcode) { switch (ref_desc->reference.class) {
case AML_REF_OF_OP: case ACPI_REFCLASS_REFOF:
/* Storing an object into a Name "container" */ /* Storing an object into a Name "container" */
@ -365,7 +368,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
ACPI_IMPLICIT_CONVERSION); ACPI_IMPLICIT_CONVERSION);
break; break;
case AML_INDEX_OP: case ACPI_REFCLASS_INDEX:
/* Storing to an Index (pointer into a packager or buffer) */ /* 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); walk_state);
break; break;
case AML_LOCAL_OP: case ACPI_REFCLASS_LOCAL:
case AML_ARG_OP: case ACPI_REFCLASS_ARG:
/* Store to a method local/arg */ /* Store to a method local/arg */
status = status =
acpi_ds_store_object_to_local(ref_desc->reference.opcode, acpi_ds_store_object_to_local(ref_desc->reference.class,
ref_desc->reference.offset, ref_desc->reference.value,
source_desc, walk_state); source_desc, walk_state);
break; break;
case AML_DEBUG_OP: case ACPI_REFCLASS_DEBUG:
/* /*
* Storing to the Debug object causes the value stored to be * 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: default:
ACPI_ERROR((AE_INFO, "Unknown Reference opcode %X", ACPI_ERROR((AE_INFO, "Unknown Reference Class %2.2X",
ref_desc->reference.opcode)); ref_desc->reference.class));
ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_ERROR); ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO);
status = AE_AML_INTERNAL; status = AE_AML_INTERNAL;
break; break;
@ -458,7 +461,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
if (ACPI_GET_OBJECT_TYPE(source_desc) == if (ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE 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 */ /* 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 */ /* 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; break;
default: default:

View File

@ -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_STRING) &&
!((ACPI_GET_OBJECT_TYPE(source_desc) == !((ACPI_GET_OBJECT_TYPE(source_desc) ==
ACPI_TYPE_LOCAL_REFERENCE) 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 */ /* Conversion successful but still not a valid type */

View File

@ -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); 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, result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, &cdev->device.kobj,
"thermal_cooling"); "thermal_cooling");
@ -327,8 +327,8 @@ static int acpi_fan_resume(struct acpi_device *device)
result = acpi_bus_get_power(device->handle, &power_state); result = acpi_bus_get_power(device->handle, &power_state);
if (result) { if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Error reading fan power state\n")); "Error reading fan power state\n");
return result; return result;
} }

View File

@ -78,19 +78,17 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
return_ACPI_STATUS(status); 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))) { facs->firmware_waking_vector = (u32)physical_address;
/*
* 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;
}
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }
@ -134,20 +132,7 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
} }
/* Get the vector */ /* Get the vector */
*physical_address = (acpi_physical_address)facs->firmware_waking_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;
}
return_ACPI_STATUS(AE_OK); 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? */ /* 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; acpi_gbl_system_awake_and_running = TRUE;
/* Enable power button */ /* Enable power button */

View File

@ -5,7 +5,7 @@
obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \ obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \
nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
nsparse.o nsparse.o nspredef.o
obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#define _COMPONENT ACPI_NAMESPACE #define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsdump") ACPI_MODULE_NAME("nsdump")
@ -334,9 +333,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
acpi_os_printf("[%s]\n", acpi_os_printf("[%s]\n",
acpi_ps_get_opcode_name(obj_desc-> acpi_ut_get_reference_name(obj_desc));
reference.
opcode));
break; break;
case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_BUFFER_FIELD:

View File

@ -78,6 +78,7 @@ ACPI_MODULE_NAME("nseval")
acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
{ {
acpi_status status; acpi_status status;
struct acpi_namespace_node *node;
ACPI_FUNCTION_TRACE(ns_evaluate); ACPI_FUNCTION_TRACE(ns_evaluate);
@ -117,6 +118,8 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->resolved_node, info->resolved_node,
acpi_ns_get_attached_object(info->resolved_node))); acpi_ns_get_attached_object(info->resolved_node)));
node = info->resolved_node;
/* /*
* Two major cases here: * Two major cases here:
* *
@ -148,21 +151,22 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->param_count++; 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) { if (info->param_count < info->obj_desc->method.param_count) {
ACPI_ERROR((AE_INFO, ACPI_WARNING((AE_INFO,
"Insufficient arguments - " "Insufficient arguments - "
"method [%4.4s] needs %d, found %d", "method [%4.4s] needs %d, found %d",
acpi_ut_get_node_name(info->resolved_node), acpi_ut_get_node_name(info->resolved_node),
info->obj_desc->method.param_count, info->obj_desc->method.param_count,
info->param_count)); info->param_count));
return_ACPI_STATUS(AE_MISSING_ARGUMENTS); } else if (info->param_count >
}
/* Just a warning if too many arguments */
else if (info->param_count >
info->obj_desc->method.param_count) { info->obj_desc->method.param_count) {
ACPI_WARNING((AE_INFO, ACPI_WARNING((AE_INFO,
"Excess arguments - " "Excess arguments - "
@ -195,7 +199,28 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
} else { } else {
/* /*
* 2) Object is not a method, return its current value * 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 * 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)
} }
} }
/* /* Validation of return values for ACPI-predefined methods and objects */
* Check if there is a return value that must be dealt with
*/ 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 (status == AE_CTRL_RETURN_VALUE) {
/* If caller does not want the return value, delete it */ /* If caller does not want the return value, delete it */

View File

@ -115,7 +115,6 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
return (AE_OK); return (AE_OK);
} }
#ifdef ACPI_DEBUG_OUTPUT
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_ns_get_external_pathname * 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); size = acpi_ns_get_pathname_length(node);
if (!size) { if (!size) {
return (NULL); return_PTR(NULL);
} }
/* Allocate a buffer to be returned to caller */ /* 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); status = acpi_ns_build_external_path(node, size, name_buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return (NULL); ACPI_FREE(name_buffer);
return_PTR(NULL);
} }
return_PTR(name_buffer); return_PTR(name_buffer);
} }
#endif
/******************************************************************************* /*******************************************************************************
* *

View 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);
}

View File

@ -331,7 +331,7 @@ acpi_ns_search_and_enter(u32 target_name,
"Found bad character(s) in name, repaired: [%4.4s]\n", "Found bad character(s) in name, repaired: [%4.4s]\n",
ACPI_CAST_PTR(char, &target_name))); ACPI_CAST_PTR(char, &target_name)));
} else { } else {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found bad character(s) in name, repaired: [%4.4s]\n", "Found bad character(s) in name, repaired: [%4.4s]\n",
ACPI_CAST_PTR(char, &target_name))); ACPI_CAST_PTR(char, &target_name)));
} }

View File

@ -48,6 +48,10 @@
#define _COMPONENT ACPI_NAMESPACE #define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfeval") ACPI_MODULE_NAME("nsxfeval")
/* Local prototypes */
static void acpi_ns_resolve_references(struct acpi_evaluate_info *info);
#ifdef ACPI_FUTURE_USAGE #ifdef ACPI_FUTURE_USAGE
/******************************************************************************* /*******************************************************************************
* *
@ -69,6 +73,7 @@ ACPI_MODULE_NAME("nsxfeval")
* be valid (non-null) * be valid (non-null)
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_evaluate_object_typed(acpi_handle handle, acpi_evaluate_object_typed(acpi_handle handle,
acpi_string pathname, acpi_string pathname,
@ -283,6 +288,10 @@ acpi_evaluate_object(acpi_handle handle,
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
/* Dereference Index and ref_of references */
acpi_ns_resolve_references(info);
/* Get the size of the returned object */ /* Get the size of the returned object */
status = status =
@ -350,6 +359,74 @@ acpi_evaluate_object(acpi_handle handle,
ACPI_EXPORT_SYMBOL(acpi_evaluate_object) 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 * FUNCTION: acpi_walk_namespace
@ -379,6 +456,7 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object)
* function, etc. * function, etc.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_walk_namespace(acpi_object_type type, acpi_walk_namespace(acpi_object_type type,
acpi_handle start_object, acpi_handle start_object,

View File

@ -253,6 +253,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
node = acpi_ns_map_handle_to_node(handle); node = acpi_ns_map_handle_to_node(handle);
if (!node) { if (!node) {
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
status = AE_BAD_PARAMETER;
goto cleanup; goto cleanup;
} }
@ -264,6 +265,10 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
info->name = node->name.integer; info->name = node->name.integer;
info->valid = 0; 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); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto cleanup; goto cleanup;

View File

@ -258,7 +258,7 @@ int __init acpi_numa_init(void)
int acpi_get_pxm(acpi_handle h) int acpi_get_pxm(acpi_handle h)
{ {
unsigned long pxm; unsigned long long pxm;
acpi_status status; acpi_status status;
acpi_handle handle; acpi_handle handle;
acpi_handle phandle = h; acpi_handle phandle = h;

View File

@ -608,7 +608,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
acpi_handle handle; acpi_handle handle;
struct acpi_pci_id *pci_id = *id; struct acpi_pci_id *pci_id = *id;
acpi_status status; acpi_status status;
unsigned long temp; unsigned long long temp;
acpi_object_type type; acpi_object_type type;
acpi_get_parent(chandle, &handle); 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)) if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
return; return;
status = status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
&temp); &temp);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
u32 val; u32 val;
@ -682,6 +681,22 @@ static void acpi_os_execute_deferred(struct work_struct *work)
return; 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 * 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, static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_osd_exec_callback function, void *context) acpi_osd_exec_callback function, void *context, int hp)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_os_dpc *dpc; struct acpi_os_dpc *dpc;
struct workqueue_struct *queue; struct workqueue_struct *queue;
int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n", "Scheduling function [%p(%p)] for deferred execution.\n",
function, context)); function, context));
@ -726,19 +742,38 @@ acpi_status acpi_os_execute(acpi_execute_type type,
dpc->function = function; dpc->function = function;
dpc->context = context; dpc->context = context;
INIT_WORK(&dpc->work, acpi_os_execute_deferred); if (!hp) {
queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred);
if (!queue_work(queue, &dpc->work)) { queue = (type == OSL_NOTIFY_HANDLER) ?
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, kacpi_notify_wq : kacpid_wq;
"Call to queue_work() failed.\n")); 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; status = AE_ERROR;
kfree(dpc); kfree(dpc);
} }
return_ACPI_STATUS(status); 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); 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) void acpi_os_wait_events_complete(void *context)
{ {
flush_workqueue(kacpid_wq); flush_workqueue(kacpid_wq);

View File

@ -719,6 +719,8 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
*op = NULL; *op = NULL;
} }
ACPI_PREEMPTION_POINT();
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }

View File

@ -137,6 +137,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
union acpi_parse_object *next; union acpi_parse_object *next;
const struct acpi_opcode_info *parent_info; const struct acpi_opcode_info *parent_info;
union acpi_parse_object *replacement_op = NULL; union acpi_parse_object *replacement_op = NULL;
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op); 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 = replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_op) { if (!replacement_op) {
goto allocate_error; status = AE_NO_MEMORY;
} }
break; break;
@ -211,7 +212,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
replacement_op = replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_op) { if (!replacement_op) {
goto allocate_error; status = AE_NO_MEMORY;
} }
} else } else
if ((op->common.parent->common.aml_opcode == 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. acpi_ps_alloc_op(op->common.
aml_opcode); aml_opcode);
if (!replacement_op) { 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; break;
@ -242,7 +243,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
replacement_op = replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
if (!replacement_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 */ /* Now we can actually delete the subtree rooted at Op */
acpi_ps_delete_parse_tree(op); acpi_ps_delete_parse_tree(op);
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(status);
allocate_error:
/* Always delete the subtree, even on error */
acpi_ps_delete_parse_tree(op);
return_ACPI_STATUS(AE_NO_MEMORY);
} }
/******************************************************************************* /*******************************************************************************
@ -641,10 +635,12 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
ACPI_WALK_METHOD_RESTART; ACPI_WALK_METHOD_RESTART;
} }
} else { } else {
/* On error, delete any return object */ /* On error, delete any return object or implicit return */
acpi_ut_remove_reference(previous_walk_state-> acpi_ut_remove_reference(previous_walk_state->
return_desc); return_desc);
acpi_ds_clear_implicit_return
(previous_walk_state);
} }
} }

View File

@ -709,7 +709,7 @@ int acpi_pci_link_free_irq(acpi_handle handle)
acpi_device_bid(link->device))); acpi_device_bid(link->device)));
if (link->refcnt == 0) { 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); mutex_unlock(&acpi_link_lock);
return (link->irq.active); return (link->irq.active);
@ -737,7 +737,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
link->device = device; link->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
acpi_driver_data(device) = link; device->driver_data = link;
mutex_lock(&acpi_link_lock); mutex_lock(&acpi_link_lock);
result = acpi_pci_link_get_possible(link); result = acpi_pci_link_get_possible(link);
@ -773,7 +773,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
end: end:
/* disable all links -- to be activated on use */ /* 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); mutex_unlock(&acpi_link_lock);
if (result) if (result)

View File

@ -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 *root = NULL;
struct acpi_pci_root *tmp; struct acpi_pci_root *tmp;
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long value = 0; unsigned long long value = 0;
acpi_handle handle = NULL; acpi_handle handle = NULL;
struct acpi_device *child; struct acpi_device *child;
@ -206,7 +206,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
root->device = device; root->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root; device->driver_data = root;
device->ops.bind = acpi_pci_bind; device->ops.bind = acpi_pci_bind;

View File

@ -76,10 +76,10 @@ static struct acpi_pci_driver acpi_pci_slot_driver = {
}; };
static int static int
check_slot(acpi_handle handle, unsigned long *sun) check_slot(acpi_handle handle, unsigned long long *sun)
{ {
int device = -1; int device = -1;
unsigned long adr, sta; unsigned long long adr, sta;
acpi_status status; acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 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) register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
int device; int device;
unsigned long sun; unsigned long long sun;
char name[SLOT_NAME_SIZE]; char name[SLOT_NAME_SIZE];
struct acpi_pci_slot *slot; struct acpi_pci_slot *slot;
struct pci_slot *pci_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) walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
int device, function; int device, function;
unsigned long adr; unsigned long long adr;
acpi_status status; acpi_status status;
acpi_handle dummy_handle; acpi_handle dummy_handle;
acpi_walk_callback user_function; acpi_walk_callback user_function;
@ -239,7 +239,7 @@ static int
walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
{ {
int seg, bus; int seg, bus;
unsigned long tmp; unsigned long long tmp;
acpi_status status; acpi_status status;
acpi_handle dummy_handle; acpi_handle dummy_handle;
struct pci_bus *pci_bus; struct pci_bus *pci_bus;

View File

@ -54,6 +54,14 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 #define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF #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_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device); static int acpi_power_resume(struct acpi_device *device);
@ -128,16 +136,16 @@ acpi_power_get_context(acpi_handle handle,
return 0; 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; acpi_status status = AE_OK;
unsigned long sta = 0; unsigned long long sta = 0;
if (!resource || !state) if (!handle || !state)
return -EINVAL; return -EINVAL;
status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; 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_POWER_RESOURCE_STATE_OFF;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", 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; 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) static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{ {
int result = 0, state1; int result = 0, state1;
struct acpi_power_resource *resource = NULL;
u32 i = 0; u32 i = 0;
@ -161,12 +168,15 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return -EINVAL; return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */ /* The state of the list is 'on' IFF all resources are 'on'. */
/* */
for (i = 0; i < list->count; i++) { for (i = 0; i < list->count; i++) {
result = acpi_power_get_context(list->handles[i], &resource); /*
if (result) * The state of the power resource can be obtained by
return result; * using the ACPI handle. In such case it is unnecessary to
result = acpi_power_get_state(resource, &state1); * get the Power resource first and then get its state again.
*/
result = acpi_power_get_state(list->handles[i], &state1);
if (result) if (result)
return result; return result;
@ -226,12 +236,18 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
result = acpi_power_get_state(resource, &state); if (!acpi_power_nocheck) {
if (result) /*
return result; * If acpi_power_nocheck is set, it is unnecessary to check
if (state != ACPI_POWER_RESOURCE_STATE_ON) * the power state after power transition.
return -ENOEXEC; */
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 */ /* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D0; 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)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
result = acpi_power_get_state(resource, &state); if (!acpi_power_nocheck) {
if (result) /*
return result; * If acpi_power_nocheck is set, it is unnecessary to check
if (state != ACPI_POWER_RESOURCE_STATE_OFF) * the power state after power transition.
return -ENOEXEC; */
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 */ /* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D3; 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) if (!resource)
goto end; goto end;
result = acpi_power_get_state(resource, &state); result = acpi_power_get_state(resource->device->handle, &state);
if (result) if (result)
goto end; goto end;
@ -657,7 +679,7 @@ static int acpi_power_add(struct acpi_device *device)
strcpy(resource->name, device->pnp.bus_id); strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 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. */ /* Evalute the object to get the system level and resource order. */
status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); 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->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order; 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) if (result)
goto end; goto end;
@ -733,9 +755,9 @@ static int acpi_power_resume(struct acpi_device *device)
if (!device || !acpi_driver_data(device)) if (!device || !acpi_driver_data(device))
return -EINVAL; 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) if (result)
return result; return result;

View File

@ -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 */ /* Check if it is a Device with HID and UID */
if (has_uid) { if (has_uid) {
unsigned long value; unsigned long long value;
status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
NULL, &value); NULL, &value);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -818,7 +818,7 @@ static int acpi_processor_add(struct acpi_device *device)
pr->handle = device->handle; pr->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
acpi_driver_data(device) = pr; device->driver_data = pr;
return 0; 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) static int is_processor_present(acpi_handle handle)
{ {
acpi_status status; acpi_status status;
unsigned long sta = 0; unsigned long long sta = 0;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);

View File

@ -1587,6 +1587,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (acpi_idle_bm_check()) { if (acpi_idle_bm_check()) {
if (dev->safe_state) { if (dev->safe_state) {
dev->last_state = dev->safe_state;
return dev->safe_state->enter(dev, dev->safe_state); return dev->safe_state->enter(dev, dev->safe_state);
} else { } else {
local_irq_disable(); local_irq_disable();

View File

@ -38,6 +38,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#endif #endif
#include <asm/cpufeature.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/processor.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) static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{ {
acpi_status status = 0; acpi_status status = 0;
unsigned long ppc = 0; unsigned long long ppc = 0;
if (!pr) if (!pr)
@ -334,7 +335,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
acpi_status status = AE_OK; acpi_status status = AE_OK;
acpi_handle handle = NULL; acpi_handle handle = NULL;
if (!pr || !pr->performance || !pr->handle) if (!pr || !pr->performance || !pr->handle)
return -EINVAL; return -EINVAL;
@ -347,13 +347,25 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
result = acpi_processor_get_performance_control(pr); result = acpi_processor_get_performance_control(pr);
if (result) if (result)
return result; goto update_bios;
result = acpi_processor_get_performance_states(pr); result = acpi_processor_get_performance_states(pr);
if (result) if (result)
return result; goto update_bios;
return 0; 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) 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; psd = buffer.pointer;
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { 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; result = -EFAULT;
goto end; goto end;
} }
if (psd->package.count != 1) { 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; result = -EFAULT;
goto end; goto end;
} }
@ -543,19 +555,19 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
status = acpi_extract_package(&(psd->package.elements[0]), status = acpi_extract_package(&(psd->package.elements[0]),
&format, &state); &format, &state);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); printk(KERN_ERR PREFIX "Invalid _PSD data\n");
result = -EFAULT; result = -EFAULT;
goto end; goto end;
} }
if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { 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; result = -EFAULT;
goto end; goto end;
} }
if (pdomain->revision != ACPI_PSD_REV0_REVISION) { 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; result = -EFAULT;
goto end; goto end;
} }

View File

@ -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) static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{ {
acpi_status status = 0; acpi_status status = 0;
unsigned long tpc = 0; unsigned long long tpc = 0;
if (!pr) if (!pr)
return -EINVAL; return -EINVAL;
@ -528,13 +528,13 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
tsd = buffer.pointer; tsd = buffer.pointer;
if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) { 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; result = -EFAULT;
goto end; goto end;
} }
if (tsd->package.count != 1) { 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; result = -EFAULT;
goto end; goto end;
} }
@ -547,19 +547,19 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
status = acpi_extract_package(&(tsd->package.elements[0]), status = acpi_extract_package(&(tsd->package.elements[0]),
&format, &state); &format, &state);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); printk(KERN_ERR PREFIX "Invalid _TSD data\n");
result = -EFAULT; result = -EFAULT;
goto end; goto end;
} }
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) { 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; result = -EFAULT;
goto end; goto end;
} }
if (pdomain->revision != ACPI_TSD_REV0_REVISION) { 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; result = -EFAULT;
goto end; goto end;
} }

View File

@ -15,9 +15,28 @@ void acpi_reboot(void)
rr = &acpi_gbl_FADT.reset_register; rr = &acpi_gbl_FADT.reset_register;
/* Is the reset register supported? */ /*
if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || * Is the ACPI reset register supported?
rr->bit_width != 8 || rr->bit_offset != 0) *
* 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; return;
reset_value = acpi_gbl_FADT.reset_value; reset_value = acpi_gbl_FADT.reset_value;

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acresrc.h> #include <acpi/acresrc.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#define _COMPONENT ACPI_RESOURCES #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_GET_OBJECT_TYPE(*sub_object_list)) ||
((ACPI_TYPE_LOCAL_REFERENCE == ((ACPI_TYPE_LOCAL_REFERENCE ==
ACPI_GET_OBJECT_TYPE(*sub_object_list)) && ACPI_GET_OBJECT_TYPE(*sub_object_list)) &&
((*sub_object_list)->reference.opcode == ((*sub_object_list)->reference.class ==
AML_INT_NAMEPATH_OP)))) { ACPI_REFCLASS_NAME)))) {
name_found = TRUE; name_found = TRUE;
} else { } else {
/* Look at the next element */ /* Look at the next element */

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acresrc.h> #include <acpi/acresrc.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#define _COMPONENT ACPI_RESOURCES #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)) { switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
if (obj_desc->reference.opcode != if (obj_desc->reference.class !=
AML_INT_NAMEPATH_OP) { ACPI_REFCLASS_NAME) {
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"(PRT[%X].Source) Need name, found reference op %X", "(PRT[%X].Source) Need name, found Reference Class %X",
index, index,
obj_desc->reference. obj_desc->reference.class));
opcode));
return_ACPI_STATUS(AE_BAD_DATA); return_ACPI_STATUS(AE_BAD_DATA);
} }

View File

@ -931,7 +931,7 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs->device = device; sbs->device = device;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SBS_CLASS); strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
acpi_driver_data(device) = sbs; device->driver_data = sbs;
result = acpi_charger_add(sbs); result = acpi_charger_add(sbs);
if (result) if (result)

View File

@ -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) static int acpi_smbus_hc_add(struct acpi_device *device)
{ {
int status; int status;
unsigned long val; unsigned long long val;
struct acpi_smb_hc *hc; struct acpi_smb_hc *hc;
if (!device) if (!device)
@ -282,7 +282,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
hc->ec = acpi_driver_data(device->parent); hc->ec = acpi_driver_data(device->parent);
hc->offset = (val >> 8) & 0xff; hc->offset = (val >> 8) & 0xff;
hc->query_bit = val & 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); 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", 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); hc = acpi_driver_data(device);
acpi_ec_remove_query_handler(hc->ec, hc->query_bit); acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
kfree(hc); kfree(hc);
acpi_driver_data(device) = NULL; device->driver_data = NULL;
return 0; return 0;
} }

View File

@ -113,16 +113,16 @@ static int acpi_bus_hot_remove_device(void *context)
if (acpi_bus_trim(device, 1)) { if (acpi_bus_trim(device, 1)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Removing device failed\n")); "Removing device failed\n");
return -1; return -1;
} }
/* power off device */ /* power off device */
status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
ACPI_DEBUG_PRINT((ACPI_DB_WARN, printk(KERN_WARNING PREFIX
"Power-off device failed\n")); "Power-off device failed\n");
if (device->flags.lockable) { if (device->flags.lockable) {
arg_list.count = 1; arg_list.count = 1;
@ -276,6 +276,13 @@ int acpi_match_device_ids(struct acpi_device *device,
{ {
const struct acpi_device_id *id; 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) { if (device->flags.hardware_id) {
for (id = ids; id->id[0]; id++) { for (id = ids; id->id[0]; id++) {
if (!strcmp((char*)id->id, device->pnp.hardware_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_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
} }
acpi_dev->driver = NULL; acpi_dev->driver = NULL;
acpi_driver_data(dev) = NULL; acpi_dev->driver_data = NULL;
put_device(dev); put_device(dev);
return 0; return 0;
@ -477,7 +484,7 @@ static int acpi_device_register(struct acpi_device *device,
result = acpi_device_setup_files(device); result = acpi_device_setup_files(device);
if(result) 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; device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
return 0; return 0;
@ -537,7 +544,7 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
result = driver->ops.add(device); result = driver->ops.add(device);
if (result) { if (result) {
device->driver = NULL; device->driver = NULL;
acpi_driver_data(device) = NULL; device->driver_data = NULL;
return result; 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)) if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1; 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: end:
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
device->flags.wake_capable = 0; 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. */ /* TBD: System wake support and resource requirements. */
device->power.state = ACPI_STATE_UNKNOWN; device->power.state = ACPI_STATE_UNKNOWN;
acpi_bus_get_power(device->handle, &(device->power.state));
return 0; return 0;
} }
@ -1152,20 +1170,6 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
return 0; 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 static int
acpi_add_single_object(struct acpi_device **child, acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type, struct acpi_device *parent, acpi_handle handle, int type,
@ -1221,15 +1225,18 @@ acpi_add_single_object(struct acpi_device **child,
result = -ENODEV; result = -ENODEV;
goto end; goto end;
} }
if (!device->status.present) { /*
/* Bay and dock should be handled even if absent */ * When the device is neither present nor functional, the
if (!ACPI_SUCCESS( * device should not be added to Linux ACPI device tree.
acpi_is_child_device(device, acpi_bay_match)) && * When the status of the device is not present but functinal,
!ACPI_SUCCESS( * it should be added to Linux ACPI tree. For example : bay
acpi_is_child_device(device, acpi_dock_match))) { * device , dock device.
result = -ENODEV; * In such conditions it is unncessary to check whether it is
goto end; * bay device or dock device.
} */
if (!device->status.present && !device->status.functional) {
result = -ENODEV;
goto end;
} }
break; break;
default: default:
@ -1251,6 +1258,16 @@ acpi_add_single_object(struct acpi_device **child,
*/ */
acpi_device_set_id(device, parent, handle, type); 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 * Power Management
* ---------------- * ----------------
@ -1281,8 +1298,6 @@ acpi_add_single_object(struct acpi_device **child,
goto end; goto end;
} }
if ((result = acpi_device_set_context(device, type)))
goto end;
result = acpi_device_register(device, parent); 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 * TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this. * 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, status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL); NULL, NULL);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
@ -1545,7 +1565,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
return result; return result;
} }
int __init acpi_boot_ec_enable(void);
static int __init acpi_scan_init(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); 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) if (!result)
result = acpi_bus_scan(acpi_root, &ops); result = acpi_bus_scan(acpi_root, &ops);

View File

@ -15,6 +15,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/reboot.h>
#include <asm/io.h> #include <asm/io.h>
@ -24,6 +25,36 @@
u8 sleep_states[ACPI_S_STATE_COUNT]; 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) static int acpi_sleep_prepare(u32 acpi_state)
{ {
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
@ -45,9 +76,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0; static u32 acpi_target_sleep_state = ACPI_STATE_S0;
/* /*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * 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' * 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. * failing transition to a sleep state.
*/ */
acpi_target_sleep_state = ACPI_STATE_S0; 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 #ifdef CONFIG_SUSPEND
extern void do_suspend_lowlevel(void); 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]) { if (sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state; acpi_target_sleep_state = acpi_state;
acpi_sleep_tts_switch(acpi_target_sleep_state);
} else { } else {
printk(KERN_ERR "ACPI does not support this state: %d\n", printk(KERN_ERR "ACPI does not support this state: %d\n",
pm_state); pm_state);
@ -200,6 +232,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
break; break;
} }
/* If ACPI is not enabled by the BIOS, we need to enable it here. */
acpi_enable();
/* Reprogram control registers and execute _BFS */ /* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(acpi_state); 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)"), 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 */ #endif /* CONFIG_SUSPEND */
@ -313,6 +355,7 @@ void __init acpi_no_s4_hw_signature(void)
static int acpi_hibernation_begin(void) static int acpi_hibernation_begin(void)
{ {
acpi_target_sleep_state = ACPI_STATE_S4; acpi_target_sleep_state = ACPI_STATE_S4;
acpi_sleep_tts_switch(acpi_target_sleep_state);
return 0; return 0;
} }
@ -376,7 +419,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
*/ */
static int acpi_hibernation_begin_old(void) 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) if (!error)
acpi_target_sleep_state = ACPI_STATE_S4; 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); acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev; struct acpi_device *adev;
char acpi_method[] = "_SxD"; 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))) { if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
printk(KERN_DEBUG "ACPI handle has no context!\n"); 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; pm_power_off = acpi_power_off;
} }
printk(")\n"); 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; return 0;
} }

View File

@ -386,8 +386,8 @@ static ssize_t counter_set(struct kobject *kobj,
goto end; goto end;
if (!(all_counters[index].flags & ACPI_EVENT_VALID)) { if (!(all_counters[index].flags & ACPI_EVENT_VALID)) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, printk(KERN_WARNING PREFIX
"Can not change Invalid GPE/Fixed Event status\n")); "Can not change Invalid GPE/Fixed Event status\n");
return -EINVAL; return -EINVAL;
} }

View File

@ -50,7 +50,7 @@ ACPI_MODULE_NAME("tbfadt")
/* Local prototypes */ /* Local prototypes */
static void inline static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, 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); 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 * FUNCTION: acpi_tb_init_generic_address
* *
* PARAMETERS: generic_address - GAS struct to be initialized * 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 * Address - Address of the register
* *
* RETURN: None * RETURN: None
@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
static void inline static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, 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 */ /* All other fields are byte-wide */
generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; 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->bit_offset = 0;
generic_address->access_width = 0; generic_address->access_width = 0;
} }
@ -342,9 +342,20 @@ static void acpi_tb_convert_fadt(void)
* useful to calculate them once, here. * useful to calculate them once, here.
* *
* The PM event blocks are split into two register blocks, first is the * The PM event blocks are split into two register blocks, first is the
* PM Status Register block, followed immediately by the PM Enable Register * PM Status Register block, followed immediately by the PM Enable
* block. Each is of length (pm1_event_length/2) * 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); pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
/* The PM1A register block is required */ /* 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 */ /* 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.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, acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
pm1_register_length, pm1_register_length,
(acpi_gbl_FADT.xpm1b_event_block. (acpi_gbl_FADT.xpm1b_event_block.
address + pm1_register_length)); address + pm1_register_length));
/* Don't forget to copy space_id of the GAS */ /* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1b_enable.space_id = acpi_gbl_xpm1b_enable.space_id =
acpi_gbl_FADT.xpm1a_event_block.space_id; acpi_gbl_FADT.xpm1b_event_block.space_id;
} }
} }

View File

@ -110,7 +110,6 @@ acpi_status
acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
{ {
u32 i; u32 i;
u32 length;
acpi_status status = AE_OK; acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_add_table); 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); * Check for a table match on the entire table length,
if (ACPI_MEMCMP(table_desc->pointer, * not just the header.
acpi_gbl_root_table_list.tables[i].pointer, */
length)) { if (table_desc->length !=
acpi_gbl_root_table_list.tables[i].length) {
continue; 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); acpi_tb_delete_table(table_desc);
*table_index = i; *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 root table list */
* Add the table to the global table list
*/
status = acpi_tb_store_table(table_desc->address, table_desc->pointer, status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
table_desc->length, table_desc->flags, table_desc->length, table_desc->flags,
table_index); table_index);
@ -171,6 +209,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
goto release; goto release;
} }
print_header:
acpi_tb_print_table_header(table_desc->address, table_desc->pointer); acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
release: release:

View File

@ -246,18 +246,18 @@ static const struct file_operations acpi_thermal_polling_fops = {
static int acpi_thermal_get_temperature(struct acpi_thermal *tz) static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long long tmp;
if (!tz) if (!tz)
return -EINVAL; return -EINVAL;
tz->last_temperature = tz->temperature; tz->last_temperature = tz->temperature;
status = status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
tz->temperature = tmp;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
tz->temperature)); 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) static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long long tmp;
if (!tz) if (!tz)
return -EINVAL; return -EINVAL;
status = status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
&tz->polling_frequency);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
tz->polling_frequency = tmp;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
tz->polling_frequency)); tz->polling_frequency));
@ -356,6 +355,7 @@ do { \
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
unsigned long long tmp;
struct acpi_handle_list devices; struct acpi_handle_list devices;
int valid = 0; int valid = 0;
int i; int i;
@ -363,7 +363,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
/* Critical Shutdown (required) */ /* Critical Shutdown (required) */
if (flag & ACPI_TRIPS_CRITICAL) { if (flag & ACPI_TRIPS_CRITICAL) {
status = acpi_evaluate_integer(tz->device->handle, 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 * Treat freezing temperatures as invalid as well; some
* BIOSes return really low values and cause reboots at startup. * 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) { } else if (crt > 0) {
unsigned long crt_k = CELSIUS_TO_KELVIN(crt); 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) if (crt_k > tz->trips.critical.temperature)
tz->trips.critical.temperature = crt_k; 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) */ /* Critical Sleep (optional) */
if (flag & ACPI_TRIPS_HOT) { if (flag & ACPI_TRIPS_HOT) {
status = acpi_evaluate_integer(tz->device->handle, status = acpi_evaluate_integer(tz->device->handle,
"_HOT", NULL, &tz->trips.hot.temperature); "_HOT", NULL, &tmp);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0; tz->trips.hot.flags.valid = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No hot threshold\n")); "No hot threshold\n"));
} else { } else {
tz->trips.hot.temperature = tmp;
tz->trips.hot.flags.valid = 1; tz->trips.hot.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found hot threshold [%lu]\n", "Found hot threshold [%lu]\n",
@ -418,33 +422,40 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (psv == -1) { if (psv == -1) {
status = AE_SUPPORT; status = AE_SUPPORT;
} else if (psv > 0) { } else if (psv > 0) {
tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv); tmp = CELSIUS_TO_KELVIN(psv);
status = AE_OK; status = AE_OK;
} else { } else {
status = acpi_evaluate_integer(tz->device->handle, status = acpi_evaluate_integer(tz->device->handle,
"_PSV", NULL, &tz->trips.passive.temperature); "_PSV", NULL, &tmp);
} }
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0; tz->trips.passive.flags.valid = 0;
else { else {
tz->trips.passive.temperature = tmp;
tz->trips.passive.flags.valid = 1; tz->trips.passive.flags.valid = 1;
if (flag == ACPI_TRIPS_INIT) { if (flag == ACPI_TRIPS_INIT) {
status = acpi_evaluate_integer( status = acpi_evaluate_integer(
tz->device->handle, "_TC1", tz->device->handle, "_TC1",
NULL, &tz->trips.passive.tc1); NULL, &tmp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0; tz->trips.passive.flags.valid = 0;
else
tz->trips.passive.tc1 = tmp;
status = acpi_evaluate_integer( status = acpi_evaluate_integer(
tz->device->handle, "_TC2", tz->device->handle, "_TC2",
NULL, &tz->trips.passive.tc2); NULL, &tmp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0; tz->trips.passive.flags.valid = 0;
else
tz->trips.passive.tc2 = tmp;
status = acpi_evaluate_integer( status = acpi_evaluate_integer(
tz->device->handle, "_TSP", tz->device->handle, "_TSP",
NULL, &tz->trips.passive.tsp); NULL, &tmp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0; 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) { if (flag & ACPI_TRIPS_ACTIVE) {
status = acpi_evaluate_integer(tz->device->handle, status = acpi_evaluate_integer(tz->device->handle,
name, NULL, &tz->trips.active[i].temperature); name, NULL, &tmp);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
tz->trips.active[i].flags.valid = 0; tz->trips.active[i].flags.valid = 0;
if (i == 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 : tz->trips.active[i - 2].temperature :
CELSIUS_TO_KELVIN(act)); CELSIUS_TO_KELVIN(act));
break; break;
} else } else {
tz->trips.active[i].temperature = tmp;
tz->trips.active[i].flags.valid = 1; tz->trips.active[i].flags.valid = 1;
}
} }
name[2] = 'L'; name[2] = 'L';
@ -1213,8 +1226,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
acpi_bus_private_data_handler, acpi_bus_private_data_handler,
tz->thermal_zone); tz->thermal_zone);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Error attaching device data\n")); "Error attaching device data\n");
return -ENODEV; return -ENODEV;
} }
@ -1647,7 +1660,7 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(tz->name, device->pnp.bus_id); strcpy(tz->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz; device->driver_data = tz;
mutex_init(&tz->lock); mutex_init(&tz->lock);

View File

@ -548,7 +548,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
if (hci_result == HCI_SUCCESS) { if (hci_result == HCI_SUCCESS) {
int new_video_out = video_out; unsigned int new_video_out = video_out;
if (lcd_out != -1) if (lcd_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
if (crt_out != -1) if (crt_out != -1)

View File

@ -232,7 +232,7 @@ acpi_status acpi_ut_validate_buffer(struct acpi_buffer * buffer)
* RETURN: Status * RETURN: Status
* *
* DESCRIPTION: Validate that the buffer is of the required length or * 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_ut_initialize_buffer(struct acpi_buffer * buffer,
acpi_size required_length) acpi_size required_length)
{ {
acpi_status status = AE_OK; acpi_size input_buffer_length;
/* Parameter validation */ /* Parameter validation */
@ -248,55 +248,58 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
return (AE_BAD_PARAMETER); 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: case ACPI_NO_BUFFER:
/* Set the exception and returned the required length */ /* Return the exception (and the required buffer length) */
status = AE_BUFFER_OVERFLOW; return (AE_BUFFER_OVERFLOW);
break;
case ACPI_ALLOCATE_BUFFER: case ACPI_ALLOCATE_BUFFER:
/* Allocate a new buffer */ /* Allocate a new buffer */
buffer->pointer = acpi_os_allocate(required_length); 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; break;
case ACPI_ALLOCATE_LOCAL_BUFFER: case ACPI_ALLOCATE_LOCAL_BUFFER:
/* Allocate a new buffer with local interface to allow tracking */ /* Allocate a new buffer with local interface to allow tracking */
buffer->pointer = ACPI_ALLOCATE_ZEROED(required_length); buffer->pointer = ACPI_ALLOCATE(required_length);
if (!buffer->pointer) {
return (AE_NO_MEMORY);
}
break; break;
default: default:
/* Existing buffer: Validate the size of the buffer */ /* Existing buffer: Validate the size of the buffer */
if (buffer->length < required_length) { if (input_buffer_length < required_length) {
status = AE_BUFFER_OVERFLOW; return (AE_BUFFER_OVERFLOW);
break;
} }
/* Clear the buffer */
ACPI_MEMSET(buffer->pointer, 0, required_length);
break; break;
} }
buffer->length = required_length; /* Validate allocation from above or input buffer pointer */
return (status);
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 #ifdef NOT_USED_BY_LINUX

View File

@ -42,7 +42,6 @@
*/ */
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.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. */ /* This is an object reference. */
switch (internal_object->reference.opcode) { switch (internal_object->reference.class) {
case AML_INT_NAMEPATH_OP: case ACPI_REFCLASS_NAME:
/* For namepath, return the object handle ("reference") */
default:
/* We are referring to the namespace node */
/*
* For namepath, return the object handle ("reference")
* We are referring to the namespace node
*/
external_object->reference.handle = external_object->reference.handle =
internal_object->reference.node; internal_object->reference.node;
external_object->reference.actual_type = external_object->reference.actual_type =
acpi_ns_get_type(internal_object->reference.node); acpi_ns_get_type(internal_object->reference.node);
break; break;
default:
/* All other reference types are unsupported */
return_ACPI_STATUS(AE_TYPE);
} }
break; break;
@ -533,7 +536,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
/* TBD: should validate incoming handle */ /* TBD: should validate incoming handle */
internal_object->reference.opcode = AML_INT_NAMEPATH_OP; internal_object->reference.class = ACPI_REFCLASS_NAME;
internal_object->reference.node = internal_object->reference.node =
external_object->reference.handle; external_object->reference.handle;
break; 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 * We copied the reference object, so we now must add a reference
* to the object pointed to by the reference * to the object pointed to by the reference
* *
* DDBHandle reference (from Load/load_table is a special reference, * DDBHandle reference (from Load/load_table) is a special reference,
* it's Reference.Object is the table index, so does not need to * it does not have a Reference.Object, so does not need to
* increase the reference count * increase the reference count
*/ */
if (source_desc->reference.opcode == AML_LOAD_OP) { if (source_desc->reference.class == ACPI_REFCLASS_TABLE) {
break; break;
} }

View File

@ -45,7 +45,6 @@
#include <acpi/acinterp.h> #include <acpi/acinterp.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/acevents.h> #include <acpi/acevents.h>
#include <acpi/amlcode.h>
#define _COMPONENT ACPI_UTILITIES #define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utdelete") 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 * reference must track changes to the ref count of the index or
* target object. * target object.
*/ */
if ((object->reference.opcode == AML_INDEX_OP) || if ((object->reference.class == ACPI_REFCLASS_INDEX) ||
(object->reference.opcode == AML_INT_NAMEPATH_OP)) { (object->reference.class == ACPI_REFCLASS_NAME)) {
next_object = object->reference.object; next_object = object->reference.object;
} }
break; break;
@ -586,6 +585,13 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,
"Could not update object reference count")); "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); return_ACPI_STATUS(status);
} }

View File

@ -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_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE,
ACPI_BITPOSITION_RT_CLOCK_ENABLE, ACPI_BITPOSITION_RT_CLOCK_ENABLE,
ACPI_BITMASK_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_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE,
ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE, ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE,
ACPI_BITMASK_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) #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/* /*
* Strings and procedures used for debug only * Strings and procedures used for debug only
@ -677,14 +717,14 @@ u8 acpi_ut_valid_object_type(acpi_object_type type)
* *
* PARAMETERS: None * PARAMETERS: None
* *
* RETURN: None * RETURN: Status
* *
* DESCRIPTION: Init library globals. All globals that require specific * DESCRIPTION: Init library globals. All globals that require specific
* initialization should be initialized here! * initialization should be initialized here!
* *
******************************************************************************/ ******************************************************************************/
void acpi_ut_init_globals(void) acpi_status acpi_ut_init_globals(void)
{ {
acpi_status status; acpi_status status;
u32 i; u32 i;
@ -695,7 +735,7 @@ void acpi_ut_init_globals(void)
status = acpi_ut_create_caches(); status = acpi_ut_create_caches();
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return; return_ACPI_STATUS(status);
} }
/* Mutex locked flags */ /* Mutex locked flags */
@ -772,8 +812,8 @@ void acpi_ut_init_globals(void)
acpi_gbl_display_final_mem_stats = FALSE; acpi_gbl_display_final_mem_stats = FALSE;
#endif #endif
return_VOID; return_ACPI_STATUS(AE_OK);
} }
ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer) ACPI_EXPORT_SYMBOL(acpi_dbg_layer)

View File

@ -995,6 +995,15 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
state->pkg. state->pkg.
this_target_obj, 0); this_target_obj, 0);
if (!state) { 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); return_ACPI_STATUS(AE_NO_MEMORY);
} }
} }

View File

@ -43,7 +43,6 @@
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acnamesp.h> #include <acpi/acnamesp.h>
#include <acpi/amlcode.h>
#define _COMPONENT ACPI_UTILITIES #define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utobject") 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: case ACPI_TYPE_LOCAL_REFERENCE:
switch (internal_object->reference.opcode) { switch (internal_object->reference.class) {
case AML_INT_NAMEPATH_OP: case ACPI_REFCLASS_NAME:
/* /*
* Get the actual length of the full pathname to this object. * 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. * required eventually.
*/ */
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Unsupported Reference opcode=%X in object %p", "Cannot convert to external object - "
internal_object->reference.opcode, "unsupported Reference Class [%s] %X in object %p",
acpi_ut_get_reference_name(internal_object),
internal_object->reference.class,
internal_object)); internal_object));
status = AE_TYPE; status = AE_TYPE;
break; break;
@ -513,7 +514,9 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
default: 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), ACPI_GET_OBJECT_TYPE(internal_object),
internal_object)); internal_object));
status = AE_TYPE; status = AE_TYPE;

View File

@ -81,7 +81,12 @@ acpi_status __init acpi_initialize_subsystem(void)
/* Initialize all globals used by the subsystem */ /* 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 */ /* Create the default mutex objects */

View File

@ -256,7 +256,7 @@ EXPORT_SYMBOL(acpi_extract_package);
acpi_status acpi_status
acpi_evaluate_integer(acpi_handle handle, acpi_evaluate_integer(acpi_handle handle,
acpi_string pathname, 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; acpi_status status = AE_OK;
union acpi_object *element; union acpi_object *element;
@ -288,7 +288,7 @@ acpi_evaluate_integer(acpi_handle handle,
*data = element->integer.value; *data = element->integer.value;
kfree(element); 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; return AE_OK;
} }

View File

@ -291,20 +291,20 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level); int level);
static int acpi_video_device_lcd_get_level_current( static int acpi_video_device_lcd_get_level_current(
struct acpi_video_device *device, struct acpi_video_device *device,
unsigned long *level); unsigned long long *level);
static int acpi_video_get_next_level(struct acpi_video_device *device, static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event); u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device, static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event); int event);
static int acpi_video_device_get_state(struct acpi_video_device *device, 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_output_get(struct output_device *od);
static int acpi_video_device_set_state(struct acpi_video_device *device, int state); static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
/*backlight device sysfs support*/ /*backlight device sysfs support*/
static int acpi_video_get_brightness(struct backlight_device *bd) static int acpi_video_get_brightness(struct backlight_device *bd)
{ {
unsigned long cur_level; unsigned long long cur_level;
int i; int i;
struct acpi_video_device *vd = struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd); (struct acpi_video_device *)bl_get_data(bd);
@ -336,7 +336,7 @@ static struct backlight_ops acpi_backlight_ops = {
/*video output device sysfs support*/ /*video output device sysfs support*/
static int acpi_video_output_get(struct output_device *od) 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 *vd =
(struct acpi_video_device *)dev_get_drvdata(&od->dev); (struct acpi_video_device *)dev_get_drvdata(&od->dev);
acpi_video_device_get_state(vd, &state); 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_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device); struct acpi_video_device *video = acpi_driver_data(device);
unsigned long level; unsigned long long level;
int state; int state;
acpi_video_device_lcd_get_level_current(video, &level); acpi_video_device_lcd_get_level_current(video, &level);
@ -410,7 +410,7 @@ static struct thermal_cooling_device_ops video_cooling_ops = {
/* device */ /* device */
static int 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; int status;
@ -421,7 +421,7 @@ acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
static int static int
acpi_video_device_get_state(struct acpi_video_device *device, acpi_video_device_get_state(struct acpi_video_device *device,
unsigned long *state) unsigned long long *state)
{ {
int status; int status;
@ -436,7 +436,7 @@ acpi_video_device_set_state(struct acpi_video_device *device, int state)
int status; int status;
union acpi_object arg0 = { ACPI_TYPE_INTEGER }; union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 }; struct acpi_object_list args = { 1, &arg0 };
unsigned long ret; unsigned long long ret;
arg0.integer.value = state; arg0.integer.value = state;
@ -495,7 +495,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
static int static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long *level) unsigned long long *level)
{ {
if (device->cap._BQC) if (device->cap._BQC)
return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, 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) acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
{ {
int status; int status;
unsigned long tmp; unsigned long long tmp;
union acpi_object arg0 = { ACPI_TYPE_INTEGER }; union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 }; 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 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; int status;
@ -575,7 +575,7 @@ acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
static int static int
acpi_video_bus_POST_options(struct acpi_video_bus *video, acpi_video_bus_POST_options(struct acpi_video_bus *video,
unsigned long *options) unsigned long long *options)
{ {
int status; int status;
@ -918,7 +918,7 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
{ {
int status; int status;
struct acpi_video_device *dev = seq->private; struct acpi_video_device *dev = seq->private;
unsigned long state; unsigned long long state;
if (!dev) 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); status = acpi_video_device_get_state(dev, &state);
seq_printf(seq, "state: "); seq_printf(seq, "state: ");
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
seq_printf(seq, "0x%02lx\n", state); seq_printf(seq, "0x%02llx\n", state);
else else
seq_printf(seq, "<not supported>\n"); seq_printf(seq, "<not supported>\n");
status = acpi_video_device_query(dev, &state); status = acpi_video_device_query(dev, &state);
seq_printf(seq, "query: "); seq_printf(seq, "query: ");
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
seq_printf(seq, "0x%02lx\n", state); seq_printf(seq, "0x%02llx\n", state);
else else
seq_printf(seq, "<not supported>\n"); 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) static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
{ {
struct acpi_video_bus *video = seq->private; struct acpi_video_bus *video = seq->private;
unsigned long options; unsigned long long options;
int status; 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 printk(KERN_WARNING PREFIX
"This indicates a BIOS bug. Please contact the manufacturer.\n"); "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>"); seq_printf(seq, "can POST: <integrated video>");
if (options & 2) if (options & 2)
seq_printf(seq, " <PCI video>"); 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; struct acpi_video_bus *video = seq->private;
int status; int status;
unsigned long id; unsigned long long id;
if (!video) if (!video)
@ -1303,7 +1303,7 @@ acpi_video_bus_write_POST(struct file *file,
struct seq_file *m = file->private_data; struct seq_file *m = file->private_data;
struct acpi_video_bus *video = m->private; struct acpi_video_bus *video = m->private;
char str[12] = { 0 }; char str[12] = { 0 };
unsigned long opt, options; unsigned long long opt, options;
if (!video || count + 1 > sizeof str) if (!video || count + 1 > sizeof str)
@ -1473,7 +1473,7 @@ static int
acpi_video_bus_get_one_device(struct acpi_device *device, acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_bus *video) struct acpi_video_bus *video)
{ {
unsigned long device_id; unsigned long long device_id;
int status; int status;
struct acpi_video_device *data; struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute; 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_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
acpi_driver_data(device) = data; device->driver_data = data;
data->device_id = device_id; data->device_id = device_id;
data->video = video; data->video = video;
@ -1530,8 +1530,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
acpi_video_device_notify, acpi_video_device_notify,
data); data);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Error installing notify handler\n")); "Error installing notify handler\n");
if(data->brightness) if(data->brightness)
kfree(data->brightness->levels); kfree(data->brightness->levels);
kfree(data->brightness); kfree(data->brightness);
@ -1724,7 +1724,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
static void static void
acpi_video_switch_brightness(struct acpi_video_device *device, int event) 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) if (!device->brightness)
return; return;
acpi_video_device_lcd_get_level_current(device, &level_current); 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); status = acpi_video_bus_get_one_device(dev, video);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, printk(KERN_WARNING PREFIX
"Cant attach device")); "Cant attach device");
continue; continue;
} }
} }
@ -1982,7 +1982,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
video->device = device; video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
acpi_driver_data(device) = video; device->driver_data = video;
acpi_video_bus_find_cap(video); acpi_video_bus_find_cap(video);
error = acpi_video_bus_check(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_DEVICE_NOTIFY,
acpi_video_bus_notify, video); acpi_video_bus_notify, video);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, printk(KERN_ERR PREFIX
"Error installing notify handler\n")); "Error installing notify handler\n");
error = -ENODEV; error = -ENODEV;
goto err_stop_video; goto err_stop_video;
} }
@ -2058,7 +2058,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_remove_fs(device); acpi_video_bus_remove_fs(device);
err_free_video: err_free_video:
kfree(video); kfree(video);
acpi_driver_data(device) = NULL; device->driver_data = NULL;
return error; return error;
} }

View File

@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
return 0; 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 * Exported WMI functions
*/ */
@ -242,7 +271,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
char method[4] = "WM"; char method[4] = "WM";
if (!find_guid(guid_string, &wblock)) if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS; return AE_ERROR;
block = &wblock->gblock; block = &wblock->gblock;
handle = wblock->handle; handle = wblock->handle;
@ -304,7 +333,7 @@ struct acpi_buffer *out)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
if (!find_guid(guid_string, &wblock)) if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS; return AE_ERROR;
block = &wblock->gblock; block = &wblock->gblock;
handle = wblock->handle; handle = wblock->handle;
@ -314,7 +343,7 @@ struct acpi_buffer *out)
/* Check GUID is a data block */ /* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
return AE_BAD_ADDRESS; return AE_ERROR;
input.count = 1; input.count = 1;
input.pointer = wq_params; input.pointer = wq_params;
@ -385,7 +414,7 @@ const struct acpi_buffer *in)
return AE_BAD_DATA; return AE_BAD_DATA;
if (!find_guid(guid_string, &wblock)) if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS; return AE_ERROR;
block = &wblock->gblock; block = &wblock->gblock;
handle = wblock->handle; handle = wblock->handle;
@ -395,7 +424,7 @@ const struct acpi_buffer *in)
/* Check GUID is a data block */ /* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
return AE_BAD_ADDRESS; return AE_ERROR;
input.count = 2; input.count = 2;
input.pointer = params; input.pointer = params;
@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data) wmi_notify_handler handler, void *data)
{ {
struct wmi_block *block; struct wmi_block *block;
acpi_status status;
if (!guid || !handler) if (!guid || !handler)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
block->handler = handler; block->handler = handler;
block->handler_data = data; block->handler_data = data;
return AE_OK; status = wmi_method_enable(block, 1);
return status;
} }
EXPORT_SYMBOL_GPL(wmi_install_notify_handler); 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) acpi_status wmi_remove_notify_handler(const char *guid)
{ {
struct wmi_block *block; struct wmi_block *block;
acpi_status status;
if (!guid) if (!guid)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!block->handler) if (!block->handler)
return AE_NULL_ENTRY; return AE_NULL_ENTRY;
status = wmi_method_enable(block, 0);
block->handler = NULL; block->handler = NULL;
block->handler_data = NULL; block->handler_data = NULL;
return AE_OK; return status;
} }
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);

View File

@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; 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() */ /* @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) 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 * @ap: ATA port ACPI event occurred
* @dev: ATA device ACPI event occurred (can be NULL) * @dev: ATA device ACPI event occurred (can be NULL)
* @event: ACPI event which occurred * @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 * 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 * 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. * ACPI notify handler context. May sleep.
*/ */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, 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 ata_eh_info *ehi = &ap->link.eh_info;
struct kobject *kobj = NULL;
int wait = 0; int wait = 0;
unsigned long flags; unsigned long flags;
acpi_handle handle, tmphandle; acpi_handle handle;
unsigned long sta;
acpi_status status;
if (dev) { if (dev)
if (dev->sdev)
kobj = &dev->sdev->sdev_gendev.kobj;
handle = dev->acpi_handle; handle = dev->acpi_handle;
} else { else
kobj = &ap->dev->kobj;
handle = ap->acpi_handle; 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); 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) { switch (event) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event"); ata_ehi_push_desc(ehi, "ACPI event");
if (ACPI_FAILURE(status)) { ata_ehi_hotplugged(ehi);
ata_port_printk(ap, KERN_ERR, ata_port_freeze(ap);
"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;
}
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event"); ata_ehi_push_desc(ehi, "ACPI event");
if (!is_dock_event)
break;
/* undock event - immediate unplug */
ata_acpi_detach_device(ap, dev); ata_acpi_detach_device(ap, dev);
wait = 1; wait = 1;
break; break;
} }
/* make sure kobj doesn't go away while ap->lock is released */
kobject_get(kobj);
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
if (wait) { if (wait)
ata_port_wait_eh(ap); 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) static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
{ {
struct ata_device *dev = 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) static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
{ {
struct ata_port *ap = 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; struct ata_device *dev = data;
ata_acpi_uevent(dev->link->ap, dev, event);
ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
} }
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) static struct acpi_dock_ops ata_acpi_dev_dock_ops = {
{ .handler = ata_acpi_dev_notify_dock,
struct ata_port *ap = data; .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 * 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); ata_acpi_associate_ide_port(ap);
if (ap->acpi_handle) { 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 */ /* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle, 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++) { for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
struct ata_device *dev = &ap->link.device[j]; struct ata_device *dev = &ap->link.device[j];
if (dev->acpi_handle) { 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 */ /* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle, register_hotplug_dock_device(dev->acpi_handle,
ata_acpi_dev_notify_dock, dev); &ata_acpi_dev_dock_ops, dev);
} }
} }
} }

View File

@ -56,7 +56,11 @@ static void cpuidle_idle_call(void)
if (pm_idle_old) if (pm_idle_old)
pm_idle_old(); pm_idle_old();
else else
#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE)
default_idle();
#else
local_irq_enable(); local_irq_enable();
#endif
return; return;
} }
@ -67,8 +71,11 @@ static void cpuidle_idle_call(void)
target_state = &dev->states[next_state]; target_state = &dev->states[next_state];
/* enter the state and update stats */ /* enter the state and update stats */
dev->last_residency = target_state->enter(dev, target_state);
dev->last_state = 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->time += (unsigned long long)dev->last_residency;
target_state->usage++; target_state->usage++;

View File

@ -171,6 +171,9 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET); xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale)); 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++) { for (i = 0; i < device->common.chancnt; i++) {
ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL); ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
if (!ioat_chan) { if (!ioat_chan) {

16
drivers/idle/Kconfig Normal file
View 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
View File

@ -0,0 +1,2 @@
obj-$(CONFIG_I7300_IDLE) += i7300_idle.o

674
drivers/idle/i7300_idle.c Normal file
View 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");

View File

@ -145,6 +145,7 @@ config ACER_WMI
depends on NEW_LEDS depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042 depends on SERIO_I8042
depends on RFKILL
select ACPI_WMI select ACPI_WMI
---help--- ---help---
This is a driver for newer Acer (and Wistron) laptops. It adds 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. 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 config COMPAL_LAPTOP
tristate "Compal Laptop Extras" tristate "Compal Laptop Extras"
depends on X86 depends on X86

View File

@ -23,6 +23,7 @@ obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o

View File

@ -33,6 +33,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/i8042.h> #include <linux/i8042.h>
#include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
@ -123,21 +125,15 @@ enum interface_flags {
static int max_brightness = 0xF; static int max_brightness = 0xF;
static int wireless = -1;
static int bluetooth = -1;
static int mailled = -1; static int mailled = -1;
static int brightness = -1; static int brightness = -1;
static int threeg = -1; static int threeg = -1;
static int force_series; static int force_series;
module_param(mailled, int, 0444); module_param(mailled, int, 0444);
module_param(wireless, int, 0444);
module_param(bluetooth, int, 0444);
module_param(brightness, int, 0444); module_param(brightness, int, 0444);
module_param(threeg, int, 0444); module_param(threeg, int, 0444);
module_param(force_series, 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(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 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 { struct acer_data {
int mailled; int mailled;
int wireless;
int bluetooth;
int threeg; int threeg;
int brightness; int brightness;
}; };
@ -157,6 +151,9 @@ struct acer_debug {
u32 wmid_devices; 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 */ /* Each low-level interface must define at least some of the following */
struct wmi_interface { struct wmi_interface {
/* The WMI device type */ /* The WMI device type */
@ -476,7 +473,7 @@ struct wmi_interface *iface)
} }
break; break;
default: default:
return AE_BAD_ADDRESS; return AE_ERROR;
} }
return AE_OK; return AE_OK;
} }
@ -514,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
break; break;
} }
default: default:
return AE_BAD_ADDRESS; return AE_ERROR;
} }
/* Actually do the set */ /* Actually do the set */
@ -689,7 +686,7 @@ struct wmi_interface *iface)
return 0; return 0;
} }
default: default:
return AE_BAD_ADDRESS; return AE_ERROR;
} }
status = WMI_execute_u32(method_id, 0, &result); 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; break;
default: default:
return AE_BAD_ADDRESS; return AE_ERROR;
} }
return WMI_execute_u32(method_id, (u32)value, NULL); 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) static acpi_status get_u32(u32 *value, u32 cap)
{ {
acpi_status status = AE_BAD_ADDRESS; acpi_status status = AE_ERROR;
switch (interface->type) { switch (interface->type) {
case ACER_AMW0: case ACER_AMW0:
@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface * capability isn't available on the given interface
*/ */
set_u32(mailled, ACER_CAP_MAILLED); 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(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS); 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 void acer_rfkill_update(struct work_struct *ignored);
static ssize_t \ static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
show_bool_##value(struct device *dev, struct device_attribute *attr, \ static void acer_rfkill_update(struct work_struct *ignored)
char *buf) \ {
{ \ u32 state;
u32 result; \ acpi_status status;
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);
show_set_bool(wireless, ACER_CAP_WIRELESS); status = get_u32(&state, ACER_CAP_WIRELESS);
show_set_bool(bluetooth, ACER_CAP_BLUETOOTH); if (ACPI_SUCCESS(status))
show_set_bool(threeg, ACER_CAP_THREEG); 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, static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
goto error_brightness; goto error_brightness;
} }
return 0; err = acer_rfkill_init(&device->dev);
return err;
error_brightness: error_brightness:
acer_led_exit(); acer_led_exit();
@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
acer_led_exit(); acer_led_exit();
if (has_cap(ACER_CAP_BRIGHTNESS)) if (has_cap(ACER_CAP_BRIGHTNESS))
acer_backlight_exit(); acer_backlight_exit();
acer_rfkill_exit();
return 0; return 0;
} }
@ -1052,16 +1146,6 @@ pm_message_t state)
if (!data) if (!data)
return -ENOMEM; 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)) { if (has_cap(ACER_CAP_MAILLED)) {
get_u32(&value, ACER_CAP_MAILLED); get_u32(&value, ACER_CAP_MAILLED);
data->mailled = value; data->mailled = value;
@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
if (!data) if (!data)
return -ENOMEM; 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)) if (has_cap(ACER_CAP_MAILLED))
set_u32(data->mailled, 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) 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)) if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg); device_remove_file(&device->dev, &dev_attr_threeg);
@ -1133,20 +1202,6 @@ static int create_sysfs(void)
{ {
int retval = -ENOMEM; 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)) { if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev, retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg); &dev_attr_threeg);

View File

@ -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.ECD0._Q10", /* L3C */
"\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
"\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
"\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
"\\_SB.PCI0.PX40.Q10", /* S1x */ "\\_SB.PCI0.PX40.Q10", /* S1x */
"\\Q10"); /* A2x, L2D, L3D, M2E */ "\\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) static int read_wireless_status(int mask)
{ {
ulong status; unsigned long long status;
acpi_status rv = AE_OK; acpi_status rv = AE_OK;
if (!wireless_status_handle) if (!wireless_status_handle)
@ -297,7 +298,7 @@ static int read_wireless_status(int mask)
static int read_gps_status(void) static int read_gps_status(void)
{ {
ulong status; unsigned long long status;
acpi_status rv = AE_OK; acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); 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, \ static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value) \ enum led_brightness value) \
{ \ { \
object##_led_wk = value; \ object##_led_wk = (value > 0) ? 1 : 0; \
queue_work(led_workqueue, &object##_led_work); \ queue_work(led_workqueue, &object##_led_work); \
} \ } \
static void object##_led_update(struct work_struct *ignored) \ 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) static int read_brightness(struct backlight_device *bd)
{ {
ulong value; unsigned long long value;
acpi_status rv = AE_OK; acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); 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) struct device_attribute *attr, char *page)
{ {
int len = 0; int len = 0;
ulong temp; unsigned long long temp;
char buf[16]; //enough for all info char buf[16]; //enough for all info
acpi_status rv = AE_OK; acpi_status rv = AE_OK;
@ -603,7 +604,7 @@ static void set_display(int value)
static int read_display(void) static int read_display(void)
{ {
ulong value = 0; unsigned long long value = 0;
acpi_status rv = AE_OK; acpi_status rv = AE_OK;
/* In most of the case, we know how to set the display, but sometime /* 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 }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL; union acpi_object *model = NULL;
ulong bsts_result, hwrs_result; unsigned long long bsts_result, hwrs_result;
char *string = NULL; char *string = NULL;
acpi_status status; acpi_status status;
@ -996,7 +997,7 @@ static int asus_hotk_add(struct acpi_device *device)
hotk->handle = device->handle; hotk->handle = device->handle;
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
acpi_driver_data(device) = hotk; device->driver_data = hotk;
hotk->device = device; hotk->device = device;
result = asus_hotk_check(); result = asus_hotk_check();

View File

@ -28,6 +28,8 @@
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/input.h>
#include <linux/rfkill.h>
#define EEEPC_LAPTOP_VERSION "0.1" #define EEEPC_LAPTOP_VERSION "0.1"
@ -125,6 +127,10 @@ struct eeepc_hotk {
by this BIOS */ by this BIOS */
uint init_flag; /* Init flags */ uint init_flag; /* Init flags */
u16 event_count[128]; /* count for each event */ 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 */ /* The actual device the driver binds to */
@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
static struct platform_device *platform_device; 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 * 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) static int read_acpi_int(acpi_handle handle, const char *method, int *val)
{ {
acpi_status status; acpi_status status;
ulong result; unsigned long long result;
status = acpi_evaluate_integer(handle, (char *)method, NULL, &result); status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -260,6 +287,44 @@ static int update_bl_status(struct backlight_device *bd)
return set_brightness(bd, bd->props.brightness); 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 * 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(camera, CM_ASL_CAMERA);
EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
static struct attribute *platform_attributes[] = { static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr, &dev_attr_camera.attr,
&dev_attr_cardr.attr, &dev_attr_cardr.attr,
&dev_attr_disp.attr, &dev_attr_disp.attr,
&dev_attr_wlan.attr,
NULL NULL
}; };
@ -328,8 +391,64 @@ static struct attribute_group platform_attribute_group = {
/* /*
* Hotkey functions * 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) static int eeepc_hotk_check(void)
{ {
const struct key_entry *key;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
int result; int result;
@ -356,6 +475,31 @@ static int eeepc_hotk_check(void)
"Get control methods supported: 0x%x\n", "Get control methods supported: 0x%x\n",
ehotk->cm_supported); 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 { } else {
printk(EEEPC_ERR "Hotkey device not present, aborting\n"); printk(EEEPC_ERR "Hotkey device not present, aborting\n");
return -EINVAL; return -EINVAL;
@ -363,21 +507,6 @@ static int eeepc_hotk_check(void)
return 0; 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) static void notify_brn(void)
{ {
struct backlight_device *bd = eeepc_backlight_device; 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 void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
{ {
static struct key_entry *key;
if (!ehotk) if (!ehotk)
return; return;
if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
notify_wlan(&event);
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
notify_brn(); notify_brn();
acpi_bus_generate_proc_event(ehotk->device, event, acpi_bus_generate_proc_event(ehotk->device, event,
ehotk->event_count[event % 128]++); 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) 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; ehotk->handle = device->handle;
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
acpi_driver_data(device) = ehotk; device->driver_data = ehotk;
ehotk->device = device; ehotk->device = device;
result = eeepc_hotk_check(); result = eeepc_hotk_check();
if (result) if (result)
@ -420,6 +563,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_hotk_notify, ehotk); eeepc_hotk_notify, ehotk);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
printk(EEEPC_ERR "Error installing notify handler\n"); 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: end:
if (result) { if (result) {
kfree(ehotk); kfree(ehotk);
@ -553,6 +737,12 @@ static void eeepc_backlight_exit(void)
{ {
if (eeepc_backlight_device) if (eeepc_backlight_device)
backlight_device_unregister(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; eeepc_backlight_device = NULL;
} }

View File

@ -44,8 +44,9 @@
* Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
* also supported by this driver. * also supported by this driver.
* *
* This driver has been tested on a Fujitsu Lifebook S6410 and S7020. It * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
* should work on most P-series and S-series Lifebooks, but YMMV. * 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 * The module parameter use_alt_lcd_levels switches between different ACPI
* brightness controls which are used by different Fujitsu laptops. In most * brightness controls which are used by different Fujitsu laptops. In most
@ -65,7 +66,7 @@
#include <linux/video_output.h> #include <linux/video_output.h>
#include <linux/platform_device.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 #define FUJITSU_LCD_N_LEVELS 8
@ -83,10 +84,10 @@
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
/* Hotkey details */ /* Hotkey details */
#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */ #define KEY1_CODE 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 KEY2_CODE 0x411
#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */ #define KEY3_CODE 0x412
#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */ #define KEY4_CODE 0x413
#define MAX_HOTKEY_RINGBUFFER_SIZE 100 #define MAX_HOTKEY_RINGBUFFER_SIZE 100
#define RINGBUFFERSIZE 40 #define RINGBUFFERSIZE 40
@ -123,6 +124,7 @@ struct fujitsu_t {
char phys[32]; char phys[32];
struct backlight_device *bl_device; struct backlight_device *bl_device;
struct platform_device *pf_device; struct platform_device *pf_device;
int keycode1, keycode2, keycode3, keycode4;
unsigned int max_brightness; unsigned int max_brightness;
unsigned int brightness_changed; unsigned int brightness_changed;
@ -224,7 +226,7 @@ static int set_lcd_level_alt(int level)
static int get_lcd_level(void) static int get_lcd_level(void)
{ {
unsigned long state = 0; unsigned long long state = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); 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) static int get_max_brightness(void)
{ {
unsigned long state = 0; unsigned long long state = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); 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) static int get_lcd_level_alt(void)
{ {
unsigned long state = 0; unsigned long long state = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); 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) static int get_irb(void)
{ {
unsigned long state = 0; unsigned long long state = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); 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; acpi_handle handle;
int have_blnf; int have_blnf;
@ -452,24 +454,40 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
"auto-detecting disable_adjust\n"); "auto-detecting disable_adjust\n");
disable_brightness_adjust = have_blnf ? 0 : 1; 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; return 0;
} }
static struct dmi_system_id __initdata fujitsu_dmi_table[] = { static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
{ {
.ident = "Fujitsu Siemens", .ident = "Fujitsu Siemens S6410",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
}, },
.callback = dmi_check_cb_s6410}, .callback = dmi_check_cb_s6410},
{ {
.ident = "FUJITSU LifeBook P8010", .ident = "Fujitsu LifeBook P8010",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), 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; fujitsu->acpi_handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 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, status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY, ACPI_DEVICE_NOTIFY,
@ -547,7 +565,6 @@ static int acpi_fujitsu_add(struct acpi_device *device)
} }
/* do config (detect defaults) */ /* do config (detect defaults) */
dmi_check_system(fujitsu_dmi_table);
use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
disable_brightness_adjust = disable_brightness_adjust == 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; keycode = 0;
if (disable_brightness_keys != 1) { if (disable_brightness_keys != 1) {
if (oldb == 0) { if (oldb == 0) {
acpi_bus_generate_proc_event(fujitsu-> acpi_bus_generate_proc_event
dev, (fujitsu->dev,
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
0); 0);
keycode = KEY_BRIGHTNESSDOWN; keycode = KEY_BRIGHTNESSDOWN;
} else if (oldb == } else if (oldb ==
(fujitsu->max_brightness) - 1) { (fujitsu->max_brightness) - 1) {
acpi_bus_generate_proc_event(fujitsu-> acpi_bus_generate_proc_event
dev, (fujitsu->dev,
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
0); 0);
keycode = KEY_BRIGHTNESSUP; keycode = KEY_BRIGHTNESSUP;
} }
} }
@ -646,8 +663,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
} }
if (disable_brightness_keys != 1) { if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev, acpi_bus_generate_proc_event(fujitsu->dev,
ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
0);
keycode = KEY_BRIGHTNESSUP; keycode = KEY_BRIGHTNESSUP;
} }
} else if (oldb > newb) { } 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) { if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev, acpi_bus_generate_proc_event(fujitsu->dev,
ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
0);
keycode = KEY_BRIGHTNESSDOWN; keycode = KEY_BRIGHTNESSDOWN;
} }
} else { } else {
@ -703,7 +718,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
sprintf(acpi_device_name(device), "%s", sprintf(acpi_device_name(device), "%s",
ACPI_FUJITSU_HOTKEY_DEVICE_NAME); ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 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, status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY, ACPI_DEVICE_NOTIFY,
@ -742,10 +757,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
input->id.product = 0x06; input->id.product = 0x06;
input->dev.parent = &device->dev; input->dev.parent = &device->dev;
input->evbit[0] = BIT(EV_KEY); input->evbit[0] = BIT(EV_KEY);
set_bit(KEY_SCREENLOCK, input->keybit); set_bit(fujitsu->keycode1, input->keybit);
set_bit(KEY_MEDIA, input->keybit); set_bit(fujitsu->keycode2, input->keybit);
set_bit(KEY_EMAIL, input->keybit); set_bit(fujitsu->keycode3, input->keybit);
set_bit(KEY_SUSPEND, input->keybit); set_bit(fujitsu->keycode4, input->keybit);
set_bit(KEY_UNKNOWN, input->keybit); set_bit(KEY_UNKNOWN, input->keybit);
error = input_register_device(input); error = input_register_device(input);
@ -833,24 +848,24 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
irb); irb);
switch (irb & 0x4ff) { switch (irb & 0x4ff) {
case LOCK_KEY: case KEY1_CODE:
keycode = KEY_SCREENLOCK; keycode = fujitsu->keycode1;
break; break;
case DISPLAY_KEY: case KEY2_CODE:
keycode = KEY_MEDIA; keycode = fujitsu->keycode2;
break; break;
case ENERGY_KEY: case KEY3_CODE:
keycode = KEY_EMAIL; keycode = fujitsu->keycode3;
break; break;
case REST_KEY: case KEY4_CODE:
keycode = KEY_SUSPEND; keycode = fujitsu->keycode4;
break; break;
case 0: case 0:
keycode = 0; keycode = 0;
break; break;
default: default:
vdbg_printk(FUJLAPTOP_DBG_WARN, vdbg_printk(FUJLAPTOP_DBG_WARN,
"Unknown GIRB result [%x]\n", irb); "Unknown GIRB result [%x]\n", irb);
keycode = -1; keycode = -1;
break; break;
} }
@ -859,12 +874,12 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
"Push keycode into ringbuffer [%d]\n", "Push keycode into ringbuffer [%d]\n",
keycode); keycode);
status = kfifo_put(fujitsu_hotkey->fifo, status = kfifo_put(fujitsu_hotkey->fifo,
(unsigned char *)&keycode, (unsigned char *)&keycode,
sizeof(keycode)); sizeof(keycode));
if (status != sizeof(keycode)) { if (status != sizeof(keycode)) {
vdbg_printk(FUJLAPTOP_DBG_WARN, vdbg_printk(FUJLAPTOP_DBG_WARN,
"Could not push keycode [0x%x]\n", "Could not push keycode [0x%x]\n",
keycode); keycode);
} else { } else {
input_report_key(input, keycode, 1); input_report_key(input, keycode, 1);
input_sync(input); 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_report_key(input, keycode_r, 0);
input_sync(input); input_sync(input);
vdbg_printk(FUJLAPTOP_DBG_TRACE, vdbg_printk(FUJLAPTOP_DBG_TRACE,
"Pop keycode from ringbuffer [%d]\n", "Pop keycode from ringbuffer [%d]\n",
keycode_r); keycode_r);
} }
} }
} }
@ -943,6 +958,11 @@ static int __init fujitsu_init(void)
if (!fujitsu) if (!fujitsu)
return -ENOMEM; return -ENOMEM;
memset(fujitsu, 0, sizeof(struct fujitsu_t)); 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); result = acpi_bus_register_driver(&acpi_fujitsu_driver);
if (result < 0) { if (result < 0) {
@ -1076,15 +1096,14 @@ MODULE_DESCRIPTION("Fujitsu laptop extras support");
MODULE_VERSION(FUJITSU_DRIVER_VERSION); MODULE_VERSION(FUJITSU_DRIVER_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
MODULE_ALIAS
("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
static struct pnp_device_id pnp_ids[] = { static struct pnp_device_id pnp_ids[] = {
{ .id = "FUJ02bf" }, {.id = "FUJ02bf"},
{ .id = "FUJ02B1" }, {.id = "FUJ02B1"},
{ .id = "FUJ02E3" }, {.id = "FUJ02E3"},
{ .id = "" } {.id = ""}
}; };
MODULE_DEVICE_TABLE(pnp, pnp_ids); MODULE_DEVICE_TABLE(pnp, pnp_ids);

View File

@ -57,7 +57,7 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
{ {
struct acpi_device *device = cdev->devdata; struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle; acpi_handle handle = device->handle;
unsigned long value; unsigned long long value;
struct acpi_object_list arg_list; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
acpi_status status = AE_OK; 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; struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle; acpi_handle handle = device->handle;
unsigned long value; unsigned long long value;
struct acpi_object_list arg_list; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
acpi_status status = AE_OK; acpi_status status = AE_OK;
@ -104,7 +104,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EFAULT; 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, 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; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
acpi_status status; acpi_status status;
int temp; unsigned long long temp;
unsigned long max_state; unsigned long max_state;
if (memory_get_int_max_bandwidth(cdev, &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 = status =
acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
(unsigned long *)&temp); &temp);
printk(KERN_INFO printk(KERN_INFO
"Bandwidth value was %d: status is %d\n", state, status); "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; goto end;
} }
acpi_driver_data(device) = cdev; device->driver_data = cdev;
result = sysfs_create_link(&device->dev.kobj, result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling"); &cdev->device.kobj, "thermal_cooling");
if (result) if (result)
@ -252,7 +252,8 @@ static DEFINE_MUTEX(intel_menlow_attr_lock);
* @auxtype : AUX0/AUX1 * @auxtype : AUX0/AUX1
* @buf: syfs buffer * @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; acpi_status status;
@ -260,7 +261,7 @@ static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
return -EINVAL; return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
NULL, (unsigned long *)value); NULL, value);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EIO; return -EIO;
@ -282,13 +283,13 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
struct acpi_object_list args = { struct acpi_object_list args = {
1, &arg 1, &arg
}; };
int temp; unsigned long long temp;
if (index != 0 && index != 1) if (index != 0 && index != 1)
return -EINVAL; return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
NULL, (unsigned long *)&temp); NULL, &temp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EIO; return -EIO;
if ((index && value < temp) || (!index && value > temp)) 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; arg.integer.value = value;
status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
&args, (unsigned long *)&temp); &args, &temp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EIO; return -EIO;
@ -312,7 +313,7 @@ static ssize_t aux0_show(struct device *dev,
struct device_attribute *dev_attr, char *buf) struct device_attribute *dev_attr, char *buf)
{ {
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value; unsigned long long value;
int result; int result;
result = sensor_get_auxtrip(attr->handle, 0, &value); 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 device_attribute *dev_attr, char *buf)
{ {
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value; unsigned long long value;
int result; int result;
result = sensor_get_auxtrip(attr->handle, 1, &value); 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) struct device_attribute *attr, char *buf)
{ {
acpi_status status; acpi_status status;
unsigned long bios_enabled; unsigned long long bios_enabled;
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
@ -492,7 +493,7 @@ static int __init intel_menlow_module_init(void)
{ {
int result = -ENODEV; int result = -ENODEV;
acpi_status status; acpi_status status;
unsigned long enable; unsigned long long enable;
if (acpi_disabled) if (acpi_disabled)
return result; return result;

View 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,
&params, 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